gsd-opencode 1.10.2 → 1.20.0

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 (164) hide show
  1. package/agents/gsd-codebase-mapper.md +29 -3
  2. package/agents/gsd-debugger.md +19 -21
  3. package/agents/gsd-executor.md +213 -528
  4. package/agents/gsd-integration-checker.md +20 -0
  5. package/agents/gsd-phase-researcher.md +189 -267
  6. package/agents/gsd-plan-checker.md +278 -279
  7. package/agents/gsd-planner.md +299 -490
  8. package/agents/gsd-project-researcher.md +103 -345
  9. package/agents/gsd-research-synthesizer.md +5 -22
  10. package/agents/gsd-roadmapper.md +43 -6
  11. package/agents/gsd-verifier.md +158 -377
  12. package/{lib → bin/dm/lib}/constants.js +10 -3
  13. package/{src → bin/dm/src}/commands/install.js +5 -4
  14. package/{src → bin/dm/src}/commands/uninstall.js +3 -1
  15. package/{src → bin/dm/src}/services/backup-manager.js +1 -1
  16. package/{src → bin/dm/src}/services/config.js +1 -1
  17. package/{src → bin/dm/src}/services/file-ops.js +20 -4
  18. package/{src → bin/dm/src}/services/health-checker.js +3 -1
  19. package/{src → bin/dm/src}/services/repair-service.js +3 -1
  20. package/{src → bin/dm/src}/services/settings.js +1 -1
  21. package/{src → bin/dm/src}/services/update-service.js +2 -2
  22. package/bin/gsd-install.js +0 -0
  23. package/bin/gsd.js +9 -9
  24. package/commands/gsd/gsd-add-phase.md +43 -0
  25. package/commands/gsd/gsd-add-todo.md +47 -0
  26. package/commands/gsd/gsd-audit-milestone.md +36 -0
  27. package/commands/gsd/gsd-check-todos.md +45 -0
  28. package/commands/gsd/gsd-cleanup.md +18 -0
  29. package/commands/gsd/{complete-milestone.md → gsd-complete-milestone.md} +1 -1
  30. package/commands/gsd/{debug.md → gsd-debug.md} +16 -21
  31. package/commands/gsd/{discuss-phase.md → gsd-discuss-phase.md} +6 -9
  32. package/commands/gsd/gsd-execute-phase.md +41 -0
  33. package/commands/gsd/gsd-health.md +22 -0
  34. package/commands/gsd/gsd-help.md +22 -0
  35. package/commands/gsd/gsd-insert-phase.md +32 -0
  36. package/commands/gsd/gsd-join-discord.md +18 -0
  37. package/commands/gsd/{list-phase-assumptions.md → gsd-list-phase-assumptions.md} +3 -7
  38. package/commands/gsd/{map-codebase.md → gsd-map-codebase.md} +3 -3
  39. package/commands/gsd/gsd-new-milestone.md +44 -0
  40. package/commands/gsd/gsd-new-project.md +42 -0
  41. package/commands/gsd/gsd-pause-work.md +38 -0
  42. package/commands/gsd/gsd-plan-milestone-gaps.md +34 -0
  43. package/commands/gsd/gsd-plan-phase.md +44 -0
  44. package/commands/gsd/gsd-progress.md +24 -0
  45. package/commands/gsd/gsd-quick.md +41 -0
  46. package/commands/gsd/gsd-reapply-patches.md +119 -0
  47. package/commands/gsd/gsd-remove-phase.md +31 -0
  48. package/commands/gsd/{research-phase.md → gsd-research-phase.md} +38 -49
  49. package/commands/gsd/{resume-work.md → gsd-resume-work.md} +2 -2
  50. package/commands/gsd/gsd-set-profile.md +34 -0
  51. package/commands/gsd/gsd-settings.md +36 -0
  52. package/commands/gsd/gsd-update.md +37 -0
  53. package/commands/gsd/gsd-verify-work.md +38 -0
  54. package/get-shit-done/bin/gsd-tools.cjs +553 -0
  55. package/get-shit-done/bin/gsd-tools.test.cjs +2346 -0
  56. package/get-shit-done/bin/lib/commands.cjs +556 -0
  57. package/get-shit-done/bin/lib/config.cjs +162 -0
  58. package/get-shit-done/bin/lib/core.cjs +377 -0
  59. package/get-shit-done/bin/lib/frontmatter.cjs +299 -0
  60. package/get-shit-done/bin/lib/init.cjs +694 -0
  61. package/get-shit-done/bin/lib/milestone.cjs +215 -0
  62. package/get-shit-done/bin/lib/phase.cjs +877 -0
  63. package/get-shit-done/bin/lib/roadmap.cjs +298 -0
  64. package/get-shit-done/bin/lib/state.cjs +490 -0
  65. package/get-shit-done/bin/lib/template.cjs +222 -0
  66. package/get-shit-done/bin/lib/verify.cjs +772 -0
  67. package/get-shit-done/references/checkpoints.md +62 -364
  68. package/get-shit-done/references/decimal-phase-calculation.md +65 -0
  69. package/get-shit-done/references/git-integration.md +10 -16
  70. package/get-shit-done/references/git-planning-commit.md +38 -0
  71. package/get-shit-done/references/model-profile-resolution.md +34 -0
  72. package/get-shit-done/references/model-profiles.md +54 -66
  73. package/get-shit-done/references/phase-argument-parsing.md +61 -0
  74. package/get-shit-done/references/planning-config.md +112 -10
  75. package/get-shit-done/references/questioning.md +4 -0
  76. package/get-shit-done/references/ui-brand.md +1 -1
  77. package/get-shit-done/templates/UAT.md +1 -1
  78. package/get-shit-done/templates/VALIDATION.md +104 -0
  79. package/get-shit-done/templates/codebase/structure.md +6 -6
  80. package/get-shit-done/templates/config.json +37 -0
  81. package/get-shit-done/templates/context.md +2 -10
  82. package/get-shit-done/templates/continue-here.md +6 -6
  83. package/get-shit-done/templates/debug-subagent-prompt.md +2 -2
  84. package/get-shit-done/templates/discovery.md +6 -6
  85. package/get-shit-done/templates/milestone-archive.md +3 -3
  86. package/get-shit-done/templates/phase-prompt.md +9 -7
  87. package/get-shit-done/templates/planner-subagent-prompt.md +6 -6
  88. package/get-shit-done/templates/research-project/ARCHITECTURE.md +1 -1
  89. package/get-shit-done/templates/research.md +29 -6
  90. package/get-shit-done/templates/roadmap.md +1 -1
  91. package/get-shit-done/templates/state.md +0 -30
  92. package/get-shit-done/templates/summary-complex.md +59 -0
  93. package/get-shit-done/templates/summary-minimal.md +41 -0
  94. package/get-shit-done/templates/summary-standard.md +48 -0
  95. package/get-shit-done/templates/summary.md +16 -37
  96. package/get-shit-done/templates/user-setup.md +1 -13
  97. package/get-shit-done/templates/verification-report.md +5 -5
  98. package/get-shit-done/workflows/add-phase.md +111 -0
  99. package/{commands/gsd → get-shit-done/workflows}/add-todo.md +24 -60
  100. package/{commands/gsd → get-shit-done/workflows}/audit-milestone.md +83 -63
  101. package/{commands/gsd → get-shit-done/workflows}/check-todos.md +21 -73
  102. package/get-shit-done/workflows/cleanup.md +152 -0
  103. package/get-shit-done/workflows/complete-milestone.md +251 -312
  104. package/get-shit-done/workflows/diagnose-issues.md +6 -31
  105. package/get-shit-done/workflows/discovery-phase.md +11 -11
  106. package/get-shit-done/workflows/discuss-phase.md +156 -49
  107. package/get-shit-done/workflows/execute-phase.md +238 -396
  108. package/get-shit-done/workflows/execute-plan.md +180 -1609
  109. package/get-shit-done/workflows/health.md +156 -0
  110. package/{commands/gsd → get-shit-done/workflows}/help.md +33 -35
  111. package/get-shit-done/workflows/insert-phase.md +129 -0
  112. package/get-shit-done/workflows/list-phase-assumptions.md +3 -3
  113. package/get-shit-done/workflows/map-codebase.md +73 -80
  114. package/get-shit-done/workflows/new-milestone.md +382 -0
  115. package/{commands/gsd → get-shit-done/workflows}/new-project.md +281 -234
  116. package/get-shit-done/workflows/oc-set-profile.md +320 -0
  117. package/{commands/gsd → get-shit-done/workflows}/pause-work.md +31 -43
  118. package/{commands/gsd → get-shit-done/workflows}/plan-milestone-gaps.md +29 -50
  119. package/get-shit-done/workflows/plan-phase.md +478 -0
  120. package/{commands/gsd → get-shit-done/workflows}/progress.md +64 -47
  121. package/get-shit-done/workflows/quick.md +453 -0
  122. package/get-shit-done/workflows/remove-phase.md +154 -0
  123. package/get-shit-done/workflows/research-phase.md +73 -0
  124. package/get-shit-done/workflows/resume-project.md +17 -26
  125. package/get-shit-done/workflows/set-profile.md +80 -0
  126. package/get-shit-done/workflows/settings.md +213 -0
  127. package/get-shit-done/workflows/transition.md +84 -104
  128. package/{commands/gsd → get-shit-done/workflows}/update.md +70 -28
  129. package/get-shit-done/workflows/verify-phase.md +106 -492
  130. package/get-shit-done/workflows/verify-work.md +26 -53
  131. package/package.json +7 -4
  132. package/rules/gsd-oc-work-hard.md +36 -0
  133. package/skills/gsd-oc-select-model/SKILL.md +348 -0
  134. package/skills/gsd-oc-select-model/scripts/select-models.cjs +268 -0
  135. package/agents/gsd-set-model.md +0 -287
  136. package/agents/gsd-set-profile.md +0 -239
  137. package/agents/gsd-settings.md +0 -749
  138. package/bin/install.js +0 -323
  139. package/commands/gsd/add-phase.md +0 -207
  140. package/commands/gsd/execute-phase.md +0 -339
  141. package/commands/gsd/insert-phase.md +0 -227
  142. package/commands/gsd/new-milestone.md +0 -721
  143. package/commands/gsd/plan-phase.md +0 -525
  144. package/commands/gsd/quick.md +0 -309
  145. package/commands/gsd/remove-phase.md +0 -349
  146. package/commands/gsd/set-model.md +0 -77
  147. package/commands/gsd/set-profile.md +0 -46
  148. package/commands/gsd/settings.md +0 -33
  149. package/commands/gsd/verify-work.md +0 -219
  150. package/commands/gsd/whats-new.md +0 -124
  151. /package/{src → bin/dm/src}/commands/check.js +0 -0
  152. /package/{src → bin/dm/src}/commands/config.js +0 -0
  153. /package/{src → bin/dm/src}/commands/list.js +0 -0
  154. /package/{src → bin/dm/src}/commands/repair.js +0 -0
  155. /package/{src → bin/dm/src}/commands/update.js +0 -0
  156. /package/{src → bin/dm/src}/services/manifest-manager.js +0 -0
  157. /package/{src → bin/dm/src}/services/migration-service.js +0 -0
  158. /package/{src → bin/dm/src}/services/scope-manager.js +0 -0
  159. /package/{src → bin/dm/src}/services/structure-detector.js +0 -0
  160. /package/{src → bin/dm/src}/utils/hash.js +0 -0
  161. /package/{src → bin/dm/src}/utils/interactive.js +0 -0
  162. /package/{src → bin/dm/src}/utils/logger.js +0 -0
  163. /package/{src → bin/dm/src}/utils/npm-registry.js +0 -0
  164. /package/{src → bin/dm/src}/utils/path-resolver.js +0 -0
