@mobiman/vector 1.1.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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/agents/vector-codebase-mapper.md +770 -0
  4. package/agents/vector-debugger.md +1338 -0
  5. package/agents/vector-executor.md +487 -0
  6. package/agents/vector-integration-checker.md +443 -0
  7. package/agents/vector-nyquist-auditor.md +176 -0
  8. package/agents/vector-phase-researcher.md +553 -0
  9. package/agents/vector-plan-checker.md +706 -0
  10. package/agents/vector-planner.md +1307 -0
  11. package/agents/vector-project-researcher.md +629 -0
  12. package/agents/vector-research-synthesizer.md +247 -0
  13. package/agents/vector-roadmapper.md +650 -0
  14. package/agents/vector-ui-auditor.md +439 -0
  15. package/agents/vector-ui-checker.md +300 -0
  16. package/agents/vector-ui-researcher.md +353 -0
  17. package/agents/vector-verifier.md +579 -0
  18. package/bin/install.cjs +2907 -0
  19. package/bin/install.cjs.map +1 -0
  20. package/bin/install.cts +3103 -0
  21. package/bin/install.d.cts +3 -0
  22. package/bin/install.d.cts.map +1 -0
  23. package/commands/vector/add-phase.md +43 -0
  24. package/commands/vector/add-tests.md +41 -0
  25. package/commands/vector/add-todo.md +47 -0
  26. package/commands/vector/audit-milestone.md +36 -0
  27. package/commands/vector/autonomous.md +41 -0
  28. package/commands/vector/check-todos.md +45 -0
  29. package/commands/vector/cleanup.md +18 -0
  30. package/commands/vector/complete-milestone.md +136 -0
  31. package/commands/vector/debug.md +168 -0
  32. package/commands/vector/discuss-phase.md +90 -0
  33. package/commands/vector/do.md +30 -0
  34. package/commands/vector/execute-phase.md +41 -0
  35. package/commands/vector/health.md +22 -0
  36. package/commands/vector/help.md +22 -0
  37. package/commands/vector/insert-phase.md +32 -0
  38. package/commands/vector/join-discord.md +18 -0
  39. package/commands/vector/list-phase-assumptions.md +46 -0
  40. package/commands/vector/map-codebase.md +71 -0
  41. package/commands/vector/new-milestone.md +44 -0
  42. package/commands/vector/new-project.md +42 -0
  43. package/commands/vector/pause-work.md +38 -0
  44. package/commands/vector/plan-milestone-gaps.md +34 -0
  45. package/commands/vector/plan-phase.md +45 -0
  46. package/commands/vector/progress.md +24 -0
  47. package/commands/vector/quick.md +47 -0
  48. package/commands/vector/reapply-patches.md +123 -0
  49. package/commands/vector/remove-phase.md +31 -0
  50. package/commands/vector/research-phase.md +190 -0
  51. package/commands/vector/resume-work.md +40 -0
  52. package/commands/vector/set-profile.md +12 -0
  53. package/commands/vector/settings.md +36 -0
  54. package/commands/vector/stats.md +18 -0
  55. package/commands/vector/ui-phase.md +34 -0
  56. package/commands/vector/ui-review.md +32 -0
  57. package/commands/vector/update.md +37 -0
  58. package/commands/vector/validate-phase.md +35 -0
  59. package/commands/vector/verify-work.md +38 -0
  60. package/core/bin/lib/commands.cjs +641 -0
  61. package/core/bin/lib/commands.cjs.map +1 -0
  62. package/core/bin/lib/commands.cts +712 -0
  63. package/core/bin/lib/commands.d.cts +23 -0
  64. package/core/bin/lib/commands.d.cts.map +1 -0
  65. package/core/bin/lib/config.cjs +281 -0
  66. package/core/bin/lib/config.cjs.map +1 -0
  67. package/core/bin/lib/config.cts +301 -0
  68. package/core/bin/lib/config.d.cts +50 -0
  69. package/core/bin/lib/config.d.cts.map +1 -0
  70. package/core/bin/lib/core.cjs +483 -0
  71. package/core/bin/lib/core.cjs.map +1 -0
  72. package/core/bin/lib/core.cts +544 -0
  73. package/core/bin/lib/core.d.cts +96 -0
  74. package/core/bin/lib/core.d.cts.map +1 -0
  75. package/core/bin/lib/frontmatter.cjs +341 -0
  76. package/core/bin/lib/frontmatter.cjs.map +1 -0
  77. package/core/bin/lib/frontmatter.cts +295 -0
  78. package/core/bin/lib/frontmatter.d.cts +18 -0
  79. package/core/bin/lib/frontmatter.d.cts.map +1 -0
  80. package/core/bin/lib/init.cjs +674 -0
  81. package/core/bin/lib/init.cjs.map +1 -0
  82. package/core/bin/lib/init.cts +775 -0
  83. package/core/bin/lib/init.d.cts +16 -0
  84. package/core/bin/lib/init.d.cts.map +1 -0
  85. package/core/bin/lib/milestone.cjs +210 -0
  86. package/core/bin/lib/milestone.cjs.map +1 -0
  87. package/core/bin/lib/milestone.cts +241 -0
  88. package/core/bin/lib/milestone.d.cts +11 -0
  89. package/core/bin/lib/milestone.d.cts.map +1 -0
  90. package/core/bin/lib/model-profiles.cjs +62 -0
  91. package/core/bin/lib/model-profiles.cjs.map +1 -0
  92. package/core/bin/lib/model-profiles.cts +66 -0
  93. package/core/bin/lib/model-profiles.d.cts +33 -0
  94. package/core/bin/lib/model-profiles.d.cts.map +1 -0
  95. package/core/bin/lib/phase.cjs +713 -0
  96. package/core/bin/lib/phase.cjs.map +1 -0
  97. package/core/bin/lib/phase.cts +914 -0
  98. package/core/bin/lib/phase.d.cts +21 -0
  99. package/core/bin/lib/phase.d.cts.map +1 -0
  100. package/core/bin/lib/roadmap.cjs +246 -0
  101. package/core/bin/lib/roadmap.cjs.map +1 -0
  102. package/core/bin/lib/roadmap.cts +311 -0
  103. package/core/bin/lib/roadmap.d.cts +7 -0
  104. package/core/bin/lib/roadmap.d.cts.map +1 -0
  105. package/core/bin/lib/state.cjs +709 -0
  106. package/core/bin/lib/state.cjs.map +1 -0
  107. package/core/bin/lib/state.cts +718 -0
  108. package/core/bin/lib/state.d.cts +47 -0
  109. package/core/bin/lib/state.d.cts.map +1 -0
  110. package/core/bin/lib/template.cjs +220 -0
  111. package/core/bin/lib/template.cjs.map +1 -0
  112. package/core/bin/lib/template.cts +229 -0
  113. package/core/bin/lib/template.d.cts +15 -0
  114. package/core/bin/lib/template.d.cts.map +1 -0
  115. package/core/bin/lib/verify.cjs +824 -0
  116. package/core/bin/lib/verify.cjs.map +1 -0
  117. package/core/bin/lib/verify.cts +829 -0
  118. package/core/bin/lib/verify.d.cts +17 -0
  119. package/core/bin/lib/verify.d.cts.map +1 -0
  120. package/core/bin/vector-tools.cjs +641 -0
  121. package/core/bin/vector-tools.cjs.map +1 -0
  122. package/core/bin/vector-tools.cts +603 -0
  123. package/core/bin/vector-tools.d.cts +128 -0
  124. package/core/bin/vector-tools.d.cts.map +1 -0
  125. package/core/references/checkpoints.md +776 -0
  126. package/core/references/continuation-format.md +249 -0
  127. package/core/references/decimal-phase-calculation.md +65 -0
  128. package/core/references/git-integration.md +248 -0
  129. package/core/references/git-planning-commit.md +38 -0
  130. package/core/references/model-profile-resolution.md +36 -0
  131. package/core/references/model-profiles.md +101 -0
  132. package/core/references/phase-argument-parsing.md +61 -0
  133. package/core/references/planning-config.md +200 -0
  134. package/core/references/questioning.md +162 -0
  135. package/core/references/tdd.md +263 -0
  136. package/core/references/ui-brand.md +160 -0
  137. package/core/references/verification-patterns.md +612 -0
  138. package/core/templates/DEBUG.md +164 -0
  139. package/core/templates/UAT.md +247 -0
  140. package/core/templates/UI-SPEC.md +100 -0
  141. package/core/templates/VALIDATION.md +76 -0
  142. package/core/templates/codebase/architecture.md +255 -0
  143. package/core/templates/codebase/concerns.md +310 -0
  144. package/core/templates/codebase/conventions.md +307 -0
  145. package/core/templates/codebase/integrations.md +280 -0
  146. package/core/templates/codebase/stack.md +186 -0
  147. package/core/templates/codebase/structure.md +285 -0
  148. package/core/templates/codebase/testing.md +480 -0
  149. package/core/templates/config.json +37 -0
  150. package/core/templates/context.md +352 -0
  151. package/core/templates/continue-here.md +78 -0
  152. package/core/templates/copilot-instructions.md +7 -0
  153. package/core/templates/debug-subagent-prompt.md +91 -0
  154. package/core/templates/discovery.md +146 -0
  155. package/core/templates/milestone-archive.md +123 -0
  156. package/core/templates/milestone.md +115 -0
  157. package/core/templates/phase-prompt.md +610 -0
  158. package/core/templates/planner-subagent-prompt.md +117 -0
  159. package/core/templates/project.md +184 -0
  160. package/core/templates/requirements.md +231 -0
  161. package/core/templates/research-project/ARCHITECTURE.md +204 -0
  162. package/core/templates/research-project/FEATURES.md +147 -0
  163. package/core/templates/research-project/PITFALLS.md +200 -0
  164. package/core/templates/research-project/STACK.md +120 -0
  165. package/core/templates/research-project/SUMMARY.md +170 -0
  166. package/core/templates/research.md +552 -0
  167. package/core/templates/retrospective.md +54 -0
  168. package/core/templates/roadmap.md +202 -0
  169. package/core/templates/state.md +176 -0
  170. package/core/templates/summary-complex.md +59 -0
  171. package/core/templates/summary-minimal.md +41 -0
  172. package/core/templates/summary-standard.md +48 -0
  173. package/core/templates/summary.md +248 -0
  174. package/core/templates/user-setup.md +311 -0
  175. package/core/templates/verification-report.md +322 -0
  176. package/core/workflows/add-phase.md +112 -0
  177. package/core/workflows/add-tests.md +351 -0
  178. package/core/workflows/add-todo.md +158 -0
  179. package/core/workflows/audit-milestone.md +332 -0
  180. package/core/workflows/autonomous.md +743 -0
  181. package/core/workflows/check-todos.md +177 -0
  182. package/core/workflows/cleanup.md +152 -0
  183. package/core/workflows/complete-milestone.md +766 -0
  184. package/core/workflows/diagnose-issues.md +219 -0
  185. package/core/workflows/discovery-phase.md +289 -0
  186. package/core/workflows/discuss-phase.md +762 -0
  187. package/core/workflows/do.md +104 -0
  188. package/core/workflows/execute-phase.md +468 -0
  189. package/core/workflows/execute-plan.md +483 -0
  190. package/core/workflows/health.md +159 -0
  191. package/core/workflows/help.md +513 -0
  192. package/core/workflows/insert-phase.md +130 -0
  193. package/core/workflows/list-phase-assumptions.md +178 -0
  194. package/core/workflows/map-codebase.md +316 -0
  195. package/core/workflows/new-milestone.md +386 -0
  196. package/core/workflows/new-project.md +1113 -0
  197. package/core/workflows/node-repair.md +92 -0
  198. package/core/workflows/pause-work.md +122 -0
  199. package/core/workflows/plan-milestone-gaps.md +274 -0
  200. package/core/workflows/plan-phase.md +666 -0
  201. package/core/workflows/progress.md +382 -0
  202. package/core/workflows/quick.md +717 -0
  203. package/core/workflows/remove-phase.md +155 -0
  204. package/core/workflows/research-phase.md +74 -0
  205. package/core/workflows/resume-project.md +307 -0
  206. package/core/workflows/settings.md +243 -0
  207. package/core/workflows/stats.md +60 -0
  208. package/core/workflows/transition.md +544 -0
  209. package/core/workflows/ui-phase.md +290 -0
  210. package/core/workflows/ui-review.md +157 -0
  211. package/core/workflows/update.md +320 -0
  212. package/core/workflows/validate-phase.md +167 -0
  213. package/core/workflows/verify-phase.md +243 -0
  214. package/core/workflows/verify-work.md +584 -0
  215. package/package.json +55 -0
  216. package/scripts/build-hooks.cjs +38 -0
  217. package/scripts/build-hooks.cjs.map +1 -0
  218. package/scripts/build-hooks.cts +41 -0
  219. package/scripts/build-hooks.d.cts +6 -0
  220. package/scripts/build-hooks.d.cts.map +1 -0
  221. package/scripts/run-tests.cjs +28 -0
  222. package/scripts/run-tests.cjs.map +1 -0
  223. package/scripts/run-tests.cts +28 -0
  224. package/scripts/run-tests.d.cts +3 -0
  225. package/scripts/run-tests.d.cts.map +1 -0
