Skip to content

refactor(cli): convert debug subcommands to effectCmd#25479

Merged
kitlangton merged 1 commit intodevfrom
kit/cli-effectify-debug
May 2, 2026
Merged

refactor(cli): convert debug subcommands to effectCmd#25479
kitlangton merged 1 commit intodevfrom
kit/cli-effectify-debug

Conversation

@kitlangton
Copy link
Copy Markdown
Contributor

@kitlangton kitlangton commented May 2, 2026

Summary

Batch-convert 6 debug commands (17 subcommands total) from `cmd()` + `bootstrap()` to `effectCmd` + `Effect.ensuring(store.dispose(ctx))`.

Files:

  • `debug/config.ts`
  • `debug/skill.ts`
  • `debug/snapshot.ts` (3 subcommands: track / patch / diff)
  • `debug/lsp.ts` (3 subcommands: diagnostics / symbols / document-symbols)
  • `debug/ripgrep.ts` (3 subcommands: tree / files / search)
  • `debug/file.ts` (5 subcommands: search / read / status / list / tree)

The parent group commands (snapshot/lsp/rg/file) stay on `cmd()` since they only dispatch to subcommands and don't run handler logic.

Behavioral notes (two parallel subagent purity audits)

Both reviews verdict: BEHAVIORALLY EQUIVALENT for success and ordinary failure paths; STRICTLY SAFER under interruption (Effect.ensuring covers it; legacy try/finally didn't).

Real semantic deltas (consistent with established `models.ts` precedent):

  1. No `InstanceBootstrap` run — legacy `bootstrap()` eagerly ran `config.get()` + `plugin.init()` (and forked LSP/File/etc init) before the body. `effectCmd` skips this; services lazy-init on first use. For `debug config` this could surface the raw unmodified config (plugin `config()` hooks haven't run). Same shape as `models.ts`.
  2. `Effect.orDie` on Ripgrep typed errors (3 sites in ripgrep.ts, 1 site in file.ts/tree) — the underlying error still surfaces with non-zero exit through the same top-level handler, but defect formatting may differ slightly from a directly-thrown typed error. Cosmetic only.

Followup (not in this PR)

Both agents flagged the 14× repeated `const ctx = yield* InstanceRef; if (!ctx) return; const store = yield* InstanceStore.Service; return yield* body.pipe(Effect.ensuring(store.dispose(ctx)))` boilerplate. Strong suggestion: fold `Effect.ensuring(store.dispose(ctx))` into `effectCmd` itself so per-command disposal is automatic. Worth a separate PR before this pattern spreads further.

Test plan

  • `bun run typecheck`
  • `bun run test test/cli/` — 137 pass
  • Smoke: `debug config` prints config JSON
  • Smoke: `debug skill` prints skill list

Convert 6 debug commands (and 17 of their subcommands) from
cmd() + bootstrap() to effectCmd + Effect.ensuring(store.dispose(ctx)).

Files:
- debug/config.ts
- debug/skill.ts
- debug/snapshot.ts (3 subcommands)
- debug/lsp.ts (3 subcommands)
- debug/ripgrep.ts (3 subcommands)
- debug/file.ts (5 subcommands)

The parent group commands (snapshot/lsp/rg/file) stay on cmd() since they
just dispatch to subcommands and don't run any handler logic.

Service calls with typed errors (Ripgrep.tree/files/search) now use
Effect.orDie to satisfy effectCmd's E=CliError handler signature.
Instance.directory references switched to ctx.directory from InstanceRef.
@kitlangton kitlangton merged commit 4de44bb into dev May 2, 2026
15 checks passed
@kitlangton kitlangton deleted the kit/cli-effectify-debug branch May 2, 2026 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant