Skip to content

feat(list): add pagination and consistent target parsing to all list commands - #262

Merged
BYK merged 23 commits into
mainfrom
byk/pagination-and-target-parsing
Feb 19, 2026
Merged

feat(list): add pagination and consistent target parsing to all list commands#262
BYK merged 23 commits into
mainfrom
byk/pagination-and-target-parsing

Conversation

@BYK

@BYK BYK commented Feb 18, 2026

Copy link
Copy Markdown
Member

Summary

Extends the pagination and flexible target parsing pattern introduced in #221 for `project list` to all remaining list commands: `issue list`, `team list`, `repo list`, `trace list`, and `log list`. Introduces a shared `dispatchOrgScopedList` infrastructure with `HandlerContext` that all list commands now use.

Changes

Shared infrastructure

  • `src/lib/arg-parsing.ts`: Added `validateLimit(value, min, max)` — shared limit validation, replaces duplicate implementations in `trace/list.ts` and `log/list.ts`
  • `src/lib/resolve-target.ts`: Added `resolveOrgsForListing()`, `resolveOrgProjectTarget()`, and `resolveOrgProjectFromArg()` — deduplicates logic previously copied across commands
  • `src/lib/api-client.ts`: Added `listIssuesPaginated()`, `listTeamsPaginated()`, `listRepositoriesPaginated()`, `listProjectTeams()` using `orgScopedRequestPaginated()` for cursor-based pagination with Link header support
  • `src/lib/org-list.ts`: Shared dispatch infrastructure — `ListCommandMeta`, `OrgListConfig`, `HandlerContext`, `ModeHandler`, `ModeHandlerMap`, `dispatchOrgScopedList`. Handlers receive a `HandlerContext` with `{ parsed, stdout, cwd, flags }` so they don't need to close over those values; commands add extras via spread: `(ctx) => handle({ ...ctx, extra })`
  • `src/lib/list-command.ts`: Shared Stricli parameter constants and `buildOrgListCommand` factory for simple org-scoped commands (team, repo)
  • `src/lib/db/pagination.ts`: Added `escapeContextKeyValue()` for safe pipe-delimiter escaping in context keys, and `resolveOrgCursor()` shared across all list commands

Command changes

Command What changed
`issue list` Added `--cursor/-c` flag; org-all mode now uses `listIssuesPaginated` and returns `{ data, hasMore, nextCursor? }` in JSON output
`team list` Full rewrite: 4-mode handler via `dispatchOrgScopedList`, `--cursor/-c` flag, project-scoped team listing via `listProjectTeams` for `org/project` mode
`repo list` Full rewrite: 4-mode handler via `dispatchOrgScopedList`, `--cursor/-c` flag, org-scoped fallback with note for `org/project` mode
`project list` Migrated to `dispatchOrgScopedList` with mode overrides (no behavior change)
`trace list` Replaced local `resolveTraceTarget` + `validateLimit` with shared versions
`log list` Replaced local `resolveLogTarget` + `validateLimit` with shared versions

Tests

  • `test/commands/team/list.test.ts`: Covers all 4 modes including project-scoped team listing and bare-slug project search
  • `test/commands/repo/list.test.ts`: Covers all 4 modes including bare-slug project search with org-scoped fallback
  • `test/lib/org-list.test.ts`: 36 tests covering the shared dispatch infrastructure
  • `test/e2e/issue.test.ts`: Updated org-all JSON output assertion to match new `{ data, hasMore }` shape

Behavior notes

  • `issue list` org-all JSON output shape changed: was a plain array `[...]`, now `{ data: [...], hasMore: bool, nextCursor?: string }` — consistent with `project list`
  • Target parsing convention: org-all mode requires a trailing slash (`/`). A bare slug (no slash) is always treated as a project slug and triggers a cross-org project search via `findProjectsBySlug` — consistent across all list commands
  • `team list org/project`: fetches teams scoped to that project (via `listProjectTeams` endpoint)
  • `repo list org/project`: repos are org-scoped; shows all repos in the org with a note that the project part is ignored
  • Context key escaping: user-supplied values (query, platform) used in pagination context keys are escaped with `escapeContextKeyValue()` to prevent pipe-delimiter injection
  • All 1903 unit tests pass; typecheck and lint clean

