5cd52eb15134d3cfb3667945a0643a87a4a7bfc6
323 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ec8a08f2d2 | docs(#530): streamline README brand header | ||
|
|
c81d5fcb2c | docs(#523): rebrand public docs as GSD Core | ||
|
|
0fbe1d899e |
chore(#191): retire the gsd-sdk shim — route everything at gsd-tools (#522)
* 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> |
||
|
|
79002a00cb |
chore(#518): rename npm package + bin to @opengsd/gsd-core (#519)
* 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> |
||
|
|
b54026e106 |
chore(#516): single-source the package name from package.json (#517)
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> |
||
|
|
a1f4996d9a |
fix(#505): remove dead SDK-shim verification subsystem from bin/install.js (#515)
* 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> |
||
|
|
d7dafafd03 |
fix(#442): --config-dir= no longer truncates paths containing equals signs (#475)
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>
|
||
|
|
b8c33647d8 |
refactor(tests): retire output-grep & source-grep via typed surfaces (finish #2974) (#462)
* refactor(#455): implement typed surfaces to retire grep tests Production surfaces added: - hooks/managed-hooks-registry.cjs: new CJS module exporting MANAGED_HOOKS as a typed array; gsd-check-update-worker.js now requires it instead of declaring an inline array - bin/install.js: elevate inline gsdHooks to module-level GSD_UNINSTALL_HOOKS, export it alongside runtimeMap/allRuntimes (already exported) - scripts/build-hooks.js: export HOOKS_TO_COPY; guard build() behind require.main===module so tests can require the file without triggering a build - get-shit-done/bin/lib/init.cjs: add --json mode to agent-skills command, emitting typed IR { agent_type, block, skills_count } for test assertions - get-shit-done/bin/gsd-tools.cjs: wire --json flag for agent-skills dispatch Category-B source-grep migrations: - tests/managed-hooks.test.cjs: require MANAGED_HOOKS from registry, drop fs.readFileSync+regex - tests/orphaned-hooks.test.cjs: require MANAGED_HOOKS+HOOKS_TO_COPY as typed exports - tests/hooks-opt-in.test.cjs: replace gsdHooks regex-parse with GSD_UNINSTALL_HOOKS import - tests/install-minimal-hooks.test.cjs: replace gsdHooks regex-parse with GSD_UNINSTALL_HOOKS - tests/copilot-install.test.cjs: replace src.includes() checks with typed assertions on runtimeMap, allRuntimes, parseRuntimeInput, buildRuntimePromptText - tests/agent-skills.test.cjs: migrate to --json typed IR assertions pending-migration-to-typed-ir token cleared (87 of 87 files): - 78 files already had source-text-is-the-product; removed duplicate token - 5 files already used typed assertions; reclassified or annotated - 4 files required individual reclassification to source-text-is-the-product or architectural-invariant Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): update workflow-guard test to typed GSD_UNINSTALL_HOOKS import; isolate HOME in runtime-launcher (D) test Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): guard install.js main() behind require.main===module so the typed export is require-safe Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(#455): document --json typed surfaces for agent-skills, progress, validate context Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(#455): add changeset fragment for new --json surfaces Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): complete grep migration for files flagged by lint-tests The branch commit 4e630d99 stripped `allow-test-rule: pending-migration-to-typed-ir` from ~80 test files without replacing their assertions or adding the correct exemption annotation. The files were NOT source-grep tests — they read .md workflow/agent/command/reference files (source-text-is-the-product) or hook source files for structural invariants (structural-regression-guard). No assertion logic was changed; only the correct allow-test-rule annotation was added to each file per CONTRIBUTING.md exception matrix. 73 files: `source-text-is-the-product` — workflow/agent/command/reference .md 7 files: `structural-regression-guard` — hook .js / bin/install.js structural checks 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> |
||
|
|
5ca646f015 |
feat(#443): unified cross-provider effort controls + fast-mode-aware routing (#463)
* test(#443): RED unified effort + fast_mode + resolve-execution All 68 tests failing as expected — no implementation yet. Covers: effort cascade (tier defaults, overrides, invalid fallthrough), fast_mode cascade (boolean-only, tier defaults), resolveEffortForTier escalation, renderEffortForRuntime clamping, resolve-execution CLI, config schema new keys, QA hostile-input matrix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#443): unified cross-provider effort + fast_mode knobs and resolve-execution query Adds config-driven effort control (universal ladder: minimal<low<medium<high<xhigh<max) and fast_mode propagation knobs, with per-runtime rendering that clamps the unique tail values (max=Anthropic-only clamps to xhigh on Codex; minimal=Codex-only clamps to low on Claude). Key changes: - config-schema.manifest.json: add effort.default, fast_mode.enabled as validKeys; add 4 dynamicKeyPatterns for effort.routing_tier_defaults, effort.agent_overrides, fast_mode.routing_tier_defaults, fast_mode.agent_overrides; fix stale _comment - config-defaults.manifest.json: add effort and fast_mode blocks with tier defaults - model-catalog.cjs: add EFFORT_RENDERING map, renderEffortForRuntime(), RUNTIMES_WITH_FAST_MODE - model-profiles.cjs: re-export new catalog exports - core.cjs: add resolveEffortInternal, resolveFastModeInternal, resolveEffortForTier, VALID_EFFORTS, EFFORT_SET, nextEffort; pass effort/fast_mode through loadConfig - commands.cjs: replace reasoning_effort in cmdResolveModel with unified effort; add cmdResolveExecution (superset command with effort_rendered, effort_param, effort_propagation, fast_mode, fast_mode_supported) - gsd-tools.cjs: add resolve-execution case with --effort/--fast-mode/--attempt flags - tests/feat-443: 69 tests covering cascade, rendering, escalation, CLI, schema, QA matrix - tests/commands.test.cjs: convert 3 reasoning_effort assertions to unified effort - docs/CONFIGURATION.md: document effort + fast_mode + resolve-execution sections - settings-advanced.md: list new effort/fast_mode keys in confirmation table Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(#443): remove dead catalog effort lane; unify codex effort through renderEffortForRuntime - Remove resolveReasoningEffortInternal (catalog-driven effort function) from core.cjs and its export; remove from commands.cjs destructure import - Convert tests/issue-2517-runtime-aware-profiles.test.cjs: all 11 effort assertions now use resolveEffortInternal + renderEffortForRuntime; Claude effort is first-class (output_config.effort); unknown runtimes assert param===null - Convert tests/feat-3023-model-phase-types.test.cjs: replace the entire resolveReasoningEffortInternal describe with unified effort assertions; effort derives from AGENT_DEFAULT_TIERS routing tier, not phase-type tier Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(#443): ADR for unified cross-provider effort + fast-mode routing Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(#443): architecture-level QA invariants + test-strategy doc Add 48-test integration suite (feat-443-effort-fast-mode.integration.test.cjs) covering 8 architectural invariants: cross-provider validity (never emit a value the real API would 400 on), param/channel contract stability, resolve-execution JSON contract (all 8 keys + correct types), totality across the full 33-agent registry, fast-mode honesty (claude always fast_mode_supported=false), precedence first-valid-wins matrix for both effort and fast_mode cascades, dynamic-routing composition (effort escalation independent of model tier), and config-set round-trip for all new effort/* and fast_mode/* key namespaces. Append test-strategy section with invariant rationale and E2E gap documentation to docs/TESTING-SUITES.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(#443): add failing install-wiring tests for effort per-runtime injection (RED) TDD RED: 10 failing tests covering: - Claude .md gets effort: injected per tier (planner=xhigh, mapper=low, executor=high) - Gemini .md does NOT get effort: (already passing — Gemini-safe) - Codex .toml gets model_reasoning_effort via unified resolver - Config-driven: effort.agent_overrides drives both Claude .md and Codex .toml - Source purity: agents/*.md have no effort: key (already passing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#443): wire effort per-runtime at install (Claude .md frontmatter + Codex .toml unified) - Import AGENT_DEFAULT_TIERS and renderEffortForRuntime from model-catalog.cjs - Add readGsdEffectiveEffortConfig(targetDir): reads merged effort config from .planning/config.json (per-project wins) + ~/.gsd/defaults.json (global fallback), same probe pattern as readGsdRuntimeProfileResolver - Add resolveInstallTimeEffort(effortCfg, agentName): pure function matching resolveEffortInternal() precedence (agent_overrides > routing_tier_defaults > default > 'high') without loadConfig side-effects (no sub-repo detection, no migration writes) - Claude agent copy loop: inject `effort: <value>` into frontmatter ONLY for runtime === 'claude'; all other .md runtimes (Gemini, Qwen, Hermes, etc.) stay effort-free (Gemini-safe source contract preserved in agents/*.md) - generateCodexAgentToml: add effortCfg param; emit model_reasoning_effort from unified resolver (replaces old catalog entry.reasoning_effort); Codex clamps max → xhigh via renderEffortForRuntime('codex', ...) - installCodexConfig: pass readGsdEffectiveEffortConfig(targetDir) to generateCodexAgentToml so per-project config wins for Codex .toml too - Update failing tests to GREEN: 12/12 pass; all 17 install tests pass; 2847/2848 unit tests pass (1 pre-existing failure: policy-shell-pinning) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(#443): source install effort defaults from manifest (kill drift) + guard test Replace hardcoded _GSD_EFFORT_MANIFEST_TIER_DEFAULTS and the 'high' fallback in resolveInstallTimeEffort with values read from config-defaults.manifest.json at module init, using the same __dirname-relative path install.js already uses for all shared manifests. Add feat-443-effort-defaults-drift.test.cjs to assert equality between install.js's runtime constants and the manifest on every CI run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): reconcile Codex TOML tests with unified effort design The #443 unified effort resolver makes generateCodexAgentToml always emit model_reasoning_effort (driven by resolveInstallTimeEffort, not model_profile_overrides). The test 'generated TOML omits reasoning_effort when runtime has none' had an obsolete premise — model_profile_overrides.reasoning_effort:'' no longer suppresses unified effort. Convert it to assert the new invariant: Codex TOML always carries a valid model_reasoning_effort from the agent's routing tier (xhigh for gsd-planner, a heavy-tier agent), while model_profile_overrides model override is still respected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): make install.js effort resolution lazy (no load-time side effects breaking launcher-parity) Replace module-load-time IIFE + hard throw (config-defaults.manifest.json read) and top-level require of model-catalog.cjs with a lazy _getGsdEffortCatalog() getter that initialises on first call from resolveInstallTimeEffort / generateCodexAgentToml / Claude .md effort injection. Requiring install.js in unrelated test contexts (e.g. runtime-launcher-parity) no longer triggers manifest IO or throws, eliminating the load-time side effect that changed subprocess exit codes / stderr on the bench. Drift-guard exports (_GSD_EFFORT_MANIFEST_TIER_DEFAULTS / _GSD_EFFORT_MANIFEST_DEFAULT) preserved as lazy getter properties on module.exports so feat-443-effort-defaults-drift still validates them without forcing eager load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): isolate install-wiring test HOME to stop \$HOME/.claude pollution breaking launcher-parity runGlobalInstall() now redirects HOME to a per-call isolated tmpdir in addition to the existing runtime-specific env-var redirects (CLAUDE_CONFIG_DIR, GEMINI_CONFIG_DIR, CODEX_HOME). This ensures install.js code that uses os.homedir() directly — including the ~/.cache/gsd update-check deletion, ~/.gsd/defaults.json reads, and any HOME-relative npm subprocess writes — never touches the real \$HOME during the test. Without the HOME isolation the install test (which is new to this branch and is now picked up by Docker's raw \`tests/*.test.cjs\` glob) could write or delete files under the real \$HOME, causing runtime-launcher-parity test (D) to fail: (D) asserts a loud non-zero exit when \$RUNTIME_DIR/gsd-tools.cjs is absent and gsd-tools is not on PATH, but the launcher's \$HOME/.claude fallback arm succeeds if \$HOME/.claude/get-shit-done/bin/gsd-tools.cjs exists. Also sets GSD_SKIP_STALE_SDK_CHECK=1 to suppress the \`npm ls -g\` subprocess that the global installer spawns — irrelevant to effort-wiring assertions, slow, and potentially writes to ~/.npm cache. All 12 feat-443 install-wiring assertions preserved. Drift-guard 5/5. Unit suite 2848/2850 (pre-existing policy-shell-pinning.test.cjs failure on next). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(#443): add changeset fragment for effort + fast-mode routing Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(#443): set GSD_TEST_MODE before requiring install.js in drift-guard test to prevent HOME leak Without GSD_TEST_MODE=1, require('bin/install.js') runs the module's main install block (guarded by !GSD_TEST_MODE), performing a real global Claude install into $HOME/.claude/. On CI ubuntu where node is on standard PATH, the launcher's $HOME/.claude fallback arm then finds gsd-tools.cjs, causing runtime-launcher-parity test (D) to exit zero when it must exit non-zero. Root cause: feat-443-effort-defaults-drift.test.cjs (unit suite) runs alphabetically before runtime-launcher-parity.test.cjs in the same node --test invocation. Each runs in a separate worker process but shares the same HOME. The drift test's install leaks gsd-tools.cjs into that HOME, then the launcher test's bash subprocess finds it via the $HOME/.claude arm. Fix: add process.env.GSD_TEST_MODE = '1' at the top of the drift-guard test, before the require(installPath) call. This matches the pattern used by feat-443-effort-fast-mode.test.cjs and feat-443-effort-install-wiring .install.test.cjs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): deterministic resolve-execution arg parsing + validate install-time effort (Codex adversarial findings) Finding 1: resolve-execution --effort low gsd-planner misrouted 'low' as the agent. Replace find(non-dash) with a proper flag-consuming loop that collects a single positional; validate missing/extra positionals and malformed --attempt values. Finding 2: resolveInstallTimeEffort returned unvalidated effort strings (e.g. "ultra") verbatim. Each precedence layer now checks GSD_EFFORT_SET (imported once from core.cjs) before accepting a value, mirroring resolveEffortInternal exactly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): newline-agnostic effort frontmatter injection (Windows CRLF) + CRLF-safe assertions Extracts injectEffortFrontmatter(content, effortValue) pure helper that detects EOL (LF vs CRLF) from the opening '---' line and inserts 'effort: <value>' before the closing '---' delimiter using the same EOL as the surrounding frontmatter. Regex now uses /^---\r?\n([\s\S]*?)^---\r?$/m instead of the LF-only /^(---\n[\s\S]*?)(---)(\n|$)/ that silently skipped CRLF files on Windows (git core.autocrlf=true checkout). Also adds 7 unit tests covering LF, CRLF, idempotency, no-frontmatter, and complex frontmatter cases. Exports injectEffortFrontmatter from module.exports. Fixes 6 CI failures in tests/feat-443-effort-install-wiring.install.test.cjs on windows-latest runners (lines 138, 145, 152, 261, 345, 356). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
92cd7e03dd |
fix(#338): write local Claude install hook wiring to settings.local.json (+ one-shot migration) (#426)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
6f33b18f69 |
fix(#376): rewrite /gsd: → /gsd- in Claude-installed hook .js files (#424)
* fix(#376): rewrite /gsd: → /gsd- in Claude-installed hook .js files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#376): preserve .sh branch + {{GSD_VERSION}} stamp in restructured hook-copy loop Trim the .js branch comment/whitespace so the `else {` and `entry.endsWith('.sh')` fall within the 1500/2000-char assertion windows anchored on `configDirReplacement` in the regression tests for #1834 and #2136. The .sh read+substitute+chmod path is intact; the new #376 hyphen- namespace rewrite for .js/.cjs files is also preserved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
978823cd06 |
fix(#410): guard ~/.gsd/defaults.json write with GSD_TEST_MODE (#130 sibling) (#421)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
fd061fccc5 |
fix(#130): skip opencode permission config under GSD_TEST_MODE (#404)
finishInstall called configureOpencodePermissions unconditionally, causing fs.mkdirSync + fs.writeFileSync to run even under GSD_TEST_MODE='1', violating the side-effect-free contract. Guarded the call with !process.env.GSD_TEST_MODE. Fixes #130 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c66705d6ba | fix(#279): document Agent mapping and deferred tool discovery (#285) | ||
|
|
80d971d01e |
Merge pull request #265 from open-gsd/issue/261-bug-worktree-executor-force-adds-gitigno-1779717159
fix(issue): bug: worktree executor force-adds gitignored .planning/SUMMARY.md into worktree branch (regression of the skipped_gitignored SDK contract) |
||
|
|
11918dcc37 | chore(#191): retire sdk package seam | ||
|
|
69cc2f9fe2 | fix(issue): bug: worktree executor force-adds gitignored .planning/SUMMARY.md into worktree branch (regression of the skipped_gitignored SDK contract) | ||
|
|
5b3646d6c8 |
fix(#213): support antigravity 2.x config directory split (#217)
* fix(#213): support antigravity 2.x config directory split * fix(#213): harden antigravity tests for windows parity |
||
|
|
0dc3fd604c |
fix(#166): omit bash.exe wrapper for windows claude sh hooks (#203)
* fix(#166): omit bash.exe wrapper for windows claude sh hooks * chore(#166): add changeset for windows claude sh hook fix * fix(#166): reset exitCode in sdk bridge integration test |
||
|
|
334a64168e |
chore(npm): rebrand packages to @opengsd scope (#127)
* chore(npm): rebrand packages to @opengsd scope Rename: - get-shit-done-redux → @opengsd/get-shit-done-redux - @gsd-redux/sdk → @opengsd/gsd-sdk Add publishConfig.access=public for first-time scoped publish. CLI binary names (get-shit-done-redux, gsd-sdk, gsd-tools) unchanged. Sweeps install commands, npx invocations, CI publish/version-check workflows, tests, docs, READMEs (all translations), and the PACKAGE_NAME constant in check-latest-version. Bumps qs 6.15.1 → 6.15.2 to clear a moderate advisory surfaced by the audit-clean test (GHSA-q8mj-m7cp-5q26). Closes #126 * chore: pin 2.0.0 release + remove canary workflow - Bump both packages 1.50.0-canary.0 → 2.0.0 for first @opengsd publish - Remove .github/workflows/canary.yml and canary dist-tag handling in release.yml / release-sdk.yml - Drop canary section from VERSIONING.md Refs #126 * chore: address review findings + harden tarball-smoke timeout - .changeset/opengsd-org-rename.md: match project's custom parse.cjs frontmatter (type: Changed / pr: 127); the scoped @changesets/cli keys were silently rejected. - CONTEXT.md: drop two canary-stream policy lines and a dangling DEFECT.CANARY-VERSION-LEAK.cross-ref now that canary.yml is gone. - tests/release-tarball-smoke.install.test.cjs: pass timeout: 600_000 for npm pack + global install; the 3-minute runNpm default was timing out on slower Docker hosts (cartographer). Refs #126 * fix(sdk): add missing type/runtime devDependencies for build prepublishOnly invokes tsc which couldn't resolve @types/node, @types/ws, or synckit. They had been hoisted from root but were not declared in sdk/'s own package.json — first publish from a clean SDK tree failed. Refs #126 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): use npm pack stdout instead of glob to find tarball `npm pack --silent` for a scoped package (@opengsd/get-shit-done-redux) produces `opengsd-get-shit-done-redux-*.tgz`, not `get-shit-done-redux-*.tgz`. Capture the filename from stdout instead of a hardcoded glob so the step works regardless of package name format. Fixes smoke (ubuntu-latest, 22, false) CI failure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: treat workflow-file changes as test-skip eligible `.github/workflows/install-smoke.yml` (and other workflow files) were in neither `test.yml` paths nor `test-skip.yml` paths-ignore, so neither workflow ran on a workflow-only commit — leaving the required test-skip check perpetually missing. Refs #126 * chore: reset version to 1.0.0 for first @opengsd publish Nothing has been published yet under the @opengsd scope, so the inaugural release uses 1.0.0 rather than 2.0.0. The "major bump" in the changeset reflects the breaking install-command change for users migrating from the prior unscoped `get-shit-done-redux`, not a numeric continuation from a 1.x line under the new identity. Refs #126 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
7ad1a5edf5 |
fix(3668): isolate --local install from global gsd-sdk (#89)
* fix(3668): isolate --local install from global gsd-sdk - `buildGsdSdkVersionMismatchReport` now accepts `opts.isLocal`; when true it sets `fix_command` to `npx get-shit-done-cc@latest --claude --local` instead of `npm install -g …`, removing the misleading global upgrade suggestion for local installs. - Propagate `isLocal` from `installSdkIfNeeded` into the mismatch report builder so the right fix_command reaches the renderer. - Export `buildGsdSdkVersionMismatchReport` and `renderGsdSdkVersionMismatchReport` so tests can assert on the IR contract directly. - Add `command -v gsd-sdk … elif node "$GSD_TOOLS"` preflight SDK resolution block to all 69 workflow files that called bare `gsd-sdk` with no fallback, matching the pattern established in update.md, execute-phase.md, and quick.md. - Add `tests/bug-3668-local-install-sdk-soft-dep.test.cjs` with 5 tests covering Defects 1-3, including a CI lint guard that blocks future workflow regressions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * changeset: add Fixed entry for #3668 * fix(3668): add allow-test-rule to suppress false lint-no-source-grep violation The test reads workflow .md files (product content) to assert structural invariants — not .cjs source files. The file-presence check is the only viable IR for markdown guard patterns. Add the // allow-test-rule annotation so lint-no-source-grep passes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): fix do.md false-positive and discuss-phase.md size overflow Two CI failures introduced by the 69-workflow preflight block: 1. do.md: the path `bin/gsd-tools.cjs` contains `/gsd-tools` which the bug-2954 parity test regex `/\/gsd[:-]([a-z][a-z0-9-]*)/g` mistakenly extracts as a slash command named `tools`. Fix: store the shim filename in _GSD_SHIM_NAME so the path construction no longer contains a static `/gsd-tools` literal. Also wire $GSD_SDK into the actual query call. 2. discuss-phase.md: the file was at 499 lines (the 500-line budget from #2551). Adding the 11-line preflight block pushed it to 510, failing workflow-size-budget.test.cjs. Fix: compress the 11-line preflight + 2-line invocations into 3 lines (one-liner guard + two $GSD_SDK calls) returning the file to 499 lines while retaining the command -v guard required by bug-3668-local-install-sdk-soft-dep.test.cjs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): wire \$GSD_SDK through all workflow callsites (#3797) PR #3797 introduced the resolution preflight block (setting \$GSD_SDK) in 69 workflows but left every downstream gsd-sdk callsite using the bare command. On local-only installs the preflight exits cleanly, then the very next line fails with 'command not found'. This is the structural gap the Codex review flagged. Changes: - 687 bare `gsd-sdk` callsites replaced with `\$GSD_SDK` across 75 workflow files (all bash/sh fenced blocks excluding the resolution guard blocks themselves) - execute-phase.md: was missing the preflight block entirely — added the standard 11-line resolution block at the initialize step - execute-phase.md: inline `if command -v gsd-sdk` availability guard (legacy #3384 fallback) replaced with `\$GSD_SDK` + error fallback since the new preflight guarantees SDK availability or exits 1 - 6 sub-workflow files (discuss-phase/modes/*, execute-phase/steps/*) that have no preflight of their own but use \$GSD_SDK — these are loaded by parent workflows that set the variable; callsites updated to use \$GSD_SDK so they work when variable is in scope Transformation script used: /private/tmp/fw2.js (regex-based fence parser with segment join invariant verification — preserves all blank lines and prose formatting). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(3668): upgrade CI guard to detect bare callsite routing (#3797) The previous Defect 3 test checked that 'command -v gsd-sdk' appeared as a string in the file — a guard-presence check, not a callsite-routing check. A workflow with the preflight block but 40 bare gsd-sdk calls below it passed the old test. This is exactly the bug state PR #3797 was supposed to fix. Upgraded test: - Parses each workflow file into markdown segments using a regex-based fence extractor (preserves all content invariantly) - Skips bash/sh blocks that contain 'command -v gsd-sdk' (those are resolution guards — bare references there are expected) - Flags any remaining bash/sh block line that invokes gsd-sdk without the \$ prefix (isBareGsdSdkInvocation predicate) - Counter-test proves the predicate correctly flags real callsite lines and correctly exempts guard assignments, comments, and \$GSD_SDK refs Also adds helper functions parseMarkdownSegments, isBareGsdSdkInvocation, and findMdFiles which are used by both the upgraded Defect 3 test and the counter-test. This test would have caught the originally-shipped bug: the preflight block was present but callsites still used bare gsd-sdk. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): update workflow content tests to accept \$GSD_SDK callsite form (#3797) Six regression tests assert on the exact textual pattern of gsd-sdk calls inside workflow .md files. After the #3797 callsite replacement (687 bare `gsd-sdk` invocations replaced with `\$GSD_SDK`), these tests failed because they searched for the literal string `gsd-sdk query <cmd>` which no longer appears at callsites. Updated each test to accept both the pre-#3797 bare form and the post-#3797 variable form using `(?:\$GSD_SDK|gsd-sdk)` regex alternation (or two-branch `includes()` checks for non-regex assertions). The structural invariants each test enforces are unchanged — we're accepting the same behavioral contract through the new callsite surface. Tests fixed: - bug-2334-quick-gsd-sdk-preflight: find init.quick call via \$GSD_SDK or bare - bug-2661-roadmap-sync-parallel: roadmap.update-plan-progress call pattern - bug-3360-codex-execute-phase-worktrees: RUNTIME config-get call detection - bug-3381-verify-work-workstream: init.verify-work / phase.mvp-mode calls - enh-2433-todo-phase-linking: commit call in new-milestone.md - enh-2792-namespace-skills: validate.context invocation in context_check step Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): update remaining workflow content tests to accept \$GSD_SDK form (#3797) After #3797 callsite replacement, ultraplan-phase.test.cjs and worktree-cleanup.test.cjs still assert bare gsd-sdk form. Update to accept either \$GSD_SDK or gsd-sdk. Also trim the execute-phase.md preflight comment to stay within the XL line-count budget (1810). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): adopt inline-per-fence SDK resolution + restore safety semantics The brief offered three options: (a) inline preflight block per fence (b) wrapper script (c) shared shell fragment sourced at the top 71 of 72 workflow files already had inline preflight blocks (just broken ones). Option (b)/(c) would have required changes to install.js + a new shared artifact, with significant risk of breaking the install pipeline. Option (a) was the path of least resistance and least new blast radius. **BLOCKER 1+2+3 (quick.md — GSD_SDK never assigned):** - quick.md had 12 `$GSD_SDK` references but zero `GSD_SDK=` assignments. - Added proper local-first preflight block with `git rev-parse --show-toplevel` path (not the broken `CLAUDE_FILE_PATHS` which is always empty in Claude Code). - Each Bash fence in Claude Code runs as a fresh `bash -c`, so env vars don't persist. The preflight block must appear in every fence that uses $GSD_SDK. **BLOCKER 4 (execute-phase.md — || exit 1 dropped):** - Restored `|| exit 1` after every `worktree.cleanup-wave` call. SDK safety refusals (drift detection #3174, deletion block #2384) must surface, not be swallowed by the old `|| { fallback }` branch. **F5 (verify-work.md untyped fence):** - Changed bare `gsd-sdk` in an untyped fence to `$GSD_SDK`. - Changed fence tag from untyped to `bash`. **F6 (non-recursive readdirSync):** - Defect 2 test now uses `findMdFiles` (recursive) to cover workflow subdirectories, not the flat `fs.readdirSync` that missed subdirs. **F7 (lint misses untyped fences):** - `parseMarkdownSegments` now treats `lang === ''` fences as bash-fences. **F8 (missing propagation test):** - Added two propagation tests in the Defect 3 describe block. **F9 (priority inverted — global before local):** - All 72 workflow files now check `[ -f "$GSD_TOOLS" ]` before `command -v gsd-sdk`. - Path: `$(git rev-parse --show-toplevel 2>/dev/null || pwd)/get-shit-done/bin/gsd-tools.cjs` **F10/F11 (broken quoting):** - Changed `GSD_SDK="node "$GSD_TOOLS""` → `GSD_SDK="node $GSD_TOOLS"` across all files. **SDK-absence fallback removal:** - The old `|| { STATE_BACKUP=...; while IFS=...WAS_DELETED...; done }` fallback code was dead — preflight now exits if neither local nor global SDK exists. Removed from quick.md, execute-phase.md. Tests updated to verify SDK delegation rather than inline shell mechanics. **Tests updated:** - bug-2384, bug-2501, bug-2838, bug-3091, bug-3195, bug-3521, bug-3668, worktree-cleanup — all updated to reflect SDK delegation contract. - Defect 2 test now uses bash-fence scan (not raw content) to skip docs-only gsd-sdk prose references (e.g. discuss-phase/modes/text.md). Closes #3668 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): restore _GSD_SHIM_NAME indirection in do.md to prevent false-positive The top commit re-introduced a literal /get-shit-done/bin/gsd-tools.cjs path in do.md, causing bug-2954 test to match /gsd-tools as an unshipped slash command. Restore the _GSD_SHIM_NAME variable indirection (from ff9939e5) to break the literal path while preserving local-first preference order. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): update worktree.test.cjs to accept SDK delegation contract (#3797) Mirror the contract update already applied to worktree-cleanup.test.cjs: - pre-merge deletion check tests: accept worktree.cleanup-wave + deletion mention as valid (inline --diff-filter=D was in the removed shell fallback) - quick.md bug-2431 tests (lock-aware, unlock retry, residual warning): accept worktree.cleanup-wave delegation as sufficient (these safety behaviors are now handled internally by the SDK cleanup-wave command) execute-phase.md tests unchanged: it retains inline .git/worktrees/, locked, git worktree unlock, and Residual worktree in its cleanup-tail snippet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(3668): refactor bug-2384 and bug-2838 from grep to structured assertions Replace content.includes() on readFileSync-bound variables with parser functions that split lines and return typed boolean fields, matching the project's no-source-grep contract (lint-no-source-grep rule F/G). --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
2a915c1b82 |
chore: migrate references from gsd-build to open-gsd/get-shit-done-redux (#120) (#121)
Security-motivated migration of all stale repository and npm-scope references. Three categories of changes (58 files, 174 substitutions): 1. gsd-build → open-gsd (security-critical): - .github/workflows/release-sdk.yml — npm token comment, tarball filename pattern - .github/workflows/hotfix.yml — same - .changeset/fix-3406-detect-stale-sdk-shadow.md — @gsd-build/sdk → @open-gsd/sdk - .changeset/sharp-quails-leap.md — same - get-shit-done/workflows/update.md — CHANGELOG raw GitHub URL 2. GSD-redux org slug → open-gsd (canonical rename): - package.json + sdk/package.json — repository/homepage/bugs metadata - All README.*.md — live badge and link sections - CONTRIBUTING.md, CONTEXT.md, QUICK-WINS-CONFIRMED-BUGS.md - .coderabbit.yaml, .release-monitor.sh, scripts/sync-rulesets.sh - docs/** — all live agent/ADR/user-facing documentation - tests/** — repo slug assertions and test fixtures - scripts/changeset/cli.cjs + github-release-notes.cjs - .github/ISSUE_TEMPLATE/*, .github/pull_request_template.md - bin/install.js, get-shit-done/bin/lib/model-catalog.cjs - sdk/HANDOVER-*.md, sdk/src/*.test.ts 3. CLAUDE.md (gitignored local file — not in this commit): Updated separately outside git: --repo gsd-build/get-shit-done → --repo open-gsd/get-shit-done-redux with security warning. Intentionally unchanged: CHANGELOG.md, docs/RELEASE-*.md, .changeset/README.md, .changeset/build-hooks-atomic-write.md, README.md migration table (historical fork record), tests/changeset-serialize.test.cjs line 78 (serialization fixture). The gsd-build/get-shit-done repo is compromised (rug-pull documented in README.md). Do not push to or interact with that repo. Closes #120 |
||
|
|
619b5c42e3 |
fix(3407): snapshot old release into gsd-pristine, not new (#87)
* fix(3407): snapshot old release into gsd-pristine, not new saveLocalPatches() was wiping gsd-pristine/ then re-populating it from pristineCtx.packageSrc — the NEW release source tree. For files that changed between old and new releases, this wrote NEW-release bytes as the pristine baseline while backup-meta.json recorded OLD-release hashes. The resulting hash mismatch triggered the #3657 verifier guard on every such file, causing it to skip the three-way diff baseline and fall back to the over-broad heuristic — effectively nullifying the #2998 feature for any file that changed upstream. Fix: preserve existing gsd-pristine/ entries that are already correct (sha256 on disk matches originalHash from manifest). These were written by the previous install with old-release bytes and remain valid. For files where no correct entry exists, leave gsd-pristine/ absent so the verifier falls back cleanly to over-broad mode — safe, never false-fails. OK_PRISTINE_DRIFT_DETECTED (added by #3657) is intentionally kept: it guards installations that already have drifted pristine from pre-fix runs and protects against other future stale-pristine scenarios. It is not removed because its guard is correct; only its trigger frequency drops. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: add changeset for #3801 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3407): hash-validated regeneration for missing gsd-pristine entries Codex adversarial review found that the #3407 fix left absent gsd-pristine/ entries permanently absent, causing persistent over-broad verification even when the file was unchanged between old and new releases. Add selective regeneration: for entries absent from gsd-pristine/, generate a candidate via populatePristineDir into a temp dir using new-release source, then only promote if sha256(candidate) === originalHash. When hashes match, the file was identical across releases so new-release bytes ARE the correct old-release pristine. Discard mismatches — over-broad fallback applies. Add regression test asserting regeneration occurs for unchanged-between- releases files whose pristine entry was absent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3407): address review — restore mkdtempSync resilience, tighten tests, fix counter accounting Addresses sonnet adversarial MAJOR (mkdtempSync outside try/finally caused uncaught exception on broken /tmp), MIN-01–MIN-05 (misleading prose, counter double-count, missing stale-pristine test, permissive assertion, vacuous antipattern-hunt), sonnet MINOR (rmSync EISDIR), NIT (unused import, test count). F1: move mkdtempSync inside try block with catch/warn for graceful degradation F2: fix misleading prose — gsd-pristine/ is populated lazily by saveLocalPatches, not a separate install-time step F3: fix counter double-counting — track stalePaths/regeneratedPaths as Sets; removed = stale NOT regenerated (non-overlapping counts); update log message accordingly F4: add stale-pristine recovery test — pre-populates gsd-pristine/ with new-release bytes (exact pre-fix bug artifact), asserts absent after fix run F5: tighten Test 3 assertion from permissive if(exists)/notEqual to strict assert.strictEqual(exists, false) F6: remove vacuous antipattern-hunt describe block (typeof checks only, no behavioral coverage) — rationale noted in comment F7: use fs.rmSync with force:true/recursive:true for EISDIR resilience; only count removed after confirming file is actually gone via existsSync F8: remove unused afterEach from destructured import F9: test count updated to reflect 4 tests in describe block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
2763d50939 |
fix(3808): codex adapter activates TEXT_MODE when request_user_input is unavailable (#84)
When Codex reports `request_user_input` as unavailable (Default mode), the
Codex skill adapter's Execute-mode-fallback section now explicitly instructs
the agent to append `--text` to `{{GSD_ARGS}}` to activate the workflow's
built-in TEXT_MODE branching. This ensures every AskUserQuestion gate is
handled consistently through the workflow's own text-mode mechanism rather
than ad-hoc plain-text fallback, and eliminates any path to silent-default
selection (#3018 / #3808).
Adds regression test bug-3808-codex-adapter-text-mode-fallback.test.cjs with
typed semantic-flag assertions covering gsd-plan-phase, gsd-discuss-phase,
gsd-execute-phase, and gsd-verify-work.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
dff176bfd2 |
chore: rebrand to GSD-redux/get-shit-done-redux
Mirror of code, issues, and PRs from the upstream gsd-build/get-shit-done, which appears compromised or abandoned (maintainer unreachable since 2026-04-01; $GSD token linked to rug-pull). - Adds rebrand notice block at top of English README - Removes $GSD token badge and @gsd_foundation X badge (keeps Discord) - Renames npm packages: get-shit-done-cc -> get-shit-done-redux, @gsd-build/sdk -> @gsd-redux/sdk - Updates all repo URLs across docs, workflows, package.json, bin/ - Updates ci@gsd-build -> ci@gsd-redux in workflow git identities - Leaves CHANGELOG and .changeset/* alone (historical, time-stamped) |
||
|
|
2d3027767b |
fix(3426): Codex Windows hooks use .cmd shim to avoid POSIX exec fail (#3768)
* test(#3426): add RED test for Codex Windows hooks .cmd shim requirement Drive buildCodexHookWindowsShimIR (typed IR) + ensureCodexHooksJsonSessionStart integration against mocked win32 platform. Counter-tests confirm darwin/linux paths remain unchanged. NOTE: Windows wall-clock verification depends on Docker matrix Windows runners. Local test exercises the generator IR shape only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#3426): Codex Windows hooks use .cmd shim to avoid bash.exe POSIX-exec failure Root cause: Codex on Windows runs hook commands from PowerShell/cmd. The previous hooks.json command format was `"node.exe" "script.js"`. Codex's hook-dispatch shell (Git Bash / MSYS) tried to POSIX-exec node.exe (a Windows PE binary) via execvp(), which fails with ENOEXEC — reported as `bash.exe: cannot execute binary file`. Fix: `ensureCodexHooksJsonSessionStart` now calls `buildCodexHookWindowsShimIR` on win32 to write a .cmd shim alongside the .js hook file. cmd.exe executes .cmd files natively via CreateProcess, bypassing the POSIX exec layer entirely. Non-Windows paths (darwin, linux) are unchanged: they continue to use the node-runner command. Also adds `gsd-check-update.cmd` to the codex-hooks-json managed-basename set so reconcileCodexHooksJsonSessionStart correctly replaces stale node-runner entries on reinstall. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(3426): update changeset to reference PR #3768 * fix(3426): fail-loud on Codex Windows shim-write failure instead of silently restoring broken command Replace the silent fallback to `projectManagedHookCommand` (the old `node.exe script.js` form) with an explicit warn-and-skip path. When `atomicWriteFileSync` fails to write the `.cmd` shim, the previous code silently called `reconcileCodexHooksJsonSessionStart` with the legacy node-runner command. That command triggers the exact `bash.exe: cannot execute binary file` POSIX-exec failure that #3426 exists to fix — so a successful-looking install was secretly restoring the original bug. New behaviour: - Emit `console.warn` with the failure reason and a remediation hint, matching the `${yellow}⚠${reset} Skipped …` idiom used at line 9098. - Return `{ changed: false, wrote: false }` to skip registration for this runtime entirely, so the outer caller can surface "NOT installed" instead of "installed (but broken)". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(3426): typed-IR assertions on .cmd shim eol/quoting/passthrough + IR extension Extend `buildCodexHookWindowsShimIR` to expose two new typed fields on the returned IR object (CONTRIBUTING.md L558-L565 IR-first discipline): eol: { cmd: '\r\n' } — CRLF is canonical for cmd.exe .cmd files passthroughArgs: true — shim forwards all args via %* Add a new describe block (Step 2b) with three IR-level assertions: 1. `eol.cmd === '\r\n'` — prevents silent EOL regression that could break parsing on Windows versions that require CRLF. 2. `invocation.target` is the raw unquoted path (no shell-metachar leakage) — quoting happens only at render time. 3. `passthroughArgs === true` — the %* forwarding contract is explicitly typed so regressions fail before the text is rendered. All assertions operate on the typed IR returned by the generator, NOT on the rendered `.cmd` file content — text-matching is the anti-pattern CONTRIBUTING.md L522-582 prohibits. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(3426): fix Windows CI failures — update hook-command filter patterns Four test files filtered for managed hooks in hooks.json using the literal string `gsd-check-update.js`. On Windows the PR-introduced .cmd shim changes the hooks.json command to `"path/gsd-check-update.cmd"` (no node prefix, .cmd extension), so those filters matched 0 entries and 24 Windows subtests failed. Fixes: - bug-2760-codex-install-defensive.test.cjs (7 filters): change `/gsd-check-update\.js/` → `/gsd-check-update/` to match both .js (POSIX) and .cmd (Windows) commands. - bug-3357-codex-legacy-hooks-json-migration.test.cjs (3 filters): same `.js` → no-extension change. - bug-3427-3433-codex-install-shape.test.cjs (2 filters): same fix; add explanatory comment to uninstall assertion. - codex-config.test.cjs (9 filters + 1 exact-command assertion): bulk-replace all `hooksJsonCommands.filter(cmd => cmd.includes('gsd-check-update.js'))` with `gsd-check-update`; make the `fresh CODEX_HOME` test platform- aware — on win32 assert `.cmd` shim path, on POSIX assert the existing `"runner" "script.js"` form (#3017). All four suites pass locally (macOS / darwin). Windows subtests verified against the Windows CI failure log patterns. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3426): address pr-review-toolkit + codex review findings - fix(uninstall): add gsd-check-update.cmd to gsdHooks cleanup list so the .cmd shim is removed from disk on Windows uninstall (was left as orphan artifact — silent failure post-uninstall) - test(3426): add uninstall test asserting gsd-check-update.cmd is deleted from hooks dir after `uninstall(true, 'codex')` (no coverage existed) - fix(comment): correct JSDoc on buildCodexHookWindowsShimIR — shim content is three-line @ECHO OFF/@SETLOCAL/@runner snippet, not bare `@node "script.js" %*` as the old comment claimed - fix(comment): update stale assertion message in codex-config.test.cjs L1457 — said "config.toml references it" but the hook is in hooks.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
e690f1bc90 |
fix(3718): shell-free Node.js UI safety gate — fixes PowerShell silent-fail (#3718)
* fix(workflows): add word-boundary anchoring to UI safety gate grep Replace unanchored grep -iE "UI |..." alternation with POSIX ERE word-boundary-anchored form: LC_ALL=C grep -iE "(^|[^[:alnum:]])(UI|...)([^[:alnum:]]|$)" Unanchored form matched 'ui' inside 'requirements', 'view' inside 'overview' and 'review', 'form' inside 'performance'/'platform'/ 'transform' — producing HAS_UI=0 on 100% of standard roadmap phases (every phase contains a **Requirements**: field). Fix applied to both plan-phase.md:625 and autonomous.md:284. LC_ALL=C added for POSIX locale portability on both BSD and GNU grep. Closes #3706 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(workflows): add regression tests for UI safety gate false-positives (#3706) - bug-3706-ui-safety-gate-false-positives.test.cjs: 36-test suite covering both plan-phase.md and autonomous.md gate behavior; verifies that Requirements/overview/performance/platform/transform/review/build/screening do NOT trigger the gate, while standalone UI/view/form/screen/dashboard/ component/lowercase-ui/hyphenated-non-UI DO trigger it. - autonomous-ui-steps.test.cjs: update stale assertion that checked for the old broken grep pattern; now asserts the word-boundary-anchored form. Test strategy: extract the POSIX ERE pattern from the workflow file and simulate grep match semantics in JS (no shell exec, no source-grep). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(changeset): add Fixed fragment for PR #3718 (UI safety gate false-positives) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(workflows): document compound-token boundary contract; add comment to gate Addresses adversarial review finding: word-boundary anchoring intentionally does not match tokens embedded in compound alphanumeric words (e.g. "microfrontend", "dashboardWidget", "uiSpec"). This is correct behavior — gsd-roadmapper generates natural English prose, not camelCase compounds. Hyphenated forms ("micro-frontend") and spaced forms are caught by the anchored pattern (hyphen is [^[:alnum:]]). Add inline comment in both workflow files explaining the pattern intent, the false-positive prevention, and the compound-word contract. Add 4 tests (2 per workflow) documenting the compound-word contract: - "microfrontend" (compound) must NOT trigger gate (documented behavior) - "micro-frontend" (hyphenated) MUST trigger gate (correct true-positive) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3718): replace shell grep gate with shell-free Node.js helper Moves UI safety gate logic from `LC_ALL=C grep -iE` (silently broken on Windows PowerShell — locale env-var prefix not recognised by pwsh) to `bin/lib/ui-safety-gate.cjs` (Node.js, reads via stdin to avoid ARG_MAX). Path is anchored via `git rev-parse --show-toplevel` (GSD_REPO_ROOT) to avoid CWD-sensitive failure when Claude Code executes from a subdirectory. Word-boundary regex is identical to the original POSIX ERE pattern: (^|[^a-zA-Z0-9])(TOKEN)([^a-zA-Z0-9]|$) Exit codes mirror grep: 0 = UI found, 1 = not found. Tests: 51/51 pass — includes spawnSync shell:false + stdin cross-shell portability tests and ARG_MAX large-input test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3706): address pr-review-toolkit + codex review findings - Multi-token-per-line: use matchAll to capture all UI tokens - Add test for multiple distinct tokens on same line - Clarify ASCII vs POSIX [:alnum:] in word-boundary comment - Correct misleading "path anchored" comment in plan-phase/autonomous workflows - Remove UI_GATE_PATTERN from module.exports (internal implementation detail) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(state): restore ACQUIRE_LOCK_RETRY_ERRNOS in acquireStateLock (#3718) Commit |
||
|
|
09ab16f9e5 |
fix(3683): normalize /gsd:<cmd> → /gsd-<cmd> in command, workflow, and reference bodies (#3685)
* fix(3683): normalize /gsd:<cmd> → /gsd-<cmd> in command, workflow, and reference bodies Extends #3677's agent-body normalizer to all body text staged through copyWithPathReplacement (commands, workflows, references). The initial isCommand guard was structurally redundant — normalizeAgentBodyForRuntime already self-gates on shouldNormalizeHyphenNamespaceInAgentBody(runtime), so dropping it covers all hyphen-name runtimes (Claude / Qwen / Hermes) without affecting colon-canonical runtimes (Gemini). Addresses the user-visible symptom in #3683: workflows like get-shit-done/workflows/discuss-phase.md (7 colon refs) leaked /gsd:<cmd> markers to the model context, which the model echoed at the end of /gsd-discuss-phase runs. Source-prose drift caught by the new cross-reference invariant test: - commands/gsd/plan-phase.md: removed a slash-form mention of the deleted /gsd-research-phase command (#3042) - commands/gsd/profile-user.md: replaced a slash-form artifact reference with a backticked bare name (the referenced item is a skill config, not a user-callable slash command) Tests: - tests/bug-3683-command-colon-namespace-leak.test.cjs — runtime-form regression for commands/gsd/*.md staging - tests/bug-3683-command-cross-reference-invariant.test.cjs — locks cross-reference coherence: every /gsd-X / /gsd:X reference in a command body must resolve to commands/gsd/X.md (so a future rename forces every cross-reference to update) - tests/bug-3683-workflow-colon-namespace-leak.test.cjs — runtime-form regression for workflows + references; negative test for gemini asserting the colon form is preserved Fixes #3683 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(changeset): remove undefined cycle reference --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
80d6306e99 |
fix(3677): normalize /gsd:<cmd> → /gsd-<cmd> in agent bodies for hyphen-name runtimes (#3680)
* fix(3677): normalize /gsd:<cmd> → /gsd-<cmd> in agent bodies for hyphen-name runtimes Closes #3677 The executor agent bodies installed to `~/.claude/agents/gsd-*.md` (and the Qwen / Hermes equivalents) still contained retired `/gsd:<cmd>` colon-form references in their prose. Every GSD skill / agent has registered under the canonical hyphen `name:` form since #2808, so the colon form is unroutable — Claude Code rejects it with `Unknown command: /gsd:execute-phase. Did you mean /gsd-execute-phase?`. Reporter measured ~28 agent files / ~96 leaked refs on a full Claude global install. This is the agent-body surface of the same class of bug as the two already-fixed sibling surfaces: - #3583 (SKILL.md skill bodies) — fixed via #3629 - #3584 (user-facing runtime "Next step: /gsd:…" emissions) — fixed via #3606 The agent-body surface in `bin/install.js`'s agent install loop was never covered: the Claude-default / Qwen / Hermes branches register hyphen `name:` but copy bodies verbatim (Qwen/Hermes do branding-only swaps; Claude-default falls through with no body conversion at all), so the colon refs leak. Fix: 1. Add a pure predicate `shouldNormalizeHyphenNamespaceInAgentBody(runtime)` backed by an explicit allow-list `HYPHEN_NAME_AGENT_RUNTIMES = {claude, qwen, hermes}`. Unknown / future runtimes default to false (better to leak than to mangle). 2. Add `normalizeAgentBodyForRuntime(content, runtime, cmdNames)` that conditionally applies the shared `transformContentToHyphen` from `scripts/fix-slash-commands.cjs` (same transform #3629 used for SKILL.md bodies). 3. Call `normalizeAgentBodyForRuntime(content, runtime, readGsdCommandNames())` in the agent install loop right before `fs.writeFileSync`, so it composes with all the existing runtime branches. For Gemini and self-converting runtimes the predicate short-circuits, so their convertClaudeAgentToXAgent output is not re-rewritten. 4. Export both functions from `bin/install.js` for the regression test. Regression test (`tests/bug-3677-agent-colon-namespace-leak.test.cjs`): 24 tests across 4 groups — A (exports exist), B (predicate matrix covering all 15 runtimes in the layout table + an unknown-runtime case), C (normalize helper applies/skips correctly for claude/qwen/hermes/ gemini/copilot), D (sanity check of the underlying transform). Verification: - node --test tests/bug-3677-*: 24/24 pass - Sibling-regression (6 slash-namespace test files): 76/76 pass - All install-minimal-all-runtimes suites: 54/54 pass after `npm run build:sdk` (the prior 27 fails were pre-existing — missing local sdk/dist build, not introduced by this change) - Full docker suite (gsd-test-summary): 11769/0 fail (11751 baseline + 18 new = my 24 tests with some collateral pickups) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(changeset): set PR number 3680 (Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>) * test(3677): port real-source efficacy + idempotence tests from #3681 Adds describe group E with 5 behavioral tests credited to John Turner (johnzilla, PR #3681 — closed in favor of this PR by its author): E0: command roster is populated and includes symptom commands E1: every agents/gsd-*.md transforms clean — real-source efficacy E2: idempotent — repeat transform on hyphenated input is a no-op E3: word boundary — /gsd:plan-phase-extra is not a roster match E4: rewrites bare gsd:<cmd> shorthand (no leading slash) E1 is the test that would have caught the original bug — pure-function tests can pass while the install.js wiring silently bypasses the transform. E2 guards against double-rewrite mangling during reinstall. 29/29 tests pass (24 original + 5 ported). Co-Authored-By: John Turner <johnzilla@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: John Turner <johnzilla@users.noreply.github.com> |
||
|
|
f970c09bf3 |
refactor(3664): migrate bin/install.js install/uninstall to Runtime Artifact Layout Module (#3674)
Phase 2 of #3660 / ADR-3660. Routes both lifecycle verbs through the Runtime Artifact Layout Module landed in Phase 1 (#3663): - Add installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile) and uninstallRuntimeArtifacts(runtime, configDir, scope) as the public orchestrators. Both pre-prune stale gsd-* entries before staged copy; installRuntimeArtifacts brackets the prune+copy with preserveUserArtifacts / restoreUserArtifacts so user-owned content (e.g. gsd-dev-preferences) survives wipe-and-replace for claude/qwen/hermes runtimes. - Add applyRuntimeContentRewritesInPlace as the per-runtime path/branding post-stage step (preserves byte-output equivalence with the legacy copyCommandsAs* pipeline, including Qwen/Hermes branding rewrites). - Add _copyStaged, _removeGsdEntries kind-aware filesystem helpers. - Add _runLegacyInstallMigrations, _runLegacyUninstallCleanup as thin dispatchers over existing ADR-0008 legacy migrations (Hermes flat->nested per #2841, dev-preferences-as-skill per #2973). For Hermes, also clean up the intermediate skills/gsd/gsd-*/ layout that pre-Phase-2 installs left on disk. - Delete the 9 copyCommandsAs*Skills functions (Codex / Cursor / Windsurf / Trae / CodeBuddy / Copilot / Claude / Antigravity / Augment) and the _copyCommandsAsSkillsViaConverter helper. All test entry points migrated to call installRuntimeArtifacts directly through the unified seam. - Collapse the 9-branch uninstall ladder to one uninstallRuntimeArtifacts call plus preserved non-layout side-effects (Codex TOML, Copilot instructions, hooks). - Unify install dispatcher: a single _isSkillsRuntime gate routes all 11 skills runtimes through installRuntimeArtifacts for both full and core/ minimal profiles. Removes 11 per-runtime if-else branches (3 minimal-mode shim branches + 8 dead after-the-gate branches). Net delta on bin/install.js: 11,495 -> 11,174 (-321 LOC). New tests: - tests/install-uninstall-layout-loop.test.cjs (34 tests) - per-runtime fixture assertions on install/uninstall/legacy-migration ordering. - tests/install-hermes-regressions.test.cjs (6 tests) - covers the six defects surfaced by iterative review: Hermes upgrade leaves stale dirs, --hermes --profile=core fall-through, --qwen --profile=core fall-through, minimal-mode dev-preferences migration skipped (Hermes/Qwen/Claude-global), and ordering bug in _runLegacyInstallMigrations. Existing tests (10,038 prior + 40 new) all green: 10,078/10,078 pass. Refs #3664 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
40e325b91f |
fix(3663): pass runtime+cmdNames to Claude converter for Hermes/Qwen
convertClaudeCommandToClaudeSkill(content, skillName, runtime, cmdNames) uses the runtime arg to gate Hermes/Qwen branding and version: frontmatter emission (#2808, #3583). Previously the layout module called it with only 2 args so the runtime-specific formatting was never applied. Changes: - skillsKind() gains a runtime param (5th arg after converterName). - stage() computes cmdNames = readGsdCommandNames() once per call (perf: avoids repeated fs.readdirSync in the converter) and wraps the real converter so all 4 args are forwarded. - readGsdCommandNames added to bin/install.js GSD_TEST_MODE exports block so the stage closure can call it without requiring the script separately. - All switch arms updated to pass the canonical runtime string. Converters that do not inspect runtime/cmdNames (Cursor, Codex, Copilot, etc.) accept and ignore the extra arguments — no behaviour change for those runtimes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
2e4fe65816 |
fix(3579): ship graphify hook + lib/ helper through build-hooks + install (#3640)
* fix(3579): ship graphify hook + lib/ helper through build-hooks + install `scripts/build-hooks.js` `HOOKS_TO_COPY` did not include `gsd-graphify-update.sh` (added in #3347 / PR #3557), so it never landed in `hooks/dist/` and `bin/install.js` — which `readdirSync`s the dist — never copied it to `~/.claude/hooks/`. The hook's detached rebuild helper at `hooks/lib/gsd-graphify-rebuild.sh` was also silently dropped because both build-hooks.js (flat allowlist) and bin/install.js (readdir + isFile filter) only walked top-level files. The published tarball gap (Gap 3 in the issue body) is not reproduced on origin/main — `npm pack --dry-run --json` shows both source files are present today. Only Gaps 1 and 2 are in scope. Changes: - Add `gsd-graphify-update.sh` to `HOOKS_TO_COPY`. - Add `HOOKS_SUBDIRS_TO_COPY = ['lib']` and copy whitelisted hook subdirectories (`hooks/<dir>/*` → `hooks/dist/<dir>/*`) in build-hooks.js, with the same syntax-check + atomic-rename path the top-level loop uses. - `bin/install.js`: when copying `hooks/dist/`, recurse one level into any directory entry so subdir files (e.g. `lib/gsd-graphify-rebuild.sh`) land at the mirrored target path the hook's REBUILD_SCRIPT lookup expects. Top-level if/else structure for files is unchanged. Regression test `tests/bug-3579-graphify-hook-publish.test.cjs`: - Drift guard: every top-level `hooks/*.sh` must appear in `HOOKS_TO_COPY`. Generalizes beyond graphify so the next .sh hook added cannot regress. - After build: `hooks/dist/gsd-graphify-update.sh` AND `hooks/dist/lib/gsd-graphify-rebuild.sh` exist. - After install: both files land at the target, and no "Missing expected hook: gsd-graphify-update.sh" warning is emitted. Fixes #3579 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(3579): replace source-grep drift guard with filesystem-behavior assertion The Gap-1 drift guard read scripts/build-hooks.js as text and regex-parsed the HOOKS_TO_COPY literal, which tripped lint-no-source-grep and is brittle under refactors. Replace with a behavior-based assertion: run the build, then for every top-level hooks/*.sh assert hooks/dist/<name> exists. Strictly stronger — catches both the original allowlist gap and any future regression that silently drops a hook for any other reason. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
05a8395566 |
fix(3406): detect + warn on stale @gsd-build/sdk@0.1.0 global shadow (#3641)
* fix(3406): detect + warn on stale @gsd-build/sdk@0.1.0 global shadow
`@gsd-build/sdk@0.1.0` is the only published version of the standalone
SDK package (the SDK now ships embedded in get-shit-done-cc). When a
user has the stale 0.1.0 globally installed, its `gsd-sdk` bin shadows
the shim get-shit-done-cc wires up — and the 0.1.0 binary only knows
`run | auto | init` (no `query`), so every `gsd-sdk query <cmd>` call
from skills and hooks fails silently until the user runs
`npm uninstall -g @gsd-build/sdk`.
Per maintainer triage decision (option 2): detect at install time and
surface the remediation, instead of waiting for the user to discover
the failure through a broken workflow.
Changes:
- New helper `detectStaleStandaloneSdk(runNpmLs)` (pure function,
accepts an injected executor). Returns `{stale: true, version}` when
`@gsd-build/sdk` is in the top-level dependency tree; returns
`{stale: false}` for every other input including executor throws,
malformed JSON, missing keys, and null/undefined returns.
- New helper `formatStaleStandaloneSdkWarning(info)` — message names
the package, version, the exact `npm uninstall -g @gsd-build/sdk`
remediation command, and references the issue.
- Call site in `install()` for `isGlobal` runs. Spawns
`npm ls -g @gsd-build/sdk --json --depth=0`, recovers the JSON
attached to the non-zero-exit error (npm's "absent" signal),
forwards to detectStaleStandaloneSdk, prints the warning if stale.
Best-effort: any failure is swallowed so detection never blocks
install.
- `GSD_SKIP_STALE_SDK_CHECK=1` opt-out for CI/test environments that
need silence (also used by the install-side test below).
Regression test `tests/bug-3406-stale-sdk-shadow-detect.test.cjs`:
- 8 unit tests pinning every detectStaleStandaloneSdk path (exported,
absent, present, executor-throws, malformed-JSON, no-deps-field,
null/undefined, format).
- 1 install-side end-to-end test confirming that when the package is
absent, the install run does NOT mention `@gsd-build/sdk` or `#3406`
in stdout. Uses a per-test `npm_config_prefix` so the test never
depends on the host's npm dependency tree.
Fixes #3406
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(3406): correct changeset pr field — 3406 was the issue number, not the PR
CodeRabbit caught that .changeset/fix-3406-detect-stale-sdk-shadow.md
referenced `pr: 3406` (the issue number) instead of `pr: 3641` (the
PR number). Per CONTEXT.md PRED.k329 changeset frontmatter pr: must
reference the pull request number.
Local: docker gsd-test-summary 11214/0 on plex2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(3406): two CR follow-ups on bin/install.js stale-shadow check
Round-2 CodeRabbit findings on PR #3641:
1. bin/install.js:7769 — GSD_SKIP_STALE_SDK_CHECK opt-out now matches
only explicit "1" / "true" / "yes". The previous any-truthy check
silently disabled the warning for `GSD_SKIP_STALE_SDK_CHECK=0` and
`GSD_SKIP_STALE_SDK_CHECK=false`.
2. bin/install.js:10568 — detectStaleStandaloneSdk now gates stale=true
on version === '0.1.0' (the known-bad shadow). Any newer published
version is intentional and must not flag a "stale shadow" warning
on every install. Added a regression test for non-0.1.0 versions
(1.50.0-canary.0 and 2.0.0) returning stale:false.
Local: 11/11 in the bug-3406 test file + docker gsd-test-summary 11215/0
on plex2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
05316369ae |
fix(3583): normalize retired colon-form commands in generated Claude/Qwen/Hermes SKILL.md bodies (#3629)
* Add first-class grok runtime support (maps to ~/.agents); wire installer, runtime-homes.cjs and sync-skills; update Grok Build engine in local ~/.agents to latest; record session progress in discussion doc * Normalize gsd colon references to hyphen in generated Claude SKILL.md bodies using the shared transformer. Fixes #3583. * Refine #3583 implementation after review: cache command names, improve tests, clean up comments * Harden gsd colon-to-hyphen transformer with bidirectional word boundaries and body-only regression guard * Track quick-wins batch status and local session notes for #3583/#3579 handoff * Port installer robustness (hoist copyLibDir + selective Codex hooks) from 3579 to make Codex tests pass on this branch. Fixes ReferenceError and prevents extra hook pollution in Codex installs. * Restore #3583 transformer wiring and Codex .sh GSD_VERSION branch lost in 50ff8f17 port Commit 50ff8f17 ('Port installer robustness from #3579') accidentally reverted: - the top-level require of transformContentToHyphen/readGsdCommandNames - the body normalization inside convertClaudeCommandToClaudeSkill - the Codex hook loop's .sh branch with {{GSD_VERSION}} substitution These were the actual #3583 fix and the Codex half of the #2136 invariant. Failing tests fixed: bug-2808-skill-hyphen-name, claude-skills-migration #3583 case, bug-2136 Codex .sh substitution. * Exempt 'sync-skills' slug from docs-parity check (skill dir name in path references) gsd-sync-skills is an installed Claude skill name and a workflow file but not a registered slash command. The docs-parity regex catches /gsd-sync-skills from filesystem path references like ~/.agents/skills/gsd-sync-skills/ in docs/discussions/grok-build-support-2026-05.md. Adding to INTERNAL_COMPONENT_SLUGS matches the existing exemption pattern for 'statusline', 'workspaces', 'graphify-update', etc. * Restrict hooks/lib/ install to hook-enabled runtimes and managed allowlist Codex/Copilot/Cursor/Windsurf/Trae/Cline already skip the hooks block but were still copying hooks/lib/ helpers, contradicting the downstream Codex comment. Gate the call on the same runtime check and pass GSD_HOOK_LIB_FILES so install scope matches the uninstall/manifest scope. |
||
|
|
6bd4091aa0 |
Merge pull request #3618 from gsd-build/fix/3610-error-installing-v1-42-2-in-codex
fix(3610): unblock fresh Codex install when leftover bundled hooks present |
||
|
|
f422a05450 |
fix(3610): unblock fresh Codex install when leftover bundled hooks present
`npx get-shit-done-cc@latest --codex` aborted with "installer migration blocked pending user choice" listing 12 hooks/gsd-* files. Those files are part of the GSD npm distribution (hooks/gsd-prompt-guard.js, hooks/gsd-context-monitor.js, etc.), not user-owned content, so asking the user to choose between keep/remove for them was a UX bug, not a real choice. The installer is about to write the fresh bundled versions in their place. Root cause: `classifyPromptUserAction` in get-shit-done/bin/lib/installer-migration-report.cjs knew two unambiguous categories (`stale-sdk-build-artifact`, `user-facing-skill`) but had no rule for the bundled GSD hooks. The first-time-baseline scan classified them as `stale-gsd-looking` prompt-user blockers, and `assertInstallerMigrationsUnblocked` threw. A second gate compounded the bug: the safe-default resolver in bin/install.js was wrapped in `if (!_migrationIsTty)`, so even with a correct classification rule, TTY runs (every `npx get-shit-done-cc` invocation) skipped the resolver and went straight to the hard throw. Fix: 1) Add `hooks/gsd-<name>.(js|sh|cjs|mjs)` to `classifyPromptUserAction` as `bundled-gsd-hook` → `remove`. The regex is anchored at the top-level `hooks/` directory so nested paths like `hooks/gsd-helpers/index.js` (or any user-owned helper directory) do NOT auto-classify. 2) Remove the `!_migrationIsTty` gate from the resolver call in bin/install.js. The classifier-based path is unambiguous and must apply regardless of TTY; the env-override branch (GSD_INSTALLER_MIGRATION_RESOLVE) still applies only when isTty=false inside the resolver, preserving the #3541 semantic. Regression test added (tests/bug-3610-installer-migration-bundled-hooks-classification.test.cjs): - Positive: hooks/gsd-*.{js,sh} → category=bundled-gsd-hook, choice=remove. - Counter-test: hooks/my-custom-hook.js → classifier returns null (user files are preserved). - Boundary: hooks/gsd-helpers/index.js → classifier returns null (nested directories don't auto-classify). - End-to-end: 12 reporter-exact bundled hooks + empty manifest → resolver clears every blocker, assertInstallerMigrationsUnblocked does not throw. Test exercises the real installer-migration code path (`runInstallerMigrations` + `resolveInstallerMigrationPromptsForNonTty` + `assertInstallerMigrationsUnblocked`) — no source-grep, no raw text matching on outputs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
79ea076daa |
fix(3571): load configuration manifests after install (#3572)
* fix(3571): load configuration manifests after install * test(3571): simplify missing manifest check |
||
|
|
eb92d107c8 |
Merge pull request #3568 from gsd-build/fix/3562-codex-0-130-0-gsd-1-42-2-installs-workfl
fix(3562): generate Codex skill surface so $gsd-* commands resolve on Codex CLI 0.130.0+ |
||
|
|
1746f89ac7 |
fix(3566): narrow scope; update codex-config tests for canonical hooks key
Two follow-up adjustments after running the full suite: 1. Reverted the rewriteTomlKeyLines() change. The original `match.keyRaw || key` fallback respects user ownership of pre-existing legacy lines (#2760 defensive principle). My fix now applies the canonical-vs-legacy split at the INSERTION points only: fresh installs write `hooks = true`, but a pre-existing user-authored `codex_hooks = true` is preserved verbatim. Codex's own runtime legacy_key alias handles backward-compat at the Codex layer. 2. Updated 12 test cases in tests/codex-config.test.cjs that pinned the old fresh-write key. These assertions now expect canonical `hooks` for fresh-write scenarios; tests covering legacy-line preservation already pass against the narrowed fix without further edits. Also updated bug-3566 regression-test cases for the legacy-preservation path — they now verify that user-owned `codex_hooks` survives an install. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
55b3f45ad0 |
fix(3566): emit canonical [features].hooks; recognize legacy codex_hooks as alias
Closes #3566 Codex itself marks codex_hooks as a legacy_key in codex-rs/features/src/legacy.rs. The canonical current Codex feature flag under [features] is hooks. The GSD installer was still writing codex_hooks on every fresh install / reinstall, leaving deprecated config behind on Codex CLI >= 0.130.0. Introduces a canonical/legacy split in bin/install.js: CODEX_HOOKS_FEATURE_KEY = 'hooks' CODEX_HOOKS_FEATURE_LEGACY_KEYS = ['codex_hooks'] isCodexHooksFeatureKey(key) // recognizes canonical OR any legacy alias Threaded through: - ensureCodexHooksFeature(): emits canonical hooks; recognizes legacy codex_hooks; migrates legacy -> canonical in section, root-dotted, and block-fallback insertion paths. - hasEnabledCodexHooksFeature(): accepts either canonical or legacy. - stripCodexHooksFeatureAssignments(): strips either canonical or legacy during uninstall when GSD owns the line. - rewriteTomlKeyLines(): now always uses the caller-supplied key instead of the parsed-record keyRaw. The old `match.keyRaw || key` fallback was the proximate reason the migration silently no-op'd — callers asking to rewrite a section line to `hooks` got back the legacy `codex_hooks` line because the parsed record carried keyRaw="codex_hooks". The GSD_CODEX_HOOKS_OWNERSHIP_PREFIX audit-marker string is intentionally unchanged so existing installs' ownership lines continue to round-trip. Tests: - New tests/bug-3566-codex-hooks-feature-canonical-key.test.cjs (6 cases): fresh install writes hooks; section-form legacy migrated; root-dotted legacy migrated; user-owned hooks preserved; uninstall removes GSD-owned canonical; uninstall preserves user-owned hooks. - Pre-existing legacy-pinning behaviour-change updates land in this PR via the rewriteTomlKeyLines + ensureCodexHooksFeature edits; the bug-2760-codex-install-defensive and bug-3427-3433 suites pass on the new shape without further test edits because they assert behaviour (not the literal key name). Docs: - docs/ARCHITECTURE.md row for Codex notes [features].hooks (canonical, legacy codex_hooks recognized and migrated forward). - docs/installer-migrations.md row updated to reflect canonical key and the new Codex 0.130.0 features.hooks compatibility sentinel. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
365340596d |
fix(3562): generate Codex skill surface; $gsd-* commands discoverable after install
Closes #3562 Codex CLI 0.130.0 only registers commands from skills/<name>/SKILL.md; it does NOT auto-discover from get-shit-done/workflows/*.md or agents/*.md. Prior installer logic (#3427/#3433) removed the gsd-* skill copies under the assumption that Codex would discover the official skills directly. That assumption does not hold — users ended up with workflows on disk and zero $gsd-* entrypoints after restart. Fix: re-wire copyCommandsAsCodexSkills() (line 5519, already present) into the Codex install dispatch path (line 8090). Generates one ~/.codex/skills/gsd-<name>/SKILL.md per commands/gsd/*.md — same shape the Copilot/Antigravity/Cursor/Windsurf/Augment/Trae installs use. Behaviour change: the pre-existing test in bug-3427-3433-codex-install-shape asserted "does not regenerate gsd-* skill copies". Updated it to assert the new behaviour (regenerate gsd-* with refreshed body, preserve non-gsd user skills). Tests: - New tests/bug-3562-codex-install-skill-surface.test.cjs (4 cases): - skills/gsd-help/SKILL.md exists - SKILL.md has YAML frontmatter with name: gsd-help - >= 10 gsd-* skill directories produced (lower-bound, currently 67) - Pre-existing custom-user-skill directory preserved - tests/bug-3427-3433-codex-install-shape.test.cjs: updated to assert regeneration + body refresh + unrelated-skill preservation. Verified by re-running the issue's repro: `node bin/install.js --codex --global --config-dir <tmp>` now produces 67 gsd-* skills and the target ~/.codex/skills/gsd-help/SKILL.md exists with valid frontmatter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
dacc23137a |
feat(3347): opt-in auto-update of knowledge graph after main HEAD advances
Closes #3347 Config: - Add graphify.auto_update (default false) to manifests: sdk/shared/config-defaults.manifest.json, config-schema.manifest.json Hook: - hooks/gsd-graphify-update.sh — PostToolUse Bash matcher - Gates: tool_name=Bash, HEAD-advancing git op, CI=unset, in git repo, current branch == default branch (git.base_branch override or main/ master/trunk fallback), graphify.enabled && graphify.auto_update both true, graphify on PATH, no live PID lock - Writes .planning/graphs/.last-build-status.json with status=running synchronously, then detaches hooks/lib/gsd-graphify-rebuild.sh - hooks/lib/gsd-graphify-rebuild.sh — detached rebuild runner - PID-lock acquire + trap-on-exit cleanup - graphify update . then cp graphify-out/* → .planning/graphs/ - Status file rewritten to status=ok|failed with exit_code, duration_ms, head_at_build - Portable detach (subshell + disown, no setsid dependency) Installer: - bin/install.js: register hook as PostToolUse Bash matcher (5s timeout) - Add to gsdHooks uninstall list and expectedShHooks warning list Planner / researcher status surface (issue #3347 reviewer must-have AC): - agents/gsd-planner.md and agents/gsd-phase-researcher.md load_graph_context steps now read .last-build-status.json and surface: running → "rebuild in flight"; failed → "auto-rebuild FAILED at {ts}, context is from prior build"; ok with stale head_at_build → "HEAD has advanced since last build" Settings: - get-shit-done/workflows/settings.md adds "Graph auto-update" question with No-Recommended default; bullets and update_config block updated Inventory: - docs/INVENTORY.md hook count 12 → 13 with new row - docs/INVENTORY-MANIFEST.json regenerated Tests: - tests/feat-3347-graphify-auto-update-config.test.cjs (8 tests): isValidConfigKey accepts graphify.auto_update, CANONICAL_CONFIG_DEFAULTS default false, config-set round-trip, sibling key preservation - tests/feat-3347-graphify-auto-update-hook.test.cjs (18 tests): all bail paths (non-Bash, non-HEAD-advancing, enabled=false, auto_update=false, CI=true, non-default-branch, missing graphify bin, live-PID lock), dispatch path with mock graphify bin (sync running status + detached transition to ok/failed), stale-PID lock, all five HEAD-advancing command matchers, git.base_branch override Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c39a7e1f6f |
fix(3541): resolve prompt-user migration actions in non-TTY runs; improve error grouping
Closes #3541 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d4d4178603 |
Merge pull request #3483 from radioflyer28/feat/agent-launch-reasoning-transport-3474
feat: transport resolved reasoning effort to agent launches |
||
|
|
3f054b4a96 |
Merge pull request #3505 from gsd-build/fix/3346-codex-aot-toml-event-key
fix(install): emit event-name leaf key for Codex AoT hooks migration (#3346) |
||
|
|
925cce684a | fix(codex): remove managed hooks.json SessionStart on uninstall | ||
|
|
1d6284a718 | fix(codex): remove duplicate skill copies and consolidate hook payloads | ||
|
|
619915de96 |
fix(install): emit event-name leaf key for Codex AoT hooks migration (#3346)
migrateCodexHooksMapFormat re-emitted the raw `[hooks.<X>]` path segment as the leaf TOML key of the new `[[hooks.<EVENT>]]` block. When the legacy table key was a `<file>:<event>:<line>:<col>` location identifier and the real event lived in an `event = "..."` body field, the migration emitted a header like `[[hooks."C:\\Users\\helen\\.codex\\config.toml:session_start:0:0"]]` that Codex 0.124.0+ refuses to load — causing `npx get-shit-done-cc@latest` to abort the Codex runtime install on Windows configs that pre-date AoT. Mirror the flat-AoT branch in the map-format and stale-namespaced-AoT branches: when the section body declares `event = "..."`, that name wins as the leaf key and `event` is excluded from the re-emitted handler body. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
810778e137 | fix(sdk): gate reasoning effort by runtime allowlist | ||
|
|
f70829d067 | feat: transport resolved reasoning effort |