* docs(#457): rewrite ADR-457 to ground truth and accept build-at-publish
The prior draft asserted a codebase state that never existed (13 tsc-generated
files, src/ trees, a tests/cjs-ts-parity.test.cjs). Corrected to verified ground
truth (84 bin/lib .cjs, 1 value-baked package-identity.cjs, no tsc pipeline),
distinguished value-baking from transpilation so package-identity stops being
miscited as precedent, made check-in-the-artifact vs build-at-publish the central
decision, and flipped status to Accepted (build-at-publish).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* build(#537): pilot TS build-at-publish for bin/lib (semver-compare)
First hand-written module collapsed to a TypeScript source of truth per ADR-457.
src/semver-compare.cts compiles (tsc, strict, noEmitOnError) to a gitignored
get-shit-done/bin/lib/semver-compare.cjs. build:lib is wired into build, pretest,
pretest:coverage, and prepublishOnly so the artifact is built before test and
shipped on publish. Type-aware ESLint on src/**/*.cts immediately caught the
params were over-typed as `unknown` (no-base-to-string); narrowed to a honest
VersionInput domain type. Behavior preserved: semver-compare.test.cjs (14) and
bug-10 (4) pass against the generated output; runtime consumer changeset/cli.cjs
unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#537): make build-at-publish robust across all CI paths (codex review)
Adversarial review found the pilot's generated artifact would be missing on
clean CI checkouts. `pretest`/`pretest:coverage` only fire for `npm test`, but
CI runs `test:unit`/`test:integration`/`test:install` and `node run-tests.cjs`
directly — none of which built the artifact, so any suite requiring
semver-compare.cjs would hit module-not-found on a clean checkout, and
install-smoke's `npm pack` could ship without it.
- Add a `prepare` script (`npm run build:lib`). `npm ci` runs it automatically,
so every CI test job and install-smoke's pack emit the artifact before use.
This is the idiomatic npm mechanism for compiled-output-not-in-git and fixes
both the test and pack paths in one place.
- Add `src/` + `tsconfig.build.json` to ci-test-scope and the install-smoke /
mutation path filters, so a source-only edit to a migrated module still
triggers its tests and mutation coverage (prevents silent CI skips).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#537): map src/*.cts to built artifact in mutation changed-files detection
Follow-up to the codex re-review. The prior commit added src/**/*.cts to the
mutation workflow's path trigger but left its "compute changed core lib files"
step diffing only get-shit-done/bin/lib/**/*.cjs — which are now gitignored and
never appear in a diff. A source-only edit would trigger the workflow then
early-exit ("no core lib files changed"), silently skipping mutation testing.
Map each changed src/*.cts to its built get-shit-done/bin/lib/*.cjs path (the
on-disk artifact Stryker mutates after prepare/build:lib), merge with the
hand-written .cjs diff, and apply the test/excluded-module filters once.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#537): use 'src/' pathspec in mutation diff (git glob doesn't match top-level)
Codex review caught that `git diff -- 'src/**/*.cts'` returns empty for a
top-level file like src/semver-compare.cts — git's default pathspec glob does
not match `**` across zero directories (verified on git 2.50.1). The prior
commit's src-detection therefore never fired, so source-only changes still
skipped mutation. Switch to the dir-scoped pathspec 'src/' + a `.cts` grep
(robust for flat and nested layouts), and broaden the workflow path trigger to
'src/**' to match install-smoke. Verified end-to-end: a change to
src/semver-compare.cts now resolves to get-shit-done/bin/lib/semver-compare.cjs
in the --mutate list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#537): add changeset fragment for build-at-publish pilot
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#537): replace prepare with prepack + build-if-missing; defer mutation wiring
CI surfaced three real issues the local run and codex review missed:
1. lockfile-sync failed on every platform. Root cause: `npm ci --dry-run` (the
repo's lockfile health check) RUNS the `prepare` script, but in dry-run the
devDependencies aren't installed, so `tsc` is not found (exit 127) and the
check reports a misleading "out of sync". `prepare` is the wrong hook for a
build needing a devDep. Replace it with `prepack` (runs only on pack/publish,
when node_modules exists) for the tarball path, and build the artifact inside
scripts/run-tests.cjs (build-if-missing) for the test path — the universal
chokepoint every CI test invocation funnels through, including the direct
`node run-tests.cjs --files-from` step that bypasses npm lifecycle hooks. The
guard is a no-op once built, so the run-tests harness test is unaffected.
2. The Stryker mutation gate ran only 1 test against semver-compare (~0% score,
71/71 mutants surviving) — a Stryker test-selection problem orthogonal to the
build migration, and raising the score needs property tests (ADR-456). Revert
the mutation.yml src wiring; mutation coverage for src-authored modules is a
separate follow-up tracked in #537. (The deletion of the gitignored top-level
.cjs does not match the workflow's `bin/lib/**/*.cjs` git pathspec, so the
gate skips cleanly.)
Verified: clean-room `npm ci --dry-run` exits 0; deleting the artifact then
running a suite rebuilds it; run-tests harness 22/22 green; `npm pack` includes
the built artifact via prepack.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#448): resolve UI safety gate helper against the GSD install dir
The §5.6 UI Design Contract Gate (and autonomous §3a.5) resolved
ui-safety-gate.cjs via `git rev-parse --show-toplevel`, i.e. the
consuming project's git root — which has no bin/lib. The node call
failed, its exit code was conflated with "no UI", and the gate
silently no-opped so frontend phases skipped the UI-SPEC prompt.
Resolve the helper against the GSD install dir via RUNTIME_DIR (the
same idiom §1 uses for gsd-tools), with git-toplevel and $HOME/.claude
fallbacks. When the helper genuinely can't be found, fail OPEN with a
stderr warning (assume UI present) rather than silently skipping.
Tests: bug-3706 structural guard now requires RUNTIME_DIR resolution
and forbids the consuming-project GSD_REPO_ROOT anchor; a new
behavioral test resolves and runs the helper from a temp consuming
project (no bin/lib) with RUNTIME_DIR set. autonomous-ui-steps updated
to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#448): add changeset fragment for PR #539
* fix(#448): add get-shit-done/bin/lib/ to UI gate probe and deploy helper there
The installer copies get-shit-done/ to the target but not root bin/lib/, so
the helper was never found for installed users. Placing ui-safety-gate.cjs in
get-shit-done/bin/lib/ ensures the installer deploys it, and probing that path
first makes the gate work correctly in installed runtimes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: update changeset to cover get-shit-done/bin/lib/ deployment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: update inventory for ui-safety-gate.cjs in get-shit-done/bin/lib/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#447): scope post-planning gap analysis to phase_req_ids
§13e gap-analysis diffed the entire REQUIREMENTS.md against a phase's
plans even when the phase mapped no REQ-IDs, so a phase mapping nothing
reported every unrelated project requirement as "not covered".
Teach the gap-analysis CLI a --phase-req-ids option (null/TBD skips the
requirements comparison, an ID list scopes to it, absent = unchanged
back-compat) and have §13e pass the phase's mapped IDs — mirroring the
§13 Requirements Coverage Gate's null/TBD skip. CONTEXT.md decisions stay
in scope regardless.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#447): source phase_req_ids from init.plan-phase, not roadmap.get-phase
Adversarial-review follow-up. roadmap.get-phase returns the raw phase
markdown (not JSON), so `--pick phase_req_ids` yielded nothing and §13e
would have skipped the requirements comparison for EVERY phase — a
silent regression. phase_req_ids is exposed by init.plan-phase; switch
§13e to it. Adds an integration test asserting the query exposes the
IDs and that gap-analysis scopes to them (and skips when unmapped).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#447): add changeset fragment for PR #538
* fix(#447): surface mapped REQ-IDs absent from REQUIREMENTS.md as explicit missing rows
Previously, a phase_req_ids entry not found in REQUIREMENTS.md was silently
dropped from the gap report, allowing the analysis to falsely report full
coverage when the requirement document had drifted.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: update changeset to cover missing-REQ-ID detection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#191): migrate gsd-sdk query call sites to gsd-tools query
Retiring the gsd-sdk shim. gsd-tools.cjs already accepts `query` as a
meta-prefix (gsd-tools query <command>), so this is a behavior-preserving 1:1
swap across the runtime reference prompts, the graphify hook's commit-detection
gate, and two bin/lib comment/message references.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#191): remove vestigial gsd-sdk shim code from installer + projection
The gsd-sdk shim was already not wired up (no gsd-sdk bin in package.json;
buildWindowsShimTriple had zero call sites). Remove the dead code:
- shell-command-projection.cjs: buildWindowsShimTriple + formatSdkPathDiagnostic
(+ their now-unused PACKAGE_NAME import) and exports
- install.js: the re-export wrappers + imports, the #3406 stale-standalone-sdk
detection (detectStaleStandaloneSdk/formatStaleStandaloneSdkWarning + its
global-install call site), and the exports
Preserved (retained, not gsd-sdk): buildCodexHookWindowsShimIR (#3426) — only
its comments referenced the gsd-sdk pattern; reworded. Also kept the
homePathCoveredByRc 'reopen your shell' branch in maybeSuggestPathExport — its
logic is bin-dir-agnostic, only the message mentioned gsd-sdk; reworded to use
the actual bin dir.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#191): update tests for retired gsd-sdk shim
- bug-3441/bug-3442: drop the formatSdkPathDiagnostic / buildWindowsShimTriple
assertions (functions removed); retained PATH-action + drift-guard tests stay
- bug-505: remove the 'still exported' assertions for detectStaleStandaloneSdk /
formatStaleStandaloneSdkWarning / the shim contract surface (#505 kept them;
#191 removes them)
- graphify-auto-update: migrate the hook-dispatch inputs gsd-sdk query commit ->
gsd-tools query commit to match the migrated commit hook
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#191): point active docs at gsd-tools query (gsd-sdk shim retired)
Update the user/agent-facing docs (AGENTS, COMMANDS, CONFIGURATION, USER-GUIDE,
ship-pr-body-sections) that presented gsd-sdk query as a current command to
gsd-tools query. Historical docs (ADRs, PRDs, release notes) left untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#191): correct state.load vs state.json description for gsd-tools query
Adversarial-review (codex) finding: the migrated USER-GUIDE line claimed both
'gsd-tools query state.json' and 'state.load' resolve to the frontmatter-rebuild
handler. Verified they don't — state.load returns the CJS load shape
(config + state_raw + flags), state.json returns the frontmatter shape. Both are
available via gsd-tools query; corrected the text to say so.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#191): add changeset for gsd-sdk shim retirement
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* chore: rename npm package + bin to @opengsd/gsd-core (functional)
- package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core,
bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs
- package-lock.json: regenerated (npm install --package-lock-only)
- tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**,
get-shit-done/bin/**, get-shit-done/workflows/**:
applied the 4-rule replacement (scoped npm ref, GitHub repo path,
bin/clone invocations) per #505 single-source refactor
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: sweep live references to @opengsd/gsd-core
Update all live documentation (README.md + translations, docs/**,
CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md,
docs/CANARY.md) to reflect the renamed package and repository.
Rules applied:
- @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name)
- open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo)
- GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org)
- bare bin/clone refs → gsd-core
CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**,
and .changeset/** are preserved byte-identical.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: add negative lookbehind to slash-command regex in bug-2954 test
The extractSlashReferences regex matched /gsd-core inside npm package
URLs (@opengsd/gsd-core), producing a false /gsd:core command reference.
Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a
letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#518): add changeset for package rename
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#518): update package-identity expectations to the renamed coordinates
The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo
open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL
package.json, so their expected literals must follow the rename. The drift-lint
unit test is left as-is — its SEAM is a self-consistent fixture and its
stale-literal detection cases would shift if altered; the live-repo scan in it
already passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#22): add plan_review.source_grounding + _authority config keys
Two additive opt-out keys for the drift guard: source_grounding (bool,
default true) gates the source-grounded reviewer pass; _authority (enum
grep|intel|treesitter|lsp|scip, default grep) selects the resolver rung.
No existing default changed.
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(#22): add intel api-surface renderer + CLI subcommand
Renders .planning/intel/api-map.json into a human-readable API-SURFACE.md
for planner injection. Empty/missing map still writes a surface that
announces itself incomplete (absence = unknown, not 'does not exist').
Gated on intel.enabled like all intel functions.
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(#22): add source-grounding pass to plan-review-convergence
Default-on reviewer pass (plan_review.source_grounding) that enumerates
every symbol a plan cites, excludes declared new artifacts, resolves each
against source via the configured authority adapter, and records
three-valued verdicts. rung-0/1 MISSING is needs-acknowledgement, not a
hard block; UNCHECKABLE is logged in a REVIEWS.md coverage section.
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(#22): inject API-SURFACE.md into planner + require Artifacts section
When intel.enabled, plan-phase regenerates API-SURFACE.md and injects it
as a HINT (prefer, may be incomplete, absence = unknown), never a hard
rule. Every plan must now emit an 'Artifacts this phase produces' section
so the source-grounding reviewer can separate new symbols from references
to existing code.
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(#22): surface drift-guard in setup + settings, add docs
/gsd:new-project asks to enable plan_review.source_grounding (default Y);
/gsd:settings exposes the toggle and authority knob. Documents both config
keys in CONFIGURATION.md, the intel api-surface command in COMMANDS.md,
the drift guard in USER-GUIDE.md, and links ADR 22 from ARCHITECTURE.md.
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(#22): respect AskUserQuestion 4-option cap and plan-phase XL line budget
settings drift-guard toggle moved to its own 2-option question; #22
plan-phase additions condensed to bring the file back under the 1810-line
XL budget without dropping the intel gate, the incomplete-surface hint, or
the Artifacts-section requirement.
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(#22): use live slash-command forms in drift-guard docs
Doc-parity gate requires every slash-command token in docs/*.md to resolve
to a registered command. Corrected the command form(s) referenced in the
#22 drift-guard / api-surface documentation.
The unresolved token was /gsd-core, matched from the GitHub repo reference
"open-gsd/gsd-core#22" in docs/adr/22-plan-drift-guard.md. This is the
same pattern as the existing 'test-runner' exemption (open-gsd/gsd-test-runner).
Added 'core' to INTERNAL_COMPONENT_SLUGS with a matching explanatory comment.
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(#22): add changeset fragment for drift guard (PR #487)
Refs #22
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor: remove stale sdk/src generated-file banners from bin/lib/*.cjs (#506)
Drop the GENERATED FILE / Source: sdk/src / Regenerate: cd sdk banners from
13 hand-maintained CJS modules and delete the orphaned
generator-freshness-contract script + test. Post-ADR-0174 cleanup; the
referenced sdk/ generator pipeline (dir, gen:* scripts, *.generated.cjs) no
longer exists. No runtime behavior change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: add changeset for #510 (sdk/src banner cleanup)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#498): generated package-identity seam derived from package.json
Introduce a single source for GSD's published-package coordinates:
scripts/generate-package-identity.cjs (pure deriveIdentity + formatManualInstall
+ render) emits the generated get-shit-done/bin/lib/package-identity.cjs with
values baked from package.json at build time. Baking is required because the
installed tree carries only a synthetic {"type":"commonjs"} package.json, so a
runtime require('package.json').name resolves to undefined (#378). Reconciles
Wired into npm run build; a parity test fails CI if the committed file drifts
from package.json.
Refs #498
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#498): repoint update worker + check-latest-version at the seam
- check-latest-version.cjs sources PACKAGE_NAME from the package-identity seam
instead of a re-typed literal (single source; #2992's constant guarantee is
preserved since the seam bakes from package.json).
- gsd-check-update-worker.js no longer does require('../package.json').name
(resolved to undefined in the installed tree → background update check
silently broken, #378). It now delegates the latest-version lookup to
checkLatestVersion(), collapsing the duplicated npm-view call onto the single
deterministic adapter and inheriting its typed {ok,version,reason} surface.
- Move the PR #3102 Windows shell-gate contract test onto execNpm (where the
spawn now lives) and assert the worker no longer spawns npm directly.
- Rewrite the #378 contract: worker must NOT use require(package.json).name and
must delegate; check-latest-version PACKAGE_NAME is single-sourced from the seam.
Fixes #378-class runtime breakage. Refs #498
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#498): changeset for package-identity seam + update-check fix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#498): drift-guard lint — value-check GSD coordinate literals against the seam
scripts/lint-package-identity-drift.cjs scans the runtime/code surface
(bin/, hooks/, scripts/, get-shit-done/) and asserts every GSD package name
and GitHub repo slug literal equals the Package Identity seam's current value.
Passes today; fails the moment a repoint isn't propagated (rename package.json,
regenerate the seam, and stale literals are reported until updated). This is
the second adapter that makes the seam real and a repoint mechanically safe.
Enforced via tests/issue-498-identity-drift-lint.test.cjs (scanRepo === [])
under npm test; also exposed as `npm run check:identity-drift`.
Refs #498
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#498): update-context projection — port update.md resolution to a tested seam
Add get-shit-done/bin/lib/update-context.cjs: a pure, injected-fs port of
update.md's ~280-line get_installed_version bash. resolveUpdateContext()
reproduces the full precedence cascade (preferred fast-path -> local probe ->
global probe via env overrides then $HOME -> LOCAL-if-distinct -> scope
cascade -> UNKNOWN) and returns the 4-field contract { installedVersion,
scope, runtime, gsdDir }. The fs is injected so every branch is finally
testable without a live multi-runtime install.
Expose it as `gsd-tools update-context [--config-dir <d>] [--runtime <r>] --json`.
Purely additive — update.md is unchanged in this commit; the workflow swap
follows separately.
Refs #498
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#498): swap update.md resolution to the update-context projection
Replace ~280 lines of inline runtime/scope/config-dir bash in update.md's
get_installed_version step with a call to `gsd-tools update-context --json`
(60 lines: derive PREFERRED_* from execution_context, resolve gsd-tools.cjs,
parse the 4-field JSON). Behavior is unchanged — the projection reproduces the
same cascade — but the logic is now tested in update-context.cjs instead of
untestable bash-in-markdown.
Relocate the #3608 antigravity-first-class contract onto the projection
(RUNTIME_DIRS order, inferPreferredRuntime, envRuntimeDirs) plus a behavioral
test; keep the execution_context path-classification assertion on update.md.
Re-point install.test's custom-config-dir assertion (kilo.jsonc/KILO_CONFIG)
to update-context.cjs where that detection now lives.
Full root suite: 2022 pass / 0 fail.
Refs #498
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#498): record Update Context Module in CONTEXT.md
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#498): CI — avoid bare gsd-tools in update.md; register new CLI modules
- update.md update-context invocation: resolve the PATH gsd-tools shim into a
variable and call "$GSD_TOOLS" (never a bare `gsd-tools` command) — satisfies
the #2851 workflow-bare-gsd-tools guard.
- Register package-identity.cjs and update-context.cjs in docs/INVENTORY.md
(CLI Modules 76 -> 78 + rows) and regenerate docs/INVENTORY-MANIFEST.json,
fixing inventory-counts and inventory-manifest-sync.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#498): make update-context + parity tests OS-agnostic (Windows CI)
Two Windows-only test failures, both test-portability (production code is fine —
the real-fs CLI integration test passed on Windows):
- update-context resolver tests + bug-3608 behavioral test used POSIX path-string
keys in their fake fs, but the resolver builds lookups via path.join/resolve
(backslash + drive letter on Windows) → keys never matched → everything
resolved to UNKNOWN/claude. Normalize fake-fs keys and gsdDir comparisons
through path.resolve so they match on both platforms.
- package-identity parity test compared render() (LF) to the committed file,
which Windows git checks out as CRLF (no .gitattributes eol rule). Normalize
line endings before comparing, matching the repo convention
(autonomous-decomposition, bug-3707).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#498): update.md backup must use GSD_DIR (adversarial-review finding)
The get_installed_version rewrite emits GSD_DIR but dropped the probe-loop
variables LOCAL_DIR/GLOBAL_DIR. The backup_custom_files step still read those,
so RUNTIME_DIR went empty for every LOCAL/GLOBAL install and detect-custom-files
was skipped — and since the update then runs a clean install that wipes managed
dirs (commands/gsd, get-shit-done), user-added files could be deleted without
the intended backup.
Set RUNTIME_DIR="$GSD_DIR" directly (the resolved config dir; empty for
UNKNOWN scope, which still skips the backup). Add a structural regression
(tests/issue-498-update-backup-runtime-dir.test.cjs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#503): re-point Antigravity .agent detection at the #498 projection
#499 moves the runtime/scope detection cascade out of update.md inline bash
into get-shit-done/bin/lib/update-context.cjs. The #503 regression test asserted
on the inline RUNTIME_DIRS array, which no longer exists, so it would fail
against the projected update.md even though the .agent guarantee is preserved.
Rewrite it to verify the surviving surfaces:
- behavioral: resolveUpdateContext resolves a LOCAL ./.agent install to the
antigravity runtime (the original root cause, now covered by adding
['antigravity', '.agent'] to the projection RUNTIME_DIRS table)
- update.md prose classifier still maps /.agent/ -> antigravity
- the post-update cache-clear for-dir loop still includes .agent
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#498): finish de-hardcoding consumers + close adversarial-review parity gaps
Restore the consumer de-hardcoding that is the point of the seam, and close the
parity gaps an adversarial review (codex) found in the update-context projection.
De-hardcode the repo slug + install command in the changeset tooling — #516
only single-sourced the package NAME, leaving 'open-gsd/get-shit-done-redux'
hardcoded in scripts/changeset/cli.cjs and github-release-notes.cjs. Route both
through the seam's repoSlug/packageName so a rename is a regenerate, not a hand
edit. The drift-lint real scan now reports zero divergent coordinate literals.
Projection parity vs the old inline bash, as ONE consistent rule
(trustedVersionAt) applied on every path:
- expand a leading ~/ in preferredConfigDir before the fast path (the bash ran
expand_home first; a custom --config-dir ~/foo otherwise fell to UNKNOWN)
- trust a version only when BOTH VERSION and the update.md marker exist — fast
path AND LOCAL/GLOBAL cascade; a partial dir falls to 0.0.0 keeping scope
- apply the same same-path dedup to the 0.0.0 fallback so a partial install
probed from cwd===home is not misdetected as LOCAL
Adds regression tests for tilde expansion, VERSION-only (cascade + fast path),
and the cwd===home partial-install dedup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#516 added get-shit-done/bin/lib/package-identity.cjs without regenerating
the inventory, breaking inventory-manifest-sync and inventory-counts on next.
Regenerate docs/INVENTORY-MANIFEST.json and bump docs/INVENTORY.md
CLI-module count 76 -> 77 with the new row.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Adds get-shit-done/bin/lib/package-identity.cjs as the single source of
truth for PACKAGE_NAME, derived from package.json `name` via require.
Refactors all runtime code-line occurrences in bin/install.js,
get-shit-done/bin/check-latest-version.cjs,
get-shit-done/bin/lib/shell-command-projection.cjs,
get-shit-done/bin/lib/verify.cjs, scripts/changeset/cli.cjs,
scripts/changeset/github-release-notes.cjs, and
scripts/release-tarball-smoke.cjs to import PACKAGE_NAME from the
identity module instead of hardcoding the literal.
The package name is unchanged (@opengsd/get-shit-done-redux). Behaviour
is byte-identical: all --help, hint, and release-notes strings render
exactly as before. Golden-literal tests (bug-2992, bug-378) keep their
hardcoded expected values and remain GREEN.
Adds tests/package-name-single-source.test.cjs lint guard: fails CI if
@opengsd/get-shit-done-redux appears as a code-line literal in runtime
.cjs/.js outside the identity module, enforcing a one-file rename path.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#505): remove dead SDK-shim verification subsystem from bin/install.js
Post-ADR-0174 the @opengsd/gsd-sdk package was retired; sdk/ no longer ships.
installSdkIfNeeded had no callers in the live install flow and its entire
transitive call graph (classifySdkInstall, buildSdkFailFastReport,
renderSdkFailFastReport, buildGsdSdkVersionMismatchReport, readGsdSdkVersion,
parseGsdSdkVersion, findGsdSdkOnPath, isGsdSdkOnPath, isLegacyGsdSdkShim,
filterNpxFromPath, getUserShellPath, getUserShellWindowsPersistentPath,
trySelfLinkGsdSdk, trySelfLinkGsdSdkWindows, buildWindowsShimTriple,
formatSdkPathDiagnostic, renderGsdSdkVersionMismatchReport) was dead code.
Also removed two now-empty test files (no-unconditional-win32-skip.test.cjs,
bug-3020-install-shell-path-probe.test.cjs) that exercised the removed
functions, and added a regression guard (bug-505-remove-dead-sdk-verification.test.cjs).
detectStaleStandaloneSdk and formatStaleStandaloneSdkWarning are deliberately
KEPT — they handle a real leftover-global-SDK condition (#3406).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: add changeset for #505 dead SDK-shim removal
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#505): restore buildWindowsShimTriple/formatSdkPathDiagnostic projection surfaces
The dead-code removal also deleted buildWindowsShimTriple and
formatSdkPathDiagnostic (plus their imports/exports). These have no
production caller, but they are the install.js side of a projection-contract
drift guard: tests/bug-3441 and tests/bug-3442 assert install.js delegates to
shell-command-projection.cjs rather than hand-rolling the projection. Removing
them broke those tests (TypeError: ... is not a function) — surfaced by the
full/coverage CI matrix, which runs suites the local scoped run skipped.
Restore the two thin wrappers, their `*FromProjection` import aliases, and
their exports. Update the bug-505 guard test to assert they remain exported as
contract surfaces (moved out of the dead-symbol list).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#500): stop state planned-phase corrupting milestone progress.* counters
Two independent defects combined to corrupt STATE.md progress.* on a
plan-phase run:
RC1 — cmdStatePlannedPhase wrote via writeStateMd, which unconditionally
runs syncStateFrontmatter and rebuilds progress.* (total/completed
plans+phases) from a half-planned disk snapshot, trampling curated
counters. It now routes through readModifyWriteStateMd(..., { resync:false }),
the same body-only-write guard state.update uses — per-phase body fields
are updated, milestone progress.* is preserved.
RC2 — isRootPlanFile's loose /PLAN/i fallback matched legacy
`<N>-PLAN-<NN>-SUMMARY.md` names (they contain "PLAN"), double-counting
summaries as plans (a 4-plan/4-summary phase scanned as planCount:8,
completed:false). isRootPlanFile now rejects isRootSummaryFile before the
fallback, so summaries are never counted as plans.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#500): add changeset for planned-phase progress fix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#501): stop flat "## Phase Details" leaking phases into active milestone
extractCurrentMilestone returned `preamble + currentSection`, where the
preamble (everything before the first milestone heading, only <details>
stripped) could carry a flat "## Phase Details" section listing `### Phase N:`
entries for ALL milestones. Those leaked into the active-milestone scope, so
getMilestonePhaseFilter / buildStateFrontmatter counted the whole project
(e.g. total_phases: 18) instead of the active milestone (14-18).
Fix (maintainer direction: code fix, count + validate-aware):
1. core.cjs extractCurrentMilestone — strip flat phase-detail blocks
(`### Phase N:` heading + body, and a "## Phase Details" heading) from the
preamble. The active milestone's own phases live in currentSection, so this
is safe. Fixes the count with no ROADMAP edits.
2. verify.cjs cmdValidateConsistency + cmdValidateHealth — the "phases on disk
but not in ROADMAP" / W007 checks now compare disk dirs against the FULL
roadmap (every milestone), not the active-milestone scope. Without this,
narrowing the scope would flag every shipped phase dir as a spurious orphan
(the documented side effect of the <details> workaround).
Tests reproduce the real layout (flat Phase Details before milestones) and
assert: state json total_phases counts only active phases; validate
consistency and validate health (W007) do not flag shipped phase dirs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#501): add changeset for flat Phase Details milestone leak fix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#503): detect local Antigravity (.agent) installs in /gsd:update
The installer places local Antigravity installs in ./.agent/
(bin/install.js getDirName('antigravity') === '.agent'), but the
/gsd:update detection cascade in update.md only knew the global
Antigravity layout (.gemini/antigravity{,-ide,-cli}). A local .agent
install fell through to the `Otherwise -> claude` default, so the
update refreshed Claude artifacts instead of the Antigravity install.
Add `.agent` -> antigravity to all four runtime-dir surfaces in
update.md: the execution_context path classifier, the RUNTIME_DIRS
candidate array, the local-scope discovery loop, and the post-update
cache-clear loop (the last otherwise left a stale update indicator on
local Antigravity installs).
Note: the issue also cited update-context.cjs, which does not exist on
`next` (it is introduced by the still-open PR #499). The same .agent
fix should be carried into update-context.cjs when #499 lands.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#503): add changeset for Antigravity .agent detection fix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
classify() under-approximated breakable checks, so scoped PRs skipped the
check their diff would break and regressions reached next (#484 docs-parity,
#482 windows-22 EBUSY). Fail-safe widen: any tests/** change forces
full_matrix (OS-specific test failures); any docs/**, commands/**, agents/**
change marks code_changed and selects docs-parity-live-registry (its runtime
inputs). Updated the docs-only test that asserted the old buggy contract.
Fixes#494
Co-authored-by: CI Rebase Check <ci@gsd-redux>
* fix(#474): route state date-stamping + installer lock loop through clock seam (nowIso/today + GSD_NOW_MS adapter)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(#474): use process.ppid (not pid 1) as held-lock owner in install-lock timeout test
pid 1 is POSIX init/launchd (always alive) but does not exist on Windows,
so isPidAlive(1) returns false, the lock is reclaimed as stale, and
acquireInstallMigrationLock no longer throws -- failing the timeout
assertion on windows-latest,22. process.ppid is a live, non-self process
on every platform, so the lock is seen as held and the timeout path
throws deterministically cross-platform.
Refs #474
---------
Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
#482 removed the afterEach outer retry guard, trusting rmSync maxRetries:20
(~5s). Under windows-2022 CI load the temp dir stays EBUSY longer, so the
bare cleanup() throws and the hook fails (next went red on full test
(windows-latest, 22)). Restore a bounded retry with async setTimeout backoff
(no Atomics.wait, per no-magic-sleep-in-tests).
Fixes#490
Co-authored-by: CI Rebase Check <ci@gsd-redux>
extractCommandTokens regexes matched the /gsd-core substring inside the
org/repo path open-gsd/gsd-core#22. Add a negative lookbehind so only
actual invocations (BOL / space / backtick / paren) match, not path or
word-embedded segments. Add a regression test covering the repo-path
false positive while proving real broken command refs are still caught.
Refs #489
Co-authored-by: CI Rebase Check <ci@gsd-redux>
The gsd_run resolver preamble now probes
<repo-root>/.claude/get-shit-done/bin/${_GSD_SHIM_NAME} as the second
check — immediately after the existing get-shit-done/bin/ check and
before command -v / $HOME/.claude fallbacks. This covers the install
layout produced by npx @opengsd/get-shit-done-redux@latest --claude --local.
A _GSD_RUNTIME_ROOT variable is introduced to bind the repo-root
expression once and reuse it for both checks without repeating the
git rev-parse subshell.
76 workflow files regenerated via node scripts/sync-runtime-launcher.cjs.
All parity, size-budget, and new regression tests pass.
Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract a pure `parseConfigDirFromArgs(argsArray)` seam from the
closure-based `parseConfigDirArg()` and fix the equals-form parser to
use `slice(indexOf('=') + 1)` instead of `split('=')[1]`, so that
paths like `/tmp/gsd=a` or `/tmp/a=b=c` are preserved in full.
Both `--config-dir=<path>` and `-c=<path>` are fixed. The pure seam
is exported via `module.exports` so the 12-case unit test can assert
on typed return values without spawning a child process.
Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 45s detached-subprocess poll caller was removed by #453; this deletes the
residual dead waitForStateMatch helper (silent-expiry anti-pattern) and the
redundant Atomics.wait-based afterEach retry loop (cleanup() already retries via
fs.rmSync maxRetries:20). Net deletion; deterministic tests untouched.
Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consolidated decision record: source-grounding verification default-on
(plan_review.source_grounding), intel.enabled stays opt-in, and the
three-valued symbol-resolver seam with a climbable adapter ladder.
Refs #22
Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add scripts/changeset/README.md specifying the cli.cjs extract
subcommand: invocation, flags, version validation, exit-code table
(0/1/2), and output shapes for text and --json modes.
Corrects two inaccuracies from the triage table against the source:
v-prefixed versions ARE accepted (stripped), and it is pre-release/
build suffixes that are rejected — not the v prefix. Also documents
the full exit-1 surface (missing flags, invalid semver, missing
changelog) and the exit-2 overlap (empty range vs malformed argv) so
external callers do not conflate "no releases in range" with failure.
Closes#23
Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>