chore: archive 463 shipped changeset fragments before wiring render (#714)

CHANGELOG promotion was a manual operator step that was never run, so 463
fragments for work already shipped in <=1.3.1 accumulated in .changeset/.
Their notes were already hand-curated into the dated [1.2.0]/[1.3.0]/[1.3.1]
CHANGELOG sections (#690 backfill, PR #694). Rendering them now would
duplicate and mis-attribute shipped work.

Move them to .changeset/archived/ (read non-recursively by all changeset
tooling, so never rendered), keeping only the 3 genuinely-unreleased
fragments at the top level. Prep for wiring `render` into the release
finalize job (#690 follow-up).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-05 14:53:17 -04:00
committed by GitHub
parent ecc42cefc6
commit 8616839cab
465 changed files with 24 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 150
---
Strategy-branch auto-switch is now skipped when `workflow.use_worktrees` is `false` — the SDK no longer switches the primary branch in single-worktree setups.

View File

@@ -0,0 +1,5 @@
---
type: Security
pr: 113
---
**Scanner now detects malicious markdown link schemes** — `scanForInjection()` previously passed markdown links containing `javascript:`, `data:` (non-image/font), `https://user:pass@host` userinfo credentials, and sensitive query-string key names (`token=`, `api_key=`, etc.) as clean. Four new rules (`MD-LINK-JS-SCHEME`, `MD-LINK-DATA-SCHEME`, `MD-LINK-USERINFO`, `MD-LINK-TOKEN-IN-QUERY`) now flag these patterns in both the scanner and the `gsd-read-injection-scanner.js` hook. The `data:` safe-list permits image and font MIME types; `data:image/svg+xml` is intentionally blocked because SVG can host inline scripts.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 117
---
**Environment bootstrap validator (`npm run check:env`)** — adds `scripts/check-env.sh` which validates Node version, npm version, lockfile presence, lockfile sync, and version-manager pin before test or audit runs. Catches environment mismatches early with structured `--json` output. Companion docs in `docs/contributing/bootstrap.md` cover prerequisites, one-time setup, daily commands, and troubleshooting. CI now runs the environment check after `setup-node` and before `npm ci` on every matrix lane. (#117)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 130
---
Test-mode installs no longer write the opencode config file — `finishInstall` now skips `configureOpencodePermissions` when `GSD_TEST_MODE=1`.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 138
---
`config-get workflow.nyquist_validation` calls in validate-phase and audit-milestone now include `--default true`, preventing stderr noise and fragile empty-variable fallback when the key is absent.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 148
---
The `--auto` flag is now wired through the `/gsd:progress` → `/gsd:next` handoff so that chaining these commands works without requiring the flag to be re-supplied manually.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 142
---
**Runtime aliases now canonicalize through one shared policy module** — runtime identity inputs from `GSD_RUNTIME` and `.planning/config.json` are normalized through a shared alias manifest used by both CJS and SDK paths. This fixes runtime-aware behavior when users set App/CLI variants like `codex-app` or `codex-cli`, and prevents drift between slash-command emission and SDK runtime detection.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 160
---
`/gsd-next` and `/gsd-progress` no longer silently skip partially-executed phases when `current_phase` was advanced past unfinished work. New Route 0 invariant scans all phases for plans without summaries and routes to `/gsd-execute-phase <lowest-numbered>` before any current_phase-based routing decision. Opt out with `--no-resume` to use the existing prior-phase defer prompt instead; `--force` bypasses all gates.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 166
---
**Windows Claude `.sh` hook command serialization** — installer-managed Claude hooks now emit script-only command entries (no explicit `bash.exe` wrapper) for Windows settings hooks, preventing the `bash.exe: ... cannot execute binary file` failure mode reported in SessionStart/PreToolUse hook execution.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 167
---
**`gsd-tools` query meta-command parity** — direct invocations like `node gsd-tools.cjs query init.progress` now behave the same as `node gsd-tools.cjs init.progress` instead of failing with `Unknown command: query`. This unblocks workflow preflight paths that call the CJS entrypoint directly with the `query` prefix.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 170
---
**Workflow fallback install hint migration** — workflow error-path guidance for missing `gsd-sdk` now points to `npx -y @opengsd/get-shit-done-redux@latest --claude --local` instead of the abandoned `get-shit-done-cc` package. Added a regression test to prevent legacy fallback hints from reappearing in workflow markdown.

View File

@@ -0,0 +1,7 @@
---
type: Changed
pr: 176
---
`CommandRoutingHub` P1.2 review findings addressed: Hub now runtime-validates handler-returned `{ ok: false, ... }` results against the typed schema and coerces malformed variants to `HandlerFailure` with a contract-violation message (Finding 1). The catch path wraps non-Error throwables in an Error with `.thrown` attached so the original value is never silently dropped (Finding 2). All four factory functions (`makeUnknownCommand`, `makeInvalidArgs`, `makeHandlerRefusal`, `makeHandlerFailure`) now return `Object.freeze`'d objects to protect the variant invariant (Finding 3). `makeHandlerFailure` validates its `cause` argument and wraps non-Error causes in an Error with `.thrown` so downstream callers can safely access `.cause.stack` (Finding 4).
<!-- docs-exempt: internal refactor — Hub runtime-validation hardening is SDK-internal (ADR-0174 P1.2); no public docs surface affected -->

View File

@@ -0,0 +1,7 @@
---
type: Changed
pr: 176
---
`CommandRoutingHub` error results are now a typed discriminated union (ADR-0174 P1.2). The `errorKind` field is renamed to `kind` and each variant carries only its own typed payload: `UnknownCommand` → `{ kind, command }`; `InvalidArgs` → `{ kind, arg, reason }`; `HandlerRefusal` → `{ kind, reason }`; `HandlerFailure` → `{ kind, message, cause? }`. Factory functions `makeUnknownCommand`, `makeInvalidArgs`, `makeHandlerRefusal`, `makeHandlerFailure` are exported for handler and caller use. The generic `message`/`details` escape hatches are removed from Hub-emitted errors.
<!-- docs-exempt: internal refactor — Hub Result shape is SDK-internal (ADR-0174 P1.2); no public docs surface affected -->

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 177
---
**Observability seam for Hub dispatch (#177)** — the Command Routing Hub now accepts an injected `DispatchLogger`. Default behaviour is silent on success and emits a structured JSON line to stderr on error. Opt-in file audit at `.planning/.gsd-trace.jsonl` is enabled via `GSD_AUDIT=1` env var or `config.audit.enabled: true`. Args are excluded from every emitted event by default (privacy); `GSD_AUDIT_ARGS=1` opts in.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 178
---
**`DispatchEvent` now propagates `parentTraceId` (#178)** — every `DispatchEvent` already carries a `traceId` (P1.3). `Hub.dispatch(req)` now accepts an optional `req.parentTraceId`; when present, it appears on the emitted event. This is the seam through which a future init-composer (Phase 2) will correlate child dispatches with their parent. Backward compatible — leaf dispatches that don't set `parentTraceId` emit events with `parentTraceId: undefined` exactly as in P1.3.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 191
---
Retired the legacy SDK package seam by deleting `sdk/`, removing the `gsd-sdk` shim/bin publishing path, and moving required shared manifests to `get-shit-done/bin/shared` for runtime/install compatibility.

View File

@@ -0,0 +1,6 @@
---
type: Fixed
pr: 192
---
Retired the SDK release pipeline by deleting `release-sdk.yml`, removing SDK-specific steps from release/hotfix/install-smoke workflows, deleting obsolete SDK tarball verification artifacts, and removing dead release-sdk regression suites.
<!-- docs-exempt: internal CI/workflow and test cleanup only; no user-facing command or behavior changes -->

View File

@@ -0,0 +1,6 @@
---
type: Changed
pr: 195
---
Replaced workflow markdown `gsd-sdk` query references with `gsd-tools.cjs query` command usage and removed global `gsd-sdk` fallback in workflow runtime command resolution blocks.
<!-- docs-exempt: workflow markdown migration under get-shit-done/workflows; no additional docs/ narrative needed -->

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 211
---
`gsd_run` workflow launcher now also probes `$HOME/.claude/get-shit-done/bin/gsd-tools.cjs` — global Claude-Code installs (`--claude` without `--local`) with no PATH wiring or `RUNTIME_DIR` are no longer rejected by the resolver. Closes #394 (duplicate).

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 213
---
Add Antigravity 2.x config-dir compatibility by auto-detecting `~/.gemini/antigravity-ide` and `~/.gemini/antigravity-cli` (with legacy `~/.gemini/antigravity` fallback), then routing installer, SDK runtime config resolution, and `/gsd-update` runtime classification through the same detection model.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 616
---
**`worktree.cleanup-wave` no longer silently loses a SUMMARY.md when the rescue copy fails** — a failed `*SUMMARY.md` rescue now blocks cleanup with `summary_rescue_failed` instead of merging and removing the worktree, preventing silent data loss.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 3515
---
**Context-window meter position is now configurable via `statusline.context_position`** — set `"front"` to render the meter immediately after the model name (useful in narrow terminals where the right edge is clipped); the default `"end"` preserves the existing byte-identical output. Invalid values at `config-set` time are hard-rejected by the enum validator; at hook runtime an invalid/stale config silently falls back to `"end"` so the statusline is never broken. Closes #2937.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3033
---
**`--sdk` flag now wired into SDK deployment** — `hasSdk` was parsed in `bin/install.js` but never passed to `installSdkIfNeeded`, so `npx get-shit-done-cc@latest --sdk` silently skipped SDK deployment and produced a misleading "✓ GSD SDK ready" message. `installSdkIfNeeded` now accepts `forceSdk: true` (set when `--sdk` is passed), which bypasses the local-install soft-skip and runs the full shim-link path so `gsd-sdk` is materialized on PATH. The `#2678` soft-skip for local installs without `--sdk` is preserved. (#3033)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 308
---
Add a per-attempt timeout (configurable via GSD_WEBSEARCH_TIMEOUT_MS) and bounded retry with Retry-After handling to the Brave websearch fetch (#308).

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 3095
---
**Distinct quota / rate-limit failure class for dispatched executor subagents** — `execute-phase` step 7 now routes provider quota and rate-limit terminations through a separate recovery branch instead of the generic "real failure" prompt. A new SDK query `agent.classify-failure` (`gsd-sdk query agent.classify-failure -- "<body>"`) classifies the agent return body as `quota-exceeded`, `classify-handoff-bug`, or `unknown-failure`, extracting `retryAfterSeconds` when the provider echoes one. Sentinels cover every runtime GSD dispatches into: Claude Code (`usage limit`, `429`), Copilot CLI (`rate_limit`, `user_weekly_rate_limited`), Codex (`usage_limit_reached`, `too many requests`), and Gemini (`RESOURCE_EXHAUSTED`, `exceeded your`). The recovery prompt for `quota-exceeded` offers wait-for-reset and resume as the first option rather than retry-now, which the runtime would reject again until the quota window resets. The resume path itself relies on the safe-resume gate landing in #3212. (#3095)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 311
---
Route changed files to sub-repos via a first-segment bucket index instead of an O(files*repos) linear scan (#311).

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 312
---
Index argv once in parseNamedArgs instead of re-scanning per flag (O(flags*argv) -> O(argv+flags)) (#312).

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 314
---
`roadmap annotate-dependencies` now indexes plan data by ID in a Map before the checklist loop, reducing plan lookup from O(lines×plans) to O(lines+plans).

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 315
---
`loadConfig` now memoizes `detectSubRepos(cwd)` per call, collapsing up to 3 redundant directory scans into 1 when migrations and filesystem re-sync both trigger.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3156
---
**`/gsd-plan-phase` no longer auto-dispatches to a subagent on OpenCode (#3156)** — `commands/gsd/plan-phase.md` carried `agent: gsd-planner` in its frontmatter. Per the OpenCode commands spec, `agent: <name>` causes the runtime to auto-dispatch the command to a named subagent context where the `Agent` (subagent-spawner) tool is unavailable. The `/gsd-plan-phase` orchestrator relies on `Agent` to spawn `gsd-phase-researcher`, `gsd-planner`, and `gsd-plan-checker` subagents; in the auto-dispatched context it fell back to doing all work inline. The `agent: gsd-planner` directive has been removed from `plan-phase.md` so the command runs in the main agent context where `Agent` is available. The same fix was applied to `commands/gsd/mvp-phase.md`, which carried the same directive and had the identical failure mode. A structural regression test parses the YAML frontmatter of every `commands/gsd/*.md` file and asserts that no command carries an `agent:` directive.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 316
---
acquireStateLock no longer allocates a fresh SharedArrayBuffer on every retry iteration — the sleep buffer is now hoisted before the retry loop and reused, eliminating per-retry heap pressure. (#316)

View File

@@ -0,0 +1,4 @@
---
type: Fixed
---
**`/gsd-graphify build` now runs inline instead of spawning a sub-agent (#3166)** — graphify v0.7+ split the build into a fast AST-extraction phase (cached) followed by a separate clustering + report-write phase. The cached extraction phase survived sub-agent isolation, but the post-extraction phase was SIGTERM'd when the agent exited, leaving the cache populated and no `graph.json` / `graph.html` / `GRAPH_REPORT.md` artifacts written to `.planning/graphs/`. The skill now runs `graphify update .`, the three artifact copies, the snapshot, and the status report as a single foreground Bash call so the entire pipeline survives to completion. The CLI's `graphify build` pre-flight still returns `action: "spawn_agent"` so external callers and existing tests keep working. Adds a structural regression test parsing the skill's YAML frontmatter to fence against re-introducing `Task` to `allowed-tools`.

View File

@@ -0,0 +1,4 @@
---
type: Enhancement
---
**`/gsd-graphify status` surfaces graphify v0.7+ commit-based staleness (#3170)** — `graphifyStatus()` now reads `built_at_commit` from `graph.json` (written by graphify v0.7+ at build time), compares it against `git HEAD`, and returns four new fields: `built_at_commit`, `current_commit`, `commits_behind`, and `commit_stale`. The `commit_stale` flag is tri-state — `true` / `false` / `null`, where `null` means the signal is unavailable (pre-v0.7 graph, non-git checkout, or unreachable commit) and callers should fall back to the existing mtime-based `stale` flag. The skill renders `Source commit: <hash> (N commits behind HEAD | current | freshness unknown)` when the signal is present, and omits the line entirely for pre-v0.7 graphs. The `built_at_commit` value is validated as 4–40 hex chars before reaching `git`, so a hostile `graph.json` cannot smuggle dashed options (e.g. `--upload-pack=…`) into the argv. Also documents `graphify hook install` in `docs/CONFIGURATION.md` for multi-dev teams who would otherwise hit `graph.json` merge conflicts on parallel rebuilds.

View File

@@ -0,0 +1,6 @@
---
type: Added
pr: 3713
---
**`phase.uat-passed` query and `isPhaseUatPassed` SDK export** — adds canonical read-only query `phase.uat-passed` (alias `phase uat-passed`) and programmatic export `isPhaseUatPassed(projectDir, phase, workstream?)` returning typed `{ passed, reasons, reasonsHuman, items }`. Predicate consumes `*-HUMAN-UAT.md` files; hardens against markdown injection (YAML frontmatter, fenced code blocks, HTML comments, blockquote-prefixed lines); surfaces operator-mistake signals as typed `REASON_CODE` frozen enum values (`CASE_MISMATCH`, `ORPHAN_ITEM_MISSING_RESULT`, `BRACKETED_PLACEHOLDER`, `NO_ITEMS_EXTRACTED`). Typed `PhaseUatPassedError extends GSDError` for invalid arguments. Refs #3184.
<!-- docs-exempt: SDK-only programmatic export in v1 per issue scope. Docs for phase.uat-passed deferred to follow-up issue pending @henjolo design confirmation. -->

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3195
---
**`/gsd-quick` worktree-merge resurrection guard no longer deletes brand-new `.planning/` files (#3195)** — the inverted `PRE_MERGE_FILES` grep that caused any file absent from the pre-merge snapshot (including freshly created `SUMMARY.md`) to be deleted has been replaced with the git-history check already used by `execute-phase.md` since PR #2510; only files with a confirmed deletion event in main's ancestry are now removed.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3200
---
`gsd-health` no longer raises W019 for `RETROSPECTIVE.md` — the file is now registered in `CANONICAL_EXACT` in `artifacts.cjs`, matching its established status as a living artifact produced by `/gsd-complete-milestone`.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 320
---
Hoist static `byPhaseTablePattern` regex in `updatePerformanceMetricsSection` to module scope so it compiles once instead of on every call. (#320)

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 3424
---
**Adds optional fallow structural pre-pass support for `/gsd-code-review` via `code_quality.fallow.*` config keys** — when enabled, the workflow resolves a fallow binary (`PATH` then `node_modules/.bin`), writes `.planning/phases/<phase>/FALLOW.json`, and passes a dedicated `<structural_findings>` block into `gsd-code-reviewer` so `REVIEW.md` can separate `Structural Findings (fallow)` from narrative reviewer findings. This ships a new CLI module (`fallow-runner.cjs`) plus SDK twin normalization logic (`sdk/src/query/fallow-audit.ts`), updates config schema/docs, and keeps default behavior unchanged when fallow remains disabled.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3305
---
**`command-aliases.generated.cjs` now exports `NON_FAMILY_COMMAND_ALIASES` with all 14 previously-missing commands** — the CJS manifest used by the SDK query registry only exposed the 7 "family" command arrays (state, verify, init, phase, phases, validate, roadmap). Commands registered in static catalogs (foundation + domain) had no manifest entry, so tooling that queries the manifest could not discover them. `command-manifest.non-family.ts` is extended with 10 new entries (`check.decision-coverage-plan`, `check.decision-coverage-verify`, `frontmatter.get`, `phase.mvp-mode`, `progress.bar`, `stats.json`, `task.is-behavior-adding`, `todo.match-phase`, `uat.render-checkpoint`, `workstream.list`); the other 4 were already in the source but not exported. Both the TS generated file and CJS manifest now include a `NON_FAMILY_COMMAND_ALIASES` array (40 entries, sorted by canonical). The generator and freshness check are extended to cover the non-family section. (#3305)

View File

@@ -0,0 +1,5 @@
---
type: Enhancement
pr: 3262
---
**Shared `scanPhasePlans()` helper extracted from four divergent copies (k014)** — `state.cjs` (3 copies), `roadmap.cjs`, and `init.cjs` each maintained their own plan-scan loop with subtly different regex shapes; divergence caused the plan-count drift that triggered #3257. All four call sites now delegate to `bin/lib/plan-scan.cjs:scanPhasePlans(phaseDir)` which returns `{ planCount, summaryCount, completed, hasNestedPlans, planFiles, summaryFiles }`. The canonical helper adopts roadmap.cjs's broader `isPlanFile` (matching the extended `5-PLAN-01-setup.md` layout gsd-plan-phase writes), adds the `-PLAN-\d+` nested-file variant init.cjs missed, and widens OUTLINE/pre-bounce exclusions to cover both flat and nested forms. (#3262)

View File

@@ -0,0 +1,5 @@
---
type: Enhancement
pr: 3302
---
**`docs/adr/` index and SDK seam ADRs (#3271)** — added `docs/adr/README.md` as an indexed entry point for all Architecture Decision Records, linking all seven ADRs. ADR 0005 documents the top-level SDK architecture seam map (Dispatch Policy Module, Model Catalog Module, Planning Workspace Module, SDK Package Seam Module, Planning Path Projection Module). ADR 0006 documents how SDK query handlers project planning paths (`cwd → effectiveRoot → .planning/<project>/...`). A structural test (`tests/enh-3271-sdk-adr-structure.test.cjs`) asserts each ADR has required headings and Status/Date metadata, and that the README links every ADR file by filename.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3306
---
**Phase directories in `/gsd-plan-milestone-gaps`, `/gsd-import`, and `/gsd-capture --backlog` now honour `project_code` prefix** — three workflow files were constructing phase directory paths using raw `{NN}-{slug}` patterns, bypassing the `project_code` prefix from `.planning/config.json`. In a project with `project_code: "XR"`, these workflows created `06-fix-auth/` instead of `XR-06-fix-auth/`, while `/gsd-plan-phase` and `/gsd-discuss-phase` (fixed in #3292) correctly produced the prefixed form. All three paths now resolve the directory name via `gsd-sdk query init.phase-op` (plan-milestone-gaps, import) or read `project_code` via `config-get` (add-backlog), consistent with the PRED.k015 requirement that project_code prefix is applied at all consumers. (#3298)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 149
---
Added regression test for the `model_profile: adaptive` settings option so future changes cannot silently break adaptive-mode selection.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3316
---
Tighten SDK-first architecture seams across planning path projection, workstream inventory, STATE.md transforms, and CJS command routing. Shared CJS/SDK helpers now reduce drift, and STATE.md progress projection preserves curated wider aggregates without hiding real disk-derived progress.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3346
---
**Codex AoT hooks migration uses event-name leaf key, not location tuple** — `migrateCodexHooksMapFormat` in `bin/install.js` re-emitted the legacy `[hooks.<X>]` section's path segment verbatim as the leaf TOML key of the new `[[hooks.<EVENT>]]` two-level nested AoT block. When the legacy table key was a `<file>:<event>:<line>:<col>` location identifier (with the actual event name in an `event = "..."` body field), the migration produced a header like `[[hooks."C:\Users\helen\.codex\config.toml:session_start:0:0"]]`, which Codex 0.124.0+ refuses to load. The map-format and stale-namespaced-AoT branches now mirror the flat-AoT branch: when the section body declares `event = "..."`, that name wins as the leaf key (and `event` is excluded from the re-emitted handler body). `npx get-shit-done-cc@latest` no longer aborts the Codex runtime install on Windows configs that pre-date the AoT migration. (#3346)

View File

@@ -0,0 +1,8 @@
---
type: Added
pr: 3557
---
**Opt-in: auto-rebuild knowledge graph after main HEAD advances** — new config key `graphify.auto_update` (default `false`) and bundled PostToolUse hook `hooks/gsd-graphify-update.sh` keep the `.planning/graphs/graph.json` consumed by `gsd-planner` and `gsd-phase-researcher` current without manual `/gsd:graphify build` runs. When both `graphify.enabled` and `graphify.auto_update` are `true`, the hook fires after Bash tool calls matching HEAD-advancing git ops (`commit`, `merge`, `pull`, `rebase --continue`, `cherry-pick`) or the exact `gsd-sdk query commit` command shape on the default branch, writes a synchronous `running` status to `.planning/graphs/.last-build-status.json`, then dispatches `graphify update .` in a detached subprocess that updates the status file to `ok` (with `duration_ms` + `head_at_build`) or `failed` (with `exit_code`). The planner and researcher's `load_graph_context` steps now surface the auto-build state alongside the existing staleness annotation — including the must-have failure-surface case from the issue review (`"auto-rebuild FAILED at {ts}; context is from the prior build"`). PID-locked against concurrent rebuilds (stale-PID tolerant via `kill -0`), CI-aware (`$CI` env suppresses), and bails silently if `graphify` is not on `PATH` or the current branch is not the default. `/gsd:settings` adds a "Graph auto-update" question gated on Graphify being enabled. Closes #3347.
<!-- docs-exempt: release-note wording refinement for existing graphify auto-update behavior; PR 3658's behavior change is covered by its Fixed fragment -->

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 338
---
`--claude --local` installs now write hook wiring to `.claude/settings.local.json` (Claude Code's per-user slot) instead of the repo-shared `.claude/settings.json` — engineer-specific absolute paths no longer leak into the shared settings file. Includes a one-shot migration of prior local-install entries on re-run.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3416
---
**`phase remove --force <phase>` now works correctly across both CLI and SDK query paths (#3409)** — flag parsing no longer treats `--force` as the phase id when the flag appears before the positional argument, preventing false success responses and unintended `STATE.md` phase-count drift.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3450
---
**Stabilized shell-command projection integration and uninstall hook cleanup** — rebasing the ADR-0009 projection work onto `main` now preserves the typed PATH-action seam while keeping the persistent PATH-export adapter used by installer messaging. It also hardens `settings.json` hook cleanup in `bin/install.js` to skip malformed/non-command hook entries before calling managed-hook classification, preventing uninstall-time crashes when mixed hook shapes are present.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3488
---
**`phase-plan-index` resolves short-form `depends_on: [NN]` for decimal-phase plans** — the DAG resolver only matched full-stem (`03-01-auth-hardening`) and canonical-prefix (`03-01`) forms, so plans in decimal phases (e.g. `99.9-test`, `02.2-cross-repo`) declaring `depends_on: [01]` had their edges silently dropped. Dependents collapsed into wave 1 and the SDK emitted a misleading `declared wave: N but depends_on DAG places it in wave 1` warning that pointed at the wave declaration rather than the broken reference. A tertiary short-form index now maps the trailing `-NN` of every plan ID to its full ID for same-phase short-form lookups, and unresolved `depends_on` references surface a dedicated `Plan X: unresolved depends_on reference 'NN' — no matching plan in phase` warning so the dropped edge can no longer hide behind the wave-mismatch warning. (#3488)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3489
---
**`state complete-phase` is now idempotent — re-invocation no longer rolls STATE.md back.** Previously, running `gsd-sdk query state.complete-phase --phase <N>` (or `gsd state complete-phase --phase <N>`) a second time on a phase that was already marked complete silently rewound STATE.md to that phase's moment-of-completion, clobbering `Status`, `Last Activity`, `Last Activity Description`, and the `## Current Position` body. Any downstream consumer trusting STATE.md (`/gsd-progress`, planner, the next phase's discuss-phase context loader) was routed back to the rolled-back phase. The handler now reads STATE.md before writing: if the canonical `Current Phase` field already names a phase distinct from the one being completed, the project has clearly advanced past it and the handler returns a no-op (`{ updated: [], phase: "<N>", idempotent: true, note: "phase already superseded; no-op" }`) without touching STATE.md. (#3489)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3502
---
**`/gsd-new-project` and `/gsd-ingest-docs` no longer create a nested `.git` inside an existing worktree (#3491)** — the shallow `has_git: false` check (which only looked for `.git` in the current directory) has been replaced with `git rev-parse --is-inside-work-tree` semantics. The init payload now surfaces `git_worktree_root` and `in_nested_subdir` so the workflows correctly skip `git init` when invoked from a subdirectory of an existing repo and warn that planning files will be tracked by the outer repo.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3493
---
**`extractCurrentMilestone` preserves generic `## Phase Details` heading** — When a roadmap placed shared phase-detail bodies under a non-version-prefixed `## Phase Details` heading AFTER a `### 📋 vX.Y+ (Planned)` sibling, the entire Phase Details section fell outside the returned milestone slice. `gsd-sdk query phase.insert N` then reported "Phase N not found in ROADMAP.md" even though `### Phase N:` was plainly present. PR #2455 (closing #2422) handled the version-prefixed variant (`## v2.0 Phase Details`) via the same-version `continue` branch; this fix extends the same intent to the generic-label variant by appending the trailing `Phase Details` block (up to the next real milestone boundary or EOF) to the active-milestone slice. The intervening planned-milestone content is skipped so it does not leak in. (#3493)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3520
---
**`phase.complete` STATE.md staleness and idempotency fixed** — Two root causes corrected atomically: (1) `completed_phases` was blindly incremented (`+1`), making `phase.complete N` non-idempotent — running it twice on the same phase double-counted (4→5→6). It now derives the count from the ROADMAP progress table's `Complete` rows, so repeated calls produce the same result. (2) Eight STATE.md fields were left stale after phase completion: `stopped_at`, `last_updated`, `total_plans`, `completed_plans` (frontmatter) and `Current focus:`, `Status:`, `Progress:` bar, `By Phase` table row (body). All fields are now updated in the same atomic write guarded by the existing `acquireStateLock`/`releaseStateLock` pair. `completed_plans` is derived from on-disk `*-SUMMARY.md` file counts; `total_plans` from ROADMAP M/N plan column sums; `percent` from the freshly-derived phase counts. (#3517)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3538
---
**Phase state verbs no longer silently no-op on projects with `project_code` set and un-padded ROADMAP prose.** v1.42.1 added the padding-tolerant `phaseMarkdownRegexSource()` helper but wired it into only 1 of 8 call sites that build phase-number regexes against ROADMAP/STATE prose; the other 7 used raw `escapeRegex(phaseNum)` or partial `0*${escapeRegex(...)}` (tolerated extra padding, not missing). When skills passed the resolved padded form (`02.7`) against un-padded ROADMAP headings (`### Phase 2.7:`), `phase complete`, `roadmap get-phase`, `roadmap analyze` checkbox detection, `roadmap annotate-dependencies`, `phase next-decimal`, and `phase insert` all silently returned success while ROADMAP.md stayed unchanged. The helper is now promoted to `core.cjs` and routed through every site. Adds a parity-style regression that runs each verb with padded and un-padded ids against an identical fixture and asserts byte-equal output, so the next call-site cannot drift back undetected. Closes #3537.

View File

@@ -0,0 +1,6 @@
---
type: Fixed
pr: 3547
---
**Installer migration no longer hangs `/gsd:update` on leftover GSD-looking files** — non-TTY installer runs now default-resolve `prompt-user` migration actions by classification (stale SDK build artifacts under `get-shit-done/sdk/{dist,src}/gsd-*` default to `remove`; user-facing `skills/gsd-*/SKILL.md` defaults to `keep`) and log each resolution. Anything that cannot be safely defaulted still blocks, but the error message now groups blocked paths by reason, lists the documented choices, and names the `GSD_INSTALLER_MIGRATION_RESOLVE` env var as the non-interactive resolution surface. (#3541)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3546
---
**Executor agents are now forbidden from running any `git stash` subcommand inside worktree isolation** — git stores stashes at `refs/stash` in the parent `.git/` directory, so the stash list is shared across the main checkout and every linked worktree. A `git stash pop` inside an executor's worktree silently applied WIP pushed from a prior sibling-worktree session, producing UU/UD merge-conflict states and phantom untracked files that violated the `isolation="worktree"` invariant. The `<destructive_git_prohibition>` block in `agents/gsd-executor.md` now lists the full `git stash` family alongside `--no-verify`, `--hard`, and `git update-ref`, with sanctioned alternatives (commit to a throwaway branch you own, or read-only `git show <ref>:<path>` / `git diff <ref> -- <path>`). The orchestrator-side post-wave-hook helper in `execute-phase.md` continues to use stash deliberately and is now annotated to make the single-checkout precondition explicit. Closes #3542.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 3548
---
**Adds a generated Workstream Inventory Builder seam with freshness guards** — introduces `sdk/src/workstream-inventory/builder.ts` (and tests) as the canonical builder source, generates `get-shit-done/bin/lib/workstream-inventory-builder.generated.cjs`, wires `check-workstream-inventory-builder-fresh` into hooks/CI, and updates inventory docs/manifests so SDK and installer-facing artifacts stay synchronized.

View File

@@ -0,0 +1,6 @@
---
type: Fixed
pr: 3568
---
**Codex global install now produces discoverable `$gsd-*` skill surface** — `npx get-shit-done-cc@latest --codex --global` was leaving Codex CLI users with `get-shit-done/workflows/*.md` and `agents/gsd-*` on disk but no `~/.codex/skills/gsd-*/SKILL.md` files, so Codex 0.130.0 silently exposed zero `$gsd-*` commands after restart. The installer had been bypassing skill generation under the assumption that Codex auto-discovers from workflow/agent files; that assumption does not hold for the current Codex CLI. Re-wired the existing `copyCommandsAsCodexSkills()` helper into the Codex install dispatch path so it produces the same skill-shape as the Claude / Copilot / Antigravity / Cursor / Windsurf / Augment / Trae installs already do (one `skills/gsd-<name>/SKILL.md` per `commands/gsd/*.md`). Pre-existing user-owned non-`gsd-*` skill directories are preserved. Closes #3562.

View File

@@ -0,0 +1,6 @@
---
type: Fixed
pr: 3573
---
**Codex installer now emits canonical `[features].hooks` on fresh inserts (no longer writes deprecated `codex_hooks`)** — Codex's own source marks `codex_hooks` as a `legacy_key` ([codex-rs/features/src/legacy.rs](https://github.com/openai/codex/blob/main/codex-rs/features/src/legacy.rs)). The GSD installer was writing the deprecated key on every install / reinstall on Codex CLI ≥ 0.130.0. The installer now writes the canonical `[features].hooks = true` (section, root-dotted, and block-fallback forms) and the runtime check recognizes both `hooks` and legacy `codex_hooks` as enabling the feature. Pre-existing legacy lines (user-authored or from older GSD installs) are preserved untouched — Codex's own `legacy_key` alias handles them at the runtime layer, so there's no breaking change for existing configs. Closes #3566.

View File

@@ -0,0 +1,6 @@
---
type: Fixed
pr: 3572
---
**Installed `gsd-tools.cjs` can load generated configuration manifests** — runtime installs now copy `config-defaults.manifest.json` and `config-schema.manifest.json` into `get-shit-done/bin/shared/`, and `configuration.generated.cjs` resolves that co-located install path before falling back to the source checkout `sdk/shared/` path. This prevents direct installed CJS invocations from failing with `MODULE_NOT_FOUND` when no sibling `sdk/` checkout exists. (#3571)

View File

@@ -0,0 +1,21 @@
---
type: Fixed
pr: 3577
---
**Phase 6 ADR/PRD compliance: out-of-seam Modules removed from SDK catalog; CJS-only verbs dispatch direct** — `verify.codebase-drift` and the eight `intel.*` verbs were wrongly bound in the SDK catalog/manifests, in violation of `docs/adr/3524-cjs-sdk-hard-seam.md` §3 and `docs/prd/3524-cjs-sdk-hard-seam.md` L160 which list `drift`, `intel`, `graphify`, `gsd2-import`, `schema-detect`, `fallow-runner`, `installer-migrations` as CJS-only ("...keep their in-process CJS implementations because no SDK counterpart exists"). The `verifyCodebaseDrift` SDK stub then `execFileSync`'d back to `gsd-tools verify codebase-drift`, which the router routed back through the SDK bridge — an infinite recursion that forked hundreds of node processes on the remote 64 GiB docker host before manual kill. All wrongly-bound entries removed; the CJS router and `gsd-tools.cjs` already had direct CJS dispatch paths for these verbs that are now the only path.
**Phase 6 `config-ensure-section` cutover via catalog rebind, not CJS fallback** — restored the legacy "no-arg full default config.json init" contract on the SDK path by binding the catalog entry `'config-ensure-section'` to `configNewProject` (whose no-args branch produces the same shape as the legacy `ensureConfigFile → buildNewProjectConfig` chain). The original Phase 6 binding to the new `configEnsureSection` handler (single-section ensure, requires `args[0]=sectionName`) broke every CLI caller, which all invoke the no-arg form.
**`configNewProject` defaults sourced from canonical Configuration Module manifest** — replaced the hardcoded duplicate `defaults` object with a derivation from `sdk/shared/config-defaults.manifest.json` (exported as `CONFIG_DEFAULTS` from `sdk/src/configuration/index.ts`). The previous duplicate had drifted from the manifest — omitted `workflow.{ai_integration_phase, tdd_mode, human_verify_mode, pattern_mapper, plan_bounce*, auto_prune_state, subagent_timeout, security_*, post_planning_gaps}`, `git.create_tag`, `claude_md_path`, `planning.*`, `graphify.*`, `mode`, `resolve_model_ids`, `context_window`. Closes the same `DEFECT.PORT-DRIFT.cjs-sdk` family the ADR was written to prevent.
**SDK `configSet` value-validation port from CJS `cmdConfigSet`** — added the missing enum/shape validators that the CJS handler enforced: `workflow.drift_action` (warn|auto-remap), `workflow.drift_threshold` (positive integer), `workflow.human_verify_mode` (mid-flight|end-of-phase), `statusline.context_position` (front|end), `code_quality.fallow.scope` (phase|repo), `code_quality.fallow.profile` (minimal|standard|strict), and `review.default_reviewers` (array of slug strings matching `^[a-zA-Z0-9_-]+$`, normalized to lowercase-unique, with the normalized value persisted to disk).
**Init handlers honor `--tdd` flag and `workflow.subagent_timeout`** — `initExecutePhase` and `initPlanPhase` now parse the `--tdd` boolean override (matching `parseNamedArgs(args, [], ['validate', 'tdd'])` in the CJS router and `options.tdd || config.tdd_mode || false` in the CJS handler), and `initMapCodebase` reads `subagent_timeout` from the canonical `workflow.subagent_timeout` location with the manifest-mandated 300000 default instead of an undefined fallback.
**`roadmap.analyze` surfaces `mode` per phase** — extracts the same `**Mode:**` field that `roadmapGetPhase` already parses, so consumers can read MVP-mode flagging from either query handler without divergence.
**SDK `phaseComplete` performs auto-prune of STATE.md when configured** — ported the `workflow.auto_prune_state === true` branch from CJS `cmdPhaseComplete`, calling `statePrune(['--keep-recent', '3', '--silent'], ...)` so completing phase N actually removes stale `[Phase 1..N-3]` decisions instead of leaving them forever. (#2087)
**SDK `initRemoveWorkspace` errors via thrown `GSDError`** — returning `{ data: { error } }` was treated as success by the CLI output path; the no-name and workspace-not-found branches now throw `GSDError(..., ErrorClassification.Validation)` so the CLI returns non-zero and writes the message to stderr.
**SDK `frontmatterGet` parses `--field <name>`** — the CLI invocation `frontmatter get <file> --field phase` was passing `args = [file, '--field', 'phase']`; the handler treated `args[1]` as the field name and saw the literal string `--field`. Now handles both `--field <name>` and positional `args[1]`.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3577
---
**Phase 6 `config-*` SDK port parity carve-outs** — restored the legacy contract for four CLI tests broken by the Phase 6 router migration. `config-ensure-section` no longer routes through the new SDK `configEnsureSection` handler (which expected a positional `<section>` arg the CLI never passes) and instead keeps the `cmdConfigEnsureSection → ensureConfigFile → buildNewProjectConfig` CJS path that produces the full default `.planning/config.json`. The SDK `configNewProject` defaults now match `sdk/shared/config-defaults.manifest.json` (`commit_docs: true`, `parallelization: true`) and report the project-rooted relative path `.planning/config.json` to mirror the CJS shape. SDK error vocabulary is aligned with CJS: `Unknown config key: <key>` (no quotes), and config-get's malformed-JSON error is led by `Failed to read config.json:` so legacy regression tests keep matching. Closes the `Usage: config-ensure-section <section>` regression seen in `tests/{config,agent-skills,ai-evals}.test.cjs`.

View File

@@ -0,0 +1,11 @@
---
type: Fixed
pr: 3577
---
**Docker test fix-forward: 12 ubuntu-only regressions surfaced by `gsd-test-summary` cleared** —
- `agents/gsd-intel-updater.md` retargeted from `gsd-sdk query intel.*` to `gsd-tools intel <subcommand>` (intel is out-of-seam per ADR §3 / PRD L160; the SDK has no handler for it, so the agent's CLI calls were broken).
- `roadmap.get-phase` two-pass lookup for project-code-prefixed IDs (port of CJS `phaseMarkdownRegexSourceExact`, #3599): a `PROJ-42` query now matches `### Phase PROJ-42:` directly without cross-matching a bare `### Phase 42:` that happens to share the trailing integer.
- `roadmap.analyze` extracts the `**Mode:**` field per phase (parity with `roadmap.get-phase`).
- `phase.remove` depth-aware end-of-section regex (port of CJS #3601 fix): removing `### Phase 2:` stops at `### Phase 2.1:` (peer-depth decimal preserved) but continues past `#### Phase 27.1:` (child-depth decimal of `### Phase 27:`). Named capture `(?<h>#{2,4})` + backreference `\k<h>(?!#)` enforces same-depth termination.
- `phase.remove` slugged-plan reference renumbering (port of CJS #3602 fix): the padded-plan-reference pattern now allows arbitrary kebab-case slug segments between `NN-NN` and the `-PLAN.md` / `-SUMMARY.md` suffix, so references like `07-01-cherry-pick-foundation-PLAN.md` get renumbered to `06-01-…` when Phase 7 is removed.
- `configNewProject` filters out manifest keys that legacy CJS init does not materialize (`git.base_branch`, `resolve_model_ids`, `context_window`, `mode`, `planning`, `graphify`): these have their own resolution paths (auto-detect, opt-in) and materializing manifest values would suppress them. `config-get git.base_branch` correctly returns "Key not found" so workflows can fall back to `origin/HEAD` resolution.

View File

@@ -0,0 +1,5 @@
---
type: Security
issue: 3589
---
**`relPlanningPath()` now validates explicit workstream names** — direct SDK callers passing a workstream argument to `relPlanningPath`, `planningPaths`, or `ContextEngine` previously had no path-traversal gate. A value like `'../../../outside'` flowed through `posix.join('.planning', 'workstreams', name)` and routed planning operations outside the intended `.planning/workstreams/<name>` subtree. The fix runs the shared `validateWorkstreamName` policy inside `relPlanningPath` so every consumer fails closed at the same seam. Env-sourced workstreams continue to fall back silently to root `.planning/` per the #2791 contract (they are filtered to `null` by `planningPaths` before reaching `relPlanningPath`).

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3591
---
**`createGSDToolsRuntime` now forwards the workstream to native registry dispatch** — the closure passed to `QueryNativeDirectAdapter.dispatch` previously called `registry.dispatch(command, args, projectDir)` and silently dropped `opts.workstream`. As a result, GSDTools-native query handlers ran against the root `.planning/` tree even when the GSDTools instance was created with a `workstream`. The closure now passes `opts.workstream` as the 4th argument, matching the `QuerySubprocessAdapter` path that already forwards it. Every native dispatch through the runtime bridge now routes planning-path queries to `.planning/workstreams/<name>/` when a workstream is set.

View File

@@ -0,0 +1,5 @@
---
"get-shit-done-cc": patch
---
**Fixed: `config-set <key>` with no value now fails cleanly.** Previously, invoking `config-set model_profile` (key only, no value) returned `{ updated: true }` with exit 0 — but the value passed through as `undefined`, which `JSON.stringify` silently dropped during the write. Now both the CJS handler and the SDK `configSet` query throw a typed `Usage` error before any write, preventing silent config corruption. Surfaced by the new CLI adversarial-input matrix (#3593).

View File

@@ -0,0 +1,5 @@
---
"get-shit-done-cc": patch
---
**Added: adversarial parser fixture corpus and tests.** New `tests/fixtures/adversarial/{frontmatter,roadmap}/` directories with hostile-but-realistic inputs (duplicate keys, CRLF endings, unclosed blocks, Unicode, null bytes, fenced-code headings, decimal phase prefix collisions, HTML-commented headings), exercised by new behavioral tests (`feat-3594-parser-adversarial-frontmatter.test.cjs`, `feat-3594-parser-adversarial-roadmap.test.cjs`) plus one deterministic seeded property-style test (`feat-3594-parser-property-style.test.cjs`) covering 500 generated inputs per assertion. Pins current parser behavior for known still-open regressions (#2787 fenced-code-block headings in the CJS parser; HTML-comment heading false positives) so the future fix lands as a one-line assertion flip.

View File

@@ -0,0 +1,5 @@
---
"get-shit-done-cc": patch
---
**Added: filesystem fault-injection coverage for `platformWriteSync`.** New tests in `tests/feat-3595-fs-fault-injection-atomic-write.test.cjs` use `node:test`'s `mock.method()` to inject `ENOSPC`, `EACCES`, `EXDEV`, `EBUSY`, and `EISDIR` against the shared atomic-write seam in `get-shit-done/bin/lib/shell-command-projection.cjs`. Covers rename-failure fallback, double-failure error propagation, mkdir failure, target-is-directory collision, paths with spaces/Unicode/newlines, symlink-replacement safety (writer does NOT follow symlinks), broken-symlink handling, and concurrent-write collision. Documents two pre-existing behavior gaps (fallback error swallows original cause; mkdir failure escapes unhandled) as pinned current behavior, ready for the future fix to flip the assertion.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3597
---
**Test suites split into named lanes and CI matrix expanded to OS×Node** — `scripts/run-tests.cjs` now accepts `--suite <unit|integration|install|security|slow|all>` and filters by filename suffix (`*.security.test.cjs`, `*.integration.test.cjs`, etc.). New package scripts `test:unit`, `test:integration`, `test:install`, `test:security`, `test:slow`, `test:coverage:unit`, and `test:coverage:all` give callers stable entrypoints; `npm test` and `npm run test:coverage` keep their original behavior (full sweep). CI matrix grew from `ubuntu × {22, 24}` + a single macOS lane to `{ubuntu, macos, windows} × {22, 24, 26}` with Node 26 in `continue-on-error` until `actions/setup-node` stabilises it. `fail-fast: false` so a single lane failure no longer cancels the rest. Install and slow suites only run on `main` push to keep PR CI fast; a dedicated `coverage` job runs `test:coverage:unit` on ubuntu/Node 24 and uploads the report. New grouping policy documented in `docs/TESTING-SUITES.md`. Closes #3597.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3649
---
**`scripts/run-tests.cjs` no longer fails on Windows when invoking many test files at once** — Windows `CreateProcess` caps `lpCommandLine` at 32,767 chars, so an unchunked spawn of `node --test <546 paths>` aborted instantly with exit 1 and no test output (Linux/macOS allow ~2 MB so the same path worked there). The harness now batches selected files into chunks whose total argv stays under 28,000 chars and runs each chunk sequentially, reporting `run-tests: chunk N/M — K files` to stderr. The ceiling is overridable via `RUN_TESTS_MAX_CMDLINE_CHARS` for tuning and tests. Adds a cross-platform regression test that forces chunking with a low ceiling.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3599
---
**`roadmap get-phase PROJ-42` now matches `### Phase PROJ-42:` instead of returning `found: false`** — `cmdRoadmapGetPhase` now does a two-pass search when the caller passes a project-code-prefixed ID. The exact-escaped form (`### Phase PROJ-42:`) is tried first, and only falls back to the #3537 padding-tolerant numeric form (`### Phase 42:`) when the exact heading is not present. New helper `phaseMarkdownRegexSourceExact()` is added alongside the existing `phaseMarkdownRegexSource()` so callers that need the prefix-preserving path can opt in.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3600
---
**`init.new-milestone` now counts project-code-prefixed phase directories** — `getMilestonePhaseFilter` previously skipped `.planning/phases/CK-01-name` against a numeric ROADMAP heading like `### Phase 1:`: the numeric matcher required the directory name to start with a digit and the custom-ID matcher compared the full prefixed name against the bare milestone token. Added a strip-and-retry path that strips the same `^[A-Z]{1,6}-(?=\d)` prefix `normalizePhaseName` already recognises and retries the numeric match. The fix lands in both the CJS runtime (`get-shit-done/bin/lib/core.cjs:isDirInMilestone`) and the SDK twin (`sdk/src/query/state.ts:isDirInMilestone`), and is shared by every caller of `getMilestonePhaseFilter` — including `init.new-milestone`, `phase complete`, `verify-work`, and `validate-health`.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3601
---
**`phase remove N` no longer collapses adjacent peer-depth decimal phases** — `updateRoadmapAfterPhaseRemoval` in `get-shit-done/bin/lib/phase.cjs` now uses a depth-aware end-of-section lookahead that captures the hash count of the header being removed and stops only at a subsequent header of the SAME depth. Previously the lookahead required the next header's digits to be followed by `\s*:`, which failed on `### Phase 2.1:` (the `.1` blocks the match) and silently consumed the decimal sibling along with the integer phase. The fix preserves `### Phase 2.1:` (peer-depth decimal) while still removing `#### Phase 27.1:` (child-depth decimal under `### Phase 27:`).

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3602
---
**`phase remove N` now renumbers slugged plan references in ROADMAP.md** — the plan-reference renumbering regex in `get-shit-done/bin/lib/phase.cjs:updateRoadmapAfterPhaseRemoval` previously only matched compact filenames like `07-01-PLAN.md`. A slug between the plan number and the `-PLAN.md` / `-SUMMARY.md` suffix (e.g. `07-01-cherry-pick-foundation-PLAN.md`) broke the lookahead, so the on-disk file was renamed but the ROADMAP entry kept pointing at the stale `07-01-…` prefix. The suffix lookahead now allows an optional kebab-case slug segment between the number and the canonical suffix.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3605
---
**Agent contracts no longer reference retired `/gsd-research-phase` or `/gsd-insert-phase`** — six surviving references in `agents/gsd-executor.md`, `agents/gsd-phase-researcher.md`, `agents/gsd-planner.md`, `agents/gsd-research-synthesizer.md`, and `agents/gsd-roadmapper.md` are replaced with `/gsd:plan-phase --research-phase <N>` and `/gsd:phase insert`. Adds a regression guard (`tests/bug-3605-stale-research-insert-phase-agent-refs.test.cjs`) that fails when any retired command name reappears in `agents/*.md` — covers the gap that let #3029, #3044, and #3131 miss the `agents/` directory.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3608
---
**`/gsd-update` invoked from Antigravity now resolves the correct runtime instead of collapsing into base Gemini** — `get-shit-done/workflows/update.md` now models `antigravity` as a first-class runtime everywhere it lists candidate dirs / env vars / classification rules. `RUNTIME_DIRS`, the `PREFERRED_RUNTIME` env-var ladder, the local-scope scan loops, the `ENV_RUNTIME_DIRS` env push, and the path-to-runtime classification bullets all list `antigravity:.gemini/antigravity` (and `ANTIGRAVITY_CONFIG_DIR`) before the base Gemini entry so the more-specific match wins. Adds `tests/bug-3608-antigravity-update-runtime-classification.test.cjs` as a structural regression guard.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
issue: 3610
---
**Fresh `npx get-shit-done-cc@latest --codex` no longer hard-aborts when leftover bundled `hooks/gsd-*` files are present** — `classifyPromptUserAction` in `installer-migration-report.cjs` now recognizes the bundled GSD hooks (`hooks/gsd-<name>.{js,sh,cjs,mjs}`) as a known category (`bundled-gsd-hook`) and resolves them to `remove` so the installer can write the fresh bundled versions. The classifier-based safe-default resolver in `bin/install.js` now runs regardless of TTY state — gating it on `!isTTY` made interactive installs throw `installer migration blocked pending user choice` for files that have no actual user choice to make.

View File

@@ -0,0 +1,5 @@
---
"get-shit-done-cc": patch
---
**Fixed: hotfix releases now correctly cherry-pick test-fixture updates.** The `release-sdk.yml` auto-cherry-pick loop accepts `test:` commits (in addition to `fix:` and `chore:`), and the shipped-paths classifier treats `tests/<name>` and `sdk/src/<name>/<file>.test.<ts|cjs|mjs|js>` as CI-gating-equivalent. When a production fix is bundled with a `fix:` commit but the matching test-fixture alignment lands in a separate `test:` commit, both are now picked together — preventing the CI-red state that broke the v1.42.3 hotfix attempt. The `.github/workflows/<file>` push-blocking guard is preserved (#2980): bundles touching workflow files still skip regardless of other content.

View File

@@ -0,0 +1,5 @@
---
type: Security
issue: 3628
---
**Installer no longer auto-removes user-authored or retired `hooks/gsd-*` files** — the `bundled-gsd-hook` classifier added in #3610 used a shape regex (`/^hooks\/gsd-[^/]+\.(?:js|sh|cjs|mjs)$/`) that matched any file with that naming shape, not only the 13 hooks actually shipped in the npm package. User-authored custom hooks (e.g. `hooks/gsd-personal-experiment.js`) and retired bundled hooks from prior versions were silently auto-classified and removed on first-time-baseline scan. The classifier now whitelists the explicit set of shipped hook filenames (`BUNDLED_GSD_HOOK_FILES`); files outside the whitelist fall through to the existing block-or-prompt flow so the user retains control. A drift guard in `tests/bug-3628-bundled-hook-classifier-whitelist.test.cjs` fails CI if the whitelist diverges from the on-disk `hooks/` directory in either direction.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3648
---
**`gsd-sdk query resolve-model` now honors `resolve_model_ids: true` under `runtime: "claude"`** — previously the resolver bailed out of `resolveRuntimeTier` for Claude (because Claude is the implicit/default runtime in `config-query.ts:149`) and fell through to the alias-return path on line 243 without consulting the catalog. Consumers asking for resolved model IDs received the tier alias (`opus` / `sonnet` / `haiku`) instead of the full Claude model ID (`claude-opus-4-7` / `claude-sonnet-4-6` / `claude-haiku-4-5`). The CJS branch at `get-shit-done/bin/lib/core.cjs:1348-1350` (`if (config.resolve_model_ids) return MODEL_ALIAS_MAP[alias] || alias;`) was missing from the TS port. Added a `runtime === 'claude' && resolveModelIds === true` branch that calls `resolveRuntimeTierDefault('claude', tier)` from the shared model-catalog so both runtimes derive Claude IDs from the same source of truth. `model_overrides`, the phase-type tier override (`config.models[phaseType]`), and `resolve_model_ids: "omit"` all retain their existing precedence. (#3643)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3658
---
**`gsd-graphify-update.sh` now matches `gsd-sdk query commit` (#3653)** — the PostToolUse auto-update hook previously substring-matched only direct shell git ops in `tool_input.command`. Because `gsd-sdk query commit` invokes git via `spawnSync('git', [...])` rather than through a shell, the literal `git commit` never appears in the Bash tool's command string, and the hook silently skipped every SDK-issued commit — including the `phase.complete`-following commit that closes every phase. Result: `.planning/graphs/` drifted stale by one or more commits at the end of every phase, with no error and no log. Gate 2 now also accepts the exact `gsd-sdk query commit` command shape, which is the user-facing invocation that triggers the SDK-internal `spawnSync('git', 'commit', ...)`, without matching sibling verbs such as `commit-to-subrepo`. Other `gsd-sdk query` verbs (`phase.complete`, `roadmap.update-plan-progress`, `state.begin-phase`) do not invoke git themselves and remain non-matching to avoid spurious rebuilds per state mutation.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3693
---
**`/gsd-resume-work` no longer drops `.planning/.continue-here*.md` checkpoints under zsh's default `NOMATCH`** — the chained `ls` of bare globs in `resume-project.md`'s `check_incomplete_work` step aborted on the first non-matching pattern, silently swallowing every later pattern (including the one that surfaces top-level handoff files). Replaced with `find .planning -maxdepth 3` + `find . -maxdepth 1`, which doesn't use shell glob expansion and tolerates absent directories on both bash and zsh.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 370
---
**Affected-tests PR runner no longer selects or runs `install`/`slow` suites (#370)** — `pickAffectedTests` now filters out any file whose suite is `install` or `slow` at the single chokepoint, covering direct-change, reverse-index, and stem-match selections. The `DEFAULT_SMOKE_TESTS` install-file fallback injection is removed; an empty selection now runs `unit` as the smoke fallback. The critical-path branch replaces `runAllSuites` (which ran every suite including `install`/`slow`) with `PR_FULL_SUITES` (`unit`, `integration`, `security`). `suiteOf` is exported from `run-tests.cjs` (guarded by `require.main`) so the affected-tests lib can reuse the canonical suite-detection logic without duplication.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3707
---
**Locked worktrees now cleaned up correctly** — `executeWorktreeWaveCleanupPlan` previously issued a single `git worktree remove --force` which Git refuses on locked worktrees, blocking every post-merge cleanup when Claude Code's agent runtime held a lock file. The fix attempts `git worktree unlock` then retries the remove. A new `worktree.reap-orphans` command (`gsd-sdk query worktree.reap-orphans`) sweeps orphaned locked worktrees from prior crashed sessions at startup — it reaps entries whose pid is dead, branch is merged into the default branch, and lock mtime is older than 5 minutes. Wired into `quick.md` and `execute-phase.md` startup. (#3707)

View File

@@ -0,0 +1,22 @@
---
type: Added
pr: 3740
---
<!-- docs-exempt: internal test refactor only — no user-facing surface changed -->
## Summary
Consolidates the Phase Lifecycle Module test cluster from 20 files to 4, satisfying the lint-test-file-count allowlist ceiling.
- Merged 10 small CJS bug-fix test files into `tests/phase.test.cjs`
- Merged `sdk/src/phase-runner-types.test.ts` and `sdk/src/phase-prompt.test.ts` into `sdk/src/phase-runner.test.ts`
- Renamed 4 mis-attributed test files whose production seam is not `phase.cjs`/`phase.ts`:
- `phase-researcher-app-aware` → `gsd-researcher-app-aware`
- `phase-researcher-flow-diagram` → `gsd-researcher-flow-diagram`
- `feat-3023-phase-type-models` → `feat-3023-model-phase-types`
- `phase-6-cjs-sdk-seam-contracts` → `cjs-sdk-bridge-seam-contracts`
- Fixed `phasePlanIndex` (#3430): non-canonical plan filename warning now flows through `warnings[]` array alongside other diagnostics instead of a separate singular `warning` field
- Updated `scripts/lint-test-file-count.allowlist.json`: `phase` ceiling 20 → 4
- Added Phase Lifecycle Module glossary entry to `CONTEXT.md`
Closes #3740

View File

@@ -0,0 +1,14 @@
---
type: Changed
pr: 3752
---
<!-- docs-exempt: internal test refactor only — no user-facing surface changed -->
Consolidates the Worktree Module test cluster from 13 files to 3, satisfying the lint-test-file-count allowlist ceiling.
- Merged 11 bug-fix CJS test files into `tests/worktree.test.cjs` (branch-check/workspace-safety) and `tests/worktree-cleanup.test.cjs` (HEAD-attachment/cleanup, split along cleanup seam, each ≤ 800 LOC)
- Retained `tests/worktree-safety.test.cjs` with safety policy tests merged in
- No `worktree` entry needed in allowlist (3 files ≤ 4 cluster budget)
- Added Worktree Workstream Seam Module glossary entry to `CONTEXT.md`
Closes #3742

View File

@@ -0,0 +1,19 @@
---
type: Fixed
pr: 3753
---
<!-- docs-exempt: internal test refactor only — no user-facing surface changed -->
## Summary
Consolidates the Milestone Module test cluster from 10 files to 4, bringing the cluster within the lint-test-file-count allowlist ceiling introduced in PR #3738.
- Rewrote `tests/milestone.test.cjs` (869 → 720 LOC) with compact shared helpers, absorbing `milestone-regex-global.test.cjs` and `bug-3043-milestone-complete-scope.test.cjs`
- New `tests/milestone-archive.test.cjs` (505 LOC) absorbs `bug-2684`, `bug-2787`, `bug-3164`, `bug-3600` — milestone archive layout, fenced code block parsing, phase filter, version forwarding
- Expanded `tests/milestone-summary.test.cjs` (471 LOC) to absorb `milestone-audit.test.cjs`
- `sdk/src/milestone-runner.test.ts` unchanged (421 LOC)
- All 99 CJS assertions and 11 SDK assertions preserved (no regression)
- Added Milestone Module glossary entry to `CONTEXT.md`
- Allowlist update deferred to rebase after PR #3738 merges; pre-rebase, `milestone` entry would change from 10 → 4
Closes #3753

View File

@@ -0,0 +1,7 @@
---
type: Changed
pr: 3755
---
Internal test refactor: consolidates the Init Command Module test cluster from 7 files to 5.
<!-- docs-exempt: internal test refactor only — no user-facing surface changed -->

View File

@@ -0,0 +1,8 @@
---
type: Fixed
pr: 3759
---
<!-- docs-exempt: internal test refactor only — no user-facing surface changed -->
Consolidates the Runtime Artifact Layout Module test cluster (ADR-3660) from 12 files spanning three module names (`surface-*`, `runtime-artifact-layout-*`, `install-profiles-*`) into 3 files, resolving the three-module-name split identified in ADR-3660.

View File

@@ -0,0 +1,6 @@
---
type: Changed
pr: 3758
---
<!-- docs-exempt: internal test refactor, no API/behavior change -->
**Consolidate Installer Module tests — 11 files → 2** — Merged `hermes-install`, `kilo-install`, `qwen-install`, `trae-install`, `antigravity-install`, `install-minimal`, `install-minimal-all-runtimes`, `install-minimal-backcompat`, `install-hermes-regressions`, `install-hooks-copy`, and `install-uninstall-layout-loop` test files into `tests/install.test.cjs` (parameterized over all 15 runtimes) and `tests/install-regressions.test.cjs` (date-stamped bug reproductions). Adds Contract 6 counter-test: `resolveRuntimeArtifactLayout` throws `TypeError` for unknown runtimes. Fixes latent `GSD_TEST_MODE` env-pollution bug in all spawned-installer tests. (#3758)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 376
---
Claude installs now rewrite `/gsd:<cmd>` → `/gsd-<cmd>` in installed hook `.js`/`.cjs` files (matching the existing rewriter behavior for other hyphen-namespace runtimes) — statusline / update-banner / workflow-guard / context-monitor messages no longer leak the colon namespace.

View File

@@ -0,0 +1,7 @@
---
type: Fixed
pr: 3762
---
<!-- docs-exempt: internal test refactor — no user-facing behavior changed -->
**Consolidate graphify Module tests — 7 files → 1 (#3761)** — collapses the test-as-changelog anti-pattern where each PR (`enh-3170`, `bug-3166`, `feat-3347-config`, `feat-3347-hook`, `bug-3579`) added a new standalone file instead of appending to the existing `graphify.test.cjs`. All 131 tests (plus one new counter-test for mvp-viz non-mvp path) are now in a single file organized into describe blocks by surface: `status`, `build`, `query`, `staleness`, `mvp-viz`, `auto-update`, `regressions`. Issue-stamped tests carry `// Regression for #NNNN` comments. Adds Knowledge Graph Module glossary entry to `CONTEXT.md`.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3773
---
acquireStateLock no longer silently grants false-success lock acquisition on non-EEXIST openSync errors (EMFILE/EINTR/ENOSPC under load) — the error is now propagated to the caller, preventing two concurrent processes from simultaneously holding the same lock and producing lost-update STATE.md overwrites. (#3773)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3777
---
acquireStateLock and withPlanningLock now retry on transient Docker overlay-fs (ENOENT/EINVAL/EIO) and NFS (ESTALE) errno codes in addition to the existing EPERM/EBUSY; truly fatal codes (EMFILE/ENOSPC/EROFS/EACCES) still throw immediately. Closes #3776.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 378
---
Update check now polls the correct scoped package name (@opengsd/get-shit-done-redux) so update_available works.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3804
---
**`worktree.cleanup-wave` no longer blocks on executor's uncommitted SUMMARY.md** — `executeWorktreeWaveCleanupPlan` previously returned `cleanup_blocked` / `worktree_dirty` when the executor left `<quick_id>-SUMMARY.md` uncommitted in the worktree's `.planning/` directory (the documented contract — the orchestrator commits it). The fix ports the shell-fallback rescue logic from `quick.md` into the CJS function: before the dirty-state check, all `*SUMMARY.md` files under `<worktree>/.planning/` are copied to the main tree (if absent or divergent), then filtered out of the porcelain output. Only non-SUMMARY dirty files now block cleanup. (#3804, mirrors #2296/#2070/#2838)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3805
---
**`fast.md` `log_to_state` no longer appends a malformed row when the STATE.md table uses the 5-column quick.md schema (#3805)** — the workflow unconditionally wrote a hardcoded 4-cell row (`| date | fast | task | ✅ |`) into STATE.md; when `quick.md` Step 7 had already created a 5-column "Quick Tasks Completed" table the mismatched row broke the Markdown table. `fast.md` now reads the existing header, counts columns, and verifies the quick.md column names before appending a properly-formed 5-cell row. If the schema is unrecognized the write is skipped with a warning rather than corrupting the table.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3806
---
**`validate health` no longer emits W005/W006/I001 false positives for multi-digit phase prefixes, milestone-archive phases, and descriptor PLAN/SUMMARY stem pairs** — PR #3479 fixed these three false-positive classes in `sdk/src/query/validate.ts` but the fix never propagated to `get-shit-done/bin/lib/verify.cjs`, which is the runtime bundle that `gsd-tools.cjs validate health` actually executes. This PR ports the three fixes: (1) W005 regex widened from `\d{2}` to `\d{2,}` so `999.1-foo` and other multi-digit backlog directories are accepted; (2) W006 now calls `forEachArchivedPhaseToken` after `collectDiskPhases` so phases whose directories live in a milestone archive are not flagged as missing; (3) I001 now builds the `summaryBases` Set with both raw and canonical plan stems so `68-01-scaffolding-PLAN.md` correctly matches `68-01-SUMMARY.md`. (#3806)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3808
---
**Codex adapter now activates TEXT_MODE when `request_user_input` is unavailable** — `bin/install.js:getCodexSkillAdapterHeader` previously told the agent only to "stop and present plain-text"; it now explicitly instructs the agent to append `--text` to `{{GSD_ARGS}}` so the workflow's built-in `TEXT_MODE` branching handles all `AskUserQuestion` gates consistently, eliminating silent-default selection in Codex Default mode (#3808).

Some files were not shown because too many files have changed in this diff Show More