@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,352 @@
1
+ /**
2
+ * Migration — v1-to-v2 file structure migration
3
+ *
4
+ * Detects v1 DGS installs (single project at .planning/ root) and migrates
5
+ * them to v2 multi-project structure (.planning/projects/<slug>/) using git mv
6
+ * for history preservation.
7
+ *
8
+ * Entry point: cmdReposInitProduct detects v1 and offers migration.
9
+ * The workflow handles the user prompt; this module handles the moves.
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const { safeReadFile, execGit, isV2Install, generateSlugInternal, output, error } = require('./core.cjs');
15
+ const { writeReposMd } = require('./repos.cjs');
16
+ const { regenerateProjectsMd } = require('./projects.cjs');
17
+ const { writeConfigField } = require('./config.cjs');
18
+ const { getPlanningRoot, PROJECTS_DIR } = require('./paths.cjs');
19
+
20
+ // ─── v1 Detection ────────────────────────────────────────────────────────────
21
+
22
+ /**
23
+ * Detect whether cwd is a v1 DGS install.
24
+ *
25
+ * v1 marker: .planning/PROJECT.md exists at root WITHOUT PROJECTS.md or REPOS.md.
26
+ * If v1 detected, extracts project name from heading and generates slug.
27
+ *
28
+ * @param {string} cwd - Working directory
29
+ * @returns {{ isV1: boolean, projectName?: string, slug?: string }}
30
+ */
31
+ function detectV1Install(cwd) {
32
+ // v1 always uses .planning/ — intentionally hardcoded for v1 source detection
33
+ const projectMdPath = path.join(cwd, '.planning', 'PROJECT.md');
34
+ const projectsMdPath = path.join(cwd, '.planning', 'PROJECTS.md');
35
+ const reposMdPath = path.join(cwd, '.planning', 'REPOS.md');
36
+
37
+ // Check if PROJECT.md exists
38
+ const projectContent = safeReadFile(projectMdPath);
39
+ if (!projectContent) {
40
+ return { isV1: false };
41
+ }
42
+
43
+ // Check v2 markers — if either exists, it's already v2 (or partially migrated)
44
+ const projectsMdContent = safeReadFile(projectsMdPath);
45
+ if (projectsMdContent && projectsMdContent.startsWith('# Projects')) {
46
+ return { isV1: false };
47
+ }
48
+
49
+ const reposMdContent = safeReadFile(reposMdPath);
50
+ if (reposMdContent && reposMdContent.startsWith('# Repos')) {
51
+ return { isV1: false };
52
+ }
53
+
54
+ // It's v1 — extract project name from heading
55
+ let projectName = null;
56
+
57
+ // Try "# Project: Name" format first
58
+ const colonMatch = projectContent.match(/^#\s+Project:\s+(.+)$/m);
59
+ if (colonMatch) {
60
+ projectName = colonMatch[1].trim();
61
+ }
62
+
63
+ // Try "# Project Name" format (no colon)
64
+ if (!projectName) {
65
+ const headingMatch = projectContent.match(/^#\s+(.+)$/m);
66
+ if (headingMatch) {
67
+ projectName = headingMatch[1].trim();
68
+ }
69
+ }
70
+
71
+ // Fall back to directory name
72
+ if (!projectName) {
73
+ projectName = path.basename(cwd);
74
+ }
75
+
76
+ const slug = generateSlugInternal(projectName) || path.basename(cwd).toLowerCase().replace(/[^a-z0-9]+/g, '-');
77
+
78
+ return { isV1: true, projectName, slug };
79
+ }
80
+
81
+ // ─── Precondition Validation ─────────────────────────────────────────────────
82
+
83
+ /**
84
+ * Validate that migration can proceed.
85
+ *
86
+ * Checks:
87
+ * 1. Not already a v2 install
88
+ * 2. .planning/PROJECT.md exists (v1 marker)
89
+ * 3. Git working tree is clean (no uncommitted changes)
90
+ *
91
+ * @param {string} cwd - Working directory
92
+ * @returns {{ valid: boolean, reason?: string }}
93
+ */
94
+ function validateMigrationPreconditions(cwd) {
95
+ // Check if already v2
96
+ if (isV2Install(cwd)) {
97
+ return { valid: false, reason: 'Already a v2 install. Migration not needed.' };
98
+ }
99
+
100
+ // Check if v1 marker exists — v1 always uses .planning/
101
+ const projectMdPath = path.join(cwd, '.planning', 'PROJECT.md');
102
+ if (!safeReadFile(projectMdPath)) {
103
+ return { valid: false, reason: 'No .planning/PROJECT.md found. Not a v1 install.' };
104
+ }
105
+
106
+ // Check git working tree is clean
107
+ const gitStatus = execGit(cwd, ['status', '--porcelain']);
108
+ if (gitStatus.exitCode !== 0) {
109
+ return { valid: false, reason: 'Not a git repository or git command failed.' };
110
+ }
111
+ if (gitStatus.stdout.trim().length > 0) {
112
+ return { valid: false, reason: 'Working tree has uncommitted changes. Please commit or stash before migration.' };
113
+ }
114
+
115
+ return { valid: true };
116
+ }
117
+
118
+ // ─── Backup Tag ──────────────────────────────────────────────────────────────
119
+
120
+ /**
121
+ * Create a pre-migration backup tag for safe rollback.
122
+ *
123
+ * @param {string} cwd - Working directory
124
+ * @returns {{ tagged: boolean, reason?: string }}
125
+ */
126
+ function createBackupTag(cwd) {
127
+ const result = execGit(cwd, ['tag', 'dgs-pre-v2-migration']);
128
+ if (result.exitCode !== 0) {
129
+ // Check if tag already exists or no git
130
+ if (result.stderr.includes('already exists')) {
131
+ return { tagged: false, reason: 'Tag dgs-pre-v2-migration already exists.' };
132
+ }
133
+ return { tagged: false, reason: result.stderr || 'Failed to create tag.' };
134
+ }
135
+ return { tagged: true };
136
+ }
137
+
138
+ // ─── Migration Planning ─────────────────────────────────────────────────────
139
+
140
+ // Directories to move (project-level, order: directories first)
141
+ const DIRS_TO_MOVE = ['phases', 'research', 'todos', 'quick', 'debug'];
142
+
143
+ // Files to move (project-level)
144
+ const FILES_TO_MOVE = ['PROJECT.md', 'REQUIREMENTS.md', 'ROADMAP.md', 'STATE.md'];
145
+
146
+ /**
147
+ * Collect all migration move operations as a plan (pure computation, no side effects).
148
+ *
149
+ * Returns an array of { relSource, relTarget, isDir } for all items that exist
150
+ * and need moving. Directories are listed before files to maximize git rename detection.
151
+ *
152
+ * @param {string} cwd - Working directory
153
+ * @param {string} slug - Project slug for subfolder name
154
+ * @returns {{ moves: Array<{relSource: string, relTarget: string, isDir: boolean}>, targetDir: string }}
155
+ */
156
+ function collectMigrationMoves(cwd, slug) {
157
+ // v1 always uses .planning/ — migration source is always the .planning directory
158
+ const planningDir = path.join(cwd, '.planning');
159
+ const targetDir = path.join(planningDir, PROJECTS_DIR, slug);
160
+ const moves = [];
161
+
162
+ // Directories first
163
+ for (const dir of DIRS_TO_MOVE) {
164
+ const sourcePath = path.join(planningDir, dir);
165
+ if (fs.existsSync(sourcePath)) {
166
+ moves.push({
167
+ relSource: path.join('.planning', dir),
168
+ relTarget: path.join('.planning', PROJECTS_DIR, slug, dir),
169
+ isDir: true,
170
+ });
171
+ }
172
+ }
173
+
174
+ // Then files
175
+ for (const file of FILES_TO_MOVE) {
176
+ const sourcePath = path.join(planningDir, file);
177
+ if (fs.existsSync(sourcePath)) {
178
+ moves.push({
179
+ relSource: path.join('.planning', file),
180
+ relTarget: path.join('.planning', PROJECTS_DIR, slug, file),
181
+ isDir: false,
182
+ });
183
+ }
184
+ }
185
+
186
+ return { moves, targetDir };
187
+ }
188
+
189
+ /**
190
+ * Validate that all planned moves can succeed.
191
+ *
192
+ * Checks:
193
+ * - Each source exists on disk
194
+ * - Each target does NOT already exist (would cause git mv to fail)
195
+ *
196
+ * @param {string} cwd - Working directory
197
+ * @param {Array<{relSource: string, relTarget: string, isDir: boolean}>} moves - Planned moves
198
+ * @returns {{ valid: boolean, errors: string[] }}
199
+ */
200
+ function validateMoves(cwd, moves) {
201
+ const errors = [];
202
+
203
+ for (const move of moves) {
204
+ const absSource = path.join(cwd, move.relSource);
205
+ if (!fs.existsSync(absSource)) {
206
+ errors.push('Source does not exist: ' + move.relSource);
207
+ }
208
+
209
+ const absTarget = path.join(cwd, move.relTarget);
210
+ if (fs.existsSync(absTarget)) {
211
+ errors.push('Target already exists: ' + move.relTarget);
212
+ }
213
+ }
214
+
215
+ return { valid: errors.length === 0, errors };
216
+ }
217
+
218
+ // ─── Core Migration ──────────────────────────────────────────────────────────
219
+
220
+ /**
221
+ * Perform the v1-to-v2 migration.
222
+ *
223
+ * Uses a dry-run-then-execute pattern:
224
+ * 1. Collect planned moves (collectMigrationMoves)
225
+ * 2. Validate all moves can succeed (validateMoves)
226
+ * 3. Execute moves with rollback on failure
227
+ * 4. Commit with diff.renameLimit=1000 for large projects
228
+ * 5. Create v2 marker files in a separate commit
229
+ *
230
+ * @param {string} cwd - Working directory
231
+ * @param {string} slug - Project slug for subfolder name
232
+ * @returns {{ migrated: boolean, slug: string, files_moved: string[], repos_created: boolean, project_created: boolean, error?: string, rollback?: boolean }}
233
+ */
234
+ function migrateV1ToV2(cwd, slug) {
235
+ // v1 always uses .planning/ — migration operates on the .planning directory
236
+ const planningDir = path.join(cwd, '.planning');
237
+
238
+ // Step 1: Collect planned moves
239
+ const { moves, targetDir } = collectMigrationMoves(cwd, slug);
240
+
241
+ // Create the target project directory (needed before validation and git mv)
242
+ fs.mkdirSync(targetDir, { recursive: true });
243
+
244
+ // Step 2: Validate all moves
245
+ const validation = validateMoves(cwd, moves);
246
+ if (!validation.valid) {
247
+ // Clean up created target directory
248
+ try { fs.rmdirSync(targetDir); } catch (_e) { /* ignore */ }
249
+ return {
250
+ migrated: false,
251
+ slug,
252
+ files_moved: [],
253
+ repos_created: false,
254
+ project_created: false,
255
+ error: 'Validation failed: ' + validation.errors.join('; '),
256
+ };
257
+ }
258
+
259
+ // Step 3: Execute moves with rollback on failure
260
+ const filesMoved = [];
261
+
262
+ try {
263
+ for (const move of moves) {
264
+ const result = execGit(cwd, ['mv', move.relSource, move.relTarget]);
265
+ if (result.exitCode !== 0) {
266
+ throw new Error('git mv failed for ' + move.relSource + ': ' + result.stderr);
267
+ }
268
+ filesMoved.push(move.isDir ? path.basename(move.relSource) + '/' : path.basename(move.relSource));
269
+ }
270
+ } catch (err) {
271
+ // Rollback: restore all files to pre-move state
272
+ execGit(cwd, ['checkout', 'HEAD', '--', '.']);
273
+ execGit(cwd, ['clean', '-fd', path.join('.planning', PROJECTS_DIR, slug)]);
274
+ return {
275
+ migrated: false,
276
+ slug,
277
+ files_moved: [],
278
+ repos_created: false,
279
+ project_created: false,
280
+ error: 'Migration failed: ' + err.message,
281
+ rollback: true,
282
+ };
283
+ }
284
+
285
+ // Step 4: Commit the moves (git mv already stages files, no git add -A needed)
286
+ // Use diff.renameLimit=1000 to handle projects with many files
287
+ execGit(cwd, ['-c', 'diff.renameLimit=1000', 'commit', '-m', 'chore: migrate to DGS v2 multi-project structure']);
288
+
289
+ // Step 5: Post-migration setup — Create REPOS.md
290
+ const dirName = path.basename(cwd);
291
+ writeReposMd(cwd, [{ name: dirName, path: '.', url: '', description: '' }]);
292
+
293
+ // Post-migration setup: Set current_project in config.json
294
+ writeConfigField(cwd, 'current_project', slug);
295
+
296
+ // Post-migration setup: Create PROJECTS.md from migrated project state
297
+ regenerateProjectsMd(cwd);
298
+
299
+ // Commit post-migration setup (new files need git add -A)
300
+ execGit(cwd, ['add', '-A']);
301
+ execGit(cwd, ['commit', '-m', 'chore: create v2 marker files after migration']);
302
+
303
+ return {
304
+ migrated: true,
305
+ slug,
306
+ files_moved: filesMoved,
307
+ repos_created: true,
308
+ project_created: true,
309
+ };
310
+ }
311
+
312
+ // ─── CLI Command ─────────────────────────────────────────────────────────────
313
+
314
+ /**
315
+ * CLI entry point for migration.
316
+ * Called from repos migrate <slug> routing.
317
+ *
318
+ * @param {string} cwd - Working directory
319
+ * @param {string} slug - Project slug
320
+ * @param {boolean} raw - Raw output mode
321
+ */
322
+ function cmdMigrateV1ToV2(cwd, slug, raw) {
323
+ // Validate preconditions
324
+ const preconditions = validateMigrationPreconditions(cwd);
325
+ if (!preconditions.valid) {
326
+ error(preconditions.reason);
327
+ }
328
+
329
+ // Create backup tag
330
+ const tag = createBackupTag(cwd);
331
+
332
+ // Perform migration
333
+ const result = migrateV1ToV2(cwd, slug);
334
+
335
+ output({
336
+ ...result,
337
+ backup_tag: tag.tagged ? 'dgs-pre-v2-migration' : null,
338
+ backup_tag_note: tag.tagged ? null : tag.reason,
339
+ }, raw);
340
+ }
341
+
342
+ // ─── Exports ────────────────────────────────────────────────────────────────
343
+
344
+ module.exports = {
345
+ detectV1Install,
346
+ validateMigrationPreconditions,
347
+ createBackupTag,
348
+ collectMigrationMoves,
349
+ validateMoves,
350
+ migrateV1ToV2,
351
+ cmdMigrateV1ToV2,
352
+ };