get-shit-done-cc 1.22.0 → 1.22.2

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.
Files changed (41) hide show
  1. package/agents/gsd-codebase-mapper.md +9 -1
  2. package/agents/gsd-debugger.md +10 -0
  3. package/agents/gsd-executor.md +11 -2
  4. package/agents/gsd-integration-checker.md +2 -0
  5. package/agents/gsd-phase-researcher.md +9 -1
  6. package/agents/gsd-plan-checker.md +3 -1
  7. package/agents/gsd-planner.md +16 -3
  8. package/agents/gsd-project-researcher.md +10 -0
  9. package/agents/gsd-research-synthesizer.md +10 -0
  10. package/agents/gsd-roadmapper.md +11 -1
  11. package/agents/gsd-verifier.md +8 -0
  12. package/bin/install.js +51 -26
  13. package/commands/gsd/discuss-phase.md +14 -10
  14. package/commands/gsd/reapply-patches.md +17 -4
  15. package/commands/gsd/research-phase.md +4 -4
  16. package/get-shit-done/bin/gsd-tools.cjs +6 -2
  17. package/get-shit-done/bin/lib/commands.cjs +3 -3
  18. package/get-shit-done/bin/lib/core.cjs +53 -2
  19. package/get-shit-done/bin/lib/milestone.cjs +22 -48
  20. package/get-shit-done/bin/lib/phase.cjs +27 -4
  21. package/get-shit-done/bin/lib/state.cjs +100 -59
  22. package/get-shit-done/bin/lib/template.cjs +3 -3
  23. package/get-shit-done/references/checkpoints.md +1 -1
  24. package/get-shit-done/references/decimal-phase-calculation.md +2 -2
  25. package/get-shit-done/references/phase-argument-parsing.md +1 -1
  26. package/get-shit-done/references/questioning.md +17 -0
  27. package/get-shit-done/workflows/diagnose-issues.md +1 -1
  28. package/get-shit-done/workflows/discuss-phase.md +106 -46
  29. package/get-shit-done/workflows/execute-phase.md +13 -4
  30. package/get-shit-done/workflows/new-milestone.md +3 -2
  31. package/get-shit-done/workflows/new-project.md +10 -18
  32. package/get-shit-done/workflows/plan-milestone-gaps.md +1 -1
  33. package/get-shit-done/workflows/plan-phase.md +27 -48
  34. package/get-shit-done/workflows/quick.md +2 -2
  35. package/get-shit-done/workflows/transition.md +2 -2
  36. package/get-shit-done/workflows/update.md +35 -10
  37. package/hooks/dist/gsd-check-update.js +22 -3
  38. package/hooks/dist/gsd-context-monitor.js +28 -9
  39. package/hooks/dist/gsd-statusline.js +19 -12
  40. package/package.json +1 -1
  41. package/commands/gsd/new-project.md.bak +0 -1041
@@ -3,6 +3,14 @@ name: gsd-codebase-mapper
3
3
  description: Explores codebase and writes structured analysis documents. Spawned by map-codebase with a focus area (tech, arch, quality, concerns). Writes documents directly to reduce orchestrator context load.
4
4
  tools: Read, Bash, Grep, Glob, Write
5
5
  color: cyan
6
+ skills:
7
+ - gsd-mapper-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -148,7 +156,7 @@ Write document(s) to `.planning/codebase/` using the templates below.
148
156
  3. If something is not found, use "Not detected" or "Not applicable"
149
157
  4. Always include file paths with backticks
150
158
 
151
- Use the Write tool to create each document.
159
+ **ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
152
160
  </step>
153
161
 
154
162
  <step name="return_confirmation">
@@ -3,6 +3,14 @@ name: gsd-debugger
3
3
  description: Investigates bugs using scientific method, manages debug sessions, handles checkpoints. Spawned by /gsd:debug orchestrator.
4
4
  tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch
5
5
  color: orange
