From ae3b7dd411540c4bbc2182716dcfe958ae60344b Mon Sep 17 00:00:00 2001 From: AliFozooni Date: Sat, 21 Mar 2026 10:54:46 -0700 Subject: [PATCH] feat: add scoped installs and local-first runtime paths --- .agents/skills/gstack-browse/SKILL.md | 20 +- .../gstack-design-consultation/SKILL.md | 22 +- .agents/skills/gstack-design-review/SKILL.md | 24 +- .../skills/gstack-document-release/SKILL.md | 20 +- .agents/skills/gstack-investigate/SKILL.md | 20 +- .agents/skills/gstack-office-hours/SKILL.md | 24 +- .../skills/gstack-plan-ceo-review/SKILL.md | 32 +- .../skills/gstack-plan-design-review/SKILL.md | 24 +- .../skills/gstack-plan-eng-review/SKILL.md | 30 +- .agents/skills/gstack-qa-only/SKILL.md | 24 +- .agents/skills/gstack-qa/SKILL.md | 24 +- .agents/skills/gstack-retro/SKILL.md | 20 +- .agents/skills/gstack-review/SKILL.md | 30 +- .../gstack-setup-browser-cookies/SKILL.md | 20 +- .agents/skills/gstack-ship/SKILL.md | 40 +-- .agents/skills/gstack-upgrade/SKILL.md | 19 +- .agents/skills/gstack/SKILL.md | 20 +- CONTRIBUTING.md | 10 + README.md | 21 +- SKILL.md | 20 +- browse/SKILL.md | 20 +- codex/SKILL.md | 22 +- design-consultation/SKILL.md | 22 +- design-review/SKILL.md | 24 +- document-release/SKILL.md | 20 +- gstack-upgrade/SKILL.md | 11 +- gstack-upgrade/SKILL.md.tmpl | 3 +- investigate/SKILL.md | 20 +- office-hours/SKILL.md | 24 +- plan-ceo-review/SKILL.md | 32 +- plan-design-review/SKILL.md | 24 +- plan-eng-review/SKILL.md | 30 +- qa-only/SKILL.md | 24 +- qa/SKILL.md | 24 +- retro/SKILL.md | 20 +- review/SKILL.md | 38 +- scripts/gen-skill-docs.ts | 78 ++++- setup | 324 +++++++++++++----- setup-browser-cookies/SKILL.md | 20 +- ship/SKILL.md | 48 +-- test/gen-skill-docs.test.ts | 39 ++- test/setup.test.ts | 150 ++++++++ 42 files changed, 959 insertions(+), 522 deletions(-) create mode 100644 test/setup.test.ts diff --git a/.agents/skills/gstack-browse/SKILL.md b/.agents/skills/gstack-browse/SKILL.md index db405e47b..5d966e12c 100644 --- a/.agents/skills/gstack-browse/SKILL.md +++ b/.agents/skills/gstack-browse/SKILL.md @@ -14,20 +14,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -35,13 +35,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"browse","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -67,7 +67,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -78,8 +78,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -205,7 +205,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/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/.agents/skills/gstack-design-consultation/SKILL.md b/.agents/skills/gstack-design-consultation/SKILL.md index 8d018781c..685667800 100644 --- a/.agents/skills/gstack-design-consultation/SKILL.md +++ b/.agents/skills/gstack-design-consultation/SKILL.md @@ -15,20 +15,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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 +36,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"design-consultation","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `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 +68,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -79,8 +79,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -206,7 +206,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -246,7 +246,7 @@ ls src/ app/ pages/ components/ 2>/dev/null | head -30 Look for office-hours output: ```bash -source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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/.agents/skills/gstack-design-review/SKILL.md b/.agents/skills/gstack-design-review/SKILL.md index 2a7d26b23..b61b5098a 100644 --- a/.agents/skills/gstack-design-review/SKILL.md +++ b/.agents/skills/gstack-design-review/SKILL.md @@ -15,20 +15,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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 +36,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"design-review","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `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 +68,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -79,8 +79,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -206,7 +206,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -693,7 +693,7 @@ Compare screenshots and observations across pages for: **Project-scoped:** ```bash -source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/skills/gstack/bin/gstack-slug) 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG ``` Write to: `~/.gstack/projects/{slug}/{user}-{branch}-design-audit-{datetime}.md` @@ -911,7 +911,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** ```bash -source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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/.agents/skills/gstack-document-release/SKILL.md b/.agents/skills/gstack-document-release/SKILL.md index 9249b0be8..be6736a9f 100644 --- a/.agents/skills/gstack-document-release/SKILL.md +++ b/.agents/skills/gstack-document-release/SKILL.md @@ -13,20 +13,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -34,13 +34,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"document-release","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -66,7 +66,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -77,8 +77,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -204,7 +204,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/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/.agents/skills/gstack-investigate/SKILL.md b/.agents/skills/gstack-investigate/SKILL.md index 39f5910ea..5add0d90b 100644 --- a/.agents/skills/gstack-investigate/SKILL.md +++ b/.agents/skills/gstack-investigate/SKILL.md @@ -16,20 +16,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -37,13 +37,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"investigate","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -69,7 +69,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -80,8 +80,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -207,7 +207,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/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/.agents/skills/gstack-office-hours/SKILL.md b/.agents/skills/gstack-office-hours/SKILL.md index eb1b7084e..571ad82fc 100644 --- a/.agents/skills/gstack-office-hours/SKILL.md +++ b/.agents/skills/gstack-office-hours/SKILL.md @@ -17,20 +17,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -38,13 +38,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"office-hours","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -70,7 +70,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -81,8 +81,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -208,7 +208,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -250,7 +250,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 <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/skills/gstack/bin/gstack-slug) 2>/dev/null) ``` 1. Read `CLAUDE.md`, `TODOS.md` (if they exist). @@ -583,7 +583,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 <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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/.agents/skills/gstack-plan-ceo-review/SKILL.md b/.agents/skills/gstack-plan-ceo-review/SKILL.md index b43b8e0a3..4fc374cbe 100644 --- a/.agents/skills/gstack-plan-ceo-review/SKILL.md +++ b/.agents/skills/gstack-plan-ceo-review/SKILL.md @@ -16,20 +16,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -37,13 +37,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-ceo-review","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -69,7 +69,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -80,8 +80,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -207,7 +207,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -316,7 +316,7 @@ Then read CLAUDE.md, TODOS.md, and any existing architecture docs. **Design doc check:** ```bash -SLUG=$(~/.codex/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") +SLUG=$($([ -x .agents/skills/gstack/browse/bin/remote-slug ] && echo .agents/skills/gstack/browse/bin/remote-slug || echo ~/.codex/skills/gstack/browse/bin/remote-slug) 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) [ -z "$DESIGN" ] && DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) @@ -511,7 +511,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 <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG/ceo-plans +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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: @@ -930,7 +930,7 @@ Complete table of every method that can fail, every exception class, rescued sta Any row with RESCUED=N, TEST=N, USER SEES=Silent → **CRITICAL GAP**. ### TODOS.md updates -Present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `.agents/skills/gstack/review/TODOS-format.md`. +Present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `$([ -f .agents/skills/gstack/review/TODOS-format.md ] && echo .agents/skills/gstack/review/TODOS-format.md || echo ~/.codex/skills/gstack/review/TODOS-format.md)`. For each TODO, describe: * **What:** One-line description of the work. @@ -1005,7 +1005,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 <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/skills/gstack/bin/gstack-slug) 2>/dev/null) rm -f ~/.gstack/projects/$SLUG/*-$BRANCH-ceo-handoff-*.md 2>/dev/null || true ``` @@ -1020,7 +1020,7 @@ the same pattern. The review dashboard depends on this data. Skipping this command breaks the review readiness dashboard in /ship. ```bash -~/.codex/skills/gstack/bin/gstack-review-log '{"skill":"plan-ceo-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' +$([ -x .agents/skills/gstack/bin/gstack-review-log ] && echo .agents/skills/gstack/bin/gstack-review-log || echo ~/.codex/skills/gstack/bin/gstack-review-log) '{"skill":"plan-ceo-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' ``` Before running this command, substitute the placeholder values from the Completion Summary you just produced: @@ -1036,7 +1036,7 @@ Before running this command, substitute the placeholder values from the Completi After completing the review, read the review log and config to display the dashboard. ```bash -~/.codex/skills/gstack/bin/gstack-review-read +$([ -x .agents/skills/gstack/bin/gstack-review-read ] && echo .agents/skills/gstack/bin/gstack-review-read || echo ~/.codex/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: diff --git a/.agents/skills/gstack-plan-design-review/SKILL.md b/.agents/skills/gstack-plan-design-review/SKILL.md index e431d72c5..b8baf4e91 100644 --- a/.agents/skills/gstack-plan-design-review/SKILL.md +++ b/.agents/skills/gstack-plan-design-review/SKILL.md @@ -15,20 +15,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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 +36,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-design-review","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `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 +68,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -79,8 +79,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -206,7 +206,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -488,7 +488,7 @@ the same pattern. The review dashboard depends on this data. Skipping this command breaks the review readiness dashboard in /ship. ```bash -~/.codex/skills/gstack/bin/gstack-review-log '{"skill":"plan-design-review","timestamp":"TIMESTAMP","status":"STATUS","overall_score":N,"unresolved":N,"decisions_made":N,"commit":"COMMIT"}' +$([ -x .agents/skills/gstack/bin/gstack-review-log ] && echo .agents/skills/gstack/bin/gstack-review-log || echo ~/.codex/skills/gstack/bin/gstack-review-log) '{"skill":"plan-design-review","timestamp":"TIMESTAMP","status":"STATUS","overall_score":N,"unresolved":N,"decisions_made":N,"commit":"COMMIT"}' ``` Substitute values from the Completion Summary: @@ -504,7 +504,7 @@ Substitute values from the Completion Summary: After completing the review, read the review log and config to display the dashboard. ```bash -~/.codex/skills/gstack/bin/gstack-review-read +$([ -x .agents/skills/gstack/bin/gstack-review-read ] && echo .agents/skills/gstack/bin/gstack-review-read || echo ~/.codex/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: diff --git a/.agents/skills/gstack-plan-eng-review/SKILL.md b/.agents/skills/gstack-plan-eng-review/SKILL.md index 012330795..2e61fde18 100644 --- a/.agents/skills/gstack-plan-eng-review/SKILL.md +++ b/.agents/skills/gstack-plan-eng-review/SKILL.md @@ -14,20 +14,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -35,13 +35,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-eng-review","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -67,7 +67,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -78,8 +78,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -205,7 +205,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -261,7 +261,7 @@ When evaluating architecture, think "boring by default." When reviewing tests, t ### Design Doc Check ```bash -SLUG=$(~/.codex/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") +SLUG=$($([ -x .agents/skills/gstack/browse/bin/remote-slug ] && echo .agents/skills/gstack/browse/bin/remote-slug || echo ~/.codex/skills/gstack/browse/bin/remote-slug) 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) [ -z "$DESIGN" ] && DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) @@ -363,7 +363,7 @@ For LLM/prompt changes: check the "Prompt/LLM changes" file patterns listed in C After producing the test diagram, write a test plan artifact to the project directory so `/qa` and `/qa-only` can consume it as primary test input (replacing the lossy git-diff heuristic): ```bash -source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/skills/gstack/bin/gstack-slug) 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) ``` @@ -419,7 +419,7 @@ Every plan review MUST produce a "NOT in scope" section listing work that was co List existing code/flows that already partially solve sub-problems in this plan, and whether the plan reuses them or unnecessarily rebuilds them. ### TODOS.md updates -After all review sections are complete, present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `.agents/skills/gstack/review/TODOS-format.md`. +After all review sections are complete, present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `$([ -f .agents/skills/gstack/review/TODOS-format.md ] && echo .agents/skills/gstack/review/TODOS-format.md || echo ~/.codex/skills/gstack/review/TODOS-format.md)`. For each TODO, describe: * **What:** One-line description of the work. @@ -477,7 +477,7 @@ the same pattern. The review dashboard depends on this data. Skipping this command breaks the review readiness dashboard in /ship. ```bash -~/.codex/skills/gstack/bin/gstack-review-log '{"skill":"plan-eng-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' +$([ -x .agents/skills/gstack/bin/gstack-review-log ] && echo .agents/skills/gstack/bin/gstack-review-log || echo ~/.codex/skills/gstack/bin/gstack-review-log) '{"skill":"plan-eng-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' ``` Substitute values from the Completion Summary: @@ -493,7 +493,7 @@ Substitute values from the Completion Summary: After completing the review, read the review log and config to display the dashboard. ```bash -~/.codex/skills/gstack/bin/gstack-review-read +$([ -x .agents/skills/gstack/bin/gstack-review-read ] && echo .agents/skills/gstack/bin/gstack-review-read || echo ~/.codex/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: diff --git a/.agents/skills/gstack-qa-only/SKILL.md b/.agents/skills/gstack-qa-only/SKILL.md index 6a6f8a7d4..aab2c91f4 100644 --- a/.agents/skills/gstack-qa-only/SKILL.md +++ b/.agents/skills/gstack-qa-only/SKILL.md @@ -13,20 +13,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -34,13 +34,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"qa-only","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -66,7 +66,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -77,8 +77,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -204,7 +204,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -268,7 +268,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 <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) + source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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 @@ -564,7 +564,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** Write test outcome artifact for cross-session context: ```bash -source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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/.agents/skills/gstack-qa/SKILL.md b/.agents/skills/gstack-qa/SKILL.md index 0617c447a..f155248cc 100644 --- a/.agents/skills/gstack-qa/SKILL.md +++ b/.agents/skills/gstack-qa/SKILL.md @@ -16,20 +16,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -37,13 +37,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"qa","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -69,7 +69,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -80,8 +80,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -207,7 +207,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -468,7 +468,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 <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) + source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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 @@ -932,7 +932,7 @@ Write the report to both local and project-scoped locations: **Project-scoped:** Write test outcome artifact for cross-session context: ```bash -source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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/.agents/skills/gstack-retro/SKILL.md b/.agents/skills/gstack-retro/SKILL.md index 5d17bf2bf..1ce922cd1 100644 --- a/.agents/skills/gstack-retro/SKILL.md +++ b/.agents/skills/gstack-retro/SKILL.md @@ -13,20 +13,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -34,13 +34,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"retro","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -66,7 +66,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -77,8 +77,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -204,7 +204,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/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/.agents/skills/gstack-review/SKILL.md b/.agents/skills/gstack-review/SKILL.md index ab00c53e3..99f9e3a28 100644 --- a/.agents/skills/gstack-review/SKILL.md +++ b/.agents/skills/gstack-review/SKILL.md @@ -12,20 +12,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -33,13 +33,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"review","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -65,7 +65,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -76,8 +76,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -203,7 +203,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -282,7 +282,7 @@ Before reviewing code quality, check: **did they build what was requested — no ## Step 2: Read the checklist -Read `.agents/skills/gstack/review/checklist.md`. +Read `$([ -f .agents/skills/gstack/review/checklist.md ] && echo .agents/skills/gstack/review/checklist.md || echo ~/.codex/skills/gstack/review/checklist.md)`. **If the file cannot be read, STOP and report the error.** Do not proceed without the checklist. @@ -290,7 +290,7 @@ Read `.agents/skills/gstack/review/checklist.md`. ## Step 2.5: Check for Greptile review comments -Read `.agents/skills/gstack/review/greptile-triage.md` and follow the fetch, filter, classify, and **escalation detection** steps. +Read `$([ -f .agents/skills/gstack/review/greptile-triage.md ] && echo .agents/skills/gstack/review/greptile-triage.md || echo ~/.codex/skills/gstack/review/greptile-triage.md)` and follow the fetch, filter, classify, and **escalation detection** steps. **If no PR exists, `gh` fails, API returns an error, or there are zero Greptile comments:** Skip this step silently. Greptile integration is additive — the review works without it. @@ -330,7 +330,7 @@ Follow the output format specified in the checklist. Respect the suppressions Check if the diff touches frontend files using `gstack-diff-scope`: ```bash -source <(~/.codex/skills/gstack/bin/gstack-diff-scope 2>/dev/null) +source <($([ -x .agents/skills/gstack/bin/gstack-diff-scope ] && echo .agents/skills/gstack/bin/gstack-diff-scope || echo ~/.codex/skills/gstack/bin/gstack-diff-scope) 2>/dev/null) ``` **If `SCOPE_FRONTEND=false`:** Skip design review silently. No output. @@ -339,7 +339,7 @@ source <(~/.codex/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 1. **Check for DESIGN.md.** If `DESIGN.md` or `design-system.md` exists in the repo root, read it. All design findings are calibrated against it — patterns blessed in DESIGN.md are not flagged. If not found, use universal design principles. -2. **Read `.agents/skills/gstack/review/design-checklist.md`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." +2. **Read `$([ -f .agents/skills/gstack/review/design-checklist.md ] && echo .agents/skills/gstack/review/design-checklist.md || echo ~/.codex/skills/gstack/review/design-checklist.md)`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." 3. **Read each changed frontend file** (full file, not just diff hunks). Frontend files are identified by the patterns listed in the checklist. @@ -353,7 +353,7 @@ source <(~/.codex/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 6. **Log the result** for the Review Readiness Dashboard: ```bash -~/.codex/skills/gstack/bin/gstack-review-log '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' +$([ -x .agents/skills/gstack/bin/gstack-review-log ] && echo .agents/skills/gstack/bin/gstack-review-log || echo ~/.codex/skills/gstack/bin/gstack-review-log) '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' ``` Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "issues_found", N = total findings, M = auto-fixed count, COMMIT = output of `git rev-parse --short HEAD`. diff --git a/.agents/skills/gstack-setup-browser-cookies/SKILL.md b/.agents/skills/gstack-setup-browser-cookies/SKILL.md index 34f95391c..21f46a5ed 100644 --- a/.agents/skills/gstack-setup-browser-cookies/SKILL.md +++ b/.agents/skills/gstack-setup-browser-cookies/SKILL.md @@ -12,20 +12,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -33,13 +33,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"setup-browser-cookies","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -65,7 +65,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -76,8 +76,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -203,7 +203,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/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/.agents/skills/gstack-ship/SKILL.md b/.agents/skills/gstack-ship/SKILL.md index 24a770bef..b6ec19005 100644 --- a/.agents/skills/gstack-ship/SKILL.md +++ b/.agents/skills/gstack-ship/SKILL.md @@ -10,20 +10,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -31,13 +31,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"ship","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -63,7 +63,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -74,8 +74,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -201,7 +201,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -271,7 +271,7 @@ You are running the `/ship` workflow. This is a **non-interactive, fully automat After completing the review, read the review log and config to display the dashboard. ```bash -~/.codex/skills/gstack/bin/gstack-review-read +$([ -x .agents/skills/gstack/bin/gstack-review-read ] && echo .agents/skills/gstack/bin/gstack-review-read || echo ~/.codex/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: @@ -313,7 +313,7 @@ If the Eng Review is NOT "CLEAR": 1. **Check for a prior override on this branch:** ```bash - source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) + source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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. @@ -323,11 +323,11 @@ If the Eng Review is NOT "CLEAR": - RECOMMENDATION: Choose C if the change is obviously trivial (< 20 lines, typo fix, config-only); Choose B for larger changes - Options: A) Ship anyway B) Abort — run /plan-eng-review first C) Change is too small to need eng review - If CEO Review is missing, mention as informational ("CEO Review not run — recommended for product changes") but do NOT block - - For Design Review: run `source <(~/.codex/skills/gstack/bin/gstack-diff-scope 2>/dev/null)`. If `SCOPE_FRONTEND=true` and no design review (plan-design-review or design-review-lite) exists in the dashboard, mention: "Design Review not run — this PR changes frontend code. The lite design check will run automatically in Step 3.5, but consider running /design-review for a full visual audit post-implementation." Still never block. + - For Design Review: run `source <($([ -x .agents/skills/gstack/bin/gstack-diff-scope ] && echo .agents/skills/gstack/bin/gstack-diff-scope || echo ~/.codex/skills/gstack/bin/gstack-diff-scope) 2>/dev/null)`. If `SCOPE_FRONTEND=true` and no design review (plan-design-review or design-review-lite) exists in the dashboard, mention: "Design Review not run — this PR changes frontend code. The lite design check will run automatically in Step 3.5, but consider running /design-review for a full visual audit post-implementation." Still never block. 3. **If the user chooses A or C,** persist the decision so future `/ship` runs on this branch skip the gate: ```bash - source <(~/.codex/skills/gstack/bin/gstack-slug 2>/dev/null) + source <($([ -x .agents/skills/gstack/bin/gstack-slug ] && echo .agents/skills/gstack/bin/gstack-slug || echo ~/.codex/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". @@ -731,7 +731,7 @@ Coverage line: `Test Coverage Audit: N new code paths. M covered (X%). K tests g Review the diff for structural issues that tests don't catch. -1. Read `.agents/skills/gstack/review/checklist.md`. If the file cannot be read, **STOP** and report the error. +1. Read `$([ -f .agents/skills/gstack/review/checklist.md ] && echo .agents/skills/gstack/review/checklist.md || echo ~/.codex/skills/gstack/review/checklist.md)`. If the file cannot be read, **STOP** and report the error. 2. Run `git diff origin/` to get the full diff (scoped to feature changes against the freshly-fetched base branch). @@ -744,7 +744,7 @@ Review the diff for structural issues that tests don't catch. Check if the diff touches frontend files using `gstack-diff-scope`: ```bash -source <(~/.codex/skills/gstack/bin/gstack-diff-scope 2>/dev/null) +source <($([ -x .agents/skills/gstack/bin/gstack-diff-scope ] && echo .agents/skills/gstack/bin/gstack-diff-scope || echo ~/.codex/skills/gstack/bin/gstack-diff-scope) 2>/dev/null) ``` **If `SCOPE_FRONTEND=false`:** Skip design review silently. No output. @@ -753,7 +753,7 @@ source <(~/.codex/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 1. **Check for DESIGN.md.** If `DESIGN.md` or `design-system.md` exists in the repo root, read it. All design findings are calibrated against it — patterns blessed in DESIGN.md are not flagged. If not found, use universal design principles. -2. **Read `.agents/skills/gstack/review/design-checklist.md`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." +2. **Read `$([ -f .agents/skills/gstack/review/design-checklist.md ] && echo .agents/skills/gstack/review/design-checklist.md || echo ~/.codex/skills/gstack/review/design-checklist.md)`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." 3. **Read each changed frontend file** (full file, not just diff hunks). Frontend files are identified by the patterns listed in the checklist. @@ -767,7 +767,7 @@ source <(~/.codex/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 6. **Log the result** for the Review Readiness Dashboard: ```bash -~/.codex/skills/gstack/bin/gstack-review-log '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' +$([ -x .agents/skills/gstack/bin/gstack-review-log ] && echo .agents/skills/gstack/bin/gstack-review-log || echo ~/.codex/skills/gstack/bin/gstack-review-log) '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' ``` Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "issues_found", N = total findings, M = auto-fixed count, COMMIT = output of `git rev-parse --short HEAD`. @@ -800,7 +800,7 @@ Save the review output — it goes into the PR body in Step 8. ## Step 3.75: Address Greptile review comments (if PR exists) -Read `.agents/skills/gstack/review/greptile-triage.md` and follow the fetch, filter, classify, and **escalation detection** steps. +Read `$([ -f .agents/skills/gstack/review/greptile-triage.md ] && echo .agents/skills/gstack/review/greptile-triage.md || echo ~/.codex/skills/gstack/review/greptile-triage.md)` and follow the fetch, filter, classify, and **escalation detection** steps. **If no PR exists, `gh` fails, API returns an error, or there are zero Greptile comments:** Skip this step silently. Continue to Step 4. @@ -884,7 +884,7 @@ For each classified comment: Cross-reference the project's TODOS.md against the changes being shipped. Mark completed items automatically; prompt only if the file is missing or disorganized. -Read `.agents/skills/gstack/review/TODOS-format.md` for the canonical format reference. +Read `$([ -f .agents/skills/gstack/review/TODOS-format.md ] && echo .agents/skills/gstack/review/TODOS-format.md || echo ~/.codex/skills/gstack/review/TODOS-format.md)` for the canonical format reference. **1. Check if TODOS.md exists** in the repository root. diff --git a/.agents/skills/gstack-upgrade/SKILL.md b/.agents/skills/gstack-upgrade/SKILL.md index adfbad440..0206e985d 100644 --- a/.agents/skills/gstack-upgrade/SKILL.md +++ b/.agents/skills/gstack-upgrade/SKILL.md @@ -22,7 +22,7 @@ First, check if auto-upgrade is enabled: ```bash _AUTO="" [ "${GSTACK_AUTO_UPGRADE:-}" = "1" ] && _AUTO="true" -[ -z "$_AUTO" ] && _AUTO=$(~/.codex/skills/gstack/bin/gstack-config get auto_upgrade 2>/dev/null || true) +[ -z "$_AUTO" ] && _AUTO=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get auto_upgrade 2>/dev/null || true) echo "AUTO_UPGRADE=$_AUTO" ``` @@ -36,7 +36,7 @@ echo "AUTO_UPGRADE=$_AUTO" **If "Always keep me up to date":** ```bash -~/.codex/skills/gstack/bin/gstack-config set auto_upgrade true +$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set auto_upgrade true ``` Tell user: "Auto-upgrade enabled. Future updates will install automatically." Then proceed to Step 2. @@ -62,26 +62,26 @@ Tell user the snooze duration: "Next reminder in 24h" (or 48h or 1 week, dependi **If "Never ask again":** ```bash -~/.codex/skills/gstack/bin/gstack-config set update_check false +$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set update_check false ``` -Tell user: "Update checks disabled. Run `~/.codex/skills/gstack/bin/gstack-config set update_check true` to re-enable." +Tell user: "Update checks disabled. Run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set update_check true` to re-enable." Continue with the current skill. ### Step 2: Detect install type ```bash -if [ -d "$HOME/.agents/skills/gstack/.git" ]; then +if [ -d "$HOME/.codex/skills/gstack/.git" ]; then INSTALL_TYPE="global-git" - INSTALL_DIR="$HOME/.agents/skills/gstack" + INSTALL_DIR="$HOME/.codex/skills/gstack" elif [ -d ".agents/skills/gstack/.git" ]; then INSTALL_TYPE="local-git" INSTALL_DIR=".agents/skills/gstack" elif [ -d ".agents/skills/gstack" ]; then INSTALL_TYPE="vendored" INSTALL_DIR=".agents/skills/gstack" -elif [ -d "$HOME/.agents/skills/gstack" ]; then +elif [ -d "$HOME/.codex/skills/gstack" ]; then INSTALL_TYPE="vendored-global" - INSTALL_DIR="$HOME/.agents/skills/gstack" + INSTALL_DIR="$HOME/.codex/skills/gstack" else echo "ERROR: gstack not found" exit 1 @@ -195,8 +195,7 @@ When invoked directly as `/gstack-upgrade` (not from a preamble): 1. Force a fresh update check (bypass cache): ```bash -~/.codex/skills/gstack/bin/gstack-update-check --force 2>/dev/null || \ -.agents/skills/gstack/bin/gstack-update-check --force 2>/dev/null || true +$([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/skills/gstack/bin/gstack-update-check) --force 2>/dev/null || true ``` Use the output to determine if an upgrade is available. diff --git a/.agents/skills/gstack/SKILL.md b/.agents/skills/gstack/SKILL.md index 4bb9ba170..c4887286a 100644 --- a/.agents/skills/gstack/SKILL.md +++ b/.agents/skills/gstack/SKILL.md @@ -45,20 +45,20 @@ 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) +_UPD=$($([ -x .agents/skills/gstack/bin/gstack-update-check ] && echo .agents/skills/gstack/bin/gstack-update-check || echo ~/.codex/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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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" _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=$($([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/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)" @@ -66,13 +66,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"gstack","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" ] && $([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.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 ``` 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 `$([ -f .agents/skills/gstack-upgrade/SKILL.md ] && echo .agents/skills/gstack-upgrade/SKILL.md || echo ~/.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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -98,7 +98,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -109,8 +109,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 `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .agents/skills/gstack/bin/gstack-config ] && echo .agents/skills/gstack/bin/gstack-config || echo ~/.codex/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -236,7 +236,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 \ +$([ -x .agents/skills/gstack/bin/gstack-telemetry-log ] && echo .agents/skills/gstack/bin/gstack-telemetry-log || echo ~/.codex/skills/gstack/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/CONTRIBUTING.md b/CONTRIBUTING.md index 8ff6a8431..c00dc3f2c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -274,6 +274,16 @@ bun run skill:check When you run `bin/dev-setup`, it creates symlinks in both `.claude/skills/` and `.agents/skills/` (if applicable), so Codex-compatible agents can discover your dev skills too. +For arbitrary checkouts outside a skills directory, `./setup` now supports explicit install scopes: + +```bash +./setup --host auto --scope user +./setup --host auto --scope workspace --project-root /path/to/project +``` + +`--scope user` installs into `~/.claude/skills/` and `~/.codex/skills/`. `--scope workspace` installs into a single project's `.claude/skills/` and `.agents/skills/` without touching your global profile. +Generated skills resolve project-local runtime assets first, then fall back to the global install, so workspace-scoped evaluation works without a separate global bootstrap step. + ### Adding a new skill When you add a new skill template, both hosts get it automatically: diff --git a/README.md b/README.md index 070477970..38d56a26d 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,13 @@ Open Claude Code and paste this. Claude does the rest. > Install gstack: run **`git clone https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup`** then add a "gstack" section to CLAUDE.md that says to use the /browse skill from gstack for all web browsing, never use mcp\_\_claude-in-chrome\_\_\* tools, and lists the available skills: /office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review, /design-consultation, /review, /ship, /browse, /qa, /qa-only, /design-review, /setup-browser-cookies, /retro, /investigate, /document-release, /codex, /careful, /freeze, /guard, /unfreeze, /gstack-upgrade. Then ask the user if they also want to add gstack to the current project so teammates get it. +Prefer to keep the checkout anywhere and still install globally? Use the new user-scoped install: + +```bash +git clone https://github.com/garrytan/gstack.git ~/gstack +cd ~/gstack && ./setup --host auto --scope user +``` + ### Step 2: Add to your repo so teammates get it (optional) > Add gstack to this project: run **`cp -Rf ~/.claude/skills/gstack .claude/skills/gstack && rm -rf .claude/skills/gstack/.git && cd .claude/skills/gstack && ./setup`** then add a "gstack" section to this project's CLAUDE.md that says to use the /browse skill from gstack for all web browsing, never use mcp\_\_claude-in-chrome\_\_\* tools, lists the available skills: /office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review, /design-consultation, /review, /ship, /browse, /qa, /qa-only, /design-review, /setup-browser-cookies, /retro, /investigate, /document-release, /codex, /careful, /freeze, /guard, /unfreeze, /gstack-upgrade, and tells Claude that if gstack skills aren't working, run `cd .claude/skills/gstack && ./setup` to build the binary and register skills. @@ -69,11 +76,23 @@ Or let setup auto-detect which agents you have installed: ```bash git clone https://github.com/garrytan/gstack.git ~/gstack -cd ~/gstack && ./setup --host auto +cd ~/gstack && ./setup --host auto --scope user ``` This installs to `~/.claude/skills/gstack` and/or `~/.codex/skills/gstack` depending on what's available. All 21 skills work across all supported agents. Hook-based safety skills (careful, freeze, guard) use inline safety advisory prose on non-Claude hosts. +### Evaluate in one repo without touching your global profile + +If you want to try gstack in a single project first, install it into that workspace only: + +```bash +git clone https://github.com/garrytan/gstack.git ~/gstack +cd ~/gstack && ./setup --host auto --scope workspace --project-root /path/to/project +``` + +That writes skills to `/path/to/project/.claude/skills/` and `/path/to/project/.agents/skills/` instead of `~/.claude/skills/` or `~/.codex/skills/`. +Generated skills prefer those project-local runtime assets when present, so you can test gstack in one repo without first wiring a global profile. + ## See it work ``` diff --git a/SKILL.md b/SKILL.md index 46b7a558b..c18164885 100644 --- a/SKILL.md +++ b/SKILL.md @@ -51,20 +51,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -72,13 +72,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"gstack","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -104,7 +104,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -115,8 +115,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -242,7 +242,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/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/browse/SKILL.md b/browse/SKILL.md index 2acf60b0e..d088d0f16 100644 --- a/browse/SKILL.md +++ b/browse/SKILL.md @@ -20,20 +20,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -41,13 +41,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"browse","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -73,7 +73,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -84,8 +84,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -211,7 +211,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/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/codex/SKILL.md b/codex/SKILL.md index 77705f7e1..6b59ee742 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -21,20 +21,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -42,13 +42,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"codex","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -74,7 +74,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -85,8 +85,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -212,7 +212,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -347,7 +347,7 @@ CROSS-MODEL ANALYSIS: 7. Persist the review result: ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"codex-review","timestamp":"TIMESTAMP","status":"STATUS","gate":"GATE","findings":N}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"codex-review","timestamp":"TIMESTAMP","status":"STATUS","gate":"GATE","findings":N}' ``` Substitute: TIMESTAMP (ISO 8601), STATUS ("clean" if PASS, "issues_found" if FAIL), diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index cc21fa7e4..1ca743941 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -25,20 +25,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -46,13 +46,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"design-consultation","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -78,7 +78,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -89,8 +89,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -216,7 +216,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -256,7 +256,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) +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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-review/SKILL.md b/design-review/SKILL.md index cbc0d5e87..458c9b4d2 100644 --- a/design-review/SKILL.md +++ b/design-review/SKILL.md @@ -25,20 +25,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -46,13 +46,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"design-review","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -78,7 +78,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -89,8 +89,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -216,7 +216,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -703,7 +703,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 +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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` @@ -921,7 +921,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 +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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/document-release/SKILL.md b/document-release/SKILL.md index d71d5d3be..f36db2269 100644 --- a/document-release/SKILL.md +++ b/document-release/SKILL.md @@ -22,20 +22,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -43,13 +43,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"document-release","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -75,7 +75,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -86,8 +86,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -213,7 +213,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/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 6dcc1f7c2..410aa754c 100644 --- a/gstack-upgrade/SKILL.md +++ b/gstack-upgrade/SKILL.md @@ -28,7 +28,7 @@ First, check if auto-upgrade is enabled: ```bash _AUTO="" [ "${GSTACK_AUTO_UPGRADE:-}" = "1" ] && _AUTO="true" -[ -z "$_AUTO" ] && _AUTO=$(~/.claude/skills/gstack/bin/gstack-config get auto_upgrade 2>/dev/null || true) +[ -z "$_AUTO" ] && _AUTO=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get auto_upgrade 2>/dev/null || true) echo "AUTO_UPGRADE=$_AUTO" ``` @@ -42,7 +42,7 @@ echo "AUTO_UPGRADE=$_AUTO" **If "Always keep me up to date":** ```bash -~/.claude/skills/gstack/bin/gstack-config set auto_upgrade true +$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set auto_upgrade true ``` Tell user: "Auto-upgrade enabled. Future updates will install automatically." Then proceed to Step 2. @@ -68,9 +68,9 @@ Tell user the snooze duration: "Next reminder in 24h" (or 48h or 1 week, dependi **If "Never ask again":** ```bash -~/.claude/skills/gstack/bin/gstack-config set update_check false +$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set update_check false ``` -Tell user: "Update checks disabled. Run `~/.claude/skills/gstack/bin/gstack-config set update_check true` to re-enable." +Tell user: "Update checks disabled. Run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set update_check true` to re-enable." Continue with the current skill. ### Step 2: Detect install type @@ -201,8 +201,7 @@ When invoked directly as `/gstack-upgrade` (not from a preamble): 1. Force a fresh update check (bypass cache): ```bash -~/.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || \ -.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || true +$([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/skills/gstack/bin/gstack-update-check) --force 2>/dev/null || true ``` Use the output to determine if an upgrade is available. diff --git a/gstack-upgrade/SKILL.md.tmpl b/gstack-upgrade/SKILL.md.tmpl index 1d49cd1b6..0761f1709 100644 --- a/gstack-upgrade/SKILL.md.tmpl +++ b/gstack-upgrade/SKILL.md.tmpl @@ -199,8 +199,7 @@ When invoked directly as `/gstack-upgrade` (not from a preamble): 1. Force a fresh update check (bypass cache): ```bash -~/.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || \ -.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || true +~/.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || true ``` Use the output to determine if an upgrade is available. diff --git a/investigate/SKILL.md b/investigate/SKILL.md index eccce870c..425f38d7b 100644 --- a/investigate/SKILL.md +++ b/investigate/SKILL.md @@ -35,20 +35,20 @@ hooks: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -56,13 +56,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"investigate","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -88,7 +88,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -99,8 +99,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -226,7 +226,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/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/office-hours/SKILL.md b/office-hours/SKILL.md index 2a2e7583b..0b7008ad0 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -26,20 +26,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -47,13 +47,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"office-hours","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -79,7 +79,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -90,8 +90,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -217,7 +217,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -259,7 +259,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) +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.claude/skills/gstack/bin/gstack-slug) 2>/dev/null) ``` 1. Read `CLAUDE.md`, `TODOS.md` (if they exist). @@ -592,7 +592,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 +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index be25485ad..4177b0e7e 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -24,20 +24,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -45,13 +45,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-ceo-review","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -77,7 +77,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -88,8 +88,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -215,7 +215,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -324,7 +324,7 @@ Then read CLAUDE.md, TODOS.md, and any existing architecture docs. **Design doc check:** ```bash -SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") +SLUG=$($([ -x .claude/skills/gstack/browse/bin/remote-slug ] && echo .claude/skills/gstack/browse/bin/remote-slug || echo ~/.claude/skills/gstack/browse/bin/remote-slug) 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) [ -z "$DESIGN" ] && DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) @@ -519,7 +519,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 +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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: @@ -938,7 +938,7 @@ Complete table of every method that can fail, every exception class, rescued sta Any row with RESCUED=N, TEST=N, USER SEES=Silent → **CRITICAL GAP**. ### TODOS.md updates -Present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `.claude/skills/review/TODOS-format.md`. +Present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `$([ -f .claude/skills/review/TODOS-format.md ] && echo .claude/skills/review/TODOS-format.md || echo ~/.claude/skills/review/TODOS-format.md)`. For each TODO, describe: * **What:** One-line description of the work. @@ -1013,7 +1013,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) +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.claude/skills/gstack/bin/gstack-slug) 2>/dev/null) rm -f ~/.gstack/projects/$SLUG/*-$BRANCH-ceo-handoff-*.md 2>/dev/null || true ``` @@ -1028,7 +1028,7 @@ the same pattern. The review dashboard depends on this data. Skipping this command breaks the review readiness dashboard in /ship. ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-ceo-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"plan-ceo-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' ``` Before running this command, substitute the placeholder values from the Completion Summary you just produced: @@ -1044,7 +1044,7 @@ Before running this command, substitute the placeholder values from the Completi After completing the review, read the review log and config to display the dashboard. ```bash -~/.claude/skills/gstack/bin/gstack-review-read +$([ -x .claude/skills/gstack/bin/gstack-review-read ] && echo .claude/skills/gstack/bin/gstack-review-read || echo ~/.claude/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md index 1483e6e8a..ea5c9707f 100644 --- a/plan-design-review/SKILL.md +++ b/plan-design-review/SKILL.md @@ -23,20 +23,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -44,13 +44,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-design-review","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -76,7 +76,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -87,8 +87,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -214,7 +214,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -496,7 +496,7 @@ the same pattern. The review dashboard depends on this data. Skipping this command breaks the review readiness dashboard in /ship. ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-design-review","timestamp":"TIMESTAMP","status":"STATUS","overall_score":N,"unresolved":N,"decisions_made":N,"commit":"COMMIT"}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"plan-design-review","timestamp":"TIMESTAMP","status":"STATUS","overall_score":N,"unresolved":N,"decisions_made":N,"commit":"COMMIT"}' ``` Substitute values from the Completion Summary: @@ -512,7 +512,7 @@ Substitute values from the Completion Summary: After completing the review, read the review log and config to display the dashboard. ```bash -~/.claude/skills/gstack/bin/gstack-review-read +$([ -x .claude/skills/gstack/bin/gstack-review-read ] && echo .claude/skills/gstack/bin/gstack-review-read || echo ~/.claude/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index 63fda40b3..994b07eed 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -23,20 +23,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -44,13 +44,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"plan-eng-review","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -76,7 +76,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -87,8 +87,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -214,7 +214,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -270,7 +270,7 @@ When evaluating architecture, think "boring by default." When reviewing tests, t ### Design Doc Check ```bash -SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") +SLUG=$($([ -x .claude/skills/gstack/browse/bin/remote-slug ] && echo .claude/skills/gstack/browse/bin/remote-slug || echo ~/.claude/skills/gstack/browse/bin/remote-slug) 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) [ -z "$DESIGN" ] && DESIGN=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) @@ -372,7 +372,7 @@ For LLM/prompt changes: check the "Prompt/LLM changes" file patterns listed in C After producing the test diagram, write a test plan artifact to the project directory so `/qa` and `/qa-only` can consume it as primary test input (replacing the lossy git-diff heuristic): ```bash -source <(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.claude/skills/gstack/bin/gstack-slug) 2>/dev/null) && mkdir -p ~/.gstack/projects/$SLUG USER=$(whoami) DATETIME=$(date +%Y%m%d-%H%M%S) ``` @@ -428,7 +428,7 @@ Every plan review MUST produce a "NOT in scope" section listing work that was co List existing code/flows that already partially solve sub-problems in this plan, and whether the plan reuses them or unnecessarily rebuilds them. ### TODOS.md updates -After all review sections are complete, present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `.claude/skills/review/TODOS-format.md`. +After all review sections are complete, present each potential TODO as its own individual AskUserQuestion. Never batch TODOs — one per question. Never silently skip this step. Follow the format in `$([ -f .claude/skills/review/TODOS-format.md ] && echo .claude/skills/review/TODOS-format.md || echo ~/.claude/skills/review/TODOS-format.md)`. For each TODO, describe: * **What:** One-line description of the work. @@ -486,7 +486,7 @@ the same pattern. The review dashboard depends on this data. Skipping this command breaks the review readiness dashboard in /ship. ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"plan-eng-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"plan-eng-review","timestamp":"TIMESTAMP","status":"STATUS","unresolved":N,"critical_gaps":N,"mode":"MODE","commit":"COMMIT"}' ``` Substitute values from the Completion Summary: @@ -502,7 +502,7 @@ Substitute values from the Completion Summary: After completing the review, read the review log and config to display the dashboard. ```bash -~/.claude/skills/gstack/bin/gstack-review-read +$([ -x .claude/skills/gstack/bin/gstack-review-read ] && echo .claude/skills/gstack/bin/gstack-review-read || echo ~/.claude/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: diff --git a/qa-only/SKILL.md b/qa-only/SKILL.md index 1d2479d17..551a892ef 100644 --- a/qa-only/SKILL.md +++ b/qa-only/SKILL.md @@ -19,20 +19,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -40,13 +40,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"qa-only","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -72,7 +72,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -83,8 +83,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -210,7 +210,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -274,7 +274,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) + source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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 @@ -570,7 +570,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 +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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 b/qa/SKILL.md index 92799a0d0..f2eb0ee64 100644 --- a/qa/SKILL.md +++ b/qa/SKILL.md @@ -26,20 +26,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -47,13 +47,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"qa","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -79,7 +79,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -90,8 +90,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -217,7 +217,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -478,7 +478,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) + source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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 @@ -942,7 +942,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 +source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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/retro/SKILL.md b/retro/SKILL.md index ff4f7283c..b458d3385 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -20,20 +20,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -41,13 +41,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"retro","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -73,7 +73,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -84,8 +84,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -211,7 +211,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/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/review/SKILL.md b/review/SKILL.md index 4a646f6ea..6410dc612 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -21,20 +21,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -42,13 +42,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"review","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -74,7 +74,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -85,8 +85,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -212,7 +212,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -291,7 +291,7 @@ Before reviewing code quality, check: **did they build what was requested — no ## Step 2: Read the checklist -Read `.claude/skills/review/checklist.md`. +Read `$([ -f .claude/skills/review/checklist.md ] && echo .claude/skills/review/checklist.md || echo ~/.claude/skills/review/checklist.md)`. **If the file cannot be read, STOP and report the error.** Do not proceed without the checklist. @@ -299,7 +299,7 @@ Read `.claude/skills/review/checklist.md`. ## Step 2.5: Check for Greptile review comments -Read `.claude/skills/review/greptile-triage.md` and follow the fetch, filter, classify, and **escalation detection** steps. +Read `$([ -f .claude/skills/review/greptile-triage.md ] && echo .claude/skills/review/greptile-triage.md || echo ~/.claude/skills/review/greptile-triage.md)` and follow the fetch, filter, classify, and **escalation detection** steps. **If no PR exists, `gh` fails, API returns an error, or there are zero Greptile comments:** Skip this step silently. Greptile integration is additive — the review works without it. @@ -339,7 +339,7 @@ Follow the output format specified in the checklist. Respect the suppressions Check if the diff touches frontend files using `gstack-diff-scope`: ```bash -source <(~/.claude/skills/gstack/bin/gstack-diff-scope 2>/dev/null) +source <($([ -x .claude/skills/gstack/bin/gstack-diff-scope ] && echo .claude/skills/gstack/bin/gstack-diff-scope || echo ~/.claude/skills/gstack/bin/gstack-diff-scope) 2>/dev/null) ``` **If `SCOPE_FRONTEND=false`:** Skip design review silently. No output. @@ -348,7 +348,7 @@ source <(~/.claude/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 1. **Check for DESIGN.md.** If `DESIGN.md` or `design-system.md` exists in the repo root, read it. All design findings are calibrated against it — patterns blessed in DESIGN.md are not flagged. If not found, use universal design principles. -2. **Read `.claude/skills/review/design-checklist.md`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." +2. **Read `$([ -f .claude/skills/review/design-checklist.md ] && echo .claude/skills/review/design-checklist.md || echo ~/.claude/skills/review/design-checklist.md)`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." 3. **Read each changed frontend file** (full file, not just diff hunks). Frontend files are identified by the patterns listed in the checklist. @@ -362,7 +362,7 @@ source <(~/.claude/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 6. **Log the result** for the Review Readiness Dashboard: ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' ``` Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "issues_found", N = total findings, M = auto-fixed count, COMMIT = output of `git rev-parse --short HEAD`. @@ -489,7 +489,7 @@ Check if the Codex CLI is available and read the user's Codex review preference: ```bash which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE" -CODEX_REVIEWS_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true) +CODEX_REVIEWS_CFG=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get codex_reviews 2>/dev/null || true) echo "CODEX_REVIEWS: ${CODEX_REVIEWS_CFG:-not_set}" ``` @@ -511,14 +511,14 @@ C) No thanks, don't ask me again If the user chooses A: persist the setting and run both: ```bash -~/.claude/skills/gstack/bin/gstack-config set codex_reviews enabled +$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set codex_reviews enabled ``` If the user chooses B: run both this time but do not persist any setting. If the user chooses C: persist the opt-out and skip: ```bash -~/.claude/skills/gstack/bin/gstack-config set codex_reviews disabled +$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set codex_reviews disabled ``` Then skip this step. Continue to the next step. @@ -576,7 +576,7 @@ Before persisting the gate result, check for errors. All errors are non-blocking **Only if codex produced a real review (non-empty stdout):** Persist the code review result: ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"codex-review","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","status":"STATUS","gate":"GATE","commit":"'"$(git rev-parse --short HEAD)"'"}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"codex-review","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","status":"STATUS","gate":"GATE","commit":"'"$(git rev-parse --short HEAD)"'"}' ``` Substitute: STATUS ("clean" if PASS, "issues_found" if FAIL), GATE ("pass" or "fail"). diff --git a/scripts/gen-skill-docs.ts b/scripts/gen-skill-docs.ts index 8bb16bf96..f3ed9e997 100644 --- a/scripts/gen-skill-docs.ts +++ b/scripts/gen-skill-docs.ts @@ -32,7 +32,11 @@ const HOST: Host = (() => { interface HostPaths { skillRoot: string; + homeSkillRoot: string; localSkillRoot: string; + localSkillsDir: string; + globalReviewDir: string; + localReviewDir: string; binDir: string; browseDir: string; } @@ -40,13 +44,21 @@ interface HostPaths { const HOST_PATHS: Record = { claude: { skillRoot: '~/.claude/skills/gstack', + homeSkillRoot: '$HOME/.claude/skills/gstack', localSkillRoot: '.claude/skills/gstack', + localSkillsDir: '.claude/skills', + globalReviewDir: '~/.claude/skills/review', + localReviewDir: '.claude/skills/review', binDir: '~/.claude/skills/gstack/bin', browseDir: '~/.claude/skills/gstack/browse/dist', }, codex: { skillRoot: '~/.codex/skills/gstack', + homeSkillRoot: '$HOME/.codex/skills/gstack', localSkillRoot: '.agents/skills/gstack', + localSkillsDir: '.agents/skills', + globalReviewDir: '~/.codex/skills/gstack/review', + localReviewDir: '.agents/skills/gstack/review', binDir: '~/.codex/skills/gstack/bin', browseDir: '~/.codex/skills/gstack/browse/dist', }, @@ -60,6 +72,67 @@ interface TemplateContext { paths: HostPaths; } +let replacementCounter = 0; + +function replacePathVariants(content: string, variants: string[], replacement: string): string { + const marker = `__GSTACK_PATH_${replacementCounter++}__`; + let updated = content; + let replaced = false; + + for (const variant of variants) { + if (!variant) continue; + if (!updated.includes(variant)) continue; + updated = updated.split(variant).join(marker); + replaced = true; + } + + return replaced ? updated.split(marker).join(replacement) : updated; +} + +function commandPathExpr(localPath: string, globalPath: string): string { + return `$([ -x ${localPath} ] && echo ${localPath} || echo ${globalPath})`; +} + +function filePathExpr(localPath: string, globalPath: string): string { + return `$([ -f ${localPath} ] && echo ${localPath} || echo ${globalPath})`; +} + +function applyRuntimeFallbacks(content: string, ctx: TemplateContext): string { + const runtimeCommands = [ + 'gstack-config', + 'gstack-diff-scope', + 'gstack-review-log', + 'gstack-review-read', + 'gstack-slug', + 'gstack-telemetry-log', + 'gstack-update-check', + ]; + + for (const command of runtimeCommands) { + const globalPath = `${ctx.paths.skillRoot}/bin/${command}`; + const homePath = `${ctx.paths.homeSkillRoot}/bin/${command}`; + const localPath = `${ctx.paths.localSkillRoot}/bin/${command}`; + content = replacePathVariants(content, [globalPath, homePath], commandPathExpr(localPath, globalPath)); + } + + const globalRemoteSlug = `${ctx.paths.skillRoot}/browse/bin/remote-slug`; + const localRemoteSlug = `${ctx.paths.localSkillRoot}/browse/bin/remote-slug`; + content = replacePathVariants(content, [globalRemoteSlug], commandPathExpr(localRemoteSlug, globalRemoteSlug)); + + const reviewDocs = ['checklist.md', 'design-checklist.md', 'greptile-triage.md', 'TODOS-format.md']; + for (const doc of reviewDocs) { + const globalPath = `${ctx.paths.globalReviewDir}/${doc}`; + const localPath = `${ctx.paths.localReviewDir}/${doc}`; + content = replacePathVariants(content, [globalPath, localPath], filePathExpr(localPath, globalPath)); + } + + const globalUpgradeSkill = `${ctx.paths.skillRoot}/gstack-upgrade/SKILL.md`; + const localUpgradeSkill = `${ctx.paths.localSkillsDir}/gstack-upgrade/SKILL.md`; + content = replacePathVariants(content, [globalUpgradeSkill], filePathExpr(localUpgradeSkill, globalUpgradeSkill)); + + return content; +} + // ─── Placeholder Resolvers ────────────────────────────────── function generateCommandReference(_ctx: TemplateContext): string { @@ -141,7 +214,7 @@ function generatePreambleBash(ctx: TemplateContext): string { return `## Preamble (run first) \`\`\`bash -_UPD=$(${ctx.paths.binDir}/gstack-update-check 2>/dev/null || ${ctx.paths.localSkillRoot}/bin/gstack-update-check 2>/dev/null || true) +_UPD=$(${ctx.paths.binDir}/gstack-update-check 2>/dev/null || true) [ -n "$_UPD" ] && echo "$_UPD" || true mkdir -p ~/.gstack/sessions touch ~/.gstack/sessions/"$PPID" @@ -1719,12 +1792,15 @@ function processTemplate(tmplPath: string, host: Host = 'claude'): { outputPath: } // Replace remaining hardcoded Claude paths with host-appropriate paths + content = content.replace(/\$HOME\/\.claude\/skills\/gstack/g, ctx.paths.homeSkillRoot); content = content.replace(/~\/\.claude\/skills\/gstack/g, ctx.paths.skillRoot); content = content.replace(/\.claude\/skills\/gstack/g, ctx.paths.localSkillRoot); content = content.replace(/\.claude\/skills\/review/g, '.agents/skills/gstack/review'); content = content.replace(/\.claude\/skills/g, '.agents/skills'); } + content = applyRuntimeFallbacks(content, ctx); + // Prepend generated header (after frontmatter) const header = GENERATED_HEADER.replace('{{SOURCE}}', path.basename(tmplPath)); const fmEnd = content.indexOf('---', content.indexOf('---') + 3); diff --git a/setup b/setup index 09d2282fd..cbb26f41a 100755 --- a/setup +++ b/setup @@ -17,12 +17,18 @@ case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*|Windows_NT) IS_WINDOWS=1 ;; esac -# ─── Parse --host flag ───────────────────────────────────────── +# ─── Parse flags ─────────────────────────────────────────────── HOST="claude" +SCOPE="auto" +PROJECT_ROOT="" while [ $# -gt 0 ]; do case "$1" in --host) HOST="$2"; shift 2 ;; --host=*) HOST="${1#--host=}"; shift ;; + --scope) SCOPE="$2"; shift 2 ;; + --scope=*) SCOPE="${1#--scope=}"; shift ;; + --project-root) PROJECT_ROOT="$2"; shift 2 ;; + --project-root=*) PROJECT_ROOT="${1#--project-root=}"; shift ;; *) shift ;; esac done @@ -32,6 +38,11 @@ case "$HOST" in *) echo "Unknown --host value: $HOST (expected claude, codex, or auto)" >&2; exit 1 ;; esac +case "$SCOPE" in + auto|user|workspace) ;; + *) echo "Unknown --scope value: $SCOPE (expected auto, user, or workspace)" >&2; exit 1 ;; +esac + # For auto: detect which agents are installed INSTALL_CLAUDE=0 INSTALL_CODEX=0 @@ -48,6 +59,39 @@ elif [ "$HOST" = "codex" ]; then INSTALL_CODEX=1 fi +detect_vendored_workspace_root() { + case "$GSTACK_DIR" in + */.claude/skills/gstack|*/.agents/skills/gstack) + dirname "$(dirname "$(dirname "$GSTACK_DIR")")" + ;; + *) + return 1 + ;; + esac +} + +resolve_workspace_root() { + if [ -n "$PROJECT_ROOT" ]; then + ( + cd "$PROJECT_ROOT" + pwd + ) + return + fi + + if vendored_root="$(detect_vendored_workspace_root 2>/dev/null)"; then + echo "$vendored_root" + return + fi + + git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || pwd +} + +WORKSPACE_ROOT="" +if [ "$SCOPE" = "workspace" ]; then + WORKSPACE_ROOT="$(resolve_workspace_root)" +fi + ensure_playwright_browser() { if [ "$IS_WINDOWS" -eq 1 ]; then # On Windows, Bun can't launch Chromium due to broken pipe handling @@ -65,27 +109,29 @@ ensure_playwright_browser() { } # 1. Build browse binary if needed (smart rebuild: stale sources, package.json, lock) -NEEDS_BUILD=0 -if [ ! -x "$BROWSE_BIN" ]; then - NEEDS_BUILD=1 -elif [ -n "$(find "$GSTACK_DIR/browse/src" -type f -newer "$BROWSE_BIN" -print -quit 2>/dev/null)" ]; then - NEEDS_BUILD=1 -elif [ "$GSTACK_DIR/package.json" -nt "$BROWSE_BIN" ]; then - NEEDS_BUILD=1 -elif [ -f "$GSTACK_DIR/bun.lock" ] && [ "$GSTACK_DIR/bun.lock" -nt "$BROWSE_BIN" ]; then - NEEDS_BUILD=1 -fi +if [ "${GSTACK_SETUP_SKIP_BUILD:-0}" != "1" ]; then + NEEDS_BUILD=0 + if [ ! -x "$BROWSE_BIN" ]; then + NEEDS_BUILD=1 + elif [ -n "$(find "$GSTACK_DIR/browse/src" -type f -newer "$BROWSE_BIN" -print -quit 2>/dev/null)" ]; then + NEEDS_BUILD=1 + elif [ "$GSTACK_DIR/package.json" -nt "$BROWSE_BIN" ]; then + NEEDS_BUILD=1 + elif [ -f "$GSTACK_DIR/bun.lock" ] && [ "$GSTACK_DIR/bun.lock" -nt "$BROWSE_BIN" ]; then + NEEDS_BUILD=1 + fi -if [ "$NEEDS_BUILD" -eq 1 ]; then - echo "Building browse binary..." - ( - cd "$GSTACK_DIR" - bun install - bun run build - ) - # Safety net: write .version if build script didn't (e.g., git not available during build) - if [ ! -f "$GSTACK_DIR/browse/dist/.version" ]; then - git -C "$GSTACK_DIR" rev-parse HEAD > "$GSTACK_DIR/browse/dist/.version" 2>/dev/null || true + if [ "$NEEDS_BUILD" -eq 1 ]; then + echo "Building browse binary..." + ( + cd "$GSTACK_DIR" + bun install + bun run build + ) + # Safety net: write .version if build script didn't (e.g., git not available during build) + if [ ! -f "$GSTACK_DIR/browse/dist/.version" ]; then + git -C "$GSTACK_DIR" rev-parse HEAD > "$GSTACK_DIR/browse/dist/.version" 2>/dev/null || true + fi fi fi @@ -95,44 +141,101 @@ if [ ! -x "$BROWSE_BIN" ]; then fi # 2. Ensure Playwright's Chromium is available -if ! ensure_playwright_browser; then - echo "Installing Playwright Chromium..." - ( - cd "$GSTACK_DIR" - bunx playwright install chromium - ) - - if [ "$IS_WINDOWS" -eq 1 ]; then - # On Windows, Node.js launches Chromium (not Bun — see oven-sh/bun#4253). - # Ensure playwright is importable by Node from the gstack directory. - if ! command -v node >/dev/null 2>&1; then - echo "gstack setup failed: Node.js is required on Windows (Bun cannot launch Chromium due to a pipe bug)" >&2 - echo " Install Node.js: https://nodejs.org/" >&2 - exit 1 - fi - echo "Windows detected — verifying Node.js can load Playwright..." +if [ "${GSTACK_SETUP_SKIP_BROWSER:-0}" != "1" ]; then + if ! ensure_playwright_browser; then + echo "Installing Playwright Chromium..." ( cd "$GSTACK_DIR" - # Bun's node_modules already has playwright; verify Node can require it - node -e "require('playwright')" 2>/dev/null || npm install --no-save playwright + bunx playwright install chromium ) + + if [ "$IS_WINDOWS" -eq 1 ]; then + # On Windows, Node.js launches Chromium (not Bun — see oven-sh/bun#4253). + # Ensure playwright is importable by Node from the gstack directory. + if ! command -v node >/dev/null 2>&1; then + echo "gstack setup failed: Node.js is required on Windows (Bun cannot launch Chromium due to a pipe bug)" >&2 + echo " Install Node.js: https://nodejs.org/" >&2 + exit 1 + fi + echo "Windows detected — verifying Node.js can load Playwright..." + ( + cd "$GSTACK_DIR" + # Bun's node_modules already has playwright; verify Node can require it + node -e "require('playwright')" 2>/dev/null || npm install --no-save playwright + ) + fi fi -fi -if ! ensure_playwright_browser; then - if [ "$IS_WINDOWS" -eq 1 ]; then - echo "gstack setup failed: Playwright Chromium could not be launched via Node.js" >&2 - echo " This is a known issue with Bun on Windows (oven-sh/bun#4253)." >&2 - echo " Ensure Node.js is installed and 'node -e \"require('playwright')\"' works." >&2 - else - echo "gstack setup failed: Playwright Chromium could not be launched" >&2 + if ! ensure_playwright_browser; then + if [ "$IS_WINDOWS" -eq 1 ]; then + echo "gstack setup failed: Playwright Chromium could not be launched via Node.js" >&2 + echo " This is a known issue with Bun on Windows (oven-sh/bun#4253)." >&2 + echo " Ensure Node.js is installed and 'node -e \"require('playwright')\"' works." >&2 + else + echo "gstack setup failed: Playwright Chromium could not be launched" >&2 + fi + exit 1 fi - exit 1 fi # 3. Ensure ~/.gstack global state directory exists mkdir -p "$HOME/.gstack/projects" +ensure_root_link() { + local link_path="$1" + local target_path="$2" + local label="$3" + mkdir -p "$(dirname "$link_path")" + + if [ -L "$link_path" ] || [ ! -e "$link_path" ]; then + ln -snf "$target_path" "$link_path" + return 0 + fi + + local resolved="" + resolved="$(cd "$link_path" 2>/dev/null && pwd || true)" + if [ "$resolved" = "$target_path" ]; then + return 0 + fi + + echo "Error: $label already exists at $link_path and points somewhere else." >&2 + echo " Remove it, rename it, or use --scope workspace to keep this install isolated." >&2 + return 1 +} + +ensure_managed_dir() { + local dir_path="$1" + local label="$2" + mkdir -p "$(dirname "$dir_path")" + + if [ -L "$dir_path" ]; then + rm -f "$dir_path" + mkdir -p "$dir_path" + return 0 + fi + + if [ ! -e "$dir_path" ]; then + mkdir -p "$dir_path" + return 0 + fi + + if [ -d "$dir_path" ]; then + return 0 + fi + + echo "Error: $label already exists at $dir_path and is not a directory." >&2 + return 1 +} + +link_sidecar_entry() { + local src="$1" + local dst="$2" + mkdir -p "$(dirname "$dst")" + if [ -L "$dst" ] || [ ! -e "$dst" ]; then + ln -snf "$src" "$dst" + fi +} + # ─── Helper: link Claude skill subdirectories into a skills parent directory ── link_claude_skill_dirs() { local gstack_dir="$1" @@ -173,6 +276,7 @@ link_codex_skill_dirs() { for skill_dir in "$agents_dir"/gstack*/; do if [ -f "$skill_dir/SKILL.md" ]; then skill_name="$(basename "$skill_dir")" + [ "$skill_name" = "gstack" ] && continue target="$skills_dir/$skill_name" # Create or update symlink if [ -L "$target" ] || [ ! -e "$target" ]; then @@ -188,66 +292,120 @@ link_codex_skill_dirs() { # ─── Helper: create .agents/skills/gstack/ sidecar symlinks ────────── # Codex/Gemini/Cursor read skills from .agents/skills/. We link runtime -# assets (bin/, browse/dist/, review/, qa/, etc.) so skill templates can +# assets (bin/, browse/dist/, review docs, etc.) so skill templates can # resolve paths like $SKILL_ROOT/review/design-checklist.md. create_agents_sidecar() { local repo_root="$1" local agents_gstack="$repo_root/.agents/skills/gstack" - mkdir -p "$agents_gstack" + ensure_managed_dir "$agents_gstack" "Codex sidecar" || return 1 + + if [ -f "$GSTACK_DIR/.agents/skills/gstack/SKILL.md" ]; then + link_sidecar_entry "$GSTACK_DIR/.agents/skills/gstack/SKILL.md" "$agents_gstack/SKILL.md" + fi - # Sidecar directories that skills reference at runtime - for asset in bin browse review qa; do + for asset in VERSION bin browse; do local src="$GSTACK_DIR/$asset" local dst="$agents_gstack/$asset" if [ -d "$src" ] || [ -f "$src" ]; then - if [ -L "$dst" ] || [ ! -e "$dst" ]; then - ln -snf "$src" "$dst" - fi + link_sidecar_entry "$src" "$dst" fi done + + local review_dir="$agents_gstack/review" + if [ ! -e "$review_dir" ]; then + mkdir -p "$review_dir" + fi + if [ -d "$review_dir" ]; then + for doc in checklist.md design-checklist.md greptile-triage.md TODOS-format.md; do + local src="$GSTACK_DIR/review/$doc" + local dst="$review_dir/$doc" + if [ -f "$src" ]; then + link_sidecar_entry "$src" "$dst" + fi + done + fi } # 4. Install for Claude (default) SKILLS_BASENAME="$(basename "$SKILLS_DIR")" if [ "$INSTALL_CLAUDE" -eq 1 ]; then - if [ "$SKILLS_BASENAME" = "skills" ]; then - link_claude_skill_dirs "$GSTACK_DIR" "$SKILLS_DIR" - echo "gstack ready (claude)." - echo " browse: $BROWSE_BIN" - else - echo "gstack ready (claude)." - echo " browse: $BROWSE_BIN" - echo " (skipped skill symlinks — not inside .claude/skills/)" - fi + case "$SCOPE" in + user) + CLAUDE_SKILLS="$HOME/.claude/skills" + ensure_root_link "$CLAUDE_SKILLS/gstack" "$GSTACK_DIR" "Claude install" + link_claude_skill_dirs "$GSTACK_DIR" "$CLAUDE_SKILLS" + echo "gstack ready (claude user)." + echo " browse: $BROWSE_BIN" + echo " claude skills: $CLAUDE_SKILLS" + ;; + workspace) + CLAUDE_SKILLS="$WORKSPACE_ROOT/.claude/skills" + ensure_root_link "$CLAUDE_SKILLS/gstack" "$GSTACK_DIR" "Claude install" + link_claude_skill_dirs "$GSTACK_DIR" "$CLAUDE_SKILLS" + echo "gstack ready (claude workspace)." + echo " browse: $BROWSE_BIN" + echo " claude skills: $CLAUDE_SKILLS" + ;; + auto) + if [ "$SKILLS_BASENAME" = "skills" ]; then + link_claude_skill_dirs "$GSTACK_DIR" "$SKILLS_DIR" + echo "gstack ready (claude)." + echo " browse: $BROWSE_BIN" + else + echo "gstack ready (claude)." + echo " browse: $BROWSE_BIN" + echo " (skipped skill symlinks — not inside .claude/skills/)" + fi + ;; + esac fi # 5. Install for Codex if [ "$INSTALL_CODEX" -eq 1 ]; then - CODEX_SKILLS="$HOME/.codex/skills" - CODEX_GSTACK="$CODEX_SKILLS/gstack" - mkdir -p "$CODEX_SKILLS" + case "$SCOPE" in + user) + CODEX_SKILLS="$HOME/.codex/skills" + CODEX_GSTACK="$CODEX_SKILLS/gstack" + mkdir -p "$CODEX_SKILLS" + ensure_root_link "$CODEX_GSTACK" "$GSTACK_DIR" "Codex install" + link_codex_skill_dirs "$GSTACK_DIR" "$CODEX_SKILLS" + echo "gstack ready (codex user)." + echo " browse: $BROWSE_BIN" + echo " codex skills: $CODEX_SKILLS" + ;; + workspace) + CODEX_SKILLS="$WORKSPACE_ROOT/.agents/skills" + mkdir -p "$CODEX_SKILLS" + link_codex_skill_dirs "$GSTACK_DIR" "$CODEX_SKILLS" + create_agents_sidecar "$WORKSPACE_ROOT" + echo "gstack ready (codex workspace)." + echo " browse: $BROWSE_BIN" + echo " codex skills: $CODEX_SKILLS" + ;; + auto) + CODEX_SKILLS="$HOME/.codex/skills" + CODEX_GSTACK="$CODEX_SKILLS/gstack" + mkdir -p "$CODEX_SKILLS" - # Symlink gstack source for runtime assets (bin/, browse/dist/) - if [ -L "$CODEX_GSTACK" ] || [ ! -e "$CODEX_GSTACK" ]; then - ln -snf "$GSTACK_DIR" "$CODEX_GSTACK" - fi - # Install generated Codex-format skills (not Claude source dirs) - link_codex_skill_dirs "$GSTACK_DIR" "$CODEX_SKILLS" + # Symlink gstack source for runtime assets (bin/, browse/dist/) + if [ -L "$CODEX_GSTACK" ] || [ ! -e "$CODEX_GSTACK" ]; then + ln -snf "$GSTACK_DIR" "$CODEX_GSTACK" + fi + # Install generated Codex-format skills (not Claude source dirs) + link_codex_skill_dirs "$GSTACK_DIR" "$CODEX_SKILLS" - echo "gstack ready (codex)." - echo " browse: $BROWSE_BIN" - echo " codex skills: $CODEX_SKILLS" + echo "gstack ready (codex)." + echo " browse: $BROWSE_BIN" + echo " codex skills: $CODEX_SKILLS" + ;; + esac fi # 6. Create .agents/ sidecar symlinks (useful for Codex/Gemini/Cursor workspace-local) -if [ "$INSTALL_CODEX" -eq 1 ]; then - # Detect repo root: if we're inside a skills directory, go up two levels - if [ "$SKILLS_BASENAME" = "skills" ]; then - REPO_ROOT="$(dirname "$SKILLS_DIR")" - else - REPO_ROOT="$GSTACK_DIR" +if [ "$INSTALL_CODEX" -eq 1 ] && [ "$SCOPE" = "auto" ]; then + if REPO_ROOT="$(detect_vendored_workspace_root 2>/dev/null)"; then + create_agents_sidecar "$REPO_ROOT" fi - create_agents_sidecar "$REPO_ROOT" fi # 7. First-time welcome + legacy cleanup diff --git a/setup-browser-cookies/SKILL.md b/setup-browser-cookies/SKILL.md index ac2d873cb..5b37e659d 100644 --- a/setup-browser-cookies/SKILL.md +++ b/setup-browser-cookies/SKILL.md @@ -17,20 +17,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -38,13 +38,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"setup-browser-cookies","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -70,7 +70,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -81,8 +81,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -208,7 +208,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/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/ship/SKILL.md b/ship/SKILL.md index 232a23e01..1102258cf 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -20,20 +20,20 @@ allowed-tools: ## Preamble (run first) ```bash -_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) +_UPD=$($([ -x .claude/skills/gstack/bin/gstack-update-check ] && echo .claude/skills/gstack/bin/gstack-update-check || echo ~/.claude/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=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true) -_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") +_CONTRIB=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get gstack_contributor 2>/dev/null || true) +_PROACTIVE=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" -_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +_TEL=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/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)" @@ -41,13 +41,13 @@ echo "TELEMETRY: ${_TEL:-off}" echo "TEL_PROMPTED: $_TEL_PROMPTED" mkdir -p ~/.gstack/analytics echo '{"skill":"ship","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" ] && ~/.claude/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" ] && $([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/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 ``` 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 `~/.claude/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 `$([ -f .claude/skills/gstack-upgrade/SKILL.md ] && echo .claude/skills/gstack-upgrade/SKILL.md || echo ~/.claude/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 `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the **Boil the Lake** principle — always do the complete @@ -73,7 +73,7 @@ Options: - A) Help gstack get better! (recommended) - B) No thanks -If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` +If A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry community` If B: ask a follow-up AskUserQuestion: @@ -84,8 +84,8 @@ Options: - A) Sure, anonymous is fine - B) No thanks, fully off -If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` -If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` +If B→A: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry anonymous` +If B→B: run `$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set telemetry off` Always run: ```bash @@ -211,7 +211,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 -~/.claude/skills/gstack/bin/gstack-telemetry-log \ +$([ -x .claude/skills/gstack/bin/gstack-telemetry-log ] && echo .claude/skills/gstack/bin/gstack-telemetry-log || echo ~/.claude/skills/gstack/bin/gstack-telemetry-log) \ --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & ``` @@ -281,7 +281,7 @@ You are running the `/ship` workflow. This is a **non-interactive, fully automat After completing the review, read the review log and config to display the dashboard. ```bash -~/.claude/skills/gstack/bin/gstack-review-read +$([ -x .claude/skills/gstack/bin/gstack-review-read ] && echo .claude/skills/gstack/bin/gstack-review-read || echo ~/.claude/skills/gstack/bin/gstack-review-read) ``` Parse the output. Find the most recent entry for each skill (plan-ceo-review, plan-eng-review, plan-design-review, design-review-lite, codex-review). Ignore entries with timestamps older than 7 days. For Design Review, show whichever is more recent between `plan-design-review` (full visual audit) and `design-review-lite` (code-level check). Append "(FULL)" or "(LITE)" to the status to distinguish. Display: @@ -323,7 +323,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) + source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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. @@ -333,11 +333,11 @@ If the Eng Review is NOT "CLEAR": - RECOMMENDATION: Choose C if the change is obviously trivial (< 20 lines, typo fix, config-only); Choose B for larger changes - Options: A) Ship anyway B) Abort — run /plan-eng-review first C) Change is too small to need eng review - If CEO Review is missing, mention as informational ("CEO Review not run — recommended for product changes") but do NOT block - - For Design Review: run `source <(~/.claude/skills/gstack/bin/gstack-diff-scope 2>/dev/null)`. If `SCOPE_FRONTEND=true` and no design review (plan-design-review or design-review-lite) exists in the dashboard, mention: "Design Review not run — this PR changes frontend code. The lite design check will run automatically in Step 3.5, but consider running /design-review for a full visual audit post-implementation." Still never block. + - For Design Review: run `source <($([ -x .claude/skills/gstack/bin/gstack-diff-scope ] && echo .claude/skills/gstack/bin/gstack-diff-scope || echo ~/.claude/skills/gstack/bin/gstack-diff-scope) 2>/dev/null)`. If `SCOPE_FRONTEND=true` and no design review (plan-design-review or design-review-lite) exists in the dashboard, mention: "Design Review not run — this PR changes frontend code. The lite design check will run automatically in Step 3.5, but consider running /design-review for a full visual audit post-implementation." Still never block. 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) + source <($([ -x .claude/skills/gstack/bin/gstack-slug ] && echo .claude/skills/gstack/bin/gstack-slug || echo ~/.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". @@ -741,7 +741,7 @@ Coverage line: `Test Coverage Audit: N new code paths. M covered (X%). K tests g Review the diff for structural issues that tests don't catch. -1. Read `.claude/skills/review/checklist.md`. If the file cannot be read, **STOP** and report the error. +1. Read `$([ -f .claude/skills/review/checklist.md ] && echo .claude/skills/review/checklist.md || echo ~/.claude/skills/review/checklist.md)`. If the file cannot be read, **STOP** and report the error. 2. Run `git diff origin/` to get the full diff (scoped to feature changes against the freshly-fetched base branch). @@ -754,7 +754,7 @@ Review the diff for structural issues that tests don't catch. Check if the diff touches frontend files using `gstack-diff-scope`: ```bash -source <(~/.claude/skills/gstack/bin/gstack-diff-scope 2>/dev/null) +source <($([ -x .claude/skills/gstack/bin/gstack-diff-scope ] && echo .claude/skills/gstack/bin/gstack-diff-scope || echo ~/.claude/skills/gstack/bin/gstack-diff-scope) 2>/dev/null) ``` **If `SCOPE_FRONTEND=false`:** Skip design review silently. No output. @@ -763,7 +763,7 @@ source <(~/.claude/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 1. **Check for DESIGN.md.** If `DESIGN.md` or `design-system.md` exists in the repo root, read it. All design findings are calibrated against it — patterns blessed in DESIGN.md are not flagged. If not found, use universal design principles. -2. **Read `.claude/skills/review/design-checklist.md`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." +2. **Read `$([ -f .claude/skills/review/design-checklist.md ] && echo .claude/skills/review/design-checklist.md || echo ~/.claude/skills/review/design-checklist.md)`.** If the file cannot be read, skip design review with a note: "Design checklist not found — skipping design review." 3. **Read each changed frontend file** (full file, not just diff hunks). Frontend files are identified by the patterns listed in the checklist. @@ -777,7 +777,7 @@ source <(~/.claude/skills/gstack/bin/gstack-diff-scope 2>/dev/null) 6. **Log the result** for the Review Readiness Dashboard: ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"design-review-lite","timestamp":"TIMESTAMP","status":"STATUS","findings":N,"auto_fixed":M,"commit":"COMMIT"}' ``` Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "issues_found", N = total findings, M = auto-fixed count, COMMIT = output of `git rev-parse --short HEAD`. @@ -810,7 +810,7 @@ Save the review output — it goes into the PR body in Step 8. ## Step 3.75: Address Greptile review comments (if PR exists) -Read `.claude/skills/review/greptile-triage.md` and follow the fetch, filter, classify, and **escalation detection** steps. +Read `$([ -f .claude/skills/review/greptile-triage.md ] && echo .claude/skills/review/greptile-triage.md || echo ~/.claude/skills/review/greptile-triage.md)` and follow the fetch, filter, classify, and **escalation detection** steps. **If no PR exists, `gh` fails, API returns an error, or there are zero Greptile comments:** Skip this step silently. Continue to Step 4. @@ -853,7 +853,7 @@ Check if the Codex CLI is available and read the user's Codex review preference: ```bash which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE" -CODEX_REVIEWS_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true) +CODEX_REVIEWS_CFG=$($([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) get codex_reviews 2>/dev/null || true) echo "CODEX_REVIEWS: ${CODEX_REVIEWS_CFG:-not_set}" ``` @@ -875,14 +875,14 @@ C) No thanks, don't ask me again If the user chooses A: persist the setting and run both: ```bash -~/.claude/skills/gstack/bin/gstack-config set codex_reviews enabled +$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set codex_reviews enabled ``` If the user chooses B: run both this time but do not persist any setting. If the user chooses C: persist the opt-out and skip: ```bash -~/.claude/skills/gstack/bin/gstack-config set codex_reviews disabled +$([ -x .claude/skills/gstack/bin/gstack-config ] && echo .claude/skills/gstack/bin/gstack-config || echo ~/.claude/skills/gstack/bin/gstack-config) set codex_reviews disabled ``` Then skip this step. Continue to the next step. @@ -940,7 +940,7 @@ Before persisting the gate result, check for errors. All errors are non-blocking **Only if codex produced a real review (non-empty stdout):** Persist the code review result: ```bash -~/.claude/skills/gstack/bin/gstack-review-log '{"skill":"codex-review","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","status":"STATUS","gate":"GATE","commit":"'"$(git rev-parse --short HEAD)"'"}' +$([ -x .claude/skills/gstack/bin/gstack-review-log ] && echo .claude/skills/gstack/bin/gstack-review-log || echo ~/.claude/skills/gstack/bin/gstack-review-log) '{"skill":"codex-review","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","status":"STATUS","gate":"GATE","commit":"'"$(git rev-parse --short HEAD)"'"}' ``` Substitute: STATUS ("clean" if PASS, "issues_found" if FAIL), GATE ("pass" or "fail"). @@ -1007,7 +1007,7 @@ Present the full output verbatim under a `CODEX SAYS (adversarial challenge):` h Cross-reference the project's TODOS.md against the changes being shipped. Mark completed items automatically; prompt only if the file is missing or disorganized. -Read `.claude/skills/review/TODOS-format.md` for the canonical format reference. +Read `$([ -f .claude/skills/review/TODOS-format.md ] && echo .claude/skills/review/TODOS-format.md || echo ~/.claude/skills/review/TODOS-format.md)` for the canonical format reference. **1. Check if TODOS.md exists** in the repository root. diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index 64b391180..b6739ef06 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -666,6 +666,12 @@ describe('Codex generation (--host codex)', () => { expect(content).toContain('.agents/skills/gstack'); }); + test('Codex runtime commands prefer project-local sidecars when present', () => { + const content = fs.readFileSync(path.join(AGENTS_DIR, 'gstack-review', 'SKILL.md'), 'utf-8'); + expect(content).toContain('$([ -x .agents/skills/gstack/bin/gstack-config ]'); + expect(content).toContain('echo ~/.codex/skills/gstack/bin/gstack-config'); + }); + // ─── Path rewriting regression tests ───────────────────────── test('sidecar paths point to .agents/skills/gstack/review/ (not gstack-review/)', () => { @@ -715,6 +721,12 @@ describe('Codex generation (--host codex)', () => { expect(content).not.toContain('.claude/skills'); }); + test('codex output keeps $HOME paths global instead of rewriting them to .agents', () => { + const content = fs.readFileSync(path.join(AGENTS_DIR, 'gstack-upgrade', 'SKILL.md'), 'utf-8'); + expect(content).toContain('$HOME/.codex/skills/gstack'); + expect(content).not.toContain('$HOME/.agents/skills/gstack'); + }); + test('path rewrite rules apply to all Codex skills with sidecar references', () => { // Verify across ALL generated skills, not just review for (const skill of CODEX_SKILLS) { @@ -814,20 +826,33 @@ describe('setup script validation', () => { expect(setupContent).toContain('claude|codex|auto'); }); + test('setup supports --scope auto|user|workspace', () => { + expect(setupContent).toContain('--scope'); + expect(setupContent).toContain('auto|user|workspace'); + }); + test('auto mode detects claude and codex binaries', () => { expect(setupContent).toContain('command -v claude'); expect(setupContent).toContain('command -v codex'); }); + test('workspace scope resolves a project root and uses project-local skill dirs', () => { + expect(setupContent).toContain('resolve_workspace_root'); + expect(setupContent).toContain('.claude/skills'); + expect(setupContent).toContain('.agents/skills'); + expect(setupContent).toContain('--project-root'); + }); + test('create_agents_sidecar links runtime assets', () => { - // Sidecar must link bin, browse, review, qa + // Sidecar must expose the root skill plus the runtime assets/datasets it needs. const fnStart = setupContent.indexOf('create_agents_sidecar()'); const fnEnd = setupContent.indexOf('}', setupContent.indexOf('done', fnStart)); const fnBody = setupContent.slice(fnStart, fnEnd); + expect(fnBody).toContain('SKILL.md'); + expect(fnBody).toContain('VERSION'); expect(fnBody).toContain('bin'); expect(fnBody).toContain('browse'); expect(fnBody).toContain('review'); - expect(fnBody).toContain('qa'); }); }); @@ -838,16 +863,18 @@ describe('telemetry', () => { expect(content).toContain('_SESSION_ID'); expect(content).toContain('TELEMETRY:'); expect(content).toContain('TEL_PROMPTED:'); - expect(content).toContain('gstack-config get telemetry'); + expect(content).toContain('get telemetry'); + expect(content).toContain('.claude/skills/gstack/bin/gstack-config'); + expect(content).toContain('~/.claude/skills/gstack/bin/gstack-config'); }); test('generated SKILL.md contains telemetry opt-in prompt', () => { const content = fs.readFileSync(path.join(ROOT, 'SKILL.md'), 'utf-8'); expect(content).toContain('.telemetry-prompted'); expect(content).toContain('Help gstack get better'); - expect(content).toContain('gstack-config set telemetry community'); - expect(content).toContain('gstack-config set telemetry anonymous'); - expect(content).toContain('gstack-config set telemetry off'); + expect(content).toContain('set telemetry community'); + expect(content).toContain('set telemetry anonymous'); + expect(content).toContain('set telemetry off'); }); test('generated SKILL.md contains telemetry epilogue', () => { diff --git a/test/setup.test.ts b/test/setup.test.ts new file mode 100644 index 000000000..d7f1ee899 --- /dev/null +++ b/test/setup.test.ts @@ -0,0 +1,150 @@ +import { describe, test, expect } from 'bun:test'; +import { spawnSync } from 'child_process'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; + +const ROOT = path.join(import.meta.dir, '..'); + +function writeExecutable(filePath: string, content: string) { + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, content, 'utf8'); + fs.chmodSync(filePath, 0o755); +} + +function createFakeGstackRepo(parentDir: string): string { + const repoDir = path.join(parentDir, 'gstack'); + fs.mkdirSync(repoDir, { recursive: true }); + + fs.copyFileSync(path.join(ROOT, 'setup'), path.join(repoDir, 'setup')); + fs.chmodSync(path.join(repoDir, 'setup'), 0o755); + + fs.writeFileSync(path.join(repoDir, 'SKILL.md'), '# gstack\n', 'utf8'); + writeExecutable(path.join(repoDir, 'browse', 'dist', 'browse'), '#!/bin/sh\nexit 0\n'); + writeExecutable(path.join(repoDir, 'bin', 'gstack-config'), '#!/bin/sh\nexit 0\n'); + fs.writeFileSync(path.join(repoDir, 'package.json'), '{}\n', 'utf8'); + + for (const skill of ['review', 'ship', 'qa']) { + fs.mkdirSync(path.join(repoDir, skill), { recursive: true }); + fs.writeFileSync(path.join(repoDir, skill, 'SKILL.md'), `# ${skill}\n`, 'utf8'); + } + for (const doc of ['checklist.md', 'design-checklist.md', 'greptile-triage.md', 'TODOS-format.md']) { + fs.writeFileSync(path.join(repoDir, 'review', doc), `${doc}\n`, 'utf8'); + } + fs.writeFileSync(path.join(repoDir, 'VERSION'), '0.0.0-test\n', 'utf8'); + + for (const skill of ['gstack', 'gstack-review', 'gstack-ship']) { + fs.mkdirSync(path.join(repoDir, '.agents', 'skills', skill), { recursive: true }); + fs.writeFileSync(path.join(repoDir, '.agents', 'skills', skill, 'SKILL.md'), `# ${skill}\n`, 'utf8'); + } + + return repoDir; +} + +function createStubBin(parentDir: string, commands: string[]): string { + const binDir = path.join(parentDir, 'bin'); + fs.mkdirSync(binDir, { recursive: true }); + + for (const command of commands) { + writeExecutable(path.join(binDir, command), '#!/bin/sh\nexit 0\n'); + } + + return binDir; +} + +function runSetup( + repoDir: string, + homeDir: string, + binDir: string, + args: string[], +) { + return spawnSync('bash', ['setup', ...args], { + cwd: repoDir, + encoding: 'utf8', + env: { + ...process.env, + HOME: homeDir, + PATH: `${binDir}:${process.env.PATH || ''}`, + GSTACK_SETUP_SKIP_BUILD: '1', + GSTACK_SETUP_SKIP_BROWSER: '1', + }, + }); +} + +function tempDir(prefix: string): string { + return fs.mkdtempSync(path.join(os.tmpdir(), prefix)); +} + +describe('setup scope support', () => { + test('workspace scope installs Claude and Codex assets into a project root', () => { + const tempRoot = tempDir('gstack-setup-workspace-'); + try { + const homeDir = path.join(tempRoot, 'home'); + const projectRoot = path.join(tempRoot, 'project'); + fs.mkdirSync(homeDir, { recursive: true }); + fs.mkdirSync(projectRoot, { recursive: true }); + + const repoDir = createFakeGstackRepo(tempRoot); + const binDir = createStubBin(tempRoot, ['bun', 'claude', 'codex']); + const result = runSetup(repoDir, homeDir, binDir, [ + '--host', 'auto', + '--scope', 'workspace', + '--project-root', projectRoot, + ]); + + expect(result.status).toBe(0); + + const claudeRoot = path.join(projectRoot, '.claude', 'skills', 'gstack'); + const claudeSkill = path.join(projectRoot, '.claude', 'skills', 'review'); + const codexRoot = path.join(projectRoot, '.agents', 'skills', 'gstack'); + const codexSkill = path.join(projectRoot, '.agents', 'skills', 'gstack-review'); + const realRepoDir = fs.realpathSync(repoDir); + + expect(fs.realpathSync(claudeRoot)).toBe(realRepoDir); + expect(fs.readlinkSync(claudeSkill)).toBe('gstack/review'); + expect(fs.statSync(codexRoot).isDirectory()).toBe(true); + expect(fs.realpathSync(path.join(codexRoot, 'SKILL.md'))).toBe(fs.realpathSync(path.join(repoDir, '.agents', 'skills', 'gstack', 'SKILL.md'))); + expect(fs.realpathSync(codexSkill)).toBe(fs.realpathSync(path.join(repoDir, '.agents', 'skills', 'gstack-review'))); + expect(fs.realpathSync(path.join(projectRoot, '.agents', 'skills', 'gstack', 'bin'))).toBe(fs.realpathSync(path.join(repoDir, 'bin'))); + expect(fs.realpathSync(path.join(codexRoot, 'VERSION'))).toBe(fs.realpathSync(path.join(repoDir, 'VERSION'))); + expect(fs.realpathSync(path.join(codexRoot, 'review', 'checklist.md'))).toBe(fs.realpathSync(path.join(repoDir, 'review', 'checklist.md'))); + expect(fs.existsSync(path.join(codexRoot, 'review', 'SKILL.md'))).toBe(false); + + expect(fs.existsSync(path.join(homeDir, '.claude', 'skills'))).toBe(false); + expect(fs.existsSync(path.join(homeDir, '.codex', 'skills'))).toBe(false); + } finally { + fs.rmSync(tempRoot, { recursive: true, force: true }); + } + }); + + test('user scope installs from an arbitrary checkout into home skill dirs', () => { + const tempRoot = tempDir('gstack-setup-user-'); + try { + const homeDir = path.join(tempRoot, 'home'); + fs.mkdirSync(homeDir, { recursive: true }); + + const repoDir = createFakeGstackRepo(tempRoot); + const binDir = createStubBin(tempRoot, ['bun']); + const result = runSetup(repoDir, homeDir, binDir, [ + '--host', 'auto', + '--scope', 'user', + ]); + + expect(result.status).toBe(0); + + const claudeRoot = path.join(homeDir, '.claude', 'skills', 'gstack'); + const claudeSkill = path.join(homeDir, '.claude', 'skills', 'ship'); + const codexRoot = path.join(homeDir, '.codex', 'skills', 'gstack'); + const codexSkill = path.join(homeDir, '.codex', 'skills', 'gstack-ship'); + const realRepoDir = fs.realpathSync(repoDir); + + expect(fs.realpathSync(claudeRoot)).toBe(realRepoDir); + expect(fs.readlinkSync(claudeSkill)).toBe('gstack/ship'); + expect(fs.realpathSync(codexRoot)).toBe(realRepoDir); + expect(fs.realpathSync(path.join(codexRoot, 'SKILL.md'))).toBe(fs.realpathSync(path.join(repoDir, 'SKILL.md'))); + expect(fs.realpathSync(codexSkill)).toBe(fs.realpathSync(path.join(repoDir, '.agents', 'skills', 'gstack-ship'))); + } finally { + fs.rmSync(tempRoot, { recursive: true, force: true }); + } + }); +});