diff --git a/.agents/skills/gstack-cso/SKILL.md b/.agents/skills/gstack-cso/SKILL.md index 2913901d..132af401 100644 --- a/.agents/skills/gstack-cso/SKILL.md +++ b/.agents/skills/gstack-cso/SKILL.md @@ -12,23 +12,28 @@ description: | ## Preamble (run first) ```bash -_UPD=$(~/.codex/skills/gstack/bin/gstack-update-check 2>/dev/null || .agents/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) +GSTACK_ROOT="$HOME/.codex/skills/gstack" +[ -n "$_ROOT" ] && [ -d "$_ROOT/.agents/skills/gstack" ] && GSTACK_ROOT="$_ROOT/.agents/skills/gstack" +GSTACK_BIN="$GSTACK_ROOT/bin" +GSTACK_BROWSE="$GSTACK_ROOT/browse/dist" +_UPD=$($GSTACK_BIN/gstack-update-check 2>/dev/null || .agents/skills/gstack/bin/gstack-update-check 2>/dev/null || true) [ -n "$_UPD" ] && echo "$_UPD" || true mkdir -p ~/.gstack/sessions touch ~/.gstack/sessions/"$PPID" _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') find ~/.gstack/sessions -mmin +120 -type f -delete 2>/dev/null || true -_CONTRIB=$(~/.codex/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.codex/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($GSTACK_BIN/gstack-config get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($GSTACK_BIN/gstack-config get proactive 2>/dev/null || echo "true") _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") echo "BRANCH: $_BRANCH" echo "PROACTIVE: $_PROACTIVE" -source <(~/.codex/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true +source <($GSTACK_BIN/gstack-repo-mode 2>/dev/null) || true REPO_MODE=${REPO_MODE:-unknown} echo "REPO_MODE: $REPO_MODE" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.codex/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($GSTACK_BIN/gstack-config get telemetry 2>/dev/null || true) _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" @@ -36,13 +41,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"cso","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true -for _PF in ~/.gstack/analytics/.pending-*; do [ -f "$_PF" ] && ~/.codex/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done +for _PF in ~/.gstack/analytics/.pending-*; do [ -f "$_PF" ] && $GSTACK_BIN/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done ``` If `PROACTIVE` is `"false"`, do not proactively suggest gstack skills — only invoke them when the user explicitly asks. The user opted out of proactive suggestions. -If output shows `UPGRADE_AVAILABLE `: read `~/.codex/skills/gstack/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED `: tell user "Running gstack v{to} (just updated!)" and continue. +If output shows `UPGRADE_AVAILABLE `: read `$GSTACK_ROOT/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED `: tell user "Running gstack v{to} (just updated!)" and continue. If `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -68,7 +73,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.codex/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$GSTACK_BIN/gstack-config set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -79,8 +84,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.codex/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.codex/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$GSTACK_BIN/gstack-config set telemetry anonymous` +If B→B: run `$GSTACK_BIN/gstack-config set telemetry off` Always run: ```bash @@ -140,7 +145,7 @@ Never let a noticed issue silently pass. The whole point is proactive communicat ## Search Before Building -Before building infrastructure, unfamiliar patterns, or anything the runtime might have a built-in — **search first.** Read `~/.codex/skills/gstack/ETHOS.md` for the full philosophy. +Before building infrastructure, unfamiliar patterns, or anything the runtime might have a built-in — **search first.** Read `$GSTACK_ROOT/ETHOS.md` for the full philosophy. **Three layers of knowledge:** - **Layer 1** (tried and true — in distribution). Don't reinvent the wheel. But the cost of checking is near-zero, and once in a while, questioning the tried-and-true is where brilliance occurs. @@ -238,7 +243,7 @@ Run this bash: _TEL_END=$(date +%s) _TEL_DUR=$(( _TEL_END - _TEL_START )) rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true -~/.codex/skills/gstack/bin/gstack-telemetry-log \ +$GSTACK_ROOT/bin/gstack-telemetry-log \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` diff --git a/gstack-upgrade/SKILL.md b/gstack-upgrade/SKILL.md index 6dcc1f7c..f97f11fb 100644 --- a/gstack-upgrade/SKILL.md +++ b/gstack-upgrade/SKILL.md @@ -79,9 +79,15 @@ Continue with the current skill. if [ -d "$HOME/.claude/skills/gstack/.git" ]; then INSTALL_TYPE="global-git" INSTALL_DIR="$HOME/.claude/skills/gstack" +elif [ -d "$HOME/.gstack/repos/gstack/.git" ]; then + INSTALL_TYPE="global-git" + INSTALL_DIR="$HOME/.gstack/repos/gstack" elif [ -d ".claude/skills/gstack/.git" ]; then INSTALL_TYPE="local-git" INSTALL_DIR=".claude/skills/gstack" +elif [ -d ".agents/skills/gstack/.git" ]; then + INSTALL_TYPE="local-git" + INSTALL_DIR=".agents/skills/gstack" elif [ -d ".claude/skills/gstack" ]; then INSTALL_TYPE="vendored" INSTALL_DIR=".claude/skills/gstack" diff --git a/gstack-upgrade/SKILL.md.tmpl b/gstack-upgrade/SKILL.md.tmpl index 1d49cd1b..ac25894b 100644 --- a/gstack-upgrade/SKILL.md.tmpl +++ b/gstack-upgrade/SKILL.md.tmpl @@ -77,9 +77,15 @@ Continue with the current skill. if [ -d "$HOME/.claude/skills/gstack/.git" ]; then INSTALL_TYPE="global-git" INSTALL_DIR="$HOME/.claude/skills/gstack" +elif [ -d "$HOME/.gstack/repos/gstack/.git" ]; then + INSTALL_TYPE="global-git" + INSTALL_DIR="$HOME/.gstack/repos/gstack" elif [ -d ".claude/skills/gstack/.git" ]; then INSTALL_TYPE="local-git" INSTALL_DIR=".claude/skills/gstack" +elif [ -d ".agents/skills/gstack/.git" ]; then + INSTALL_TYPE="local-git" + INSTALL_DIR=".agents/skills/gstack" elif [ -d ".claude/skills/gstack" ]; then INSTALL_TYPE="vendored" INSTALL_DIR=".claude/skills/gstack" diff --git a/review/SKILL.md b/review/SKILL.md index 5bbf79c3..2048435a 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -745,7 +745,7 @@ TMPERR_ADV=$(mktemp /tmp/codex-adv-XXXXXXXX) codex exec "Review the changes on this branch against the base branch. Run git diff origin/ to see the diff. Your job is to find ways this code will fail in production. Think like an attacker and a chaos engineer. Find edge cases, race conditions, security holes, resource leaks, failure modes, and silent data corruption paths. Be adversarial. Be thorough. No compliments — just the problems." -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR_ADV" ``` -Use a 5-minute timeout (`timeout: 300000`). After the command completes, read stderr: +Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. After the command completes, read stderr: ```bash cat "$TMPERR_ADV" ``` @@ -790,7 +790,7 @@ TMPERR=$(mktemp /tmp/codex-review-XXXXXXXX) codex review --base -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR" ``` -Use a 5-minute timeout. Present output under `CODEX SAYS (code review):` header. +Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. Present output under `CODEX SAYS (code review):` header. Check for `[P1]` markers: found → `GATE: FAIL`, not found → `GATE: PASS`. If GATE is FAIL, use AskUserQuestion: diff --git a/scripts/gen-skill-docs.ts b/scripts/gen-skill-docs.ts index 3822f961..5062d520 100644 --- a/scripts/gen-skill-docs.ts +++ b/scripts/gen-skill-docs.ts @@ -2044,7 +2044,7 @@ TMPERR_ADV=$(mktemp /tmp/codex-adv-XXXXXXXX) codex exec "Review the changes on this branch against the base branch. Run git diff origin/ to see the diff. Your job is to find ways this code will fail in production. Think like an attacker and a chaos engineer. Find edge cases, race conditions, security holes, resource leaks, failure modes, and silent data corruption paths. Be adversarial. Be thorough. No compliments — just the problems." -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR_ADV" \`\`\` -Use a 5-minute timeout (\`timeout: 300000\`). After the command completes, read stderr: +Set the Bash tool's \`timeout\` parameter to \`300000\` (5 minutes). Do NOT use the \`timeout\` shell command — it doesn't exist on macOS. After the command completes, read stderr: \`\`\`bash cat "$TMPERR_ADV" \`\`\` @@ -2089,7 +2089,7 @@ TMPERR=$(mktemp /tmp/codex-review-XXXXXXXX) codex review --base -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR" \`\`\` -Use a 5-minute timeout. Present output under \`CODEX SAYS (code review):\` header. +Set the Bash tool's \`timeout\` parameter to \`300000\` (5 minutes). Do NOT use the \`timeout\` shell command — it doesn't exist on macOS. Present output under \`CODEX SAYS (code review):\` header. Check for \`[P1]\` markers: found → \`GATE: FAIL\`, not found → \`GATE: PASS\`. If GATE is FAIL, use AskUserQuestion: diff --git a/setup b/setup index 3cb47d38..75dbf731 100755 --- a/setup +++ b/setup @@ -24,7 +24,7 @@ esac HOST="claude" while [ $# -gt 0 ]; do case "$1" in - --host) HOST="$2"; shift 2 ;; + --host) [ -z "$2" ] && echo "Missing value for --host (expected claude, codex, kiro, or auto)" >&2 && exit 1; HOST="$2"; shift 2 ;; --host=*) HOST="${1#--host=}"; shift ;; *) shift ;; esac @@ -293,6 +293,10 @@ create_codex_runtime_root() { if [ -L "$codex_gstack" ]; then rm -f "$codex_gstack" + elif [ -d "$codex_gstack" ] && [ "$codex_gstack" != "$gstack_dir" ]; then + # Old direct installs left a real directory here with stale source skills. + # Remove it so we start fresh with only the minimal runtime assets. + rm -rf "$codex_gstack" fi mkdir -p "$codex_gstack" "$codex_gstack/browse" "$codex_gstack/gstack-upgrade" "$codex_gstack/review" @@ -318,6 +322,10 @@ create_codex_runtime_root() { ln -snf "$gstack_dir/review/$f" "$codex_gstack/review/$f" fi done + # ETHOS.md — referenced by "Search Before Building" in all skill preambles + if [ -f "$gstack_dir/ETHOS.md" ]; then + ln -snf "$gstack_dir/ETHOS.md" "$codex_gstack/ETHOS.md" + fi } # 4. Install for Claude (default) @@ -348,7 +356,11 @@ if [ "$INSTALL_CODEX" -eq 1 ]; then fi mkdir -p "$CODEX_SKILLS" - create_codex_runtime_root "$SOURCE_GSTACK_DIR" "$CODEX_GSTACK" + # Skip runtime root creation for repo-local installs — the checkout IS the runtime root. + # create_codex_runtime_root would create self-referential symlinks (bin → bin, etc.). + if [ "$CODEX_REPO_LOCAL" -eq 0 ]; then + create_codex_runtime_root "$SOURCE_GSTACK_DIR" "$CODEX_GSTACK" + fi # Install generated Codex-format skills (not Claude source dirs) link_codex_skill_dirs "$SOURCE_GSTACK_DIR" "$CODEX_SKILLS" @@ -367,9 +379,24 @@ if [ "$INSTALL_KIRO" -eq 1 ]; then KIRO_GSTACK="$KIRO_SKILLS/gstack" # Remove old whole-dir symlink from previous installs [ -L "$KIRO_GSTACK" ] && rm -f "$KIRO_GSTACK" - mkdir -p "$KIRO_GSTACK" + mkdir -p "$KIRO_GSTACK" "$KIRO_GSTACK/browse" "$KIRO_GSTACK/gstack-upgrade" "$KIRO_GSTACK/review" ln -snf "$SOURCE_GSTACK_DIR/bin" "$KIRO_GSTACK/bin" - ln -snf "$SOURCE_GSTACK_DIR/browse" "$KIRO_GSTACK/browse" + ln -snf "$SOURCE_GSTACK_DIR/browse/dist" "$KIRO_GSTACK/browse/dist" + ln -snf "$SOURCE_GSTACK_DIR/browse/bin" "$KIRO_GSTACK/browse/bin" + # ETHOS.md — referenced by "Search Before Building" in all skill preambles + if [ -f "$SOURCE_GSTACK_DIR/ETHOS.md" ]; then + ln -snf "$SOURCE_GSTACK_DIR/ETHOS.md" "$KIRO_GSTACK/ETHOS.md" + fi + # gstack-upgrade skill + if [ -f "$AGENTS_DIR/gstack-upgrade/SKILL.md" ]; then + ln -snf "$AGENTS_DIR/gstack-upgrade/SKILL.md" "$KIRO_GSTACK/gstack-upgrade/SKILL.md" + fi + # Review runtime assets (individual files, not whole dir) + for f in checklist.md design-checklist.md greptile-triage.md TODOS-format.md; do + if [ -f "$SOURCE_GSTACK_DIR/review/$f" ]; then + ln -snf "$SOURCE_GSTACK_DIR/review/$f" "$KIRO_GSTACK/review/$f" + fi + done # Rewrite root SKILL.md paths for Kiro sed -e "s|~/.claude/skills/gstack|~/.kiro/skills/gstack|g" \ @@ -385,10 +412,11 @@ if [ "$INSTALL_KIRO" -eq 1 ]; then skill_name="$(basename "$skill_dir")" target_dir="$KIRO_SKILLS/$skill_name" mkdir -p "$target_dir" - sed -e "s|~/.codex/skills/gstack|~/.kiro/skills/gstack|g" \ + # Generated Codex skills use $HOME/.codex (not ~/), plus $GSTACK_ROOT variables. + # Rewrite the default GSTACK_ROOT value and any remaining literal paths. + sed -e 's|\$HOME/.codex/skills/gstack|$HOME/.kiro/skills/gstack|g' \ + -e "s|~/.codex/skills/gstack|~/.kiro/skills/gstack|g" \ -e "s|~/.claude/skills/gstack|~/.kiro/skills/gstack|g" \ - -e "s|\.agents/skills/gstack|.kiro/skills/gstack|g" \ - -e "s|\.agents/skills|.kiro/skills|g" \ "$skill_dir/SKILL.md" > "$target_dir/SKILL.md" done echo "gstack ready (kiro)." diff --git a/ship/SKILL.md b/ship/SKILL.md index 23b3ed1e..f5af3735 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -1112,7 +1112,7 @@ TMPERR_ADV=$(mktemp /tmp/codex-adv-XXXXXXXX) codex exec "Review the changes on this branch against the base branch. Run git diff origin/ to see the diff. Your job is to find ways this code will fail in production. Think like an attacker and a chaos engineer. Find edge cases, race conditions, security holes, resource leaks, failure modes, and silent data corruption paths. Be adversarial. Be thorough. No compliments — just the problems." -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR_ADV" ``` -Use a 5-minute timeout (`timeout: 300000`). After the command completes, read stderr: +Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. After the command completes, read stderr: ```bash cat "$TMPERR_ADV" ``` @@ -1157,7 +1157,7 @@ TMPERR=$(mktemp /tmp/codex-review-XXXXXXXX) codex review --base -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR" ``` -Use a 5-minute timeout. Present output under `CODEX SAYS (code review):` header. +Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. Present output under `CODEX SAYS (code review):` header. Check for `[P1]` markers: found → `GATE: FAIL`, not found → `GATE: PASS`. If GATE is FAIL, use AskUserQuestion: diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index ce32b343..95f615c2 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -967,7 +967,10 @@ describe('Codex generation (--host codex)', () => { for (const skill of ALL_SKILLS) { const content = fs.readFileSync(path.join(ROOT, skill.dir, 'SKILL.md'), 'utf-8'); expect(content).not.toContain('~/.codex/'); - expect(content).not.toContain('.agents/skills'); + // gstack-upgrade legitimately references .agents/skills for cross-platform detection + if (skill.dir !== 'gstack-upgrade') { + expect(content).not.toContain('.agents/skills'); + } } }); });