Skip to content

refactor(output): land the command-output module and adapter wiring - #325

Merged
BlackHole1 merged 1 commit into
mainfrom
output-contract-module
Jul 27, 2026
Merged

refactor(output): land the command-output module and adapter wiring#325
BlackHole1 merged 1 commit into
mainfrom
output-contract-module

Conversation

@BlackHole1

@BlackHole1 BlackHole1 commented Jul 27, 2026

Copy link
Copy Markdown
Member

Part 1/3 of the output-contract deepening (candidate 08 of the architecture review; spec in .scratch/output-contract/spec.md, local-only).

What

Deepens the shallow json-output.ts (an option array + a JSON.stringify writer) into command-output.ts, the single owner of the JSON/text output contract:

  • resolveOutputFormat is now the one --json/--format precedence rule. The commander adapter's private telemetry copy is deleted; the onCommandResolved event imports the shared rule (with a json-only ternary so JSON-only commands report "json").
  • createCommandOutput builds the per-invocation CommandOutput handle ({format, emit, emitJson}) that handlers receive via the new CliCommandContext (CliExecutionContext + output). Commands that declare an output mode get strict --format validation before parseInput and the shared option definitions attached by the adapter. Undeclared commands get an inert text handle — nothing changes for them.
  • CliCommandDefinition gains output?: "standard" | "json-only". No command sets it yet; migration follows in the stacked PR.
  • jsonOutputOptions is renamed to outputFormatOptions everywhere (same array, honest name — the contract covers text too).

Behavior

No behavior change. No command declares an output mode yet, and the telemetry-rule relocation evaluates identically for every existing command and flag combination.

Tests

Table-driven module tests over the new seam (lenient precedence, strict rejection with the offending value, inert handle, json-only pinning, emit routing, schemaVersion envelope). Three new adapter tests cover option attachment, pre-handler strict rejection, and the json-only telemetry event. Handler-invoking test fabrication sites gained the output member (compiler-verified set).

Stack

  1. refactor(output): land the command-output module and adapter wiring #325 👈 current
  2. refactor(commands): migrate all standard commands onto the output handle #326
  3. refactor(output): standardize the JSON-only commands and retire the legacy exports #327

Deepen json-output.ts (renamed to command-output.ts) into the owner of
the JSON/text output contract:

- resolveOutputFormat is the one --json/--format precedence rule; the
  commander adapter's private telemetry copy is deleted and the
  onCommandResolved event now uses the shared rule (json-only commands
  report "json").
- createCommandOutput builds the per-invocation CommandOutput handle
  ({format, emit, emitJson}) handed to handlers via the new
  CliCommandContext. Commands that declare an output mode get strict
  --format validation before parseInput and the shared option
  definitions attached by the adapter; undeclared commands get an inert
  text handle, so nothing changes for existing commands.
- CliCommandDefinition gains an optional output: "standard" | "json-only"
  field (no command sets it yet; migration follows in the next PR).
- jsonOutputOptions is renamed to outputFormatOptions everywhere; the
  schemaVersion envelope logic is unchanged and now also backs
  CommandOutput.emitJson.

No behavior change: no command declares an output mode yet, and the
telemetry rule relocation evaluates identically for every existing
command.
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Introduces a shared command-output module for output-format options, format resolution, strict validation, output handles, and schema-versioned JSON serialization. The Commander adapter now creates and passes output handles to handlers, reports resolved formats, and supports json-only commands. Application commands migrate from jsonOutputOptions to outputFormatOptions, while tests adopt CliCommandContext and validate output behavior, invalid formats, and schema-versioned payloads.

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant CommanderCliAdapter
  participant CommandOutput
  participant CommandHandler
  participant Writer
  CLI->>CommanderCliAdapter: execute command with output flags
  CommanderCliAdapter->>CommandOutput: resolve and validate format
  CommanderCliAdapter->>CommandHandler: invoke with output handle
  CommandHandler->>CommandOutput: emit result
  CommandOutput->>Writer: write text or JSON payload
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title follows the required type(scope): subject format and accurately describes the output-contract and adapter wiring refactor.
Description check ✅ Passed The description is clearly related to the output-contract refactor and summarizes the main changes, tests, and migration scope.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch output-contract-module

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/application/commands/command-output.ts (1)

93-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated json-only/format-precedence ternary across two files. Both sites independently reimplement mode/definition.output === "json-only" ? "json" : resolveOutputFormat(optionValues); extracting a single shared helper avoids the two copies drifting if the json-only rule changes.

  • src/application/commands/command-output.ts#L93-L109: export a helper (e.g. resolveDeclaredOutputFormat(optionValues, mode)) encapsulating this ternary, and use it as the final return of resolveStrictOutputFormat.
  • src/adapters/commander/commander-cli-adapter.ts#L284-L306: call the same exported helper for the outputFormat telemetry field instead of re-deriving it inline.
