Skip to content

CLI: generator internals — path-param flags, streaming endpoints, OAuth scope fallback (RND-12046, RND-12044, RND-12043)#1247

Merged
talagluck merged 17 commits into
mainfrom
cli-generator-internals
Jul 17, 2026
Merged

CLI: generator internals — path-param flags, streaming endpoints, OAuth scope fallback (RND-12046, RND-12044, RND-12043)#1247
talagluck merged 17 commits into
mainfrom
cli-generator-internals

Conversation

@talagluck

Copy link
Copy Markdown
Contributor

Bucket 1 of the mcp-cli follow-ups from #1205 — the generator-internals cluster. Stacked on cli-help-discoverability (#1245, bucket 2); retarget to main once that merges.

RND-12046 — path params as positionals and --flags

Generated commands now register each OpenAPI path parameter as an optional positional and a --<name> flag; the positional wins when both are given. Missing params produce a clear error showing both invocation forms. Applied uniformly via a new emitCommandPreamble shared by the simple and streaming emitters.

gb organizations sites list <orgId>
gb organizations sites list --organizationId <orgId>
gb organizations sites list --organizationId=<orgId>

RND-12044 — the 5 SSE streaming endpoints

Streaming ops are no longer skipped by the generator — they're tagged (Route.isStreaming) and emitted via a dedicated path that iterates the EventIterator through a new StreamRenderer in output.ts:

  • --json → NDJSON (one object per line); --yaml → a ----delimited YAML document stream
  • pretty → recommended questions live, answer text incrementally, agent-response events as status lines, sources as end-of-stream citations
  • SIGINT flushes and exits 130; a mid-flight error surfaces after the partial output

Commands (mechanical naming, each mirrors its URL and sits beside its buffered sibling): organizations ask stream, organizations ask questions stream, organizations sites ask stream, organizations sites ask questions stream, organizations sites ai response stream.

RND-12043 — OAuth scopes from the spec (as a fallback)

The premise was stale: gitbook login already requests scopes from the OAuth server's .well-known discovery metadata (environment-correct), not a hardcoded list. This adds the spec's oauth securityScheme scopes as a generated fallback (generated-oauth-scopes.ts), used only when discovery omits scopes_supported, so login never silently requests zero scopes. The OAuth endpoint stays runtime-derived (the bundled spec is prod-only).

Idle request timeout (follow-on from testing)

All generated commands (buffered, merged, streaming) now abort a request that produces no response — for streams, no next event — within CLI_TIMEOUT_MS (default 60s, GITBOOK_CLI_TIMEOUT_MS to override, 0 disables). The stream timer resets per event so a slow-but-live response isn't cut off. This came out of testing: the org-level AI ask endpoints were observed hanging server-side (raw curl -i -N returns no HTTP status), so the CLI now fails loudly instead of hanging.

Testing

  • bun run generate-commands, tsc --noEmit, ./build.sh, bun test (49 pass) all clean.
  • Exercised end-to-end: all three path-param forms + precedence + missing-param error; streaming command wiring (reaches the correct URL, errors promptly on a bad token); timeout fires on both buffered and streaming, and the normal error path still reports real API errors.
  • Not verified against a live successful AI stream — the ask endpoints were unresponsive server-side during testing (see above). The renderer is covered by unit tests across all event shapes.

🤖 Generated with Claude Code

talagluck and others added 8 commits July 16, 2026 12:38
Shell completion was generated purely from the spec-derived command tree, so the
hand-written groups' subcommands never tab-completed. Add a static
HAND_WRITTEN_COMPLETIONS map (integration -> new/dev/publish/unpublish/tail/check,
openapi -> publish) merged into the completion map before the scripts are emitted.
…D-12047, RND-12053)

- Append a "Command groups (nested)" section to every group's --help so nested
  subgroups (e.g. organizations sites) are discoverable without drilling in.
  Root uses a compact one-line-per-group layout; subgroup pages use an indented
  tree. Attached generically by walking the Commander tree at runtime.
