fix(#3544): restore tilde form for at-refs in the global spec tree (#3551)

* fix(#3544): restore tilde form for at-refs in the global spec tree

A global claude install emitted @$HOME/.claude/gsd-core/references/*.md
in its workflows and references. $HOME does not expand in a Claude Code
@-import - only relative, absolute and ~ are documented, and a controlled
/context test confirmed a $HOME import loads nothing - so 54 includes
across 22 files silently resolved to nothing on a live install.

This is a divergence, not a new bug. #3133 already applies exactly this
correction to skill and command bodies through _applyRuntimeRewrites's
claude case; copyWithPathReplacement, the spec-tree emit path, never had
it. Both now call one exported helper, so the two surfaces cannot drift
apart again.

Deliberately narrower than changing computePathPrefix's return value:
shipped markdown also carries double-quoted "$HOME/.claude/..." shell
invocations, and ~ does not expand inside double quotes, so rewriting the
prefix wholesale would regress #1284. Only @-prefixed references move.

Refs #3544

* fix(#3544): derive the tilde restore from the resolved prefix

Three review findings, one batch.

The restore was hardcoded to the literal .claude directory, so a global
install with --config-dir pointing anywhere else silently no-opped and
reproduced the very defect this fixes. It now derives the tilde form from
the resolved prefix, which also closes the same latent gap in #3133's
original path since both call sites share the helper.

The @-anchor is quote-aware, so a double-quoted shell path is never
rewritten into a form the shell does not expand. Deliberately a lookbehind
rather than a line-start anchor: @-references are documented to work
mid-line, and anchoring would have traded a theoretical bug for a real one.

Found while testing the above: the bare-form rewrites re-matched their own
output whenever a config dir name extends .claude, emitting
.claude-work-work. Guarded with the same negative-lookahead convention
this file already uses to preserve .claude-plugin.

The tests prove the emitted form, never that the host resolves it - no CI
test can - and both the helper and the suite now say so, because an
undocumented verification boundary is how this defect stayed green for its
whole life.

Refs #3544

* test(#3544): acknowledge the tilde-restore emitted drift

The converter change moves 94 emitted paths that no source-file diff can
explain, which is exactly the case the per-PR ack fragment exists for.
Verified before acknowledging rather than after: both trees were built
from real installs and every one of the 211 changed lines across all 94
paths is @$HOME becoming @~, with nothing outside that single kind.

Nine spent entries were pruned from the #3151 and #2658 fragments. Those
paths moved again here, and two ack sources naming one path is a hard
duplicate error rather than last-wins, so the inert entries had to go
before this one could land. Both fragments retain their remaining
entries.

Refs #3544

* chore(#3544): backfill changeset pr number

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-08-15 09:31:59 -04:00
committed by GitHub
parent b7cca0363f
commit fd2b97a52a
7 changed files with 675 additions and 35 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3551
---
**Global Claude Code installs now load their referenced workflow context** — `gsd-core/workflows/*.md` and other spec-tree files previously emitted `@$HOME/.claude/...` `@`-file-references, a form Claude Code's `@`-import resolver silently drops (only `~/` and absolute paths resolve). Every such reference now resolves on `~/`, matching the already-working skill/command surface; double-quoted shell $HOME references are untouched. (#3544)

View File

@@ -7952,8 +7952,20 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
content = content.replace(globalClaudeRegex, pathPrefix);
content = content.replace(globalClaudeHomeRegex, pathPrefix);
content = content.replace(localClaudeRegex, `./${dirName}/`);
content = content.replace(/~\/\.claude\b/g, pathPrefix.replace(/\/$/, ''));
content = content.replace(/\$HOME\/\.claude\b/g, pathPrefix.replace(/\/$/, ''));
// #3544 review (Finding 1 fallout): guarded with the SAME
// negative-lookahead convention already used at ~:2859-2860 below
// ("preserve .claude-plugin and .claudeignore"). A naive `\b` here
// is satisfied by ANY non-word character, including '-' — so for a
// --config-dir whose name EXTENDS '.claude' (e.g. '.claude-work',
// pathPrefix '$HOME/.claude-work/'), this pass re-matched the
// '$HOME/.claude' PREFIX of its own slash-form output (lines above)
// and re-appended the full prefix, corrupting every emitted path to
// '$HOME/.claude-work-work/...'. Harmless no-op for the literal
// default '.claude' (self-replace with an identical string), which
// is why this went undetected until a non-default config-dir name
// was exercised.
content = content.replace(/~\/\.claude(?![\w-])/g, pathPrefix.replace(/\/$/, ''));
content = content.replace(/\$HOME\/\.claude(?![\w-])/g, pathPrefix.replace(/\/$/, ''));
content = content.replace(/\.\/\.claude\b/g, `./${dirName}`);
content = content.replace(/~\/\.qwen\//g, pathPrefix);
content = content.replace(/\$HOME\/\.qwen\//g, pathPrefix);
@@ -7961,6 +7973,17 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
content = content.replace(/~\/\.hermes\//g, pathPrefix);
content = content.replace(/\$HOME\/\.hermes\//g, pathPrefix);
content = content.replace(/\.\/\.hermes\//g, `./${dirName}/`);
// #3544: restore @-file-reference lines to the tilde form Claude Code
// actually expands — the SAME correction #3133 already applies to
// skill/command bodies via _applyRuntimeRewrites's 'claude' case (see
// restoreClaudeGlobalAtRefTilde's doc comment in
// runtime-artifact-conversion.cts). This is the gsd-core/ spec-tree
// emit path, which never had it: every @~/.claude/gsd-core/… include
// in a global install's workflows/references tree silently resolved
// to nothing (54 includes across 22 files on a live install).
if (runtime === 'claude') {
content = runtimeArtifactConversion._restoreClaudeGlobalAtRefTilde(content, pathPrefix);
}
}
content = processAttribution(content, getCommitAttribution(runtime));

View File

@@ -2785,6 +2785,81 @@ function _stampNonClaudeRuntimeDefaults(content: string, runtime: string): strin
return content;
}
/**
* #3544 (extending #3133's fix): restore `@$HOME<suffix>` `@`-file-reference
* lines back to their tilde equivalent (`@~<suffix>`) in Claude-emitted
* content whose pathPrefix is the `$HOME` form. This is a NARROW,
* context-sensitive correction layered on top of the blanket `~/.claude/` /
* `$HOME/.claude/` -> pathPrefix substitution every Claude emit path
* applies: that blanket substitution MUST keep emitting `$HOME` for global
* installs — shell commands embedded in workflow/command bodies (e.g.
* `node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs"`) need it, since `~` does
* not expand inside double-quoted shell strings (#1284). But Claude Code's
* own `@`-import resolver does the opposite: it documents `~` expansion and
* does NOT expand `$HOME`. That is not merely undocumented — a controlled
* `/context` measurement showed an `@$HOME/…` import loading nothing (see
* .gsd/bug/fix-3544-home-expansion-spec-tree/10-diagnosis.md's ADDENDUM). No
* automated test can verify *resolution* inside a live Claude Code session
* (nothing in CI can spawn one and read `/context`); every test here — unit
* and spawned-installer alike — verifies only the emitted STRING takes the
* `~` form Claude Code documents as expanding. A single pathPrefix string
* cannot satisfy both the shell and the `@`-import consumer, so this runs as
* a second, `@`-anchored pass AFTER the blanket substitution.
*
* #3133 first applied this restore inline in `_applyRuntimeRewrites`'s
* `case 'claude'` below (the skill/command staging pipeline). #3544 found
* the identical defect in bin/install.js's `copyWithPathReplacement` — the
* `gsd-core/` spec-tree emit path, which never had the restore step, so
* every `@~/.claude/gsd-core/…` include in a global install's workflows/
* references tree silently resolved to nothing (54 includes across 22 files
* on a live install, per the diagnosis). Both call sites now share this one
* implementation instead of drifting independently (DEFECT.GENERATIVE-FIX).
*
* No-op unless `pathPrefix` is the `$HOME` form — local installs already
* bake an absolute, `@`-resolvable pathPrefix and are unaffected, as are
* every non-Claude runtime (never called for them).
*
* #3544 review (2nd pass): the first cut of this function hardcoded the
* literal `.claude/` segment, so it silently no-opped for any global install
* under a non-default `--config-dir` (e.g. `~/.claude-work`) — reproducing
* the exact defect #3544 fixes, just one directory name later. This ALSO
* corrects the same latent gap in #3133's original path, since both call
* sites share this one implementation. Fixed by deriving the rewrite from
* `pathPrefix` itself rather than a hardcoded directory name: the tilde
* equivalent of any `$HOME`-form prefix is `'~' + pathPrefix.slice(5)`
* (`'$HOME'.length === 5`), so the transform generalizes to any config-dir
* name with no runtime-specific literal.
*
* #3544 review (2nd pass), quote-awareness: the anchor is a negative
* lookbehind for a preceding quote character, NOT a line-start anchor —
* Claude Code documents `@`-references as valid "anywhere in your
* CLAUDE.md" (e.g. `See @README for project overview`), so anchoring to
* line-start would miss a legitimate mid-line reference. The lookbehind
* instead guards the one demonstrated false-positive: a quoted shell string
* like `echo "@$HOME/.claude/x"`, where rewriting `$HOME` to `~` inside
* double quotes reintroduces the #1284 failure mode (`~` does not expand in
* double-quoted shell). Deliberately NOT fenced-code-block aware (unlike
* `resolveSpecRootReference`'s `scanFencedBlocks` use above): this pass
* targets genuine `@`-import lines and inline shell references across the
* whole emitted corpus, and today there are zero occurrences anywhere in the
* tree of an `@$HOME<suffix>` sequence inside a fenced code block (the
* quote-guard already closes the one reachable false-positive class).
* Layering `scanFencedBlocks` on top would roughly double this function's
* size to guard an undemonstrated case — the opposite of the brief's
* "simpler, not more complex" direction. If a fenced example ever needs this
* literal sequence, add fence-awareness then, with a regression test proving
* the fence is real.
*
* @private — exported as `_restoreClaudeGlobalAtRefTilde` for tests and for
* bin/install.js's `copyWithPathReplacement`.
*/
function restoreClaudeGlobalAtRefTilde(content, pathPrefix) {
if (typeof pathPrefix !== 'string' || !pathPrefix.startsWith('$HOME')) return content;
const tildeEquivalent = '~' + pathPrefix.slice('$HOME'.length);
const atRefRe = new RegExp(`(?<!["'])@${escapeRegExp(pathPrefix)}`, 'g');
return content.replace(atRefRe, `@${tildeEquivalent}`);
}
/**
* Apply the per-runtime rewrite table to a single content string.
* Relocated from bin/install.js `_applyRuntimeRewrites`.
@@ -2916,18 +2991,10 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
content = content.replace(/~\/\.claude\//g, pathPrefix);
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
// #3133: Claude Code expands `~` and absolute paths in @-file references
// but NOT `$HOME`. computePathPrefix returns the $HOME/.claude/ form for
// global installs under $HOME (correct for double-quoted shell commands —
// `~` does not expand inside double quotes, causing MODULE_NOT_FOUND,
// #1284), so the substitutions above rewrite @~/.claude/… → @$HOME/.claude/…
// which silently resolves to nothing and leaves skills with an empty
// execution_context. Restore the tilde form Claude expands (the form the
// shipped tarball uses). Local installs use an absolute pathPrefix (already
// @-resolvable) and are unaffected — the guard fires only for the $HOME form.
if (pathPrefix.startsWith('$HOME')) {
content = content.replace(/@\$HOME\/\.claude\//g, '@~/.claude/');
}
// #3133 / #3544: restore @-file-reference lines to the tilde form
// Claude actually expands — see restoreClaudeGlobalAtRefTilde's doc
// comment above for why this must be a separate, @-anchored pass.
content = restoreClaudeGlobalAtRefTilde(content, pathPrefix);
content = processAttribution(content, attribution);
break;
@@ -3384,6 +3451,7 @@ export = {
applyAgentPathRewrites,
normalizeAgentBodyForRuntime,
_computePathPrefix: computePathPrefix,
_restoreClaudeGlobalAtRefTilde: restoreClaudeGlobalAtRefTilde,
_applyRuntimeRewrites,
_stampNonClaudeRuntimeDefaults,
// #2652: registry-resolved dispatch isolation, mirroring routeDispatchIsolation

View File

@@ -10,11 +10,8 @@
"gsd-core/references/planner-human-verify-mode.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/templates/README.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/templates/claude-md.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/templates/codebase/structure.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/workflows/execute-plan.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/workflows/help/modes/full.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/workflows/milestone-summary.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/workflows/profile-user.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/workflows/progress.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/workflows/quick.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",
"gsd-core/workflows/sketch-wrap-up.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').",

View File

@@ -1,15 +1,6 @@
{
"version": 1,
"paths": {
"skills/gsd-autonomous/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-execute-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-next/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-ns-manage/skills/stats/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
@@ -28,15 +19,6 @@
"skills/gsd-ns-workflow/skills/progress/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-plan-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-progress/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-stats/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd/gsd-ns-manage/skills/stats/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},

View File

@@ -0,0 +1,287 @@
{
"paths": {
"gsd-core/references/context-budget.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/edge-probe.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/honest-verifier.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/model-profile-resolution.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/planner-guidance.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/planner-mvp-mode.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/prohibition-probe.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/thinking-models-planning.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/verification-patterns.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/references/verifier-phase-gates.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/templates/codebase/structure.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/templates/phase-prompt.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/ai-integration-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/autonomous.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/discuss-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/discuss-phase/modes/power.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/eval-review.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/execute-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/execute-plan.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/explore.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/mvp-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/onboard.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/plan-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/plan-review-convergence.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/profile-user.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/resume-project.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/secure-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/sketch.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/spec-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/transition.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/ui-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/ui-review.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/undo.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/validate-phase.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/verify-work.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md": {
"reason": "#3544: the gsd-core/ spec-tree emit path now runs restoreClaudeGlobalAtRefTilde over @-file-reference lines, rewriting every @$HOME/gsd-core/... include to the @~/gsd-core/... tilde form Claude Code actually expands (verified: @$HOME references silently resolved to nothing on a live global install, 54 includes across 22 files). This is the same correction #3133 already applies to skill/command bodies via _applyRuntimeRewrites's 'claude' case; this fragment covers the gsd-core/ workflows, references, and templates tree, which never had it. bin/install.js's bare-form '~/.claude'/'$HOME/.claude' substitution regexes were also tightened from a trailing \\b to (?![\\w-]), so a --config-dir extending '.claude' (e.g. '.claude-work') no longer gets its own emitted prefix re-mangled; that fix does not itself change any byte in this fragment's paths under the default global install measured here, but is part of the same commit and is named for completeness."
},
"skills/gsd-add-tests/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-ai-integration-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-audit-fix/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-audit-milestone/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-audit-uat/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-autonomous/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-capture/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-cleanup/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-code-review/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-complete-milestone/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-config/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-debug/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-docs-update/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-eval-review/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-execute-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-explore/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-extract-learnings/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-fast/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-forensics/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-health/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-help/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-import/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-inbox/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-ingest-docs/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-manager/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-map-codebase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-milestone-summary/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-mvp-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-new-milestone/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-new-project/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-next/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-onboard/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-pause-work/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-plan-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-plan-review-convergence/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-pr-branch/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-profile-user/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-progress/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-quick/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-resume-work/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-review/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-secure-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-settings/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-ship/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-sketch/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-spec-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-spike/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-stats/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-thread/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-ui-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-ui-review/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-ultraplan-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-undo/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-update/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-validate-phase/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-verify-work/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
},
"skills/gsd-workspace/SKILL.md": {
"reason": "#3544: the gsd-core/ spec-tree tilde-restore fix (see the workflows/references/templates entries in this same fragment) also applies inside command bodies converted into Claude skills - this SKILL.md embeds a @$HOME/gsd-core/... include from its source command that now emits as @~/gsd-core/... so Claude Code actually expands it, matching the tilde form #3133 already normalized elsewhere in the skill body. The bin/install.js bare-form '~/.claude'/'$HOME/.claude' guard (\\b -> (?![\\w-])) shipped in the same commit but does not itself move this file's bytes under the default global install."
}
},
"version": 1
}

View File

@@ -549,3 +549,281 @@ describe('#3133: global Claude @-references resolve on tilde, not $HOME', () =>
assert.doesNotMatch(out, /@\$HOME/, `no @$HOME; got:\n${out}`);
});
});
// ────────────────────────────────────────────────────────────────────────
// #3544: `$HOME` does NOT expand in a Claude Code @-import (measured — see
// .gsd/bug/fix-3544-home-expansion-spec-tree/10-diagnosis.md's ADDENDUM).
// #3133 (above) already fixed this for the SKILL/command staging pipeline
// (_applyRuntimeRewrites's 'claude' case) by restoring @-anchored $HOME
// references to tilde AFTER the blanket $HOME substitution. #3544 found the
// identical defect in bin/install.js's copyWithPathReplacement — the
// gsd-core/ SPEC-TREE emit path — which never had that restore step: every
// `@~/.claude/gsd-core/…` include in a global install's workflows/references
// tree (e.g. gsd-core/workflows/plan-phase.md's own @-includes) silently
// resolved to nothing.
//
// The old test at the top of this file ('$HOME expands inside double-quoted
// shell commands') asserted only the raw computePathPrefix STRING, never
// that an @-reference actually resolves — which is exactly why the spec-tree
// defect survived undetected. That assertion is preserved above (unchanged:
// computePathPrefix's raw $HOME form is CORRECT and must stay — it is what
// keeps double-quoted shell commands working, #1284). What was missing is
// coverage of the @-anchored restore step. This section adds it, plus a
// real spawned-installer proof that the fix reaches the actual emit path
// (not just the pure function), plus negative-proof rows for OpenCode,
// local installs, and a second non-Claude global runtime (Cursor).
// ────────────────────────────────────────────────────────────────────────
describe('#3544: _restoreClaudeGlobalAtRefTilde (spec-tree @-ref restore, unit)', () => {
const { _restoreClaudeGlobalAtRefTilde } = require('../gsd-core/bin/lib/runtime-artifact-conversion.cjs');
test('restores an @$HOME/.claude/ reference to @~/.claude/ when pathPrefix is the $HOME form', () => {
const src = '@$HOME/.claude/gsd-core/references/ui-brand.md\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude/');
assert.strictEqual(out, '@~/.claude/gsd-core/references/ui-brand.md\n');
});
test('leaves a non-@-anchored $HOME/.claude/ shell reference untouched (#1284)', () => {
const src = 'node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" query state\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude/');
assert.strictEqual(out, src, 'a double-quoted shell $HOME reference must never be rewritten to ~ (breaks #1284)');
});
test('is a no-op when pathPrefix is an absolute (local-install) path', () => {
const src = '@$HOME/.claude/gsd-core/references/ui-brand.md\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '/abs/projects/foo/.claude/');
assert.strictEqual(out, src);
});
test('handles multiple @-references and preserves an interleaved shell reference', () => {
const src =
'@$HOME/.claude/gsd-core/references/a.md\n' +
'node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs"\n' +
'@$HOME/.claude/gsd-core/references/b.md\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude/');
assert.strictEqual(
out,
'@~/.claude/gsd-core/references/a.md\n' +
'node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs"\n' +
'@~/.claude/gsd-core/references/b.md\n',
);
});
// #3544 review (Finding 1): a custom --config-dir under $HOME produces a
// pathPrefix like '$HOME/.claude-work/' — the directory name is NOT
// '.claude'. The restore must derive the tilde form from pathPrefix itself
// rather than a hardcoded '.claude' literal, or it silently no-ops for any
// non-default config-dir name (reproducing the exact defect #3544 fixes).
test('generalizes to a non-default config-dir name (not hardcoded to .claude)', () => {
const src = '@$HOME/.claude-work/gsd-core/workflows/plan-phase.md\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude-work/');
assert.strictEqual(out, '@~/.claude-work/gsd-core/workflows/plan-phase.md\n');
});
// #3544 review (Finding 2): quote-aware, not line-start-anchored. A
// double-quoted or single-quoted `@$HOME/...` sequence must be left alone
// (rewriting $HOME -> ~ inside a quoted shell string reintroduces #1284 —
// ~ does not expand in double quotes). A bare line-start `@$HOME/...` and a
// legitimate MID-LINE `@`-reference (Claude Code documents @-references as
// valid "anywhere in your CLAUDE.md") must both still be rewritten.
test('leaves a double-quoted @$HOME/.claude/ sequence untouched (quote-aware)', () => {
const src = 'echo "@$HOME/.claude/x"\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude/');
assert.strictEqual(out, src, 'a double-quoted @$HOME sequence must not be rewritten');
});
test('leaves a single-quoted @$HOME/.claude/ sequence untouched (quote-aware)', () => {
const src = "'@$HOME/.claude/x'\n";
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude/');
assert.strictEqual(out, src, 'a single-quoted @$HOME sequence must not be rewritten');
});
test('rewrites a bare line-start @$HOME/.claude/ reference', () => {
const src = '@$HOME/.claude/x\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude/');
assert.strictEqual(out, '@~/.claude/x\n');
});
test('rewrites a legitimate mid-line @$HOME/.claude/ reference (not line-start-anchored)', () => {
const src = 'See @$HOME/.claude/x for details\n';
const out = _restoreClaudeGlobalAtRefTilde(src, '$HOME/.claude/');
assert.strictEqual(out, 'See @~/.claude/x for details\n');
});
});
// Verification boundary (#3544): this suite proves the emitted @-line takes
// the `~` STRING form Claude Code documents as expanding. It cannot prove
// the host actually resolves it — no automated test can spawn a live Claude
// Code session and read `/context` in CI. Read a green run here as "the
// installer emits the documented form", not as "the include loads". See
// restoreClaudeGlobalAtRefTilde's doc comment (runtime-artifact-conversion.cts)
// for the controlled measurement that established the documented form is the
// one that actually resolves.
describe('#3544: spawned installer — gsd-core/ spec tree @-refs resolve on tilde', () => {
const { before, after } = require('node:test');
const { cleanup } = require('./helpers.cjs');
const { runNode } = require('./helpers/process-seam.cjs');
const { INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
const { INSTALL_SCRIPT, installerEnv } = require('./helpers/install-shared.cjs');
const { splitLines } = require('../gsd-core/bin/lib/text-lines.cjs');
const sandboxes = [];
function makeSandbox(prefix) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `gsd-3544-${prefix}-`));
sandboxes.push(dir);
return dir;
}
// No --config-dir: install.js must resolve the DEFAULT <HOME>/.claude (or
// runtime equivalent) under the sandboxed HOME, so the emitted tree has the
// real `~/.claude/gsd-core/…` shape the diagnosis measured — a --config-dir
// run pins configDir to the sandbox root itself (target === home), which
// never reproduces that layout.
function spawnInstall(args, home) {
return runNode([INSTALL_SCRIPT, ...args], {
cwd: home,
env: installerEnv({ HOME: home, USERPROFILE: home }),
timeoutMs: INSTALL_TIMEOUT_MS,
});
}
function collectAtLines(rootDir) {
const out = [];
const walk = (dir) => {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walk(full);
else if (entry.name.endsWith('.md')) {
const content = fs.readFileSync(full, 'utf8');
for (const line of splitLines(content)) {
if (line.startsWith('@')) out.push({ file: full, line });
}
}
}
};
if (fs.existsSync(rootDir)) walk(rootDir);
return out;
}
let claudeGlobalHome, claudeLocalHome, opencodeGlobalHome, cursorGlobalHome, claudeConfigDirHome, claudeConfigDirTarget;
before(() => {
claudeGlobalHome = makeSandbox('claude-global');
const g = spawnInstall(['--claude', '--global'], claudeGlobalHome);
assert.strictEqual(g.exitCode, 0, `claude --global install failed:\n${g.stdout}\n${g.stderr}`);
claudeLocalHome = makeSandbox('claude-local');
const l = spawnInstall(['--claude', '--local'], claudeLocalHome);
assert.strictEqual(l.exitCode, 0, `claude --local install failed:\n${l.stdout}\n${l.stderr}`);
opencodeGlobalHome = makeSandbox('opencode-global');
const o = spawnInstall(['--opencode', '--global'], opencodeGlobalHome);
assert.strictEqual(o.exitCode, 0, `opencode --global install failed:\n${o.stdout}\n${o.stderr}`);
cursorGlobalHome = makeSandbox('cursor-global');
const c = spawnInstall(['--cursor', '--global'], cursorGlobalHome);
assert.strictEqual(c.exitCode, 0, `cursor --global install failed:\n${c.stdout}\n${c.stderr}`);
// #3544 review (Finding 1): a custom --config-dir name under $HOME
// (i.e. NOT the default .claude) — the target must be a subdirectory of
// HOME (not HOME itself) so computePathPrefix takes the $HOME-shorthand
// branch with a non-'.claude' suffix, the exact precondition the
// hardcoded-'.claude' bug required.
claudeConfigDirHome = makeSandbox('claude-config-dir-home');
claudeConfigDirTarget = path.join(claudeConfigDirHome, '.claude-work');
const cd = spawnInstall(['--claude', '--global', '--config-dir', claudeConfigDirTarget], claudeConfigDirHome);
assert.strictEqual(cd.exitCode, 0, `claude --global --config-dir install failed:\n${cd.stdout}\n${cd.stderr}`);
});
after(() => {
for (const dir of sandboxes) cleanup(dir);
});
test('claude --global: gsd-core/workflows/plan-phase.md @-lines use ~/, never @$HOME', () => {
const planPhase = path.join(claudeGlobalHome, '.claude', 'gsd-core', 'workflows', 'plan-phase.md');
assert.ok(fs.existsSync(planPhase), `expected ${planPhase} to exist`);
const content = fs.readFileSync(planPhase, 'utf8');
const atLines = splitLines(content).filter((l) => l.startsWith('@'));
assert.ok(atLines.length > 0, 'expected plan-phase.md to carry at least one @-line');
for (const line of atLines) {
assert.ok(!/^@\$HOME/.test(line), `plan-phase.md @-line must not use @$HOME: ${line}`);
}
assert.ok(
atLines.some((l) => l.startsWith('@~/')),
`expected at least one @~/ line, got: ${JSON.stringify(atLines)}`,
);
});
test('claude --global: zero ^@$HOME lines remain anywhere under the emitted gsd-core/ tree', () => {
const gsdCoreDir = path.join(claudeGlobalHome, '.claude', 'gsd-core');
const homeLines = collectAtLines(gsdCoreDir).filter(({ line }) => /^@\$HOME/.test(line));
assert.deepStrictEqual(homeLines, [], `found @$HOME lines: ${JSON.stringify(homeLines)}`);
});
// #3544 review (Finding 1): a real install under a non-default --config-dir
// name reproduces the exact defect #3544 fixes if the restore is hardcoded
// to '.claude/'. This must FAIL against the pre-fix restoreClaudeGlobalAtRefTilde.
test('claude --global --config-dir <custom>: zero @$HOME lines remain, and @~/<custom>/ appears', () => {
const gsdCoreDir = path.join(claudeConfigDirTarget, 'gsd-core');
assert.ok(fs.existsSync(gsdCoreDir), `expected ${gsdCoreDir} to exist`);
const homeLines = collectAtLines(gsdCoreDir).filter(({ line }) => /^@\$HOME/.test(line));
assert.deepStrictEqual(homeLines, [], `found @$HOME lines under a custom --config-dir: ${JSON.stringify(homeLines)}`);
const tildeLines = collectAtLines(gsdCoreDir).filter(({ line }) => line.startsWith('@~/.claude-work/'));
assert.ok(
tildeLines.length > 0,
`expected at least one @~/.claude-work/ line under a custom --config-dir, got: ${JSON.stringify(collectAtLines(gsdCoreDir))}`,
);
});
test('claude --global: double-quoted shell $HOME references are preserved (#1284)', () => {
// At least one emitted file must still carry a double-quoted
// "$HOME/.claude/" shell reference — proving the restore step did NOT
// blanket-convert every $HOME occurrence, only @-anchored ones.
const gsdCoreDir = path.join(claudeGlobalHome, '.claude', 'gsd-core');
let sawShellHome = false;
const walk = (dir) => {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walk(full);
else if (entry.name.endsWith('.md') && fs.readFileSync(full, 'utf8').includes('"$HOME/.claude/')) {
sawShellHome = true;
}
}
};
walk(gsdCoreDir);
assert.ok(sawShellHome, 'expected at least one emitted file to preserve a "$HOME/.claude/ shell reference');
});
test('claude --local: pathPrefix is absolute — no @$HOME or bare @~ leak (negative proof)', () => {
const gsdCoreDir = path.join(claudeLocalHome, '.claude', 'gsd-core');
assert.ok(fs.existsSync(gsdCoreDir), `expected ${gsdCoreDir} to exist`);
const badLines = collectAtLines(gsdCoreDir).filter(
({ line }) => /^@\$HOME/.test(line) || /^@~\//.test(line),
);
assert.deepStrictEqual(badLines, [], `local install must not emit @$HOME or @~/: ${JSON.stringify(badLines)}`);
});
test('opencode --global: unaffected — never emits an @~/.claude/ line (negative proof)', () => {
const gsdCoreDir = path.join(opencodeGlobalHome, '.config', 'opencode', 'gsd-core');
assert.ok(fs.existsSync(gsdCoreDir), `expected ${gsdCoreDir} to exist`);
const leaked = collectAtLines(gsdCoreDir).filter(({ line }) => line.startsWith('@~/.claude/'));
assert.deepStrictEqual(
leaked, [],
`opencode must never emit a @~/.claude/ line (claude-only restore leaked): ${JSON.stringify(leaked)}`,
);
});
test('cursor --global: unaffected — still emits @$HOME/.cursor/ (unrestored), never @~/.claude/ (negative proof)', () => {
const gsdCoreDir = path.join(cursorGlobalHome, '.cursor', 'gsd-core');
assert.ok(fs.existsSync(gsdCoreDir), `expected ${gsdCoreDir} to exist`);
const atLines = collectAtLines(gsdCoreDir);
const leaked = atLines.filter(({ line }) => line.startsWith('@~/.claude/'));
assert.deepStrictEqual(
leaked, [],
`cursor must never emit a @~/.claude/ line (claude-only restore leaked): ${JSON.stringify(leaked)}`,
);
assert.ok(
atLines.some(({ line }) => line.startsWith('@$HOME/.cursor/')),
`expected cursor's own $HOME-form @-refs to remain unrestored, got: ${JSON.stringify(atLines)}`,
);
});
});