Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .seeds/issues.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,6 @@
{"id":"seeds-e294","title":"Migrate suggestions/timing/completions tests off subprocess spawn to in-process runCli","status":"closed","type":"task","priority":3,"plan_step_index":2,"description":"<!-- seeds:plan-backref:start -->\nStep 3 of plan pl-c94f.\n\nParent seed: seeds-a644 — nightwatch patrol: 2026-06-30\nPlan template: refactor\nPlan approach: Four independent small PRs. Each is a single-concern hygiene fix with co-located test updates. Land in any order; the optional release step gathers the trio of consumer-observable changes (error formatting, plan-show human render,…\n\nRun `sd plan show pl-c94f` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-30T11:06:02.417Z","updatedAt":"2026-06-30T11:24:46.729Z","labels":["nightwatch"],"plan_id":"pl-c94f","blocks":["seeds-a644"],"closedAt":"2026-06-30T11:24:46.729Z"}
{"id":"seeds-a024","title":"store.ts: write '' (not '\\n') when rewriting an empty issues/templates/plans list","status":"closed","type":"task","priority":3,"plan_step_index":3,"description":"<!-- seeds:plan-backref:start -->\nStep 4 of plan pl-c94f.\n\nParent seed: seeds-a644 — nightwatch patrol: 2026-06-30\nPlan template: refactor\nPlan approach: Four independent small PRs. Each is a single-concern hygiene fix with co-located test updates. Land in any order; the optional release step gathers the trio of consumer-observable changes (error formatting, plan-show human render,…\n\nRun `sd plan show pl-c94f` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-30T11:06:02.417Z","updatedAt":"2026-06-30T11:28:26.034Z","labels":["nightwatch"],"plan_id":"pl-c94f","blocks":["seeds-d92f","seeds-a644"],"closedAt":"2026-06-30T11:28:26.034Z"}
{"id":"seeds-d92f","title":"Release: run /release per .claude/commands/release.md","status":"closed","type":"task","priority":3,"plan_step_index":4,"description":"<!-- seeds:plan-backref:start -->\nStep 5 of plan pl-c94f.\n\nParent seed: seeds-a644 — nightwatch patrol: 2026-06-30\nPlan template: refactor\nPlan approach: Four independent small PRs. Each is a single-concern hygiene fix with co-located test updates. Land in any order; the optional release step gathers the trio of consumer-observable changes (error formatting, plan-show human render,…\n\nRun `sd plan show pl-c94f` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-30T11:06:02.417Z","updatedAt":"2026-06-30T11:31:11.668Z","labels":["nightwatch"],"plan_id":"pl-c94f","blocks":["seeds-a644"],"closedAt":"2026-06-30T11:31:11.668Z"}
{"id":"seeds-ed7e","title":"nightwatch patrol: 2026-07-17","status":"open","type":"task","priority":3,"createdAt":"2026-07-17T22:02:14.492Z","updatedAt":"2026-07-17T22:02:40.995Z","labels":["patrol","nightwatch"],"plan_id":"pl-dcda","blockedBy":["seeds-5286","seeds-37ae"]}
{"id":"seeds-5286","title":"Render plan suffix in `sd blocked` plain/default output","status":"open","type":"bug","priority":2,"plan_step_index":0,"description":"<!-- seeds:plan-backref:start -->\nStep 1 of plan pl-dcda.\n\nParent seed: seeds-ed7e — nightwatch patrol: 2026-07-17\nPlan template: refactor\nPlan approach: In `src/commands/blocked.ts`, mirror the plan-suffix rendering used by `list.ts` and `ready.ts`: in the `plain` branch, replace `console.log(stripAnsi(formatIssueOneLine(issue, closedIds)))` with…\n\nRun `sd plan show pl-dcda` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-07-17T22:02:40.995Z","updatedAt":"2026-07-17T22:02:40.995Z","labels":["nightwatch"],"plan_id":"pl-dcda","blocks":["seeds-37ae","seeds-ed7e"]}
{"id":"seeds-37ae","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":1,"description":"<!-- seeds:plan-backref:start -->\nStep 2 of plan pl-dcda.\n\nParent seed: seeds-ed7e — nightwatch patrol: 2026-07-17\nPlan template: refactor\nPlan approach: In `src/commands/blocked.ts`, mirror the plan-suffix rendering used by `list.ts` and `ready.ts`: in the `plain` branch, replace `console.log(stripAnsi(formatIssueOneLine(issue, closedIds)))` with…\n\nRun `sd plan show pl-dcda` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-07-17T22:02:40.995Z","updatedAt":"2026-07-17T22:02:40.995Z","labels":["nightwatch"],"plan_id":"pl-dcda","blockedBy":["seeds-5286"],"blocks":["seeds-ed7e"]}
1 change: 1 addition & 0 deletions .seeds/plans.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
{"id":"pl-a786","seed":"seeds-2718","template":"refactor","status":"done","revision":1,"sections":{"context":"Nightwatch patrol on 2026-06-16 found three small consistency gaps. (1) sd list/search accept arbitrary --status values and sd list/search/ready accept arbitrary --type values without validation — invalid input silently filters to an empty result instead of erroring the way sd create/update/tpl/plan do (cf. src/commands/update.ts:87-88 for --status, src/commands/update.ts:117-118 for --type). (2) src/index.ts:194 emits the unknown-command JSON error via raw writeStdout(JSON.stringify(payload, null, 2)) instead of routing through outputJson(payload) like every other JSON output site. (3) src/index.ts declares `const jsonMode = process.argv.includes(\"--json\")` *after* the `main()` function definition even though main() reads jsonMode through closure — a TDZ-fragile ordering that should be hoisted above main(). All other gates are green (bun test 993/993, bun run check:all 9/9).","behavior_invariant":"Existing valid invocations of sd list/search/ready and the unknown-command JSON error path must keep emitting byte-identical output. Specifically: (a) sd list/search/ready with valid --status (open|in_progress|closed) and valid --type (task|bug|feature|epic) still pass through unchanged; (b) the unknown-command JSON envelope shape stays { success: false, command, error, suggestion? } with two-space JSON.stringify indentation and a trailing newline; (c) all 993 existing tests in bun test continue to pass; (d) bun run check:all stays 9/9.","approach":"Surgical edits, no architecture changes. Each step is a single small PR that mirrors an existing pattern already in the codebase (the same validation idiom used by sd update, the same outputJson() helper used by every command). Keep the new --status / --type error messages in the same `Invalid --<flag> value: X. Valid: a|b|c` shape as src/commands/update.ts so the wording stays uniform across the CLI surface.","steps":[{"title":"Validate --status and --type values in sd list, search, and ready","type":"bug","priority":2,"labels":["nightwatch"],"blocks":[3]},{"title":"Tidy src/index.ts unknown-command JSON path: use outputJson() and hoist jsonMode declaration above main()","type":"task","priority":3,"labels":["nightwatch"],"blocks":[3]},{"title":"Release: run /release per .claude/commands/release.md","type":"task","priority":2,"labels":["nightwatch"],"blocks":[]}],"acceptance":["bun test passes (>=993 tests, 0 failures)","bun run check:all is 9/9","sd list --status bogus, sd list --type bogus, sd search foo --status bogus, sd search foo --type bogus, sd ready --type bogus all exit 1 with `Invalid --<flag> value: bogus. Valid: ...` on stderr (and a {success:false, command, error} JSON envelope under --json)","Each updated command has at least one test covering the new validation failure on both human and --json output","Unknown-command JSON path in src/index.ts goes through outputJson() and `jsonMode` is declared above the `main()` function"]},"children":["seeds-d305","seeds-e93c","seeds-47c1"],"createdAt":"2026-06-16T11:07:52.499Z","updatedAt":"2026-06-16T11:20:00.484Z","name":"nightwatch patrol fixes 2026-06-16"}
{"id":"pl-611d","seed":"seeds-cfc7","template":"feature","status":"approved","revision":1,"sections":{"context":"`sd plan list --status <s>` only does an exact status match, so there is no way to ask for \"every plan except done\". Plan status is derived from children in src/plan-lifecycle.ts (draft | approved | active | done; done means all children closed). Agents and humans need a one-shot view of plans that still have work, i.e. status !== \"done\". This adds `sd plan ready` to fill that gap, mirroring the existing `sd plan list` filters and output.","approach":"Add a `plan ready` subcommand in src/commands/plan.ts that reads plans, filters to status !== \"done\" (strictly not-done; draft/approved/active all shown), applies the same passthrough filters as `plan list` (--seed, --template, --outcome) plus --json, sorts newest-first, and renders via a shared output helper extracted from runList so `plan ready` and `plan list` stay byte-identical in format. Chosen over adding a `--not-done`/negation flag to `plan list` because a named `ready` verb mirrors the top-level `sd ready` mental model and keeps `plan list` filters purely positive/exact. Documentation and a patch release close out the plan.","steps":[{"title":"Extract shared plan-list rendering helper in src/commands/plan.ts","type":"task","priority":2,"blocks":[2],"labels":["plan-ready"]},{"title":"Implement and register `sd plan ready` (status !== done) in src/commands/plan.ts","type":"feature","priority":2,"blocks":[3,4],"labels":["plan-ready"]},{"title":"Add tests for `sd plan ready` covering not-done filter, passthrough filters, --json, and empty case","type":"task","priority":2,"blocks":[5],"labels":["plan-ready"]},{"title":"Document `sd plan ready` in CLAUDE.md, AGENTS.md, sd prime, and CHANGELOG [Unreleased]","type":"task","priority":2,"blocks":[5],"labels":["plan-ready"]},{"title":"Run .claude/commands/release.md flow with a patch version bump","type":"task","priority":2,"blocks":[],"labels":["plan-ready"]}],"acceptance":["`sd plan ready` lists plans with status draft, approved, or active, and excludes status done.","`sd plan ready --json` returns the same shape as `sd plan list --json` (success, command, plans, count).","`sd plan ready` honors --seed, --template, and --outcome passthrough filters and sorts newest-first.","`sd plan list` human + JSON output is unchanged (byte-identical) after the shared-helper extraction.","bun run check:all passes and a patch release is cut via the release flow."]},"children":["seeds-03f2","seeds-25de","seeds-80eb","seeds-347c","seeds-8b2c"],"createdAt":"2026-06-20T19:08:27.726Z","updatedAt":"2026-06-20T19:08:27.726Z","name":"sd plan ready"}
{"id":"pl-c94f","seed":"seeds-a644","template":"refactor","status":"done","revision":1,"sections":{"context":"Code-patrol scan of the seeds repo on 2026-06-30. All quality gates pass (lint, typecheck, 1009 tests, check:all 9/9). The scan surfaced four small hygiene issues: (1) error-printing inconsistency — src/output.ts:62 defines printError() with a red-✗ prefix but only src/commands/onboard.ts uses it; every other command (list, ready, show, search, stats, blocked, sync, completions, plan) emits inline validation errors via bare console.error(msg), so the same class of validation error renders differently depending on whether it is thrown to the top-level handler or guarded inline; (2) sd plan show human renderer (src/commands/plan-show.ts renderStepEntry, lines 114-132) only surfaces title/blocks/requires_plan/plan_template and silently drops type, priority, labels, existing_seed — even though those fields are first-class in STEP_SCHEMA and present in the --json output (mulch records mx-a2e5b4, mx-4ade46, mx-444e00 document the labels/type/priority surfaces but the human render was never updated); (3) test-spawning convention drift — mulch record mx-39215e (cli-smoke-subprocess-coverage) says src/cli-smoke.test.ts is the only test file that intentionally spawns 'bun run', but src/suggestions.test.ts, src/timing.test.ts, and src/commands/completions.test.ts each still spawn subprocesses for cases the in-process harness (src/test-harness.ts runCli/runCliJson) could cover; (4) src/store.ts writeIssues/writeTemplates/writePlans produce a stray '\\n' (single newline byte) when called with an empty array, because the body is `${items.map(...).join('\\n')}\\n`, which yields '\\n' for the empty-array case rather than ''. Result: an empty store rewrite leaves a one-byte file that diffs against an absent or empty file. None of these are introducing new features or changing public API signatures; they are inconsistency/drift fixes in existing surfaces.","behavior_invariant":"After the sweep: (a) every CLI command continues to emit the same JSON envelope shape it does today (success/command/error/issue/issues/plan/plans/count fields unchanged); (b) sd list/sd ready/sd show/sd search/sd stats human stderr output for validation errors becomes consistent (all routed through printError, which prefixes a red ✗) — exit codes unchanged; (c) sd plan show --json output is byte-identical; the human plan show output gains additional dim sub-lines for non-empty step.type, step.priority, step.labels, step.existing_seed but the existing title/blocks/requires_plan/plan_template lines stay byte-identical; (d) store rewrite of an empty list produces '' instead of '\\n', and readIssues/readTemplates/readPlans round-trip '' to [] (existing behavior, covered by parseJsonl skipping blank lines); (e) suggestions/timing/completions tests assert the same observable behavior post-migration. bun test, bun run lint, bun run typecheck, and bun run check:all all stay green.","approach":"Four independent small PRs. Each is a single-concern hygiene fix with co-located test updates. Land in any order; the optional release step gathers the trio of consumer-observable changes (error formatting, plan-show human render, empty-store rewrite) into one batched announcement. Test-migration step (3) is internal-only and does not require a release.","steps":[{"title":"Route inline validation errors through printError across command modules","type":"task","priority":3,"blocks":[5],"labels":["nightwatch"]},{"title":"sd plan show: surface step.type, priority, labels, existing_seed in human render","type":"task","priority":3,"blocks":[5],"labels":["nightwatch"]},{"title":"Migrate suggestions/timing/completions tests off subprocess spawn to in-process runCli","type":"task","priority":3,"blocks":[],"labels":["nightwatch"]},{"title":"store.ts: write '' (not '\\n') when rewriting an empty issues/templates/plans list","type":"task","priority":3,"blocks":[5],"labels":["nightwatch"]},{"title":"Release: run /release per .claude/commands/release.md","type":"task","priority":3,"blocks":[],"labels":["nightwatch"]}],"risks":["Step 1 changes user-visible stderr text (adds a red ✗ glyph and color) for validation errors — downstream tests that grep stderr exactly may need updating. Mitigation: scan src/**/*.test.ts for exact-match stderr assertions and adjust to substring/regex.","Step 2 changes user-visible human plan-show output. Mitigation: update src/commands/plan-show.test.ts to assert the new sub-lines; keep --json contract untouched (the test already exercises --json shape).","Step 4 changes on-disk byte content for an edge case (empty list rewrite). Mitigation: src/store.test.ts already asserts trailing-newline behavior for non-empty writes — add a parallel test for the empty case and verify roundtrip readIssues([]) → [].","Step 3 is test-only but uses the in-process harness, which builds a fresh commander program per call (mx-a76d9e); confirm the --timing hook still fires under runCli (it should — preAction/postAction hooks are registered before .parseAsync)."],"acceptance":["bun run check:all passes 9/9 gates after every step lands.","bun test: 1009+ tests pass; new assertions cover (a) printError formatting for at least one validation error per migrated command, (b) human plan-show shows type/priority/labels/existing_seed when present, (c) writeIssues/writeTemplates/writePlans with [] produce '' on disk, (d) the three migrated test files no longer reference Bun.spawn/bun run CLI.","grep for 'Bun.spawn' across src/**/*.test.ts returns only src/cli-smoke.test.ts and src/commands/plan*.test.ts (the documented exception per mx-39215e) plus subprocess-only sync.test.ts git invocations.","sd plan show --json output diffed before/after step 2 is byte-identical for a representative pl-* id.","If the release step runs: CHANGELOG.md gains a Fixed section noting the error-formatting, plan-show, and empty-store-rewrite changes; version bumped via bun run version:bump patch."]},"children":["seeds-a3e7","seeds-5892","seeds-e294","seeds-a024","seeds-d92f"],"createdAt":"2026-06-30T11:06:02.417Z","updatedAt":"2026-06-30T11:31:11.668Z","name":"nightwatch patrol 2026-06-30 hygiene sweep"}
{"id":"pl-dcda","seed":"seeds-ed7e","template":"refactor","status":"approved","revision":1,"sections":{"context":"Code-patrol scan of the seeds repo on 2026-07-17. All nine quality gates pass (lint, typecheck, agents, dups, deps, size, debt, coverage, ci-parity) and 1019 tests are green. One consumer-observable inconsistency surfaced: `sd blocked` drops the plan-suffix decoration in its plain and default (color) output modes, while every peer list-style command (`sd list`, `sd ready`, `sd search`) attaches `planLineSuffix(plan)` to each rendered issue and passes the suffix through `printIssueOneLine`. Because blocked already calls `loadPlanContext` and threads plan data into JSON output via `issueJsonWithPlan`, the omission is an oversight, not a design choice — it silently hides plan membership for blocked issues from human-readable output only.","behavior_invariant":"`sd blocked` continues to (a) filter to non-closed issues with at least one still-open blocker, (b) emit `{success:true,command:\"blocked\",issues,count}` in `--format json` with `issueJsonWithPlan` per row, (c) print `id` per row in `--format ids`, (d) print `formatIssueOneLineCompact(issue, closedIds)` per row in `--format compact`, (e) print a trailing `\\n<n> blocked issue(s)` summary in `plain` and default modes, and (f) print `No blocked issues.` when the result set is empty. Exit codes and JSON envelope shape do not change. Only the plain and default rendered lines gain the plan suffix that peer commands already emit.","approach":"In `src/commands/blocked.ts`, mirror the plan-suffix rendering used by `list.ts` and `ready.ts`: in the `plain` branch, replace `console.log(stripAnsi(formatIssueOneLine(issue, closedIds)))` with `console.log(stripAnsi(formatIssueOneLine(issue, closedIds) + planLineSuffix(planForIssue(planCtx, issue))))`; in the default branch, replace `printIssueOneLine(issue, closedIds)` with `printIssueOneLine(issue, closedIds, planLineSuffix(planForIssue(planCtx, issue)))`. Import `planLineSuffix` from `../plan-context.ts` alongside the existing imports. `ids` and `compact` modes stay untouched (they already match their peers). Extend `src/commands/blocked.test.ts` with a fixture that pours a plan and asserts the plain/default output includes the plan suffix for blocked children (and that JSON output still round-trips).","steps":[{"title":"Render plan suffix in `sd blocked` plain/default output","type":"bug","priority":2,"blocks":[2],"labels":["nightwatch"]},{"title":"Release: run /release per .claude/commands/release.md","type":"task","priority":3,"blocks":[],"labels":["nightwatch"]}],"acceptance":["`bun test src/commands/blocked.test.ts` passes, including a new case that asserts plan-suffix decoration appears on blocked issues that belong to a plan in both plain and default modes.","Manually poured plan whose children include a blocked issue: `sd blocked` prints the same `[plan:<id>]`-style suffix on the blocked row as `sd list` and `sd ready` do for the same issue.","`sd blocked --json` output is byte-identical to pre-change for the same fixture (envelope, issues, count all unchanged).","`bun run check:all` remains green (all nine gates)."]},"children":["seeds-5286","seeds-37ae"],"createdAt":"2026-07-17T22:02:40.995Z","updatedAt":"2026-07-17T22:02:40.995Z","name":"Nightwatch patrol 2026-07-17"}
Loading