@ktpartners/dgs-platform 2.8.0 → 3.0.4

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 (94) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +41 -13
  3. package/agents/dgs-plan-checker.md +29 -3
  4. package/agents/dgs-planner.md +10 -0
  5. package/commands/dgs/abandon-quick.md +28 -0
  6. package/commands/dgs/add-tests.md +2 -2
  7. package/commands/dgs/audit-milestone.md +2 -2
  8. package/commands/dgs/capture-principle.md +11 -11
  9. package/commands/dgs/cleanup.md +2 -2
  10. package/commands/dgs/complete-milestone.md +11 -11
  11. package/commands/dgs/complete-quick.md +28 -0
  12. package/commands/dgs/create-milestone-job.md +2 -2
  13. package/commands/dgs/debug.md +3 -3
  14. package/commands/dgs/develop-idea.md +1 -1
  15. package/commands/dgs/fast.md +3 -1
  16. package/commands/dgs/health.md +1 -1
  17. package/commands/dgs/map-codebase.md +6 -6
  18. package/commands/dgs/new-milestone.md +5 -5
  19. package/commands/dgs/new-project.md +6 -6
  20. package/commands/dgs/plan-milestone-gaps.md +1 -1
  21. package/commands/dgs/progress.md +3 -3
  22. package/commands/dgs/quick-abandon.md +8 -0
  23. package/commands/dgs/quick-complete.md +8 -0
  24. package/commands/dgs/quick.md +10 -3
  25. package/commands/dgs/research-idea.md +2 -2
  26. package/commands/dgs/research-phase.md +3 -3
  27. package/commands/dgs/switch-project.md +1 -1
  28. package/commands/dgs/write-spec.md +3 -3
  29. package/deliver-great-systems/bin/dgs-tools.cjs +284 -30
  30. package/deliver-great-systems/bin/lib/commands.cjs +316 -31
  31. package/deliver-great-systems/bin/lib/commands.test.cjs +336 -0
  32. package/deliver-great-systems/bin/lib/config.cjs +39 -6
  33. package/deliver-great-systems/bin/lib/context.cjs +120 -0
  34. package/deliver-great-systems/bin/lib/core.cjs +28 -11
  35. package/deliver-great-systems/bin/lib/execution.cjs +49 -17
  36. package/deliver-great-systems/bin/lib/flat-migration.test.cjs +396 -0
  37. package/deliver-great-systems/bin/lib/ideas.cjs +206 -91
  38. package/deliver-great-systems/bin/lib/ideas.test.cjs +244 -1
  39. package/deliver-great-systems/bin/lib/init.cjs +306 -39
  40. package/deliver-great-systems/bin/lib/init.test.cjs +416 -6
  41. package/deliver-great-systems/bin/lib/jobs.cjs +124 -21
  42. package/deliver-great-systems/bin/lib/jobs.test.cjs +193 -74
  43. package/deliver-great-systems/bin/lib/migration.cjs +409 -1
  44. package/deliver-great-systems/bin/lib/migration.test.cjs +158 -1
  45. package/deliver-great-systems/bin/lib/milestone.cjs +54 -29
  46. package/deliver-great-systems/bin/lib/phase.cjs +128 -2
  47. package/deliver-great-systems/bin/lib/phase.test.cjs +420 -0
  48. package/deliver-great-systems/bin/lib/projects.cjs +28 -8
  49. package/deliver-great-systems/bin/lib/projects.test.cjs +86 -0
  50. package/deliver-great-systems/bin/lib/quick.cjs +584 -0
  51. package/deliver-great-systems/bin/lib/quick.test.cjs +596 -0
  52. package/deliver-great-systems/bin/lib/repos.cjs +25 -1
  53. package/deliver-great-systems/bin/lib/roadmap.cjs +34 -13
  54. package/deliver-great-systems/bin/lib/specs.cjs +3 -81
  55. package/deliver-great-systems/bin/lib/state-transition-gate.test.cjs +160 -0
  56. package/deliver-great-systems/bin/lib/state.cjs +142 -54
  57. package/deliver-great-systems/bin/lib/sync.cjs +75 -0
  58. package/deliver-great-systems/bin/lib/verify.cjs +80 -1
  59. package/deliver-great-systems/bin/lib/worktrees.cjs +764 -0
  60. package/deliver-great-systems/bin/lib/worktrees.test.cjs +887 -0
  61. package/deliver-great-systems/templates/claude-md.md +16 -0
  62. package/deliver-great-systems/workflows/abandon-quick.md +89 -0
  63. package/deliver-great-systems/workflows/add-idea.md +3 -3
  64. package/deliver-great-systems/workflows/add-tests.md +14 -0
  65. package/deliver-great-systems/workflows/add-todo.md +1 -0
  66. package/deliver-great-systems/workflows/approve-spec.md +25 -4
  67. package/deliver-great-systems/workflows/audit-phase.md +15 -5
  68. package/deliver-great-systems/workflows/cancel-job.md +1 -1
  69. package/deliver-great-systems/workflows/check-todos.md +2 -3
  70. package/deliver-great-systems/workflows/complete-milestone.md +197 -22
  71. package/deliver-great-systems/workflows/complete-quick.md +68 -0
  72. package/deliver-great-systems/workflows/consolidate-ideas.md +1 -1
  73. package/deliver-great-systems/workflows/create-milestone-job.md +4 -4
  74. package/deliver-great-systems/workflows/develop-idea.md +11 -11
  75. package/deliver-great-systems/workflows/diagnose-issues.md +14 -0
  76. package/deliver-great-systems/workflows/discuss-idea.md +1 -1
  77. package/deliver-great-systems/workflows/execute-phase.md +121 -32
  78. package/deliver-great-systems/workflows/execute-plan.md +12 -21
  79. package/deliver-great-systems/workflows/help.md +33 -29
  80. package/deliver-great-systems/workflows/init-product.md +2 -18
  81. package/deliver-great-systems/workflows/new-milestone.md +40 -24
  82. package/deliver-great-systems/workflows/new-project.md +22 -680
  83. package/deliver-great-systems/workflows/progress-all.md +133 -0
  84. package/deliver-great-systems/workflows/quick-abandon.md +89 -0
  85. package/deliver-great-systems/workflows/quick-complete.md +68 -0
  86. package/deliver-great-systems/workflows/quick.md +152 -23
  87. package/deliver-great-systems/workflows/refine-spec.md +1 -1
  88. package/deliver-great-systems/workflows/research-idea.md +8 -8
  89. package/deliver-great-systems/workflows/resume-project.md +2 -2
  90. package/deliver-great-systems/workflows/run-job.md +8 -8
  91. package/deliver-great-systems/workflows/validate-phase.md +39 -1
  92. package/deliver-great-systems/workflows/verify-work.md +14 -0
  93. package/deliver-great-systems/workflows/write-spec.md +2 -2
  94. package/package.json +1 -1
