get-shit-done-cc 1.5.28 → 1.5.29
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/agents/gsd-plan-checker.md +3 -2
- package/bin/install.js +13 -109
- package/commands/gsd/discuss-phase.md +24 -15
- package/commands/gsd/plan-phase.md +25 -14
- package/commands/gsd/research-phase.md +13 -7
- package/get-shit-done/templates/context.md +143 -13
- package/get-shit-done/workflows/discuss-phase.md +95 -46
- package/hooks/gsd-check-update.js +51 -0
- package/hooks/statusline.js +84 -0
- package/package.json +1 -1
- package/hooks/gsd-check-update.sh +0 -20
- package/hooks/gsd-notify.sh +0 -59
- package/hooks/statusline.sh +0 -58
|
@@ -244,8 +244,9 @@ issue:
|
|
|
244
244
|
Gather verification context from the phase directory and project state.
|
|
245
245
|
|
|
246
246
|
```bash
|
|
247
|
-
#
|
|
248
|
-
|
|
247
|
+
# Normalize phase and find directory
|
|
248
|
+
PADDED_PHASE=$(printf "%02d" ${PHASE_ARG} 2>/dev/null || echo "${PHASE_ARG}")
|
|
249
|
+
PHASE_DIR=$(ls -d .planning/phases/${PADDED_PHASE}-* .planning/phases/${PHASE_ARG}-* 2>/dev/null | head -1)
|
|
249
250
|
|
|
250
251
|
# List all PLAN.md files
|
|
251
252
|
ls "$PHASE_DIR"/*-PLAN.md 2>/dev/null
|
package/bin/install.js
CHANGED
|
@@ -55,8 +55,6 @@ function parseConfigDirArg() {
|
|
|
55
55
|
const explicitConfigDir = parseConfigDirArg();
|
|
56
56
|
const hasHelp = args.includes('--help') || args.includes('-h');
|
|
57
57
|
const forceStatusline = args.includes('--force-statusline');
|
|
58
|
-
const forceNotify = args.includes('--force-notify');
|
|
59
|
-
const noNotify = args.includes('--no-notify');
|
|
60
58
|
|
|
61
59
|
console.log(banner);
|
|
62
60
|
|
|
@@ -70,8 +68,6 @@ if (hasHelp) {
|
|
|
70
68
|
${cyan}-c, --config-dir <path>${reset} Specify custom Claude config directory
|
|
71
69
|
${cyan}-h, --help${reset} Show this help message
|
|
72
70
|
${cyan}--force-statusline${reset} Replace existing statusline config
|
|
73
|
-
${cyan}--force-notify${reset} Replace existing notification hook
|
|
74
|
-
${cyan}--no-notify${reset} Skip notification hook installation
|
|
75
71
|
|
|
76
72
|
${yellow}Examples:${reset}
|
|
77
73
|
${dim}# Install to default ~/.claude directory${reset}
|
|
@@ -221,10 +217,6 @@ function install(isGlobal) {
|
|
|
221
217
|
const srcFile = path.join(hooksSrc, entry);
|
|
222
218
|
const destFile = path.join(hooksDest, entry);
|
|
223
219
|
fs.copyFileSync(srcFile, destFile);
|
|
224
|
-
// Make shell scripts executable
|
|
225
|
-
if (entry.endsWith('.sh')) {
|
|
226
|
-
fs.chmodSync(destFile, 0o755);
|
|
227
|
-
}
|
|
228
220
|
}
|
|
229
221
|
console.log(` ${green}✓${reset} Installed hooks`);
|
|
230
222
|
}
|
|
@@ -233,14 +225,11 @@ function install(isGlobal) {
|
|
|
233
225
|
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
234
226
|
const settings = readSettings(settingsPath);
|
|
235
227
|
const statuslineCommand = isGlobal
|
|
236
|
-
? '$HOME/.claude/hooks/statusline.
|
|
237
|
-
: '.claude/hooks/statusline.
|
|
228
|
+
? 'node "$HOME/.claude/hooks/statusline.js"'
|
|
229
|
+
: 'node .claude/hooks/statusline.js';
|
|
238
230
|
const updateCheckCommand = isGlobal
|
|
239
|
-
? '$HOME/.claude/hooks/gsd-check-update.
|
|
240
|
-
: '.claude/hooks/gsd-check-update.
|
|
241
|
-
const notifyCommand = isGlobal
|
|
242
|
-
? '$HOME/.claude/hooks/gsd-notify.sh'
|
|
243
|
-
: '.claude/hooks/gsd-notify.sh';
|
|
231
|
+
? 'node "$HOME/.claude/hooks/gsd-check-update.js"'
|
|
232
|
+
: 'node .claude/hooks/gsd-check-update.js';
|
|
244
233
|
|
|
245
234
|
// Configure SessionStart hook for update checking
|
|
246
235
|
if (!settings.hooks) {
|
|
@@ -267,13 +256,13 @@ function install(isGlobal) {
|
|
|
267
256
|
console.log(` ${green}✓${reset} Configured update check hook`);
|
|
268
257
|
}
|
|
269
258
|
|
|
270
|
-
return { settingsPath, settings, statuslineCommand
|
|
259
|
+
return { settingsPath, settings, statuslineCommand };
|
|
271
260
|
}
|
|
272
261
|
|
|
273
262
|
/**
|
|
274
|
-
* Apply statusline
|
|
263
|
+
* Apply statusline config, then print completion message
|
|
275
264
|
*/
|
|
276
|
-
function finishInstall(settingsPath, settings, statuslineCommand,
|
|
265
|
+
function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallStatusline) {
|
|
277
266
|
if (shouldInstallStatusline) {
|
|
278
267
|
settings.statusLine = {
|
|
279
268
|
type: 'command',
|
|
@@ -282,25 +271,6 @@ function finishInstall(settingsPath, settings, statuslineCommand, notifyCommand,
|
|
|
282
271
|
console.log(` ${green}✓${reset} Configured statusline`);
|
|
283
272
|
}
|
|
284
273
|
|
|
285
|
-
if (shouldInstallNotify) {
|
|
286
|
-
if (!settings.hooks.Stop) {
|
|
287
|
-
settings.hooks.Stop = [];
|
|
288
|
-
}
|
|
289
|
-
// Remove any existing GSD notify hook first
|
|
290
|
-
settings.hooks.Stop = settings.hooks.Stop.filter(entry =>
|
|
291
|
-
!(entry.hooks && entry.hooks.some(h => h.command && h.command.includes('gsd-notify')))
|
|
292
|
-
);
|
|
293
|
-
settings.hooks.Stop.push({
|
|
294
|
-
hooks: [
|
|
295
|
-
{
|
|
296
|
-
type: 'command',
|
|
297
|
-
command: notifyCommand
|
|
298
|
-
}
|
|
299
|
-
]
|
|
300
|
-
});
|
|
301
|
-
console.log(` ${green}✓${reset} Configured completion notifications`);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
274
|
// Always write settings (hooks were already configured in install())
|
|
305
275
|
writeSettings(settingsPath, settings);
|
|
306
276
|
|
|
@@ -365,66 +335,6 @@ function handleStatusline(settings, isInteractive, callback) {
|
|
|
365
335
|
});
|
|
366
336
|
}
|
|
367
337
|
|
|
368
|
-
/**
|
|
369
|
-
* Handle notification hook configuration with optional prompt
|
|
370
|
-
*/
|
|
371
|
-
function handleNotifications(settings, isInteractive, callback) {
|
|
372
|
-
// Check if --no-notify flag was passed
|
|
373
|
-
if (noNotify) {
|
|
374
|
-
callback(false);
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Check if GSD notify hook already exists
|
|
379
|
-
const hasExisting = settings.hooks?.Stop?.some(entry =>
|
|
380
|
-
entry.hooks && entry.hooks.some(h => h.command && h.command.includes('gsd-notify'))
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
// No existing - just install it
|
|
384
|
-
if (!hasExisting) {
|
|
385
|
-
callback(true);
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Has existing and --force-notify flag
|
|
390
|
-
if (forceNotify) {
|
|
391
|
-
callback(true);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Has existing, non-interactive mode - skip
|
|
396
|
-
if (!isInteractive) {
|
|
397
|
-
console.log(` ${yellow}⚠${reset} Skipping notifications (already configured)`);
|
|
398
|
-
console.log(` Use ${cyan}--force-notify${reset} to replace\n`);
|
|
399
|
-
callback(false);
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Has existing, interactive mode - prompt user
|
|
404
|
-
const rl = readline.createInterface({
|
|
405
|
-
input: process.stdin,
|
|
406
|
-
output: process.stdout
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
console.log(`
|
|
410
|
-
${yellow}⚠${reset} Existing notification hook detected
|
|
411
|
-
|
|
412
|
-
GSD includes completion notifications that alert you when:
|
|
413
|
-
• A phase completes planning or execution
|
|
414
|
-
• Claude stops and needs your input
|
|
415
|
-
• Works on Mac, Linux, and Windows
|
|
416
|
-
|
|
417
|
-
${cyan}1${reset}) Keep existing
|
|
418
|
-
${cyan}2${reset}) Replace with GSD notifications
|
|
419
|
-
`);
|
|
420
|
-
|
|
421
|
-
rl.question(` Choice ${dim}[1]${reset}: `, (answer) => {
|
|
422
|
-
rl.close();
|
|
423
|
-
const choice = answer.trim() || '1';
|
|
424
|
-
callback(choice === '2');
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
|
|
428
338
|
/**
|
|
429
339
|
* Prompt for install location
|
|
430
340
|
*/
|
|
@@ -448,12 +358,10 @@ function promptLocation() {
|
|
|
448
358
|
rl.close();
|
|
449
359
|
const choice = answer.trim() || '1';
|
|
450
360
|
const isGlobal = choice !== '2';
|
|
451
|
-
const { settingsPath, settings, statuslineCommand
|
|
361
|
+
const { settingsPath, settings, statuslineCommand } = install(isGlobal);
|
|
452
362
|
// Interactive mode - prompt for optional features
|
|
453
363
|
handleStatusline(settings, true, (shouldInstallStatusline) => {
|
|
454
|
-
|
|
455
|
-
finishInstall(settingsPath, settings, statuslineCommand, notifyCommand, shouldInstallStatusline, shouldInstallNotify);
|
|
456
|
-
});
|
|
364
|
+
finishInstall(settingsPath, settings, statuslineCommand, shouldInstallStatusline);
|
|
457
365
|
});
|
|
458
366
|
});
|
|
459
367
|
}
|
|
@@ -466,20 +374,16 @@ if (hasGlobal && hasLocal) {
|
|
|
466
374
|
console.error(` ${yellow}Cannot use --config-dir with --local${reset}`);
|
|
467
375
|
process.exit(1);
|
|
468
376
|
} else if (hasGlobal) {
|
|
469
|
-
const { settingsPath, settings, statuslineCommand
|
|
377
|
+
const { settingsPath, settings, statuslineCommand } = install(true);
|
|
470
378
|
// Non-interactive - respect flags
|
|
471
379
|
handleStatusline(settings, false, (shouldInstallStatusline) => {
|
|
472
|
-
|
|
473
|
-
finishInstall(settingsPath, settings, statuslineCommand, notifyCommand, shouldInstallStatusline, shouldInstallNotify);
|
|
474
|
-
});
|
|
380
|
+
finishInstall(settingsPath, settings, statuslineCommand, shouldInstallStatusline);
|
|
475
381
|
});
|
|
476
382
|
} else if (hasLocal) {
|
|
477
|
-
const { settingsPath, settings, statuslineCommand
|
|
383
|
+
const { settingsPath, settings, statuslineCommand } = install(false);
|
|
478
384
|
// Non-interactive - respect flags
|
|
479
385
|
handleStatusline(settings, false, (shouldInstallStatusline) => {
|
|
480
|
-
|
|
481
|
-
finishInstall(settingsPath, settings, statuslineCommand, notifyCommand, shouldInstallStatusline, shouldInstallNotify);
|
|
482
|
-
});
|
|
386
|
+
finishInstall(settingsPath, settings, statuslineCommand, shouldInstallStatusline);
|
|
483
387
|
});
|
|
484
388
|
} else {
|
|
485
389
|
promptLocation();
|
|
@@ -35,10 +35,10 @@ Phase number: $ARGUMENTS (required)
|
|
|
35
35
|
<process>
|
|
36
36
|
1. Validate phase number (error if missing or not in roadmap)
|
|
37
37
|
2. Check if CONTEXT.md exists (offer update/view/skip if yes)
|
|
38
|
-
3. **Analyze phase** — Identify domain
|
|
39
|
-
4. **Present gray areas** — Multi-select
|
|
40
|
-
5. **Deep-dive each area** —
|
|
41
|
-
6. **Write CONTEXT.md** —
|
|
38
|
+
3. **Analyze phase** — Identify domain and generate phase-specific gray areas
|
|
39
|
+
4. **Present gray areas** — Multi-select: which to discuss? (NO skip option)
|
|
40
|
+
5. **Deep-dive each area** — 4 questions per area, then offer more/next
|
|
41
|
+
6. **Write CONTEXT.md** — Sections match areas discussed
|
|
42
42
|
7. Offer next steps (research or plan)
|
|
43
43
|
|
|
44
44
|
**CRITICAL: Scope guardrail**
|
|
@@ -47,18 +47,27 @@ Phase number: $ARGUMENTS (required)
|
|
|
47
47
|
- If user suggests new capabilities: "That's its own phase. I'll note it for later."
|
|
48
48
|
- Capture deferred ideas — don't lose them, don't act on them
|
|
49
49
|
|
|
50
|
-
**
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
50
|
+
**Domain-aware gray areas:**
|
|
51
|
+
Gray areas depend on what's being built. Analyze the phase goal:
|
|
52
|
+
- Something users SEE → layout, density, interactions, states
|
|
53
|
+
- Something users CALL → responses, errors, auth, versioning
|
|
54
|
+
- Something users RUN → output format, flags, modes, error handling
|
|
55
|
+
- Something users READ → structure, tone, depth, flow
|
|
56
|
+
- Something being ORGANIZED → criteria, grouping, naming, exceptions
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
58
|
+
Generate 3-4 **phase-specific** gray areas, not generic categories.
|
|
59
|
+
|
|
60
|
+
**Probing depth:**
|
|
61
|
+
- Ask 4 questions per area before checking
|
|
62
|
+
- "More questions about [area], or move to next?"
|
|
63
|
+
- If more → ask 4 more, check again
|
|
64
|
+
- After all areas → "Ready to create context?"
|
|
65
|
+
|
|
66
|
+
**Do NOT ask about (Claude handles these):**
|
|
67
|
+
- Technical implementation
|
|
68
|
+
- Architecture choices
|
|
69
|
+
- Performance concerns
|
|
70
|
+
- Scope expansion
|
|
62
71
|
</process>
|
|
63
72
|
|
|
64
73
|
<success_criteria>
|
|
@@ -37,13 +37,7 @@ Phase number: $ARGUMENTS (optional - auto-detects next unplanned phase if not pr
|
|
|
37
37
|
- `--gaps` — Gap closure mode (reads VERIFICATION.md, skips research)
|
|
38
38
|
- `--skip-verify` — Skip planner → checker verification loop
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
ls .planning/phases/${PHASE}-*/*-RESEARCH.md 2>/dev/null
|
|
44
|
-
ls .planning/phases/${PHASE}-*/*-PLAN.md 2>/dev/null
|
|
45
|
-
```
|
|
46
|
-
|
|
40
|
+
Normalize phase input in step 2 before any directory lookups.
|
|
47
41
|
</context>
|
|
48
42
|
|
|
49
43
|
<process>
|
|
@@ -56,7 +50,7 @@ ls .planning/ 2>/dev/null
|
|
|
56
50
|
|
|
57
51
|
**If not found:** Error - user should run `/gsd:new-project` first.
|
|
58
52
|
|
|
59
|
-
## 2. Parse Arguments
|
|
53
|
+
## 2. Parse and Normalize Arguments
|
|
60
54
|
|
|
61
55
|
Extract from $ARGUMENTS:
|
|
62
56
|
|
|
@@ -68,6 +62,24 @@ Extract from $ARGUMENTS:
|
|
|
68
62
|
|
|
69
63
|
**If no phase number:** Detect next unplanned phase from roadmap.
|
|
70
64
|
|
|
65
|
+
**Normalize phase to zero-padded format:**
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Normalize phase number (8 → 08, but preserve decimals like 2.1 → 02.1)
|
|
69
|
+
if [[ "$PHASE" =~ ^[0-9]+$ ]]; then
|
|
70
|
+
PHASE=$(printf "%02d" "$PHASE")
|
|
71
|
+
elif [[ "$PHASE" =~ ^([0-9]+)\.([0-9]+)$ ]]; then
|
|
72
|
+
PHASE=$(printf "%02d.%s" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}")
|
|
73
|
+
fi
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Check for existing research and plans:**
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
ls .planning/phases/${PHASE}-*/*-RESEARCH.md 2>/dev/null
|
|
80
|
+
ls .planning/phases/${PHASE}-*/*-PLAN.md 2>/dev/null
|
|
81
|
+
```
|
|
82
|
+
|
|
71
83
|
## 3. Validate Phase
|
|
72
84
|
|
|
73
85
|
```bash
|
|
@@ -79,14 +91,13 @@ grep -A5 "Phase ${PHASE}:" .planning/ROADMAP.md 2>/dev/null
|
|
|
79
91
|
## 4. Ensure Phase Directory Exists
|
|
80
92
|
|
|
81
93
|
```bash
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
PHASE_DIR=$(ls -d .planning/phases/${PADDED_PHASE}-* .planning/phases/${PHASE}-* 2>/dev/null | head -1)
|
|
94
|
+
# PHASE is already normalized (08, 02.1, etc.) from step 2
|
|
95
|
+
PHASE_DIR=$(ls -d .planning/phases/${PHASE}-* 2>/dev/null | head -1)
|
|
85
96
|
if [ -z "$PHASE_DIR" ]; then
|
|
86
|
-
# Create phase directory from roadmap name
|
|
97
|
+
# Create phase directory from roadmap name
|
|
87
98
|
PHASE_NAME=$(grep "Phase ${PHASE}:" .planning/ROADMAP.md | sed 's/.*Phase [0-9]*: //' | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
|
|
88
|
-
mkdir -p ".planning/phases/${
|
|
89
|
-
PHASE_DIR=".planning/phases/${
|
|
99
|
+
mkdir -p ".planning/phases/${PHASE}-${PHASE_NAME}"
|
|
100
|
+
PHASE_DIR=".planning/phases/${PHASE}-${PHASE_NAME}"
|
|
90
101
|
fi
|
|
91
102
|
```
|
|
92
103
|
|
|
@@ -26,17 +26,23 @@ Research how to implement a phase. Spawns gsd-phase-researcher agent with phase
|
|
|
26
26
|
<context>
|
|
27
27
|
Phase number: $ARGUMENTS (required)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
ls .planning/phases/${PHASE}-*/*RESEARCH.md 2>/dev/null
|
|
32
|
-
```
|
|
29
|
+
Normalize phase input in step 1 before any directory lookups.
|
|
33
30
|
</context>
|
|
34
31
|
|
|
35
32
|
<process>
|
|
36
33
|
|
|
37
|
-
## 1.
|
|
34
|
+
## 1. Normalize and Validate Phase
|
|
38
35
|
|
|
39
36
|
```bash
|
|
37
|
+
# Normalize phase number (8 → 08, but preserve decimals like 2.1 → 02.1)
|
|
38
|
+
if [[ "$ARGUMENTS" =~ ^[0-9]+$ ]]; then
|
|
39
|
+
PHASE=$(printf "%02d" "$ARGUMENTS")
|
|
40
|
+
elif [[ "$ARGUMENTS" =~ ^([0-9]+)\.([0-9]+)$ ]]; then
|
|
41
|
+
PHASE=$(printf "%02d.%s" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}")
|
|
42
|
+
else
|
|
43
|
+
PHASE="$ARGUMENTS"
|
|
44
|
+
fi
|
|
45
|
+
|
|
40
46
|
grep -A5 "Phase ${PHASE}:" .planning/ROADMAP.md 2>/dev/null
|
|
41
47
|
```
|
|
42
48
|
|
|
@@ -118,7 +124,7 @@ Before declaring complete, verify:
|
|
|
118
124
|
</quality_gate>
|
|
119
125
|
|
|
120
126
|
<output>
|
|
121
|
-
Write to: .planning/phases
|
|
127
|
+
Write to: .planning/phases/${PHASE}-{slug}/${PHASE}-RESEARCH.md
|
|
122
128
|
</output>
|
|
123
129
|
```
|
|
124
130
|
|
|
@@ -146,7 +152,7 @@ Continue research for Phase {phase_number}: {phase_name}
|
|
|
146
152
|
</objective>
|
|
147
153
|
|
|
148
154
|
<prior_state>
|
|
149
|
-
Research file: @.planning/phases
|
|
155
|
+
Research file: @.planning/phases/${PHASE}-{slug}/${PHASE}-RESEARCH.md
|
|
150
156
|
</prior_state>
|
|
151
157
|
|
|
152
158
|
<checkpoint_response>
|
|
@@ -4,6 +4,8 @@ Template for `.planning/phases/XX-name/{phase}-CONTEXT.md` - captures implementa
|
|
|
4
4
|
|
|
5
5
|
**Purpose:** Document decisions that downstream agents need. Researcher uses this to know WHAT to investigate. Planner uses this to know WHAT choices are locked vs flexible.
|
|
6
6
|
|
|
7
|
+
**Key principle:** Categories are NOT predefined. They emerge from what was actually discussed for THIS phase. A CLI phase has CLI-relevant sections, a UI phase has UI-relevant sections.
|
|
8
|
+
|
|
7
9
|
**Downstream consumers:**
|
|
8
10
|
- `gsd-phase-researcher` — Reads decisions to focus research (e.g., "card layout" → research card component patterns)
|
|
9
11
|
- `gsd-planner` — Reads decisions to create specific tasks (e.g., "infinite scroll" → task includes virtualization)
|
|
@@ -28,11 +30,14 @@ Template for `.planning/phases/XX-name/{phase}-CONTEXT.md` - captures implementa
|
|
|
28
30
|
<decisions>
|
|
29
31
|
## Implementation Decisions
|
|
30
32
|
|
|
31
|
-
### [
|
|
33
|
+
### [Area 1 that was discussed]
|
|
32
34
|
- [Specific decision made]
|
|
33
35
|
- [Another decision if applicable]
|
|
34
36
|
|
|
35
|
-
### [
|
|
37
|
+
### [Area 2 that was discussed]
|
|
38
|
+
- [Specific decision made]
|
|
39
|
+
|
|
40
|
+
### [Area 3 that was discussed]
|
|
36
41
|
- [Specific decision made]
|
|
37
42
|
|
|
38
43
|
### Claude's Discretion
|
|
@@ -65,6 +70,9 @@ Template for `.planning/phases/XX-name/{phase}-CONTEXT.md` - captures implementa
|
|
|
65
70
|
```
|
|
66
71
|
|
|
67
72
|
<good_examples>
|
|
73
|
+
|
|
74
|
+
**Example 1: Visual feature (Post Feed)**
|
|
75
|
+
|
|
68
76
|
```markdown
|
|
69
77
|
# Phase 3: Post Feed - Context
|
|
70
78
|
|
|
@@ -81,18 +89,17 @@ Display posts from followed users in a scrollable feed. Users can view posts and
|
|
|
81
89
|
<decisions>
|
|
82
90
|
## Implementation Decisions
|
|
83
91
|
|
|
84
|
-
###
|
|
92
|
+
### Layout style
|
|
85
93
|
- Card-based layout, not timeline or list
|
|
86
94
|
- Each card shows: author avatar, name, timestamp, full post content, reaction counts
|
|
87
95
|
- Cards have subtle shadows, rounded corners — modern feel
|
|
88
|
-
- Show 10 posts initially, load more on scroll
|
|
89
96
|
|
|
90
|
-
###
|
|
97
|
+
### Loading behavior
|
|
91
98
|
- Infinite scroll, not pagination
|
|
92
99
|
- Pull-to-refresh on mobile
|
|
93
100
|
- New posts indicator at top ("3 new posts") rather than auto-inserting
|
|
94
101
|
|
|
95
|
-
### Empty
|
|
102
|
+
### Empty state
|
|
96
103
|
- Friendly illustration + "Follow people to see posts here"
|
|
97
104
|
- Suggest 3-5 accounts to follow based on interests
|
|
98
105
|
|
|
@@ -108,7 +115,6 @@ Display posts from followed users in a scrollable feed. Users can view posts and
|
|
|
108
115
|
|
|
109
116
|
- "I like how Twitter shows the new posts indicator without disrupting your scroll position"
|
|
110
117
|
- Cards should feel like Linear's issue cards — clean, not cluttered
|
|
111
|
-
- No infinite scroll fatigue — maybe show "You're all caught up" after ~50 posts
|
|
112
118
|
|
|
113
119
|
</specifics>
|
|
114
120
|
|
|
@@ -116,7 +122,6 @@ Display posts from followed users in a scrollable feed. Users can view posts and
|
|
|
116
122
|
## Deferred Ideas
|
|
117
123
|
|
|
118
124
|
- Commenting on posts — Phase 5
|
|
119
|
-
- Reaction picker (not just counts) — Phase 5
|
|
120
125
|
- Bookmarking posts — add to backlog
|
|
121
126
|
|
|
122
127
|
</deferred>
|
|
@@ -126,6 +131,131 @@ Display posts from followed users in a scrollable feed. Users can view posts and
|
|
|
126
131
|
*Phase: 03-post-feed*
|
|
127
132
|
*Context gathered: 2025-01-20*
|
|
128
133
|
```
|
|
134
|
+
|
|
135
|
+
**Example 2: CLI tool (Database backup)**
|
|
136
|
+
|
|
137
|
+
```markdown
|
|
138
|
+
# Phase 2: Backup Command - Context
|
|
139
|
+
|
|
140
|
+
**Gathered:** 2025-01-20
|
|
141
|
+
**Status:** Ready for planning
|
|
142
|
+
|
|
143
|
+
<domain>
|
|
144
|
+
## Phase Boundary
|
|
145
|
+
|
|
146
|
+
CLI command to backup database to local file or S3. Supports full and incremental backups. Restore command is a separate phase.
|
|
147
|
+
|
|
148
|
+
</domain>
|
|
149
|
+
|
|
150
|
+
<decisions>
|
|
151
|
+
## Implementation Decisions
|
|
152
|
+
|
|
153
|
+
### Output format
|
|
154
|
+
- JSON for programmatic use, table format for humans
|
|
155
|
+
- Default to table, --json flag for JSON
|
|
156
|
+
- Verbose mode (-v) shows progress, silent by default
|
|
157
|
+
|
|
158
|
+
### Flag design
|
|
159
|
+
- Short flags for common options: -o (output), -v (verbose), -f (force)
|
|
160
|
+
- Long flags for clarity: --incremental, --compress, --encrypt
|
|
161
|
+
- Required: database connection string (positional or --db)
|
|
162
|
+
|
|
163
|
+
### Error recovery
|
|
164
|
+
- Retry 3 times on network failure, then fail with clear message
|
|
165
|
+
- --no-retry flag to fail fast
|
|
166
|
+
- Partial backups are deleted on failure (no corrupt files)
|
|
167
|
+
|
|
168
|
+
### Claude's Discretion
|
|
169
|
+
- Exact progress bar implementation
|
|
170
|
+
- Compression algorithm choice
|
|
171
|
+
- Temp file handling
|
|
172
|
+
|
|
173
|
+
</decisions>
|
|
174
|
+
|
|
175
|
+
<specifics>
|
|
176
|
+
## Specific Ideas
|
|
177
|
+
|
|
178
|
+
- "I want it to feel like pg_dump — familiar to database people"
|
|
179
|
+
- Should work in CI pipelines (exit codes, no interactive prompts)
|
|
180
|
+
|
|
181
|
+
</specifics>
|
|
182
|
+
|
|
183
|
+
<deferred>
|
|
184
|
+
## Deferred Ideas
|
|
185
|
+
|
|
186
|
+
- Scheduled backups — separate phase
|
|
187
|
+
- Backup rotation/retention — add to backlog
|
|
188
|
+
|
|
189
|
+
</deferred>
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
*Phase: 02-backup-command*
|
|
194
|
+
*Context gathered: 2025-01-20*
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Example 3: Organization task (Photo library)**
|
|
198
|
+
|
|
199
|
+
```markdown
|
|
200
|
+
# Phase 1: Photo Organization - Context
|
|
201
|
+
|
|
202
|
+
**Gathered:** 2025-01-20
|
|
203
|
+
**Status:** Ready for planning
|
|
204
|
+
|
|
205
|
+
<domain>
|
|
206
|
+
## Phase Boundary
|
|
207
|
+
|
|
208
|
+
Organize existing photo library into structured folders. Handle duplicates and apply consistent naming. Tagging and search are separate phases.
|
|
209
|
+
|
|
210
|
+
</domain>
|
|
211
|
+
|
|
212
|
+
<decisions>
|
|
213
|
+
## Implementation Decisions
|
|
214
|
+
|
|
215
|
+
### Grouping criteria
|
|
216
|
+
- Primary grouping by year, then by month
|
|
217
|
+
- Events detected by time clustering (photos within 2 hours = same event)
|
|
218
|
+
- Event folders named by date + location if available
|
|
219
|
+
|
|
220
|
+
### Duplicate handling
|
|
221
|
+
- Keep highest resolution version
|
|
222
|
+
- Move duplicates to _duplicates folder (don't delete)
|
|
223
|
+
- Log all duplicate decisions for review
|
|
224
|
+
|
|
225
|
+
### Naming convention
|
|
226
|
+
- Format: YYYY-MM-DD_HH-MM-SS_originalname.ext
|
|
227
|
+
- Preserve original filename as suffix for searchability
|
|
228
|
+
- Handle name collisions with incrementing suffix
|
|
229
|
+
|
|
230
|
+
### Claude's Discretion
|
|
231
|
+
- Exact clustering algorithm
|
|
232
|
+
- How to handle photos with no EXIF data
|
|
233
|
+
- Folder emoji usage
|
|
234
|
+
|
|
235
|
+
</decisions>
|
|
236
|
+
|
|
237
|
+
<specifics>
|
|
238
|
+
## Specific Ideas
|
|
239
|
+
|
|
240
|
+
- "I want to be able to find photos by roughly when they were taken"
|
|
241
|
+
- Don't delete anything — worst case, move to a review folder
|
|
242
|
+
|
|
243
|
+
</specifics>
|
|
244
|
+
|
|
245
|
+
<deferred>
|
|
246
|
+
## Deferred Ideas
|
|
247
|
+
|
|
248
|
+
- Face detection grouping — future phase
|
|
249
|
+
- Cloud sync — out of scope for now
|
|
250
|
+
|
|
251
|
+
</deferred>
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
*Phase: 01-photo-organization*
|
|
256
|
+
*Context gathered: 2025-01-20*
|
|
257
|
+
```
|
|
258
|
+
|
|
129
259
|
</good_examples>
|
|
130
260
|
|
|
131
261
|
<guidelines>
|
|
@@ -133,11 +263,11 @@ Display posts from followed users in a scrollable feed. Users can view posts and
|
|
|
133
263
|
|
|
134
264
|
The output should answer: "What does the researcher need to investigate? What choices are locked for the planner?"
|
|
135
265
|
|
|
136
|
-
**Good content:**
|
|
266
|
+
**Good content (concrete decisions):**
|
|
137
267
|
- "Card-based layout, not timeline"
|
|
138
|
-
- "
|
|
139
|
-
- "
|
|
140
|
-
- "
|
|
268
|
+
- "Retry 3 times on network failure, then fail"
|
|
269
|
+
- "Group by year, then by month"
|
|
270
|
+
- "JSON for programmatic use, table for humans"
|
|
141
271
|
|
|
142
272
|
**Bad content (too vague):**
|
|
143
273
|
- "Should feel modern and clean"
|
|
@@ -148,7 +278,7 @@ The output should answer: "What does the researcher need to investigate? What ch
|
|
|
148
278
|
**Sections explained:**
|
|
149
279
|
|
|
150
280
|
- **Domain** — The scope anchor. Copied/derived from ROADMAP.md. Fixed boundary.
|
|
151
|
-
- **Decisions** — Organized by
|
|
281
|
+
- **Decisions** — Organized by areas discussed (NOT predefined categories). Section headers come from the actual discussion — "Layout style", "Flag design", "Grouping criteria", etc.
|
|
152
282
|
- **Claude's Discretion** — Explicit acknowledgment of what Claude can decide during implementation.
|
|
153
283
|
- **Specifics** — Product references, examples, "like X but..." statements.
|
|
154
284
|
- **Deferred** — Ideas captured but explicitly out of scope. Prevents scope creep while preserving good ideas.
|
|
@@ -66,23 +66,44 @@ For now, let's focus on [phase domain]."
|
|
|
66
66
|
Capture the idea in a "Deferred Ideas" section. Don't lose it, don't act on it.
|
|
67
67
|
</scope_guardrail>
|
|
68
68
|
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- **
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
69
|
+
<gray_area_identification>
|
|
70
|
+
Gray areas are **implementation decisions the user cares about** — things that could go multiple ways and would change the result.
|
|
71
|
+
|
|
72
|
+
**How to identify gray areas:**
|
|
73
|
+
|
|
74
|
+
1. **Read the phase goal** from ROADMAP.md
|
|
75
|
+
2. **Understand the domain** — What kind of thing is being built?
|
|
76
|
+
- Something users SEE → visual presentation, interactions, states matter
|
|
77
|
+
- Something users CALL → interface contracts, responses, errors matter
|
|
78
|
+
- Something users RUN → invocation, output, behavior modes matter
|
|
79
|
+
- Something users READ → structure, tone, depth, flow matter
|
|
80
|
+
- Something being ORGANIZED → criteria, grouping, handling exceptions matter
|
|
81
|
+
3. **Generate phase-specific gray areas** — Not generic categories, but concrete decisions for THIS phase
|
|
82
|
+
|
|
83
|
+
**Don't use generic category labels** (UI, UX, Behavior). Generate specific gray areas:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
Phase: "User authentication"
|
|
87
|
+
→ Session handling, Error responses, Multi-device policy, Recovery flow
|
|
88
|
+
|
|
89
|
+
Phase: "Organize photo library"
|
|
90
|
+
→ Grouping criteria, Duplicate handling, Naming convention, Folder structure
|
|
91
|
+
|
|
92
|
+
Phase: "CLI for database backups"
|
|
93
|
+
→ Output format, Flag design, Progress reporting, Error recovery
|
|
94
|
+
|
|
95
|
+
Phase: "API documentation"
|
|
96
|
+
→ Structure/navigation, Code examples depth, Versioning approach, Interactive elements
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**The key question:** What decisions would change the outcome that the user should weigh in on?
|
|
100
|
+
|
|
101
|
+
**Claude handles these (don't ask):**
|
|
102
|
+
- Technical implementation details
|
|
103
|
+
- Architecture patterns
|
|
104
|
+
- Performance optimization
|
|
105
|
+
- Scope (roadmap defines this)
|
|
106
|
+
</gray_area_identification>
|
|
86
107
|
|
|
87
108
|
<process>
|
|
88
109
|
|
|
@@ -169,47 +190,79 @@ We'll clarify HOW to implement this.
|
|
|
169
190
|
|
|
170
191
|
**Then use AskUserQuestion (multiSelect: true):**
|
|
171
192
|
- header: "Discuss"
|
|
172
|
-
- question: "Which areas do you want to discuss?"
|
|
173
|
-
- options: Generate
|
|
174
|
-
- "[
|
|
175
|
-
-
|
|
193
|
+
- question: "Which areas do you want to discuss for [phase name]?"
|
|
194
|
+
- options: Generate 3-4 phase-specific gray areas, each formatted as:
|
|
195
|
+
- "[Specific area]" (label) — concrete, not generic
|
|
196
|
+
- [1-2 questions this covers] (description)
|
|
197
|
+
|
|
198
|
+
**Do NOT include a "skip" or "you decide" option.** User ran this command to discuss — give them real choices.
|
|
176
199
|
|
|
177
|
-
**
|
|
200
|
+
**Examples by domain:**
|
|
201
|
+
|
|
202
|
+
For "Post Feed" (visual feature):
|
|
203
|
+
```
|
|
204
|
+
☐ Layout style — Cards vs list vs timeline? Information density?
|
|
205
|
+
☐ Loading behavior — Infinite scroll or pagination? Pull to refresh?
|
|
206
|
+
☐ Content ordering — Chronological, algorithmic, or user choice?
|
|
207
|
+
☐ Post metadata — What info per post? Timestamps, reactions, author?
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
For "Database backup CLI" (command-line tool):
|
|
211
|
+
```
|
|
212
|
+
☐ Output format — JSON, table, or plain text? Verbosity levels?
|
|
213
|
+
☐ Flag design — Short flags, long flags, or both? Required vs optional?
|
|
214
|
+
☐ Progress reporting — Silent, progress bar, or verbose logging?
|
|
215
|
+
☐ Error recovery — Fail fast, retry, or prompt for action?
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
For "Organize photo library" (organization task):
|
|
178
219
|
```
|
|
179
|
-
☐
|
|
180
|
-
☐
|
|
181
|
-
☐
|
|
182
|
-
☐
|
|
220
|
+
☐ Grouping criteria — By date, location, faces, or events?
|
|
221
|
+
☐ Duplicate handling — Keep best, keep all, or prompt each time?
|
|
222
|
+
☐ Naming convention — Original names, dates, or descriptive?
|
|
223
|
+
☐ Folder structure — Flat, nested by year, or by category?
|
|
183
224
|
```
|
|
184
225
|
|
|
185
|
-
|
|
186
|
-
Otherwise: Continue to discuss_areas with selected areas.
|
|
226
|
+
Continue to discuss_areas with selected areas.
|
|
187
227
|
</step>
|
|
188
228
|
|
|
189
229
|
<step name="discuss_areas">
|
|
190
230
|
For each selected area, conduct a focused discussion loop.
|
|
191
231
|
|
|
232
|
+
**Philosophy: 4 questions, then check.**
|
|
233
|
+
|
|
234
|
+
Ask 4 questions per area before offering to continue or move on. Each answer often reveals the next question.
|
|
235
|
+
|
|
192
236
|
**For each area:**
|
|
193
237
|
|
|
194
238
|
1. **Announce the area:**
|
|
195
239
|
```
|
|
196
|
-
Let's talk about [
|
|
240
|
+
Let's talk about [Area].
|
|
197
241
|
```
|
|
198
242
|
|
|
199
|
-
2. **Ask
|
|
200
|
-
- header: "[
|
|
201
|
-
- question: Specific
|
|
202
|
-
- options: 2-3 concrete choices
|
|
243
|
+
2. **Ask 4 questions using AskUserQuestion:**
|
|
244
|
+
- header: "[Area]"
|
|
245
|
+
- question: Specific decision for this area
|
|
246
|
+
- options: 2-3 concrete choices (AskUserQuestion adds "Other" automatically)
|
|
247
|
+
- Include "You decide" as an option when reasonable — captures Claude discretion
|
|
203
248
|
|
|
204
|
-
3. **
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
-
|
|
249
|
+
3. **After 4 questions, check:**
|
|
250
|
+
- header: "[Area]"
|
|
251
|
+
- question: "More questions about [area], or move to next?"
|
|
252
|
+
- options: "More questions" / "Next area"
|
|
208
253
|
|
|
209
|
-
4
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
254
|
+
If "More questions" → ask 4 more, then check again
|
|
255
|
+
If "Next area" → proceed to next selected area
|
|
256
|
+
|
|
257
|
+
4. **After all areas complete:**
|
|
258
|
+
- header: "Done"
|
|
259
|
+
- question: "That covers [list areas]. Ready to create context?"
|
|
260
|
+
- options: "Create context" / "Revisit an area"
|
|
261
|
+
|
|
262
|
+
**Question design:**
|
|
263
|
+
- Options should be concrete, not abstract ("Cards" not "Option A")
|
|
264
|
+
- Each answer should inform the next question
|
|
265
|
+
- If user picks "Other", receive their input, reflect it back, confirm
|
|
213
266
|
|
|
214
267
|
**Scope creep handling:**
|
|
215
268
|
If user mentions something outside the phase domain:
|
|
@@ -217,14 +270,10 @@ If user mentions something outside the phase domain:
|
|
|
217
270
|
"[Feature] sounds like a new capability — that belongs in its own phase.
|
|
218
271
|
I'll note it as a deferred idea.
|
|
219
272
|
|
|
220
|
-
Back to [current
|
|
273
|
+
Back to [current area]: [return to current question]"
|
|
221
274
|
```
|
|
222
275
|
|
|
223
276
|
Track deferred ideas internally.
|
|
224
|
-
|
|
225
|
-
**Continue until:**
|
|
226
|
-
- User says "Move to next area" and all selected areas are done, OR
|
|
227
|
-
- User says "That's enough, create context"
|
|
228
277
|
</step>
|
|
229
278
|
|
|
230
279
|
<step name="write_context">
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Check for GSD updates in background, write result to cache
|
|
3
|
+
// Called by SessionStart hook - runs once per session
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { execSync, spawn } = require('child_process');
|
|
9
|
+
|
|
10
|
+
const homeDir = os.homedir();
|
|
11
|
+
const cacheDir = path.join(homeDir, '.claude', 'cache');
|
|
12
|
+
const cacheFile = path.join(cacheDir, 'gsd-update-check.json');
|
|
13
|
+
const versionFile = path.join(homeDir, '.claude', 'get-shit-done', 'VERSION');
|
|
14
|
+
|
|
15
|
+
// Ensure cache directory exists
|
|
16
|
+
if (!fs.existsSync(cacheDir)) {
|
|
17
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Run check in background (spawn detached process)
|
|
21
|
+
const child = spawn(process.execPath, ['-e', `
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const { execSync } = require('child_process');
|
|
24
|
+
|
|
25
|
+
const cacheFile = ${JSON.stringify(cacheFile)};
|
|
26
|
+
const versionFile = ${JSON.stringify(versionFile)};
|
|
27
|
+
|
|
28
|
+
let installed = '0.0.0';
|
|
29
|
+
try {
|
|
30
|
+
installed = fs.readFileSync(versionFile, 'utf8').trim();
|
|
31
|
+
} catch (e) {}
|
|
32
|
+
|
|
33
|
+
let latest = null;
|
|
34
|
+
try {
|
|
35
|
+
latest = execSync('npm view get-shit-done-cc version', { encoding: 'utf8', timeout: 10000 }).trim();
|
|
36
|
+
} catch (e) {}
|
|
37
|
+
|
|
38
|
+
const result = {
|
|
39
|
+
update_available: latest && installed !== latest,
|
|
40
|
+
installed,
|
|
41
|
+
latest: latest || 'unknown',
|
|
42
|
+
checked: Math.floor(Date.now() / 1000)
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
fs.writeFileSync(cacheFile, JSON.stringify(result));
|
|
46
|
+
`], {
|
|
47
|
+
detached: true,
|
|
48
|
+
stdio: 'ignore'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
child.unref();
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Claude Code Statusline - GSD Edition
|
|
3
|
+
// Shows: model | current task | directory | context usage
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
// Read JSON from stdin
|
|
10
|
+
let input = '';
|
|
11
|
+
process.stdin.setEncoding('utf8');
|
|
12
|
+
process.stdin.on('data', chunk => input += chunk);
|
|
13
|
+
process.stdin.on('end', () => {
|
|
14
|
+
try {
|
|
15
|
+
const data = JSON.parse(input);
|
|
16
|
+
const model = data.model?.display_name || 'Claude';
|
|
17
|
+
const dir = data.workspace?.current_dir || process.cwd();
|
|
18
|
+
const session = data.session_id || '';
|
|
19
|
+
const remaining = data.context_window?.remaining_percentage;
|
|
20
|
+
|
|
21
|
+
// Context window display (shows USED percentage)
|
|
22
|
+
let ctx = '';
|
|
23
|
+
if (remaining != null) {
|
|
24
|
+
const rem = Math.round(remaining);
|
|
25
|
+
const used = 100 - rem;
|
|
26
|
+
|
|
27
|
+
// Build progress bar (10 segments)
|
|
28
|
+
const filled = Math.floor(used / 10);
|
|
29
|
+
const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
|
|
30
|
+
|
|
31
|
+
// Color based on usage
|
|
32
|
+
if (used < 50) {
|
|
33
|
+
ctx = ` \x1b[32m${bar} ${used}%\x1b[0m`;
|
|
34
|
+
} else if (used < 65) {
|
|
35
|
+
ctx = ` \x1b[33m${bar} ${used}%\x1b[0m`;
|
|
36
|
+
} else if (used < 80) {
|
|
37
|
+
ctx = ` \x1b[38;5;208m${bar} ${used}%\x1b[0m`;
|
|
38
|
+
} else {
|
|
39
|
+
ctx = ` \x1b[5;31m💀 ${bar} ${used}%\x1b[0m`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Current task from todos
|
|
44
|
+
let task = '';
|
|
45
|
+
const homeDir = os.homedir();
|
|
46
|
+
const todosDir = path.join(homeDir, '.claude', 'todos');
|
|
47
|
+
if (session && fs.existsSync(todosDir)) {
|
|
48
|
+
const files = fs.readdirSync(todosDir)
|
|
49
|
+
.filter(f => f.startsWith(session) && f.includes('-agent-') && f.endsWith('.json'))
|
|
50
|
+
.map(f => ({ name: f, mtime: fs.statSync(path.join(todosDir, f)).mtime }))
|
|
51
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
52
|
+
|
|
53
|
+
if (files.length > 0) {
|
|
54
|
+
try {
|
|
55
|
+
const todos = JSON.parse(fs.readFileSync(path.join(todosDir, files[0].name), 'utf8'));
|
|
56
|
+
const inProgress = todos.find(t => t.status === 'in_progress');
|
|
57
|
+
if (inProgress) task = inProgress.activeForm || '';
|
|
58
|
+
} catch (e) {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// GSD update available?
|
|
63
|
+
let gsdUpdate = '';
|
|
64
|
+
const cacheFile = path.join(homeDir, '.claude', 'cache', 'gsd-update-check.json');
|
|
65
|
+
if (fs.existsSync(cacheFile)) {
|
|
66
|
+
try {
|
|
67
|
+
const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
|
68
|
+
if (cache.update_available) {
|
|
69
|
+
gsdUpdate = '\x1b[33m⬆ /gsd:update\x1b[0m │ ';
|
|
70
|
+
}
|
|
71
|
+
} catch (e) {}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Output
|
|
75
|
+
const dirname = path.basename(dir);
|
|
76
|
+
if (task) {
|
|
77
|
+
process.stdout.write(`${gsdUpdate}\x1b[2m${model}\x1b[0m │ \x1b[1m${task}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
|
|
78
|
+
} else {
|
|
79
|
+
process.stdout.write(`${gsdUpdate}\x1b[2m${model}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
|
|
80
|
+
}
|
|
81
|
+
} catch (e) {
|
|
82
|
+
// Silent fail - don't break statusline on parse errors
|
|
83
|
+
}
|
|
84
|
+
});
|
package/package.json
CHANGED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Check for GSD updates in background, write result to cache
|
|
3
|
-
# Called by SessionStart hook - runs once per session
|
|
4
|
-
|
|
5
|
-
CACHE_FILE="$HOME/.claude/cache/gsd-update-check.json"
|
|
6
|
-
mkdir -p "$HOME/.claude/cache"
|
|
7
|
-
|
|
8
|
-
# Run check in background (non-blocking)
|
|
9
|
-
(
|
|
10
|
-
installed=$(cat "$HOME/.claude/get-shit-done/VERSION" 2>/dev/null || echo "0.0.0")
|
|
11
|
-
latest=$(npm view get-shit-done-cc version 2>/dev/null)
|
|
12
|
-
|
|
13
|
-
if [[ -n "$latest" && "$installed" != "$latest" ]]; then
|
|
14
|
-
echo "{\"update_available\":true,\"installed\":\"$installed\",\"latest\":\"$latest\",\"checked\":$(date +%s)}" > "$CACHE_FILE"
|
|
15
|
-
else
|
|
16
|
-
echo "{\"update_available\":false,\"installed\":\"$installed\",\"latest\":\"${latest:-unknown}\",\"checked\":$(date +%s)}" > "$CACHE_FILE"
|
|
17
|
-
fi
|
|
18
|
-
) &
|
|
19
|
-
|
|
20
|
-
exit 0
|
package/hooks/gsd-notify.sh
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# GSD Completion Notification Hook
|
|
3
|
-
# Cross-platform alert when Claude stops (task complete, needs input, etc.)
|
|
4
|
-
|
|
5
|
-
input=$(cat)
|
|
6
|
-
session_id=$(echo "$input" | jq -r '.session_id // empty')
|
|
7
|
-
cwd=$(echo "$input" | jq -r '.cwd // empty')
|
|
8
|
-
transcript_path=$(echo "$input" | jq -r '.transcript_path // empty')
|
|
9
|
-
|
|
10
|
-
# Extract project name
|
|
11
|
-
project="Claude Code"
|
|
12
|
-
if [[ -n "$cwd" ]]; then
|
|
13
|
-
project=$(basename "$cwd")
|
|
14
|
-
fi
|
|
15
|
-
|
|
16
|
-
# Check todo list for current/completed task
|
|
17
|
-
message=""
|
|
18
|
-
if [[ -n "$session_id" ]]; then
|
|
19
|
-
todo_file=$(ls -t "$HOME/.claude/todos/${session_id}"*.json 2>/dev/null | head -1)
|
|
20
|
-
if [[ -f "$todo_file" ]]; then
|
|
21
|
-
# Get most recently completed task, or in-progress task
|
|
22
|
-
completed=$(jq -r '[.[] | select(.status=="completed")] | last | .content // empty' "$todo_file" 2>/dev/null)
|
|
23
|
-
if [[ -n "$completed" ]]; then
|
|
24
|
-
message="Completed: $completed"
|
|
25
|
-
else
|
|
26
|
-
in_progress=$(jq -r '.[] | select(.status=="in_progress") | .content' "$todo_file" 2>/dev/null | head -1)
|
|
27
|
-
if [[ -n "$in_progress" ]]; then
|
|
28
|
-
message="Paused: $in_progress"
|
|
29
|
-
fi
|
|
30
|
-
fi
|
|
31
|
-
fi
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
# Fallback: generic message
|
|
35
|
-
if [[ -z "$message" ]]; then
|
|
36
|
-
message="Ready for input"
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
# Send notification based on OS
|
|
40
|
-
case "$(uname -s)" in
|
|
41
|
-
Darwin)
|
|
42
|
-
osascript -e "display alert \"GSD: $project\" message \"$message\" as informational" &>/dev/null &
|
|
43
|
-
;;
|
|
44
|
-
Linux)
|
|
45
|
-
if command -v notify-send &>/dev/null; then
|
|
46
|
-
notify-send "GSD: $project" "$message" --urgency=normal
|
|
47
|
-
elif command -v zenity &>/dev/null; then
|
|
48
|
-
zenity --info --title="GSD: $project" --text="$message" &
|
|
49
|
-
fi
|
|
50
|
-
;;
|
|
51
|
-
MINGW*|CYGWIN*|MSYS*)
|
|
52
|
-
# Windows via PowerShell
|
|
53
|
-
if command -v powershell.exe &>/dev/null; then
|
|
54
|
-
powershell.exe -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('$message', 'GSD: $project', 'OK', 'Information')" &>/dev/null &
|
|
55
|
-
fi
|
|
56
|
-
;;
|
|
57
|
-
esac
|
|
58
|
-
|
|
59
|
-
exit 0
|
package/hooks/statusline.sh
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Claude Code Statusline - GSD Edition
|
|
3
|
-
# Shows: model | current task | directory | context usage
|
|
4
|
-
|
|
5
|
-
input=$(cat)
|
|
6
|
-
model=$(echo "$input" | jq -r '.model.display_name')
|
|
7
|
-
dir=$(echo "$input" | jq -r '.workspace.current_dir')
|
|
8
|
-
session=$(echo "$input" | jq -r '.session_id')
|
|
9
|
-
remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty')
|
|
10
|
-
|
|
11
|
-
# Context window display (shows USED percentage)
|
|
12
|
-
ctx=""
|
|
13
|
-
if [ -n "$remaining" ]; then
|
|
14
|
-
rem=$(printf "%.0f" "$remaining")
|
|
15
|
-
used=$((100 - rem))
|
|
16
|
-
|
|
17
|
-
# Build progress bar (10 segments) - fills as context is consumed
|
|
18
|
-
filled=$((used / 10))
|
|
19
|
-
bar=""
|
|
20
|
-
for ((i=0; i<filled; i++)); do bar+="█"; done
|
|
21
|
-
for ((i=filled; i<10; i++)); do bar+="░"; done
|
|
22
|
-
|
|
23
|
-
# Color based on usage with blinking skull at 80%+
|
|
24
|
-
if [ "$used" -lt 50 ]; then
|
|
25
|
-
ctx=$' \033[32m'"$bar $used%"$'\033[0m'
|
|
26
|
-
elif [ "$used" -lt 65 ]; then
|
|
27
|
-
ctx=$' \033[33m'"$bar $used%"$'\033[0m'
|
|
28
|
-
elif [ "$used" -lt 80 ]; then
|
|
29
|
-
ctx=$' \033[38;5;208m'"$bar $used%"$'\033[0m'
|
|
30
|
-
else
|
|
31
|
-
# Blinking red with skull
|
|
32
|
-
ctx=$' \033[5;31m💀 '"$bar $used%"$'\033[0m'
|
|
33
|
-
fi
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
|
-
# Current task from todos
|
|
37
|
-
task=""
|
|
38
|
-
todo=$(ls -t "$HOME/.claude/todos/${session}"-agent-*.json 2>/dev/null | head -1)
|
|
39
|
-
if [[ -f "$todo" ]]; then
|
|
40
|
-
task=$(jq -r '.[] | select(.status=="in_progress") | .activeForm' "$todo" 2>/dev/null | head -1)
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
# GSD update available?
|
|
44
|
-
gsd_update=""
|
|
45
|
-
if [[ -f "$HOME/.claude/cache/gsd-update-check.json" ]]; then
|
|
46
|
-
update_available=$(jq -r '.update_available' "$HOME/.claude/cache/gsd-update-check.json" 2>/dev/null)
|
|
47
|
-
if [[ "$update_available" == "true" ]]; then
|
|
48
|
-
gsd_update=$'\033[33m⬆ /gsd:update\033[0m │ '
|
|
49
|
-
fi
|
|
50
|
-
fi
|
|
51
|
-
|
|
52
|
-
# Output
|
|
53
|
-
dirname=$(basename "$dir")
|
|
54
|
-
if [[ -n "$task" ]]; then
|
|
55
|
-
printf '%s\033[2m%s\033[0m │ \033[1m%s\033[0m │ \033[2m%s\033[0m%s' "$gsd_update" "$model" "$task" "$dirname" "$ctx"
|
|
56
|
-
else
|
|
57
|
-
printf '%s\033[2m%s\033[0m │ \033[2m%s\033[0m%s' "$gsd_update" "$model" "$dirname" "$ctx"
|
|
58
|
-
fi
|