- Sort subcommands alphabetically (built-in list via configureHelp + the tree).
- Point `gitbook integrations --help` at the singular `gitbook integration`
  group for the build/publish lifecycle (new/dev/publish/...).
Generated commands now register each OpenAPI path parameter as an optional
positional AND a --<name> flag. The positional wins when both are supplied.
Missing params produce a helpful error showing both invocation forms.
Streaming operations are no longer skipped by the generator; they are tagged
and emitted via a dedicated path that iterates the EventIterator through a new
StreamRenderer in output.ts. Machine modes stream one record per event (NDJSON
for --json, a YAML document stream for --yaml); pretty mode renders recommended
questions live, answer text incrementally, agent-response events as status
lines, and sources as end-of-stream citations. SIGINT flushes and exits 130;
a mid-flight error surfaces after the partial output. Adds renderer unit tests.

Commands (mechanical naming, each mirrors its URL and sits beside its buffered
sibling): organizations ask stream, organizations ask questions stream,
organizations sites ask stream, organizations sites ask questions stream,
organizations sites ai response stream.
… (RND-12043)

gitbook login already requests scopes from the OAuth server's .well-known
discovery metadata (environment-correct), not a hardcoded list. This adds the
spec's oauth securityScheme scopes as a generated fallback (generate-commands.ts
now also emits generated-oauth-scopes.ts), used only when discovery's
scopes_supported is absent — so login never silently requests zero scopes. The
OAuth endpoint stays runtime-derived (the bundled spec is prod-only).
Generated commands (buffered, merged, and streaming) now abort a request that
produces no response — for streams, no next event — within CLI_TIMEOUT_MS
(default 60s, override via GITBOOK_CLI_TIMEOUT_MS, 0 disables), so the CLI fails
loudly with explainTimeout() instead of hanging on an unresponsive endpoint.
The stream timer resets on each event so a slow-but-live response is not cut
off. Adds createRequestTimeout/explainTimeout to output.ts with unit tests.
@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a0d58b0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@gitbook/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

bun add https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@1247

commit: a0d58b0

Base automatically changed from cli-help-discoverability to main July 16, 2026 17:52
@talagluck
talagluck marked this pull request as ready for review July 16, 2026 17:52
talagluck and others added 3 commits July 16, 2026 19:52
…nswer

The ask endpoints default `format` to `document` (a structured tree the pretty
renderer can't turn into text), so a plain `ask stream` printed only the sources
with no answer body. Default `format` to markdown when the user hasn't set it;
`--format document` still gets the raw form. Verified end-to-end against a live
site: the answer now streams in pretty mode without any extra flag.
Adds documentToText to flatten a GitBook document node tree to plain text, so
`ask stream --format document` (and any answer that arrives as a document rather
than a markdown string) still shows the answer body in pretty mode instead of
only the sources. Marks are dropped; it's a legible fallback, not a full
markdown serializer. Verified live + unit-tested.
@talagluck
talagluck requested a review from spastorelli July 17, 2026 08:20
Comment thread packages/cli/src/output.ts Outdated
talagluck and others added 2 commits July 17, 2026 14:37
Addresses review feedback: the pretty renderer no longer sniffs event shapes in
one monolith. createStreamRenderer now owns only the generic mechanics (NDJSON/
YAML serialization, the sink + mid-line tracking, end-of-stream flush) and
delegates per-event rendering to an injectable StreamEventRenderer. The three
schemas get dedicated strategies (answer / question / agent-response) plus a
generic fallback; the generator selects one per endpoint from the SSE response's
event schema (STREAM_RENDERERS), so a new/changed schema means a new strategy at
the call site rather than editing the core.
@talagluck
talagluck merged commit fc57ad2 into main Jul 17, 2026
13 of 14 checks passed
@talagluck
talagluck deleted the cli-generator-internals branch July 17, 2026 13:02
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.

2 participants