BYK added 2 commits February 18, 2026 11:06
Bun's mock.module() leaks across test files in the same run.
The simplified stub for formatMultipleProjectsFooter in the
dsn/index.js mock was poisoning errors.test.ts, causing 4 failures
in test:isolated.

Import the real function from its source file (dsn/errors.js) and
pass it through the mock so the leaked version retains real behavior.

Fixes #258
@github-actions

github-actions Bot commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Build

  • Add hole-punch tool to reduce compressed binary size by BYK in #245
  • Add gzip-compressed binary downloads by BYK in #244

Other

  • (args) Parse Sentry web URLs as CLI arguments by BYK in #252
  • (list) Add pagination and consistent target parsing to all list commands by BYK in #262

Bug Fixes 🐛

Telemetry

  • Reduce noise from version-check JSON parse errors by BYK in #253
  • Skip Sentry reporting for 4xx API errors by BYK in #251
  • Handle EPIPE errors from piped stdout gracefully by BYK in #250
  • Upgrade Sentry SDK to 10.39.0 and remove custom patches by BYK in #249

Other

  • (commands) Support org/project/id as single positional arg by BYK in #261
  • (db) Handle readonly database gracefully instead of crashing by betegon in #235
  • (errors) Show meaningful detail instead of [object Object] in API errors by BYK in #259
  • (issue-list) Propagate original errors instead of wrapping in plain Error by BYK in #254
  • (polyfill) Add exited promise and stdin to Bun.spawn Node.js polyfill by BYK in #248
  • (project-list) Add pagination and flexible target parsing by BYK in #221
  • (test) Prevent mock.module() leak from breaking test:isolated by BYK in #260
  • (upgrade) Remove v prefix from release URLs and work around Bun.write streaming bug by BYK in #243

Internal Changes 🔧

  • (build) Replace local hole-punch script with binpunch package by BYK in #246
  • Use @sentry/api client for requests by MathurAditya724 in #226

🤖 This preview updates automatically when you update the PR.

Comment thread src/commands/issue/list.ts Outdated
Comment thread src/commands/issue/list.ts Outdated
Comment thread src/commands/team/list.ts Outdated
Comment thread src/commands/repo/list.ts Outdated
Comment thread src/commands/issue/list.ts Outdated
Comment thread src/commands/repo/list.ts Outdated
@github-actions

github-actions Bot commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊

✅ Patch coverage is 88.46%. Project has 3644 uncovered lines.
✅ Project coverage is 73.98%. Comparing base (base) to head (head).

