Cline was documented as a supported runtime but was absent from
bin/install.js. This adds full Cline support:
- Registers --cline CLI flag and adds 'cline' to --all list
- Adds getDirName/getConfigDirFromHome/getGlobalDir entries (CLINE_CONFIG_DIR env var respected)
- Adds convertClaudeToCliineMarkdown() and convertClaudeAgentToClineAgent()
- Wires Cline into copyWithPathReplacement(), install(), writeManifest(), finishInstall()
- Local install writes to project root (like Claude Code), not .cline/ subdirectory
- Generates .clinerules at install root with GSD integration rules
- Installs get-shit-done engine and agents with path/brand replacement
- Adds Cline as option 4 in interactive menu (13-runtime menu, All = 14)
- Updates banner description to include Cline
- Exports convertClaudeToCliineMarkdown and convertClaudeAgentToClineAgent for testing
- Adds tests/cline-install.test.cjs with 17 regression tests
- Updates multi-runtime-select, copilot-install, kilo-install tests for new option numbers
Fixes#1991
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The convertSlashCommandsToCodexSkillMentions function only converted
colon-style skill invocations (/gsd:command) but not hyphen-style
command references (/gsd-command) used in workflow output templates
(Next Up blocks, phase completion messages, etc.). This caused Codex
users to see /gsd- prefixed commands instead of $gsd- in chat output.
- Add regex to convert /gsd-command → $gsd-command with negative
lookbehind to exclude file paths (e.g. bin/gsd-tools.cjs)
- Strip /clear references in Codex output (no Codex equivalent)
- Add 5 regression tests covering command conversion, path
preservation, and /clear removal
Co-authored-by: Lakshman <lakshman@lakshman-GG9LQ90J61.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Running gsd-update (re-running the installer) silently deleted two
user-generated files:
- get-shit-done/USER-PROFILE.md (created by /gsd-profile-user)
- commands/gsd/dev-preferences.md (created by /gsd-profile-user)
Root causes:
1. copyWithPathReplacement() calls fs.rmSync(destDir, {recursive:true})
before copying, wiping USER-PROFILE.md with no preserve allowlist.
2. The legacy commands/gsd/ cleanup at ~line 5211 rmSync'd the entire
directory, wiping dev-preferences.md.
3. The backup path in profile-user.md pointed to the same directory
that gets wiped, so the backup was also lost.
Fix:
- Add preserveUserArtifacts(destDir, fileNames) and restoreUserArtifacts()
helpers that save/restore listed files around destructive wipes.
- Call them in install() before the get-shit-done/ copy (preserves
USER-PROFILE.md) and before the legacy commands/gsd/ cleanup
(preserves dev-preferences.md).
- Fix profile-user.md backup path from ~/.claude/get-shit-done/USER-PROFILE.backup.md
to ~/.claude/USER-PROFILE.backup.md (outside the wiped directory).
Closes#1924
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Local installs wrote bare relative paths (e.g. `node .claude/hooks/...`)
into settings.json. Claude Code persists the shell's cwd between tool
calls, so a single `cd subdir` broke every hook for the rest of the
session.
Prefix all 9 local hook commands with "$CLAUDE_PROJECT_DIR"/ so path
resolution is always anchored to the project root regardless of cwd.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The installer writes gsd-file-manifest.json to the runtime config root
at install time but uninstall() never removed it, leaving stale metadata
after every uninstall. Add fs.rmSync for MANIFEST_NAME at the end of the
uninstall cleanup sequence.
Regression test: tests/bug-1908-uninstall-manifest.test.cjs covers both
global and local uninstall paths.
Closes#1908
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add fs.existsSync() guards to all .js hook registrations in install.js,
matching the pattern already used for .sh hooks (#1817). When hooks/dist/
is missing from the npm package, the copy step produces no files but the
registration step previously ran unconditionally for .js hooks, causing
"PreToolUse:Bash hook error" on every tool invocation.
Each .js hook (check-update, context-monitor, prompt-guard, read-guard,
workflow-guard) now verifies the target file exists before registering
in settings.json, and emits a skip warning when the file is absent.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(installer): deploy commands directory in local installs (#1736)
Local Claude installs now populate .claude/commands/gsd/ with command .md
files. Claude Code reads local project commands from .claude/commands/gsd/,
not .claude/skills/ — only the global ~/.claude/skills/ is used for the
skills format. The previous code deployed skills/ for both global and local
installs, causing all /gsd-* commands to return "Unknown skill" after a
local install.
Global installs continue to use skills/gsd-xxx/SKILL.md (Claude Code 2.1.88+
format). Local installs now use commands/gsd/xxx.md (the format Claude Code
reads for local project commands).
Also adds execute-phase.md to the prompt-injection scan allowlist (the
workflow grew past 50K chars, matching the existing discuss-phase.md exemption).
Closes#1736
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(installer): fix test cleanup pattern and uninstall local/global split (#1736)
Replace try/finally with t.after() in all 3 regression tests per CONTRIBUTING.md
conventions. Split the Claude Code uninstall branch on isGlobal: global removes
skills/gsd-*/ directories (with legacy commands/gsd/ cleanup), local removes
commands/gsd/ as the primary install location since #1736.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(install): preserve non-array hook entries during uninstall
Uninstall filtering returned null for hook entries without a hooks
array, silently deleting user-owned entries with unexpected shapes.
Return the entry unchanged instead so only GSD hooks are removed.
* test(install): add regression test for non-array hook entry preservation (#1825)
Fix mirrored filterGsdHooks helper to match production code and add
test proving non-array hook entries survive uninstall filtering.
Before registering each .sh hook (validate-commit, session-state, phase-boundary),
check that the target file was actually copied. If the .sh file is missing (e.g.
omitted from the npm package as in v1.32.0), skip registration and emit a warning
instead of writing a broken hook entry that errors on every tool invocation.
Closes#1817
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Community PRs repeatedly add marketing commentary in parentheses next to
product names (licensing model, parent company, architecture). Product
listings should contain only the product name.
Cleaned across 8 files in 5 languages (EN, KO, JA, ZH, PT) plus
install.js code comments and CHANGELOG. Added static analysis guard
test that prevents this pattern from recurring.
Fixes#1777
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The hook was built, copied to hooks/dist/, and installed to disk — but
never registered as a PreToolUse entry in settings.json, making the
hooks.workflow_guard config flag permanently inert.
Adds the registration block following the same pattern as the other
community hooks (prompt-guard, read-guard, validate-commit, etc.).
Includes regression test that verifies every JS hook in gsdHooks has a
corresponding command construction and registration block.
Fixes#1767
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Addresses three findings from Codex adversarial review of #1768:
- Uninstall settings cleanup now filters at per-hook granularity instead of
per-entry. User hooks that share an entry with a GSD hook are preserved
instead of being removed as collateral damage.
- Add gsd-workflow-guard to PreToolUse/BeforeTool uninstall settings filter
so opt-in users don't get dangling references after uninstall.
- Codex install now strips legacy gsd-update-check.js hook entries before
appending the corrected gsd-check-update.js, preventing duplicate hooks
on upgrade from affected versions.
- 8 new regression tests covering per-hook filtering, legacy migration regex.
Fixes#1755
* 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>