gsd-cc 1.3.3 → 1.4.1
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 +22 -13
- package/hooks/gsd-prompt-guard.sh +12 -11
- package/hooks/gsd-statusline.sh +22 -36
- package/package.json +1 -1
- package/skills/gsd/plan/SKILL.md +2 -2
- package/skills/gsd/seed/SKILL.md +3 -3
- package/skills/gsd/unify/SKILL.md +3 -3
package/bin/install.js
CHANGED
|
@@ -29,7 +29,7 @@ ${cyan} ██████╗ ███████╗██████╗
|
|
|
29
29
|
// Sub-skills that get their own top-level directory under .claude/skills/
|
|
30
30
|
const SUB_SKILLS = ['apply', 'auto', 'config', 'discuss', 'help', 'ideate', 'ingest', 'plan', 'profile', 'seed', 'stack', 'status', 'tutorial', 'unify', 'update', 'vision'];
|
|
31
31
|
|
|
32
|
-
// Shared directories
|
|
32
|
+
// Shared directories installed directly into .claude/
|
|
33
33
|
const SHARED_DIRS = ['checklists', 'prompts', 'templates'];
|
|
34
34
|
|
|
35
35
|
// Parse args
|
|
@@ -139,13 +139,15 @@ function install(isGlobal) {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
// 3. Install shared resources (templates, checklists, prompts)
|
|
143
|
-
const
|
|
142
|
+
// 3. Install shared resources (templates, checklists, prompts) into .claude/
|
|
143
|
+
const claudeBase = isGlobal
|
|
144
|
+
? path.join(os.homedir(), '.claude')
|
|
145
|
+
: path.join(process.cwd(), '.claude');
|
|
144
146
|
for (const dir of SHARED_DIRS) {
|
|
145
147
|
const srcDir = path.join(skillsSrc, dir);
|
|
146
148
|
if (fs.existsSync(srcDir)) {
|
|
147
|
-
copyDir(srcDir, path.join(
|
|
148
|
-
fileCount += countFiles(path.join(
|
|
149
|
+
copyDir(srcDir, path.join(claudeBase, dir));
|
|
150
|
+
fileCount += countFiles(path.join(claudeBase, dir));
|
|
149
151
|
}
|
|
150
152
|
}
|
|
151
153
|
|
|
@@ -219,22 +221,19 @@ function installHooks(isGlobal, hooksDir) {
|
|
|
219
221
|
]
|
|
220
222
|
});
|
|
221
223
|
|
|
222
|
-
// PostToolUse: context monitor (all tools) + workflow guard (Edit/Write)
|
|
224
|
+
// PostToolUse: context monitor + statusline (all tools) + workflow guard (Edit/Write)
|
|
223
225
|
if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = [];
|
|
224
226
|
settings.hooks.PostToolUse.push({
|
|
225
|
-
hooks: [
|
|
227
|
+
hooks: [
|
|
228
|
+
{ type: 'command', command: contextMonitor, timeout: 5000 },
|
|
229
|
+
{ type: 'command', command: statusline, timeout: 3000 }
|
|
230
|
+
]
|
|
226
231
|
});
|
|
227
232
|
settings.hooks.PostToolUse.push({
|
|
228
233
|
matcher: 'Edit|Write',
|
|
229
234
|
hooks: [{ type: 'command', command: workflowGuard, timeout: 5000 }]
|
|
230
235
|
});
|
|
231
236
|
|
|
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
237
|
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
239
238
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
240
239
|
console.log(` ${green}✓${reset} Hooks configured in ${settingsPath.replace(os.homedir(), '~').replace(process.cwd(), '.')}`);
|
|
@@ -314,6 +313,7 @@ function countFiles(dir) {
|
|
|
314
313
|
function uninstall() {
|
|
315
314
|
const locations = [getSkillsBase(true), getSkillsBase(false)];
|
|
316
315
|
const allDirs = ['gsd-cc', ...SUB_SKILLS.map(s => `gsd-cc-${s}`), 'gsd-cc-shared', 'gsd'];
|
|
316
|
+
const sharedDirs = ['checklists', 'prompts', 'templates', 'hooks'];
|
|
317
317
|
|
|
318
318
|
let removed = false;
|
|
319
319
|
|
|
@@ -330,6 +330,15 @@ function uninstall() {
|
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
+
// Remove shared dirs from .claude/
|
|
334
|
+
const claudeDir = base.replace(/\/skills$/, '');
|
|
335
|
+
for (const dir of sharedDirs) {
|
|
336
|
+
const fullPath = path.join(claudeDir, dir);
|
|
337
|
+
if (removeDir(fullPath)) {
|
|
338
|
+
removedFromLocation = true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
333
342
|
if (removedFromLocation) {
|
|
334
343
|
console.log(` ${green}✓${reset} Removed GSD-CC from ${label}`);
|
|
335
344
|
removed = true;
|
|
@@ -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 (
|
|
59
|
-
if
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
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
|
package/hooks/gsd-statusline.sh
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# GSD-CC Statusline —
|
|
3
|
-
#
|
|
4
|
-
#
|
|
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
|
|
51
|
-
BRIDGE_FILE="/tmp/gsd-cc-
|
|
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,
|
|
54
|
+
'{phase: $phase, position: $position, total_slices: ($total|tonumber), done_slices: ($done|tonumber)}' \
|
|
59
55
|
> "$BRIDGE_FILE" 2>/dev/null
|
|
60
56
|
|
|
61
|
-
#
|
|
62
|
-
|
|
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
|
+
"version": "1.4.1",
|
|
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",
|
package/skills/gsd/plan/SKILL.md
CHANGED
|
@@ -202,8 +202,8 @@ One file per task, using the PLAN.xml template format:
|
|
|
202
202
|
|
|
203
203
|
Before finishing, check against `checklists/planning-ready.md`:
|
|
204
204
|
|
|
205
|
-
Read: `~/.claude/
|
|
206
|
-
(or `./.claude/
|
|
205
|
+
Read: `~/.claude/checklists/planning-ready.md`
|
|
206
|
+
(or `./.claude/checklists/planning-ready.md`)
|
|
207
207
|
|
|
208
208
|
Verify ALL of these:
|
|
209
209
|
|
package/skills/gsd/seed/SKILL.md
CHANGED
|
@@ -102,8 +102,8 @@ Walk through the guide sections **one at a time**. For each section:
|
|
|
102
102
|
|
|
103
103
|
After completing all sections, mentally check against `checklists/planning-ready.md`:
|
|
104
104
|
|
|
105
|
-
Read: `~/.claude/
|
|
106
|
-
(or `./.claude/
|
|
105
|
+
Read: `~/.claude/checklists/planning-ready.md`
|
|
106
|
+
(or `./.claude/checklists/planning-ready.md`)
|
|
107
107
|
|
|
108
108
|
Verify:
|
|
109
109
|
- Is there enough information to create a roadmap?
|
|
@@ -118,7 +118,7 @@ Create the `.gsd/` directory and write these files:
|
|
|
118
118
|
|
|
119
119
|
#### `.gsd/PLANNING.md`
|
|
120
120
|
|
|
121
|
-
Use the template from `~/.claude/
|
|
121
|
+
Use the template from `~/.claude/templates/PLANNING.md` (or `./.claude/templates/PLANNING.md`). Fill in all sections from the conversation:
|
|
122
122
|
- Vision (from their initial description + refinements)
|
|
123
123
|
- Users (from user/auth discussions)
|
|
124
124
|
- Requirements v1, v2, Out of Scope (from exploration)
|
|
@@ -194,14 +194,14 @@ If no VISION.md exists, skip this step.
|
|
|
194
194
|
|
|
195
195
|
Check against `checklists/unify-complete.md`:
|
|
196
196
|
|
|
197
|
-
Read: `~/.claude/
|
|
198
|
-
(or `./.claude/
|
|
197
|
+
Read: `~/.claude/checklists/unify-complete.md`
|
|
198
|
+
(or `./.claude/checklists/unify-complete.md`)
|
|
199
199
|
|
|
200
200
|
Verify ALL items pass. If any fails, fix the UNIFY document before proceeding.
|
|
201
201
|
|
|
202
202
|
## Step 9: Write UNIFY.md
|
|
203
203
|
|
|
204
|
-
Write `.gsd/S{nn}-UNIFY.md` using the template from `~/.claude/
|
|
204
|
+
Write `.gsd/S{nn}-UNIFY.md` using the template from `~/.claude/templates/UNIFY.md` (or `./.claude/templates/UNIFY.md`). Include all sections from Steps 2-7.
|
|
205
205
|
|
|
206
206
|
Set frontmatter:
|
|
207
207
|
```yaml
|