diff --git a/autoplan/SKILL.md b/autoplan/SKILL.md index cd9f81d1..10ba3522 100644 --- a/autoplan/SKILL.md +++ b/autoplan/SKILL.md @@ -416,7 +416,7 @@ State what you examined and why nothing was flagged (1-2 sentences minimum). Before doing anything, save the plan file's current state to an external file: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-') DATETIME=$(date +%Y%m%d-%H%M%S) echo "RESTORE_PATH=$HOME/.gstack/projects/$SLUG/${BRANCH}-autoplan-restore-${DATETIME}.md" diff --git a/autoplan/SKILL.md.tmpl b/autoplan/SKILL.md.tmpl index 6c844d67..2213c8b9 100644 --- a/autoplan/SKILL.md.tmpl +++ b/autoplan/SKILL.md.tmpl @@ -107,7 +107,7 @@ State what you examined and why nothing was flagged (1-2 sentences minimum). Before doing anything, save the plan file's current state to an external file: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +{{SLUG_SETUP}} BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-') DATETIME=$(date +%Y%m%d-%H%M%S) echo "RESTORE_PATH=$HOME/.gstack/projects/$SLUG/${BRANCH}-autoplan-restore-${DATETIME}.md" diff --git a/benchmark/SKILL.md b/benchmark/SKILL.md index ac12a280..9e1a6bc3 100644 --- a/benchmark/SKILL.md +++ b/benchmark/SKILL.md @@ -333,7 +333,7 @@ When the user types `/benchmark`, run this skill. ### Phase 1: Setup ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown") +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown")" mkdir -p .gstack/benchmark-reports mkdir -p .gstack/benchmark-reports/baselines ``` diff --git a/benchmark/SKILL.md.tmpl b/benchmark/SKILL.md.tmpl index d0c0ecbc..f72b5a93 100644 --- a/benchmark/SKILL.md.tmpl +++ b/benchmark/SKILL.md.tmpl @@ -41,7 +41,7 @@ When the user types `/benchmark`, run this skill. ### Phase 1: Setup ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown") +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown")" mkdir -p .gstack/benchmark-reports mkdir -p .gstack/benchmark-reports/baselines ``` diff --git a/bin/gstack-review-log b/bin/gstack-review-log index 816cfa46..d7235bc3 100755 --- a/bin/gstack-review-log +++ b/bin/gstack-review-log @@ -3,7 +3,7 @@ # Usage: gstack-review-log '{"skill":"...","timestamp":"...","status":"..."}' set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -source <("$SCRIPT_DIR/gstack-slug" 2>/dev/null) +eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)" GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}" mkdir -p "$GSTACK_HOME/projects/$SLUG" echo "$1" >> "$GSTACK_HOME/projects/$SLUG/$BRANCH-reviews.jsonl" diff --git a/bin/gstack-review-read b/bin/gstack-review-read index 578d7480..ccf1d70f 100755 --- a/bin/gstack-review-read +++ b/bin/gstack-review-read @@ -3,7 +3,7 @@ # Usage: gstack-review-read set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -source <("$SCRIPT_DIR/gstack-slug" 2>/dev/null) +eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)" GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}" cat "$GSTACK_HOME/projects/$SLUG/$BRANCH-reviews.jsonl" 2>/dev/null || echo "NO_REVIEWS" echo "---CONFIG---" diff --git a/bin/gstack-slug b/bin/gstack-slug index 3ad30381..a7ae7883 100755 --- a/bin/gstack-slug +++ b/bin/gstack-slug @@ -1,6 +1,6 @@ #!/usr/bin/env bash # gstack-slug — output project slug and sanitized branch name -# Usage: source <(gstack-slug) → sets SLUG and BRANCH variables +# Usage: eval "$(gstack-slug)" → sets SLUG and BRANCH variables # Or: gstack-slug → prints SLUG=... and BRANCH=... lines # # Security: output is sanitized to [a-zA-Z0-9._-] only, preventing diff --git a/canary/SKILL.md b/canary/SKILL.md index c71d51a9..2b2bb403 100644 --- a/canary/SKILL.md +++ b/canary/SKILL.md @@ -351,7 +351,7 @@ When the user types `/canary`, run this skill. ### Phase 1: Setup ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown") +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown")" mkdir -p .gstack/canary-reports mkdir -p .gstack/canary-reports/baselines mkdir -p .gstack/canary-reports/screenshots @@ -501,7 +501,7 @@ Save report to `.gstack/canary-reports/{date}-canary.md` and `.gstack/canary-rep Log the result for the review dashboard: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" mkdir -p ~/.gstack/projects/$SLUG ``` diff --git a/canary/SKILL.md.tmpl b/canary/SKILL.md.tmpl index d0ddadfe..eca0fd1f 100644 --- a/canary/SKILL.md.tmpl +++ b/canary/SKILL.md.tmpl @@ -42,7 +42,7 @@ When the user types `/canary`, run this skill. ### Phase 1: Setup ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown") +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown")" mkdir -p .gstack/canary-reports mkdir -p .gstack/canary-reports/baselines mkdir -p .gstack/canary-reports/screenshots @@ -192,7 +192,7 @@ Save report to `.gstack/canary-reports/{date}-canary.md` and `.gstack/canary-rep Log the result for the review dashboard: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +{{SLUG_EVAL}} mkdir -p ~/.gstack/projects/$SLUG ``` diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index d4cf72b2..3e5b1889 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -327,7 +327,7 @@ ls src/ app/ pages/ components/ 2>/dev/null | head -30 Look for office-hours output: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" ls ~/.gstack/projects/$SLUG/*office-hours* 2>/dev/null | head -5 ls .context/*office-hours* .context/attachments/*office-hours* 2>/dev/null | head -5 ``` diff --git a/design-consultation/SKILL.md.tmpl b/design-consultation/SKILL.md.tmpl index 87c191df..d8604ceb 100644 --- a/design-consultation/SKILL.md.tmpl +++ b/design-consultation/SKILL.md.tmpl @@ -52,7 +52,7 @@ ls src/ app/ pages/ components/ 2>/dev/null | head -30 Look for office-hours output: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +{{SLUG_EVAL}} ls ~/.gstack/projects/$SLUG/*office-hours* 2>/dev/null | head -5 ls .context/*office-hours* .context/attachments/*office-hours* 2>/dev/null | head -5 ``` diff --git a/design-review/SKILL.md b/design-review/SKILL.md index ae8fa1bd..a1abf723 100644 --- a/design-review/SKILL.md +++ b/design-review/SKILL.md @@ -774,7 +774,7 @@ Compare screenshots and observations across pages for: **Project-scoped:** ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG ``` Write to: `~/.gstack/projects/{slug}/{user}-{branch}-design-audit-{datetime}.md` @@ -1142,7 +1142,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG ``` Write to `~/.gstack/projects/{slug}/{user}-{branch}-design-audit-{datetime}.md` diff --git a/design-review/SKILL.md.tmpl b/design-review/SKILL.md.tmpl index e54332fa..636307e8 100644 --- a/design-review/SKILL.md.tmpl +++ b/design-review/SKILL.md.tmpl @@ -224,7 +224,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +{{SLUG_SETUP}} ``` Write to `~/.gstack/projects/{slug}/{user}-{branch}-design-audit-{datetime}.md` diff --git a/land-and-deploy/SKILL.md b/land-and-deploy/SKILL.md index 25bc5e54..c89e2de0 100644 --- a/land-and-deploy/SKILL.md +++ b/land-and-deploy/SKILL.md @@ -883,7 +883,7 @@ Save report to `.gstack/deploy-reports/{date}-pr{number}-deploy.md`. Log to the review dashboard: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" mkdir -p ~/.gstack/projects/$SLUG ``` diff --git a/land-and-deploy/SKILL.md.tmpl b/land-and-deploy/SKILL.md.tmpl index 0e84d859..af902b9b 100644 --- a/land-and-deploy/SKILL.md.tmpl +++ b/land-and-deploy/SKILL.md.tmpl @@ -542,7 +542,7 @@ Save report to `.gstack/deploy-reports/{date}-pr{number}-deploy.md`. Log to the review dashboard: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +{{SLUG_EVAL}} mkdir -p ~/.gstack/projects/$SLUG ``` diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index ab69f1b6..3755ef27 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -331,7 +331,7 @@ You are a **YC office hours partner**. Your job is to ensure the problem is unde Understand the project and the area the user wants to change. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" ``` 1. Read `CLAUDE.md`, `TODOS.md` (if they exist). @@ -784,7 +784,7 @@ Count the signals. You'll use this count in Phase 6 to determine which tier of c Write the design document to the project directory. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) ``` diff --git a/office-hours/SKILL.md.tmpl b/office-hours/SKILL.md.tmpl index 33d673c1..72b43af3 100644 --- a/office-hours/SKILL.md.tmpl +++ b/office-hours/SKILL.md.tmpl @@ -39,7 +39,7 @@ You are a **YC office hours partner**. Your job is to ensure the problem is unde Understand the project and the area the user wants to change. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +{{SLUG_EVAL}} ``` 1. Read `CLAUDE.md`, `TODOS.md` (if they exist). @@ -407,7 +407,7 @@ Count the signals. You'll use this count in Phase 6 to determine which tier of c Write the design document to the project directory. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +{{SLUG_SETUP}} USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) ``` diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index 1050ed4f..a9f4f671 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -607,7 +607,7 @@ Rules: After the opt-in/cherry-pick ceremony, write the plan to disk so the vision and decisions survive beyond this conversation. Only run this step for EXPANSION and SELECTIVE EXPANSION modes. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG/ceo-plans +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG/ceo-plans ``` Before writing, check for existing CEO plans in the ceo-plans/ directory. If any are >30 days old or their branch has been merged/deleted, offer to archive them: @@ -1101,7 +1101,7 @@ After producing the Completion Summary, clean up any handoff notes for this bran the review is complete and the context is no longer needed. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" rm -f ~/.gstack/projects/$SLUG/*-$BRANCH-ceo-handoff-*.md 2>/dev/null || true ``` diff --git a/plan-ceo-review/SKILL.md.tmpl b/plan-ceo-review/SKILL.md.tmpl index 6b676a86..a94c9ffe 100644 --- a/plan-ceo-review/SKILL.md.tmpl +++ b/plan-ceo-review/SKILL.md.tmpl @@ -298,7 +298,7 @@ Rules: After the opt-in/cherry-pick ceremony, write the plan to disk so the vision and decisions survive beyond this conversation. Only run this step for EXPANSION and SELECTIVE EXPANSION modes. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG/ceo-plans +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG/ceo-plans ``` Before writing, check for existing CEO plans in the ceo-plans/ directory. If any are >30 days old or their branch has been merged/deleted, offer to archive them: @@ -732,7 +732,7 @@ After producing the Completion Summary, clean up any handoff notes for this bran the review is complete and the context is no longer needed. ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) +{{SLUG_EVAL}} rm -f ~/.gstack/projects/$SLUG/*-$BRANCH-ceo-handoff-*.md 2>/dev/null || true ``` diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index 435d4f09..678d42a3 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -611,7 +611,7 @@ The plan should be complete enough that when implementation begins, every test i After producing the coverage diagram, write a test plan artifact to the project directory so `/qa` and `/qa-only` can consume it as primary test input: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) ``` diff --git a/qa-only/SKILL.md b/qa-only/SKILL.md index bd714612..48a3983c 100644 --- a/qa-only/SKILL.md +++ b/qa-only/SKILL.md @@ -346,7 +346,7 @@ Before falling back to git diff heuristics, check for richer test plan sources: 1. **Project-scoped test plans:** Check `~/.gstack/projects/` for recent `*-test-plan-*.md` files for this repo ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" ls -t ~/.gstack/projects/$SLUG/*-test-plan-*.md 2>/dev/null | head -1 ``` 2. **Conversation context:** Check if a prior `/plan-eng-review` or `/plan-ceo-review` produced test plan output in this conversation @@ -642,7 +642,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** Write test outcome artifact for cross-session context: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG ``` Write to `~/.gstack/projects/{slug}/{user}-{branch}-test-outcome-{datetime}.md` diff --git a/qa-only/SKILL.md.tmpl b/qa-only/SKILL.md.tmpl index 293a7b36..ef4ae6bd 100644 --- a/qa-only/SKILL.md.tmpl +++ b/qa-only/SKILL.md.tmpl @@ -54,7 +54,7 @@ Before falling back to git diff heuristics, check for richer test plan sources: 1. **Project-scoped test plans:** Check `~/.gstack/projects/` for recent `*-test-plan-*.md` files for this repo ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + {{SLUG_EVAL}} ls -t ~/.gstack/projects/$SLUG/*-test-plan-*.md 2>/dev/null | head -1 ``` 2. **Conversation context:** Check if a prior `/plan-eng-review` or `/plan-ceo-review` produced test plan output in this conversation @@ -74,7 +74,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** Write test outcome artifact for cross-session context: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +{{SLUG_SETUP}} ``` Write to `~/.gstack/projects/{slug}/{user}-{branch}-test-outcome-{datetime}.md` diff --git a/qa/SKILL.md b/qa/SKILL.md index d59ba122..2bd5d305 100644 --- a/qa/SKILL.md +++ b/qa/SKILL.md @@ -549,7 +549,7 @@ Before falling back to git diff heuristics, check for richer test plan sources: 1. **Project-scoped test plans:** Check `~/.gstack/projects/` for recent `*-test-plan-*.md` files for this repo ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" ls -t ~/.gstack/projects/$SLUG/*-test-plan-*.md 2>/dev/null | head -1 ``` 2. **Conversation context:** Check if a prior `/plan-eng-review` or `/plan-ceo-review` produced test plan output in this conversation @@ -1013,7 +1013,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** Write test outcome artifact for cross-session context: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG ``` Write to `~/.gstack/projects/{slug}/{user}-{branch}-test-outcome-{datetime}.md` diff --git a/qa/SKILL.md.tmpl b/qa/SKILL.md.tmpl index a3d02abc..c5695722 100644 --- a/qa/SKILL.md.tmpl +++ b/qa/SKILL.md.tmpl @@ -89,7 +89,7 @@ Before falling back to git diff heuristics, check for richer test plan sources: 1. **Project-scoped test plans:** Check `~/.gstack/projects/` for recent `*-test-plan-*.md` files for this repo ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + {{SLUG_EVAL}} ls -t ~/.gstack/projects/$SLUG/*-test-plan-*.md 2>/dev/null | head -1 ``` 2. **Conversation context:** Check if a prior `/plan-eng-review` or `/plan-ceo-review` produced test plan output in this conversation @@ -277,7 +277,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** Write test outcome artifact for cross-session context: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +{{SLUG_SETUP}} ``` Write to `~/.gstack/projects/{slug}/{user}-{branch}-test-outcome-{datetime}.md` diff --git a/scripts/gen-skill-docs.ts b/scripts/gen-skill-docs.ts index 364db1fe..837d33ce 100644 --- a/scripts/gen-skill-docs.ts +++ b/scripts/gen-skill-docs.ts @@ -1219,7 +1219,7 @@ Compare screenshots and observations across pages for: **Project-scoped:** \`\`\`bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG \`\`\` Write to: \`~/.gstack/projects/{slug}/{user}-{branch}-design-audit-{datetime}.md\` @@ -1815,7 +1815,7 @@ The plan should be complete enough that when implementation begins, every test i After producing the coverage diagram, write a test plan artifact to the project directory so \`/qa\` and \`/qa-only\` can consume it as primary test input: \`\`\`bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) \`\`\` @@ -1879,7 +1879,7 @@ Coverage line: \`Test Coverage Audit: N new code paths. M covered (X%). K tests After producing the coverage diagram, write a test plan artifact so \`/qa\` and \`/qa-only\` can consume it: \`\`\`bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) \`\`\` @@ -2542,7 +2542,17 @@ ${slopItems} Source: [OpenAI "Designing Delightful Frontends with GPT-5.4"](https://developers.openai.com/blog/designing-delightful-frontends-with-gpt-5-4) (Mar 2026) + gstack design methodology.`; } +function generateSlugEval(ctx: TemplateContext): string { + return `eval "$(${ctx.paths.binDir}/gstack-slug 2>/dev/null)"`; +} + +function generateSlugSetup(ctx: TemplateContext): string { + return `eval "$(${ctx.paths.binDir}/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG`; +} + const RESOLVERS: Record string> = { + SLUG_EVAL: generateSlugEval, + SLUG_SETUP: generateSlugSetup, COMMAND_REFERENCE: generateCommandReference, SNAPSHOT_FLAGS: generateSnapshotFlags, PREAMBLE: generatePreamble, diff --git a/ship/SKILL.md b/ship/SKILL.md index af138e1d..ce3196ea 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -395,7 +395,7 @@ If the Eng Review is NOT "CLEAR": 1. **Check for a prior override on this branch:** ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" grep '"skill":"ship-review-override"' ~/.gstack/projects/$SLUG/$BRANCH-reviews.jsonl 2>/dev/null || echo "NO_OVERRIDE" ``` If an override exists, display the dashboard and note "Review gate previously accepted — continuing." Do NOT ask again. @@ -409,7 +409,7 @@ If the Eng Review is NOT "CLEAR": 3. **If the user chooses A or C,** persist the decision so future `/ship` runs on this branch skip the gate: ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" echo '{"skill":"ship-review-override","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","decision":"USER_CHOICE"}' >> ~/.gstack/projects/$SLUG/$BRANCH-reviews.jsonl ``` Substitute USER_CHOICE with "ship_anyway" or "not_relevant". @@ -969,7 +969,7 @@ Coverage line: `Test Coverage Audit: N new code paths. M covered (X%). K tests g After producing the coverage diagram, write a test plan artifact so `/qa` and `/qa-only` can consume it: ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p ~/.gstack/projects/$SLUG USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) ``` diff --git a/ship/SKILL.md.tmpl b/ship/SKILL.md.tmpl index bd74c197..0308dd8b 100644 --- a/ship/SKILL.md.tmpl +++ b/ship/SKILL.md.tmpl @@ -62,7 +62,7 @@ If the Eng Review is NOT "CLEAR": 1. **Check for a prior override on this branch:** ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + {{SLUG_EVAL}} grep '"skill":"ship-review-override"' ~/.gstack/projects/$SLUG/$BRANCH-reviews.jsonl 2>/dev/null || echo "NO_OVERRIDE" ``` If an override exists, display the dashboard and note "Review gate previously accepted — continuing." Do NOT ask again. @@ -76,7 +76,7 @@ If the Eng Review is NOT "CLEAR": 3. **If the user chooses A or C,** persist the decision so future `/ship` runs on this branch skip the gate: ```bash - source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) + {{SLUG_EVAL}} echo '{"skill":"ship-review-override","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","decision":"USER_CHOICE"}' >> ~/.gstack/projects/$SLUG/$BRANCH-reviews.jsonl ``` Substitute USER_CHOICE with "ship_anyway" or "not_relevant". diff --git a/test/skill-validation.test.ts b/test/skill-validation.test.ts index 2085eaec..3d76ae67 100644 --- a/test/skill-validation.test.ts +++ b/test/skill-validation.test.ts @@ -1004,6 +1004,25 @@ describe('gstack-slug', () => { expect(slug).toMatch(/^[a-zA-Z0-9._-]+$/); expect(branch).toMatch(/^[a-zA-Z0-9._-]+$/); }); + test('eval sets variables under bash with set -euo pipefail', () => { + const result = Bun.spawnSync( + ['bash', '-c', 'set -euo pipefail; eval "$(./bin/gstack-slug 2>/dev/null)"; echo "SLUG=$SLUG"; echo "BRANCH=$BRANCH"'], + { cwd: ROOT, stdout: 'pipe', stderr: 'pipe' } + ); + expect(result.exitCode).toBe(0); + const output = result.stdout.toString(); + expect(output).toMatch(/^SLUG=.+/m); + expect(output).toMatch(/^BRANCH=.+/m); + }); + + test('no templates or bin scripts use source process substitution for gstack-slug', () => { + const result = Bun.spawnSync( + ['grep', '-r', 'source <(.*gstack-slug', '--include=*.tmpl', '--include=gstack-review-*', '.'], + { cwd: ROOT, stdout: 'pipe', stderr: 'pipe' } + ); + // grep returns exit code 1 when no matches found — that's what we want + expect(result.stdout.toString().trim()).toBe(''); + }); }); // --- Test Bootstrap validation ---