@@ -0,0 +1,775 @@
1
+ /**
2
+ * Init — Compound init commands for workflow bootstrapping
3
+ */
4
+
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import os from 'os';
8
+ import { execSync } from 'child_process';
9
+ import { loadConfig, resolveModelInternal, findPhaseInternal, getRoadmapPhaseInternal, pathExistsInternal, generateSlugInternal, getMilestoneInfo, getMilestonePhaseFilter, stripShippedMilestones, normalizePhaseName, toPosixPath, output, error } from './core.cjs';
10
+
11
+ export function cmdInitExecutePhase(cwd: string, phase: string | undefined, raw: boolean): void {
12
+ if (!phase) {
13
+ error('phase required for init execute-phase');
14
+ }
15
+
16
+ const config = loadConfig(cwd);
17
+ const phaseInfo = findPhaseInternal(cwd, phase!);
18
+ const milestone = getMilestoneInfo(cwd);
19
+
20
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase!);
21
+ const reqMatch = roadmapPhase?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
22
+ const reqExtracted = reqMatch
23
+ ? reqMatch[1].replace(/[\[\]]/g, '').split(',').map((s: string) => s.trim()).filter(Boolean).join(', ')
24
+ : null;
25
+ const phase_req_ids = (reqExtracted && reqExtracted !== 'TBD') ? reqExtracted : null;
26
+
27
+ const result = {
28
+ // Models
29
+ executor_model: resolveModelInternal(cwd, 'vector-executor'),
30
+ verifier_model: resolveModelInternal(cwd, 'vector-verifier'),
31
+
32
+ // Config flags
33
+ commit_docs: config.commit_docs,
34
+ parallelization: config.parallelization,
35
+ branching_strategy: config.branching_strategy,
36
+ phase_branch_template: config.phase_branch_template,
37
+ milestone_branch_template: config.milestone_branch_template,
38
+ verifier_enabled: config.verifier,
39
+
40
+ // Phase info
41
+ phase_found: !!phaseInfo,
42
+ phase_dir: phaseInfo?.directory || null,
43
+ phase_number: phaseInfo?.phase_number || null,
44
+ phase_name: phaseInfo?.phase_name || null,
45
+ phase_slug: phaseInfo?.phase_slug || null,
46
+ phase_req_ids,
47
+
48
+ // Plan inventory
49
+ plans: phaseInfo?.plans || [],
50
+ summaries: phaseInfo?.summaries || [],
51
+ incomplete_plans: phaseInfo?.incomplete_plans || [],
52
+ plan_count: phaseInfo?.plans?.length || 0,
53
+ incomplete_count: phaseInfo?.incomplete_plans?.length || 0,
54
+
55
+ // Branch name (pre-computed)
56
+ branch_name: config.branching_strategy === 'phase' && phaseInfo
57
+ ? (config.phase_branch_template as string)
58
+ .replace('{phase}', phaseInfo.phase_number)
59
+ .replace('{slug}', phaseInfo.phase_slug || 'phase')
60
+ : config.branching_strategy === 'milestone'
61
+ ? (config.milestone_branch_template as string)
62
+ .replace('{milestone}', milestone.version)
63
+ .replace('{slug}', generateSlugInternal(milestone.name) || 'milestone')
64
+ : null,
65
+
66
+ // Milestone info
67
+ milestone_version: milestone.version,
68
+ milestone_name: milestone.name,
69
+ milestone_slug: generateSlugInternal(milestone.name),
70
+
71
+ // File existence
72
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
73
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
74
+ config_exists: pathExistsInternal(cwd, '.planning/config.json'),
75
+ // File paths
76
+ state_path: '.planning/STATE.md',
77
+ roadmap_path: '.planning/ROADMAP.md',
78
+ config_path: '.planning/config.json',
79
+ };
80
+
81
+ output(result, raw);
82
+ }
83
+
84
+ export function cmdInitPlanPhase(cwd: string, phase: string | undefined, raw: boolean): void {
85
+ if (!phase) {
86
+ error('phase required for init plan-phase');
87
+ }
88
+
89
+ const config = loadConfig(cwd);
90
+ const phaseInfo = findPhaseInternal(cwd, phase!);
91
+
92
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase!);
93
+ const reqMatch = roadmapPhase?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
94
+ const reqExtracted = reqMatch
95
+ ? reqMatch[1].replace(/[\[\]]/g, '').split(',').map((s: string) => s.trim()).filter(Boolean).join(', ')
96
+ : null;
97
+ const phase_req_ids = (reqExtracted && reqExtracted !== 'TBD') ? reqExtracted : null;
98
+
99
+ const result: Record<string, unknown> = {
100
+ // Models
101
+ researcher_model: resolveModelInternal(cwd, 'vector-phase-researcher'),
102
+ planner_model: resolveModelInternal(cwd, 'vector-planner'),
103
+ checker_model: resolveModelInternal(cwd, 'vector-plan-checker'),
104
+
105
+ // Workflow flags
106
+ research_enabled: config.research,
107
+ plan_checker_enabled: config.plan_checker,
108
+ nyquist_validation_enabled: config.nyquist_validation,
109
+ commit_docs: config.commit_docs,
110
+
111
+ // Phase info
112
+ phase_found: !!phaseInfo,
113
+ phase_dir: phaseInfo?.directory || null,
114
+ phase_number: phaseInfo?.phase_number || null,
115
+ phase_name: phaseInfo?.phase_name || null,
116
+ phase_slug: phaseInfo?.phase_slug || null,
117
+ padded_phase: phaseInfo?.phase_number ? normalizePhaseName(phaseInfo.phase_number) : null,
118
+ phase_req_ids,
119
+
120
+ // Existing artifacts
121
+ has_research: phaseInfo?.has_research || false,
122
+ has_context: phaseInfo?.has_context || false,
123
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
124
+ plan_count: phaseInfo?.plans?.length || 0,
125
+
126
+ // Environment
127
+ planning_exists: pathExistsInternal(cwd, '.planning'),
128
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
129
+
130
+ // File paths
131
+ state_path: '.planning/STATE.md',
132
+ roadmap_path: '.planning/ROADMAP.md',
133
+ requirements_path: '.planning/REQUIREMENTS.md',
134
+ };
135
+
136
+ if (phaseInfo?.directory) {
137
+ // Find *-CONTEXT.md in phase directory
138
+ const phaseDirFull = path.join(cwd, phaseInfo.directory);
139
+ try {
140
+ const files = fs.readdirSync(phaseDirFull);
141
+ const contextFile = files.find(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
142
+ if (contextFile) {
143
+ result.context_path = toPosixPath(path.join(phaseInfo.directory, contextFile));
144
+ }
145
+ const researchFile = files.find(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
146
+ if (researchFile) {
147
+ result.research_path = toPosixPath(path.join(phaseInfo.directory, researchFile));
148
+ }
149
+ const verificationFile = files.find(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
150
+ if (verificationFile) {
151
+ result.verification_path = toPosixPath(path.join(phaseInfo.directory, verificationFile));
152
+ }
153
+ const uatFile = files.find(f => f.endsWith('-UAT.md') || f === 'UAT.md');
154
+ if (uatFile) {
155
+ result.uat_path = toPosixPath(path.join(phaseInfo.directory, uatFile));
156
+ }
157
+ } catch {}
158
+ }
159
+
160
+ output(result, raw);
161
+ }
162
+
163
+ export function cmdInitNewProject(cwd: string, raw: boolean): void {
164
+ const config = loadConfig(cwd);
165
+
166
+ // Detect Brave Search API key availability
167
+ const homedir = os.homedir();
168
+ const braveKeyFile = path.join(homedir, '.vector', 'brave_api_key');
169
+ const hasBraveSearch = !!(process.env.BRAVE_API_KEY || fs.existsSync(braveKeyFile));
170
+
171
+ // Detect existing code
172
+ let hasCode = false;
173
+ let hasPackageFile = false;
174
+ try {
175
+ 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', {
176
+ cwd,
177
+ encoding: 'utf-8',
178
+ stdio: ['pipe', 'pipe', 'pipe'],
179
+ });
180
+ hasCode = files.trim().length > 0;
181
+ } catch {}
182
+
183
+ hasPackageFile = pathExistsInternal(cwd, 'package.json') ||
184
+ pathExistsInternal(cwd, 'requirements.txt') ||
185
+ pathExistsInternal(cwd, 'Cargo.toml') ||
186
+ pathExistsInternal(cwd, 'go.mod') ||
187
+ pathExistsInternal(cwd, 'Package.swift');
188
+
189
+ const result = {
190
+ // Models
191
+ researcher_model: resolveModelInternal(cwd, 'vector-project-researcher'),
192
+ synthesizer_model: resolveModelInternal(cwd, 'vector-research-synthesizer'),
193
+ roadmapper_model: resolveModelInternal(cwd, 'vector-roadmapper'),
194
+
195
+ // Config
196
+ commit_docs: config.commit_docs,
197
+
198
+ // Existing state
199
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
200
+ has_codebase_map: pathExistsInternal(cwd, '.planning/codebase'),
201
+ planning_exists: pathExistsInternal(cwd, '.planning'),
202
+
203
+ // Brownfield detection
204
+ has_existing_code: hasCode,
205
+ has_package_file: hasPackageFile,
206
+ is_brownfield: hasCode || hasPackageFile,
207
+ needs_codebase_map: (hasCode || hasPackageFile) && !pathExistsInternal(cwd, '.planning/codebase'),
208
+
209
+ // Git state
210
+ has_git: pathExistsInternal(cwd, '.git'),
211
+
212
+ // Enhanced search
213
+ brave_search_available: hasBraveSearch,
214
+
215
+ // File paths
216
+ project_path: '.planning/PROJECT.md',
217
+ };
218
+
219
+ output(result, raw);
220
+ }
221
+
222
+ export function cmdInitNewMilestone(cwd: string, raw: boolean): void {
223
+ const config = loadConfig(cwd);
224
+ const milestone = getMilestoneInfo(cwd);
225
+
226
+ const result = {
227
+ // Models
228
+ researcher_model: resolveModelInternal(cwd, 'vector-project-researcher'),
229
+ synthesizer_model: resolveModelInternal(cwd, 'vector-research-synthesizer'),
230
+ roadmapper_model: resolveModelInternal(cwd, 'vector-roadmapper'),
231
+
232
+ // Config
233
+ commit_docs: config.commit_docs,
234
+ research_enabled: config.research,
235
+
236
+ // Current milestone
237
+ current_milestone: milestone.version,
238
+ current_milestone_name: milestone.name,
239
+
240
+ // File existence
241
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
242
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
243
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
244
+
245
+ // File paths
246
+ project_path: '.planning/PROJECT.md',
247
+ roadmap_path: '.planning/ROADMAP.md',
248
+ state_path: '.planning/STATE.md',
249
+ };
250
+
251
+ output(result, raw);
252
+ }
253
+
254
+ export function cmdInitQuick(cwd: string, description: string | undefined, raw: boolean): void {
255
+ const config = loadConfig(cwd);
256
+ const now = new Date();
257
+ const slug = description ? generateSlugInternal(description)?.substring(0, 40) : null;
258
+
259
+ // Generate collision-resistant quick task ID: YYMMDD-xxx
260
+ // xxx = 2-second precision blocks since midnight, encoded as 3-char Base36 (lowercase)
261
+ // Range: 000 (00:00:00) to xbz (23:59:58), guaranteed 3 chars for any time of day.
262
+ // Provides ~2s uniqueness window per user — practically collision-free across a team.
263
+ const yy = String(now.getFullYear()).slice(-2);
264
+ const mm = String(now.getMonth() + 1).padStart(2, '0');
265
+ const dd = String(now.getDate()).padStart(2, '0');
266
+ const dateStr = yy + mm + dd;
267
+ const secondsSinceMidnight = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
268
+ const timeBlocks = Math.floor(secondsSinceMidnight / 2);
269
+ const timeEncoded = timeBlocks.toString(36).padStart(3, '0');
270
+ const quickId = dateStr + '-' + timeEncoded;
271
+
272
+ const result = {
273
+ // Models
274
+ planner_model: resolveModelInternal(cwd, 'vector-planner'),
275
+ executor_model: resolveModelInternal(cwd, 'vector-executor'),
276
+ checker_model: resolveModelInternal(cwd, 'vector-plan-checker'),
277
+ verifier_model: resolveModelInternal(cwd, 'vector-verifier'),
278
+
279
+ // Config
280
+ commit_docs: config.commit_docs,
281
+
282
+ // Quick task info
283
+ quick_id: quickId,
284
+ slug: slug,
285
+ description: description || null,
286
+
287
+ // Timestamps
288
+ date: now.toISOString().split('T')[0],
289
+ timestamp: now.toISOString(),
290
+
291
+ // Paths
292
+ quick_dir: '.planning/quick',
293
+ task_dir: slug ? `.planning/quick/${quickId}-${slug}` : null,
294
+
295
+ // File existence
296
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
297
+ planning_exists: pathExistsInternal(cwd, '.planning'),
298
+ };
299
+
300
+ output(result, raw);
301
+ }
302
+
303
+ export function cmdInitResume(cwd: string, raw: boolean): void {
304
+ const config = loadConfig(cwd);
305
+
306
+ // Check for interrupted agent
307
+ let interruptedAgentId: string | null = null;
308
+ try {
309
+ interruptedAgentId = fs.readFileSync(path.join(cwd, '.planning', 'current-agent-id.txt'), 'utf-8').trim();
310
+ } catch {}
311
+
312
+ const result = {
313
+ // File existence
314
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
315
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
316
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.MD'),
317
+ planning_exists: pathExistsInternal(cwd, '.planning'),
318
+
319
+ // File paths
320
+ state_path: '.planning/STATE.md',
321
+ roadmap_path: '.planning/ROADMAP.md',
322
+ project_path: '.planning/PROJECT.md',
323
+
324
+ // Agent state
325
+ has_interrupted_agent: !!interruptedAgentId,
326
+ interrupted_agent_id: interruptedAgentId,
327
+
328
+ // Config
329
+ commit_docs: config.commit_docs,
330
+ };
331
+
332
+ output(result, raw);
333
+ }
334
+
335
+ export function cmdInitVerifyWork(cwd: string, phase: string | undefined, raw: boolean): void {
336
+ if (!phase) {
337
+ error('phase required for init verify-work');
338
+ }
339
+
340
+ const config = loadConfig(cwd);
341
+ const phaseInfo = findPhaseInternal(cwd, phase!);
342
+
343
+ const result = {
344
+ // Models
345
+ planner_model: resolveModelInternal(cwd, 'vector-planner'),
346
+ checker_model: resolveModelInternal(cwd, 'vector-plan-checker'),
347
+
348
+ // Config
349
+ commit_docs: config.commit_docs,
350
+
351
+ // Phase info
352
+ phase_found: !!phaseInfo,
353
+ phase_dir: phaseInfo?.directory || null,
354
+ phase_number: phaseInfo?.phase_number || null,
355
+ phase_name: phaseInfo?.phase_name || null,
356
+
357
+ // Existing artifacts
358
+ has_verification: phaseInfo?.has_verification || false,
359
+ };
360
+
361
+ output(result, raw);
362
+ }
363
+
364
+ export function cmdInitPhaseOp(cwd: string, phase: string | undefined, raw: boolean): void {
365
+ const config = loadConfig(cwd);
366
+ let phaseInfo = findPhaseInternal(cwd, phase!);
367
+
368
+ // If the only disk match comes from an archived milestone, prefer the
369
+ // current milestone's ROADMAP entry so discuss-phase and similar flows
370
+ // don't attach to shipped work that reused the same phase number.
371
+ if (phaseInfo?.archived) {
372
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase!);
373
+ if (roadmapPhase?.found) {
374
+ const phaseName = roadmapPhase.phase_name;
375
+ phaseInfo = {
376
+ found: true,
377
+ directory: null,
378
+ phase_number: roadmapPhase.phase_number,
379
+ phase_name: phaseName,
380
+ phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
381
+ plans: [],
382
+ summaries: [],
383
+ incomplete_plans: [],
384
+ has_research: false,
385
+ has_context: false,
386
+ has_verification: false,
387
+ };
388
+ }
389
+ }
390
+
391
+ // Fallback to ROADMAP.md if no directory exists (e.g., Plans: TBD)
392
+ if (!phaseInfo) {
393
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase!);
394
+ if (roadmapPhase?.found) {
395
+ const phaseName = roadmapPhase.phase_name;
396
+ phaseInfo = {
397
+ found: true,
398
+ directory: null,
399
+ phase_number: roadmapPhase.phase_number,
400
+ phase_name: phaseName,
401
+ phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
402
+ plans: [],
403
+ summaries: [],
404
+ incomplete_plans: [],
405
+ has_research: false,
406
+ has_context: false,
407
+ has_verification: false,
408
+ };
409
+ }
410
+ }
411
+
412
+ const result: Record<string, unknown> = {
413
+ // Config
414
+ commit_docs: config.commit_docs,
415
+ brave_search: config.brave_search,
416
+
417
+ // Phase info
418
+ phase_found: !!phaseInfo,
419
+ phase_dir: phaseInfo?.directory || null,
420
+ phase_number: phaseInfo?.phase_number || null,
421
+ phase_name: phaseInfo?.phase_name || null,
422
+ phase_slug: phaseInfo?.phase_slug || null,
423
+ padded_phase: phaseInfo?.phase_number ? normalizePhaseName(phaseInfo.phase_number) : null,
424
+
425
+ // Existing artifacts
426
+ has_research: phaseInfo?.has_research || false,
427
+ has_context: phaseInfo?.has_context || false,
428
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
429
+ has_verification: phaseInfo?.has_verification || false,
430
+ plan_count: phaseInfo?.plans?.length || 0,
431
+
432
+ // File existence
433
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
434
+ planning_exists: pathExistsInternal(cwd, '.planning'),
435
+
436
+ // File paths
437
+ state_path: '.planning/STATE.md',
438
+ roadmap_path: '.planning/ROADMAP.md',
439
+ requirements_path: '.planning/REQUIREMENTS.md',
440
+ };
441
+
442
+ if (phaseInfo?.directory) {
443
+ const phaseDirFull = path.join(cwd, phaseInfo.directory);
444
+ try {
445
+ const files = fs.readdirSync(phaseDirFull);
446
+ const contextFile = files.find(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
447
+ if (contextFile) {
448
+ result.context_path = toPosixPath(path.join(phaseInfo.directory, contextFile));
449
+ }
450
+ const researchFile = files.find(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
451
+ if (researchFile) {
452
+ result.research_path = toPosixPath(path.join(phaseInfo.directory, researchFile));
453
+ }
454
+ const verificationFile = files.find(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
455
+ if (verificationFile) {
456
+ result.verification_path = toPosixPath(path.join(phaseInfo.directory, verificationFile));
457
+ }
458
+ const uatFile = files.find(f => f.endsWith('-UAT.md') || f === 'UAT.md');
459
+ if (uatFile) {
460
+ result.uat_path = toPosixPath(path.join(phaseInfo.directory, uatFile));
461
+ }
462
+ } catch {}
463
+ }
464
+
465
+ output(result, raw);
466
+ }
467
+
468
+ export function cmdInitTodos(cwd: string, area: string | undefined, raw: boolean): void {
469
+ const config = loadConfig(cwd);
470
+ const now = new Date();
471
+
472
+ // List todos (reuse existing logic)
473
+ const pendingDir = path.join(cwd, '.planning', 'todos', 'pending');
474
+ let count = 0;
475
+ const todos: Array<{ file: string; created: string; title: string; area: string; path: string }> = [];
476
+
477
+ try {
478
+ const files = fs.readdirSync(pendingDir).filter(f => f.endsWith('.md'));
479
+ for (const file of files) {
480
+ try {
481
+ const content = fs.readFileSync(path.join(pendingDir, file), 'utf-8');
482
+ const createdMatch = content.match(/^created:\s*(.+)$/m);
483
+ const titleMatch = content.match(/^title:\s*(.+)$/m);
484
+ const areaMatch = content.match(/^area:\s*(.+)$/m);
485
+ const todoArea = areaMatch ? areaMatch[1].trim() : 'general';
486
+
487
+ if (area && todoArea !== area) continue;
488
+
489
+ count++;
490
+ todos.push({
491
+ file,
492
+ created: createdMatch ? createdMatch[1].trim() : 'unknown',
493
+ title: titleMatch ? titleMatch[1].trim() : 'Untitled',
494
+ area: todoArea,
495
+ path: '.planning/todos/pending/' + file,
496
+ });
497
+ } catch {}
498
+ }
499
+ } catch {}
500
+
501
+ const result = {
502
+ // Config
503
+ commit_docs: config.commit_docs,
504
+
505
+ // Timestamps
506
+ date: now.toISOString().split('T')[0],
507
+ timestamp: now.toISOString(),
508
+
509
+ // Todo inventory
510
+ todo_count: count,
511
+ todos,
512
+ area_filter: area || null,
513
+
514
+ // Paths
515
+ pending_dir: '.planning/todos/pending',
516
+ completed_dir: '.planning/todos/completed',
517
+
518
+ // File existence
519
+ planning_exists: pathExistsInternal(cwd, '.planning'),
520
+ todos_dir_exists: pathExistsInternal(cwd, '.planning/todos'),
521
+ pending_dir_exists: pathExistsInternal(cwd, '.planning/todos/pending'),
522
+ };
523
+
524
+ output(result, raw);
525
+ }
526
+
527
+ export function cmdInitMilestoneOp(cwd: string, raw: boolean): void {
528
+ const config = loadConfig(cwd);
529
+ const milestone = getMilestoneInfo(cwd);
530
+
531
+ // Count phases
532
+ let phaseCount = 0;
533
+ let completedPhases = 0;
534
+ const phasesDir = path.join(cwd, '.planning', 'phases');
535
+ try {
536
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
537
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
538
+ phaseCount = dirs.length;
539
+
540
+ // Count phases with summaries (completed)
541
+ for (const dir of dirs) {
542
+ try {
543
+ const phaseFiles = fs.readdirSync(path.join(phasesDir, dir));
544
+ const hasSummary = phaseFiles.some(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
545
+ if (hasSummary) completedPhases++;
546
+ } catch {}
547
+ }
548
+ } catch {}
549
+
550
+ // Check archive
551
+ const archiveDir = path.join(cwd, '.planning', 'archive');
552
+ let archivedMilestones: string[] = [];
553
+ try {
554
+ archivedMilestones = fs.readdirSync(archiveDir, { withFileTypes: true })
555
+ .filter(e => e.isDirectory())
556
+ .map(e => e.name);
557
+ } catch {}
558
+
559
+ const result = {
560
+ // Config
561
+ commit_docs: config.commit_docs,
562
+
563
+ // Current milestone
564
+ milestone_version: milestone.version,
565
+ milestone_name: milestone.name,
566
+ milestone_slug: generateSlugInternal(milestone.name),
567
+
568
+ // Phase counts
569
+ phase_count: phaseCount,
570
+ completed_phases: completedPhases,
571
+ all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
572
+
573
+ // Archive
574
+ archived_milestones: archivedMilestones,
575
+ archive_count: archivedMilestones.length,
576
+
577
+ // File existence
578
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
579
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
580
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
581
+ archive_exists: pathExistsInternal(cwd, '.planning/archive'),
582
+ phases_dir_exists: pathExistsInternal(cwd, '.planning/phases'),
583
+ };
584
+
585
+ output(result, raw);
586
+ }
587
+
588
+ export function cmdInitMapCodebase(cwd: string, raw: boolean): void {
589
+ const config = loadConfig(cwd);
590
+
591
+ // Check for existing codebase maps
592
+ const codebaseDir = path.join(cwd, '.planning', 'codebase');
593
+ let existingMaps: string[] = [];
594
+ try {
595
+ existingMaps = fs.readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
596
+ } catch {}
597
+
598
+ const result = {
599
+ // Models
600
+ mapper_model: resolveModelInternal(cwd, 'vector-codebase-mapper'),
601
+
602
+ // Config
603
+ commit_docs: config.commit_docs,
604
+ search_gitignored: config.search_gitignored,
605
+ parallelization: config.parallelization,
606
+
607
+ // Paths
608
+ codebase_dir: '.planning/codebase',
609
+
610
+ // Existing maps
611
+ existing_maps: existingMaps,
612
+ has_maps: existingMaps.length > 0,
613
+
614
+ // File existence
615
+ planning_exists: pathExistsInternal(cwd, '.planning'),
616
+ codebase_dir_exists: pathExistsInternal(cwd, '.planning/codebase'),
617
+ };
618
+
619
+ output(result, raw);
620
+ }
621
+
622
+ export function cmdInitProgress(cwd: string, raw: boolean): void {
623
+ const config = loadConfig(cwd);
624
+ const milestone = getMilestoneInfo(cwd);
625
+
626
+ // Analyze phases — filter to current milestone and include ROADMAP-only phases
627
+ const phasesDir = path.join(cwd, '.planning', 'phases');
628
+ const phases: Array<{
629
+ number: string;
630
+ name: string | null;
631
+ directory: string | null;
632
+ status: string;
633
+ plan_count: number;
634
+ summary_count: number;
635
+ has_research: boolean;
636
+ }> = [];
637
+ let currentPhase: typeof phases[number] | null = null;
638
+ let nextPhase: typeof phases[number] | null = null;
639
+
640
+ // Build set of phases defined in ROADMAP for the current milestone
641
+ const roadmapPhaseNums = new Set<string>();
642
+ const roadmapPhaseNames = new Map<string, string>();
643
+ try {
644
+ const roadmapContent = stripShippedMilestones(
645
+ fs.readFileSync(path.join(cwd, '.planning', 'ROADMAP.md'), 'utf-8')
646
+ );
647
+ const headingPattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:\s*([^\n]+)/gi;
648
+ let hm: RegExpExecArray | null;
649
+ while ((hm = headingPattern.exec(roadmapContent)) !== null) {
650
+ roadmapPhaseNums.add(hm[1]);
651
+ roadmapPhaseNames.set(hm[1], hm[2].replace(/\(INSERTED\)/i, '').trim());
652
+ }
653
+ } catch {}
654
+
655
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
656
+ const seenPhaseNums = new Set<string>();
657
+
658
+ try {
659
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
660
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name)
661
+ .filter(isDirInMilestone)
662
+ .sort((a, b) => {
663
+ const pa = a.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
664
+ const pb = b.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
665
+ if (!pa || !pb) return a.localeCompare(b);
666
+ return parseInt(pa[1], 10) - parseInt(pb[1], 10);
667
+ });
668
+
669
+ for (const dir of dirs) {
670
+ const match = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)-?(.*)/i);
671
+ const phaseNumber = match ? match[1] : dir;
672
+ const phaseName = match && match[2] ? match[2] : null;
673
+ seenPhaseNums.add(phaseNumber.replace(/^0+/, '') || '0');
674
+
675
+ const phasePath = path.join(phasesDir, dir);
676
+ const phaseFiles = fs.readdirSync(phasePath);
677
+
678
+ const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
679
+ const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
680
+ const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
681
+
682
+ const status = summaries.length >= plans.length && plans.length > 0 ? 'complete' :
683
+ plans.length > 0 ? 'in_progress' :
684
+ hasResearch ? 'researched' : 'pending';
685
+
686
+ const phaseEntry = {
687
+ number: phaseNumber,
688
+ name: phaseName,
689
+ directory: '.planning/phases/' + dir,
690
+ status,
691
+ plan_count: plans.length,
692
+ summary_count: summaries.length,
693
+ has_research: hasResearch,
694
+ };
695
+
696
+ phases.push(phaseEntry);
697
+
698
+ // Find current (first incomplete with plans) and next (first pending)
699
+ if (!currentPhase && (status === 'in_progress' || status === 'researched')) {
700
+ currentPhase = phaseEntry;
701
+ }
702
+ if (!nextPhase && status === 'pending') {
703
+ nextPhase = phaseEntry;
704
+ }
705
+ }
706
+ } catch {}
707
+
708
+ // Add phases defined in ROADMAP but not yet scaffolded to disk
709
+ for (const [num, name] of roadmapPhaseNames) {
710
+ const stripped = num.replace(/^0+/, '') || '0';
711
+ if (!seenPhaseNums.has(stripped)) {
712
+ const phaseEntry = {
713
+ number: num,
714
+ name: name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''),
715
+ directory: null,
716
+ status: 'not_started',
717
+ plan_count: 0,
718
+ summary_count: 0,
719
+ has_research: false,
720
+ };
721
+ phases.push(phaseEntry);
722
+ if (!nextPhase && !currentPhase) {
723
+ nextPhase = phaseEntry;
724
+ }
725
+ }
726
+ }
727
+
728
+ // Re-sort phases by number after adding ROADMAP-only phases
729
+ phases.sort((a, b) => parseInt(a.number, 10) - parseInt(b.number, 10));
730
+
731
+ // Check for paused work
732
+ let pausedAt: string | null = null;
733
+ try {
734
+ const state = fs.readFileSync(path.join(cwd, '.planning', 'STATE.md'), 'utf-8');
735
+ const pauseMatch = state.match(/\*\*Paused At:\*\*\s*(.+)/);
736
+ if (pauseMatch) pausedAt = pauseMatch[1].trim();
737
+ } catch {}
738
+
739
+ const result = {
740
+ // Models
741
+ executor_model: resolveModelInternal(cwd, 'vector-executor'),
742
+ planner_model: resolveModelInternal(cwd, 'vector-planner'),
743
+
744
+ // Config
745
+ commit_docs: config.commit_docs,
746
+
747
+ // Milestone
748
+ milestone_version: milestone.version,
749
+ milestone_name: milestone.name,
750
+
751
+ // Phase overview
752
+ phases,
753
+ phase_count: phases.length,
754
+ completed_count: phases.filter(p => p.status === 'complete').length,
755
+ in_progress_count: phases.filter(p => p.status === 'in_progress').length,
756
+
757
+ // Current state
758
+ current_phase: currentPhase,
759
+ next_phase: nextPhase,
760
+ paused_at: pausedAt,
761
+ has_work_in_progress: !!currentPhase,
762
+
763
+ // File existence
764
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
765
+ roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
766
+ state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
767
+ // File paths
768
+ state_path: '.planning/STATE.md',
769
+ roadmap_path: '.planning/ROADMAP.md',
770
+ project_path: '.planning/PROJECT.md',
771
+ config_path: '.planning/config.json',
772
+ };
773
+
774
+ output(result, raw);
775
+ }