* test: add stale /gsd: colon reference regression guard
Fixes#1748
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace 39 stale /gsd: colon references with /gsd- hyphen format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fixes#1709
copyFlattenedCommands replaced ~/.opencode/ paths but had no
equivalent ~/.kilo/ replacement. Adds kiloDirRegex for symmetric
path handling between the OpenCode and Kilo install pipelines.
* ci: drop Windows runner, add static hardcoded-path detection
Replace the Windows CI runner with a static analysis test that catches
the same class of platform-specific path bugs (C:\, /home/, /Users/,
/tmp/) without requiring an actual Windows machine.
- tests/hardcoded-paths.test.cjs: new static scanner that checks string
literals in all source JS/CJS files for hardcoded platform paths;
runs on Linux/macOS in <100ms and fires on every PR
- .github/workflows/test.yml: remove windows-latest from matrix; switch
macOS smoke-test runner from Node 22 → Node 24 (the declared standard)
- package.json: bump engines.node from >=20.0.0 to >=22.0.0 (Node 20
reached EOL April 2026)
Matrix goes from 4 runners → 3 runners per run:
ubuntu/22 ubuntu/24 macos/24
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(install): apply path replacement in copyCommandsAsClaudeSkills (#1653)
copyCommandsAsClaudeSkills received pathPrefix as a parameter but never
used it — all 51 SKILL.md files kept hardcoded ~/.claude/ paths even on
local (per-project) installs, causing every skill's @-file references
to resolve to a nonexistent global directory.
Add the same three regex replacements that copyCommandsAsCodexSkills
already applies: ~/.claude/ → pathPrefix, $HOME/.claude/ → pathPrefix,
./.claude/ → ./getDirName(runtime)/.
Closes#1653
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: ignore .worktrees directory
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(install): remove marketing taglines from runtime selection prompt
Closes#1654
The runtime selection menu had promotional copy appended to some
entries ("open source, the #1 AI coding platform on OpenRouter",
"open source, free models"). Replaced with just the name and path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(kilo): update test to assert marketing tagline is removed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(tests): use process.execPath so tests pass in shells without node on PATH
Three test patterns called bare `node` via shell, which fails in Claude Code
sessions where `node` is not on PATH:
- helpers.cjs string branch: execSync(`node ...`) → execFileSync(process.execPath)
with a shell-style tokenizer that handles quoted args and inner-quote stripping
- hooks-opt-in.test.cjs: spawnSync('bash', ...) for hooks that call `node`
internally → spawnHook() wrapper that injects process.execPath dir into PATH
- concurrency-safety.test.cjs: exec(`node ...`) for concurrent patch test
→ exec(`"${process.execPath}" ...`)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: resolve#1656 and #1657 — bash hooks missing from dist, SDK install prompt
#1656: Community bash hooks (gsd-session-state.sh, gsd-validate-commit.sh,
gsd-phase-boundary.sh) were never included in HOOKS_TO_COPY in build-hooks.js,
so hooks/dist/ never contained them and the installer could not copy them to
user machines. Fixed by adding the three .sh files to the copy array with
chmod +x preservation and skipping JS syntax validation for shell scripts.
#1657: promptSdk() called installSdk() which ran `npm install -g @gsd-build/sdk`
— a package that does not exist on npm, causing visible errors during interactive
installs. Removed promptSdk(), installSdk(), --sdk flag, and all call sites.
Regression tests in tests/bugs-1656-1657.test.cjs guard both fixes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: sort runtime list alphabetically after Claude Code
- Claude Code stays pinned at position 1
- Remaining 10 runtimes sorted A-Z: Antigravity(2), Augment(3), Codex(4),
Copilot(5), Cursor(6), Gemini(7), Kilo(8), OpenCode(9), Trae(10), Windsurf(11)
- Updated runtimeMap, allRuntimes, and prompt display in promptRuntime()
- Updated multi-runtime-select, kilo-install, copilot-install tests to match
Also fix#1656 regression test: run build-hooks.js in before() hook so
hooks/dist/ is populated on CI (directory is gitignored; build runs via
prepublishOnly before publish, not during npm ci).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: ignore .worktrees directory
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(install): remove marketing taglines from runtime selection prompt
Closes#1654
The runtime selection menu had promotional copy appended to some
entries ("open source, the #1 AI coding platform on OpenRouter",
"open source, free models"). Replaced with just the name and path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(kilo): update test to assert marketing tagline is removed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The discord.gg/gsd vanity link was lost due to a drop in server boosts.
Updated all references to the permanent invite link discord.gg/mYgfVNfA2r
across READMEs, issue templates, install script, and join-discord command.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add Trae runtime install support
- Add Trae as a supported runtime in bin/install.js
- Update README and ARCHITECTURE documentation for Trae support
- Add trae-install.test.cjs test file
- Update multi-runtime-select tests for Trae compatibility
* feat(trae): add TRAE_CONFIG_DIR environment variable support
Add support for TRAE_CONFIG_DIR environment variable as an additional way to specify the config directory for Trae runtime, following the same precedence pattern as other runtimes.
* fix(trae): improve slash command conversion and subagent type mapping
Update the slash command regex pattern to properly match and convert command names. Change subagent type mapping from "general-purpose" to "general_purpose_task" to match Trae's conventions. Also add comprehensive tests for Trae uninstall cleanup behavior.
* docs: add Trae and Windsurf to supported runtimes in translations
Update Korean, Japanese, and Portuguese README files to include Trae and Windsurf as supported runtimes in the documentation. Add installation and uninstallation instructions for Trae.
* fix: update runtime selection logic and path replacements
- Change 'All' shortcut from option 11 to 12 to accommodate new runtime
- Update path replacement regex to handle gsd- prefix more precisely
- Adjust test cases to reflect new runtime selection numbering
- Add configDir to trae install options for proper path resolution
* test(trae-install): add tests for getGlobalDir function
Add test cases to verify behavior of getGlobalDir function with different configurations:
- Default directory when no env var or explicit dir is provided
- Explicit directory takes priority
- Respects TRAE_CONFIG_DIR env var
- Priority of explicit dir over env var
- Compatibility with other runtimes
* fix(hooks): add read-before-edit guidance for non-Claude runtimes
When models that don't natively enforce read-before-edit hit the guard,
the error message now includes explicit instruction to Read first.
This prevents infinite retry loops that burn through usage.
Closes#1628
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(build): register gsd-read-guard.js in HOOKS_TO_COPY and harden tests
The hook was missing from scripts/build-hooks.js, so global installs
would never receive the hook file in hooks/dist/. Also adds tests for
build registration, install uninstall list, and non-string file_path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace /gsd: command format with /gsd- skill format in all suggestions
All next-step suggestions shown to users were still using the old colon
format (/gsd:xxx) which cannot be copy-pasted as skills. Migrated all
occurrences across agents/, commands/, get-shit-done/, docs/, README files,
bin/install.js (hardcoded defaults for claude runtime), and
get-shit-done/bin/lib/*.cjs (generate-claude-md templates and error messages).
Updated tests to assert new hyphen format instead of old colon format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: migrate remaining /gsd: format to /gsd- in hooks, workflows, and sdk
Addresses remaining user-facing occurrences missed in the initial migration:
- hooks/: fix 4 user-facing messages (pause-work, update, fast, quick)
and 2 comments in gsd-workflow-guard.js
- get-shit-done/workflows/: fix 21 Skill() literal calls that Claude
executes directly (installer does not transform workflow content)
- sdk/prompt-sanitizer.ts: update regex to strip /gsd- format in addition
to legacy /gsd: format; update JSDoc comment
- tests/: update autonomous-ui-steps, prompt-sanitizer to assert new format
Note: commands/gsd/*.md frontmatter (name: gsd:xxx) intentionally unchanged
— installer derives skillName from directory path, not the name field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(plan-phase): preserve --chain flag in auto-advance sync and handle ui-phase gate in chain mode
Bug 1: step 15 sync-flag check only guarded against --auto, causing
_auto_chain_active to be cleared when plan-phase is invoked without
--auto in ARGUMENTS even though a --chain pipeline was active. Added
--chain to the guard condition, matching discuss-phase behaviour.
Bug 2: UI Design Contract gate (step 5.6) always exited the workflow
when UI-SPEC was missing, breaking the discuss --chain pipeline
silently. When _auto_chain_active is true, the gate now auto-invokes
gsd-ui-phase --auto via Skill() and continues to step 6 without
prompting. Manual invocations retain the existing AskUserQuestion flow.
* fix: remove <sub>/clear</sub> pattern and duplicate old-format command in discuss-phase.md
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Remove the unused JSONC helper and duplicate test export so the installer only keeps the shipped fixes. This closes the remaining code-level review feedback after the Kilo support sync.
Keep Kilo skill path rewrites consistent and avoid rewriting valid string-valued OpenCode permission configs while preserving resolved config-dir handling.
Bring the latest main branch updates into feat/kilo-runtime-support while preserving KILO_CONFIG resolution, Kilo agent permission conversion, and relative .claude path rewrites.
After #1540 migrated Claude Code to skills/ format, the uninstall
added a legacy commands/gsd/ cleanup that wiped the directory without
checking for user files. Add preserve logic to the legacy cleanup path
matching what Gemini's commands/gsd/ path already has.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback: wrap writeFileSync in try/catch so restore
failures surface a clear error instead of silently losing user files.
Add comment noting the naming convention approach for future scaling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The uninstall step wipes get-shit-done/ and commands/gsd/ directories
entirely, destroying user-generated files like USER-PROFILE.md (from
/gsd:profile-user) and dev-preferences.md. These files are now read
before rmSync and restored immediately after.
Closes#1423
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Honor KILO_CONFIG across installer and workflow resolution, preserve Claude agent tool intent as explicit Kilo permissions, and rewrite relative .claude references during Kilo conversion.
Port 3 community hooks from gsd-skill-creator, gated behind hooks.community config flag. All hooks are registered on install but are no-ops unless the project config has hooks: { community: true }.
gsd-session-state.sh (SessionStart): outputs STATE.md head for orientation. gsd-validate-commit.sh (PreToolUse/Bash): blocks non-Conventional-Commits messages. gsd-phase-boundary.sh (PostToolUse/Write|Edit): warns when .planning/ files are modified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add --augment flag to install for Augment only
- Add Augment to --all and interactive menu (now 9 runtimes + All)
- Create conversion functions for Augment skills and agents:
- convertClaudeToAugmentMarkdown: path and brand replacement
- convertClaudeCommandToAugmentSkill: skill format with adapter header
- convertClaudeAgentToAugmentAgent: agent format conversion
- copyCommandsAsAugmentSkills: copy commands as skills
- Map tool names: Bash → launch-process, Edit → str-replace-editor, etc.
- Add runtime label and uninstall support for Augment
- Add tests: augment-conversion.test.cjs with 15 test cases
- Update multi-runtime-select.test.cjs to include Augment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude Code 2.1.88+ deprecated commands/ subdirectory discovery in favor of
skills/*/SKILL.md format. This migrates the Claude Code installer to use the
same skills pattern already used by Codex, Copilot, Cursor, Windsurf, and
Antigravity.
Key changes:
- New convertClaudeCommandToClaudeSkill() preserving allowed-tools and argument-hint
- New copyCommandsAsClaudeSkills() mirroring Copilot pattern
- Install now writes skills/gsd-*/SKILL.md instead of commands/gsd/*.md
- Legacy commands/gsd/ cleaned up during install
- Manifest tracks skills/ for Claude Code
- Uninstall handles both skills/ and legacy commands/
Fixes#1504
Supersedes #1538
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix path replacement for ~/.claude to ~/.github
The current rules miss replacing this path because the current rules look for the .claude directory with a trailing slash, which this does not have.
* Fix regex to replace trailing .claude with .github
When settings.json contains comments (// or /* */), which many CLI tools
allow, JSON.parse() fails and readSettings() silently returned {}.
This empty object was then written back by writeSettings(), destroying
the user's entire configuration.
Changes:
- Add stripJsonComments() that handles line comments, block comments,
trailing commas, and preserves comments inside string values
- readSettings() tries standard JSON first (fast path), falls back to
JSONC stripping on parse failure
- On truly malformed files (even JSONC stripping fails), return null
with a warning instead of silently returning {} — prevents data loss
- All callers of readSettings() now guard against null return to skip
settings modification rather than overwriting with empty object
Closes#1461
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The reapply-patches workflow used a two-way comparison (user's backup vs
new version) which couldn't distinguish user customizations from version
drift. This caused 10/10 files to be misclassified as "no custom content"
in real-world usage, silently discarding user modifications.
Changes:
- Rewrite workflow with three-way merge strategy (pristine baseline vs
user-modified backup vs newly installed version)
- Add critical invariant: files in gsd-local-patches/ must NEVER be
classified as "no custom content" — they were backed up because the
installer's hash check detected modifications
- Add git-aware detection path using commit history when config dir is
a git repo
- Add pristine_hashes to backup-meta.json so the reapply workflow can
verify reconstructed baseline files
- Add from_manifest_timestamp to backup-meta.json for version tracking
- Conservative default: flag as CONFLICT when uncertain, not SKIP
Closes#1469
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
convertClaudeToCodexMarkdown() was missing path replacement — unlike
Copilot/Gemini/Antigravity converters which all replace $HOME/.claude/
paths. This left hardcoded .claude references in Codex agent files,
causing ENOENT when gsd-tools.cjs tried to load from ~/.claude/ on
Codex installations.
Closes#1430
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add installSdk() and promptSdk() to the installer so users can
optionally install @gsd-build/sdk during GSD setup. The --sdk flag
installs without prompting; interactive installs get a Y/N prompt
after runtime installation completes. SDK installs use @latest with
suppressed npm noise (--force --no-fund --loglevel=error, stdio: pipe).
Cherry-picked from fix/sdk-cli-runtime-bugs (de9f18f) which was
left out of #1407.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Node v25 preserves trailing slashes in path.join, causing
writeFileSync to fail with ENOENT when the converted path
ends in '/'. Affects all Windsurf users on Node v25+.
Fixesgsd-build/get-shit-done#1392
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-#1346 GSD installs prepended [features] before bare top-level keys
in ~/.codex/config.toml, trapping keys like model="gpt-5.3-codex" under
[features] where Codex expects only booleans. The #1346 fix prevented
NEW corruption but did not repair EXISTING corrupted configs. Re-installing
GSD left the trapped keys in place, causing "invalid type: string, expected
a boolean" on every Codex launch.
repairTrappedFeaturesKeys() now detects non-boolean key-value lines inside
[features] and relocates them before the [features] header during
ensureCodexHooksFeature(), so re-installs heal previously corrupted configs.
Fixes#1379
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add validateHookFields() that strips invalid hook entries before they
cause Claude Code's Zod schema to silently discard the entire
settings.json file. Agent hooks require "prompt", command hooks require
"command", and entries without a valid hooks sub-array are removed.
Uses a clean two-pass approach: first validate and build new arrays
(no mutation inside filter predicates), then collect-and-delete empty
event keys (no delete during Object.keys iteration). Result entries
are shallow copies so the original input objects are never mutated.
Includes 24 tests covering passthrough, removal, structural invalidity,
empty cleanup, mutation safety, unknown types, and iteration safety.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes for Codex config.toml compatibility:
1. ensureCodexHooksFeature: insert [features] before the first table header
instead of prepending it before all content. Prepending traps bare
top-level keys (model, model_reasoning_effort) under [features], where
Codex rejects them with "invalid type: string, expected a boolean".
2. generateCodexConfigBlock: use absolute config_file paths when targetDir
is provided. Codex ≥0.116 requires AbsolutePathBuf and cannot resolve
relative "agents/..." paths, failing with "AbsolutePathBuf deserialized
without a base path".
Fixes#1202
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds full Windsurf (by Codeium) runtime integration, following the same
pattern as the existing Cursor support. Windsurf uses .windsurf/ for
local config and ~/.windsurf/ for global config, with skills in
.windsurf/skills/ using the SKILL.md structure.
What:
- CLI flag --windsurf and interactive prompt option (8)
- Directory mapping (.windsurf local, ~/.windsurf global)
- Content converter functions (tool names, path replacements, brand refs)
- Skill copy function (copyCommandsAsWindsurfSkills)
- Agent conversion (convertClaudeAgentToWindsurfAgent)
- Install/uninstall branches
- Banner, help text, and issue template updates
- Windsurf conversion test suite (windsurf-conversion.test.cjs)
- Updated multi-runtime selection tests for 8 runtimes
Closes#1336
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gemini CLI uses BeforeTool (not PreToolUse) for pre-tool hooks, matching
the existing pattern where AfterTool is used instead of PostToolUse. The
prompt injection guard hook was hardcoded to PreToolUse, causing Gemini
CLI to log "Invalid hook event name: PreToolUse" on startup.
Apply the same runtime-conditional mapping used for post-tool hooks, and
update the uninstall cleanup to iterate both event names.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The interactive prompt now accepts comma-separated or space-separated
choices (e.g., "1,4,6" or "1 4 6") to install multiple runtimes in
one go, without needing --all or running the installer multiple times.
- Replaced if/else-if chain with runtimeMap lookup + split parser
- Added hint text: "Select multiple: 1,4,6 or 1 4 6"
- Invalid choices silently filtered, duplicates deduplicated
- Empty input still defaults to Claude Code
- Choice "8" still selects all runtimes
Tests: 10 new tests covering comma/space/mixed separators,
deduplication, invalid input filtering, order preservation,
and source-level assertions.
Closes#1281
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>