@@ -14,6 +14,7 @@
14
14
  * state get [section] Get STATE.md content or section
15
15
  * state patch --field val ... Batch update STATE.md fields
16
16
  * state archive-quick-tasks Archive excess quick task rows to HISTORY.md
17
+ * state mark-milestone-complete Mark milestone complete in STATE.md
17
18
  * resolve-model <agent-type> Get model for agent based on profile
18
19
  * find-phase <phase> Find phase directory by number
19
20
  * commit <message> [--files f1 f2] Commit planning docs
@@ -38,6 +39,13 @@
38
39
  * phase insert <after> <description> Insert decimal phase after existing
39
40
  * phase remove <phase> [--force] Remove phase, renumber all subsequent
40
41
  * phase complete <phase> Mark phase done, update state + roadmap
42
+ * phase finalize <phase> Mark phase done + commit tracking files + VERIFICATION.md atomically
43
+ * [--push] Push after commit (respects sync_push config)
44
+ *
45
+ * Plan Operations:
46
+ * plan finalize <phase> <plan> Update state/roadmap/requirements + commit PLAN+SUMMARY+tracking atomically
47
+ * [--push] Push after commit
48
+ * [--plan-name <name>] Override plan name in commit message
41
49
  *
42
50
  * Roadmap Operations:
43
51
  * roadmap get-phase <phase> Extract phase section from ROADMAP.md
@@ -62,6 +70,8 @@
62
70
  *
63
71
  * Todos:
64
72
  * todo complete <filename> Move todo from pending to completed
73
+ * todo set-status <filename> Set todo status (frontmatter)
74
+ * --status <pending|done>
65
75
  *
66
76
  * Scaffolding:
67
77
  * scaffold context --phase <N> Create CONTEXT.md template
@@ -72,6 +82,7 @@
72
82
  *
73
83
  * Migration:
74
84
  * migrate --layout root Migrate .planning/ to root layout
85
+ * migrate --layout flat [--apply] Migrate to flat status directories
75
86
  * [--dry-run] Show what would change without modifying
76
87
  * [--raw] JSON output for scripting
77
88
  *
@@ -182,6 +193,18 @@
182
193
  * sync workflow-push <workflow> Workflow-level push check/execute
183
194
  * [--check-only] [--mid-workflow] [--record-yes]
184
195
  *
196
+ * Worktrees:
197
+ * worktrees create <slug> Create worktrees for project repos
198
+ * --type milestone|quick
199
+ * [--mode full|debug]
200
+ * [--repo <name>]
201
+ * worktrees remove <slug> Remove worktree and clean up
202
+ * worktrees list List tracked worktrees (JSON)
203
+ * worktrees setup <slug> Re-run setup command for worktree
204
+ * worktrees prune Remove orphaned worktree entries
205
+ * worktrees rebase-and-merge <slug> --repo <name> Rebase and merge worktree branch
206
+ * worktrees health <slug> Check worktree health
207
+ *
185
208
  * Ideas Operations:
186
209
  * ideas create --title T --body B Create new idea with auto-assigned ID
187
210
  * [--tags "t1,t2"]
@@ -193,6 +216,7 @@
193
216
  * ideas reject --id N [--reason R] Reject idea (move to rejected/)
194
217
  * ideas restore --id N Restore idea to pending
195
218
  * ideas move-state --id N --to S Move idea to target state
219
+ * ideas set-status --id N --status S Set idea status (frontmatter)
196
220
  * ideas discuss-save --id N Save structured discussion entry
197
221
  * --entry '{json}' JSON: { date, keyInsights, refinedProblem, refinedApproach, openQuestions, decision }
198
222
  * ideas research-save --id N Save structured research log entry
@@ -237,6 +261,8 @@
237
261
  * [--no-check] Omit audit/complete steps
238
262
  * jobs record-start-shas <file> Record starting commit SHAs into job file
239
263
  * jobs rollback <version> Roll back code repos to pre-job SHAs
264
+ * jobs set-status <version> Set job status (frontmatter + header)
265
+ * --status <pending|in-progress|completed|failed|rolled_back>
240
266
  *
241
267
  * Search Operations:
242
268
  * search <query> [--flags] Search across ideas, specs, docs, projects
@@ -257,6 +283,7 @@
257
283
  * init milestone-op All context for milestone operations
258
284
  * init map-codebase All context for map-codebase workflow
259
285
  * init progress All context for progress workflow
286
+ * init progress-all Product-level dashboard across all active projects
260
287
  */
261
288
 
262
289
  const { error, loadConfig } = require('./lib/core.cjs');
@@ -283,7 +310,7 @@ const mergeConflicts = require('./lib/merge-conflicts.cjs');
283
310
  const conflictAgent = require('./lib/conflict-agent.cjs');
284
311
  const { requireGitIdentity, formatAuthorString, cmdIdentityResolve } = require('./lib/identity.cjs');
285
312
  const { pullAll, pushAll, getCadence, checkStaleState, shouldShowFirstRunHint, markFirstRunHintShown, isWithinSuppressionWindow, recordPromptYes } = require('./lib/sync.cjs');
286
- const { migrateDotPlanningToRoot, rejectV1Install } = require('./lib/migration.cjs');
313
+ const { migrateDotPlanningToRoot, rejectV1Install, migrateBranchingConfig, migrateFlatStatus } = require('./lib/migration.cjs');
287
314
 
288
315
  // ─── Identity Gate ────────────────────────────────────────────────────────────