@@ -0,0 +1,694 @@
1
+ /**
2
+ * Init — Compound init commands for workflow bootstrapping
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { execSync } = require('child_process');
8
+ const { loadConfig, resolveModelInternal, findPhaseInternal, getRoadmapPhaseInternal, pathExistsInternal, generateSlugInternal, getMilestoneInfo, normalizePhaseName, output, error } = require('./core.cjs');
9
+
10
+ function cmdInitExecutePhase(cwd, phase, raw) {
11
+ if (!phase) {
12
+ error('phase required for init execute-phase');
13
+ }
14
+
15
+ const config = loadConfig(cwd);
16
+ const phaseInfo = findPhaseInternal(cwd, phase);
17
+ const milestone = getMilestoneInfo(cwd);
18
+
19
+ const result = {
20
+ // Models
21
+ executor_model: resolveModelInternal(cwd, 'gsd-executor'),
22
+ verifier_model: resolveModelInternal(cwd, 'gsd-verifier'),
23
+
24
+ // Config flags
25
+ commit_docs: config.commit_docs,
26
+ parallelization: config.parallelization,
27
+ branching_strategy: config.branching_strategy,
28
+ phase_branch_template: config.phase_branch_template,
29
+ milestone_branch_template: config.milestone_branch_template,
30
+ verifier_enabled: config.verifier,
31
+
32
+ // Phase info
33
+ phase_found: !!phaseInfo,
34
+ phase_dir: phaseInfo?.directory || null,
35
+ phase_number: phaseInfo?.phase_number || null,
36
+ phase_name: phaseInfo?.phase_name || null,
37
+ phase_slug: phaseInfo?.phase_slug || null,
38
+
39
+ // Plan inventory
40
+ plans: phaseInfo?.plans || [],
41
+ summaries: phaseInfo?.summaries || [],
42
+ incomplete_plans: phaseInfo?.incomplete_plans || [],
43
+ plan_count: phaseInfo?.plans?.length || 0,
44
+ incomplete_count: phaseInfo?.incomplete_plans?.length || 0,
45
+
46
+ // Branch name (pre-computed)
47
+ branch_name: config.branching_strategy === 'phase' && phaseInfo
48
+ ? config.phase_branch_template
49
+ .replace('{phase}', phaseInfo.phase_number)
50
+ .replace('{slug}', phaseInfo.phase_slug || 'phase')
51
+ : config.branching_strategy === 'milestone'
52
+ ? config.milestone_branch_template
53
+ .replace('{milestone}', milestone.version)
54
+ .replace('{slug}', generateSlugInternal(milestone.name) || 'milestone')
55
+ : null,
56
+
57
+ // Milestone info
58
+ milestone_version: milestone.version,
59
+ milestone_name: milestone.name,
60
+ milestone_slug: generateSlugInternal(milestone.name),
61
+
62
+ // File existence
63
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
64
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
65
+ config_exists: pathExistsInternal(cwd, '.planning/config.json'),
66
+ // File paths
67
+ state_path: '.planning/STATE.md',
68
+ roadmap_path: '.planning/ROADMAP.md',
69
+ config_path: '.planning/config.json',
70
+ };
71
+
72
+ output(result, raw);
73
+ }
74
+
75
+ function cmdInitPlanPhase(cwd, phase, raw) {
76
+ if (!phase) {
77
+ error('phase required for init plan-phase');
78
+ }
79
+
80
+ const config = loadConfig(cwd);
81
+ const phaseInfo = findPhaseInternal(cwd, phase);
82
+
83
+ const result = {
84
+ // Models
85
+ researcher_model: resolveModelInternal(cwd, 'gsd-phase-researcher'),
86
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
87
+ checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
88
+
89
+ // Workflow flags
90
+ research_enabled: config.research,
91
+ plan_checker_enabled: config.plan_checker,
92
+ nyquist_validation_enabled: config.nyquist_validation,
93
+ commit_docs: config.commit_docs,
94
+
95
+ // Phase info
96
+ phase_found: !!phaseInfo,
97
+ phase_dir: phaseInfo?.directory || null,
98
+ phase_number: phaseInfo?.phase_number || null,
99
+ phase_name: phaseInfo?.phase_name || null,
100
+ phase_slug: phaseInfo?.phase_slug || null,
101
+ padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
102
+
103
+ // Existing artifacts
104
+ has_research: phaseInfo?.has_research || false,
105
+ has_context: phaseInfo?.has_context || false,
106
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
107
+ plan_count: phaseInfo?.plans?.length || 0,
108
+
109
+ // Environment
110
+ planning_exists: pathExistsInternal(cwd, '.planning'),
111
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
112
+
113
+ // File paths
114
+ state_path: '.planning/STATE.md',
115
+ roadmap_path: '.planning/ROADMAP.md',
116
+ requirements_path: '.planning/REQUIREMENTS.md',
117
+ };
118
+
119
+ if (phaseInfo?.directory) {
120
+ // Find *-CONTEXT.md in phase directory
121
+ const phaseDirFull = path.join(cwd, phaseInfo.directory);
122
+ try {
123
+ const files = fs.readdirSync(phaseDirFull);
124
+ const contextFile = files.find(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
125
+ if (contextFile) {
126
+ result.context_path = path.join(phaseInfo.directory, contextFile);
127
+ }
128
+ const researchFile = files.find(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
129
+ if (researchFile) {
130
+ result.research_path = path.join(phaseInfo.directory, researchFile);
131
+ }
132
+ const verificationFile = files.find(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
133
+ if (verificationFile) {
134
+ result.verification_path = path.join(phaseInfo.directory, verificationFile);
135
+ }
136
+ const uatFile = files.find(f => f.endsWith('-UAT.md') || f === 'UAT.md');
137
+ if (uatFile) {
138
+ result.uat_path = path.join(phaseInfo.directory, uatFile);
139
+ }
140
+ } catch {}
141
+ }
142
+
143
+ output(result, raw);
144
+ }
145
+
146
+ function cmdInitNewProject(cwd, raw) {
147
+ const config = loadConfig(cwd);
148
+
149
+ // Detect Brave Search API key availability
150
+ const homedir = require('os').homedir();
151
+ const braveKeyFile = path.join(homedir, '.gsd', 'brave_api_key');
152
+ const hasBraveSearch = !!(process.env.BRAVE_API_KEY || fs.existsSync(braveKeyFile));
153
+
154
+ // Detect existing code
155
+ let hasCode = false;
156
+ let hasPackageFile = false;
157
+ try {
158
+ const files = execSync('find . -maxdepth 3 \\( -name "*.ts" -o -name "*.js" -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.swift" -o -name "*.java" \\) 2>/dev/null | grep -v node_modules | grep -v .git | head -5', {
159
+ cwd,
160
+ encoding: 'utf-8',
161
+ stdio: ['pipe', 'pipe', 'pipe'],
162
+ });
163
+ hasCode = files.trim().length > 0;
164
+ } catch {}
165
+
166
+ hasPackageFile = pathExistsInternal(cwd, 'package.json') ||
167
+ pathExistsInternal(cwd, 'requirements.txt') ||
168
+ pathExistsInternal(cwd, 'Cargo.toml') ||
169
+ pathExistsInternal(cwd, 'go.mod') ||
170
+ pathExistsInternal(cwd, 'Package.swift');
171
+
172
+ const result = {
173
+ // Models
174
+ researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
175
+ synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
176
+ roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
177
+
178
+ // Config
179
+ commit_docs: config.commit_docs,
180
+
181
+ // Existing state
182
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
183
+ has_codebase_map: pathExistsInternal(cwd, '.planning/codebase'),
184
+ planning_exists: pathExistsInternal(cwd, '.planning'),
185
+
186
+ // Brownfield detection
187
+ has_existing_code: hasCode,
188
+ has_package_file: hasPackageFile,
189
+ is_brownfield: hasCode || hasPackageFile,
190
+ needs_codebase_map: (hasCode || hasPackageFile) && !pathExistsInternal(cwd, '.planning/codebase'),
191
+
192
+ // Git state
193
+ has_git: pathExistsInternal(cwd, '.git'),
194
+
195
+ // Enhanced search
196
+ brave_search_available: hasBraveSearch,
197
+
198
+ // File paths
199
+ project_path: '.planning/PROJECT.md',
200
+ };
201
+
202
+ output(result, raw);
203
+ }
204
+
205
+ function cmdInitNewMilestone(cwd, raw) {
206
+ const config = loadConfig(cwd);
207
+ const milestone = getMilestoneInfo(cwd);
208
+
209
+ const result = {
210
+ // Models
211
+ researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
212
+ synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
213
+ roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
214
+
215
+ // Config
216
+ commit_docs: config.commit_docs,
217
+ research_enabled: config.research,
218
+
219
+ // Current milestone
220
+ current_milestone: milestone.version,
221
+ current_milestone_name: milestone.name,
222
+
223
+ // File existence
224
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
225
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
226
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
227
+
228
+ // File paths
229
+ project_path: '.planning/PROJECT.md',
230
+ roadmap_path: '.planning/ROADMAP.md',
231
+ state_path: '.planning/STATE.md',
232
+ };
233
+
234
+ output(result, raw);
235
+ }
236
+
237
+ function cmdInitQuick(cwd, description, raw) {
238
+ const config = loadConfig(cwd);
239
+ const now = new Date();
240
+ const slug = description ? generateSlugInternal(description)?.substring(0, 40) : null;
241
+
242
+ // Find next quick task number
243
+ const quickDir = path.join(cwd, '.planning', 'quick');
244
+ let nextNum = 1;
245
+ try {
246
+ const existing = fs.readdirSync(quickDir)
247
+ .filter(f => /^\d+-/.test(f))
248
+ .map(f => parseInt(f.split('-')[0], 10))
249
+ .filter(n => !isNaN(n));
250
+ if (existing.length > 0) {
251
+ nextNum = Math.max(...existing) + 1;
252
+ }
253
+ } catch {}
254
+
255
+ const result = {
256
+ // Models
257
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
258
+ executor_model: resolveModelInternal(cwd, 'gsd-executor'),
259
+ checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
260
+ verifier_model: resolveModelInternal(cwd, 'gsd-verifier'),
261
+
262
+ // Config
263
+ commit_docs: config.commit_docs,
264
+
265
+ // Quick task info
266
+ next_num: nextNum,
267
+ slug: slug,
268
+ description: description || null,
269
+
270
+ // Timestamps
271
+ date: now.toISOString().split('T')[0],
272
+ timestamp: now.toISOString(),
273
+
274
+ // Paths
275
+ quick_dir: '.planning/quick',
276
+ task_dir: slug ? `.planning/quick/${nextNum}-${slug}` : null,
277
+
278
+ // File existence
279
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
280
+ planning_exists: pathExistsInternal(cwd, '.planning'),
281
+
282
+ };
283
+
284
+ output(result, raw);
285
+ }
286
+
287
+ function cmdInitResume(cwd, raw) {
288
+ const config = loadConfig(cwd);
289
+
290
+ // Check for interrupted agent
291
+ let interruptedAgentId = null;
292
+ try {
293
+ interruptedAgentId = fs.readFileSync(path.join(cwd, '.planning', 'current-agent-id.txt'), 'utf-8').trim();
294
+ } catch {}
295
+
296
+ const result = {
297
+ // File existence
298
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
299
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
300
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
301
+ planning_exists: pathExistsInternal(cwd, '.planning'),
302
+
303
+ // File paths
304
+ state_path: '.planning/STATE.md',
305
+ roadmap_path: '.planning/ROADMAP.md',
306
+ project_path: '.planning/PROJECT.md',
307
+
308
+ // Agent state
309
+ has_interrupted_agent: !!interruptedAgentId,
310
+ interrupted_agent_id: interruptedAgentId,
311
+
312
+ // Config
313
+ commit_docs: config.commit_docs,
314
+ };
315
+
316
+ output(result, raw);
317
+ }
318
+
319
+ function cmdInitVerifyWork(cwd, phase, raw) {
320
+ if (!phase) {
321
+ error('phase required for init verify-work');
322
+ }
323
+
324
+ const config = loadConfig(cwd);
325
+ const phaseInfo = findPhaseInternal(cwd, phase);
326
+
327
+ const result = {
328
+ // Models
329
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
330
+ checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
331
+
332
+ // Config
333
+ commit_docs: config.commit_docs,
334
+
335
+ // Phase info
336
+ phase_found: !!phaseInfo,
337
+ phase_dir: phaseInfo?.directory || null,
338
+ phase_number: phaseInfo?.phase_number || null,
339
+ phase_name: phaseInfo?.phase_name || null,
340
+
341
+ // Existing artifacts
342
+ has_verification: phaseInfo?.has_verification || false,
343
+ };
344
+
345
+ output(result, raw);
346
+ }
347
+
348
+ function cmdInitPhaseOp(cwd, phase, raw) {
349
+ const config = loadConfig(cwd);
350
+ let phaseInfo = findPhaseInternal(cwd, phase);
351
+
352
+ // Fallback to ROADMAP.md if no directory exists (e.g., Plans: TBD)
353
+ if (!phaseInfo) {
354
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
355
+ if (roadmapPhase?.found) {
356
+ const phaseName = roadmapPhase.phase_name;
357
+ phaseInfo = {
358
+ found: true,
359
+ directory: null,
360
+ phase_number: roadmapPhase.phase_number,
361
+ phase_name: phaseName,
362
+ phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
363
+ plans: [],
364
+ summaries: [],
365
+ incomplete_plans: [],
366
+ has_research: false,
367
+ has_context: false,
368
+ has_verification: false,
369
+ };
370
+ }
371
+ }
372
+
373
+ const result = {
374
+ // Config
375
+ commit_docs: config.commit_docs,
376
+ brave_search: config.brave_search,
377
+
378
+ // Phase info
379
+ phase_found: !!phaseInfo,
380
+ phase_dir: phaseInfo?.directory || null,
381
+ phase_number: phaseInfo?.phase_number || null,
382
+ phase_name: phaseInfo?.phase_name || null,
383
+ phase_slug: phaseInfo?.phase_slug || null,
384
+ padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
385
+
386
+ // Existing artifacts
387
+ has_research: phaseInfo?.has_research || false,
388
+ has_context: phaseInfo?.has_context || false,
389
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
390
+ has_verification: phaseInfo?.has_verification || false,
391
+ plan_count: phaseInfo?.plans?.length || 0,
392
+
393
+ // File existence
394
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
395
+ planning_exists: pathExistsInternal(cwd, '.planning'),
396
+
397
+ // File paths
398
+ state_path: '.planning/STATE.md',
399
+ roadmap_path: '.planning/ROADMAP.md',
400
+ requirements_path: '.planning/REQUIREMENTS.md',
401
+ };
402
+
403
+ if (phaseInfo?.directory) {
404
+ const phaseDirFull = path.join(cwd, phaseInfo.directory);
405
+ try {
406
+ const files = fs.readdirSync(phaseDirFull);
407
+ const contextFile = files.find(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
408
+ if (contextFile) {
409
+ result.context_path = path.join(phaseInfo.directory, contextFile);
410
+ }
411
+ const researchFile = files.find(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
412
+ if (researchFile) {
413
+ result.research_path = path.join(phaseInfo.directory, researchFile);
414
+ }
415
+ const verificationFile = files.find(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
416
+ if (verificationFile) {
417
+ result.verification_path = path.join(phaseInfo.directory, verificationFile);
418
+ }
419
+ const uatFile = files.find(f => f.endsWith('-UAT.md') || f === 'UAT.md');
420
+ if (uatFile) {
421
+ result.uat_path = path.join(phaseInfo.directory, uatFile);
422
+ }
423
+ } catch {}
424
+ }
425
+
426
+ output(result, raw);
427
+ }
428
+
429
+ function cmdInitTodos(cwd, area, raw) {
430
+ const config = loadConfig(cwd);
431
+ const now = new Date();
432
+
433
+ // List todos (reuse existing logic)
434
+ const pendingDir = path.join(cwd, '.planning', 'todos', 'pending');
435
+ let count = 0;
436
+ const todos = [];
437
+
438
+ try {
439
+ const files = fs.readdirSync(pendingDir).filter(f => f.endsWith('.md'));
440
+ for (const file of files) {
441
+ try {
442
+ const content = fs.readFileSync(path.join(pendingDir, file), 'utf-8');
443
+ const createdMatch = content.match(/^created:\s*(.+)$/m);
444
+ const titleMatch = content.match(/^title:\s*(.+)$/m);
445
+ const areaMatch = content.match(/^area:\s*(.+)$/m);
446
+ const todoArea = areaMatch ? areaMatch[1].trim() : 'general';
447
+
448
+ if (area && todoArea !== area) continue;
449
+
450
+ count++;
451
+ todos.push({
452
+ file,
453
+ created: createdMatch ? createdMatch[1].trim() : 'unknown',
454
+ title: titleMatch ? titleMatch[1].trim() : 'Untitled',
455
+ area: todoArea,
456
+ path: path.join('.planning', 'todos', 'pending', file),
457
+ });
458
+ } catch {}
459
+ }
460
+ } catch {}
461
+
462
+ const result = {
463
+ // Config
464
+ commit_docs: config.commit_docs,
465
+
466
+ // Timestamps
467
+ date: now.toISOString().split('T')[0],
468
+ timestamp: now.toISOString(),
469
+
470
+ // Todo inventory
471
+ todo_count: count,
472
+ todos,
473
+ area_filter: area || null,
474
+
475
+ // Paths
476
+ pending_dir: '.planning/todos/pending',
477
+ completed_dir: '.planning/todos/completed',
478
+
479
+ // File existence
480
+ planning_exists: pathExistsInternal(cwd, '.planning'),
481
+ todos_dir_exists: pathExistsInternal(cwd, '.planning/todos'),
482
+ pending_dir_exists: pathExistsInternal(cwd, '.planning/todos/pending'),
483
+ };
484
+
485
+ output(result, raw);
486
+ }
487
+
488
+ function cmdInitMilestoneOp(cwd, raw) {
489
+ const config = loadConfig(cwd);
490
+ const milestone = getMilestoneInfo(cwd);
491
+
492
+ // Count phases
493
+ let phaseCount = 0;
494
+ let completedPhases = 0;
495
+ const phasesDir = path.join(cwd, '.planning', 'phases');
496
+ try {
497
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
498
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
499
+ phaseCount = dirs.length;
500
+
501
+ // Count phases with summaries (completed)
502
+ for (const dir of dirs) {
503
+ try {
504
+ const phaseFiles = fs.readdirSync(path.join(phasesDir, dir));
505
+ const hasSummary = phaseFiles.some(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
506
+ if (hasSummary) completedPhases++;
507
+ } catch {}
508
+ }
509
+ } catch {}
510
+
511
+ // Check archive
512
+ const archiveDir = path.join(cwd, '.planning', 'archive');
513
+ let archivedMilestones = [];
514
+ try {
515
+ archivedMilestones = fs.readdirSync(archiveDir, { withFileTypes: true })
516
+ .filter(e => e.isDirectory())
517
+ .map(e => e.name);
518
+ } catch {}
519
+
520
+ const result = {
521
+ // Config
522
+ commit_docs: config.commit_docs,
523
+
524
+ // Current milestone
525
+ milestone_version: milestone.version,
526
+ milestone_name: milestone.name,
527
+ milestone_slug: generateSlugInternal(milestone.name),
528
+
529
+ // Phase counts
530
+ phase_count: phaseCount,
531
+ completed_phases: completedPhases,
532
+ all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
533
+
534
+ // Archive
535
+ archived_milestones: archivedMilestones,
536
+ archive_count: archivedMilestones.length,
537
+
538
+ // File existence
539
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
540
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
541
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
542
+ archive_exists: pathExistsInternal(cwd, '.planning/archive'),
543
+ phases_dir_exists: pathExistsInternal(cwd, '.planning/phases'),
544
+ };
545
+
546
+ output(result, raw);
547
+ }
548
+
549
+ function cmdInitMapCodebase(cwd, raw) {
550
+ const config = loadConfig(cwd);
551
+
552
+ // Check for existing codebase maps
553
+ const codebaseDir = path.join(cwd, '.planning', 'codebase');
554
+ let existingMaps = [];
555
+ try {
556
+ existingMaps = fs.readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
557
+ } catch {}
558
+
559
+ const result = {
560
+ // Models
561
+ mapper_model: resolveModelInternal(cwd, 'gsd-codebase-mapper'),
562
+
563
+ // Config
564
+ commit_docs: config.commit_docs,
565
+ search_gitignored: config.search_gitignored,
566
+ parallelization: config.parallelization,
567
+
568
+ // Paths
569
+ codebase_dir: '.planning/codebase',
570
+
571
+ // Existing maps
572
+ existing_maps: existingMaps,
573
+ has_maps: existingMaps.length > 0,
574
+
575
+ // File existence
576
+ planning_exists: pathExistsInternal(cwd, '.planning'),
577
+ codebase_dir_exists: pathExistsInternal(cwd, '.planning/codebase'),
578
+ };
579
+
580
+ output(result, raw);
581
+ }
582
+
583
+ function cmdInitProgress(cwd, raw) {
584
+ const config = loadConfig(cwd);
585
+ const milestone = getMilestoneInfo(cwd);
586
+
587
+ // Analyze phases
588
+ const phasesDir = path.join(cwd, '.planning', 'phases');
589
+ const phases = [];
590
+ let currentPhase = null;
591
+ let nextPhase = null;
592
+
593
+ try {
594
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
595
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
596
+
597
+ for (const dir of dirs) {
598
+ const match = dir.match(/^(\d+(?:\.\d+)?)-?(.*)/);
599
+ const phaseNumber = match ? match[1] : dir;
600
+ const phaseName = match && match[2] ? match[2] : null;
601
+
602
+ const phasePath = path.join(phasesDir, dir);
603
+ const phaseFiles = fs.readdirSync(phasePath);
604
+
605
+ const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
606
+ const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
607
+ const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
608
+
609
+ const status = summaries.length >= plans.length && plans.length > 0 ? 'complete' :
610
+ plans.length > 0 ? 'in_progress' :
611
+ hasResearch ? 'researched' : 'pending';
612
+
613
+ const phaseInfo = {
614
+ number: phaseNumber,
615
+ name: phaseName,
616
+ directory: path.join('.planning', 'phases', dir),
617
+ status,
618
+ plan_count: plans.length,
619
+ summary_count: summaries.length,
620
+ has_research: hasResearch,
621
+ };
622
+
623
+ phases.push(phaseInfo);
624
+
625
+ // Find current (first incomplete with plans) and next (first pending)
626
+ if (!currentPhase && (status === 'in_progress' || status === 'researched')) {
627
+ currentPhase = phaseInfo;
628
+ }
629
+ if (!nextPhase && status === 'pending') {
630
+ nextPhase = phaseInfo;
631
+ }
632
+ }
633
+ } catch {}
634
+
635
+ // Check for paused work
636
+ let pausedAt = null;
637
+ try {
638
+ const state = fs.readFileSync(path.join(cwd, '.planning', 'STATE.md'), 'utf-8');
639
+ const pauseMatch = state.match(/\*\*Paused At:\*\*\s*(.+)/);
640
+ if (pauseMatch) pausedAt = pauseMatch[1].trim();
641
+ } catch {}
642
+
643
+ const result = {
644
+ // Models
645
+ executor_model: resolveModelInternal(cwd, 'gsd-executor'),
646
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
647
+
648
+ // Config
649
+ commit_docs: config.commit_docs,
650
+
651
+ // Milestone
652
+ milestone_version: milestone.version,
653
+ milestone_name: milestone.name,
654
+
655
+ // Phase overview
656
+ phases,
657
+ phase_count: phases.length,
658
+ completed_count: phases.filter(p => p.status === 'complete').length,
659
+ in_progress_count: phases.filter(p => p.status === 'in_progress').length,
660
+
661
+ // Current state
662
+ current_phase: currentPhase,
663
+ next_phase: nextPhase,
664
+ paused_at: pausedAt,
665
+ has_work_in_progress: !!currentPhase,
666
+
667
+ // File existence
668
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
669
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
670
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
671
+ // File paths
672
+ state_path: '.planning/STATE.md',
673
+ roadmap_path: '.planning/ROADMAP.md',
674
+ project_path: '.planning/PROJECT.md',
675
+ config_path: '.planning/config.json',
676
+ };
677
+
678
+ output(result, raw);
679
+ }
680
+
681
+ module.exports = {
682
+ cmdInitExecutePhase,
683
+ cmdInitPlanPhase,
684
+ cmdInitNewProject,
685
+ cmdInitNewMilestone,
686
+ cmdInitQuick,
687
+ cmdInitResume,
688
+ cmdInitVerifyWork,
689
+ cmdInitPhaseOp,
690
+ cmdInitTodos,
691
+ cmdInitMilestoneOp,
692
+ cmdInitMapCodebase,
693
+ cmdInitProgress,
694
+ };