♻️ Proposed refactor
+export function resolveDeclaredOutputFormat(
+    optionValues: OutputOptionValues,
+    mode: CliCommandOutputMode,
+): "json" | "text" {
+    return mode === "json-only" ? "json" : resolveOutputFormat(optionValues);
+}
+
 function resolveStrictOutputFormat(
     optionValues: OutputOptionValues,
     mode: CliCommandOutputMode,
 ): "json" | "text" {
     const format = optionValues.format;

     if (
         format !== undefined
         && !outputFormatValues.includes(format as (typeof outputFormatValues)[number])
     ) {
         throw new CliUserError("errors.shared.invalidFormat", 2, {
             value: String(format),
         });
     }

-    return mode === "json-only" ? "json" : resolveOutputFormat(optionValues);
+    return resolveDeclaredOutputFormat(optionValues, mode);
 }
-            outputFormat: definition.output === "json-only"
-                ? "json"
-                : resolveOutputFormat(optionValues),
+            outputFormat: definition.output === undefined
+                ? resolveOutputFormat(optionValues)
+                : resolveDeclaredOutputFormat(optionValues, definition.output),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/command-output.ts` around lines 93 - 109, Extract
the shared json-only/output-format precedence logic from
resolveStrictOutputFormat into an exported helper such as
resolveDeclaredOutputFormat(optionValues, mode), and use it for the function’s
final return. In src/application/commands/command-output.ts lines 93-109, retain
the existing strict validation and delegate only the format resolution; in
src/adapters/commander/commander-cli-adapter.ts lines 284-306, replace the
inline derivation of the outputFormat telemetry field with this helper.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/application/commands/completion.test.ts`:
- Line 3: The test fixtures must satisfy the CliCommandContext contract by
providing output directly instead of using a double cast. In
src/application/commands/completion.test.ts lines 3-3 and 40-40, import
createCommandOutput, add it to the completion context fixture, and remove the as
unknown as CliCommandContext cast. In
src/application/commands/file/cleanup.test.ts lines 1-1, 31-31, 58-58, 85-85,
and 114-114, import createCommandOutput and provide an output handle for each
cleanup invocation.

In `@src/application/commands/skills/recommend/suppression-command.ts`:
- Line 58: Align both command schemas with the shared output format options: in
src/application/commands/skills/recommend/suppression-command.ts at lines 58-58,
widen suppressionFormatValues and its schema to accept "text" alongside "json";
in src/application/commands/skills/uninstall.ts at lines 99-99, widen
SkillsUninstallInput.format to accept "text" as well.

---

Nitpick comments:
In `@src/application/commands/command-output.ts`:
- Around line 93-109: Extract the shared json-only/output-format precedence
logic from resolveStrictOutputFormat into an exported helper such as
resolveDeclaredOutputFormat(optionValues, mode), and use it for the function’s
final return. In src/application/commands/command-output.ts lines 93-109, retain
the existing strict validation and delegate only the format resolution; in
src/adapters/commander/commander-cli-adapter.ts lines 284-306, replace the
inline derivation of the outputFormat telemetry field with this helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5c1a3b02-839d-4835-b18e-41f43e12207b

📥 Commits

Reviewing files that changed from the base of the PR and between 924f76f and 7c493f6.

📒 Files selected for processing (44)
  • src/adapters/commander/commander-cli-adapter.test.ts
  • src/adapters/commander/commander-cli-adapter.ts
  • src/application/commands/auth/index.cli.test.ts
  • src/application/commands/auth/status.ts
  • src/application/commands/check-update.ts
  • src/application/commands/command-output.test.ts
  • src/application/commands/command-output.ts
  • src/application/commands/completion.test.ts
  • src/application/commands/connector/apps.ts
  • src/application/commands/connector/proxy.ts
  • src/application/commands/connector/run.ts
  • src/application/commands/connector/schema.ts
  • src/application/commands/connector/search.ts
  • src/application/commands/file/cleanup.test.ts
  • src/application/commands/file/cleanup.ts
  • src/application/commands/file/download.test.ts
  • src/application/commands/file/list.ts
  • src/application/commands/file/upload.ts
  • src/application/commands/info.cli.test.ts
  • src/application/commands/info.ts
  • src/application/commands/json-output.test.ts
  • src/application/commands/json-output.ts
  • src/application/commands/llm/config.ts
  • src/application/commands/llm/json.ts
  • src/application/commands/search.ts
  • src/application/commands/skills/check-update.ts
  • src/application/commands/skills/install.ts
  • src/application/commands/skills/list.ts
  • src/application/commands/skills/recommend/plan.ts
  • src/application/commands/skills/recommend/suppression-command.ts
  • src/application/commands/skills/repair.ts
  • src/application/commands/skills/search.test.ts
  • src/application/commands/skills/search.ts
  • src/application/commands/skills/sync.ts
  • src/application/commands/skills/uninstall.ts
  • src/application/commands/skills/update.ts
  • src/application/commands/team/current.ts
  • src/application/commands/team/list.ts
  • src/application/commands/variables/create.ts
  • src/application/commands/variables/delete.ts
  • src/application/commands/variables/get.ts
  • src/application/commands/variables/list.ts
  • src/application/commands/version.ts
  • src/application/contracts/cli.ts
💤 Files with no reviewable changes (2)
  • src/application/commands/json-output.test.ts
  • src/application/commands/json-output.ts

Comment thread src/application/commands/completion.test.ts
Comment thread src/application/commands/skills/recommend/suppression-command.ts
@BlackHole1
BlackHole1 merged commit 684848c into main Jul 27, 2026
6 checks passed
@BlackHole1
BlackHole1 deleted the output-contract-module branch July 27, 2026 22:48
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