get-shit-done-cc 1.5.21 → 1.5.23
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-phase-researcher.md +37 -4
- package/agents/gsd-planner.md +30 -3
- package/agents/gsd-roadmapper.md +11 -7
- package/bin/install.js +141 -19
- package/commands/gsd/create-roadmap.md +0 -1
- package/commands/gsd/plan-phase.md +4 -3
- package/commands/gsd/progress.md +0 -2
- package/commands/gsd/update.md +6 -0
- package/get-shit-done/workflows/create-roadmap.md +0 -1
- package/get-shit-done/workflows/discuss-phase.md +5 -3
- package/get-shit-done/workflows/execute-plan.md +0 -1
- package/hooks/gsd-check-update.sh +20 -0
- package/hooks/gsd-notify.sh +69 -0
- package/hooks/statusline.sh +11 -2
- package/package.json +1 -1
|
@@ -23,6 +23,18 @@ Your job: Answer "What do I need to know to PLAN this phase well?" Produce a sin
|
|
|
23
23
|
- Return structured result to orchestrator
|
|
24
24
|
</role>
|
|
25
25
|
|
|
26
|
+
<upstream_input>
|
|
27
|
+
**CONTEXT.md** (if exists) — User decisions from `/gsd:discuss-phase`
|
|
28
|
+
|
|
29
|
+
| Section | How You Use It |
|
|
30
|
+
|---------|----------------|
|
|
31
|
+
| `## Decisions` | Locked choices — research THESE, not alternatives |
|
|
32
|
+
| `## Claude's Discretion` | Your freedom areas — research options, recommend |
|
|
33
|
+
| `## Deferred Ideas` | Out of scope — ignore completely |
|
|
34
|
+
|
|
35
|
+
If CONTEXT.md exists, it constrains your research scope. Don't explore alternatives to locked decisions.
|
|
36
|
+
</upstream_input>
|
|
37
|
+
|
|
26
38
|
<downstream_consumer>
|
|
27
39
|
Your RESEARCH.md is consumed by `gsd-planner` which uses specific sections:
|
|
28
40
|
|
|
@@ -420,7 +432,7 @@ Things that couldn't be fully resolved:
|
|
|
420
432
|
|
|
421
433
|
<execution_flow>
|
|
422
434
|
|
|
423
|
-
## Step 1: Receive Research Scope
|
|
435
|
+
## Step 1: Receive Research Scope and Load Context
|
|
424
436
|
|
|
425
437
|
Orchestrator provides:
|
|
426
438
|
- Phase number and name
|
|
@@ -429,6 +441,25 @@ Orchestrator provides:
|
|
|
429
441
|
- Prior decisions/constraints
|
|
430
442
|
- Output file path
|
|
431
443
|
|
|
444
|
+
**Load phase context if exists:**
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
PHASE_DIR=$(ls -d .planning/phases/${PHASE}-* 2>/dev/null | head -1)
|
|
448
|
+
ls "${PHASE_DIR}/${PHASE}-CONTEXT.md" 2>/dev/null
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**If CONTEXT.md exists, read it:**
|
|
452
|
+
|
|
453
|
+
The CONTEXT.md contains user decisions from `/gsd:discuss-phase` that MUST guide your research:
|
|
454
|
+
- **Decisions** — locked choices that constrain what you research
|
|
455
|
+
- **Claude's Discretion** — areas where you have freedom
|
|
456
|
+
- **Deferred Ideas** — out of scope, ignore these
|
|
457
|
+
|
|
458
|
+
**Use CONTEXT.md to focus research:**
|
|
459
|
+
- If user decided "use library X" → research X deeply, don't explore alternatives
|
|
460
|
+
- If user decided "simple UI, no animations" → don't research animation libraries
|
|
461
|
+
- If marked as Claude's discretion → research options and recommend
|
|
462
|
+
|
|
432
463
|
Parse and confirm understanding before proceeding.
|
|
433
464
|
|
|
434
465
|
## Step 2: Identify Research Domains
|
|
@@ -484,12 +515,14 @@ Run through verification protocol checklist:
|
|
|
484
515
|
|
|
485
516
|
Use the output format template. Populate all sections with verified findings.
|
|
486
517
|
|
|
487
|
-
Write to:
|
|
518
|
+
Write to: `${PHASE_DIR}/${PHASE}-RESEARCH.md`
|
|
519
|
+
|
|
520
|
+
Where `PHASE_DIR` is the full path (e.g., `.planning/phases/01-foundation`)
|
|
488
521
|
|
|
489
522
|
## Step 6: Commit Research
|
|
490
523
|
|
|
491
524
|
```bash
|
|
492
|
-
git add
|
|
525
|
+
git add "${PHASE_DIR}/${PHASE}-RESEARCH.md"
|
|
493
526
|
git commit -m "docs(${PHASE}): research phase domain
|
|
494
527
|
|
|
495
528
|
Phase ${PHASE}: ${PHASE_NAME}
|
|
@@ -522,7 +555,7 @@ When research finishes successfully:
|
|
|
522
555
|
|
|
523
556
|
### File Created
|
|
524
557
|
|
|
525
|
-
|
|
558
|
+
`${PHASE_DIR}/${PHASE}-RESEARCH.md`
|
|
526
559
|
|
|
527
560
|
### Confidence Assessment
|
|
528
561
|
|
package/agents/gsd-planner.md
CHANGED
|
@@ -1156,11 +1156,38 @@ Write to `.planning/phases/XX-name/{phase}-{NN}-PLAN.md` (e.g., `01-02-PLAN.md`
|
|
|
1156
1156
|
Include frontmatter (phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves).
|
|
1157
1157
|
</step>
|
|
1158
1158
|
|
|
1159
|
+
<step name="update_roadmap">
|
|
1160
|
+
Update ROADMAP.md to finalize phase placeholders created by add-phase or insert-phase.
|
|
1161
|
+
|
|
1162
|
+
1. Read `.planning/ROADMAP.md`
|
|
1163
|
+
2. Find the phase entry (`### Phase {N}:`)
|
|
1164
|
+
3. Update placeholders:
|
|
1165
|
+
|
|
1166
|
+
**Goal** (only if placeholder):
|
|
1167
|
+
- `[To be planned]` → derive from CONTEXT.md > RESEARCH.md > phase description
|
|
1168
|
+
- `[Urgent work - to be planned]` → derive from same sources
|
|
1169
|
+
- If Goal already has real content → leave it alone
|
|
1170
|
+
|
|
1171
|
+
**Plans** (always update):
|
|
1172
|
+
- `**Plans:** 0 plans` → `**Plans:** {N} plans`
|
|
1173
|
+
- `**Plans:** (created by /gsd:plan-phase)` → `**Plans:** {N} plans`
|
|
1174
|
+
|
|
1175
|
+
**Plan list** (always update):
|
|
1176
|
+
- Replace `Plans:\n- [ ] TBD ...` with actual plan checkboxes:
|
|
1177
|
+
```
|
|
1178
|
+
Plans:
|
|
1179
|
+
- [ ] {phase}-01-PLAN.md — {brief objective}
|
|
1180
|
+
- [ ] {phase}-02-PLAN.md — {brief objective}
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
4. Write updated ROADMAP.md
|
|
1184
|
+
</step>
|
|
1185
|
+
|
|
1159
1186
|
<step name="git_commit">
|
|
1160
|
-
Commit phase plan(s):
|
|
1187
|
+
Commit phase plan(s) and updated roadmap:
|
|
1161
1188
|
|
|
1162
1189
|
```bash
|
|
1163
|
-
git add .planning/phases/${PHASE}-*/${PHASE}-*-PLAN.md
|
|
1190
|
+
git add .planning/phases/${PHASE}-*/${PHASE}-*-PLAN.md .planning/ROADMAP.md
|
|
1164
1191
|
git commit -m "docs(${PHASE}): create phase plan
|
|
1165
1192
|
|
|
1166
1193
|
Phase ${PHASE}: ${PHASE_NAME}
|
|
@@ -1264,7 +1291,7 @@ Execute: `/gsd:execute-phase {phase}`
|
|
|
1264
1291
|
|
|
1265
1292
|
### Files Updated
|
|
1266
1293
|
|
|
1267
|
-
- .planning/phases/{phase_dir}/{plan}-PLAN.md
|
|
1294
|
+
- .planning/phases/{phase_dir}/{phase}-{plan}-PLAN.md
|
|
1268
1295
|
|
|
1269
1296
|
{If any issues NOT addressed:}
|
|
1270
1297
|
|
package/agents/gsd-roadmapper.md
CHANGED
|
@@ -505,13 +505,17 @@ If gaps found, include in draft for user decision.
|
|
|
505
505
|
|
|
506
506
|
**Write files first, then return.** This ensures artifacts persist even if context is lost.
|
|
507
507
|
|
|
508
|
-
1. **Create phase directories:**
|
|
508
|
+
1. **Create phase directories (zero-padded):**
|
|
509
509
|
```bash
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
510
|
+
# Always zero-pad phase numbers: 01, 02, ... 09, 10, 11
|
|
511
|
+
for i in 1 2 3; do
|
|
512
|
+
PADDED=$(printf "%02d" $i)
|
|
513
|
+
mkdir -p ".planning/phases/${PADDED}-{phase-name}"
|
|
514
|
+
done
|
|
513
515
|
```
|
|
514
516
|
|
|
517
|
+
Examples: `01-foundation`, `02-core-features`, `10-polish`
|
|
518
|
+
|
|
515
519
|
2. **Write ROADMAP.md** using output format
|
|
516
520
|
|
|
517
521
|
3. **Write STATE.md** using output format
|
|
@@ -546,9 +550,9 @@ When files are written and returning to orchestrator:
|
|
|
546
550
|
**Files written:**
|
|
547
551
|
- .planning/ROADMAP.md
|
|
548
552
|
- .planning/STATE.md
|
|
549
|
-
- .planning/phases/01-{name}/
|
|
550
|
-
- .planning/phases/02-{name}/
|
|
551
|
-
...
|
|
553
|
+
- .planning/phases/01-{phase-name}/
|
|
554
|
+
- .planning/phases/02-{phase-name}/
|
|
555
|
+
- ... (all phases zero-padded)
|
|
552
556
|
|
|
553
557
|
**Updated:**
|
|
554
558
|
- .planning/REQUIREMENTS.md (traceability section)
|
package/bin/install.js
CHANGED
|
@@ -55,6 +55,8 @@ 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');
|
|
58
60
|
|
|
59
61
|
console.log(banner);
|
|
60
62
|
|
|
@@ -68,6 +70,8 @@ if (hasHelp) {
|
|
|
68
70
|
${cyan}-c, --config-dir <path>${reset} Specify custom Claude config directory
|
|
69
71
|
${cyan}-h, --help${reset} Show this help message
|
|
70
72
|
${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
|
|
71
75
|
|
|
72
76
|
${yellow}Examples:${reset}
|
|
73
77
|
${dim}# Install to default ~/.claude directory${reset}
|
|
@@ -225,29 +229,81 @@ function install(isGlobal) {
|
|
|
225
229
|
console.log(` ${green}✓${reset} Installed hooks`);
|
|
226
230
|
}
|
|
227
231
|
|
|
228
|
-
// Configure statusline in settings.json
|
|
232
|
+
// Configure statusline and hooks in settings.json
|
|
229
233
|
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
230
234
|
const settings = readSettings(settingsPath);
|
|
231
235
|
const statuslineCommand = isGlobal
|
|
232
236
|
? '$HOME/.claude/hooks/statusline.sh'
|
|
233
237
|
: '.claude/hooks/statusline.sh';
|
|
238
|
+
const updateCheckCommand = isGlobal
|
|
239
|
+
? '$HOME/.claude/hooks/gsd-check-update.sh'
|
|
240
|
+
: '.claude/hooks/gsd-check-update.sh';
|
|
241
|
+
const notifyCommand = isGlobal
|
|
242
|
+
? '$HOME/.claude/hooks/gsd-notify.sh'
|
|
243
|
+
: '.claude/hooks/gsd-notify.sh';
|
|
244
|
+
|
|
245
|
+
// Configure SessionStart hook for update checking
|
|
246
|
+
if (!settings.hooks) {
|
|
247
|
+
settings.hooks = {};
|
|
248
|
+
}
|
|
249
|
+
if (!settings.hooks.SessionStart) {
|
|
250
|
+
settings.hooks.SessionStart = [];
|
|
251
|
+
}
|
|
234
252
|
|
|
235
|
-
|
|
253
|
+
// Check if GSD update hook already exists
|
|
254
|
+
const hasGsdUpdateHook = settings.hooks.SessionStart.some(entry =>
|
|
255
|
+
entry.hooks && entry.hooks.some(h => h.command && h.command.includes('gsd-check-update'))
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
if (!hasGsdUpdateHook) {
|
|
259
|
+
settings.hooks.SessionStart.push({
|
|
260
|
+
hooks: [
|
|
261
|
+
{
|
|
262
|
+
type: 'command',
|
|
263
|
+
command: updateCheckCommand
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
});
|
|
267
|
+
console.log(` ${green}✓${reset} Configured update check hook`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return { settingsPath, settings, statuslineCommand, notifyCommand };
|
|
236
271
|
}
|
|
237
272
|
|
|
238
273
|
/**
|
|
239
|
-
* Apply statusline config
|
|
274
|
+
* Apply statusline and notification config, then print completion message
|
|
240
275
|
*/
|
|
241
|
-
function finishInstall(settingsPath, settings, statuslineCommand,
|
|
242
|
-
if (
|
|
276
|
+
function finishInstall(settingsPath, settings, statuslineCommand, notifyCommand, shouldInstallStatusline, shouldInstallNotify) {
|
|
277
|
+
if (shouldInstallStatusline) {
|
|
243
278
|
settings.statusLine = {
|
|
244
279
|
type: 'command',
|
|
245
280
|
command: statuslineCommand
|
|
246
281
|
};
|
|
247
|
-
writeSettings(settingsPath, settings);
|
|
248
282
|
console.log(` ${green}✓${reset} Configured statusline`);
|
|
249
283
|
}
|
|
250
284
|
|
|
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
|
+
// Always write settings (hooks were already configured in install())
|
|
305
|
+
writeSettings(settingsPath, settings);
|
|
306
|
+
|
|
251
307
|
console.log(`
|
|
252
308
|
${green}Done!${reset} Launch Claude Code and run ${cyan}/gsd:help${reset}.
|
|
253
309
|
`);
|
|
@@ -256,7 +312,7 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstall)
|
|
|
256
312
|
/**
|
|
257
313
|
* Handle statusline configuration with optional prompt
|
|
258
314
|
*/
|
|
259
|
-
function handleStatusline(
|
|
315
|
+
function handleStatusline(settings, isInteractive, callback) {
|
|
260
316
|
const hasExisting = settings.statusLine != null;
|
|
261
317
|
|
|
262
318
|
// No existing statusline - just install it
|
|
@@ -309,6 +365,66 @@ function handleStatusline(settingsPath, settings, statuslineCommand, isInteracti
|
|
|
309
365
|
});
|
|
310
366
|
}
|
|
311
367
|
|
|
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
|
+
|
|
312
428
|
/**
|
|
313
429
|
* Prompt for install location
|
|
314
430
|
*/
|
|
@@ -332,10 +448,12 @@ function promptLocation() {
|
|
|
332
448
|
rl.close();
|
|
333
449
|
const choice = answer.trim() || '1';
|
|
334
450
|
const isGlobal = choice !== '2';
|
|
335
|
-
const { settingsPath, settings, statuslineCommand } = install(isGlobal);
|
|
336
|
-
// Interactive mode - prompt for
|
|
337
|
-
handleStatusline(
|
|
338
|
-
|
|
451
|
+
const { settingsPath, settings, statuslineCommand, notifyCommand } = install(isGlobal);
|
|
452
|
+
// Interactive mode - prompt for optional features
|
|
453
|
+
handleStatusline(settings, true, (shouldInstallStatusline) => {
|
|
454
|
+
handleNotifications(settings, true, (shouldInstallNotify) => {
|
|
455
|
+
finishInstall(settingsPath, settings, statuslineCommand, notifyCommand, shouldInstallStatusline, shouldInstallNotify);
|
|
456
|
+
});
|
|
339
457
|
});
|
|
340
458
|
});
|
|
341
459
|
}
|
|
@@ -348,16 +466,20 @@ if (hasGlobal && hasLocal) {
|
|
|
348
466
|
console.error(` ${yellow}Cannot use --config-dir with --local${reset}`);
|
|
349
467
|
process.exit(1);
|
|
350
468
|
} else if (hasGlobal) {
|
|
351
|
-
const { settingsPath, settings, statuslineCommand } = install(true);
|
|
352
|
-
// Non-interactive -
|
|
353
|
-
handleStatusline(
|
|
354
|
-
|
|
469
|
+
const { settingsPath, settings, statuslineCommand, notifyCommand } = install(true);
|
|
470
|
+
// Non-interactive - respect flags
|
|
471
|
+
handleStatusline(settings, false, (shouldInstallStatusline) => {
|
|
472
|
+
handleNotifications(settings, false, (shouldInstallNotify) => {
|
|
473
|
+
finishInstall(settingsPath, settings, statuslineCommand, notifyCommand, shouldInstallStatusline, shouldInstallNotify);
|
|
474
|
+
});
|
|
355
475
|
});
|
|
356
476
|
} else if (hasLocal) {
|
|
357
|
-
const { settingsPath, settings, statuslineCommand } = install(false);
|
|
358
|
-
// Non-interactive -
|
|
359
|
-
handleStatusline(
|
|
360
|
-
|
|
477
|
+
const { settingsPath, settings, statuslineCommand, notifyCommand } = install(false);
|
|
478
|
+
// Non-interactive - respect flags
|
|
479
|
+
handleStatusline(settings, false, (shouldInstallStatusline) => {
|
|
480
|
+
handleNotifications(settings, false, (shouldInstallNotify) => {
|
|
481
|
+
finishInstall(settingsPath, settings, statuslineCommand, notifyCommand, shouldInstallStatusline, shouldInstallNotify);
|
|
482
|
+
});
|
|
361
483
|
});
|
|
362
484
|
} else {
|
|
363
485
|
promptLocation();
|
|
@@ -81,10 +81,11 @@ grep -A5 "Phase ${PHASE}:" .planning/ROADMAP.md 2>/dev/null
|
|
|
81
81
|
```bash
|
|
82
82
|
PHASE_DIR=$(ls -d .planning/phases/${PHASE}-* 2>/dev/null | head -1)
|
|
83
83
|
if [ -z "$PHASE_DIR" ]; then
|
|
84
|
-
# Create phase directory from roadmap name
|
|
84
|
+
# Create phase directory from roadmap name with zero-padded phase number
|
|
85
85
|
PHASE_NAME=$(grep "Phase ${PHASE}:" .planning/ROADMAP.md | sed 's/.*Phase [0-9]*: //' | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
PADDED_PHASE=$(printf "%02d" ${PHASE})
|
|
87
|
+
mkdir -p ".planning/phases/${PADDED_PHASE}-${PHASE_NAME}"
|
|
88
|
+
PHASE_DIR=".planning/phases/${PADDED_PHASE}-${PHASE_NAME}"
|
|
88
89
|
fi
|
|
89
90
|
```
|
|
90
91
|
|
package/commands/gsd/progress.md
CHANGED
|
@@ -201,7 +201,6 @@ Check if `{phase}-CONTEXT.md` exists in phase directory.
|
|
|
201
201
|
|
|
202
202
|
**Also available:**
|
|
203
203
|
- `/gsd:discuss-phase {phase}` — gather context first
|
|
204
|
-
- `/gsd:research-phase {phase}` — investigate unknowns
|
|
205
204
|
- `/gsd:list-phase-assumptions {phase}` — see Claude's assumptions
|
|
206
205
|
|
|
207
206
|
---
|
|
@@ -276,7 +275,6 @@ Read ROADMAP.md to get the next phase's name and goal.
|
|
|
276
275
|
**Also available:**
|
|
277
276
|
- `/gsd:verify-work {Z}` — user acceptance test before continuing
|
|
278
277
|
- `/gsd:discuss-phase {Z+1}` — gather context first
|
|
279
|
-
- `/gsd:research-phase {Z+1}` — investigate unknowns
|
|
280
278
|
|
|
281
279
|
---
|
|
282
280
|
```
|
package/commands/gsd/update.md
CHANGED
|
@@ -85,6 +85,12 @@ npx get-shit-done-cc --global
|
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
Capture output. If install fails, show error and STOP.
|
|
88
|
+
|
|
89
|
+
Clear the update cache so statusline indicator disappears:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
rm -f ~/.claude/cache/gsd-update-check.json
|
|
93
|
+
```
|
|
88
94
|
</step>
|
|
89
95
|
|
|
90
96
|
<step name="fetch_changelog">
|
|
@@ -229,7 +229,9 @@ Track deferred ideas internally.
|
|
|
229
229
|
<step name="write_context">
|
|
230
230
|
Create CONTEXT.md capturing decisions made.
|
|
231
231
|
|
|
232
|
-
**File location:** `.planning/phases/${
|
|
232
|
+
**File location:** `.planning/phases/${PADDED_PHASE}-${SLUG}/${PADDED_PHASE}-CONTEXT.md`
|
|
233
|
+
|
|
234
|
+
Zero-pad the phase number: `PADDED_PHASE=$(printf "%02d" ${PHASE})`
|
|
233
235
|
|
|
234
236
|
Create phase directory if it doesn't exist. Use roadmap phase name for slug (lowercase, hyphens).
|
|
235
237
|
|
|
@@ -294,7 +296,7 @@ Write file.
|
|
|
294
296
|
Present summary and next steps:
|
|
295
297
|
|
|
296
298
|
```
|
|
297
|
-
Created: .planning/phases/${
|
|
299
|
+
Created: .planning/phases/${PADDED_PHASE}-${SLUG}/${PADDED_PHASE}-CONTEXT.md
|
|
298
300
|
|
|
299
301
|
## Decisions Captured
|
|
300
302
|
|
|
@@ -321,7 +323,7 @@ Created: .planning/phases/${PHASE}-${SLUG}/${PHASE}-CONTEXT.md
|
|
|
321
323
|
---
|
|
322
324
|
|
|
323
325
|
**Also available:**
|
|
324
|
-
- `/gsd:
|
|
326
|
+
- `/gsd:plan-phase ${PHASE} --skip-research` — plan without research
|
|
325
327
|
- Review/edit CONTEXT.md before continuing
|
|
326
328
|
|
|
327
329
|
---
|
|
@@ -1771,7 +1771,6 @@ All {Y} plans finished.
|
|
|
1771
1771
|
**Also available:**
|
|
1772
1772
|
- `/gsd:verify-work {Z}` — manual acceptance testing before continuing
|
|
1773
1773
|
- `/gsd:discuss-phase {Z+1}` — gather context first
|
|
1774
|
-
- `/gsd:research-phase {Z+1}` — investigate unknowns
|
|
1775
1774
|
- Review phase accomplishments before continuing
|
|
1776
1775
|
|
|
1777
1776
|
---
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
# Try to get context from GSD state file
|
|
17
|
+
message=""
|
|
18
|
+
state_file="$cwd/.planning/STATE.md"
|
|
19
|
+
if [[ -f "$state_file" ]]; then
|
|
20
|
+
phase=$(grep -m1 "^current_phase:" "$state_file" 2>/dev/null | sed 's/^current_phase: *//')
|
|
21
|
+
status=$(grep -m1 "^status:" "$state_file" 2>/dev/null | sed 's/^status: *//')
|
|
22
|
+
if [[ -n "$phase" && -n "$status" ]]; then
|
|
23
|
+
message="Phase $phase: $status"
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Fallback: check todo list for current/completed task
|
|
28
|
+
if [[ -z "$message" && -n "$session_id" ]]; then
|
|
29
|
+
todo_file=$(ls -t "$HOME/.claude/todos/${session_id}"*.json 2>/dev/null | head -1)
|
|
30
|
+
if [[ -f "$todo_file" ]]; then
|
|
31
|
+
# Get most recently completed task, or in-progress task
|
|
32
|
+
completed=$(jq -r '[.[] | select(.status=="completed")] | last | .content // empty' "$todo_file" 2>/dev/null)
|
|
33
|
+
if [[ -n "$completed" ]]; then
|
|
34
|
+
message="Completed: $completed"
|
|
35
|
+
else
|
|
36
|
+
in_progress=$(jq -r '.[] | select(.status=="in_progress") | .content' "$todo_file" 2>/dev/null | head -1)
|
|
37
|
+
if [[ -n "$in_progress" ]]; then
|
|
38
|
+
message="Paused: $in_progress"
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Fallback: generic message
|
|
45
|
+
if [[ -z "$message" ]]; then
|
|
46
|
+
message="Ready for input"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Send notification based on OS
|
|
50
|
+
case "$(uname -s)" in
|
|
51
|
+
Darwin)
|
|
52
|
+
osascript -e "display alert \"GSD: $project\" message \"$message\" as informational" &>/dev/null &
|
|
53
|
+
;;
|
|
54
|
+
Linux)
|
|
55
|
+
if command -v notify-send &>/dev/null; then
|
|
56
|
+
notify-send "GSD: $project" "$message" --urgency=normal
|
|
57
|
+
elif command -v zenity &>/dev/null; then
|
|
58
|
+
zenity --info --title="GSD: $project" --text="$message" &
|
|
59
|
+
fi
|
|
60
|
+
;;
|
|
61
|
+
MINGW*|CYGWIN*|MSYS*)
|
|
62
|
+
# Windows via PowerShell
|
|
63
|
+
if command -v powershell.exe &>/dev/null; then
|
|
64
|
+
powershell.exe -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('$message', 'GSD: $project', 'OK', 'Information')" &>/dev/null &
|
|
65
|
+
fi
|
|
66
|
+
;;
|
|
67
|
+
esac
|
|
68
|
+
|
|
69
|
+
exit 0
|
package/hooks/statusline.sh
CHANGED
|
@@ -40,10 +40,19 @@ if [[ -f "$todo" ]]; then
|
|
|
40
40
|
task=$(jq -r '.[] | select(.status=="in_progress") | .activeForm' "$todo" 2>/dev/null | head -1)
|
|
41
41
|
fi
|
|
42
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
|
+
|
|
43
52
|
# Output
|
|
44
53
|
dirname=$(basename "$dir")
|
|
45
54
|
if [[ -n "$task" ]]; then
|
|
46
|
-
printf '\033[2m%s\033[0m │ \033[1m%s\033[0m │ \033[2m%s\033[0m%s' "$model" "$task" "$dirname" "$ctx"
|
|
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"
|
|
47
56
|
else
|
|
48
|
-
printf '\033[2m%s\033[0m │ \033[2m%s\033[0m%s' "$model" "$dirname" "$ctx"
|
|
57
|
+
printf '%s\033[2m%s\033[0m │ \033[2m%s\033[0m%s' "$gsd_update" "$model" "$dirname" "$ctx"
|
|
49
58
|
fi
|
package/package.json
CHANGED