mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-07 05:56:41 +02:00
d9f17c2394
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>
87 lines
3.0 KiB
Cheetah
87 lines
3.0 KiB
Cheetah
---
|
|
name: freeze
|
|
version: 0.1.0
|
|
description: |
|
|
Restrict file edits to a specific directory for the session. Blocks Edit and
|
|
Write outside the allowed path. Use when debugging to prevent accidentally
|
|
"fixing" unrelated code, or when you want to scope changes to one module.
|
|
Use when asked to "freeze", "restrict edits", "only edit this folder",
|
|
or "lock down edits". (gstack)
|
|
triggers:
|
|
- freeze edits to directory
|
|
- lock editing scope
|
|
- restrict file changes
|
|
allowed-tools:
|
|
- Bash
|
|
- Read
|
|
- AskUserQuestion
|
|
hooks:
|
|
PreToolUse:
|
|
- matcher: "Edit"
|
|
hooks:
|
|
- type: command
|
|
command: "bash ${CLAUDE_SKILL_DIR}/bin/check-freeze.sh"
|
|
statusMessage: "Checking freeze boundary..."
|
|
- matcher: "Write"
|
|
hooks:
|
|
- type: command
|
|
command: "bash ${CLAUDE_SKILL_DIR}/bin/check-freeze.sh"
|
|
statusMessage: "Checking freeze boundary..."
|
|
sensitive: true
|
|
---
|
|
|
|
# /freeze — Restrict Edits to a Directory
|
|
|
|
Lock file edits to a specific directory. Any Edit or Write operation targeting
|
|
a file outside the allowed path will be **blocked** (not just warned).
|
|
|
|
```bash
|
|
mkdir -p ~/.gstack/analytics
|
|
echo '{"skill":"freeze","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
|
|
```
|
|
|
|
## Setup
|
|
|
|
Ask the user which directory to restrict edits to. Use AskUserQuestion:
|
|
|
|
- Question: "Which directory should I restrict edits to? Files outside this path will be blocked from editing."
|
|
- Text input (not multiple choice) — the user types a path.
|
|
|
|
Once the user provides a directory path:
|
|
|
|
1. Resolve it to an absolute path:
|
|
```bash
|
|
FREEZE_DIR=$(cd "<user-provided-path>" 2>/dev/null && pwd)
|
|
echo "$FREEZE_DIR"
|
|
```
|
|
|
|
2. Ensure trailing slash and save to the freeze state file:
|
|
```bash
|
|
FREEZE_DIR="${FREEZE_DIR%/}/"
|
|
eval "$(~/.claude/skills/gstack/bin/gstack-paths)"
|
|
STATE_DIR="$GSTACK_STATE_ROOT"
|
|
mkdir -p "$STATE_DIR"
|
|
echo "$FREEZE_DIR" > "$STATE_DIR/freeze-dir.txt"
|
|
echo "Freeze boundary set: $FREEZE_DIR"
|
|
```
|
|
|
|
Tell the user: "Edits are now restricted to `<path>/`. Any Edit or Write
|
|
outside this directory will be blocked. To change the boundary, run `/freeze`
|
|
again. To remove it, run `/unfreeze` or end the session."
|
|
|
|
## How it works
|
|
|
|
The hook reads `file_path` from the Edit/Write tool input JSON, then checks
|
|
whether the path starts with the freeze directory. If not, it returns
|
|
`permissionDecision: "deny"` to block the operation.
|
|
|
|
The freeze boundary persists for the session via the state file. The hook
|
|
script reads it on every Edit/Write invocation.
|
|
|
|
## Notes
|
|
|
|
- The trailing `/` on the freeze directory prevents `/src` from matching `/src-old`
|
|
- Freeze applies to Edit and Write tools only — Read, Bash, Glob, Grep are unaffected
|
|
- This prevents accidental edits, not a security boundary — Bash commands like `sed` can still modify files outside the boundary
|
|
- To deactivate, run `/unfreeze` or end the conversation
|