mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-06 21:46:40 +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:
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# gstack-paths — output portable state-root paths for skill bash blocks
|
||||
# Usage: eval "$(gstack-paths)" → sets GSTACK_STATE_ROOT, PLAN_ROOT, TMP_ROOT
|
||||
# Or: gstack-paths → prints GSTACK_STATE_ROOT=... etc.
|
||||
#
|
||||
# Resolves three roots with explicit fallback chains so skills work the same
|
||||
# whether installed as a Claude Code plugin (CLAUDE_PLUGIN_DATA / CLAUDE_PLANS_DIR
|
||||
# set), a global ~/.claude/skills/gstack/ install, or a local checkout under
|
||||
# CI / container env where HOME may be unset.
|
||||
#
|
||||
# Chains:
|
||||
# GSTACK_STATE_ROOT: GSTACK_HOME -> CLAUDE_PLUGIN_DATA -> $HOME/.gstack -> .gstack
|
||||
# PLAN_ROOT: GSTACK_PLAN_DIR -> CLAUDE_PLANS_DIR -> $HOME/.claude/plans -> .claude/plans
|
||||
# TMP_ROOT: TMPDIR -> TMP -> .gstack/tmp (and mkdir -p, best-effort)
|
||||
#
|
||||
# Security: output values are not sanitized — callers may receive paths with
|
||||
# shell-special characters if env vars contain them. Skills should always quote
|
||||
# expansions ("$GSTACK_STATE_ROOT", not $GSTACK_STATE_ROOT).
|
||||
set -u
|
||||
|
||||
# State root: where gstack writes projects/, sessions/, analytics/.
|
||||
if [ -n "${GSTACK_HOME:-}" ]; then
|
||||
_state_root="$GSTACK_HOME"
|
||||
elif [ -n "${CLAUDE_PLUGIN_DATA:-}" ]; then
|
||||
_state_root="$CLAUDE_PLUGIN_DATA"
|
||||
elif [ -n "${HOME:-}" ]; then
|
||||
_state_root="$HOME/.gstack"
|
||||
else
|
||||
_state_root=".gstack"
|
||||
fi
|
||||
|
||||
# Plan root: where /context-save and /codex consult write plan files.
|
||||
if [ -n "${GSTACK_PLAN_DIR:-}" ]; then
|
||||
_plan_root="$GSTACK_PLAN_DIR"
|
||||
elif [ -n "${CLAUDE_PLANS_DIR:-}" ]; then
|
||||
_plan_root="$CLAUDE_PLANS_DIR"
|
||||
elif [ -n "${HOME:-}" ]; then
|
||||
_plan_root="$HOME/.claude/plans"
|
||||
else
|
||||
_plan_root=".claude/plans"
|
||||
fi
|
||||
|
||||
# Tmp root: where ephemeral files (codex stderr captures, etc.) live.
|
||||
# Honor TMPDIR / TMP for Windows + container compat; fall back to a
|
||||
# project-local .gstack/tmp so we never write to a system /tmp that may
|
||||
# be read-only or shared.
|
||||
if [ -n "${TMPDIR:-}" ]; then
|
||||
_tmp_root="$TMPDIR"
|
||||
elif [ -n "${TMP:-}" ]; then
|
||||
_tmp_root="$TMP"
|
||||
else
|
||||
_tmp_root=".gstack/tmp"
|
||||
fi
|
||||
|
||||
# Best-effort mkdir; if it fails (read-only fs, permission denied), the caller
|
||||
# will discover that on their own write attempt. Don't fail the eval here.
|
||||
mkdir -p "$_tmp_root" 2>/dev/null || true
|
||||
|
||||
echo "GSTACK_STATE_ROOT=$_state_root"
|
||||
echo "PLAN_ROOT=$_plan_root"
|
||||
echo "TMP_ROOT=$_tmp_root"
|
||||
Reference in New Issue
Block a user