Skip to content

feat(cli): Section B foundation — registerCommand tags, ESLint rule, COMMAND_INVENTORY#30159

Merged
noanflaherty merged 7 commits into
mainfrom
credence/cli-foundation-tags-lint
May 10, 2026
Merged

feat(cli): Section B foundation — registerCommand tags, ESLint rule, COMMAND_INVENTORY#30159
noanflaherty merged 7 commits into
mainfrom
credence/cli-foundation-tags-lint

Conversation

@credence-the-bot
Copy link
Copy Markdown
Contributor

@credence-the-bot credence-the-bot Bot commented May 9, 2026

Summary

This is the Section B foundation for the CLI refactor. Three sub-PRs land together:

Notable details

  • cache-fs.ts moved from commands/lib/ (it's a node:fs re-export for test isolation, not an actual command)
  • default-action.ts uses program.action() (root default handler) and cannot be wrapped with registerCommand; tagged LOCAL in the inventory
  • autonomy is tagged local per JARVIS-745 (file-write only, no daemon consumer)
  • status.ts daemon-down path uses process.stdout.write() directly (Bun's console.log bypasses process.stdout.write overrides in tests)
  • CI workflow step for lint:inventory needs manual addition to .github/workflows/pr-assistant.yaml (GitHub App lacks workflows permission); diff is in PR feat(cli): COMMAND_INVENTORY.md + bidirectional CI check + AGENTS.md canonical example #30158 body

Release notes

Behavior change (script-facing): assistant status exit code on daemon-down.
Previously assistant status exited with code 1 when the daemon was unreachable. As of this PR it exits with code 0 and prints a structured "daemon down" report (with --json returning { "ok": false, "reason": "daemon-not-running" }). This is intentional per DESIGN §3.7 — "daemon down" is a normal operational state, not an error.

If you have scripts that grep $? of assistant status to detect daemon-down, switch to:

assistant status --json | jq -e '.ok' >/dev/null

Test plan

  • bun run lint passes (ESLint rule wired as warn — 18 advisory warnings on partially-migrated commands)
  • bun run lint:inventory exits 0
  • bunx tsc --noEmit clean
  • ESLint rule smoke tests: helper-module skip, missing-transport, allowlist-gap regression, type-only-import skip — all pass
  • After merge: manually add - name: Check CLI inventory / run: bun run lint:inventory after Lint unused code step in .github/workflows/pr-assistant.yaml

Review cycle 1 fixes (commit bb15a8c0b)

Addressing Codex + Devin findings on the initial rollup:

  1. Allowlist gap (Codex P2 / Devin 🟡): added ../logger + ../output to local and bootstrap allowlists. Drops 5 false-positives on tagged local commands.
  2. Doc reference (Devin 🟡): forbiddenImport error message → points to src/cli/AGENTS.md (was nonexistent DESIGN.md §3.1).
  3. Target glob too broad (Codex P2): rule now silently skips files without registerCommand calls. Helper modules under commands/ (e.g. oauth/shared.ts) no longer false-positive. Backdoor closed because sibling helpers aren't allowlisted as imports.
  4. Type-only imports (extends Codex P2 feat: initialize Next.js app in /web directory #1): import type {...} is erased at compile time and skipped. Drops 3 false-positives on memory-v2.ts + mcp.ts type imports from runtime/routes/.
  5. Canonical example claim (Devin 🟡): pending.ts migrated to actually use exitFromIpcResult so AGENTS.md stops lying.
  6. mcp.ts misclassification (Devin 🚩): reclassified THINLEGACY in COMMAND_INVENTORY with a note that Section C/D will thin it. The advisory rule correctly warns on this file (5 warnings, all real).

After cycle 1: 0 errors, 18 warnings (down from 21), all on legitimately partially-migrated commands (config, keys, credential-execution, status, task, mcp) — these are real Section C-I work, not noise.

Part of plan: cli-foundation-tags-lint.md


Open in Devin Review

credence-the-bot Bot and others added 3 commits May 9, 2026 21:10
…§3.7 daemon-down message (#30156)

* feat(cli): registerCommand helper + transport tags for 21 commands + §3.7 daemon-down message

* fix(lint): sort imports in cache.ts, clients.ts, register-command.test.ts

* fix(tests): use console.log in status.ts; update exit-helper test for §3.7 message

* fix(tests): use process.stdout.write in status.ts for testable output

* fix: revert daemon terminology per AGENTS.md; use 'the assistant' in user-facing messages; 'Assistant: running/down' in status

---------

Co-authored-by: credence-the-bot[bot] <test@test.com>
* feat(cli): advisory ESLint rule cli/no-daemon-internals

* fix(lint): convert ESLint rule to plain JS so Node.js ESM loader can find it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: credence-the-bot[bot] <test@test.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…canonical example (PR #30158)

* feat(cli): COMMAND_INVENTORY.md + bidirectional CI check + AGENTS.md canonical example

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(lint): sort named imports alphabetically in check-cli-inventory.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(lint): correct named import sort order in check-cli-inventory.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: credence-the-bot[bot] <test@test.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8869493c13

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +49 to +50
files: ["src/cli/commands/**/*.ts"],
ignores: ["src/cli/commands/**/__tests__/**"],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Narrow lint rule target to actual command entry files

Applying cli/no-daemon-internals to every src/cli/commands/**/*.ts file causes persistent false positives on helper modules that are not command registrars (for example src/cli/commands/oauth/shared.ts imports modules but intentionally has no registerCommand(...) call). Those files can only trigger missingTransport, which adds noise and makes real transport-boundary warnings harder to spot during migration.

Useful? React with 👍 / 👎.

Comment on lines +11 to +15
local: [
"node:",
"bun:",
"commander",
"../../config/loader",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add local transport logger/output imports to allowlist

The local allowlist omits common CLI output imports like ../logger (and related output helpers), so newly tagged local commands in this same change (autonomy.ts, config.ts, completions.ts, keys.ts, credential-execution.ts) are immediately reported as violations despite following the intended transport tagging. This makes the rule noisy and blocks using warnings as a reliable migration signal.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 5 potential issues.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +11 to +19
local: [
"node:",
"bun:",
"commander",
"../../config/loader",
"../../config/schema",
"../../util/platform",
"../lib/",
],
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.

🟡 ESLint local/bootstrap allowlists missing ../logger and ../output prefixes

The ipc transport allowlist includes "../logger" and "../output" (lines 7-8), but the local and bootstrap allowlists omit them. These are pure CLI utilities (assistant/src/cli/logger.ts, assistant/src/cli/output.ts) with no daemon-internal dependencies, yet every local-tagged command that imports them will produce a false-positive forbiddenImport warning. All five local-tagged commands in this PR import ../logger.js: autonomy.ts, config.ts, completions.ts, keys.ts, and credential-execution.ts (the latter also imports ../output.js). This significantly reduces the signal-to-noise ratio of the advisory lint rule.

Suggested change
local: [
"node:",
"bun:",
"commander",
"../../config/loader",
"../../config/schema",
"../../util/platform",
"../lib/",
],
local: [
"node:",
"bun:",
"commander",
"../../config/loader",
"../../config/schema",
"../../util/platform",
"../logger",
"../output",
"../lib/",
],
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

missingTransport:
"CLI command file must call registerCommand({ transport: ... }) to declare its transport class.",
forbiddenImport:
"'{{transport}}'-tagged CLI command imports forbidden module '{{source}}'. See DESIGN.md §3.1 for allowed imports.",
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.

🟡 ESLint error message references nonexistent DESIGN.md §3.1

The forbiddenImport message says "See DESIGN.md §3.1 for allowed imports" but no DESIGN.md file exists anywhere in the repository (confirmed via find). Developers encountering this lint warning will look for a doc that doesn't exist. The reference should point to COMMAND_INVENTORY.md or src/cli/AGENTS.md, both of which are introduced in this PR and describe the allowed import rules.

Suggested change
"'{{transport}}'-tagged CLI command imports forbidden module '{{source}}'. See DESIGN.md §3.1 for allowed imports.",
"'{{transport}}'-tagged CLI command imports forbidden module '{{source}}'. See src/cli/AGENTS.md for allowed imports.",
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Single `registerCommand({ transport: "ipc", ... })` call
- One `cliIpcCall` per subcommand action
- Table output with `--json` flag alternative
- Clean error handling via `exitFromIpcResult`
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.

🟡 AGENTS.md canonical example claims pending.ts uses exitFromIpcResult but it doesn't

The newly added canonical example section in assistant/src/cli/AGENTS.md:54 states pending.ts uses "Clean error handling via exitFromIpcResult", but pending.ts never imports or calls exitFromIpcResult — it uses manual log.error() + process.exitCode = 1 instead. No command file under src/cli/commands/ uses exitFromIpcResult. Since AGENTS.md is a mandatory instruction file, agents following this guidance to model new commands after pending.ts will look for a pattern that doesn't exist in the reference implementation.

Suggested change
- Clean error handling via `exitFromIpcResult`
- Clean error handling via `log.error` + `process.exitCode = 1`
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread assistant/src/cli/commands/status.ts Outdated
const workspace = getWorkspaceDirDisplay();
process.stdout.write((socketExists ? "Assistant: running" : "Assistant: down") + "\n");
process.stdout.write(`Workspace: ${workspace}\n`);
process.exit(0);
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.

🚩 status.ts behavioral change: exit(1) → exit(0) on daemon-down

The old status.ts called process.exit(1) when the daemon was unreachable, making assistant status fail when the daemon was down. The new code at line 36 calls process.exit(0) with a "down"/"running" status message instead. This is an intentional design change (tested at assistant/src/cli/commands/__tests__/status.test.ts:152-158), but it changes the exit code contract for any scripts or CI pipelines that use assistant status as a daemon health check. The use of process.exit(0) instead of process.exitCode = 0; return; also skips any Commander cleanup, though this is unlikely to matter for a status command.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 6 to 8
import { McpClient } from "../../mcp/client.js";
import { deleteMcpOAuthCredentials } from "../../mcp/mcp-oauth-provider.js";
import { openInHostBrowser } from "../../util/browser.js";
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.

🚩 Several ipc-tagged commands import daemon-internal modules beyond the allowlist

mcp.ts (tagged ipc) imports ../../mcp/client.js, ../../mcp/mcp-oauth-provider.js, and ../../util/browser.js — these are daemon-internal modules. browser.ts imports ../../browser/operations.js and ../../browser/types.js. memory-v2.ts imports types from ../../runtime/routes/memory-v2-routes.js. These would all be flagged as forbiddenImport warnings. The COMMAND_INVENTORY.md acknowledges mcp touches config directly, but the others are labeled THIN despite importing daemon internals. Since the rule is warn, this is tolerable during migration but the inventory's THIN labels may be misleading for browser and mcp.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Cycle 1 fixes for PR #30159 review feedback:

1. Allowlist gap (Codex P2 / Devin 🟡):
   Add `../logger` and `../output` to `local` and `bootstrap` allowlists
   in `cli-no-daemon-internals.js`. Without this, every newly tagged
   `local` command (autonomy, config, completions, keys,
   credential-execution) false-positives on its standard logger/output
   imports, killing the rule's signal-to-noise ratio.

2. Doc reference (Devin 🟡):
   `forbiddenImport` error message pointed to nonexistent `DESIGN.md
   §3.1`. Now points to `src/cli/AGENTS.md` which is the actual shipped
   reference.

3. Target glob too broad (Codex P2):
   The rule fired `missingTransport` on every file under
   `src/cli/commands/**/*.ts` including helper modules like
   `oauth/shared.ts` that aren't command registrars. Narrowed by making
   the rule skip files that don't call `registerCommand` directly (now a
   tri-state `findTransport`: `string` for tagged, `MISSING_TRANSPORT`
   for registrars without transport prop, `null` for non-registrars).
   Helper modules pass silently. Backdoor closed because helpers can't
   be imported via blessed paths anyway (sibling `./helper.js` doesn't
   match any allowlist prefix).

4. Type-only imports (extends Codex P2 #1):
   `import type {...}` is erased at compile time and doesn't constitute
   a runtime boundary violation. Rule now skips type-only imports.
   Drops 3 false-positives on `memory-v2.ts` and `mcp.ts` type imports
   from runtime/routes/.

5. Canonical-example claim (Devin 🟡):
   `AGENTS.md` claimed `pending.ts` uses `exitFromIpcResult` but it
   didn't. Migrated `pending.ts` to actually use the helper added in
   Section A. Now matches the doc.

6. mcp.ts misclassification (Devin 🚩):
   `mcp.ts` was marked `THIN` in COMMAND_INVENTORY but imports
   `mcp/client.js`, `mcp/mcp-oauth-provider.js`, `util/browser.js` —
   actual daemon internals. Reclassified to `LEGACY` with a note that
   Section C/D will thin it. Until then the advisory rule will warn on
   this file (and that's the right signal).

Lint: 18 warnings remain (down from 21) on partially-migrated commands
(config, keys, credential-execution, status, task, mcp). All are
legitimate signals — those files have non-allowlisted imports that
need migration before Section J flips the rule from advisory → error.

Tests: rule test suite extended with helper-module + type-only +
local-with-logger regression cases; 5/5 manual smoke tests pass; tsc
clean; lint:inventory passes.
@credence-the-bot
Copy link
Copy Markdown
Contributor Author

credence-the-bot Bot commented May 10, 2026

Cycle 1 fixes pushed (bb15a8c0b)

Addressing all 7 review findings from Codex and Devin:

# Source Finding Fix
1 Codex P2 + Devin 🟡 local/bootstrap allowlists missing ../logger/../output Added both to allowlists
2 Devin 🟡 forbiddenImport referenced nonexistent DESIGN.md §3.1 src/cli/AGENTS.md
3 Codex P2 Rule applied to non-registrar helpers (e.g. oauth/shared.ts) Skip files without registerCommand call
4 (extends #3) Type-only imports false-positived Skip importKind === "type" imports
5 Devin 🟡 AGENTS.md claimed pending.ts uses exitFromIpcResult but it didn't Migrated pending.ts to actually use it
6 Devin 🚩 mcp.ts tagged THIN but imports daemon internals Reclassified THINLEGACY in COMMAND_INVENTORY w/ note
7 Devin 🚩 status.ts exit-code change is intentional but breaking for scripts Added release-note section to PR body w/ --json migration recipe

State after cycle 1: 0 lint errors, 18 advisory warnings (was 21) — all on legitimately partially-migrated commands (config, keys, credential-execution, status, task, mcp), which is the rule's intended signal-vs-noise. CI 8/8 ✅ on bb15a8c0b.

@codex review
@devin review

@credence-the-bot
Copy link
Copy Markdown
Contributor Author

Re-tagging with the right handles (sorry, was using bot account names instead of trigger handles):

@codex review
@devin review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bb15a8c0bc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +85 to +88
case "CallExpression":
for (const arg of node.arguments) {
worklist.push(arg);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Traverse call callees when detecting registerCommand usage

The AST walk only enqueues CallExpression.arguments and never the callee, so chained patterns like registerCommand(...).command(...) are treated as if no registerCommand call exists. In that case findTransport() returns null, and the rule skips all checks, allowing forbidden runtime imports and missing transport tags to pass silently in command-entry files that use chaining.

Useful? React with 👍 / 👎.

Comment on lines +179 to +183
// `import type {...}` and `import { type X }` are erased at compile
// time — they don't ship in the bundle and don't constitute a
// runtime boundary violation. Skip them.
if (importNode.importKind === "type") {
continue;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Skip inline type-only imports in transport import checks

The rule claims to ignore both import type {...} and import { type X } ..., but it only checks importNode.importKind === "type". For inline type specifiers, importKind remains "value" at the declaration level, so these imports are still linted and incorrectly reported as forbidden. This creates false positives for type-only route/model imports and undermines the migration signal quality.

Useful? React with 👍 / 👎.

… inline-type imports

Codex P2 (cli-no-daemon-internals.js:88) — traverse callees:
The AST walk only enqueued CallExpression.arguments, never the callee.
Chained patterns like `registerCommand({...}).command(...).description(...)`
were treated as if no registerCommand call existed (findTransport returned
null), silently skipping all checks for those command-entry files.
Fix: enqueue node.callee on CallExpression and node.object on
MemberExpression so the walk reaches through the receiver chain.

Codex P2 (cli-no-daemon-internals.js:183) — inline type-only specifiers:
The rule only checked importNode.importKind === "type", which catches
`import type {...}` but not `import { type X }` — for the inline form
the declaration's importKind stays "value" and each ImportSpecifier
carries its own importKind. All-type-only inline imports are erased at
compile time and must not flag forbidden-import.
Fix: also skip when every specifier is an ImportSpecifier with
importKind === "type". Side-effect-only imports (no specifiers) and
mixed value+type imports still get linted.
@credence-the-bot
Copy link
Copy Markdown
Contributor Author

Cycle 2 fix push — commit d4c9d000c

Addressing both Codex P2 findings on cycle-1 commit bb15a8c0bc.

Codex P2 #1 — chained registerCommand walk (cli-no-daemon-internals.js:88)

The AST walk only enqueued CallExpression.arguments, never the callee. Chained patterns like registerCommand({...}).command(...).description(...) were treated as if no registerCommand call existed — findTransport() returned null and the rule skipped all checks for those command-entry files.

Fix: enqueue node.callee on CallExpression and node.object on MemberExpression so the walk reaches through the receiver chain.

Codex P2 #2 — inline type-only specifiers (cli-no-daemon-internals.js:183)

The rule only checked importNode.importKind === "type", which catches import type { X } but not import { type X } — for the inline form the declaration's importKind stays "value" and each ImportSpecifier carries its own importKind. All-type-only inline imports are erased at compile time and must not flag.

Fix: also skip when every specifier is an ImportSpecifier with importKind === "type". Side-effect-only imports (import "x" — empty specifier list) and mixed value+type imports still get linted, which matches the rule's intent.

Test fixtures

Added two new valid cases in eslint-rules/__tests__/cli-no-daemon-internals.test.ts:

  1. import { type MemoryV2Result, type ScoreBreakdown } from a non-allowlisted source — must NOT flag.
  2. registerCommand({...}).command(...).description(...) chain in an ipc-tagged file — must apply ipc allowlist correctly.

I also validated 7 cases (4 valid + 3 invalid) via a local RuleTester driver — all pass. The 3 invalid cases include: forbidden runtime import in a chained registerCommand, mixed { value, type X } import (value triggers flag), and side-effect-only import outside the allowlist (still flagged).

Note on rule-test wiring (out-of-scope follow-up)

The rule tests live at assistant/eslint-rules/__tests__/ but the CI test sweep (assistant/scripts/test.sh) only walks src/, so they don't actually run in CI today. Worth a follow-up to extend the sweep — but that's a larger plumbing change (preload + bunfig) and is orthogonal to the review findings here. Filing as a separate JARVIS ticket if desired.

Local verification

  • bun run lint clean (0 errors, 18 warnings — same partially-migrated commands flagged as cycle-1)
  • bunx tsc --noEmit clean
  • Standalone RuleTester driver passes 4 valid + 3 invalid fixtures incl. both new edge cases.

@codex review
@devin review

@credence-the-bot
Copy link
Copy Markdown
Contributor Author

Cycle 2 commit d4c9d000c addressed both Codex P2 findings on the cycle-1 commit. CI 7/7 green.

@codex review
@devin review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4c9d000ca

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread assistant/src/cli/commands/status.ts Outdated
Comment on lines +30 to +36
if (!result.ok || !result.result) {
const socketPath = getAssistantSocketPath();
const socketExists = existsSync(socketPath);
const workspace = getWorkspaceDirDisplay();
process.stdout.write((socketExists ? "Assistant: running" : "Assistant: down") + "\n");
process.stdout.write(`Workspace: ${workspace}\n`);
process.exit(0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Distinguish daemon-down from other IPC failures

Only daemon-unreachable cases should be normalized to a successful status result, but this branch catches every !result.ok and every missing-body response and then exits 0. That masks real failures (e.g. daemon reachable but health returns an internal error or malformed payload) as a healthy command execution, so scripts can report success while the assistant is actually unhealthy. Restrict the zero-exit fallback to connection-level errors (e.g. ENOENT/ECONNREFUSED) and keep non-connection IPC failures as non-zero.

Useful? React with 👍 / 👎.

@credence-the-bot
Copy link
Copy Markdown
Contributor Author

Cycle 3 — `a275ce18e`

Finding addressed (Codex P2 · status.ts:36): Narrow zero-exit fallback to genuine daemon-unreachable cases only.

What changed

`status.ts` — Split the !result.ok branch:

  • Connection-level errors (error string starts with "Could not connect to the assistant at " — the exact prefix produced by ENOENT/ECONNREFUSED/connect-timeout in `cliIpcCall`) → show "Assistant: down/running" + exit 0
  • All other failures (daemon-side error with `statusCode`, framing errors, "Connection closed before response", abort) → print error to stderr + exit 1
  • `ok=true` but missing body → "health check returned empty response" to stderr + exit 1

`status.test.ts` — 9 tests (was 4):

  • Updated mock error strings to match what `cliIpcCall` actually produces
  • Added 4 new cases covering non-connection failures (internal error, early close, empty body)

Mapping

Scenario Before After
ENOENT/ECONNREFUSED/connect-timeout exit 0 ✓ exit 0 ✓
Daemon internal error (statusCode 500) exit 0 ✗ exit 1 ✓
Connection closed before response exit 0 ✗ exit 1 ✓
`ok=true` but missing body exit 0 ✗ exit 1 ✓

@codex review @devin review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

…on-tags-lint

# Conflicts:
#	assistant/src/cli/commands/memory-v2.ts
@credence-the-bot
Copy link
Copy Markdown
Contributor Author

Merged main → branch (57745372e)

origin/main had moved past the branch base and the rebase tripped on memory-v2.ts (PR #30146 dropped four dormant subcommands; the rollup branch was still wrapping them with registerCommand).

Resolution:

Verified locally:

  • bun run typecheck
  • bun run lint ✅ (0 errors; 18 pre-existing warnings unchanged)
  • bun run lint:inventory ✅ (in sync with 58 commands)
  • bun test memory-v2.test.ts ✅ (15/15)
  • bun test status.test.ts ✅ (9/9)
  • bun test register-command.test.ts ✅ (7/7)
  • Format: prettier --write applied to the two touched files

Awaiting CI green + reviewer signal.

@noanflaherty noanflaherty merged commit 4b31ef9 into main May 10, 2026
13 checks passed
@noanflaherty noanflaherty deleted the credence/cli-foundation-tags-lint branch May 10, 2026 13:53
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.

3 participants