289
316
 
@@ -593,6 +620,23 @@ async function main() {
593
620
  // fails for unexpected reasons (defensive, should not normally trigger).
594
621
  }
595
622
 
623
+ // Run lazy branching config migration (best-effort, non-blocking)
624
+ try {
625
+ migrateBranchingConfig(cwd);
626
+ } catch (e) {
627
+ process.stderr.write('Warning: Migration check failed: ' + (e.message || String(e)) + '\n');
628
+ }
629
+
630
+ // Run flat status migration auto-detect (best-effort, non-blocking)
631
+ // Same pattern as branching config: detect legacy layout, log if found, apply on explicit command
632
+ if (command !== 'migrate') try {
633
+ const flatResult = migrateFlatStatus(cwd);
634
+ // In auto-detect mode (dryRun=true by default), just check if migration is needed
635
+ if (flatResult.dryRun && flatResult.actions.length > 0) {
636
+ process.stderr.write('[DGS] Legacy directory-based state detected (' + flatResult.filesMoved + ' file(s) to migrate). Run: dgs-tools migrate --layout flat --apply\n');
637
+ }
638
+ } catch { /* ignore auto-detect errors */ }
639
+
596
640
  if (!command) {
597
641
  error('Usage: dgs-tools <command> [args] [--raw]\nCommands: state, resolve-model, find-phase, commit, verify-summary, verify, frontmatter, template, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, repos, projects, overlap, merge-conflicts, conflict-agent, init, migrate');
598
642
  }
@@ -659,6 +703,8 @@ async function main() {
659
703
  }, raw);
660
704
  } else if (subcommand === 'archive-quick-tasks') {
661
705
  state.cmdStateArchiveQuickTasks(cwd, raw);
706
+ } else if (subcommand === 'mark-milestone-complete') {
707
+ state.cmdMarkMilestoneComplete(cwd, raw);
662
708
  } else {
663
709
  state.cmdStateLoad(cwd, raw);
664
710
  }
@@ -736,7 +782,11 @@ async function main() {
736
782
  // Parse --phase-dir flag (available for context, passed through if supported)
737
783
  const phaseDirIdx = args.indexOf('--phase-dir');
738
784
  const phaseDir = phaseDirIdx !== -1 ? args[phaseDirIdx + 1] : null;
739
- commands.cmdCommit(cwd, message, files, raw, amend, push);
785
+ // Parse --repo-cwd flag: runs git ops in the target dir while loading
786
+ // config from cwd (mirrors the --cwd flag pattern on auto-test).
787
+ const repoCwdIdx = args.indexOf('--repo-cwd');
788
+ const repoCwd = repoCwdIdx !== -1 ? args[repoCwdIdx + 1] : undefined;
789
+ commands.cmdCommit(cwd, message, files, raw, amend, push, repoCwd);
740
790
  break;
741
791
  }
742
792
 
@@ -856,6 +906,11 @@ async function main() {
856
906
  break;
857
907
  }
858
908
 
