diff --git a/scripts/resolvers/runtime-root.ts b/scripts/resolvers/runtime-root.ts index 9617e606b..ff0044fc7 100644 --- a/scripts/resolvers/runtime-root.ts +++ b/scripts/resolvers/runtime-root.ts @@ -70,7 +70,7 @@ export function skillStartLines(ctx: TemplateContext): { lookup: string; command } return { lookup: [ - `[ -d "\${GSTACK_ROOT:-/-}/bin" ]&&[ -d "$GSTACK_ROOT/lib" ]||GSTACK_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)/${getHostConfig(ctx.host).localSkillRoot}`, + `[ -d "\${GSTACK_ROOT:-/-}/lib" ]&&[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)/${getHostConfig(ctx.host).localSkillRoot}`, `[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=${globalRoot(ctx)}`, `[ -d "$GSTACK_ROOT/bin" ]||echo "gstack: no install found (tried $GSTACK_ROOT). ${fix}">&2`, ].join('\n'), diff --git a/test/fixtures/golden/agy-ship-SKILL.md b/test/fixtures/golden/agy-ship-SKILL.md index b3aa51ef4..1f64ff199 100644 --- a/test/fixtures/golden/agy-ship-SKILL.md +++ b/test/fixtures/golden/agy-ship-SKILL.md @@ -17,9 +17,10 @@ This skill follows gstack shared preamble `6872f1ec4eb9` (AskUserQuestion format ## Preamble (run first) ```bash -[ -d "${GSTACK_ROOT:-/-}/bin" ]&&[ -d "$GSTACK_ROOT/lib" ]||{ _r=$(git rev-parse --show-toplevel 2>/dev/null)/.agents/skills/gstack;[ -d "$_r/bin" ]||_r=~/.gemini/antigravity-cli/skills/gstack;[ -d "$_r/bin" ]||{ echo "gstack: no install found (tried $_r). Fix: ./setup --host agy from your gstack checkout; ./setup --status shows it.">&2;exit 1;};GSTACK_ROOT=$_r;} -GSTACK_BIN=$GSTACK_ROOT/bin -"$GSTACK_BIN/gstack-skill-start" --skill "ship" --model "gemini" +[ -d "${GSTACK_ROOT:-/-}/lib" ]&&[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)/.agents/skills/gstack +[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=~/.gemini/antigravity-cli/skills/gstack +[ -d "$GSTACK_ROOT/bin" ]||echo "gstack: no install found (tried $GSTACK_ROOT). Fix: ./setup --host agy from your gstack checkout; ./setup --status shows it.">&2 +"$GSTACK_ROOT/bin/gstack-skill-start" --skill "ship" --model "gemini" ``` **Antigravity tool names:** `AskUserQuestion` means your `ask_question` tool (options as choices); there is no `mcp__*__AskUserQuestion` variant. The Bash tool means `run_command`, the Read tool `view_file`, the Write tool `write_to_file`, the Edit tool `replace_file_content` (`multi_replace_file_content` for several edits in one file), Grep `grep_search`, Glob `find_by_name`, and the Agent tool `invoke_subagent`. There is no Skill tool: load a skill by reading its SKILL.md with `view_file`. If a step says to call `ExitPlanMode`, tell the user the plan is ready and wait. `view_file` can return only part of a long file: when a SKILL.md or a file it tells you to read ends before its last line, read the remaining line ranges before acting on it. diff --git a/test/fixtures/golden/codex-ship-SKILL.md b/test/fixtures/golden/codex-ship-SKILL.md index e3b16338d..019c9e671 100644 --- a/test/fixtures/golden/codex-ship-SKILL.md +++ b/test/fixtures/golden/codex-ship-SKILL.md @@ -17,9 +17,10 @@ This skill follows gstack shared preamble `2af24c2d75e4` (AskUserQuestion format ## Preamble (run first) ```bash -[ -d "${GSTACK_ROOT:-/-}/bin" ]&&[ -d "$GSTACK_ROOT/lib" ]||{ _r=$(git rev-parse --show-toplevel 2>/dev/null)/.agents/skills/gstack;[ -d "$_r/bin" ]||_r=${CODEX_HOME:-~/.codex}/skills/gstack;[ -d "$_r/bin" ]||{ echo "gstack: no install found (tried $_r). Fix: ./setup --host codex from your gstack checkout; ./setup --status shows it.">&2;exit 1;};GSTACK_ROOT=$_r;} -GSTACK_BIN=$GSTACK_ROOT/bin -"$GSTACK_BIN/gstack-skill-start" --skill "ship" --model "gpt" +[ -d "${GSTACK_ROOT:-/-}/lib" ]&&[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)/.agents/skills/gstack +[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=${CODEX_HOME:-~/.codex}/skills/gstack +[ -d "$GSTACK_ROOT/bin" ]||echo "gstack: no install found (tried $GSTACK_ROOT). Fix: ./setup --host codex from your gstack checkout; ./setup --status shows it.">&2 +"$GSTACK_ROOT/bin/gstack-skill-start" --skill "ship" --model "gpt" ``` Read the echoed `KEY: value` STATUS lines — they drive every preamble rule diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md index 148a7b6fb..981464983 100644 --- a/test/fixtures/golden/factory-ship-SKILL.md +++ b/test/fixtures/golden/factory-ship-SKILL.md @@ -19,9 +19,10 @@ This skill follows gstack shared preamble `99cd6cb5d373` (AskUserQuestion format ## Preamble (run first) ```bash -[ -d "${GSTACK_ROOT:-/-}/bin" ]&&[ -d "$GSTACK_ROOT/lib" ]||{ _r=$(git rev-parse --show-toplevel 2>/dev/null)/.factory/skills/gstack;[ -d "$_r/bin" ]||_r=~/.factory/skills/gstack;[ -d "$_r/bin" ]||{ echo "gstack: no install found (tried $_r). Fix: ./setup --host factory from your gstack checkout; ./setup --status shows it.">&2;exit 1;};GSTACK_ROOT=$_r;} -GSTACK_BIN=$GSTACK_ROOT/bin -"$GSTACK_BIN/gstack-skill-start" --skill "ship" --model "claude" +[ -d "${GSTACK_ROOT:-/-}/lib" ]&&[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)/.factory/skills/gstack +[ -d "$GSTACK_ROOT/bin" ]||GSTACK_ROOT=~/.factory/skills/gstack +[ -d "$GSTACK_ROOT/bin" ]||echo "gstack: no install found (tried $GSTACK_ROOT). Fix: ./setup --host factory from your gstack checkout; ./setup --status shows it.">&2 +"$GSTACK_ROOT/bin/gstack-skill-start" --skill "ship" --model "claude" ``` Read the echoed `KEY: value` STATUS lines — they drive every preamble rule diff --git a/test/fixtures/skill-md-size-allowlist.json b/test/fixtures/skill-md-size-allowlist.json index 45435e0a9..db541ccaf 100644 --- a/test/fixtures/skill-md-size-allowlist.json +++ b/test/fixtures/skill-md-size-allowlist.json @@ -2,56 +2,56 @@ "_comment": "Generated SKILL.md files over the limit, pinned at their exact character count (#3199). test/skill-md-size-guard.test.ts fails when a pinned skill grows past its pin or shrinks below it: lower the pin when a skill shrinks and delete it once the skill is within the limit. Raising a pin is an owner decision. The shared-preamble hoist (GSTA-96) moved every tier 2+ skill's shared preamble into sections/preamble.md; the pins below are what remains.", "limit": 100000, "pins": { - "agy/gstack-autoplan": 109666, - "agy/gstack-plan-design-review": 109116, - "agy/gstack-plan-devex-review": 114958, - "agy/gstack-plan-eng-review": 143590, - "agy/gstack-review": 104276, - "codex/gstack-autoplan": 108409, - "codex/gstack-plan-design-review": 110473, - "codex/gstack-plan-devex-review": 116466, - "codex/gstack-plan-eng-review": 144755, - "codex/gstack-review": 103799, - "copilot/gstack-autoplan": 109109, - "copilot/gstack-plan-design-review": 109382, - "copilot/gstack-plan-devex-review": 114420, - "copilot/gstack-plan-eng-review": 143755, - "copilot/gstack-review": 103857, - "cursor/gstack-autoplan": 108341, - "cursor/gstack-plan-design-review": 107924, - "cursor/gstack-plan-devex-review": 113690, - "cursor/gstack-plan-eng-review": 142345, - "cursor/gstack-review": 122147, - "factory/gstack-autoplan": 110619, - "factory/gstack-plan-design-review": 111022, - "factory/gstack-plan-devex-review": 117053, - "factory/gstack-plan-eng-review": 145453, - "factory/gstack-review": 125920, - "gbrain/gstack-autoplan": 108748, - "gbrain/gstack-plan-eng-review": 124972, - "gemini/gstack-autoplan": 108899, - "gemini/gstack-plan-design-review": 109210, - "gemini/gstack-plan-devex-review": 114248, - "gemini/gstack-plan-eng-review": 143588, - "gemini/gstack-review": 103679, - "hermes/gstack-autoplan": 108751, - "hermes/gstack-plan-eng-review": 125008, - "kiro/gstack-autoplan": 108115, - "kiro/gstack-plan-design-review": 107770, - "kiro/gstack-plan-devex-review": 113542, - "kiro/gstack-plan-eng-review": 142207, - "kiro/gstack-review": 121971, - "openclaw/gstack-autoplan": 108571, - "openclaw/gstack-plan-eng-review": 123487, - "opencode/gstack-autoplan": 109090, - "opencode/gstack-plan-design-review": 109238, - "opencode/gstack-plan-devex-review": 114298, - "opencode/gstack-plan-eng-review": 143614, - "opencode/gstack-review": 122769, - "slate/gstack-autoplan": 108228, - "slate/gstack-plan-design-review": 107847, - "slate/gstack-plan-devex-review": 113616, - "slate/gstack-plan-eng-review": 142276, - "slate/gstack-review": 122059 + "agy/gstack-autoplan": 109657, + "agy/gstack-plan-design-review": 109107, + "agy/gstack-plan-devex-review": 114949, + "agy/gstack-plan-eng-review": 143581, + "agy/gstack-review": 104267, + "codex/gstack-autoplan": 108400, + "codex/gstack-plan-design-review": 110464, + "codex/gstack-plan-devex-review": 116457, + "codex/gstack-plan-eng-review": 144746, + "codex/gstack-review": 103790, + "copilot/gstack-autoplan": 109100, + "copilot/gstack-plan-design-review": 109373, + "copilot/gstack-plan-devex-review": 114411, + "copilot/gstack-plan-eng-review": 143746, + "copilot/gstack-review": 103848, + "cursor/gstack-autoplan": 108332, + "cursor/gstack-plan-design-review": 107915, + "cursor/gstack-plan-devex-review": 113681, + "cursor/gstack-plan-eng-review": 142336, + "cursor/gstack-review": 122138, + "factory/gstack-autoplan": 110610, + "factory/gstack-plan-design-review": 111013, + "factory/gstack-plan-devex-review": 117044, + "factory/gstack-plan-eng-review": 145444, + "factory/gstack-review": 125911, + "gbrain/gstack-autoplan": 108739, + "gbrain/gstack-plan-eng-review": 124963, + "gemini/gstack-autoplan": 108890, + "gemini/gstack-plan-design-review": 109201, + "gemini/gstack-plan-devex-review": 114239, + "gemini/gstack-plan-eng-review": 143579, + "gemini/gstack-review": 103670, + "hermes/gstack-autoplan": 108742, + "hermes/gstack-plan-eng-review": 124999, + "kiro/gstack-autoplan": 108106, + "kiro/gstack-plan-design-review": 107761, + "kiro/gstack-plan-devex-review": 113533, + "kiro/gstack-plan-eng-review": 142198, + "kiro/gstack-review": 121962, + "openclaw/gstack-autoplan": 108562, + "openclaw/gstack-plan-eng-review": 123478, + "opencode/gstack-autoplan": 109081, + "opencode/gstack-plan-design-review": 109229, + "opencode/gstack-plan-devex-review": 114289, + "opencode/gstack-plan-eng-review": 143605, + "opencode/gstack-review": 122760, + "slate/gstack-autoplan": 108219, + "slate/gstack-plan-design-review": 107838, + "slate/gstack-plan-devex-review": 113607, + "slate/gstack-plan-eng-review": 142267, + "slate/gstack-review": 122050 } } diff --git a/test/gstack-skill-start.test.ts b/test/gstack-skill-start.test.ts index 5dca2124f..0c57213d8 100644 --- a/test/gstack-skill-start.test.ts +++ b/test/gstack-skill-start.test.ts @@ -118,7 +118,8 @@ describe('gstack-skill-start contract', () => { // Worktree-isolated Claude Code sessions refuse a start command named by a // variable, a `[ -x ] ||` fallback, or a trailing `|| echo` (reproduced // with the pinned CLI). The Claude render is the literal install path; - // env-var hosts reach the script through $GSTACK_BIN. A missing helper is + // checked-in env-var host renders reach it through $GSTACK_ROOT/bin (an + // install-root render names the literal path, GST-882). A missing helper is // covered by the degraded-mode prose, not a shell fallback. const fence = (text: string) => { const at = text.search(/^## Preamble \((?:run first|after scope gate)\)/m); @@ -130,7 +131,7 @@ describe('gstack-skill-start contract', () => { } for (const host of ['codex', 'gbrain']) { const lines = fence(generatePreamble({ skillName: 'ship', tmplPath: 'ship/SKILL.md.tmpl', host, paths: HOST_PATHS[host], preambleTier: 4 } as TemplateContext)).split('\n'); - expect(lines.at(-1)).toMatch(/^"\$GSTACK_BIN\/gstack-skill-start" --skill "ship" --model "[^"]+"( --brain-health)?$/); + expect(lines.at(-1)).toMatch(/^"\$GSTACK_ROOT\/bin\/gstack-skill-start" --skill "ship" --model "[^"]+"( --brain-health)?$/); expect(lines.join('\n')).not.toMatch(/_SS|\$PPID|\|\| echo|\[ -x/); } }); diff --git a/test/skill-start-plain.test.ts b/test/skill-start-plain.test.ts index 07f1b56a6..753b2c663 100644 --- a/test/skill-start-plain.test.ts +++ b/test/skill-start-plain.test.ts @@ -23,7 +23,7 @@ const ctx = (host: string, installRoot: string | null) => const startFence = (c: TemplateContext) => insertRuntimePreludes(generatePreambleBash(c), c).match(/```bash\n([\s\S]*?)\n```/)![1]; const GROUPED = /(?:^|[;&|]\s*)\{\s|exit 1;\s*\}/m; const sh = (body: string, env: Record) => - spawnSync('bash', ['-c', body], { cwd: tmp, encoding: 'utf8', timeout: 10_000, env: { PATH: '/usr/bin:/bin', ...env } }); + spawnSync('bash', ['-uc', body], { cwd: tmp, encoding: 'utf8', timeout: 10_000, env: { PATH: '/usr/bin:/bin', ...env } }); function stubStart(root: string) { fs.mkdirSync(path.join(root, 'bin'), { recursive: true }); fs.mkdirSync(path.join(root, 'lib'), { recursive: true });