Files with missing lines (69)
File Patch % Lines
human.ts 58.39% ⚠️ 394 Missing
resolve-target.ts 37.26% ⚠️ 325 Missing
api-client.ts 70.60% ⚠️ 237 Missing
oauth.ts 30.94% ⚠️ 183 Missing
list.ts 29.55% ⚠️ 155 Missing
plan.ts 19.37% ⚠️ 154 Missing
list.ts 72.41% ⚠️ 120 Missing
resolver.ts 3.23% ⚠️ 120 Missing
help.ts 19.85% ⚠️ 109 Missing
upgrade.ts 61.37% ⚠️ 107 Missing
view.ts 41.90% ⚠️ 104 Missing
interactive-login.ts 9.17% ⚠️ 99 Missing
errors.ts 5.94% ⚠️ 95 Missing
view.ts 25.81% ⚠️ 92 Missing
view.ts 41.50% ⚠️ 86 Missing
clipboard.ts 4.49% ⚠️ 85 Missing
status.ts 24.07% ⚠️ 82 Missing
migration.ts 47.44% ⚠️ 82 Missing
list.ts 27.18% ⚠️ 75 Missing
browser.ts 4.11% ⚠️ 70 Missing
login.ts 33.33% ⚠️ 64 Missing
list.ts 86.08% ⚠️ 59 Missing
span-tree.ts 5.00% ⚠️ 57 Missing
explain.ts 33.33% ⚠️ 56 Missing
api.ts 89.80% ⚠️ 47 Missing
upgrade.ts 66.91% ⚠️ 46 Missing
seer.ts 75.54% ⚠️ 45 Missing
refresh.ts 40.63% ⚠️ 38 Missing
schema.ts 91.06% ⚠️ 37 Missing
seer.ts 79.87% ⚠️ 30 Missing
preload.ts 53.23% ⚠️ 29 Missing
view.ts 87.27% ⚠️ 28 Missing
telemetry.ts 93.01% ⚠️ 27 Missing
utils.ts 88.94% ⚠️ 25 Missing
view.ts 61.54% ⚠️ 25 Missing
fix.ts 89.29% ⚠️ 24 Missing
org-list.ts 93.81% ⚠️ 21 Missing
detector.ts 90.10% ⚠️ 20 Missing
arg-parsing.ts 90.67% ⚠️ 18 Missing
binary.ts 88.67% ⚠️ 17 Missing
help.ts 57.14% ⚠️ 15 Missing
sentry-client.ts 92.17% ⚠️ 13 Missing
dsn-cache.ts 94.62% ⚠️ 12 Missing
code-scanner.ts 96.25% ⚠️ 12 Missing
logout.ts 56.00% ⚠️ 11 Missing
token.ts 52.17% ⚠️ 11 Missing
qrcode.ts 33.33% ⚠️ 10 Missing
fs-utils.ts 57.14% ⚠️ 9 Missing
view.ts 94.89% ⚠️ 7 Missing
project-root.ts 97.73% ⚠️ 7 Missing
version-check.ts 92.47% ⚠️ 7 Missing
feedback.ts 84.21% ⚠️ 6 Missing
auth.ts 95.56% ⚠️ 6 Missing
shell.ts 96.23% ⚠️ 6 Missing
app.ts 93.90% ⚠️ 5 Missing
setup.ts 97.84% ⚠️ 4 Missing
project-aliases.ts 97.40% ⚠️ 2 Missing
project-root-cache.ts 96.92% ⚠️ 2 Missing
output.ts 89.47% ⚠️ 2 Missing
list.ts 99.01% ⚠️ 1 Missing
alias.ts 99.42% ⚠️ 1 Missing
completions.ts 99.37% ⚠️ 1 Missing
index.ts 98.99% ⚠️ 1 Missing
env-file.ts 99.19% ⚠️ 1 Missing
parser.ts 98.63% ⚠️ 1 Missing
colors.ts 98.21% ⚠️ 1 Missing
trace.ts 99.16% ⚠️ 1 Missing
region.ts 97.30% ⚠️ 1 Missing
helpers.ts 94.74% ⚠️ 1 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    73.15%    73.98%    +0.83%
==========================================
  Files          111       114        +3
  Lines        13756     14005      +249
  Branches         0         0         —
==========================================
+ Hits         10063     10361      +298
- Misses        3693      3644       -49
- Partials         0         0         —

Generated by Codecov Action

Comment thread src/commands/issue/list.ts Outdated
Comment thread src/lib/api-client.ts
BYK added 2 commits February 18, 2026 12:47
- Rewrite team/list and repo/list tests with 23 tests each covering explicit,
  auto-detect, org-all, cursor, ValidationError, and ContextError modes
- Add org-all cursor pagination tests to issue/list
- Add new resolve-target-listing.test.ts with 19 tests for resolveOrgsForListing,
  resolveOrgProjectTarget, and resolveOrgProjectFromArg
- Fix api-client.test.ts: close missing listTeamsPaginated describe block, add
  cursor/perPage tests for listTeamsPaginated, fix Link header format to use
  named cursor attribute instead of URL query param
Comment thread src/commands/issue/list.ts Outdated
BYK and others added 4 commits February 18, 2026 13:01
- Fix malformed 'project:' filter: empty projectSlug now produces empty
  string (falsy) so .filter(Boolean) correctly removes it for org-wide listing
- Fix isMultiProject=false in org-all issue listing: set to true so the ALIAS
  column shows which project each issue belongs to
- Fix missing hasMore check on empty page in issue list org-all path: show
  'try the next page' hint instead of definitive 'no issues' when hasMore=true
- Remove redundant footer tip from handleOrgAll in repo/list and team/list:
  the tip told users to do what they already did
- Deduplicate buildContextKey/resolveCursor: extract buildOrgContextKey and
  resolveOrgCursor into src/lib/db/pagination.ts and update all callers
…repo commands

