CodeRabbit surfaced one outstanding inline finding plus an outside-diff
finding and a finer point on two already-remediated sites; all addressed:
1. (inline, Minor) runtime-slash.cjs:31 — a degenerate input like `/gsd:`,
`gsd:`, or `gsd-` normalizes to empty and the previous fallback returned
the original colon-form input, reintroducing the deprecated shape the
module exists to suppress. Now returns `''` (empty string) so callers
see "no command" instead of an unroutable string. Also catches
whitespace-only inputs the same way. New unit tests pin the contract.
2. (inline, Major) drift.cjs library purity — the earlier remediation
passed `projectDir` into `detectDrift` and re-resolved runtime inside the
library. CodeRabbit (correctly) flagged this as breaking the module's
pure-library contract. detectDrift now accepts `input.runtime` directly;
verify.cmdVerifyCodebaseDrift resolves the runtime once and passes the
literal name in. drift.cjs no longer reads env or config at all.
3. (duplicate inline, Minor) gsd2-import.cjs:475 — when
`gsd2-import --path <dir>` targets a project that isn't the process
cwd, the preview command was formatted for the wrong runtime.
buildPreview now receives the resolved `projectDir` (the same one
used to find the .gsd/ root) instead of the raw `cwd`.
4. (outside-diff, Minor) tests/copilot-install.test.cjs:1-5 — the
`allow-test-rule: integration-test-input` rationale block specifically
named verify.cjs as the fixture, but #3584 changed that test to use a
synthetic input. Comment now describes the real shape of the file's
readFileSync usage (commands/, agents/, install.js source inputs to
the installer/converter functions under test) and notes the synthetic
substitution for the bin/lib path.
Full suite: 9366/9366 pass (+1 new test). Lint clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex review surfaced five issues in the initial slash-formatter PR — three MED
and two LOW. All five are addressed:
1. (MED) formatter corrupted argument tails under codex runtime. Splitting on
the first whitespace and lowercasing only the command token preserves
path-like arguments (`Map-Codebase --paths C:\\Users\\Me\\Project`) and
case-sensitive flag values. (`runtime-slash.cjs`)
2. (MED) profile-output `cmdGenerateDevPreferences` emitted a hardcoded
`command_name: '/gsd-dev-preferences'`. Replaced with
`formatGsdSlash('dev-preferences', resolveRuntime(cwd))` so the structured
result honors codex/skills runtime distinction. (`profile-output.cjs`)
3. (MED) `drift.detectDrift` → `buildMessage` called `resolveRuntime(null)`,
ignoring a project's `.planning/config.json` `runtime` setting when
`GSD_RUNTIME` env var was absent. Threaded `projectDir` through
`detectDrift({projectDir})` → `buildMessage(..., projectDir)` →
`resolveRuntime(projectDir)`. `verify.cmdVerifyCodebaseDrift` now passes
`cwd` into the detect call. (`drift.cjs`, `verify.cjs`)
4. (LOW) `gsd2-import.buildPreview` had the same env-vs-config issue. Threaded
`cwd` through `buildPreview(..., projectDir)` for parity. (`gsd2-import.cjs`)
5. (LOW) The codex emitter test only asserted absence of `/gsd:` — a regression
to `/gsd-` (skills) form in codex output would have passed undetected.
Added positive assertions that every gsd-referencing fix string under
`GSD_RUNTIME=codex` contains `$gsd-` and contains neither `/gsd-` nor
`/gsd:`. Also added formatter unit tests pinning the argument-tail
preservation contract for both hyphen and codex runtimes.
Full suite: 9365/9365 pass (+2 new). Lint clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduce `runtime-slash.cjs` as the single source of truth for emitting
GSD slash-command references in user-facing runtime output and persisted
artifacts. `formatGsdSlash(commandName, runtime)` produces `/gsd-<cmd>`
for skills-based runtimes (Claude/Cursor/OpenCode/Kilo/etc.) and
`$gsd-<cmd>` for Codex. The deprecated `/gsd:<cmd>` colon form is never
emitted — pasting a recommended-action command into Claude Code now
routes correctly instead of failing with `Unknown command`.
Wired into the high-impact emitters identified in #3584:
- `init.cjs` `cmdInitManager` recommended_actions[].command (the
original failure path in the bug report) plus the no-ROADMAP /
no-STATE error hints.
- `phase.cjs` `cmdPhaseAdd`, `cmdPhaseAddBatch`, `cmdPhaseInsert` —
ROADMAP.md `Plans:` references now persist the routable form
instead of the legacy colon form.
- `verify.cjs` `cmdValidateHealth` — every fix-hint addIssue() call
(E001/E002/E003/E004/E005, W002/W003/W008/W009/W011/W016/W018) and
the persisted STATE.md regenerate / MILESTONES.md backfill notes.
- `milestone.cjs` `cmdMilestoneComplete` — Operator Next Steps tail
rewrite.
- `validate-command-router.cjs` — `validate context` recommendation
strings for WARNING/CRITICAL utilization bands.
- `workstream.cjs` — missing .planning hint.
- `profile-output.cjs` — `generate-claude-md` workflow enforcement
block, project/skills fallbacks, profile placeholder, and the
dev-preferences refresh hints.
- `drift.cjs`, `gsd2-import.cjs`, `commands.cjs scaffold context` —
remaining one-off persisted references.
Runtime detection: `resolveRuntime(projectDir)` reads
`process.env.GSD_RUNTIME` first, then a side-effect-free direct read of
`.planning/config.json` (NOT `loadConfig`, which would normalize legacy
keys and re-write the file just to read the runtime name).
Tests:
- `tests/bug-3584-runtime-slash-formatter.test.cjs` — 22 unit tests
covering the pure formatter and resolver (hyphen vs codex, prefix
normalization, defensive returns, env/config/default chain).
- `tests/bug-3584-runtime-slash-emitters.test.cjs` — 6 integration
tests exercising `init manager`, `phase add` (via the structured
`roadmap get-phase` payload to avoid raw-text matching on the
on-disk artifact), `validate health`, `validate context`, and the
codex variant.
- Existing tests updated to assert the new contract: validate-context
recommendations, claude-md workflow block, milestone complete
Operator Next Steps. Copilot-install engine-conversion test now
asserts against a synthetic input since bin/lib/*.cjs no longer
contains literal `/gsd:` references for the install-time converter
to rewrite.
INVENTORY.md and INVENTORY-MANIFEST.json updated for the new module
(64 CLI modules shipped, +1).
Fixes#3584
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(shell-projection): remove deprecated wrappers + finalize ADRs (Phase 4, #3468)
Final phase of the shell-command-projection expansion. Removes the legacy
core.cjs wrappers (`atomicWriteFileSync`, `safeReadFile`, `normalizeMd`)
now that every call site lives behind the seam, plus three Phase-3
stragglers (`graphify.cjs`, `template.cjs`, dead import in
`profile-pipeline.cjs`).
Documentation:
- ADR-0009: addendum noting Phase 1–4 scope expansion (subprocess +
file I/O ownership), supersession of "does not execute" constraint,
and resolution of open Q4.
- ADR-0010: status changed to Superseded by ADR-0009 with explanation.
- CONTEXT.md "Shell Command Projection Module" entry already current
from Phase 1 — no edit needed.
Tests:
- `tests/atomic-write.test.cjs` deleted — wrapper it tested is gone;
`atomic-write-coverage.test.cjs` (Phase 3) covers platformWriteSync.
- `tests/core.test.cjs::safeReadFile` + `::normalizeMd` describes
deleted — wrappers are gone.
- `tests/concurrency-safety.test.cjs` normalizeMd suite (behavioral /
perf / snapshot) repointed via 2-line shim at the seam's
`normalizeContent` — full regression coverage preserved.
Test result: 9059/9041/18 — exact pre-Phase-4 baseline. All 18
failures are pre-existing path-with-spaces local-env issues.
Closes#3468
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(shell-projection): migrate remaining raw fs.writeFileSync sites (Phase 4, #3468)
Sweeps the 7 raw fs.writeFileSync call sites that bypassed the seam through Phase 3,
folding them into platformWriteSync. Net -14 lines: deletes the local writeFileAtomicSync
helper in installer-migrations.cjs and collapses surface.cjs's manual tmp+rename into a
single seam call.
Sites migrated:
- drift.cjs (1) — frontmatter write
- learnings.cjs (1) — learning record JSON write
- install-profiles.cjs (1) — profile marker write (collapsed redundant mkdir)
- gsd2-import.cjs (1) — imported file write (collapsed redundant mkdir)
- surface.cjs (1) — surface state write (replaced manual tmp+rename block)
- installer-migrations.cjs (3) — journal init/finalize + rewrite-json action;
deleted private writeFileAtomicSync helper and its three call sites
Two sites intentionally retained outside the seam:
- planning-workspace.cjs:241 — workspace lock (wx-flag atomic-create; previously excluded by Phase 3)
- installer-migrations.cjs:220 — install migration lock (fd write into wx-opened handle)
- writeInstallState (installer-migrations.cjs) — strict atomic contract for install state;
the seam's fallback-to-direct-write on rename failure would silently violate the
invariant that install state must never be left half-written. Inline tmp+rename with
rethrow keeps the original guarantee.
Tests: 9059 / 9041 / 18 — exactly the pre-Phase-4 baseline; 18 failures are the
pre-existing path-with-spaces local-env issues, identical files as before.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(installer-migrations): use strict atomic write for rollback install-state restore
The rollback path was restoring INSTALL_STATE via platformWriteSync, which falls
back to a direct write on rename failure and would silently violate the
half-written invariant that the install-state contract guarantees elsewhere.
Extracts the strict tmp+rename logic from writeInstallState into a shared
atomicWriteInstallState(configDir, content) helper and routes both
writeInstallState and rollbackAppliedMigrationResult through it. Preserves the
existing null-handling (rmSync when previousInstallStateBytes === null) and
existing failure-collection (failures.push on caught errors).
Byte-faithful restore: previousInstallStateBytes is written as-is (no JSON
parse round-trip), preserving the exact prior file contents on restore.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
All workflow, command, reference, template, and tool-output files that
surfaced /gsd:<cmd> as a user-typed slash command have been updated to
use /gsd-<cmd>, matching the Claude Code skill directory name.
Closes#2697
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Commands are now installed as commands/gsd/<name>.md and invoked as
/gsd:<name> in Claude Code. The old hyphen form /gsd-<name> was still
hardcoded in hundreds of places across workflows, references, templates,
lib modules, and command files — causing "Unknown command" errors
whenever GSD suggested a command to the user.
Replace all /gsd-<cmd> occurrences where <cmd> is a known command name
(derived at runtime from commands/gsd/*.md) using a targeted Node.js
script. Agent names, tool names (gsd-sdk, gsd-tools), directory names,
and path fragments are not touched.
Adds regression test tests/bug-2543-gsd-slash-namespace.test.cjs that
enforces zero legacy occurrences going forward. Removes inverted
tests/stale-colon-refs.test.cjs (bug #1748) which enforced the now-obsolete
hyphen form; the new bug-2543 test supersedes it. Updates 5 assertion
tests that hardcoded the old hyphen form to accept the new colon form.
Closes#2543
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a new command and CLI subcommand that converts a GSD-2 `.gsd/`
project back to GSD v1 `.planning/` format — the reverse of the forward
migration GSD-2 ships.
Closes#2069
Maps GSD-2's Milestone → Slice → Task hierarchy to v1's flat
Milestone sections → Phase → Plan structure. Slices are numbered
sequentially across all milestones; tasks become numbered plans within
their phase. Completion state, research files, and summaries are
preserved.
New files:
- `get-shit-done/bin/lib/gsd2-import.cjs` — parser, transformer, writer
- `commands/gsd/from-gsd2.md` — slash command definition
- `tests/gsd2-import.test.cjs` — 41 tests, 99.21% statement coverage
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>