6
+ skills:
7
+ - gsd-debugger-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -849,6 +857,8 @@ ls .planning/debug/*.md 2>/dev/null | grep -v resolved
849
857
  <step name="create_debug_file">
850
858
  **Create debug file IMMEDIATELY.**
851
859
 
860
+ **ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
861
+
852
862
  1. Generate slug from user input (lowercase, hyphens, max 30 chars)
853
863
  2. `mkdir -p .planning/debug`
854
864
  3. Create file with initial state:
@@ -3,6 +3,14 @@ name: gsd-executor
3
3
  description: Executes GSD plans with atomic commits, deviation handling, checkpoint protocols, and state management. Spawned by execute-phase orchestrator or execute-plan command.
4
4
  tools: Read, Write, Edit, Bash, Grep, Glob
5
5
  color: yellow
6
+ skills:
7
+ - gsd-executor-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -197,13 +205,14 @@ Do NOT continue reading. Analysis without action is a stuck signal.
197
205
  </authentication_gates>
198
206
 
199
207
  <auto_mode_detection>
200
- Check if auto mode is active at executor start:
208
+ Check if auto mode is active at executor start (chain flag or user preference):
201
209
 
202
210
  ```bash
211
+ AUTO_CHAIN=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get workflow._auto_chain_active 2>/dev/null || echo "false")
203
212
  AUTO_CFG=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get workflow.auto_advance 2>/dev/null || echo "false")
204
213
  ```
205
214
 
206
- Store the result for checkpoint handling below.
215
+ Auto mode is active if either `AUTO_CHAIN` or `AUTO_CFG` is `"true"`. Store the result for checkpoint handling below.
207
216
  </auto_mode_detection>
208
217
 
209
218
  <checkpoint_protocol>
@@ -3,6 +3,8 @@ name: gsd-integration-checker
3
3
  description: Verifies cross-phase integration and E2E flows. Checks that phases connect properly and user workflows complete end-to-end.
4
4
  tools: Read, Bash, Grep, Glob
5
5
  color: blue
6
+ skills:
7
+ - gsd-integration-workflow
6
8
  ---
7
9
 
8
10
  <role>
@@ -3,6 +3,14 @@ name: gsd-phase-researcher
3
3
  description: Researches how to implement a phase before planning. Produces RESEARCH.md consumed by gsd-planner. Spawned by /gsd:plan-phase orchestrator.
4
4
  tools: Read, Write, Bash, Grep, Glob, WebSearch, WebFetch, mcp__context7__*
5
5
  color: cyan
6
+ skills:
7
+ - gsd-researcher-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -421,7 +429,7 @@ List missing test files, framework config, or shared fixtures needed before impl
421
429
 
422
430
  ## Step 6: Write RESEARCH.md
423
431
 
424
- **ALWAYS use Write tool to persist to disk** — mandatory regardless of `commit_docs` setting.
432
+ **ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation. Mandatory regardless of `commit_docs` setting.
425
433
 
426
434
  **CRITICAL: If CONTEXT.md exists, FIRST content section MUST be `<user_constraints>`:**
427
435
 
@@ -3,6 +3,8 @@ name: gsd-plan-checker
3
3
  description: Verifies plans will achieve phase goal before execution. Goal-backward analysis of plan quality. Spawned by /gsd:plan-phase orchestrator.
4
4
  tools: Read, Bash, Glob, Grep
5
5
  color: green
6
+ skills:
7
+ - gsd-plan-checker-workflow
6
8
  ---
7
9
 
8
10
  <role>
@@ -445,7 +447,7 @@ Session persists | 01 | 3 | COVERED
445
447
 
446
448
  For each requirement: find covering task(s), verify action is specific, flag gaps.
447
449
 
448
- **Exhaustive cross-check:** Also read PROJECT.md requirements (not just phase goal). Verify no PROJECT.md requirement relevant to this phase is silently dropped. Any unmapped requirement is an automatic blocker — list it explicitly in issues.
450
+ **Exhaustive cross-check:** Also read PROJECT.md requirements (not just phase goal). Verify no PROJECT.md requirement relevant to this phase is silently dropped. A requirement is "relevant" if the ROADMAP.md explicitly maps it to this phase or if the phase goal directly implies it — do NOT flag requirements that belong to other phases or future work. Any unmapped relevant requirement is an automatic blocker — list it explicitly in issues.
449
451
 
450
452
  ## Step 5: Validate Task Structure
451
453
 
@@ -3,6 +3,14 @@ name: gsd-planner
3
3
  description: Creates executable phase plans with task breakdown, dependency analysis, and goal-backward verification. Spawned by /gsd:plan-phase orchestrator.
4
4
  tools: Read, Write, Bash, Glob, Grep, WebFetch, mcp__context7__*
5
5
  color: green
6
+ skills:
7
+ - gsd-planner-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -844,15 +852,20 @@ grep -l "status: diagnosed" "$phase_dir"/*-UAT.md 2>/dev/null
844
852
  </task>
845
853
  ```
846
854
 
847
- **7. Write PLAN.md files:**
855
+ **7. Assign waves using standard dependency analysis** (same as `assign_waves` step):
856
+ - Plans with no dependencies → wave 1
857
+ - Plans that depend on other gap closure plans → max(dependency waves) + 1
858
+ - Also consider dependencies on existing (non-gap) plans in the phase
859
+
860
+ **8. Write PLAN.md files:**
848
861
 
849
862
  ```yaml
850
863
  ---
851
864
  phase: XX-name
852
865
  plan: NN # Sequential after existing
853
866
  type: execute
854
- wave: 1 # Gap closures typically single wave
855
- depends_on: []
867
+ wave: N # Computed from depends_on (see assign_waves)
868
+ depends_on: [...] # Other plans this depends on (gap or existing)
856
869
  files_modified: [...]
857
870
  autonomous: true
858
871
  gap_closure: true # Flag for tracking
@@ -3,6 +3,14 @@ name: gsd-project-researcher
3
3
  description: Researches domain ecosystem before roadmap creation. Produces files in .planning/research/ consumed during roadmap creation. Spawned by /gsd:new-project or /gsd:new-milestone orchestrators.
4
4
  tools: Read, Write, Bash, Grep, Glob, WebSearch, WebFetch, mcp__context7__*
5
5
  color: cyan
6
+ skills:
7
+ - gsd-researcher-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -518,6 +526,8 @@ Run pre-submission checklist (see verification_protocol).
518
526
 
519
527
  ## Step 5: Write Output Files
520
528
 
529
+ **ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
530
+
521
531
  In `.planning/research/`:
522
532
  1. **SUMMARY.md** — Always
523
533
  2. **STACK.md** — Always
@@ -3,6 +3,14 @@ name: gsd-research-synthesizer
3
3
  description: Synthesizes research outputs from parallel researcher agents into SUMMARY.md. Spawned by /gsd:new-project after 4 researcher agents complete.
4
4
  tools: Read, Write, Bash
5
5
  color: purple
6
+ skills:
7
+ - gsd-synthesizer-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -122,6 +130,8 @@ Identify gaps that couldn't be resolved and need attention during planning.
122
130
 
123
131
  ## Step 6: Write SUMMARY.md
124
132
 
133
+ **ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
134
+
125
135
  Use template: ~/.claude/get-shit-done/templates/research-project/SUMMARY.md
126
136
 
127
137
  Write to `.planning/research/SUMMARY.md`
@@ -3,6 +3,14 @@ name: gsd-roadmapper
3
3
  description: Creates project roadmaps with phase breakdown, requirement mapping, success criteria derivation, and coverage validation. Spawned by /gsd:new-project orchestrator.
4
4
  tools: Read, Write, Bash, Glob, Grep
5
5
  color: purple
6
+ skills:
7
+ - gsd-roadmapper-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
@@ -449,7 +457,9 @@ If gaps found, include in draft for user decision.
449
457
 
450
458
  ## Step 7: Write Files Immediately
451
459
 
452
- **Write files first, then return.** This ensures artifacts persist even if context is lost.
460
+ **ALWAYS use the Write tool to create files** never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
461
+
462
+ Write files first, then return. This ensures artifacts persist even if context is lost.
453
463
 
454
464
  1. **Write ROADMAP.md** using output format
455
465
 
@@ -3,6 +3,14 @@ name: gsd-verifier
3
3
  description: Verifies phase goal achievement through goal-backward analysis. Checks codebase delivers what phase promised, not just that tasks completed. Creates VERIFICATION.md report.
4
4
  tools: Read, Write, Bash, Grep, Glob
5
5
  color: green
6
+ skills:
7
+ - gsd-verifier-workflow
8
+ # hooks:
9
+ # PostToolUse:
10
+ # - matcher: "Write|Edit"
11
+ # hooks:
12
+ # - type: command
13
+ # command: "npx eslint --fix $FILE 2>/dev/null || true"
6
14
  ---
7
15
 
8
16
  <role>
package/bin/install.js CHANGED
@@ -638,9 +638,31 @@ function mergeCodexConfig(configPath, gsdBlock) {
638
638
 
639
639
  // Case 2: Has GSD marker — truncate and re-append
640
640
  if (markerIndex !== -1) {
641
- const before = existing.substring(0, markerIndex).trimEnd();
642
- const newContent = before ? before + '\n\n' + gsdBlock + '\n' : gsdBlock + '\n';
643
- fs.writeFileSync(configPath, newContent);
641
+ let before = existing.substring(0, markerIndex).trimEnd();
642
+ if (before) {
643
+ // Strip any GSD-managed sections that leaked above the marker from previous installs
644
+ before = before.replace(/^\[agents\.gsd-[^\]]+\]\n(?:(?!\[)[^\n]*\n?)*/gm, '');
645
+ before = before.replace(/^\[agents\]\n(?:(?!\[)[^\n]*\n?)*/m, '');
646
+ before = before.replace(/\n{3,}/g, '\n\n').trimEnd();
647
+
648
+ // Re-inject feature keys if user has [features] above the marker
649
+ const hasFeatures = /^\[features\]\s*$/m.test(before);
650
+ if (hasFeatures) {
651
+ if (!before.includes('multi_agent')) {
652
+ before = before.replace(/^\[features\]\s*$/m, '[features]\nmulti_agent = true');
653
+ }
654
+ if (!before.includes('default_mode_request_user_input')) {
655
+ before = before.replace(/^\[features\].*$/m, '$&\ndefault_mode_request_user_input = true');
656
+ }
657
+ }
658
+ // Skip [features] from gsdBlock if user already has it
659
+ const block = hasFeatures
660
+ ? GSD_CODEX_MARKER + '\n' + gsdBlock.substring(gsdBlock.indexOf('[agents]'))
661
+ : gsdBlock;
662
+ fs.writeFileSync(configPath, before + '\n\n' + block + '\n');
663
+ } else {
664
+ fs.writeFileSync(configPath, gsdBlock + '\n');
665
+ }
644
666
  return;