909
+ case 'config-local-set': {
910
+ config.cmdConfigLocalSet(cwd, args[1], args[2], raw);
911
+ break;
912
+ }
913
+
859
914
  case 'config-get': {
860
915
  config.cmdConfigGet(cwd, args[1], raw);
861
916
  break;
@@ -1025,7 +1080,7 @@ async function main() {
1025
1080
  case 'phase': {
1026
1081
  const subcommand = args[1];
1027
1082
  // Gate write subcommands
1028
- if (subcommand === 'add' || subcommand === 'insert' || subcommand === 'remove' || subcommand === 'complete') {
1083
+ if (subcommand === 'add' || subcommand === 'insert' || subcommand === 'remove' || subcommand === 'complete' || subcommand === 'finalize') {
1029
1084
  gateIdentity();
1030
1085
  }
1031
1086
  if (subcommand === 'next-decimal') {
@@ -1039,8 +1094,25 @@ async function main() {
1039
1094
  phase.cmdPhaseRemove(cwd, args[2], { force: forceFlag }, raw);
1040
1095
  } else if (subcommand === 'complete') {
1041
1096
  phase.cmdPhaseComplete(cwd, args[2], raw);
1097
+ } else if (subcommand === 'finalize') {
1098
+ const push = args.includes('--push');
1099
+ phase.cmdPhaseFinalize(cwd, args[2], { push }, raw);
1042
1100
  } else {
1043
- error('Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete');
1101
+ error('Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete, finalize');
1102
+ }
1103
+ break;
1104
+ }
1105
+
1106
+ case 'plan': {
1107
+ const subcommand = args[1];
1108
+ if (subcommand === 'finalize') {
1109
+ gateIdentity();
1110
+ const push = args.includes('--push');
1111
+ const planNameIdx = args.indexOf('--plan-name');
1112
+ const planName = planNameIdx !== -1 ? args[planNameIdx + 1] : null;
1113
+ commands.cmdPlanFinalize(cwd, args[2], args[3], { push, planName }, raw);
1114
+ } else {
1115
+ error('Unknown plan subcommand. Available: finalize');
1044
1116
  }
1045
1117
  break;
1046
1118
  }
@@ -1090,13 +1162,28 @@ async function main() {
1090
1162
  case 'todo': {
1091
1163
  const subcommand = args[1];
1092
1164
  // Gate write subcommand
1093
- if (subcommand === 'complete') {
1165
+ if (subcommand === 'complete' || subcommand === 'set-status') {
1094
1166
  gateIdentity();
1095
1167
  }
1096
1168
  if (subcommand === 'complete') {
1097
1169
  commands.cmdTodoComplete(cwd, args[2], raw);
1170
+ } else if (subcommand === 'set-status') {
1171
+ const filename = args[2];
1172
+ const statusIdx = args.indexOf('--status');
1173
+ const status = statusIdx !== -1 ? args[statusIdx + 1] : null;
1174
+ if (!filename || !status) {
1175
+ error('Usage: todo set-status <filename> --status <pending|done>');
1176
+ }
1177
+ const { setTodoStatus } = require('./lib/commands.cjs');
1178
+ try {
1179
+ const result = setTodoStatus(cwd, filename, status);
1180
+ const { output: out } = require('./lib/core.cjs');
1181
+ out(result, raw);
1182
+ } catch (err) {
1183
+ error(err.message);
1184
+ }
1098
1185
  } else {
1099
- error('Unknown todo subcommand. Available: complete');
1186
+ error('Unknown todo subcommand. Available: complete, set-status');
1100
1187
  }
1101
1188
  break;
1102
1189
  }
@@ -1168,8 +1255,11 @@ async function main() {
1168
1255
  case 'progress':
1169
1256
  init.cmdInitProgress(cwd, raw);
1170
1257
  break;
1258
+ case 'progress-all':
1259
+ init.cmdInitProgressAll(cwd, raw);
1260
+ break;
1171
1261
  default:
1172
- error(`Unknown init workflow: ${workflow}\nAvailable: execute-phase, plan-phase, new-project, new-milestone, quick, resume, verify-work, audit-phase, phase-op, todos, milestone-op, map-codebase, progress`);
1262
+ error(`Unknown init workflow: ${workflow}\nAvailable: execute-phase, plan-phase, new-project, new-milestone, quick, resume, verify-work, audit-phase, phase-op, todos, milestone-op, map-codebase, progress, progress-all`);
1173
1263
  }
1174
1264
  break;
1175
1265
  }
@@ -1328,8 +1418,18 @@ async function main() {
1328
1418
  raw,
1329
1419
  author
1330
1420
  );
1421
+ } else if (subcommand === 'set-status') {
1422
+ // Alias for move-state (frontmatter-based)
1423
+ const idIdx = args.indexOf('--id');
1424
+ const statusIdx = args.indexOf('--status');
1425
+ const id = idIdx !== -1 ? args[idIdx + 1] : null;
1426
+ const status = statusIdx !== -1 ? args[statusIdx + 1] : null;
1427
+ if (!id || !status) {
1428
+ error('Usage: ideas set-status --id <N> --status <pending|done|rejected|consolidated>');
1429
+ }
1430
+ ideas.cmdIdeasMoveState(cwd, id, status, raw, author);
1331
1431
  } else {
1332
- error('Unknown ideas subcommand: ' + subcommand);
1432
+ error('Unknown ideas subcommand: ' + (subcommand || '(none)') + '. Available: create, list, update, append-note, discuss-save, research-save, consolidate, find-related, undo-consolidation, move-state, set-status, reject, restore');
1333
1433
  }
1334
1434
  break;
1335
1435
  }
@@ -1669,8 +1769,23 @@ async function main() {
1669
1769
  } else if (subcommand === 'rollback') {
1670
1770
  if (!args[2]) error('Usage: jobs rollback <version>');
1671
1771
  jobs.cmdJobsRollback(cwd, args[2], raw);
1772
+ } else if (subcommand === 'set-status') {
1773
+ const version = args[2];
1774
+ const statusIdx = args.indexOf('--status');
1775
+ const status = statusIdx !== -1 ? args[statusIdx + 1] : null;
1776
+ if (!version || !status) {
1777
+ error('Usage: jobs set-status <version> --status <pending|in-progress|completed|failed|rolled_back>');
1778
+ }
1779
+ const { setJobStatus } = require('./lib/jobs.cjs');
1780
+ try {
1781
+ const result = setJobStatus(cwd, version, status);
1782
+ const { output: out } = require('./lib/core.cjs');
1783
+ out(result, raw);
1784
+ } catch (err) {
1785
+ error(err.message);
1786
+ }
1672
1787
  } else {
1673
- error('Unknown jobs subcommand: ' + (subcommand || '(none)') + '. Available: parse, update-step, move, find-job, update-header, insert-steps, insert-gap-fix-section, insert-phase-gap-fix, create-milestone, milestone-preview, list-jobs, cancel-job, health, dry-run, generate-summary, record-start-shas, rollback');
1788
+ error('Unknown jobs subcommand: ' + (subcommand || '(none)') + '. Available: parse, update-step, move, find-job, update-header, insert-steps, insert-gap-fix-section, insert-phase-gap-fix, create-milestone, milestone-preview, list-jobs, cancel-job, health, dry-run, generate-summary, record-start-shas, rollback, set-status');
1674
1789
  }
1675
1790
  break;
1676
1791
  }
@@ -1747,35 +1862,174 @@ async function main() {
1747
1862
  break;
1748
1863
  }
1749
1864
 
1865
+ case 'worktrees': {
1866
+ const subcommand = args[1];
1867
+ const worktrees = require('./lib/worktrees.cjs');
1868
+ const { output: wtOutput } = require('./lib/core.cjs');
1869
+ if (subcommand === 'create') {
1870
+ worktrees.cmdWorktreesCreate(cwd, args.slice(2));
1871
+ } else if (subcommand === 'remove') {
1872
+ worktrees.cmdWorktreesRemove(cwd, args.slice(2));
1873
+ } else if (subcommand === 'list') {
1874
+ worktrees.cmdWorktreesList(cwd, args.slice(2));
1875
+ } else if (subcommand === 'setup') {
1876
+ worktrees.cmdWorktreesSetup(cwd, args.slice(2));
1877
+ } else if (subcommand === 'prune') {
1878
+ worktrees.cmdWorktreesPrune(cwd, args.slice(2));
1879
+ } else if (subcommand === 'rebase-and-merge') {
1880
+ const slug = args[2];
1881
+ if (!slug) error('Usage: worktrees rebase-and-merge <slug> --repo <name>');
1882
+ const repoIdx = args.indexOf('--repo');
1883
+ const repoName = repoIdx !== -1 ? args[repoIdx + 1] : null;
1884
+ if (!repoName) error('--repo required for rebase-and-merge');
1885
+ const noPush = args.includes('--no-push');
1886
+ const result = worktrees.rebaseAndMerge(cwd, repoName, slug, { push: !noPush });
1887
+ wtOutput(result);
1888
+ } else if (subcommand === 'health') {
1889
+ const slug = args[2];
1890
+ if (!slug) error('Usage: worktrees health <slug>');
1891
+ const result = worktrees.checkWorktreeHealth(cwd, slug);
1892
+ wtOutput(result);
1893
+ } else {
1894
+ error('Unknown worktrees subcommand: ' + subcommand + '. Available: create, remove, list, setup, prune, rebase-and-merge, health');
1895
+ }
1896
+ break;
1897
+ }
1898
+
1750
1899
  case 'migrate': {
1751
1900
  const layoutIdx = args.indexOf('--layout');
1752
1901
  const layout = layoutIdx !== -1 ? args[layoutIdx + 1] : null;
1753
- if (layout !== 'root') {
1754
- error('Usage: dgs-tools migrate --layout root [--dry-run] [--raw]');
1755
- }
1756
- const dryRun = args.includes('--dry-run');
1757
- const result = migrateDotPlanningToRoot(cwd, { dryRun });
1758
- if (raw) {
1759
- const { output: out } = require('./lib/core.cjs');
1760
- out(result, raw);
1761
- } else if (result.dryRun) {
1762
- if (result.actions.length === 0) {
1763
- process.stderr.write('Nothing to migrate. Already in root layout.\n');
1902
+
1903
+ if (layout === 'root') {
1904
+ // Existing .planning/ to root migration
1905
+ const dryRun = args.includes('--dry-run');
1906
+ const result = migrateDotPlanningToRoot(cwd, { dryRun });
1907
+ if (raw) {
1908
+ const { output: out } = require('./lib/core.cjs');
1909
+ out(result, raw);
1910
+ } else if (result.dryRun) {
1911
+ if (result.actions.length === 0) {
1912
+ process.stderr.write('Nothing to migrate. Already in root layout.\n');
1913
+ } else {
1914
+ process.stderr.write('Dry run — the following changes would be made:\n');
1915
+ for (const action of result.actions) {
1916
+ const label = action.type === 'identical' ? '(identical, delete .planning copy)' : '';
1917
+ process.stderr.write(` ${action.from} -> ${action.to} ${label}\n`);
1918
+ }
1919
+ process.stderr.write(`\n${result.filesMoved} file(s) to move, ${result.identicalResolved} identical conflict(s) to resolve.\n`);
1920
+ }
1921
+ } else if (result.migrated) {
1922
+ process.stderr.write(`Migration complete. ${result.filesMoved} file(s) moved.`);
1923
+ if (result.commitHash) process.stderr.write(` Commit: ${result.commitHash}`);
1924
+ process.stderr.write('\n');
1764
1925
  } else {
1765
- process.stderr.write('Dry run the following changes would be made:\n');
1766
- for (const action of result.actions) {
1767
- const label = action.type === 'identical' ? '(identical, delete .planning copy)' : '';
1768
- process.stderr.write(` ${action.from} -> ${action.to} ${label}\n`);
1926
+ process.stderr.write('Nothing to migrate. Already in root layout.\n');
1927
+ }
1928
+ } else if (layout === 'flat') {
1929
+ // Flat status migration (v20.0)
1930
+ const apply = args.includes('--apply');
1931
+ const result = migrateFlatStatus(cwd, { apply });
1932
+ if (raw) {
1933
+ const { output: out } = require('./lib/core.cjs');
1934
+ out(result, raw);
1935
+ } else if (!apply) {
1936
+ // Dry-run mode (default)
1937
+ if (result.actions.length === 0) {
1938
+ process.stderr.write('Nothing to migrate. All files already in flat layout (or migration already done).\n');
1939
+ } else {
1940
+ process.stderr.write('Dry run — the following changes would be made:\n\n');
1941
+ // Group by subsystem
1942
+ const grouped = {};
1943
+ for (const action of result.actions) {
1944
+ const key = action.subsystem || 'research';
1945
+ if (!grouped[key]) grouped[key] = [];
1946
+ grouped[key].push(action);
1947
+ }
1948
+ for (const [sub, subActions] of Object.entries(grouped)) {
1949
+ process.stderr.write(` ${sub}:\n`);
1950
+ for (const action of subActions) {
1951
+ const statusNote = action.mappedStatus ? ` (status: ${action.mappedStatus})` : '';
1952
+ process.stderr.write(` ${action.from} -> ${action.to}${statusNote}\n`);
1953
+ }
1954
+ }
1955
+ process.stderr.write(`\n${result.filesMoved} file(s) to move, ${result.statusFieldsAdded} status field(s) to add.\n`);
1956
+ process.stderr.write('\nTo apply: dgs-tools migrate --layout flat --apply\n');
1769
1957
  }
1770
- process.stderr.write(`\n${result.filesMoved} file(s) to move, ${result.identicalResolved} identical conflict(s) to resolve.\n`);
1958
+ } else if (result.migrated) {
1959
+ process.stderr.write(`Flat status migration complete. ${result.filesMoved} file(s) moved, ${result.statusFieldsAdded} status field(s) added, ${result.pathsNormalized} path(s) normalized.`);
1960
+ if (result.commitHash) process.stderr.write(` Commit: ${result.commitHash}`);
1961
+ process.stderr.write('\n');
1962
+ } else {
1963
+ process.stderr.write('Nothing to migrate. All files already in flat layout (or migration already done).\n');
1771
1964
  }
1772
- } else if (result.migrated) {
1773
- process.stderr.write(`Migration complete. ${result.filesMoved} file(s) moved.`);
1774
- if (result.commitHash) process.stderr.write(` Commit: ${result.commitHash}`);
1775
- process.stderr.write('\n');
1776
1965
  } else {
1777
- process.stderr.write('Nothing to migrate. Already in root layout.\n');
1966
+ error('Usage: dgs-tools migrate --layout root|flat [--dry-run] [--apply] [--raw]');
1967
+ }
1968
+ break;
1969
+ }
1970
+
1971
+ case 'complete-quick':
1972
+ case 'quick-complete': {
1973
+ const { cmdQuickComplete } = require('./lib/quick.cjs');
1974
+ cmdQuickComplete(cwd);
1975
+ break;
1976
+ }
1977
+
1978
+ case 'abandon-quick':
1979
+ case 'quick-abandon': {
1980
+ const { cmdQuickAbandon } = require('./lib/quick.cjs');
1981
+ cmdQuickAbandon(cwd, args.slice(1));
1982
+ break;
1983
+ }
1984
+
1985
+ case 'quick': {
1986
+ const subcommand = args[1];
1987
+ if (subcommand !== 'finalize') {
1988
+ error('Usage: dgs-tools quick finalize <quick_id> [--description <desc>] --quick-dir <dir> [--state-path <path>] [--push] [--repo-cwd <path>] [--fast]');
1989
+ return;
1990
+ }
1991
+ gateIdentity();
1992
+ const quickId = args[2];
1993
+ if (!quickId) {
1994
+ error('quick_id required');
1995
+ return;
1778
1996
  }
1997
+
1998
+ // Parse flags starting at args[3]
1999
+ let description = null;
2000
+ let quickDir = null;
2001
+ let statePath = null;
2002
+ let push = false;
2003
+ let repoCwd = null;
2004
+ let fast = false;
2005
+
2006
+ for (let i = 3; i < args.length; i++) {
2007
+ const a = args[i];
2008
+ if (a === '--description') {
2009
+ // Multi-word: consume args until next --flag or end
2010
+ const parts = [];
2011
+ let j = i + 1;
2012
+ while (j < args.length && !args[j].startsWith('--')) {
2013
+ parts.push(args[j]);
2014
+ j++;
2015
+ }
2016
+ description = parts.join(' ');
2017
+ i = j - 1;
2018
+ } else if (a === '--quick-dir') {
2019
+ quickDir = args[++i];
2020
+ } else if (a === '--state-path') {
2021
+ statePath = args[++i];
2022
+ } else if (a === '--push') {
2023
+ push = true;
2024
+ } else if (a === '--repo-cwd') {
2025
+ repoCwd = args[++i];
2026
+ } else if (a === '--fast') {
2027
+ fast = true;
2028
+ }
2029
+ }
2030
+
2031
+ const { cmdQuickFinalize } = require('./lib/quick.cjs');
2032
+ cmdQuickFinalize(cwd, quickId, { description, quickDir, statePath, push, repoCwd, fast }, raw);
1779
2033
  break;
1780
2034
  }
1781
2035