Introduce OrgListConfig-driven dispatch and a generic table renderer to
eliminate ~670 lines of duplicated code between team/list and repo/list.

New modules:
- src/lib/org-list.ts: fetchOrgSafe, fetchAllOrgs, handleOrgAll,
  handleAutoDetect, handleExplicitOrg, dispatchOrgScopedList
- src/lib/formatters/table.ts: writeTable with Column<T> definitions

team/list.ts: 420 → 127 lines (-70%)
repo/list.ts: 424 → 125 lines (-71%)
Add LIST_TARGET_POSITIONAL, LIST_JSON_FLAG, LIST_CURSOR_FLAG,
buildListLimitFlag, and LIST_BASE_ALIASES as shared constants so all
four list commands stop redefining the same flag/positional shapes.

Add buildOrgListCommand factory (Level B) for team and repo commands
whose entire func body is dispatchOrgScopedList; reduces those files
to config + column definitions + one call.

team/list.ts and repo/list.ts each drop ~40 more lines.
project/list.ts and issue/list.ts spread the shared constants,
removing the duplicated positional/json/cursor/limit definitions.

12 new tests in test/lib/list-command.test.ts; 1850 unit tests pass.
Comment thread src/commands/issue/list.ts Outdated
…e-slug routing

- team list: add listForProject (project-scoped teams via listAProject_sTeams)
- repo list: bare slug now routes through project-search → org-scoped fallback
- project list and issue list: replace switch-case dispatch with dispatchOrgScopedList + overrides
- team/repo list tests: update to mock findProjectsBySlug for project-search mode
- org-list.ts: full rewrite with ListCommandMeta, OrgListConfig, ModeHandlerMap, dispatchOrgScopedList
- 1874 unit tests passing, lint and typecheck clean
Comment thread src/lib/org-list.ts Outdated
Comment thread src/lib/org-list.ts
Comment thread src/lib/list-command.ts
Comment thread src/commands/project/list.ts
- handleOrgAll: apply withOrg mapping so ORG column is populated in paginated output
- handleOrgAllIssues: use isMultiProject=true in header (already true in row formatOptions)
- displayFetchedItems: add orgSlugForHint field so truncation hint emits valid CLI command
- project/list: move resolveCursor inside org-all override closure so ValidationError fires before ContextError
- list-command.ts: clean up leftover syntax fragment from reverted bare-slug change
- Update PR description: bare slug = project search (consistent across all list commands)
Comment thread src/commands/issue/list.ts Outdated
Comment thread src/commands/project/list.ts Outdated
Comment thread src/commands/project/list.ts Outdated
Comment thread src/lib/list-command.ts
Comment thread src/lib/org-list.ts
- Replace parsed.type ternaries with Extract<> casts in issue/list.ts and project/list.ts override closures
- Fix handleProjectSearch to throw ContextError("Project", ...) instead of ContextError(config.entityName, ...)
- Add List Command Infrastructure section to AGENTS.md documenting list-command.ts and org-list.ts helpers
Comment thread src/lib/org-list.ts
BYK added 2 commits February 19, 2026 00:15
…ct<> casts

ModeHandler<T> now receives ParsedVariant<T> as an argument. The dispatcher
passes the correctly-narrowed parsed value, so override closures can access
variant-specific fields (.org, .projectSlug) directly without manual casts.
Comment thread src/lib/db/pagination.ts
…gCursor

project/list.ts had a local resolveCursor that duplicated resolveOrgCursor
from db/pagination.ts. Replace the local function and update tests.
Comment thread src/lib/api-client.ts
Comment thread src/commands/issue/list.ts Outdated
Comment thread src/commands/project/list.ts
- Escape '|' to '%7C' in user-provided query and platform values used in
  pagination context keys to prevent delimiter injection.
- Send query: undefined instead of query: '' when no project or query filter
  is active in listIssuesPaginated.
Comment thread src/commands/issue/list.ts Outdated
Comment thread src/commands/project/list.ts Outdated
Comment thread src/lib/api-client.ts
Comment thread src/lib/org-list.ts
…licated handler

- Extract escapeContextKeyValue() into db/pagination.ts as shared utility
  for pipe-delimiter escaping in context keys (was inline in issue/list.ts
  and project/list.ts).
