fix(install): wire --sdk flag into installSdkIfNeeded (#3033)

hasSdk was parsed in bin/install.js but never passed to
installSdkIfNeeded, so `npx get-shit-done-cc@latest --sdk` silently
skipped SDK deployment via the isLocal early-return and emitted a
misleading "✓ GSD SDK ready" message.

installSdkIfNeeded now accepts opts.forceSdk. When true (set from
hasSdk at the call site in installAllRuntimes), the local-install
soft-skip is bypassed so the full shim-link path runs regardless of
install mode. When dist is also missing with forceSdk=true, the
fail-fast diagnostic fires instead of silently returning.

The #2678 soft-skip (isLocal + missing dist + no --sdk) is preserved.

Closes #3033

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-05-06 21:04:03 -04:00
parent f4d0208abb
commit 2bc49b0aec
4 changed files with 194 additions and 15 deletions

View File

@@ -8,22 +8,11 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Fixed
- **`/gsd-quick` worktree-merge resurrection guard no longer deletes brand-new `.planning/` files** — 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. (#3195)
- **`--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)
- **Milestone-archive layout support** — `validate consistency`, `validate health`, and `find-phase` now scan `.planning/milestones/v*-phases/` directories in addition to the flat `.planning/phases/` layout. Projects that have graduated to milestone-archive layout no longer receive spurious W006 "Phase N in ROADMAP.md but no directory on disk" warnings for every active phase. (#3164)
### Feature
- **Vertical MVP discovery & progress surfaces.** `/gsd new-project` now prompts the user to choose between **Vertical MVP** (each phase delivers an end-to-end user capability — recommended for new products) and **Horizontal Layers** (build complete technical layers, assemble at the end). Picking Vertical MVP writes `**Mode:** mvp` on every initial roadmap phase. `/gsd progress` adds a user-flow status sub-block sourced from PLAN.md task names when a phase has `**Mode:** mvp`. `/gsd stats` adds a 'Phases: N total | M MVP | K standard' summary line when at least one MVP phase exists. `/gsd graphify` renders MVP-mode phase nodes with a distinct green fill (`#22c55e`) and a ` (MVP)` label suffix — two-channel signaling for color-blind and grayscale renders. Closes the umbrella PRD #2826. (#2826)
- **MVP-mode UAT framing in `/gsd verify-work`** — when the phase under verification has `**Mode:** mvp` in ROADMAP.md, the generated UAT script asks "can a real user complete the feature?" before any technical checks. User-flow steps (open, fill, click, observe) run first; technical checks (endpoint schemas, error states) only run AFTER the user flow passes. Adds a goal-backward "User Flow Coverage" section to VERIFICATION.md that maps user-story steps to evidence in the codebase. User-story-format guard refuses to verify a `mode: mvp` phase whose `**Goal:**` line is not in user-story format. (#2826)
- **MVP+TDD runtime gate in `/gsd execute-phase`** — when both `MVP_MODE` and `TDD_MODE` are active for a phase, the executor refuses to advance a behavior-adding task until a failing-test commit exists for it. The existing end-of-phase TDD review (advisory by default) escalates to **blocking** under the same condition: phases with missing RED→GREEN commits cannot be marked complete without `--force-mvp-gate`. Pure doc-only / config-only / test-only tasks are exempt. (#2826)
- **`/gsd mvp-phase <N>` command** — guided MVP planning entry point. Prompts for an "As a / I want to / So that" user story (three structured fields), runs SPIDR splitting check (full interactive flow per PRD Q3) if the story is too large, writes `**Mode:** mvp` and the formatted goal to ROADMAP.md, then delegates to `/gsd plan-phase <N>` (which auto-detects MVP via the roadmap mode field shipped in PRD Phase 1). The `gsd-planner` agent now emits a `## Phase Goal` section with bolded **As a** / **I want to** / **so that** keywords as the first content under the phase header in PLAN.md when MVP_MODE is active. (#2826)
- **`--mvp` flag on `/gsd plan-phase`** — opt-in vertical-slice planning. Plans are
organized as feature slices (UI→API→DB) instead of horizontal layers, so each task
moves a real user-visible capability forward. Persistable per-phase via `**Mode:** mvp`
in ROADMAP.md. New-project Phase 1 + `--mvp` triggers Walking Skeleton output
(`SKELETON.md`) capturing architectural decisions for subsequent phases. Single
planner agent, mode-switched (no new agent surface). PRD Phases 2–4 (`mvp-phase`
command, TDD wiring, discovery/UX) deferred to follow-up plans. (#2826)
- **Six namespace meta-skills with keyword-tag descriptions** — replace the flat 86-skill
listing with two-stage hierarchical routing. Model sees 6 namespace routers
(`gsd:workflow`, `gsd:project`, `gsd:review`, `gsd:context`, `gsd:manage`,
@@ -122,7 +111,6 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Fix
- **`generate-claude-md` now writes to `AGENTS.md` on Codex runtime** — when `config.runtime` is `codex` (or `GSD_RUNTIME=codex`), the handler overrides the output target to `AGENTS.md` regardless of `claude_md_path`, so Codex projects no longer have GSD sections written to `CLAUDE.md` by mistake. Explicit `--output` flags are still honoured. Regression covered by `tests/bug-3163-codex-agents-md.test.cjs`. (#3163)
- **`/gsd-graphify build` now runs inline instead of spawning a sub-agent** — 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. Regression covered by `tests/bug-3166-graphify-inline-build.test.cjs` (4 structural assertions that parse `commands/gsd/graphify.md` YAML frontmatter and body to fence against re-introducing `Task` to `allowed-tools` or `Task(` invocation syntax). (#3166)
- **`gsd-pristine/` is now populated by the installer when local patches are detected** — `saveLocalPatches` declared a `pristineDir` variable and JSDoc'd "saves pristine copies (from manifest) to gsd-pristine/ to enable three-way merge during reapply-patches", but no code ever wrote to that directory. Effect: the `/gsd-reapply-patches` Step 5 verifier (#2972) silently degraded to its over-broad fallback heuristic ("every significant backup line"), exactly the silent-success-on-lost-content failure mode #2969 was designed to prevent. Fix: new `populatePristineDir({ packageSrc, pristineDir, modified, runtime, pathPrefix, isGlobal })` helper runs the install transform pipeline (`copyWithPathReplacement`) into a tmp staging dir, then copies out only the modified-file paths into `gsd-pristine/`. `saveLocalPatches` now accepts a `pristineCtx` and calls the helper when local patches are detected; the install entry point passes the package source root, runtime, pathPrefix, and isGlobal so transforms produce byte-identical output to what `copyWithPathReplacement` would have written under normal install. Soft-fails on transform errors (logs a warning, continues with empty pristine — no worse than pre-fix behavior). Pristine reflects the about-to-install version's content, which is what the verifier needs as the "what would survive without the user's modifications" baseline. Regression covered by `tests/bug-2998-pristine-dir-populated.test.cjs` (6 tests across two suites): asserts the helper is exported, returns 0 for empty modified list, writes one pristine file per source-existing path, skips ghost paths without corrupting pristine, and produces deterministic output (two runs with same inputs yield byte-identical pristine — the property `pristine_hashes` in `backup-meta.json` depends on). (#2998)
- **`release-sdk` hotfix re-run no longer fails at `Dry-run publish validation` when the version is already on npm** — the `Detect prior publish (reconciliation mode)` step sets `skip_publish=true` when the package version is already on the registry, and the actual publish step honors that gate. The `Dry-run publish validation` step was missing the same guard, so any operator re-run of an already-published hotfix (the typical recovery path when later steps fail mid-flight) hit `npm publish --dry-run` first and got `npm error You cannot publish over the previously published versions: X.Y.Z` — `npm publish --dry-run` contacts the registry and rejects existing-version targets even though it doesn't actually publish. The dry-run validation step is now gated on the same `steps.prior_publish.outputs.skip_publish != 'true'` condition as the publish step. The rehearsal still runs on first publishes (where it has value); it skips only in the specific reconciliation case where the publish itself would be skipped. Trigger run: [25233855236](https://github.com/gsd-build/get-shit-done/actions/runs/25233855236/job/73995605643). Regression covered by `tests/bug-2987-dry-run-validation-skip-on-reconciliation.test.cjs`. (#2987)