@ktpartners/dgs-platform 2.6.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 (256) hide show
  1. package/LICENSE +38 -0
  2. package/README.md +851 -0
  3. package/agents/dgs-codebase-cross-analyzer.md +183 -0
  4. package/agents/dgs-codebase-mapper.md +782 -0
  5. package/agents/dgs-codebase-synthesizer.md +156 -0
  6. package/agents/dgs-debugger.md +1256 -0
  7. package/agents/dgs-executor.md +550 -0
  8. package/agents/dgs-integration-checker.md +481 -0
  9. package/agents/dgs-nyquist-auditor.md +178 -0
  10. package/agents/dgs-phase-researcher.md +563 -0
  11. package/agents/dgs-phase-verifier.md +450 -0
  12. package/agents/dgs-plan-checker.md +708 -0
  13. package/agents/dgs-planner.md +1324 -0
  14. package/agents/dgs-project-researcher.md +631 -0
  15. package/agents/dgs-research-synthesizer.md +249 -0
  16. package/agents/dgs-roadmapper.md +652 -0
  17. package/agents/dgs-verifier.md +607 -0
  18. package/bin/install.js +2073 -0
  19. package/commands/dgs/add-doc.md +45 -0
  20. package/commands/dgs/add-idea.md +38 -0
  21. package/commands/dgs/add-phase.md +43 -0
  22. package/commands/dgs/add-repo.md +54 -0
  23. package/commands/dgs/add-tests.md +41 -0
  24. package/commands/dgs/add-todo.md +47 -0
  25. package/commands/dgs/approve-spec.md +38 -0
  26. package/commands/dgs/audit-milestone.md +36 -0
  27. package/commands/dgs/audit-phase.md +37 -0
  28. package/commands/dgs/cancel-job.md +23 -0
  29. package/commands/dgs/capture-principle.md +143 -0
  30. package/commands/dgs/check-todos.md +45 -0
  31. package/commands/dgs/cleanup.md +18 -0
  32. package/commands/dgs/complete-milestone.md +136 -0
  33. package/commands/dgs/complete-project.md +70 -0
  34. package/commands/dgs/consolidate-ideas.md +50 -0
  35. package/commands/dgs/create-milestone-job.md +37 -0
  36. package/commands/dgs/debug.md +164 -0
  37. package/commands/dgs/develop-idea.md +53 -0
  38. package/commands/dgs/discuss-idea.md +41 -0
  39. package/commands/dgs/discuss-phase.md +83 -0
  40. package/commands/dgs/execute-phase.md +41 -0
  41. package/commands/dgs/fast.md +38 -0
  42. package/commands/dgs/find-related-ideas.md +43 -0
  43. package/commands/dgs/health.md +28 -0
  44. package/commands/dgs/help.md +22 -0
  45. package/commands/dgs/import-spec.md +36 -0
  46. package/commands/dgs/init-product.md +28 -0
  47. package/commands/dgs/insert-phase.md +32 -0
  48. package/commands/dgs/join-discord.md +18 -0
  49. package/commands/dgs/list-docs.md +40 -0
  50. package/commands/dgs/list-ideas.md +42 -0
  51. package/commands/dgs/list-jobs.md +22 -0
  52. package/commands/dgs/list-phase-assumptions.md +46 -0
  53. package/commands/dgs/list-projects.md +57 -0
  54. package/commands/dgs/list-specs.md +40 -0
  55. package/commands/dgs/map-codebase.md +92 -0
  56. package/commands/dgs/new-milestone.md +44 -0
  57. package/commands/dgs/new-project.md +42 -0
  58. package/commands/dgs/node-repair.md +26 -0
  59. package/commands/dgs/overlap-check.md +20 -0
  60. package/commands/dgs/pause-work.md +38 -0
  61. package/commands/dgs/plan-milestone-gaps.md +34 -0
  62. package/commands/dgs/plan-phase.md +44 -0
  63. package/commands/dgs/progress.md +24 -0
  64. package/commands/dgs/quick.md +41 -0
  65. package/commands/dgs/reactivate-project.md +70 -0
  66. package/commands/dgs/reapply-patches.md +110 -0
  67. package/commands/dgs/refine-spec.md +38 -0
  68. package/commands/dgs/reject-idea.md +43 -0
  69. package/commands/dgs/remove-doc.md +44 -0
  70. package/commands/dgs/remove-phase.md +31 -0
  71. package/commands/dgs/remove-repo.md +69 -0
  72. package/commands/dgs/research-idea.md +43 -0
  73. package/commands/dgs/research-phase.md +189 -0
  74. package/commands/dgs/restore-idea.md +45 -0
  75. package/commands/dgs/resume-work.md +40 -0
  76. package/commands/dgs/rollback-job.md +24 -0
  77. package/commands/dgs/run-job.md +35 -0
  78. package/commands/dgs/search.md +40 -0
  79. package/commands/dgs/set-profile.md +34 -0
  80. package/commands/dgs/settings.md +38 -0
  81. package/commands/dgs/switch-project.md +58 -0
  82. package/commands/dgs/undo-consolidation.md +42 -0
  83. package/commands/dgs/update-idea.md +44 -0
  84. package/commands/dgs/update.md +37 -0
  85. package/commands/dgs/validate-phase.md +35 -0
  86. package/commands/dgs/verify-work.md +39 -0
  87. package/commands/dgs/write-spec.md +49 -0
  88. package/deliver-great-systems/.planning/phases/09-backend-wiring-and-error-handling/09-01-SUMMARY.md +84 -0
  89. package/deliver-great-systems/.planning/phases/09-backend-wiring-and-error-handling/09-02-SUMMARY.md +86 -0
  90. package/deliver-great-systems/.planning/phases/10-v1-to-v2-migration-flow/10-01-SUMMARY.md +85 -0
  91. package/deliver-great-systems/bin/dgs-tools.cjs +1444 -0
  92. package/deliver-great-systems/bin/lib/auto-test.cjs +1365 -0
  93. package/deliver-great-systems/bin/lib/commands.cjs +570 -0
  94. package/deliver-great-systems/bin/lib/config.cjs +417 -0
  95. package/deliver-great-systems/bin/lib/conflict-agent.cjs +1063 -0
  96. package/deliver-great-systems/bin/lib/conflict-agent.test.cjs +554 -0
  97. package/deliver-great-systems/bin/lib/context.cjs +929 -0
  98. package/deliver-great-systems/bin/lib/context.test.cjs +693 -0
  99. package/deliver-great-systems/bin/lib/core.cjs +744 -0
  100. package/deliver-great-systems/bin/lib/core.test.cjs +822 -0
  101. package/deliver-great-systems/bin/lib/docs.cjs +919 -0
  102. package/deliver-great-systems/bin/lib/docs.test.cjs +211 -0
  103. package/deliver-great-systems/bin/lib/execution.cjs +705 -0
  104. package/deliver-great-systems/bin/lib/execution.test.cjs +1472 -0
  105. package/deliver-great-systems/bin/lib/frontmatter.cjs +324 -0
  106. package/deliver-great-systems/bin/lib/ideas.cjs +1406 -0
  107. package/deliver-great-systems/bin/lib/ideas.test.cjs +1417 -0
  108. package/deliver-great-systems/bin/lib/identity.cjs +125 -0
  109. package/deliver-great-systems/bin/lib/init.cjs +1114 -0
  110. package/deliver-great-systems/bin/lib/init.test.cjs +1271 -0
  111. package/deliver-great-systems/bin/lib/jobs.cjs +2015 -0
  112. package/deliver-great-systems/bin/lib/jobs.test.cjs +2619 -0
  113. package/deliver-great-systems/bin/lib/merge-conflicts.cjs +654 -0
  114. package/deliver-great-systems/bin/lib/merge-conflicts.test.cjs +370 -0
  115. package/deliver-great-systems/bin/lib/migration.cjs +352 -0
  116. package/deliver-great-systems/bin/lib/migration.test.cjs +582 -0
  117. package/deliver-great-systems/bin/lib/milestone.cjs +243 -0
  118. package/deliver-great-systems/bin/lib/overlap.cjs +437 -0
  119. package/deliver-great-systems/bin/lib/overlap.test.cjs +747 -0
  120. package/deliver-great-systems/bin/lib/path-audit.test.cjs +384 -0
  121. package/deliver-great-systems/bin/lib/paths.cjs +144 -0
  122. package/deliver-great-systems/bin/lib/paths.test.cjs +486 -0
  123. package/deliver-great-systems/bin/lib/phase.cjs +910 -0
  124. package/deliver-great-systems/bin/lib/projects.cjs +691 -0
  125. package/deliver-great-systems/bin/lib/projects.test.cjs +871 -0
  126. package/deliver-great-systems/bin/lib/repos.cjs +1432 -0
  127. package/deliver-great-systems/bin/lib/repos.test.cjs +1882 -0
  128. package/deliver-great-systems/bin/lib/roadmap.cjs +305 -0
  129. package/deliver-great-systems/bin/lib/search.cjs +570 -0
  130. package/deliver-great-systems/bin/lib/specs.cjs +1303 -0
  131. package/deliver-great-systems/bin/lib/state.cjs +893 -0
  132. package/deliver-great-systems/bin/lib/template.cjs +228 -0
  133. package/deliver-great-systems/bin/lib/test-helpers.cjs +291 -0
  134. package/deliver-great-systems/bin/lib/verify.cjs +796 -0
  135. package/deliver-great-systems/references/checkpoints.md +776 -0
  136. package/deliver-great-systems/references/conflict-resolution.md +66 -0
  137. package/deliver-great-systems/references/context-tiers.md +166 -0
  138. package/deliver-great-systems/references/continuation-format.md +249 -0
  139. package/deliver-great-systems/references/decimal-phase-calculation.md +67 -0
  140. package/deliver-great-systems/references/git-integration.md +250 -0
  141. package/deliver-great-systems/references/git-planning-commit.md +40 -0
  142. package/deliver-great-systems/references/model-profile-resolution.md +36 -0
  143. package/deliver-great-systems/references/model-profiles.md +95 -0
  144. package/deliver-great-systems/references/phase-argument-parsing.md +61 -0
  145. package/deliver-great-systems/references/planning-config.md +224 -0
  146. package/deliver-great-systems/references/questioning.md +162 -0
  147. package/deliver-great-systems/references/spec-review-loop.md +177 -0
  148. package/deliver-great-systems/references/tdd.md +265 -0
  149. package/deliver-great-systems/references/ui-brand.md +160 -0
  150. package/deliver-great-systems/references/verification-patterns.md +612 -0
  151. package/deliver-great-systems/templates/DEBUG.md +166 -0
  152. package/deliver-great-systems/templates/UAT.md +251 -0
  153. package/deliver-great-systems/templates/VALIDATION.md +95 -0
  154. package/deliver-great-systems/templates/claude-md.md +74 -0
  155. package/deliver-great-systems/templates/codebase/architecture.md +257 -0
  156. package/deliver-great-systems/templates/codebase/concerns.md +312 -0
  157. package/deliver-great-systems/templates/codebase/conventions.md +309 -0
  158. package/deliver-great-systems/templates/codebase/integrations.md +282 -0
  159. package/deliver-great-systems/templates/codebase/stack.md +188 -0
  160. package/deliver-great-systems/templates/codebase/structure.md +287 -0
  161. package/deliver-great-systems/templates/codebase/testing.md +482 -0
  162. package/deliver-great-systems/templates/config.json +38 -0
  163. package/deliver-great-systems/templates/context.md +354 -0
  164. package/deliver-great-systems/templates/continue-here.md +80 -0
  165. package/deliver-great-systems/templates/debug-subagent-prompt.md +93 -0
  166. package/deliver-great-systems/templates/discovery.md +148 -0
  167. package/deliver-great-systems/templates/milestone-archive.md +125 -0
  168. package/deliver-great-systems/templates/milestone.md +117 -0
  169. package/deliver-great-systems/templates/phase-prompt.md +615 -0
  170. package/deliver-great-systems/templates/planner-subagent-prompt.md +119 -0
  171. package/deliver-great-systems/templates/project.md +186 -0
  172. package/deliver-great-systems/templates/requirements.md +233 -0
  173. package/deliver-great-systems/templates/research-project/ARCHITECTURE.md +206 -0
  174. package/deliver-great-systems/templates/research-project/FEATURES.md +149 -0
  175. package/deliver-great-systems/templates/research-project/PITFALLS.md +202 -0
  176. package/deliver-great-systems/templates/research-project/STACK.md +122 -0
  177. package/deliver-great-systems/templates/research-project/SUMMARY.md +172 -0
  178. package/deliver-great-systems/templates/research.md +554 -0
  179. package/deliver-great-systems/templates/retrospective.md +54 -0
  180. package/deliver-great-systems/templates/roadmap.md +204 -0
  181. package/deliver-great-systems/templates/state.md +178 -0
  182. package/deliver-great-systems/templates/summary-complex.md +59 -0
  183. package/deliver-great-systems/templates/summary-minimal.md +41 -0
  184. package/deliver-great-systems/templates/summary-standard.md +48 -0
  185. package/deliver-great-systems/templates/summary.md +253 -0
  186. package/deliver-great-systems/templates/user-setup.md +313 -0
  187. package/deliver-great-systems/templates/verification-report.md +324 -0
  188. package/deliver-great-systems/workflows/add-doc.md +151 -0
  189. package/deliver-great-systems/workflows/add-idea.md +96 -0
  190. package/deliver-great-systems/workflows/add-phase.md +120 -0
  191. package/deliver-great-systems/workflows/add-tests.md +359 -0
  192. package/deliver-great-systems/workflows/add-todo.md +162 -0
  193. package/deliver-great-systems/workflows/approve-spec.md +194 -0
  194. package/deliver-great-systems/workflows/audit-milestone.md +364 -0
  195. package/deliver-great-systems/workflows/audit-phase.md +462 -0
  196. package/deliver-great-systems/workflows/cancel-job.md +108 -0
  197. package/deliver-great-systems/workflows/check-todos.md +181 -0
  198. package/deliver-great-systems/workflows/cleanup.md +247 -0
  199. package/deliver-great-systems/workflows/codereview.md +526 -0
  200. package/deliver-great-systems/workflows/complete-milestone.md +1298 -0
  201. package/deliver-great-systems/workflows/consolidate-ideas.md +365 -0
  202. package/deliver-great-systems/workflows/create-milestone-job.md +177 -0
  203. package/deliver-great-systems/workflows/develop-idea.md +544 -0
  204. package/deliver-great-systems/workflows/diagnose-issues.md +231 -0
  205. package/deliver-great-systems/workflows/discovery-phase.md +301 -0
  206. package/deliver-great-systems/workflows/discuss-idea.md +263 -0
  207. package/deliver-great-systems/workflows/discuss-phase.md +733 -0
  208. package/deliver-great-systems/workflows/execute-phase.md +571 -0
  209. package/deliver-great-systems/workflows/execute-plan.md +592 -0
  210. package/deliver-great-systems/workflows/find-related-ideas.md +271 -0
  211. package/deliver-great-systems/workflows/health.md +173 -0
  212. package/deliver-great-systems/workflows/help.md +997 -0
  213. package/deliver-great-systems/workflows/import-spec.md +381 -0
  214. package/deliver-great-systems/workflows/init-product.md +767 -0
  215. package/deliver-great-systems/workflows/insert-phase.md +138 -0
  216. package/deliver-great-systems/workflows/list-docs.md +119 -0
  217. package/deliver-great-systems/workflows/list-ideas.md +154 -0
  218. package/deliver-great-systems/workflows/list-jobs.md +89 -0
  219. package/deliver-great-systems/workflows/list-phase-assumptions.md +192 -0
  220. package/deliver-great-systems/workflows/list-specs.md +101 -0
  221. package/deliver-great-systems/workflows/map-codebase.md +621 -0
  222. package/deliver-great-systems/workflows/new-milestone.md +591 -0
  223. package/deliver-great-systems/workflows/new-project.md +1113 -0
  224. package/deliver-great-systems/workflows/node-repair.md +94 -0
  225. package/deliver-great-systems/workflows/overlap-check.md +86 -0
  226. package/deliver-great-systems/workflows/pause-work.md +134 -0
  227. package/deliver-great-systems/workflows/plan-milestone-gaps.md +306 -0
  228. package/deliver-great-systems/workflows/plan-phase.md +698 -0
  229. package/deliver-great-systems/workflows/progress.md +386 -0
  230. package/deliver-great-systems/workflows/quick.md +845 -0
  231. package/deliver-great-systems/workflows/refine-spec.md +275 -0
  232. package/deliver-great-systems/workflows/reject-idea.md +109 -0
  233. package/deliver-great-systems/workflows/remove-doc.md +117 -0
  234. package/deliver-great-systems/workflows/remove-phase.md +163 -0
  235. package/deliver-great-systems/workflows/research-idea.md +325 -0
  236. package/deliver-great-systems/workflows/research-phase.md +81 -0
  237. package/deliver-great-systems/workflows/restore-idea.md +101 -0
  238. package/deliver-great-systems/workflows/resume-project.md +311 -0
  239. package/deliver-great-systems/workflows/rollback-job.md +130 -0
  240. package/deliver-great-systems/workflows/run-job.md +498 -0
  241. package/deliver-great-systems/workflows/search.md +130 -0
  242. package/deliver-great-systems/workflows/set-profile.md +83 -0
  243. package/deliver-great-systems/workflows/settings.md +470 -0
  244. package/deliver-great-systems/workflows/transition.md +563 -0
  245. package/deliver-great-systems/workflows/undo-consolidation.md +155 -0
  246. package/deliver-great-systems/workflows/update-idea.md +157 -0
  247. package/deliver-great-systems/workflows/update.md +242 -0
  248. package/deliver-great-systems/workflows/validate-phase.md +177 -0
  249. package/deliver-great-systems/workflows/verify-phase.md +253 -0
  250. package/deliver-great-systems/workflows/verify-work.md +671 -0
  251. package/deliver-great-systems/workflows/write-spec.md +450 -0
  252. package/hooks/dist/dgs-check-update.js +62 -0
  253. package/hooks/dist/dgs-context-monitor.js +141 -0
  254. package/hooks/dist/dgs-statusline.js +115 -0
  255. package/package.json +60 -0
  256. package/scripts/build-hooks.js +43 -0