645
667
  }
646
668
 
@@ -1403,24 +1425,26 @@ function uninstall(isGlobal, runtime = 'claude') {
1403
1425
  }
1404
1426
  }
1405
1427
 
1406
- // Remove GSD hooks from PostToolUse
1407
- if (settings.hooks && settings.hooks.PostToolUse) {
1408
- const before = settings.hooks.PostToolUse.length;
1409
- settings.hooks.PostToolUse = settings.hooks.PostToolUse.filter(entry => {
1410
- if (entry.hooks && Array.isArray(entry.hooks)) {
1411
- const hasGsdHook = entry.hooks.some(h =>
1412
- h.command && h.command.includes('gsd-context-monitor')
1413
- );
1414
- return !hasGsdHook;
1428
+ // Remove GSD hooks from PostToolUse and AfterTool (Gemini uses AfterTool)
1429
+ for (const eventName of ['PostToolUse', 'AfterTool']) {
1430
+ if (settings.hooks && settings.hooks[eventName]) {
1431
+ const before = settings.hooks[eventName].length;
1432
+ settings.hooks[eventName] = settings.hooks[eventName].filter(entry => {
1433
+ if (entry.hooks && Array.isArray(entry.hooks)) {
1434
+ const hasGsdHook = entry.hooks.some(h =>
1435
+ h.command && h.command.includes('gsd-context-monitor')
1436
+ );
1437
+ return !hasGsdHook;
1438
+ }
1439
+ return true;
1440
+ });
1441
+ if (settings.hooks[eventName].length < before) {
1442
+ settingsModified = true;
1443
+ console.log(` ${green}✓${reset} Removed context monitor hook from settings`);
1444
+ }
1445
+ if (settings.hooks[eventName].length === 0) {
1446
+ delete settings.hooks[eventName];
1415
1447
  }
1416
- return true;
1417
- });
1418
- if (settings.hooks.PostToolUse.length < before) {
1419
- settingsModified = true;
1420
- console.log(` ${green}✓${reset} Removed context monitor hook from settings`);
1421
- }
1422
- if (settings.hooks.PostToolUse.length === 0) {
1423
- delete settings.hooks.PostToolUse;
1424
1448
  }
1425
1449
  }
1426
1450
 
@@ -2031,7 +2055,8 @@ function install(isGlobal, runtime = 'claude') {
2031
2055
  }
2032
2056
 
2033
2057
  // Configure statusline and hooks in settings.json
2034
- // Gemini shares same hook system as Claude Code for now
2058
+ // Gemini uses AfterTool instead of PostToolUse for post-tool hooks
2059
+ const postToolEvent = runtime === 'gemini' ? 'AfterTool' : 'PostToolUse';
2035
2060
  const settingsPath = path.join(targetDir, 'settings.json');
2036
2061
  const settings = cleanupOrphanedHooks(readSettings(settingsPath));
2037
2062
  const statuslineCommand = isGlobal
@@ -2080,17 +2105,17 @@ function install(isGlobal, runtime = 'claude') {
2080
2105
  console.log(` ${green}✓${reset} Configured update check hook`);
2081
2106
  }
2082
2107
 
2083
- // Configure PostToolUse hook for context window monitoring
2084
- if (!settings.hooks.PostToolUse) {
2085
- settings.hooks.PostToolUse = [];
2108
+ // Configure post-tool hook for context window monitoring
2109
+ if (!settings.hooks[postToolEvent]) {
2110
+ settings.hooks[postToolEvent] = [];
2086
2111
  }
2087
2112
 
2088
- const hasContextMonitorHook = settings.hooks.PostToolUse.some(entry =>
2113
+ const hasContextMonitorHook = settings.hooks[postToolEvent].some(entry =>
2089
2114
  entry.hooks && entry.hooks.some(h => h.command && h.command.includes('gsd-context-monitor'))
2090
2115
  );
2091
2116
 
2092
2117
  if (!hasContextMonitorHook) {
2093
- settings.hooks.PostToolUse.push({
2118
+ settings.hooks[postToolEvent].push({
2094
2119
  hooks: [
2095
2120
  {
2096
2121
  type: 'command',
@@ -18,10 +18,12 @@ allowed-tools:
18
18
  Extract implementation decisions that downstream agents need — researcher and planner will use CONTEXT.md to know what to investigate and what choices are locked.
19
19
 
20
20
  **How it works:**
21
- 1. Analyze the phase to identify gray areas (UI, UX, behavior, etc.)
22
- 2. Present gray areas user selects which to discuss
23
- 3. Deep-dive each selected area until satisfied
24
- 4. Create CONTEXT.md with decisions that guide research and planning
21
+ 1. Load prior context (PROJECT.md, REQUIREMENTS.md, STATE.md, prior CONTEXT.md files)
22
+ 2. Scout codebase for reusable assets and patterns
23
+ 3. Analyze phase skip gray areas already decided in prior phases
24
+ 4. Present remaining gray areas user selects which to discuss
25
+ 5. Deep-dive each selected area until satisfied
26
+ 6. Create CONTEXT.md with decisions that guide research and planning
25
27
 
26
28
  **Output:** `{phase_num}-CONTEXT.md` — decisions clear enough that downstream agents can act without asking the user again
27
29
  </objective>
@@ -40,12 +42,13 @@ Context files are resolved in-workflow using `init phase-op` and roadmap/state t
40
42
  <process>
41
43
  1. Validate phase number (error if missing or not in roadmap)
42
44
  2. Check if CONTEXT.md exists (offer update/view/skip if yes)
43
- 3. **Scout codebase** — Find reusable assets, patterns, and integration points
44
- 4. **Analyze phase** — Identify domain and generate code-informed gray areas
45
- 5. **Present gray areas** — Multi-select: which to discuss? (NO skip option)
46
- 6. **Deep-dive each area** — 4 questions per area, code-informed options, Context7 for library choices
47
- 7. **Write CONTEXT.md** — Sections match areas discussed + code_context section
48
- 8. Offer next steps (research or plan)
45
+ 3. **Load prior context** — Read PROJECT.md, REQUIREMENTS.md, STATE.md, and all prior CONTEXT.md files
46
+ 4. **Scout codebase** — Find reusable assets, patterns, and integration points
47
+ 5. **Analyze phase** — Check prior decisions, skip already-decided areas, generate remaining gray areas
48
+ 6. **Present gray areas** — Multi-select: which to discuss? Annotate with prior decisions + code context
49
+ 7. **Deep-dive each area** — 4 questions per area, code-informed options, Context7 for library choices
50
+ 8. **Write CONTEXT.md** Sections match areas discussed + code_context section
51
+ 9. Offer next steps (research or plan)
49
52
 
50
53
  **CRITICAL: Scope guardrail**
51
54
  - Phase boundary from ROADMAP.md is FIXED
@@ -77,6 +80,7 @@ Generate 3-4 **phase-specific** gray areas, not generic categories.
77
80
  </process>
78
81
 
79
82
  <success_criteria>
83
+ - Prior context loaded and applied (no re-asking decided questions)
80
84
  - Gray areas identified through intelligent analysis
81
85
  - User chose which areas to discuss
82
86
  - Each selected area explored until satisfied
@@ -14,11 +14,24 @@ After a GSD update wipes and reinstalls files, this command merges user's previo
14
14
  Check for local patches directory:
15
15
 
16
16
  ```bash
17
- # Global install (path templated at install time)
18
- PATCHES_DIR=~/.claude/gsd-local-patches
19
- # Local install fallback
17
+ # Global install detect runtime config directory
18
+ if [ -d "$HOME/.config/opencode/gsd-local-patches" ]; then
19
+ PATCHES_DIR="$HOME/.config/opencode/gsd-local-patches"
20
+ elif [ -d "$HOME/.opencode/gsd-local-patches" ]; then
21
+ PATCHES_DIR="$HOME/.opencode/gsd-local-patches"
22
+ elif [ -d "$HOME/.gemini/gsd-local-patches" ]; then
23
+ PATCHES_DIR="$HOME/.gemini/gsd-local-patches"
24
+ else
25
+ PATCHES_DIR="$HOME/.claude/gsd-local-patches"
26
+ fi
27
+ # Local install fallback — check all runtime directories
20
28
  if [ ! -d "$PATCHES_DIR" ]; then
21
- PATCHES_DIR=./.claude/gsd-local-patches
29
+ for dir in .config/opencode .opencode .gemini .claude; do
30
+ if [ -d "./$dir/gsd-local-patches" ]; then
31
+ PATCHES_DIR="./$dir/gsd-local-patches"
32
+ break
33
+ fi
34
+ done
22
35
  fi
23
36
  ```
24
37
 
@@ -135,8 +135,8 @@ Write to: .planning/phases/${PHASE}-{slug}/${PHASE}-RESEARCH.md
135
135
 
136
136
  ```
137
137
  Task(
138
- prompt="First, read ~/.claude/agents/gsd-phase-researcher.md for your role and instructions.\n\n" + filled_prompt,
139
- subagent_type="general-purpose",
138
+ prompt=filled_prompt,
139
+ subagent_type="gsd-phase-researcher",
140
140
  model="{researcher_model}",
141
141
  description="Research Phase {phase}"
142
142
  )
@@ -171,8 +171,8 @@ Continue research for Phase {phase_number}: {phase_name}
171
171
 
172
172
  ```
173
173
  Task(
174
- prompt="First, read ~/.claude/agents/gsd-phase-researcher.md for your role and instructions.\n\n" + continuation_prompt,
175
- subagent_type="general-purpose",
174
+ prompt=continuation_prompt,
175
+ subagent_type="gsd-phase-researcher",
176
176
  model="{researcher_model}",
177
177
  description="Continue research Phase {phase}"
178
178
  )
@@ -259,9 +259,13 @@ async function main() {
259
259
 
260
260
  case 'commit': {
261
261
  const amend = args.includes('--amend');
262
- const message = args[1];
263
- // Parse --files flag (collect args after --files, stopping at other flags)
264
262
  const filesIndex = args.indexOf('--files');
263
+ // Collect all positional args between command name and first flag,
264
+ // then join them — handles both quoted ("multi word msg") and
265
+ // unquoted (multi word msg) invocations from different shells
266
+ const endIndex = filesIndex !== -1 ? filesIndex : args.length;
267
+ const messageArgs = args.slice(1, endIndex).filter(a => !a.startsWith('--'));
268
+ const message = messageArgs.join(' ') || undefined;
265
269
  const files = filesIndex !== -1 ? args.slice(filesIndex + 1).filter(a => !a.startsWith('--')) : [];
266
270
  commands.cmdCommit(cwd, message, files, raw, amend);
267
271
  break;
@@ -4,7 +4,7 @@
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const { execSync } = require('child_process');
7
- const { safeReadFile, loadConfig, isGitIgnored, execGit, normalizePhaseName, comparePhaseNum, getArchivedPhaseDirs, generateSlugInternal, getMilestoneInfo, resolveModelInternal, MODEL_PROFILES, output, error, findPhaseInternal } = require('./core.cjs');
7
+ const { safeReadFile, loadConfig, isGitIgnored, execGit, normalizePhaseName, comparePhaseNum, getArchivedPhaseDirs, generateSlugInternal, getMilestoneInfo, resolveModelInternal, MODEL_PROFILES, toPosixPath, output, error, findPhaseInternal } = require('./core.cjs');
8
8
  const { extractFrontmatter } = require('./frontmatter.cjs');
9
9
 
10
10
  function cmdGenerateSlug(text, raw) {
@@ -68,7 +68,7 @@ function cmdListTodos(cwd, area, raw) {
68
68
  created: createdMatch ? createdMatch[1].trim() : 'unknown',
69
69
  title: titleMatch ? titleMatch[1].trim() : 'Untitled',
70
70
  area: todoArea,
71
- path: path.join('.planning', 'todos', 'pending', file),
71
+ path: toPosixPath(path.join('.planning', 'todos', 'pending', file)),
72
72
  });
73
73
  } catch {}
74
74
  }
@@ -528,7 +528,7 @@ function cmdScaffold(cwd, type, options, raw) {
528
528
  }
529
529
 
530
530
  fs.writeFileSync(filePath, content, 'utf-8');
531
- const relPath = path.relative(cwd, filePath);
531
+ const relPath = toPosixPath(path.relative(cwd, filePath));
532
532
  output({ created: true, path: relPath }, raw, relPath);
533
533
  }
534
534
 
@@ -124,7 +124,11 @@ function loadConfig(cwd) {
124
124
 
125
125
  function isGitIgnored(cwd, targetPath) {
126
126
  try {
127
- execSync('git check-ignore -q -- ' + targetPath.replace(/[^a-zA-Z0-9._\-/]/g, ''), {
127
+ // --no-index checks .gitignore rules regardless of whether the file is tracked.
128
+ // Without it, git check-ignore returns "not ignored" for tracked files even when
129
+ // .gitignore explicitly lists them — a common source of confusion when .planning/
130
+ // was committed before being added to .gitignore.
131
+ execSync('git check-ignore -q --no-index -- ' + targetPath.replace(/[^a-zA-Z0-9._\-/]/g, ''), {
128
132
  cwd,
129
133
  stdio: 'pipe',
130
134
  });
@@ -388,7 +392,18 @@ function generateSlugInternal(text) {
388
392
  function getMilestoneInfo(cwd) {
389
393
  try {
390
394
  const roadmap = fs.readFileSync(path.join(cwd, '.planning', 'ROADMAP.md'), 'utf-8');
391
- // Strip <details>...</details> blocks so shipped milestones don't interfere
395
+
396
+ // First: check for list-format roadmaps using 🚧 (in-progress) marker
397
+ // e.g. "- 🚧 **v2.1 Belgium** — Phases 24-28 (in progress)"
398
+ const inProgressMatch = roadmap.match(/🚧\s*\*\*v(\d+\.\d+)\s+([^*]+)\*\*/);
399
+ if (inProgressMatch) {
400
+ return {
401
+ version: 'v' + inProgressMatch[1],
402
+ name: inProgressMatch[2].trim(),
403
+ };
404
+ }
405
+
406
+ // Second: heading-format roadmaps — strip shipped milestones in <details> blocks
392
407
  const cleaned = roadmap.replace(/<details>[\s\S]*?<\/details>/gi, '');
393
408
  // Extract version and name from the same ## heading for consistency
394
409
  const headingMatch = cleaned.match(/## .*v(\d+\.\d+)[:\s]+([^\n(]+)/);
@@ -409,6 +424,41 @@ function getMilestoneInfo(cwd) {
409
424
  }
410
425
  }
411
426
 
427
+ /**
428
+ * Returns a filter function that checks whether a phase directory belongs
429
+ * to the current milestone based on ROADMAP.md phase headings.
430
+ * If no ROADMAP exists or no phases are listed, returns a pass-all filter.
431
+ */
432
+ function getMilestonePhaseFilter(cwd) {
433
+ const milestonePhaseNums = new Set();
434
+ try {
435
+ const roadmap = fs.readFileSync(path.join(cwd, '.planning', 'ROADMAP.md'), 'utf-8');
436
+ const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
437
+ let m;
438
+ while ((m = phasePattern.exec(roadmap)) !== null) {
439
+ milestonePhaseNums.add(m[1]);
440
+ }
441
+ } catch {}
442
+
443
+ if (milestonePhaseNums.size === 0) {
444
+ const passAll = () => true;
445
+ passAll.phaseCount = 0;
446
+ return passAll;
447
+ }
448
+
449
+ const normalized = new Set(
450
+ [...milestonePhaseNums].map(n => (n.replace(/^0+/, '') || '0').toLowerCase())
451
+ );
452
+
453
+ function isDirInMilestone(dirName) {
454
+ const m = dirName.match(/^0*(\d+[A-Za-z]?(?:\.\d+)*)/);
455
+ if (!m) return false;
456
+ return normalized.has(m[1].toLowerCase());
457
+ }
458
+ isDirInMilestone.phaseCount = milestonePhaseNums.size;
459
+ return isDirInMilestone;
460
+ }
461
+
412
462
  module.exports = {
413
463
  MODEL_PROFILES,
414
464
  output,
@@ -428,5 +478,6 @@ module.exports = {
428
478
  pathExistsInternal,
429
479
  generateSlugInternal,
430
480
  getMilestoneInfo,
481
+ getMilestonePhaseFilter,
431
482
  toPosixPath,
432
483
  };