@spardutti/claude-skills 1.27.2 → 1.27.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/setup-hook.mjs +23 -16
- package/package.json +1 -1
package/lib/setup-hook.mjs
CHANGED
|
@@ -2,21 +2,24 @@ import { mkdir, writeFile, readFile, chmod } from "node:fs/promises";
|
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
// PreToolUse gate on Write|Edit|MultiEdit. Blocks the tool call unless
|
|
5
|
-
//
|
|
6
|
-
// the most recent user prompt.
|
|
7
|
-
//
|
|
5
|
+
// a per-prompt marker file exists at $PROJECT_DIR/.claude/.skill-gate-<UUID>,
|
|
6
|
+
// where <UUID> is the uuid of the most recent typed user prompt. The
|
|
7
|
+
// assistant creates the marker via Bash; Bash output is flushed
|
|
8
|
+
// synchronously, so the marker is race-free against the message-buffering
|
|
9
|
+
// behavior that broke the earlier text-sentinel approach (Claude Code
|
|
10
|
+
// writes assistant content blocks to JSONL only after the turn completes,
|
|
11
|
+
// so [skills-checked] text emitted in the same message as a tool_use is
|
|
12
|
+
// invisible to PreToolUse).
|
|
13
|
+
//
|
|
14
|
+
// LAST_PROMPT_UUID is detected by matching user-role lines whose content
|
|
15
|
+
// is a JSON string ("role":"user","content":"..."), which excludes
|
|
16
|
+
// tool_results, skill loads, task notifications, and slash-command
|
|
17
|
+
// payloads (all of which use array content).
|
|
8
18
|
//
|
|
9
19
|
// Pass-through cases:
|
|
10
20
|
// - project has no .claude/skills/*/SKILL.md files
|
|
11
21
|
// - transcript_path missing or unreadable
|
|
12
|
-
// - no user prompt found in transcript
|
|
13
|
-
//
|
|
14
|
-
// LAST_PROMPT is detected by matching user-role lines whose content is
|
|
15
|
-
// a JSON string ("role":"user","content":"..."), which excludes
|
|
16
|
-
// tool_results, skill loads, task notifications, and slash-command
|
|
17
|
-
// payloads (all of which use array content). The sentinel scan also
|
|
18
|
-
// excludes tool_result lines so the gate's own deny message — which
|
|
19
|
-
// embeds the literal sentinel — cannot self-satisfy.
|
|
22
|
+
// - no typed user prompt found in transcript
|
|
20
23
|
const GATE_SCRIPT = `#!/bin/bash
|
|
21
24
|
# PreToolUse gate: forces skill evaluation before file-writing tools run.
|
|
22
25
|
|
|
@@ -34,17 +37,21 @@ if [ -z "$TRANSCRIPT" ] || [ ! -f "$TRANSCRIPT" ]; then
|
|
|
34
37
|
exit 0
|
|
35
38
|
fi
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
LAST_LINE=$(grep -E '"role":"user","content":"' "$TRANSCRIPT" 2>/dev/null | tail -1)
|
|
41
|
+
LAST_PROMPT_UUID=$(printf '%s' "$LAST_LINE" | grep -o '"uuid":"[^"]*"' | head -1 | sed 's/"uuid":"//;s/"$//')
|
|
42
|
+
if [ -z "$LAST_PROMPT_UUID" ]; then
|
|
39
43
|
exit 0
|
|
40
44
|
fi
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
MARKER_DIR="$PROJECT_DIR/.claude"
|
|
47
|
+
MARKER="$MARKER_DIR/.skill-gate-$LAST_PROMPT_UUID"
|
|
48
|
+
if [ -f "$MARKER" ]; then
|
|
49
|
+
find "$MARKER_DIR" -maxdepth 1 -name '.skill-gate-*' ! -name ".skill-gate-$LAST_PROMPT_UUID" -delete 2>/dev/null
|
|
43
50
|
exit 0
|
|
44
51
|
fi
|
|
45
52
|
|
|
46
|
-
cat <<
|
|
47
|
-
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Skill evaluation required before
|
|
53
|
+
cat <<EOF
|
|
54
|
+
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Skill evaluation required before file edits. (1) List each available skill as ACTIVATE or SKIP with a one-line reason. (2) Call Skill() for any ACTIVATE entries. (3) Run this exact Bash command to record approval: mkdir -p .claude && touch .claude/.skill-gate-$LAST_PROMPT_UUID (4) Then retry the file edit. The marker is unique to this user prompt and is auto-cleaned on the next prompt."}}
|
|
48
55
|
EOF
|
|
49
56
|
exit 0
|
|
50
57
|
`;
|