- Deduplicate handleResolvedTargets overrides in issue/list.ts: single
  resolveAndHandle function reused across auto-detect, explicit, and
  project-search modes instead of three identical closures.
- Add explanatory comments for fullQuery || undefined in api-client.ts
  and for 'Project' ContextError resource in org-list.ts handleProjectSearch.
Comment thread src/commands/issue/list.ts Outdated
BYK added 3 commits February 19, 2026 09:19
… variant

Introduces HandlerContext<T> that bundles parsed, stdout, cwd, and flags
into a single object passed to every mode handler. This eliminates the
need for handlers to close over these values from their parent scope.

Commands add extra fields via spread: (ctx) => handle({ ...ctx, extra }).

Also adds a 'fallback' option to DispatchOptions so commands where most
modes share one handler (e.g. issue list) can specify it once instead of
repeating it for each key.
The fallback added complexity for minimal benefit — a shared local
handler assigned to each mode key is clearer and just as concise.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment thread src/lib/org-list.ts
displayFetchedItems was emitting an inline truncation hint via orgSlugForHint
AND handleExplicitOrg was writing the same tip again via writeFooter.
Remove orgSlugForHint so displayFetchedItems only shows the plain count line;
the writeFooter below is the single source for the pagination tip.
@BYK
BYK merged commit 995fd40 into main Feb 19, 2026
23 checks passed
@BYK
BYK deleted the byk/pagination-and-target-parsing branch February 19, 2026 11:57
BYK added a commit that referenced this pull request Feb 19, 2026
…265)

## What

Two fixes found during post-merge testing of #262:

### CLI-72: `pagination_cursors` wrong primary key

Migration 4→5 used `CREATE TABLE IF NOT EXISTS`, so any DB that already
had `pagination_cursors` from an earlier code path kept a single-column
PK (`command_key TEXT PRIMARY KEY`) instead of the required composite PK
(`PRIMARY KEY (command_key, context)`). This caused a runtime crash on
the first `--cursor last` use:

```
SQLiteError: ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint
```

**Fix:**
- Schema version bumped to 6 with a migration that detects the wrong PK,
drops the table, and recreates it correctly. Cursor data loss is safe
(5-min TTL).
- `repairWrongPrimaryKeys()` added to `repairSchema()` so auto-repair
also catches this.
- `isSchemaError()` extended to recognise the ON CONFLICT error and
trigger auto-repair.
- New `wrong_primary_key` `SchemaIssue` variant surfaced in
`getSchemaIssues()` and `sentry cli fix`.

### Test isolation: `bun test` caused ~130 spurious failures locally

`"test": "bun test"` ran all files in one process.
`test/isolated/resolve-target.test.ts` uses `mock.module()` which leaks
global module state across files, poisoning `api-client.js`,
`db/defaults.js`, and others for all subsequent tests.

**Fix:** Change the `test` script to `bun run test:unit && bun run
test:isolated` so each suite runs in a separate Bun process. The split
was already documented in `AGENTS.md`; the top-level script just wasn't
using it.

## Result

`bun run test`: 1931 tests, 0 failures (was 130 failures).
BYK added a commit that referenced this pull request Feb 23, 2026
## Summary

`org list` was the only list command not using the shared constants from
`list-command.ts` that landed in #262. This switches it over.

## Changes

- Replace inline `limit` and `json` flag definitions with
`buildListLimitFlag("organizations")` and `LIST_JSON_FLAG`
- Add `LIST_BASE_ALIASES` — gives `org list` the missing `-n` shorthand
for `--limit`, consistent with all other list commands
- Remove now-unused `numberParser` import from `command.ts`

No behaviour change beyond the new `-n` alias.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
betegon pushed a commit that referenced this pull request Feb 26, 2026
## Summary

`org list` was the only list command not using the shared constants from
`list-command.ts` that landed in #262. This switches it over.

## Changes

- Replace inline `limit` and `json` flag definitions with
`buildListLimitFlag("organizations")` and `LIST_JSON_FLAG`
- Add `LIST_BASE_ALIASES` — gives `org list` the missing `-n` shorthand
for `--limit`, consistent with all other list commands
- Remove now-unused `numberParser` import from `command.ts`

No behaviour change beyond the new `-n` alias.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant