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.
@@ -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: `.planning/phases/{phase_dir}/{phase}-RESEARCH.md`
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 .planning/phases/${PHASE_DIR}/${PHASE}-RESEARCH.md
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
- `.planning/phases/{phase_dir}/{phase}-RESEARCH.md`
558
+ `${PHASE_DIR}/${PHASE}-RESEARCH.md`
526
559
 
527
560
  ### Confidence Assessment
528
561
 
@@ -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
 
@@ -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
- mkdir -p .planning/phases/01-{name}
511
- mkdir -p .planning/phases/02-{name}
512
- # etc.
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
- return { settingsPath, settings, statuslineCommand };
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 and print completion message
274
+ * Apply statusline and notification config, then print completion message
240
275
  */
241
- function finishInstall(settingsPath, settings, statuslineCommand, shouldInstall) {
242
- if (shouldInstall) {
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(settingsPath, settings, statuslineCommand, isInteractive, callback) {
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 statusline if needed
337
- handleStatusline(settingsPath, settings, statuslineCommand, true, (shouldInstall) => {
338
- finishInstall(settingsPath, settings, statuslineCommand, shouldInstall);
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 - skip prompt, respect --force-statusline
353
- handleStatusline(settingsPath, settings, statuslineCommand, false, (shouldInstall) => {
354
- finishInstall(settingsPath, settings, statuslineCommand, shouldInstall);
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 - skip prompt, respect --force-statusline
359
- handleStatusline(settingsPath, settings, statuslineCommand, false, (shouldInstall) => {
360
- finishInstall(settingsPath, settings, statuslineCommand, shouldInstall);
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();
@@ -119,7 +119,6 @@ Roadmap created:
119
119
 
120
120
  **Also available:**
121
121
  - `/gsd:discuss-phase 1` — gather context first
122
- - `/gsd:research-phase 1` — investigate unknowns
123
122
  - Review roadmap
124
123
 
125
124
  ---
@@ -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
- mkdir -p ".planning/phases/${PHASE}-${PHASE_NAME}"
87
- PHASE_DIR=".planning/phases/${PHASE}-${PHASE_NAME}"
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
 
@@ -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
  ```
@@ -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">
@@ -585,7 +585,6 @@ Project initialized:
585
585
 
586
586
  **Also available:**
587
587
  - `/gsd:discuss-phase 1` — gather context first
588
- - `/gsd:research-phase 1` — investigate unknowns
589
588
  - Review roadmap
590
589
 
591
590
  ---
@@ -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/${PHASE}-${SLUG}/${PHASE}-CONTEXT.md`
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/${PHASE}-${SLUG}/${PHASE}-CONTEXT.md
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:research-phase ${PHASE}` — investigate unknowns first
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
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "get-shit-done-cc",
3
- "version": "1.5.21",
3
+ "version": "1.5.23",
4
4
  "description": "A meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.",
5
5
  "bin": {
6
6
  "get-shit-done-cc": "bin/install.js"