mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-13 16:04:58 +02:00
feat(paths): bin/gstack-paths helper + migrate 8 skills off inline state-root chains
New bin/gstack-paths emits GSTACK_STATE_ROOT, PLAN_ROOT, TMP_ROOT exports for
skill bash blocks to source via eval. Honors GSTACK_HOME → CLAUDE_PLUGIN_DATA →
$HOME/.gstack → .gstack (and parallel chains for plan/tmp roots) so skills work
the same in plugin installs, global installs, and CI containers without HOME.
Eight skills migrate off inline ${CLAUDE_PLUGIN_DATA:-...} or ${GSTACK_HOME:-...}
chains: careful, freeze, guard, unfreeze, investigate, context-save,
context-restore, learn, office-hours, plan-tune, codex. Resolved values are
identical, so existing tests cover correctness; the win is consolidating 11
copy-pasted fallback chains behind one helper.
codex/SKILL.md.tmpl gets a new Step 0.6 Resolve portable roots that sources
gstack-paths once, then replaces hardcoded ~/.claude/plans/*.md and
/tmp/codex-*-XXXXXX.txt with "$PLAN_ROOT"/*.md and "$TMP_ROOT/codex-*-XXXXXX.txt".
Hardening direction credited to the McGluut/gstack fork; this is upstream's
factoring of the per-skill chain the fork inlined.
Tests: test/gstack-paths.test.ts covers all three fallback chains with 8 unit
tests (HOME unset, CLAUDE_PLUGIN_DATA set, GSTACK_HOME wins, etc).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+8
-4
@@ -783,7 +783,8 @@ Power-user shortcuts (one-word invocations) — handle these too:
|
||||
# Ensure profile exists
|
||||
~/.claude/skills/gstack/bin/gstack-developer-profile --read >/dev/null
|
||||
# Update declared dimensions atomically
|
||||
_PROFILE="${GSTACK_HOME:-$HOME/.gstack}/developer-profile.json"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_PROFILE="$GSTACK_STATE_ROOT/developer-profile.json"
|
||||
bun -e "
|
||||
const fs = require('fs');
|
||||
const p = JSON.parse(fs.readFileSync('$_PROFILE','utf-8'));
|
||||
@@ -844,7 +845,8 @@ Parse the JSON. Present in **plain English**, not raw floats:
|
||||
|
||||
```bash
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)"
|
||||
_LOG="${GSTACK_HOME:-$HOME/.gstack}/projects/$SLUG/question-log.jsonl"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl"
|
||||
if [ ! -f "$_LOG" ]; then
|
||||
echo "NO_LOG"
|
||||
else
|
||||
@@ -937,7 +939,8 @@ is a trust boundary (Codex #15 in the design doc).
|
||||
|
||||
3. After Y, write:
|
||||
```bash
|
||||
_PROFILE="${GSTACK_HOME:-$HOME/.gstack}/developer-profile.json"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_PROFILE="$GSTACK_STATE_ROOT/developer-profile.json"
|
||||
bun -e "
|
||||
const fs = require('fs');
|
||||
const p = JSON.parse(fs.readFileSync('$_PROFILE','utf-8'));
|
||||
@@ -978,7 +981,8 @@ the user decides whether declared is wrong or behavior is wrong.
|
||||
```bash
|
||||
~/.claude/skills/gstack/bin/gstack-question-preference --stats
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)"
|
||||
_LOG="${GSTACK_HOME:-$HOME/.gstack}/projects/$SLUG/question-log.jsonl"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl"
|
||||
[ -f "$_LOG" ] && echo "TOTAL_LOGGED: $(wc -l < "$_LOG" | tr -d ' ')" || echo "TOTAL_LOGGED: 0"
|
||||
~/.claude/skills/gstack/bin/gstack-developer-profile --profile | bun -e "
|
||||
const p = JSON.parse(await Bun.stdin.text());
|
||||
|
||||
@@ -144,7 +144,8 @@ Power-user shortcuts (one-word invocations) — handle these too:
|
||||
# Ensure profile exists
|
||||
~/.claude/skills/gstack/bin/gstack-developer-profile --read >/dev/null
|
||||
# Update declared dimensions atomically
|
||||
_PROFILE="${GSTACK_HOME:-$HOME/.gstack}/developer-profile.json"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_PROFILE="$GSTACK_STATE_ROOT/developer-profile.json"
|
||||
bun -e "
|
||||
const fs = require('fs');
|
||||
const p = JSON.parse(fs.readFileSync('$_PROFILE','utf-8'));
|
||||
@@ -205,7 +206,8 @@ Parse the JSON. Present in **plain English**, not raw floats:
|
||||
|
||||
```bash
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)"
|
||||
_LOG="${GSTACK_HOME:-$HOME/.gstack}/projects/$SLUG/question-log.jsonl"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl"
|
||||
if [ ! -f "$_LOG" ]; then
|
||||
echo "NO_LOG"
|
||||
else
|
||||
@@ -298,7 +300,8 @@ is a trust boundary (Codex #15 in the design doc).
|
||||
|
||||
3. After Y, write:
|
||||
```bash
|
||||
_PROFILE="${GSTACK_HOME:-$HOME/.gstack}/developer-profile.json"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_PROFILE="$GSTACK_STATE_ROOT/developer-profile.json"
|
||||
bun -e "
|
||||
const fs = require('fs');
|
||||
const p = JSON.parse(fs.readFileSync('$_PROFILE','utf-8'));
|
||||
@@ -339,7 +342,8 @@ the user decides whether declared is wrong or behavior is wrong.
|
||||
```bash
|
||||
~/.claude/skills/gstack/bin/gstack-question-preference --stats
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)"
|
||||
_LOG="${GSTACK_HOME:-$HOME/.gstack}/projects/$SLUG/question-log.jsonl"
|
||||
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
||||
_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl"
|
||||
[ -f "$_LOG" ] && echo "TOTAL_LOGGED: $(wc -l < "$_LOG" | tr -d ' ')" || echo "TOTAL_LOGGED: 0"
|
||||
~/.claude/skills/gstack/bin/gstack-developer-profile --profile | bun -e "
|
||||
const p = JSON.parse(await Bun.stdin.text());
|
||||
|
||||
Reference in New Issue
Block a user