gsd-cc 1.3.3 → 1.4.0

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/bin/install.js CHANGED
@@ -219,22 +219,19 @@ function installHooks(isGlobal, hooksDir) {
219
219
  ]
220
220
  });
221
221
 
222
- // PostToolUse: context monitor (all tools) + workflow guard (Edit/Write)
222
+ // PostToolUse: context monitor + statusline (all tools) + workflow guard (Edit/Write)
223
223
  if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = [];
224
224
  settings.hooks.PostToolUse.push({
225
- hooks: [{ type: 'command', command: contextMonitor, timeout: 5000 }]
225
+ hooks: [
226
+ { type: 'command', command: contextMonitor, timeout: 5000 },
227
+ { type: 'command', command: statusline, timeout: 3000 }
228
+ ]
226
229
  });
227
230
  settings.hooks.PostToolUse.push({
228
231
  matcher: 'Edit|Write',
229
232
  hooks: [{ type: 'command', command: workflowGuard, timeout: 5000 }]
230
233
  });
231
234
 
232
- // Notification: statusline
233
- if (!settings.hooks.Notification) settings.hooks.Notification = [];
234
- settings.hooks.Notification.push({
235
- hooks: [{ type: 'command', command: statusline, timeout: 3000 }]
236
- });
237
-
238
235
  fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
239
236
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
240
237
  console.log(` ${green}✓${reset} Hooks configured in ${settingsPath.replace(os.homedir(), '~').replace(process.cwd(), '.')}`);
@@ -55,21 +55,22 @@ if echo "$CONTENT" | grep -iqE '(show|reveal|print|output|display) (your|the|sys
55
55
  REASON="Detected system prompt extraction attempt"
56
56
  fi
57
57
 
58
- # Pattern 4: Invisible Unicode characters (zero-width spaces, RTL override, etc.)
59
- if echo "$CONTENT" | grep -qP '[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{202A}-\x{202E}\x{2066}-\x{2069}]' 2>/dev/null; then
60
- SUSPICIOUS=true
61
- REASON="Detected invisible Unicode characters"
62
- fi
63
-
64
- # Pattern 5: Base64-encoded instructions
65
- if echo "$CONTENT" | grep -qE '[A-Za-z0-9+/]{50,}={0,2}'; then
66
- # Only flag if it's in a suspicious context (not normal code)
67
- if echo "$CONTENT" | grep -iqE '(decode|eval|execute|base64).*[A-Za-z0-9+/]{50,}'; then
58
+ # Pattern 4: Invisible Unicode characters (macOS-compatible using perl)
59
+ if command -v perl >/dev/null 2>&1; then
60
+ if echo "$CONTENT" | perl -ne 'exit 1 if /[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{202A}-\x{202E}\x{2066}-\x{2069}]/' 2>/dev/null; then
61
+ : # no match
62
+ else
68
63
  SUSPICIOUS=true
69
- REASON="Detected potentially encoded instructions"
64
+ REASON="Detected invisible Unicode characters"
70
65
  fi
71
66
  fi
72
67
 
68
+ # Pattern 5: Base64-encoded instructions in suspicious context
69
+ if echo "$CONTENT" | grep -iqE '(decode|eval|execute|base64).*[A-Za-z0-9+/]{50,}'; then
70
+ SUSPICIOUS=true
71
+ REASON="Detected potentially encoded instructions"
72
+ fi
73
+
73
74
  # Pattern 6: HTML/script injection in markdown
74
75
  if echo "$CONTENT" | grep -iqE '<script|javascript:|on(load|error|click)='; then
75
76
  SUSPICIOUS=true
@@ -1,7 +1,8 @@
1
1
  #!/bin/bash
2
- # GSD-CC Statusline — Notification hook
3
- # Renders project status in the terminal statusline.
4
- # Shows: current phase, milestone/slice/task position, and project type.
2
+ # GSD-CC Statusline — PostToolUse hook
3
+ # Injects current project status as additionalContext after each tool use.
4
+ # This keeps Claude aware of the current position in the project.
5
+ # Also writes a bridge file for other hooks to read.
5
6
 
6
7
  INPUT=$(cat)
7
8
  CWD=$(echo "$INPUT" | jq -r '.cwd')
@@ -12,12 +13,23 @@ if [ ! -f "$STATE_FILE" ]; then
12
13
  exit 0
13
14
  fi
14
15
 
