@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.
Files changed (2) hide show
  1. package/lib/setup-hook.mjs +23 -16
  2. package/package.json +1 -1
@@ -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
- // the assistant has emitted the literal sentinel [skills-checked] since
6
- // the most recent user prompt. Resets every user turn, runs once per
7
- // turn (subsequent edits in the same turn pass through).
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
- LAST_PROMPT=$(grep -nE '"role":"user","content":"' "$TRANSCRIPT" 2>/dev/null | tail -1 | cut -d: -f1)
38
- if [ -z "$LAST_PROMPT" ]; then
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
- if tail -n +"$LAST_PROMPT" "$TRANSCRIPT" | grep -v '"type":"tool_result"' | grep -qF '[skills-checked]'; then
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 <<'EOF'
47
- {"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Skill evaluation required before writing or editing code. List each available skill as ACTIVATE or SKIP with a one-line reason, call Skill() for any ACTIVATE entries, then emit the literal token [skills-checked] (square brackets included) on its own line. Then retry the tool call."}}
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
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spardutti/claude-skills",
3
- "version": "1.27.2",
3
+ "version": "1.27.3",
4
4
  "description": "CLI to install Claude Code skills from the claude-skills collection",
5
5
  "type": "module",
6
6
  "bin": {