@@ -0,0 +1,1114 @@
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, toPosixPath, output, error, resolveProjectPath, getProjectRoot, isV2Install, getProjectFolders, getV2Hint } = require('./core.cjs');
9
+ const { requireGitIdentity, formatAuthorString } = require('./identity.cjs');
10
+ const { getPlanningRoot, PROJECTS_DIR } = require('./paths.cjs');
11
+ const { parseReposMd, validateReposMdEager } = require('./repos.cjs');
12
+
13
+ /**
14
+ * Safely resolve the current git author string.
15
+ * Returns null on failure instead of throwing, since init commands
16
+ * should not hard-fail on identity resolution.
17
+ */
18
+ function resolveAuthorSafe(cwd) {
19
+ try {
20
+ const identity = requireGitIdentity(cwd);
21
+ return formatAuthorString(identity);
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ // ─── v2 Project Context Resolution ──────────────────────────────────────────
28
+
29
+ /**
30
+ * Resolve the project root, handling the NO_CURRENT_PROJECT_V2 guard.
31
+ * Returns { root, dgs_mode, current_project, guard, v2_hint } where:
32
+ * - root: the resolved project root path (null if guard triggered)
33
+ * - dgs_mode: 'v1' or 'v2'
34
+ * - current_project: string or null
35
+ * - guard: null (ok) | { action, message, projects? } (needs user action)
36
+ * - v2_hint: string or null (one-time v2 availability hint for v1 users)
37
+ */
38
+ function resolveProjectContext(cwd) {
39
+ const config = loadConfig(cwd);
40
+ const v2 = isV2Install(cwd);
41
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
42
+
43
+ try {
44
+ const root = getProjectRoot(cwd);
45
+ return {
46
+ root,
47
+ dgs_mode: v2 ? 'v2' : 'v1',
48
+ current_project: config.current_project || null,
49
+ guard: null,
50
+ v2_hint: !v2 ? getV2Hint(cwd, config) : null,
51
+ };
52
+ } catch (err) {
53
+ if (err.message === 'NO_CURRENT_PROJECT_V2') {
54
+ const folders = getProjectFolders(cwd);
55
+ if (folders.length === 0) {
56
+ return {
57
+ root: null,
58
+ dgs_mode: 'v2',
59
+ current_project: null,
60
+ guard: {
61
+ action: 'create',
62
+ message: 'No projects found. Run /dgs:new-project to create one.',
63
+ },
64
+ v2_hint: null,
65
+ };
66
+ }
67
+ if (folders.length === 1) {
68
+ const project = folders[0];
69
+ return {
70
+ root: path.join(planRootRel, PROJECTS_DIR, project),
71
+ dgs_mode: 'v2',
72
+ current_project: project,
73
+ guard: {
74
+ action: 'auto_selected',
75
+ project,
76
+ message: `Auto-selected project '${project}'`,
77
+ },
78
+ v2_hint: null,
79
+ };
80
+ }
81
+ const numbered = folders.map((f, i) => `${i + 1}) ${f}`).join(' ');
82
+ return {
83
+ root: null,
84
+ dgs_mode: 'v2',
85
+ current_project: null,
86
+ guard: {
87
+ action: 'prompt',
88
+ projects: folders,
89
+ message: `Multiple projects found. Select one:\n${numbered}`,
90
+ },
91
+ v2_hint: null,
92
+ };
93
+ }
94
+ if (err.message.startsWith('PROJECT_NOT_FOUND:')) {
95
+ const projectName = err.message.split(': ')[1];
96
+ return {
97
+ root: null,
98
+ dgs_mode: 'v2',
99
+ current_project: projectName,
100
+ guard: {
101
+ action: 'project_missing',
102
+ message: `Project '${projectName}' not found on disk. Run /dgs:switch-project to select a valid project.`,
103
+ },
104
+ v2_hint: null,
105
+ };
106
+ }
107
+ if (err.message.startsWith('PROJECT_COMPLETED:')) {
108
+ const projectName = err.message.split(': ')[1];
109
+ return {
110
+ root: null,
111
+ dgs_mode: 'v2',
112
+ current_project: projectName,
113
+ guard: {
114
+ action: 'project_completed',
115
+ message: `Project '${projectName}' is completed. Run /dgs:switch-project to select an active project.`,
116
+ },
117
+ v2_hint: null,
118
+ };
119
+ }
120
+ throw err;
121
+ }
122
+ }
123
+
124
+ function cmdInitExecutePhase(cwd, phase, raw) {
125
+ if (!phase) {
126
+ error('phase required for init execute-phase');
127
+ }
128
+
129
+ const config = loadConfig(cwd);
130
+ const ctx = resolveProjectContext(cwd);
131
+ const phaseInfo = findPhaseInternal(cwd, phase);
132
+ const milestone = getMilestoneInfo(cwd);
133
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
134
+
135
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
136
+ const reqMatch = roadmapPhase?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
137
+ const reqExtracted = reqMatch
138
+ ? reqMatch[1].replace(/[\[\]]/g, '').split(',').map(s => s.trim()).filter(Boolean).join(', ')
139
+ : null;
140
+ const phase_req_ids = (reqExtracted && reqExtracted !== 'TBD') ? reqExtracted : null;
141
+
142
+ // Resolve {project} in a branch template — errors if template uses {project} but current_project is not set
143
+ function resolveProjectInTemplate(template, currentProject) {
144
+ if (template.includes('{project}')) {
145
+ if (!currentProject) {
146
+ return { error: 'current_project not set. Run /dgs:settings to configure.' };
147
+ }
148
+ return { value: template.replace('{project}', currentProject) };
149
+ }
150
+ return { value: template };
151
+ }
152
+
153
+ const result = {
154
+ // Models
155
+ executor_model: resolveModelInternal(cwd, 'dgs-executor'),
156
+ verifier_model: resolveModelInternal(cwd, 'dgs-verifier'),
157
+
158
+ // Config flags
159
+ commit_docs: config.commit_docs,
160
+ parallelization: config.parallelization,
161
+ branching_strategy: config.branching_strategy,
162
+ phase_branch_template: config.phase_branch_template,
163
+ milestone_branch_template: config.milestone_branch_template,
164
+ verifier_enabled: config.verifier,
165
+ base_branch: config.base_branch,
166
+
167
+ // Phase info
168
+ phase_found: !!phaseInfo,
169
+ phase_dir: phaseInfo?.directory || null,
170
+ phase_number: phaseInfo?.phase_number || null,
171
+ phase_name: phaseInfo?.phase_name || null,
172
+ phase_slug: phaseInfo?.phase_slug || null,
173
+ phase_req_ids,
174
+
175
+ // Plan inventory
176
+ plans: phaseInfo?.plans || [],
177
+ summaries: phaseInfo?.summaries || [],
178
+ incomplete_plans: phaseInfo?.incomplete_plans || [],
179
+ plan_count: phaseInfo?.plans?.length || 0,
180
+ incomplete_count: phaseInfo?.incomplete_plans?.length || 0,
181
+
182
+ // Branch name (pre-computed with {project} resolution)
183
+ branch_name: (() => {
184
+ let template, resolved;
185
+ if (config.branching_strategy === 'phase' && phaseInfo) {
186
+ template = config.phase_branch_template;
187
+ resolved = resolveProjectInTemplate(template, ctx.current_project);
188
+ if (resolved.error) return resolved.error;
189
+ return resolved.value
190
+ .replace('{phase}', phaseInfo.phase_number)
191
+ .replace('{slug}', phaseInfo.phase_slug || 'phase');
192
+ } else if (config.branching_strategy === 'milestone') {
193
+ template = config.milestone_branch_template;
194
+ resolved = resolveProjectInTemplate(template, ctx.current_project);
195
+ if (resolved.error) return resolved.error;
196
+ return resolved.value
197
+ .replace('{milestone}', milestone.version)
198
+ .replace('{slug}', generateSlugInternal(milestone.name) || 'milestone');
199
+ }
200
+ return null;
201
+ })(),
202
+
203
+ // Milestone info
204
+ milestone_version: milestone.version,
205
+ milestone_name: milestone.name,
206
+ milestone_slug: generateSlugInternal(milestone.name),
207
+
208
+ // File existence
209
+ state_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'STATE.md')) : false,
210
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : false,
211
+ config_exists: pathExistsInternal(cwd, path.join(planRootRel, 'dgs.config.json')),
212
+ // File paths (project-qualified)
213
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
214
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
215
+ config_path: path.join(planRootRel, 'dgs.config.json'),
216
+ project_path: ctx.root ? path.join(ctx.root, 'PROJECT.md') : path.join(planRootRel, 'PROJECT.md'),
217
+ debug_dir: ctx.root ? path.join(ctx.root, 'debug') : path.join(planRootRel, 'debug'),
218
+
219
+ // Author
220
+ author: resolveAuthorSafe(cwd),
221
+
222
+ // v2 context
223
+ dgs_mode: ctx.dgs_mode,
224
+ current_project: ctx.current_project,
225
+ project_root: ctx.root,
226
+ guard: ctx.guard,
227
+ v2_hint: ctx.v2_hint || null,
228
+ };
229
+
230
+ output(result, raw);
231
+ }
232
+
233
+ function cmdInitPlanPhase(cwd, phase, raw) {
234
+ if (!phase) {
235
+ error('phase required for init plan-phase');
236
+ }
237
+
238
+ const config = loadConfig(cwd);
239
+ const ctx = resolveProjectContext(cwd);
240
+ const phaseInfo = findPhaseInternal(cwd, phase);
241
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
242
+
243
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
244
+ const reqMatch = roadmapPhase?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
245
+ const reqExtracted = reqMatch
246
+ ? reqMatch[1].replace(/[\[\]]/g, '').split(',').map(s => s.trim()).filter(Boolean).join(', ')
247
+ : null;
248
+ const phase_req_ids = (reqExtracted && reqExtracted !== 'TBD') ? reqExtracted : null;
249
+
250
+ const result = {
251
+ // Models
252
+ researcher_model: resolveModelInternal(cwd, 'dgs-phase-researcher'),
253
+ planner_model: resolveModelInternal(cwd, 'dgs-planner'),
254
+ checker_model: resolveModelInternal(cwd, 'dgs-plan-checker'),
255
+
256
+ // Workflow flags
257
+ research_enabled: config.research,
258
+ plan_checker_enabled: config.plan_checker,
259
+ nyquist_validation_enabled: config.nyquist_validation,
260
+ commit_docs: config.commit_docs,
261
+
262
+ // Phase info
263
+ phase_found: !!phaseInfo,
264
+ phase_dir: phaseInfo?.directory || null,
265
+ phase_number: phaseInfo?.phase_number || null,
266
+ phase_name: phaseInfo?.phase_name || null,
267
+ phase_slug: phaseInfo?.phase_slug || null,
268
+ padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
269
+ phase_req_ids,
270
+
271
+ // Existing artifacts
272
+ has_research: phaseInfo?.has_research || false,
273
+ has_context: phaseInfo?.has_context || false,
274
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
275
+ plan_count: phaseInfo?.plans?.length || 0,
276
+
277
+ // Environment
278
+ planning_exists: pathExistsInternal(cwd, planRootRel),
279
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'ROADMAP.md')),
280
+
281
+ // File paths (project-qualified)
282
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
283
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
284
+ requirements_path: ctx.root ? path.join(ctx.root, 'REQUIREMENTS.md') : path.join(planRootRel, 'REQUIREMENTS.md'),
285
+
286
+ // Author
287
+ author: resolveAuthorSafe(cwd),
288
+
289
+ // v2 context
290
+ dgs_mode: ctx.dgs_mode,
291
+ current_project: ctx.current_project,
292
+ project_root: ctx.root,
293
+ guard: ctx.guard,
294
+ v2_hint: ctx.v2_hint || null,
295
+ };
296
+
297
+ if (phaseInfo?.directory) {
298
+ // Find *-CONTEXT.md in phase directory
299
+ const phaseDirFull = path.join(cwd, phaseInfo.directory);
300
+ try {
301
+ const files = fs.readdirSync(phaseDirFull);
302
+ const contextFile = files.find(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
303
+ if (contextFile) {
304
+ result.context_path = toPosixPath(path.join(phaseInfo.directory, contextFile));
305
+ }
306
+ const researchFile = files.find(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
307
+ if (researchFile) {
308
+ result.research_path = toPosixPath(path.join(phaseInfo.directory, researchFile));
309
+ }
310
+ const verificationFile = files.find(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
311
+ if (verificationFile) {
312
+ result.verification_path = toPosixPath(path.join(phaseInfo.directory, verificationFile));
313
+ }
314
+ const uatFile = files.find(f => f.endsWith('-UAT.md') || f === 'UAT.md');
315
+ if (uatFile) {
316
+ result.uat_path = toPosixPath(path.join(phaseInfo.directory, uatFile));
317
+ }
318
+ } catch {}
319
+ }
320
+
321
+ output(result, raw);
322
+ }
323
+
324
+ function cmdInitNewProject(cwd, raw) {
325
+ const config = loadConfig(cwd);
326
+ const ctx = resolveProjectContext(cwd);
327
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
328
+
329
+ // Detect Brave Search API key availability
330
+ const homedir = require('os').homedir();
331
+ const braveKeyFile = path.join(homedir, '.dgs', 'brave_api_key');
332
+ const hasBraveSearch = !!(process.env.BRAVE_API_KEY || fs.existsSync(braveKeyFile));
333
+
334
+ // Detect existing code
335
+ let hasCode = false;
336
+ let hasPackageFile = false;
337
+ try {
338
+ 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', {
339
+ cwd,
340
+ encoding: 'utf-8',
341
+ stdio: ['pipe', 'pipe', 'pipe'],
342
+ });
343
+ hasCode = files.trim().length > 0;
344
+ } catch {}
345
+
346
+ hasPackageFile = pathExistsInternal(cwd, 'package.json') ||
347
+ pathExistsInternal(cwd, 'requirements.txt') ||
348
+ pathExistsInternal(cwd, 'Cargo.toml') ||
349
+ pathExistsInternal(cwd, 'go.mod') ||
350
+ pathExistsInternal(cwd, 'Package.swift');
351
+
352
+ const result = {
353
+ // Models
354
+ researcher_model: resolveModelInternal(cwd, 'dgs-project-researcher'),
355
+ synthesizer_model: resolveModelInternal(cwd, 'dgs-research-synthesizer'),
356
+ roadmapper_model: resolveModelInternal(cwd, 'dgs-roadmapper'),
357
+
358
+ // Config
359
+ commit_docs: config.commit_docs,
360
+
361
+ // Existing state (project-qualified)
362
+ project_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'PROJECT.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'PROJECT.md')),
363
+ has_codebase_map: pathExistsInternal(cwd, path.join(planRootRel, 'codebase')),
364
+ planning_exists: pathExistsInternal(cwd, planRootRel),
365
+
366
+ // Brownfield detection
367
+ has_existing_code: hasCode,
368
+ has_package_file: hasPackageFile,
369
+ is_brownfield: hasCode || hasPackageFile,
370
+ needs_codebase_map: (hasCode || hasPackageFile) && !pathExistsInternal(cwd, path.join(planRootRel, 'codebase')),
371
+
372
+ // Git state
373
+ has_git: pathExistsInternal(cwd, '.git'),
374
+
375
+ // Author
376
+ author: resolveAuthorSafe(cwd),
377
+
378
+ // Enhanced search
379
+ brave_search_available: hasBraveSearch,
380
+
381
+ // File paths (project-qualified)
382
+ project_path: ctx.root ? path.join(ctx.root, 'PROJECT.md') : path.join(planRootRel, 'PROJECT.md'),
383
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
384
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
385
+ requirements_path: ctx.root ? path.join(ctx.root, 'REQUIREMENTS.md') : path.join(planRootRel, 'REQUIREMENTS.md'),
386
+ research_dir: ctx.root ? path.join(ctx.root, 'research') : path.join(planRootRel, 'research'),
387
+
388
+ // v2 context
389
+ dgs_mode: ctx.dgs_mode,
390
+ current_project: ctx.current_project,
391
+ project_root: ctx.root,
392
+ guard: ctx.guard,
393
+ v2_hint: ctx.v2_hint || null,
394
+ };
395
+
396
+ output(result, raw);
397
+ }
398
+
399
+ function cmdInitNewMilestone(cwd, raw) {
400
+ const config = loadConfig(cwd);
401
+ const ctx = resolveProjectContext(cwd);
402
+ const milestone = getMilestoneInfo(cwd);
403
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
404
+
405
+ const result = {
406
+ // Models
407
+ researcher_model: resolveModelInternal(cwd, 'dgs-project-researcher'),
408
+ synthesizer_model: resolveModelInternal(cwd, 'dgs-research-synthesizer'),
409
+ roadmapper_model: resolveModelInternal(cwd, 'dgs-roadmapper'),
410
+
411
+ // Config
412
+ commit_docs: config.commit_docs,
413
+ research_enabled: config.research,
414
+
415
+ // Current milestone
416
+ current_milestone: milestone.version,
417
+ current_milestone_name: milestone.name,
418
+
419
+ // File existence (project-qualified)
420
+ project_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'PROJECT.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'PROJECT.md')),
421
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'ROADMAP.md')),
422
+ state_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'STATE.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'STATE.md')),
423
+
424
+ // File paths (project-qualified)
425
+ project_path: ctx.root ? path.join(ctx.root, 'PROJECT.md') : path.join(planRootRel, 'PROJECT.md'),
426
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
427
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
428
+
429
+ // Author
430
+ author: resolveAuthorSafe(cwd),
431
+
432
+ // v2 context
433
+ dgs_mode: ctx.dgs_mode,
434
+ current_project: ctx.current_project,
435
+ project_root: ctx.root,
436
+ guard: ctx.guard,
437
+ v2_hint: ctx.v2_hint || null,
438
+ };
439
+
440
+ output(result, raw);
441
+ }
442
+
443
+ function cmdInitQuick(cwd, description, raw) {
444
+ const config = loadConfig(cwd);
445
+ const ctx = resolveProjectContext(cwd);
446
+ const now = new Date();
447
+ const slug = description ? generateSlugInternal(description)?.substring(0, 40) : null;
448
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
449
+
450
+ // Generate collision-resistant quick task ID: YYMMDD-xxx
451
+ // xxx = 2-second precision blocks since midnight, encoded as 3-char Base36 (lowercase)
452
+ // Range: 000 (00:00:00) to xbz (23:59:58), guaranteed 3 chars for any time of day.
453
+ // Provides ~2s uniqueness window per user — practically collision-free across a team.
454
+ const quickBase = ctx.root ? path.join(ctx.root, 'quick') : path.join(planRootRel, 'quick');
455
+ const yy = String(now.getFullYear()).slice(-2);
456
+ const mm = String(now.getMonth() + 1).padStart(2, '0');
457
+ const dd = String(now.getDate()).padStart(2, '0');
458
+ const dateStr = yy + mm + dd;
459
+ const secondsSinceMidnight = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
460
+ const timeBlocks = Math.floor(secondsSinceMidnight / 2);
461
+ const timeEncoded = timeBlocks.toString(36).padStart(3, '0');
462
+ const quickId = dateStr + '-' + timeEncoded;
463
+
464
+ const result = {
465
+ // Models
466
+ planner_model: resolveModelInternal(cwd, 'dgs-planner'),
467
+ executor_model: resolveModelInternal(cwd, 'dgs-executor'),
468
+ checker_model: resolveModelInternal(cwd, 'dgs-plan-checker'),
469
+ verifier_model: resolveModelInternal(cwd, 'dgs-verifier'),
470
+
471
+ // Config
472
+ commit_docs: config.commit_docs,
473
+
474
+ // Quick task info
475
+ quick_id: quickId,
476
+ slug: slug,
477
+ description: description || null,
478
+
479
+ // Timestamps
480
+ date: now.toISOString().split('T')[0],
481
+ timestamp: now.toISOString(),
482
+
483
+ // Paths (project-qualified)
484
+ quick_dir: quickBase,
485
+ task_dir: slug ? path.join(quickBase, `${quickId}-${slug}`) : null,
486
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
487
+
488
+ // File existence
489
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'ROADMAP.md')),
490
+ planning_exists: pathExistsInternal(cwd, planRootRel),
491
+
492
+ // Author
493
+ author: resolveAuthorSafe(cwd),
494
+
495
+ // v2 context
496
+ dgs_mode: ctx.dgs_mode,
497
+ current_project: ctx.current_project,
498
+ project_root: ctx.root,
499
+ guard: ctx.guard,
500
+ v2_hint: ctx.v2_hint || null,
501
+ };
502
+
503
+ output(result, raw);
504
+ }
505
+
506
+ function cmdInitResume(cwd, raw) {
507
+ const config = loadConfig(cwd);
508
+ const ctx = resolveProjectContext(cwd);
509
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
510
+
511
+ // Check for interrupted agent
512
+ let interruptedAgentId = null;
513
+ try {
514
+ interruptedAgentId = fs.readFileSync(path.join(getPlanningRoot(cwd), 'current-agent-id.txt'), 'utf-8').trim();
515
+ } catch {}
516
+
517
+ const result = {
518
+ // File existence (project-qualified)
519
+ state_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'STATE.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'STATE.md')),
520
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'ROADMAP.md')),
521
+ project_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'PROJECT.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'PROJECT.md')),
522
+ planning_exists: pathExistsInternal(cwd, planRootRel),
523
+
524
+ // File paths (project-qualified)
525
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
526
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
527
+ project_path: ctx.root ? path.join(ctx.root, 'PROJECT.md') : path.join(planRootRel, 'PROJECT.md'),
528
+
529
+ // Author
530
+ author: resolveAuthorSafe(cwd),
531
+
532
+ // Agent state
533
+ has_interrupted_agent: !!interruptedAgentId,
534
+ interrupted_agent_id: interruptedAgentId,
535
+
536
+ // Config
537
+ commit_docs: config.commit_docs,
538
+
539
+ // v2 context
540
+ dgs_mode: ctx.dgs_mode,
541
+ current_project: ctx.current_project,
542
+ project_root: ctx.root,
543
+ guard: ctx.guard,
544
+ v2_hint: ctx.v2_hint || null,
545
+ };
546
+
547
+ output(result, raw);
548
+ }
549
+
550
+ function cmdInitVerifyWork(cwd, phase, raw) {
551
+ if (!phase) {
552
+ error('phase required for init verify-work');
553
+ }
554
+
555
+ const config = loadConfig(cwd);
556
+ const ctx = resolveProjectContext(cwd);
557
+ const phaseInfo = findPhaseInternal(cwd, phase);
558
+
559
+ const result = {
560
+ // Models
561
+ planner_model: resolveModelInternal(cwd, 'dgs-planner'),
562
+ checker_model: resolveModelInternal(cwd, 'dgs-plan-checker'),
563
+
564
+ // Config
565
+ commit_docs: config.commit_docs,
566
+
567
+ // Phase info
568
+ phase_found: !!phaseInfo,
569
+ phase_dir: phaseInfo?.directory || null,
570
+ phase_number: phaseInfo?.phase_number || null,
571
+ phase_name: phaseInfo?.phase_name || null,
572
+
573
+ // Existing artifacts
574
+ has_verification: phaseInfo?.has_verification || false,
575
+
576
+ // Author
577
+ author: resolveAuthorSafe(cwd),
578
+
579
+ // v2 context
580
+ dgs_mode: ctx.dgs_mode,
581
+ current_project: ctx.current_project,
582
+ project_root: ctx.root,
583
+ guard: ctx.guard,
584
+ };
585
+
586
+ output(result, raw);
587
+ }
588
+
589
+ function cmdInitAuditPhase(cwd, phase, raw) {
590
+ if (!phase) {
591
+ error('phase required for init audit-phase');
592
+ }
593
+
594
+ const config = loadConfig(cwd);
595
+ const ctx = resolveProjectContext(cwd);
596
+ const phaseInfo = findPhaseInternal(cwd, phase);
597
+
598
+ const result = {
599
+ // Models
600
+ planner_model: resolveModelInternal(cwd, 'dgs-planner'),
601
+ checker_model: resolveModelInternal(cwd, 'dgs-plan-checker'),
602
+
603
+ // Config
604
+ commit_docs: config.commit_docs,
605
+
606
+ // Phase info
607
+ phase_found: !!phaseInfo,
608
+ phase_dir: phaseInfo?.directory || null,
609
+ phase_number: phaseInfo?.phase_number || null,
610
+ phase_name: phaseInfo?.phase_name || null,
611
+
612
+ // Existing artifacts
613
+ has_verification: phaseInfo?.has_verification || false,
614
+
615
+ // Author
616
+ author: resolveAuthorSafe(cwd),
617
+
618
+ // v2 context
619
+ dgs_mode: ctx.dgs_mode,
620
+ current_project: ctx.current_project,
621
+ project_root: ctx.root,
622
+ guard: ctx.guard,
623
+ };
624
+
625
+ output(result, raw);
626
+ }
627
+
628
+ function cmdInitPhaseOp(cwd, phase, raw) {
629
+ const config = loadConfig(cwd);
630
+ const ctx = resolveProjectContext(cwd);
631
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
632
+ let phaseInfo = findPhaseInternal(cwd, phase);
633
+
634
+ // Fallback to ROADMAP.md if no directory exists (e.g., Plans: TBD)
635
+ if (!phaseInfo) {
636
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
637
+ if (roadmapPhase?.found) {
638
+ const phaseName = roadmapPhase.phase_name;
639
+ phaseInfo = {
640
+ found: true,
641
+ directory: null,
642
+ phase_number: roadmapPhase.phase_number,
643
+ phase_name: phaseName,
644
+ phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
645
+ plans: [],
646
+ summaries: [],
647
+ incomplete_plans: [],
648
+ has_research: false,
649
+ has_context: false,
650
+ has_verification: false,
651
+ };
652
+ }
653
+ }
654
+
655
+ const result = {
656
+ // Config
657
+ commit_docs: config.commit_docs,
658
+ brave_search: config.brave_search,
659
+
660
+ // Phase info
661
+ phase_found: !!phaseInfo,
662
+ phase_dir: phaseInfo?.directory || null,
663
+ phase_number: phaseInfo?.phase_number || null,
664
+ phase_name: phaseInfo?.phase_name || null,
665
+ phase_slug: phaseInfo?.phase_slug || null,
666
+ padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
667
+
668
+ // Existing artifacts
669
+ has_research: phaseInfo?.has_research || false,
670
+ has_context: phaseInfo?.has_context || false,
671
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
672
+ has_verification: phaseInfo?.has_verification || false,
673
+ plan_count: phaseInfo?.plans?.length || 0,
674
+
675
+ // File existence (project-qualified)
676
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'ROADMAP.md')),
677
+ planning_exists: pathExistsInternal(cwd, planRootRel),
678
+
679
+ // File paths (project-qualified)
680
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
681
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
682
+ requirements_path: ctx.root ? path.join(ctx.root, 'REQUIREMENTS.md') : path.join(planRootRel, 'REQUIREMENTS.md'),
683
+ project_path: ctx.root ? path.join(ctx.root, 'PROJECT.md') : path.join(planRootRel, 'PROJECT.md'),
684
+ phases_dir: ctx.root ? path.join(ctx.root, 'phases') : path.join(planRootRel, 'phases'),
685
+
686
+ // Author
687
+ author: resolveAuthorSafe(cwd),
688
+
689
+ // v2 context
690
+ dgs_mode: ctx.dgs_mode,
691
+ current_project: ctx.current_project,
692
+ project_root: ctx.root,
693
+ guard: ctx.guard,
694
+ v2_hint: ctx.v2_hint || null,
695
+ };
696
+
697
+ if (phaseInfo?.directory) {
698
+ const phaseDirFull = path.join(cwd, phaseInfo.directory);
699
+ try {
700
+ const files = fs.readdirSync(phaseDirFull);
701
+ const contextFile = files.find(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
702
+ if (contextFile) {
703
+ result.context_path = toPosixPath(path.join(phaseInfo.directory, contextFile));
704
+ }
705
+ const researchFile = files.find(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
706
+ if (researchFile) {
707
+ result.research_path = toPosixPath(path.join(phaseInfo.directory, researchFile));
708
+ }
709
+ const verificationFile = files.find(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
710
+ if (verificationFile) {
711
+ result.verification_path = toPosixPath(path.join(phaseInfo.directory, verificationFile));
712
+ }
713
+ const uatFile = files.find(f => f.endsWith('-UAT.md') || f === 'UAT.md');
714
+ if (uatFile) {
715
+ result.uat_path = toPosixPath(path.join(phaseInfo.directory, uatFile));
716
+ }
717
+ } catch {}
718
+ }
719
+
720
+ output(result, raw);
721
+ }
722
+
723
+ function cmdInitTodos(cwd, area, raw) {
724
+ const config = loadConfig(cwd);
725
+ const ctx = resolveProjectContext(cwd);
726
+ const now = new Date();
727
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
728
+
729
+ // List todos (reuse existing logic) — project-qualified
730
+ const pendingBase = path.join(planRootRel, 'todos', 'pending');
731
+ const pendingDir = path.join(cwd, pendingBase);
732
+ let count = 0;
733
+ const todos = [];
734
+
735
+ try {
736
+ const files = fs.readdirSync(pendingDir).filter(f => f.endsWith('.md'));
737
+ for (const file of files) {
738
+ try {
739
+ const content = fs.readFileSync(path.join(pendingDir, file), 'utf-8');
740
+ const createdMatch = content.match(/^created:\s*(.+)$/m);
741
+ const titleMatch = content.match(/^title:\s*(.+)$/m);
742
+ const areaMatch = content.match(/^area:\s*(.+)$/m);
743
+ const todoArea = areaMatch ? areaMatch[1].trim() : 'general';
744
+
745
+ if (area && todoArea !== area) continue;
746
+
747
+ count++;
748
+ todos.push({
749
+ file,
750
+ created: createdMatch ? createdMatch[1].trim() : 'unknown',
751
+ title: titleMatch ? titleMatch[1].trim() : 'Untitled',
752
+ area: todoArea,
753
+ path: pendingBase + '/' + file,
754
+ });
755
+ } catch {}
756
+ }
757
+ } catch {}
758
+
759
+ const completedBase = path.join(planRootRel, 'todos', 'completed');
760
+ const todosBase = path.join(planRootRel, 'todos');
761
+
762
+ const result = {
763
+ // Config
764
+ commit_docs: config.commit_docs,
765
+
766
+ // Timestamps
767
+ date: now.toISOString().split('T')[0],
768
+ timestamp: now.toISOString(),
769
+
770
+ // Todo inventory
771
+ todo_count: count,
772
+ todos,
773
+ area_filter: area || null,
774
+
775
+ // Paths (project-qualified)
776
+ pending_dir: pendingBase,
777
+ completed_dir: completedBase,
778
+
779
+ // File existence
780
+ planning_exists: pathExistsInternal(cwd, planRootRel),
781
+ todos_dir_exists: pathExistsInternal(cwd, todosBase),
782
+ pending_dir_exists: pathExistsInternal(cwd, pendingBase),
783
+
784
+ // Author
785
+ author: resolveAuthorSafe(cwd),
786
+
787
+ // v2 context
788
+ dgs_mode: ctx.dgs_mode,
789
+ current_project: ctx.current_project,
790
+ project_root: ctx.root,
791
+ guard: ctx.guard,
792
+ v2_hint: ctx.v2_hint || null,
793
+ };
794
+
795
+ output(result, raw);
796
+ }
797
+
798
+ function cmdInitMilestoneOp(cwd, raw) {
799
+ const config = loadConfig(cwd);
800
+ const ctx = resolveProjectContext(cwd);
801
+ const milestone = getMilestoneInfo(cwd);
802
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
803
+
804
+ // Count phases (project-qualified)
805
+ let phaseCount = 0;
806
+ let completedPhases = 0;
807
+ const phasesBase = ctx.root ? path.join(ctx.root, 'phases') : path.join(planRootRel, 'phases');
808
+ const phasesDir = path.join(cwd, phasesBase);
809
+ try {
810
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
811
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
812
+ phaseCount = dirs.length;
813
+
814
+ // Count phases with summaries (completed)
815
+ for (const dir of dirs) {
816
+ try {
817
+ const phaseFiles = fs.readdirSync(path.join(phasesDir, dir));
818
+ const hasSummary = phaseFiles.some(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
819
+ if (hasSummary) completedPhases++;
820
+ } catch {}
821
+ }
822
+ } catch {}
823
+
824
+ // Check archive (project-qualified)
825
+ const archiveBase = ctx.root ? path.join(ctx.root, 'archive') : path.join(planRootRel, 'archive');
826
+ const archiveDir = path.join(cwd, archiveBase);
827
+ let archivedMilestones = [];
828
+ try {
829
+ archivedMilestones = fs.readdirSync(archiveDir, { withFileTypes: true })
830
+ .filter(e => e.isDirectory())
831
+ .map(e => e.name);
832
+ } catch {}
833
+
834
+ const result = {
835
+ // Config
836
+ commit_docs: config.commit_docs,
837
+ base_branch: config.base_branch,
838
+ branching_strategy: config.branching_strategy,
839
+ phase_branch_template: config.phase_branch_template,
840
+ milestone_branch_template: config.milestone_branch_template,
841
+
842
+ // Current milestone
843
+ milestone_version: milestone.version,
844
+ milestone_name: milestone.name,
845
+ milestone_slug: generateSlugInternal(milestone.name),
846
+
847
+ // Phase counts
848
+ phase_count: phaseCount,
849
+ completed_phases: completedPhases,
850
+ all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
851
+
852
+ // Archive
853
+ archived_milestones: archivedMilestones,
854
+ archive_count: archivedMilestones.length,
855
+
856
+ // File existence (project-qualified)
857
+ project_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'PROJECT.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'PROJECT.md')),
858
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'ROADMAP.md')),
859
+ state_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'STATE.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'STATE.md')),
860
+ archive_exists: pathExistsInternal(cwd, archiveBase),
861
+ phases_dir_exists: pathExistsInternal(cwd, phasesBase),
862
+
863
+ // File paths (project-qualified)
864
+ project_path: ctx.root ? path.join(ctx.root, 'PROJECT.md') : path.join(planRootRel, 'PROJECT.md'),
865
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
866
+ state_path: ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md'),
867
+ requirements_path: ctx.root ? path.join(ctx.root, 'REQUIREMENTS.md') : path.join(planRootRel, 'REQUIREMENTS.md'),
868
+ phases_dir: phasesBase,
869
+ archive_dir: archiveBase,
870
+ jobs_root: path.join(planRootRel, 'jobs'),
871
+
872
+ // Author
873
+ author: resolveAuthorSafe(cwd),
874
+
875
+ // v2 context
876
+ dgs_mode: ctx.dgs_mode,
877
+ current_project: ctx.current_project,
878
+ project_root: ctx.root,
879
+ guard: ctx.guard,
880
+ v2_hint: ctx.v2_hint || null,
881
+ };
882
+
883
+ output(result, raw);
884
+ }
885
+
886
+ function cmdInitMapCodebase(cwd, onlyRepo, raw) {
887
+ const config = loadConfig(cwd);
888
+ const ctx = resolveProjectContext(cwd);
889
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
890
+
891
+ // Check for existing codebase maps — codebase is product-level (shared), NOT project-qualified
892
+ const codebaseDir = path.join(getPlanningRoot(cwd), 'codebase');
893
+ let existingMaps = [];
894
+ try {
895
+ existingMaps = fs.readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
896
+ } catch {}
897
+
898
+ // ── Multi-repo: read and validate REPOS.md ──
899
+ const parsed = parseReposMd(cwd);
900
+ const validated = validateReposMdEager(cwd);
901
+
902
+ // Filter out planning repo (cwd itself) from valid repos
903
+ const resolvedCwd = path.resolve(cwd);
904
+ const allValidRepos = (validated.repos || []).filter(repo => {
905
+ const resolvedRepoPath = path.resolve(cwd, repo.path);
906
+ return resolvedRepoPath !== resolvedCwd;
907
+ });
908
+
909
+ const repoErrors = validated.errors || [];
910
+
911
+ // ── --only flag: validate and filter ──
912
+ let validRepos = allValidRepos;
913
+ let mode = 'refresh';
914
+ let only_repo = null;
915
+
916
+ if (onlyRepo) {
917
+ const matched = allValidRepos.find(r => r.name === onlyRepo);
918
+ if (!matched) {
919
+ error(`'${onlyRepo}' not found in REPOS.md. Available repos: ${allValidRepos.map(r => r.name).join(', ')}`);
920
+ }
921
+ validRepos = [matched];
922
+ mode = 'update';
923
+ only_repo = onlyRepo;
924
+ }
925
+
926
+ // Detect existing per-repo maps in codebase/<repo-name>/ subdirectories
927
+ const existingRepoMaps = {};
928
+ for (const repo of validRepos) {
929
+ const repoCodebaseDir = path.join(codebaseDir, repo.name);
930
+ try {
931
+ const maps = fs.readdirSync(repoCodebaseDir).filter(f => f.endsWith('.md'));
932
+ if (maps.length > 0) {
933
+ existingRepoMaps[repo.name] = maps;
934
+ }
935
+ } catch {}
936
+ }
937
+
938
+ const result = {
939
+ // Models
940
+ mapper_model: resolveModelInternal(cwd, 'dgs-codebase-mapper'),
941
+
942
+ // Config
943
+ commit_docs: config.commit_docs,
944
+ search_gitignored: config.search_gitignored,
945
+ parallelization: config.parallelization,
946
+
947
+ // Paths — codebase stays product-level
948
+ codebase_dir: path.join(planRootRel, 'codebase'),
949
+
950
+ // Existing maps (backward compat: flat top-level maps)
951
+ existing_maps: existingMaps,
952
+ has_maps: existingMaps.length > 0,
953
+
954
+ // File existence
955
+ planning_exists: pathExistsInternal(cwd, planRootRel),
956
+ codebase_dir_exists: pathExistsInternal(cwd, path.join(planRootRel, 'codebase')),
957
+
958
+ // ── Multi-repo fields ──
959
+ repos: validRepos.map(r => ({
960
+ name: r.name,
961
+ path: path.resolve(cwd, r.path),
962
+ url: r.url || '',
963
+ description: r.description || '',
964
+ })),
965
+ multi_repo: validRepos.length > 0,
966
+ valid_repos: validRepos.map(r => r.name),
967
+ repo_errors: repoErrors,
968
+ existing_repo_maps: existingRepoMaps,
969
+
970
+ // ── Mode fields ──
971
+ mode: mode,
972
+ only_repo: only_repo,
973
+
974
+ // Author
975
+ author: resolveAuthorSafe(cwd),
976
+
977
+ // v2 context
978
+ dgs_mode: ctx.dgs_mode,
979
+ current_project: ctx.current_project,
980
+ project_root: ctx.root,
981
+ guard: ctx.guard,
982
+ v2_hint: ctx.v2_hint || null,
983
+ };
984
+
985
+ output(result, raw);
986
+ }
987
+
988
+ function cmdInitProgress(cwd, raw) {
989
+ const config = loadConfig(cwd);
990
+ const ctx = resolveProjectContext(cwd);
991
+ const milestone = getMilestoneInfo(cwd);
992
+ const planRootRel = path.relative(cwd, getPlanningRoot(cwd)) || '.';
993
+
994
+ // Analyze phases (project-qualified)
995
+ const phasesBase = ctx.root ? path.join(ctx.root, 'phases') : path.join(planRootRel, 'phases');
996
+ const phasesDir = path.join(cwd, phasesBase);
997
+ const phases = [];
998
+ let currentPhase = null;
999
+ let nextPhase = null;
1000
+
1001
+ try {
1002
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
1003
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
1004
+
1005
+ for (const dir of dirs) {
1006
+ const match = dir.match(/^(\d+(?:\.\d+)*)-?(.*)/);
1007
+ const phaseNumber = match ? match[1] : dir;
1008
+ const phaseName = match && match[2] ? match[2] : null;
1009
+
1010
+ const phasePath = path.join(phasesDir, dir);
1011
+ const phaseFiles = fs.readdirSync(phasePath);
1012
+
1013
+ const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
1014
+ const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
1015
+ const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
1016
+
1017
+ const status = summaries.length >= plans.length && plans.length > 0 ? 'complete' :
1018
+ plans.length > 0 ? 'in_progress' :
1019
+ hasResearch ? 'researched' : 'pending';
1020
+
1021
+ const phaseInfo = {
1022
+ number: phaseNumber,
1023
+ name: phaseName,
1024
+ directory: phasesBase + '/' + dir,
1025
+ status,
1026
+ plan_count: plans.length,
1027
+ summary_count: summaries.length,
1028
+ has_research: hasResearch,
1029
+ };
1030
+
1031
+ phases.push(phaseInfo);
1032
+
1033
+ // Find current (first incomplete with plans) and next (first pending)
1034
+ if (!currentPhase && (status === 'in_progress' || status === 'researched')) {
1035
+ currentPhase = phaseInfo;
1036
+ }
1037
+ if (!nextPhase && status === 'pending') {
1038
+ nextPhase = phaseInfo;
1039
+ }
1040
+ }
1041
+ } catch {}
1042
+
1043
+ // Check for paused work (project-qualified)
1044
+ let pausedAt = null;
1045
+ const statePath = ctx.root ? path.join(ctx.root, 'STATE.md') : path.join(planRootRel, 'STATE.md');
1046
+ try {
1047
+ const state = fs.readFileSync(path.join(cwd, statePath), 'utf-8');
1048
+ const pauseMatch = state.match(/\*\*Paused At:\*\*\s*(.+)/);
1049
+ if (pauseMatch) pausedAt = pauseMatch[1].trim();
1050
+ } catch {}
1051
+
1052
+ const result = {
1053
+ // Models
1054
+ executor_model: resolveModelInternal(cwd, 'dgs-executor'),
1055
+ planner_model: resolveModelInternal(cwd, 'dgs-planner'),
1056
+
1057
+ // Config
1058
+ commit_docs: config.commit_docs,
1059
+
1060
+ // Milestone
1061
+ milestone_version: milestone.version,
1062
+ milestone_name: milestone.name,
1063
+
1064
+ // Phase overview
1065
+ phases,
1066
+ phase_count: phases.length,
1067
+ completed_count: phases.filter(p => p.status === 'complete').length,
1068
+ in_progress_count: phases.filter(p => p.status === 'in_progress').length,
1069
+
1070
+ // Current state
1071
+ current_phase: currentPhase,
1072
+ next_phase: nextPhase,
1073
+ paused_at: pausedAt,
1074
+ has_work_in_progress: !!currentPhase,
1075
+
1076
+ // File existence (project-qualified)
1077
+ project_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'PROJECT.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'PROJECT.md')),
1078
+ roadmap_exists: ctx.root ? pathExistsInternal(cwd, path.join(ctx.root, 'ROADMAP.md')) : pathExistsInternal(cwd, path.join(planRootRel, 'ROADMAP.md')),
1079
+ state_exists: pathExistsInternal(cwd, statePath),
1080
+ // File paths (project-qualified; config stays product-level)
1081
+ state_path: statePath,
1082
+ roadmap_path: ctx.root ? path.join(ctx.root, 'ROADMAP.md') : path.join(planRootRel, 'ROADMAP.md'),
1083
+ project_path: ctx.root ? path.join(ctx.root, 'PROJECT.md') : path.join(planRootRel, 'PROJECT.md'),
1084
+ config_path: path.join(planRootRel, 'dgs.config.json'),
1085
+
1086
+ // Author
1087
+ author: resolveAuthorSafe(cwd),
1088
+
1089
+ // v2 context
1090
+ dgs_mode: ctx.dgs_mode,
1091
+ current_project: ctx.current_project,
1092
+ project_root: ctx.root,
1093
+ guard: ctx.guard,
1094
+ v2_hint: ctx.v2_hint || null,
1095
+ };
1096
+
1097
+ output(result, raw);
1098
+ }
1099
+
1100
+ module.exports = {
1101
+ cmdInitExecutePhase,
1102
+ cmdInitPlanPhase,
1103
+ cmdInitNewProject,
1104
+ cmdInitNewMilestone,
1105
+ cmdInitQuick,
1106
+ cmdInitResume,
1107
+ cmdInitVerifyWork,
1108
+ cmdInitAuditPhase,
1109
+ cmdInitPhaseOp,
1110
+ cmdInitTodos,
1111
+ cmdInitMilestoneOp,
1112
+ cmdInitMapCodebase,
1113
+ cmdInitProgress,
1114
+ };