16
+ # Debounce: only inject status every 10 tool calls
17
+ DEBOUNCE_FILE="/tmp/gsd-cc-statusline-$(echo "$CWD" | cksum | cut -d' ' -f1)"
18
+ COUNTER=0
19
+ if [ -f "$DEBOUNCE_FILE" ]; then
20
+ COUNTER=$(cat "$DEBOUNCE_FILE")
21
+ fi
22
+ COUNTER=$((COUNTER + 1))
23
+ echo "$COUNTER" > "$DEBOUNCE_FILE"
24
+ if [ $((COUNTER % 10)) -ne 0 ]; then
25
+ exit 0
26
+ fi
27
+
15
28
  # Parse STATE.md frontmatter
16
29
  PHASE=$(grep '^phase:' "$STATE_FILE" | head -1 | sed 's/phase: *//')
17
30
  MILESTONE=$(grep '^milestone:' "$STATE_FILE" | head -1 | sed 's/milestone: *//')
18
31
  SLICE=$(grep '^current_slice:' "$STATE_FILE" | head -1 | sed 's/current_slice: *//')
19
32
  TASK=$(grep '^current_task:' "$STATE_FILE" | head -1 | sed 's/current_task: *//')
20
- RIGOR=$(grep '^rigor:' "$STATE_FILE" | head -1 | sed 's/rigor: *//')
21
33
 
22
34
  # Build position string
23
35
  POSITION="$MILESTONE"
@@ -28,46 +40,20 @@ if [ "$TASK" != "—" ] && [ -n "$TASK" ]; then
28
40
  POSITION="$POSITION / $TASK"
29
41
  fi
30
42
 
31
- # Map phase to display name
32
- case "$PHASE" in
33
- "seed") PHASE_DISPLAY="Seed" ;;
34
- "seed-complete") PHASE_DISPLAY="Seed ✓" ;;
35
- "stack-complete") PHASE_DISPLAY="Stack ✓" ;;
36
- "roadmap-complete") PHASE_DISPLAY="Roadmap ✓" ;;
37
- "discuss-complete") PHASE_DISPLAY="Discuss ✓" ;;
38
- "plan-complete") PHASE_DISPLAY="Plan ✓" ;;
39
- "planning") PHASE_DISPLAY="Planning..." ;;
40
- "applying") PHASE_DISPLAY="Executing..." ;;
41
- "apply-complete") PHASE_DISPLAY="UNIFY required" ;;
42
- "unified") PHASE_DISPLAY="Unified ✓" ;;
43
- *) PHASE_DISPLAY="$PHASE" ;;
44
- esac
45
-
46
43
  # Count progress
47
44
  TOTAL_SLICES=$(grep -c '| S[0-9]' "$STATE_FILE" 2>/dev/null || echo "0")
48
- DONE_SLICES=$(grep '| done' "$STATE_FILE" | wc -l | xargs)
45
+ DONE_SLICES=$(grep '| done' "$STATE_FILE" 2>/dev/null | wc -l | xargs)
49
46
 
50
- # Write status to bridge file for other hooks
51
- BRIDGE_FILE="/tmp/gsd-cc-status-$(echo "$CWD" | md5sum 2>/dev/null | cut -c1-8 || echo "default").json"
47
+ # Write bridge file for other hooks
48
+ BRIDGE_FILE="/tmp/gsd-cc-bridge-$(echo "$CWD" | cksum | cut -d' ' -f1).json"
52
49
  jq -n \
53
50
  --arg phase "$PHASE" \
54
51
  --arg position "$POSITION" \
55
- --arg rigor "$RIGOR" \
56
52
  --arg total "$TOTAL_SLICES" \
57
53
  --arg done "$DONE_SLICES" \
58
- '{phase: $phase, position: $position, rigor: $rigor, total_slices: ($total|tonumber), done_slices: ($done|tonumber)}' \
54
+ '{phase: $phase, position: $position, total_slices: ($total|tonumber), done_slices: ($done|tonumber)}' \
59
55
  > "$BRIDGE_FILE" 2>/dev/null
60
56
 
61
- # Output statusline data
62
- jq -n \
63
- --arg pos "$POSITION" \
64
- --arg phase "$PHASE_DISPLAY" \
65
- --arg rigor "$RIGOR" \
66
- --arg progress "${DONE_SLICES}/${TOTAL_SLICES}" \
67
- '{
68
- "hookSpecificOutput": {
69
- "hookEventName": "Notification",
70
- "additionalContext": ("GSD-CC: " + $pos + " | " + $phase + " | " + $rigor + " | " + $progress + " slices")
71
- }
72
- }'
57
+ # No additionalContext output — this hook is silent.
58
+ # It only maintains the bridge file for cross-hook communication.
73
59
  exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-cc",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "Get Shit Done on Claude Code — structured AI development with your Max plan",
5
5
  "author": "Philipp Briese (https://github.com/0ui-labs)",
6
6
  "homepage": "https://github.com/0ui-labs/GSD-CC#readme",