feat(cli): add managed daemon commands - #55
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueComment |
| throw error; | ||
| return realpathSync.native(entry) === realpathSync.native(fileURLToPath(import.meta.url)); | ||
| } catch { | ||
| return false; |
There was a problem hiding this comment.
isExecutableEntry() silently disables the whole CLI if realpathSync.native throws. The old index.ts always invoked main() unconditionally; now, on an install layout where process.argv[1] can't be realpath-resolved (ENOENT/EACCES, an unusual global-install symlink chain, or the bin file briefly missing during an atomic npm install), the catch swallows the error and this returns false. dispatchCli() is then never called, process.exitCode stays at its default 0, and the CLI silently does nothing instead of running the command or reporting an error.
No test exercises this exception path — index.test.ts only covers the "import as module" and "symlink success" cases. Consider at least logging/exiting non-zero when the realpath comparison throws, rather than treating it the same as "this is not the entry module."
| export function usageText(): string { | ||
| return [ | ||
| "", | ||
| " Magic Context CLI", | ||
| " -----------------", | ||
| "", | ||
| " Commands:", | ||
| " setup Interactive setup wizard", | ||
| " doctor Check and fix configuration issues", | ||
| " daemon start Start the managed mc-host", | ||
| " daemon stop Stop the managed mc-host", | ||
| " daemon restart Restart the managed mc-host as one transaction", | ||
| " daemon status Show lifecycle and readiness state without mutation", | ||
| " daemon doctor Run read-only lifecycle diagnostics", | ||
| "", | ||
| " Daemon output:", | ||
| " --json Emit one magic-context.daemon/v1 JSON object", | ||
| "", | ||
| " Doctor options:", | ||
| " doctor --force Force-clear plugin cache", | ||
| " doctor --issue Collect diagnostics and open a GitHub issue", | ||
| " doctor --clear Interactive cache cleanup picker", | ||
| " doctor --check-v22-backfill Show v22 memory backfill status", | ||
| " doctor --retry-v22-backfill Retry failed v22 memory backfill rows", | ||
| " doctor --rekey-v22-dir-identity <path> Re-key legacy dir identity rows", | ||
| " doctor --check-claims-backfill Show v84 claims backfill status", | ||
| " doctor --retry-claims-backfill Repair and resume the v84 claims backfill", | ||
| ' doctor --waive-claims-backfill-failure <id> --rationale "<why>"', | ||
| " doctor drain-authority <project> Drain module memory/note authority to TypeScript", | ||
| " doctor migrate Migrate OpenCode session to Pi or OMP JSONL", | ||
| " doctor migrate-session Re-home an OpenCode session to another directory", | ||
| " doctor merge-identity Merge project rows (--from ID --to ID [--dry-run] [--yes])", | ||
| " doctor repair-db Back up and salvage a corrupted shared database", | ||
| "", | ||
| " Harness selection:", | ||
| " --harness opencode Target OpenCode only", | ||
| " --harness pi Target Pi only", | ||
| " --harness omp Target Oh My Pi (OMP) only", | ||
| " (default: auto-detect, prompt if multiple installed)", | ||
| "", | ||
| " Usage:", | ||
| " npx @cortexkit/magic-context@latest setup", | ||
| " npx @cortexkit/magic-context@latest doctor", | ||
| " npx @cortexkit/magic-context@latest daemon status --json", | ||
| "", | ||
| ].join("\n"); | ||
| } |
There was a problem hiding this comment.
usageText() regresses --help output vs. the previous printUsage() in index.ts. Several lines present in the old implementation are missing here:
- the
--dry-runtip undersetup("add--dry-runto preview the wizard without writing any files") - the
doctor --issueusage example - the two-line
doctor migrate --from opencode --to <pi|omp> --session ses_xxx --dry-runexample - the trailing "Waive a reviewed lineage failure" description after the
--waive-claims-backfill-failure <id> --rationale "<why>"line (now cut off mid-sentence at line 72)
index.test.ts only asserts daemon actions and --json appear in the help text, so this regression isn't caught by tests. Worth restoring for parity, or confirming the drop was intentional.
| const redacted = redactResult(result, dependencies.env); | ||
| dependencies.stdout(parsed.json ? JSON.stringify(redacted) : renderDaemonHuman(redacted)); |
There was a problem hiding this comment.
redactResult() and the stdout/renderDaemonHuman() call run outside the try block above (lines 136-144), which is the block that's supposed to guarantee "bounded stderr, no partial output" on failure (see the daemon.test.ts case "policy exceptions produce bounded stderr without a partial v1 object"). That guarantee is only tested for createPolicy/invoke throwing — if redactResult → sanitizeDiagnosticText ever throws (e.g. a future contract change or alternate DaemonPolicy implementation returns a versions field that isn't strictly string | null), the error propagates uncaught out of runDaemonCommand instead of hitting the bounded-stderr path.
Might be worth extending the try to cover redaction + rendering as well, so the "no partial/unredacted output" contract holds for the whole function, not just the policy call.
Review summaryReviewed
No security concerns beyond #3 (which is about failure-mode robustness, not an exploitable issue) — the redaction/sanitization approach for daemon output looks sound, and the SQLite-preflight bypass for daemon commands is scoped correctly ( |
Summary
magic-context.daemon/v1JSON and human renderingStack
PR 8 of 10. Base:
stack/mc-host-07-plugin-demand.Validation
Post-Deploy Monitoring & Validation
Watch command exit codes and reason/effect distributions for one release cycle. Roll back if status/doctor mutate state, JSON shape drifts, or restart effects disagree with observed lifecycle state. Owner: CLI maintainers.