feat(cli): emit reusable columnar JSON for paginated output - #322
Conversation
…-pagination # Conflicts: # packages/middleware/src/__tests__/agent-local-domains.test.ts
…de on bad pagination metadata
- Add session.tools.resolve() to agent-sdk, resolving a domain/tool to its
schema and a bound call() from a single getSessionTools fetch, and expose
the canonical resolved domainId. The CLI's call-tool path now uses it
instead of getSchema()+call(), cutting per-call-tool-invocation payload
from two full tool listings to one.
- Reject non-object --args for declared paginated tools with a clear error
instead of silently substituting {}; non-paginated tools keep their prior
args passthrough behavior.
- Make getToolPagination degrade malformed pagination metadata to
"non-paginated" (with a stderr warning) instead of throwing, matching the
documented contract that malformed pagination leaves results unshaped.
`next` commands echoed the user-typed domain token verbatim, including the deprecated legacy slug alias, and were built with the bare `rozenite` binary despite the documented `npx rozenite` workflow. - formatAgentCommand now emits `npx rozenite agent ...`. - The call-tool continuation uses `resolvedTool.domainId` (already resolved by session.tools.resolve, no extra fetch). - session.tools.list now attaches the resolved canonical `domainId` to each AgentDomainTool so the `agent <domain> tools` listing continuation can use it without a second getSessionTools round trip; the pagination cursor scope is keyed off the same canonical id so re-running the emitted command doesn't invalidate the cursor. - Added a shell-safety test for slash-containing domain ids (e.g. avasapp/ably) and updated SKILL.md's next-command example to match.
…rk cursors - projectRowKeyed omits absent fields instead of nulling them, so 0/1-row agent listings stay smaller than the columnar shape they exist to avoid (only the columnar branch, which needs positional cells, fills null). - shapeToolResult now degrades to unshaped output instead of silently overwriting tool metadata that collides with cols/rows/next. - register-agent-command no longer double-projects rows before handing them to shapePaginatedRows, which already projects internally. - Network domain pagination stamps cursors with the capture generation and returns page.reset instead of resuming into a wiped buffer after an app relaunch invalidates a previously-issued cursor.
…ion fields First-party paginated tools never declared defaultFields, so --verbose was a no-op and heavy columns like console getMessages' argsPreview/context always shipped. Add defaultFields to console, react, network, network-activity, and tanstack-query tool declarations, and add a small cursorPagination helper that ties each built-in's declared fields to keyof its actual row type, turning schema drift into a build error instead of a silent null column.
Move parseFields, parseLimit, projectRows, shapePaginatedRows, and shapeToolResult from packages/cli into @rozenite/agent-shared so MCP and other agent-sdk consumers can reuse the same envelope, per issue #318's maintainer comment. shapePaginatedRows/shapeToolResult now take a frontend-neutral `nextAffordance` string instead of a CLI-specific `nextCommand`, so the shared functions carry no shell-command assumptions. paginateRows (cursor encode/decode) and formatAgentCommand/shellEscape stay CLI-only: paginateRows is an offset pager scoped to CLI-owned tools/domains listings, not the general shared pagination engine that issue #320 already owns, and the shell-command builder is explicitly a CLI-only rendering of the next-page affordance per the maintainer's carve-out. Adds a test script + vitest suite to agent-shared, which previously had none.
|
Merged Review findings addressed
NotesTwo findings from the review were split out rather than folded in here:
Carve-out 2 (token-based rather than row-based page cap) is not addressed here, deliberately — see my note on #320. Also worth a reviewer's eye: Validation
One caveat on the earlier |
Summary
@rozenite/agent-shared, re-exported from@rozenite/agent-bridgeBehavior
Declared paginated tools return the normal
{items, page}contract. Their registered metadata defines the stable allowed/default field order; the CLI never infers columns from observed values.cols/rowsitemsnullnextcommand--jsonremains a deprecated no-op with no legacy escape hatchWhy
Agent CLI row payloads repeated field names for every record, increasing byte and token usage. The original implementation solved this with a CLI-private allowlist, which excluded third-party plugins and duplicated knowledge of tool schemas. The corrected design makes pagination presentation an explicit tool contract owned by each producer.
Issue #320 remains responsible for the separate shared cursor/source pagination engine and migrations away from offset pagination.
Validation
@rozenite/agent-bridgeproduction build passesgit diff --checkpassenabledoptionCloses #318