@ktpartners/dgs-platform 2.9.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/CHANGELOG.md +197 -0
  2. package/README.md +34 -2
  3. package/agents/dgs-executor.md +124 -3
  4. package/agents/dgs-idea-researcher.md +447 -0
  5. package/agents/dgs-plan-checker.md +61 -3
  6. package/agents/dgs-planner.md +51 -8
  7. package/bin/install.js +44 -0
  8. package/commands/dgs/abandon-quick.md +28 -0
  9. package/commands/dgs/add-tests.md +2 -2
  10. package/commands/dgs/audit-milestone.md +4 -3
  11. package/commands/dgs/capture-principle.md +11 -11
  12. package/commands/dgs/cleanup.md +2 -2
  13. package/commands/dgs/complete-milestone.md +11 -11
  14. package/commands/dgs/complete-quick.md +28 -0
  15. package/commands/dgs/create-milestone-job.md +2 -2
  16. package/commands/dgs/debug.md +3 -3
  17. package/commands/dgs/develop-idea.md +1 -1
  18. package/commands/dgs/diff-report.md +124 -0
  19. package/commands/dgs/fast.md +3 -1
  20. package/commands/dgs/health.md +1 -1
  21. package/commands/dgs/map-codebase.md +6 -6
  22. package/commands/dgs/new-milestone.md +5 -5
  23. package/commands/dgs/new-project.md +8 -21
  24. package/commands/dgs/package-scan.md +43 -0
  25. package/commands/dgs/plan-milestone-gaps.md +1 -1
  26. package/commands/dgs/progress.md +3 -3
  27. package/commands/dgs/quick-abandon.md +8 -0
  28. package/commands/dgs/quick-complete.md +8 -0
  29. package/commands/dgs/quick.md +10 -3
  30. package/commands/dgs/research-idea.md +3 -2
  31. package/commands/dgs/research-phase.md +3 -3
  32. package/commands/dgs/switch-project.md +14 -1
  33. package/commands/dgs/write-spec.md +3 -3
  34. package/deliver-great-systems/bin/dgs-tools.cjs +401 -32
  35. package/deliver-great-systems/bin/lib/audit-tolerance.cjs +77 -0
  36. package/deliver-great-systems/bin/lib/audit-tolerance.test.cjs +101 -0
  37. package/deliver-great-systems/bin/lib/commands.cjs +626 -46
  38. package/deliver-great-systems/bin/lib/commands.test.cjs +451 -0
  39. package/deliver-great-systems/bin/lib/commit-verify.test.cjs +236 -0
  40. package/deliver-great-systems/bin/lib/config.cjs +80 -6
  41. package/deliver-great-systems/bin/lib/config.test.cjs +309 -0
  42. package/deliver-great-systems/bin/lib/context.cjs +120 -0
  43. package/deliver-great-systems/bin/lib/core.cjs +35 -14
  44. package/deliver-great-systems/bin/lib/core.test.cjs +79 -1
  45. package/deliver-great-systems/bin/lib/execution.cjs +49 -17
  46. package/deliver-great-systems/bin/lib/fast-routing.cjs +199 -0
  47. package/deliver-great-systems/bin/lib/fast-routing.test.cjs +108 -0
  48. package/deliver-great-systems/bin/lib/final-commit-precondition.test.cjs +87 -0
  49. package/deliver-great-systems/bin/lib/fixtures/package-scan/bundler-audit-gemfile.json +21 -0
  50. package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-expected.md +186 -0
  51. package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-runresult.json +235 -0
  52. package/deliver-great-systems/bin/lib/fixtures/package-scan/govulncheck-import.json +3 -0
  53. package/deliver-great-systems/bin/lib/fixtures/package-scan/npm-audit-v10.json +37 -0
  54. package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-clean.json +3 -0
  55. package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-vulns.json +77 -0
  56. package/deliver-great-systems/bin/lib/fixtures/package-scan/pip-audit-requirements.json +28 -0
  57. package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-lodash.json +30 -0
  58. package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-workspaces.json +55 -0
  59. package/deliver-great-systems/bin/lib/flat-migration.test.cjs +396 -0
  60. package/deliver-great-systems/bin/lib/frontmatter.cjs +1 -1
  61. package/deliver-great-systems/bin/lib/governance.cjs +211 -0
  62. package/deliver-great-systems/bin/lib/governance.test.cjs +339 -0
  63. package/deliver-great-systems/bin/lib/health-untracked-phase.test.cjs +269 -0
  64. package/deliver-great-systems/bin/lib/ideas.cjs +206 -91
  65. package/deliver-great-systems/bin/lib/ideas.test.cjs +244 -1
  66. package/deliver-great-systems/bin/lib/init.cjs +357 -61
  67. package/deliver-great-systems/bin/lib/init.test.cjs +625 -8
  68. package/deliver-great-systems/bin/lib/jobs.cjs +131 -25
  69. package/deliver-great-systems/bin/lib/jobs.test.cjs +193 -74
  70. package/deliver-great-systems/bin/lib/migration.cjs +409 -1
  71. package/deliver-great-systems/bin/lib/migration.test.cjs +158 -1
  72. package/deliver-great-systems/bin/lib/milestone.cjs +154 -31
  73. package/deliver-great-systems/bin/lib/milestone.test.cjs +203 -0
  74. package/deliver-great-systems/bin/lib/package-adapters.cjs +530 -0
  75. package/deliver-great-systems/bin/lib/package-adapters.test.cjs +618 -0
  76. package/deliver-great-systems/bin/lib/package-ecosystems.cjs +350 -0
  77. package/deliver-great-systems/bin/lib/package-ecosystems.test.cjs +348 -0
  78. package/deliver-great-systems/bin/lib/package-runner.cjs +199 -0
  79. package/deliver-great-systems/bin/lib/package-runner.test.cjs +198 -0
  80. package/deliver-great-systems/bin/lib/package-scan-provenance.cjs +56 -0
  81. package/deliver-great-systems/bin/lib/package-scan-provenance.test.cjs +103 -0
  82. package/deliver-great-systems/bin/lib/package-scan-report.cjs +1140 -0
  83. package/deliver-great-systems/bin/lib/package-scan-report.test.cjs +1963 -0
  84. package/deliver-great-systems/bin/lib/package-scan-skill.cjs +96 -0
  85. package/deliver-great-systems/bin/lib/package-scan-skill.test.cjs +136 -0
  86. package/deliver-great-systems/bin/lib/package-scan.cjs +919 -0
  87. package/deliver-great-systems/bin/lib/package-scan.test.cjs +2147 -0
  88. package/deliver-great-systems/bin/lib/phase.cjs +146 -3
  89. package/deliver-great-systems/bin/lib/phase.test.cjs +420 -0
  90. package/deliver-great-systems/bin/lib/plan-number-validity.test.cjs +48 -0
  91. package/deliver-great-systems/bin/lib/projects.cjs +65 -10
  92. package/deliver-great-systems/bin/lib/projects.test.cjs +198 -2
  93. package/deliver-great-systems/bin/lib/quick.cjs +739 -0
  94. package/deliver-great-systems/bin/lib/quick.test.cjs +730 -0
  95. package/deliver-great-systems/bin/lib/repos.cjs +37 -13
  96. package/deliver-great-systems/bin/lib/review.cjs +1821 -0
  97. package/deliver-great-systems/bin/lib/roadmap.cjs +34 -13
  98. package/deliver-great-systems/bin/lib/specs.cjs +3 -81
  99. package/deliver-great-systems/bin/lib/state-transition-gate.test.cjs +160 -0
  100. package/deliver-great-systems/bin/lib/state.cjs +147 -55
  101. package/deliver-great-systems/bin/lib/summary-frontmatter.cjs +54 -0
  102. package/deliver-great-systems/bin/lib/summary-frontmatter.test.cjs +78 -0
  103. package/deliver-great-systems/bin/lib/sweep-scope.test.cjs +263 -0
  104. package/deliver-great-systems/bin/lib/sync.cjs +75 -0
  105. package/deliver-great-systems/bin/lib/verify.cjs +198 -7
  106. package/deliver-great-systems/bin/lib/verify.test.cjs +82 -0
  107. package/deliver-great-systems/bin/lib/wave-0-template-rename.test.cjs +40 -0
  108. package/deliver-great-systems/bin/lib/worktrees.cjs +790 -0
  109. package/deliver-great-systems/bin/lib/worktrees.test.cjs +963 -0
  110. package/deliver-great-systems/references/agent-step-reliability.md +60 -0
  111. package/deliver-great-systems/references/conflict-resolution.md +4 -0
  112. package/deliver-great-systems/references/context-tiers.md +4 -0
  113. package/deliver-great-systems/references/package-scan-config.md +151 -0
  114. package/deliver-great-systems/references/questioning.md +0 -30
  115. package/deliver-great-systems/references/spec-review-loop.md +1 -2
  116. package/deliver-great-systems/references/workflow-conventions.md +29 -0
  117. package/deliver-great-systems/skills/dgs-tests/package-scan.md +44 -0
  118. package/deliver-great-systems/templates/REVIEW.md +35 -0
  119. package/deliver-great-systems/templates/VALIDATION.md +1 -1
  120. package/deliver-great-systems/templates/claude-md.md +27 -0
  121. package/deliver-great-systems/templates/package-scan-report.md +108 -0
  122. package/deliver-great-systems/templates/project.md +6 -170
  123. package/deliver-great-systems/templates/summary.md +3 -1
  124. package/deliver-great-systems/workflows/abandon-quick.md +89 -0
  125. package/deliver-great-systems/workflows/add-idea.md +3 -3
  126. package/deliver-great-systems/workflows/add-phase.md +5 -0
  127. package/deliver-great-systems/workflows/add-tests.md +14 -0
  128. package/deliver-great-systems/workflows/add-todo.md +1 -0
  129. package/deliver-great-systems/workflows/approve-spec.md +25 -4
  130. package/deliver-great-systems/workflows/audit-milestone.md +66 -10
  131. package/deliver-great-systems/workflows/audit-phase.md +15 -5
  132. package/deliver-great-systems/workflows/cancel-job.md +2 -2
  133. package/deliver-great-systems/workflows/check-todos.md +2 -3
  134. package/deliver-great-systems/workflows/codereview.md +103 -9
  135. package/deliver-great-systems/workflows/complete-milestone.md +218 -24
  136. package/deliver-great-systems/workflows/complete-quick.md +106 -0
  137. package/deliver-great-systems/workflows/consolidate-ideas.md +1 -1
  138. package/deliver-great-systems/workflows/create-milestone-job.md +4 -4
  139. package/deliver-great-systems/workflows/develop-idea.md +11 -11
  140. package/deliver-great-systems/workflows/diagnose-issues.md +14 -0
  141. package/deliver-great-systems/workflows/discuss-idea.md +1 -1
  142. package/deliver-great-systems/workflows/discuss-phase.md +3 -2
  143. package/deliver-great-systems/workflows/execute-phase.md +209 -33
  144. package/deliver-great-systems/workflows/execute-plan.md +22 -22
  145. package/deliver-great-systems/workflows/help.md +53 -20
  146. package/deliver-great-systems/workflows/import-spec.md +65 -7
  147. package/deliver-great-systems/workflows/init-product.md +45 -167
  148. package/deliver-great-systems/workflows/new-milestone.md +140 -33
  149. package/deliver-great-systems/workflows/new-project.md +60 -331
  150. package/deliver-great-systems/workflows/package-scan.md +59 -0
  151. package/deliver-great-systems/workflows/plan-phase.md +79 -1
  152. package/deliver-great-systems/workflows/progress-all.md +133 -0
  153. package/deliver-great-systems/workflows/quick-abandon.md +89 -0
  154. package/deliver-great-systems/workflows/quick-complete.md +106 -0
  155. package/deliver-great-systems/workflows/quick.md +328 -26
  156. package/deliver-great-systems/workflows/refine-spec.md +1 -1
  157. package/deliver-great-systems/workflows/research-idea.md +77 -139
  158. package/deliver-great-systems/workflows/resume-project.md +2 -2
  159. package/deliver-great-systems/workflows/run-job.md +29 -43
  160. package/deliver-great-systems/workflows/settings.md +13 -77
  161. package/deliver-great-systems/workflows/validate-phase.md +39 -1
  162. package/deliver-great-systems/workflows/verify-work.md +14 -0
  163. package/deliver-great-systems/workflows/write-spec.md +11 -13
  164. package/hooks/dist/dgs-enforce-discipline.js +196 -0
  165. package/package.json +1 -1
  166. package/scripts/build-hooks.js +1 -0
@@ -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
@@ -29,6 +30,7 @@
29
30
  * summary-extract <path> [--fields] Extract structured data from SUMMARY.md
30
31
  * state-snapshot Structured parse of STATE.md
31
32
  * phase-plan-index <phase> Index plans with waves and status
33
+ * package-scan [--raw] Scan all repos for dependency vulnerabilities; writes committed report
32
34
  * websearch <query> Search web via Brave API (if configured)
33
35
  * [--limit N] [--freshness day|week|month]
34
36
  *
@@ -38,6 +40,13 @@
38
40
  * phase insert <after> <description> Insert decimal phase after existing
39
41
  * phase remove <phase> [--force] Remove phase, renumber all subsequent
40
42
  * phase complete <phase> Mark phase done, update state + roadmap
43
+ * phase finalize <phase> Mark phase done + commit tracking files + VERIFICATION.md atomically
44
+ * [--push] Push after commit (respects sync_push config)
45
+ *
46
+ * Plan Operations:
47
+ * plan finalize <phase> <plan> Update state/roadmap/requirements + commit PLAN+SUMMARY+tracking atomically
48
+ * [--push] Push after commit
49
+ * [--plan-name <name>] Override plan name in commit message
41
50
  *
42
51
  * Roadmap Operations:
43
52
  * roadmap get-phase <phase> Extract phase section from ROADMAP.md
@@ -62,6 +71,8 @@
62
71
  *
63
72
  * Todos:
64
73
  * todo complete <filename> Move todo from pending to completed
74
+ * todo set-status <filename> Set todo status (frontmatter)
75
+ * --status <pending|done>
65
76
  *
66
77
  * Scaffolding:
67
78
  * scaffold context --phase <N> Create CONTEXT.md template
@@ -72,6 +83,7 @@
72
83
  *
73
84
  * Migration:
74
85
  * migrate --layout root Migrate .planning/ to root layout
86
+ * migrate --layout flat [--apply] Migrate to flat status directories
75
87
  * [--dry-run] Show what would change without modifying
76
88
  * [--raw] JSON output for scripting
77
89
  *
@@ -182,6 +194,18 @@
182
194
  * sync workflow-push <workflow> Workflow-level push check/execute
183
195
  * [--check-only] [--mid-workflow] [--record-yes]
184
196
  *
197
+ * Worktrees:
198
+ * worktrees create <slug> Create worktrees for project repos
199
+ * --type milestone|quick
200
+ * [--mode full|debug]
201
+ * [--repo <name>]
202
+ * worktrees remove <slug> Remove worktree and clean up
203
+ * worktrees list List tracked worktrees (JSON)
204
+ * worktrees setup <slug> Re-run setup command for worktree
205
+ * worktrees prune Remove orphaned worktree entries
206
+ * worktrees rebase-and-merge <slug> --repo <name> Rebase and merge worktree branch
207
+ * worktrees health <slug> Check worktree health
208
+ *
185
209
  * Ideas Operations:
186
210
  * ideas create --title T --body B Create new idea with auto-assigned ID
187
211
  * [--tags "t1,t2"]
@@ -193,6 +217,7 @@
193
217
  * ideas reject --id N [--reason R] Reject idea (move to rejected/)
194
218
  * ideas restore --id N Restore idea to pending
195
219
  * ideas move-state --id N --to S Move idea to target state
220
+ * ideas set-status --id N --status S Set idea status (frontmatter)
196
221
  * ideas discuss-save --id N Save structured discussion entry
197
222
  * --entry '{json}' JSON: { date, keyInsights, refinedProblem, refinedApproach, openQuestions, decision }
198
223
  * ideas research-save --id N Save structured research log entry
@@ -237,6 +262,8 @@
237
262
  * [--no-check] Omit audit/complete steps
238
263
  * jobs record-start-shas <file> Record starting commit SHAs into job file
239
264
  * jobs rollback <version> Roll back code repos to pre-job SHAs
265
+ * jobs set-status <version> Set job status (frontmatter + header)
266
+ * --status <pending|in-progress|completed|failed|rolled_back>
240
267
  *
241
268
  * Search Operations:
242
269
  * search <query> [--flags] Search across ideas, specs, docs, projects
@@ -257,6 +284,7 @@
257
284
  * init milestone-op All context for milestone operations
258
285
  * init map-codebase All context for map-codebase workflow
259
286
  * init progress All context for progress workflow
287
+ * init progress-all Product-level dashboard across all active projects
260
288
  */
261
289
 
262
290
  const { error, loadConfig } = require('./lib/core.cjs');
@@ -283,7 +311,7 @@ const mergeConflicts = require('./lib/merge-conflicts.cjs');
283
311
  const conflictAgent = require('./lib/conflict-agent.cjs');
284
312
  const { requireGitIdentity, formatAuthorString, cmdIdentityResolve } = require('./lib/identity.cjs');
285
313
  const { pullAll, pushAll, getCadence, checkStaleState, shouldShowFirstRunHint, markFirstRunHintShown, isWithinSuppressionWindow, recordPromptYes } = require('./lib/sync.cjs');
286
- const { migrateDotPlanningToRoot, rejectV1Install } = require('./lib/migration.cjs');
314
+ const { migrateDotPlanningToRoot, rejectV1Install, migrateBranchingConfig, migrateFlatStatus } = require('./lib/migration.cjs');
287
315
 
288
316
  // ─── Identity Gate ────────────────────────────────────────────────────────────
289
317
 
@@ -593,6 +621,23 @@ async function main() {
593
621
  // fails for unexpected reasons (defensive, should not normally trigger).
594
622
  }
595
623
 
624
+ // Run lazy branching config migration (best-effort, non-blocking)
625
+ try {
626
+ migrateBranchingConfig(cwd);
627
+ } catch (e) {
628
+ process.stderr.write('Warning: Migration check failed: ' + (e.message || String(e)) + '\n');
629
+ }
630
+
631
+ // Run flat status migration auto-detect (best-effort, non-blocking)
632
+ // Same pattern as branching config: detect legacy layout, log if found, apply on explicit command
633
+ if (command !== 'migrate') try {
634
+ const flatResult = migrateFlatStatus(cwd);
635
+ // In auto-detect mode (dryRun=true by default), just check if migration is needed
636
+ if (flatResult.dryRun && flatResult.actions.length > 0) {
637
+ process.stderr.write('[DGS] Legacy directory-based state detected (' + flatResult.filesMoved + ' file(s) to migrate). Run: dgs-tools migrate --layout flat --apply\n');
638
+ }
639
+ } catch { /* ignore auto-detect errors */ }
640
+
596
641
  if (!command) {
597
642
  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
643
  }
@@ -659,6 +704,8 @@ async function main() {
659
704
  }, raw);
660
705
  } else if (subcommand === 'archive-quick-tasks') {
661
706
  state.cmdStateArchiveQuickTasks(cwd, raw);
707
+ } else if (subcommand === 'mark-milestone-complete') {
708
+ state.cmdMarkMilestoneComplete(cwd, raw);
662
709
  } else {
663
710
  state.cmdStateLoad(cwd, raw);
664
711
  }
@@ -736,10 +783,96 @@ async function main() {
736
783
  // Parse --phase-dir flag (available for context, passed through if supported)
737
784
  const phaseDirIdx = args.indexOf('--phase-dir');
738
785
  const phaseDir = phaseDirIdx !== -1 ? args[phaseDirIdx + 1] : null;
739
- commands.cmdCommit(cwd, message, files, raw, amend, push);
786
+ // Parse --repo-cwd flag: runs git ops in the target dir while loading
787
+ // config from cwd (mirrors the --cwd flag pattern on auto-test).
788
+ const repoCwdIdx = args.indexOf('--repo-cwd');
789
+ const repoCwd = repoCwdIdx !== -1 ? args[repoCwdIdx + 1] : undefined;
790
+ commands.cmdCommit(cwd, message, files, raw, amend, push, repoCwd);
740
791
  break;
741
792
  }
742
793
 
794
+ case 'final-commit-precondition': {
795
+ // REL-08 (Phase 157): pre-commit precondition gate. Aborts with
796
+ // `summary-frontmatter-mismatch` label when PLAN.md `requirements:` is
797
+ // non-empty AND SUMMARY.md `requirements_completed:` is empty. Read-only —
798
+ // never writes to the working tree.
799
+ const planIdx = args.indexOf('--plan');
800
+ const summaryIdx = args.indexOf('--summary');
801
+ const opts = {
802
+ plan: planIdx !== -1 ? args[planIdx + 1] : undefined,
803
+ summary: summaryIdx !== -1 ? args[summaryIdx + 1] : undefined,
804
+ };
805
+ return commands.cmdFinalCommitPrecondition(cwd, opts);
806
+ }
807
+
808
+ case 'commit-verify-plan': {
809
+ // REL-01 (Phase 156): orchestrator-side commit + verification helper
810
+ // for /dgs:plan-phase. Commits a planner-emitted createdFiles list and
811
+ // verifies every reported path appears in HEAD; on mismatch, returns
812
+ // plan-commit-incomplete with working tree unchanged.
813
+ gateIdentity();
814
+ const message = args[1];
815
+ // --files <paths...> (collect args after --files until next --flag)
816
+ const filesIndex = args.indexOf('--files');
817
+ const createdFiles = filesIndex !== -1
818
+ ? args.slice(filesIndex + 1).filter(a => !a.startsWith('--'))
819
+ : [];
820
+ // --extra-files <paths...> (e.g. ROADMAP.md)
821
+ const extraIdx = args.indexOf('--extra-files');
822
+ const extraFiles = extraIdx !== -1
823
+ ? args.slice(extraIdx + 1).filter(a => !a.startsWith('--'))
824
+ : [];
825
+ // --repo-cwd <path>
826
+ const repoCwdIdxV = args.indexOf('--repo-cwd');
827
+ const repoCwdV = repoCwdIdxV !== -1 ? args[repoCwdIdxV + 1] : undefined;
828
+ const pushV = args.includes('--push');
829
+ const result = commands.verifyPlanCommit(cwd, {
830
+ message,
831
+ createdFiles,
832
+ extraFiles,
833
+ repoCwd: repoCwdV,
834
+ push: pushV,
835
+ }, raw);
836
+ // verifyPlanCommit is a pure helper — emit output and exit non-zero
837
+ // on plan-commit-incomplete so the calling workflow can detect failure.
838
+ if (raw) {
839
+ process.stdout.write(JSON.stringify(result));
840
+ } else {
841
+ if (result.ok) {
842
+ process.stdout.write(result.hash || result.reason || 'ok');
843
+ } else {
844
+ process.stdout.write(`[${result.exitLabel}] ${result.reason}`);
845
+ }
846
+ }
847
+ process.exit(result.ok ? 0 : 1);
848
+ }
849
+
850
+ case 'compute-phase-sweep': {
851
+ // REL-02 (Phase 156): scope-bounded executor sweep helper.
852
+ // Returns the UNION of git-discovered phase-dir paths and the
853
+ // executor-reported modified_files list, scope-filtered to
854
+ // ${phasesDir}/${phaseDir}/ only.
855
+ const phasesDirIdx = args.indexOf('--phases-dir');
856
+ const phaseDirIdx = args.indexOf('--phase-dir');
857
+ const modifiedIdx = args.indexOf('--modified-files');
858
+ const phasesDirV = phasesDirIdx !== -1 ? args[phasesDirIdx + 1] : undefined;
859
+ const phaseDirV = phaseDirIdx !== -1 ? args[phaseDirIdx + 1] : undefined;
860
+ const modifiedFiles = modifiedIdx !== -1
861
+ ? args.slice(modifiedIdx + 1).filter(a => !a.startsWith('--'))
862
+ : [];
863
+ const result = commands.computePhaseSweep(cwd, {
864
+ phasesDir: phasesDirV,
865
+ phaseDir: phaseDirV,
866
+ modifiedFiles,
867
+ }, raw);
868
+ if (raw) {
869
+ process.stdout.write(JSON.stringify(result));
870
+ } else {
871
+ process.stdout.write(`Swept: ${result.swept.length} | Dropped: ${result.dropped.length}`);
872
+ }
873
+ process.exit(result.error ? 1 : 0);
874
+ }
875
+
743
876
  case 'verify-summary': {
744
877
  const summaryPath = args[1];
745
878
  const countIndex = args.indexOf('--check-count');
@@ -856,6 +989,11 @@ async function main() {
856
989
  break;
857
990
  }
858
991
 
992
+ case 'config-local-set': {
993
+ config.cmdConfigLocalSet(cwd, args[1], args[2], raw);
994
+ break;
995
+ }
996
+
859
997
  case 'config-get': {
860
998
  config.cmdConfigGet(cwd, args[1], raw);
861
999
  break;
@@ -1025,7 +1163,7 @@ async function main() {
1025
1163
  case 'phase': {
1026
1164
  const subcommand = args[1];
1027
1165
  // Gate write subcommands
1028
- if (subcommand === 'add' || subcommand === 'insert' || subcommand === 'remove' || subcommand === 'complete') {
1166
+ if (subcommand === 'add' || subcommand === 'insert' || subcommand === 'remove' || subcommand === 'complete' || subcommand === 'finalize') {
1029
1167
  gateIdentity();
1030
1168
  }
1031
1169
  if (subcommand === 'next-decimal') {
@@ -1039,8 +1177,25 @@ async function main() {
1039
1177
  phase.cmdPhaseRemove(cwd, args[2], { force: forceFlag }, raw);
1040
1178
  } else if (subcommand === 'complete') {
1041
1179
  phase.cmdPhaseComplete(cwd, args[2], raw);
1180
+ } else if (subcommand === 'finalize') {
1181
+ const push = args.includes('--push');
1182
+ phase.cmdPhaseFinalize(cwd, args[2], { push }, raw);
1042
1183
  } else {
1043
- error('Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete');
1184
+ error('Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete, finalize');
1185
+ }
1186
+ break;
1187
+ }
1188
+
1189
+ case 'plan': {
1190
+ const subcommand = args[1];
1191
+ if (subcommand === 'finalize') {
1192
+ gateIdentity();
1193
+ const push = args.includes('--push');
1194
+ const planNameIdx = args.indexOf('--plan-name');
1195
+ const planName = planNameIdx !== -1 ? args[planNameIdx + 1] : null;
1196
+ commands.cmdPlanFinalize(cwd, args[2], args[3], { push, planName }, raw);
1197
+ } else {
1198
+ error('Unknown plan subcommand. Available: finalize');
1044
1199
  }
1045
1200
  break;
1046
1201
  }
@@ -1051,6 +1206,7 @@ async function main() {
1051
1206
  if (subcommand === 'complete') {
1052
1207
  const nameIndex = args.indexOf('--name');
1053
1208
  const archivePhases = args.includes('--archive-phases');
1209
+ const force = args.includes('--force');
1054
1210
  // Collect --name value (everything after --name until next flag or end)
1055
1211
  let milestoneName = null;
1056
1212
  if (nameIndex !== -1) {
@@ -1061,7 +1217,7 @@ async function main() {
1061
1217
  }
1062
1218
  milestoneName = nameArgs.join(' ') || null;
1063
1219
  }
1064
- milestone.cmdMilestoneComplete(cwd, args[2], { name: milestoneName, archivePhases }, raw);
1220
+ milestone.cmdMilestoneComplete(cwd, args[2], { name: milestoneName, archivePhases, force }, raw);
1065
1221
  } else {
1066
1222
  error('Unknown milestone subcommand. Available: complete');
1067
1223
  }
@@ -1090,13 +1246,28 @@ async function main() {
1090
1246
  case 'todo': {
1091
1247
  const subcommand = args[1];
1092
1248
  // Gate write subcommand
1093
- if (subcommand === 'complete') {
1249
+ if (subcommand === 'complete' || subcommand === 'set-status') {
1094
1250
  gateIdentity();
1095
1251
  }
1096
1252
  if (subcommand === 'complete') {
1097
1253
  commands.cmdTodoComplete(cwd, args[2], raw);
1254
+ } else if (subcommand === 'set-status') {
1255
+ const filename = args[2];
1256
+ const statusIdx = args.indexOf('--status');
1257
+ const status = statusIdx !== -1 ? args[statusIdx + 1] : null;
1258
+ if (!filename || !status) {
1259
+ error('Usage: todo set-status <filename> --status <pending|done>');
1260
+ }
1261
+ const { setTodoStatus } = require('./lib/commands.cjs');
1262
+ try {
1263
+ const result = setTodoStatus(cwd, filename, status);
1264
+ const { output: out } = require('./lib/core.cjs');
1265
+ out(result, raw);
1266
+ } catch (err) {
1267
+ error(err.message);
1268
+ }
1098
1269
  } else {
1099
- error('Unknown todo subcommand. Available: complete');
1270
+ error('Unknown todo subcommand. Available: complete, set-status');
1100
1271
  }
1101
1272
  break;
1102
1273
  }
@@ -1124,7 +1295,7 @@ async function main() {
1124
1295
  init.cmdInitPlanPhase(cwd, args[2], raw);
1125
1296
  break;
1126
1297
  case 'new-project':
1127
- init.cmdInitNewProject(cwd, raw);
1298
+ init.cmdInitNewProject(cwd, args[2], raw);
1128
1299
  break;
1129
1300
  case 'new-milestone':
1130
1301
  init.cmdInitNewMilestone(cwd, raw);
@@ -1168,8 +1339,11 @@ async function main() {
1168
1339
  case 'progress':
1169
1340
  init.cmdInitProgress(cwd, raw);
1170
1341
  break;
1342
+ case 'progress-all':
1343
+ init.cmdInitProgressAll(cwd, raw);
1344
+ break;
1171
1345
  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`);
1346
+ 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
1347
  }
1174
1348
  break;
1175
1349
  }
@@ -1328,8 +1502,18 @@ async function main() {
1328
1502
  raw,
1329
1503
  author
1330
1504
  );
1505
+ } else if (subcommand === 'set-status') {
1506
+ // Alias for move-state (frontmatter-based)
1507
+ const idIdx = args.indexOf('--id');
1508
+ const statusIdx = args.indexOf('--status');
1509
+ const id = idIdx !== -1 ? args[idIdx + 1] : null;
1510
+ const status = statusIdx !== -1 ? args[statusIdx + 1] : null;
1511
+ if (!id || !status) {
1512
+ error('Usage: ideas set-status --id <N> --status <pending|done|rejected|consolidated>');
1513
+ }
1514
+ ideas.cmdIdeasMoveState(cwd, id, status, raw, author);
1331
1515
  } else {
1332
- error('Unknown ideas subcommand: ' + subcommand);
1516
+ 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
1517
  }
1334
1518
  break;
1335
1519
  }
@@ -1597,6 +1781,7 @@ async function main() {
1597
1781
  jobs.cmdJobsUpdateStep(cwd, args[2], args[3], args[4], { timestamp: timestampVal, error: errorVal }, raw);
1598
1782
  } else if (subcommand === 'move') {
1599
1783
  if (!args[2] || !args[3]) error('Usage: jobs move <file> <target-dir>');
1784
+ process.stderr.write('[DGS] Deprecation: "jobs move" is deprecated. Use "jobs set-status <version> --status <status>" for state transitions.\n');
1600
1785
  jobs.cmdJobsMove(cwd, args[2], args[3], raw);
1601
1786
  } else if (subcommand === 'create-milestone') {
1602
1787
  const noCheckIdx = args.indexOf('--no-check');
@@ -1669,8 +1854,28 @@ async function main() {
1669
1854
  } else if (subcommand === 'rollback') {
1670
1855
  if (!args[2]) error('Usage: jobs rollback <version>');
1671
1856
  jobs.cmdJobsRollback(cwd, args[2], raw);
1857
+ } else if (subcommand === 'generate-review') {
1858
+ const review = require('./lib/review.cjs');
1859
+ const detailed = args.includes('--detailed');
1860
+ const versionArg = args.slice(2).filter(a => a !== '--detailed' && a !== '--raw')[0];
1861
+ review.cmdJobsGenerateReview(cwd, versionArg, raw, detailed);
1862
+ } else if (subcommand === 'set-status') {
1863
+ const version = args[2];
1864
+ const statusIdx = args.indexOf('--status');
1865
+ const status = statusIdx !== -1 ? args[statusIdx + 1] : null;
1866
+ if (!version || !status) {
1867
+ error('Usage: jobs set-status <version> --status <pending|in-progress|completed|failed|rolled_back>');
1868
+ }
1869
+ const { setJobStatus } = require('./lib/jobs.cjs');
1870
+ try {
1871
+ const result = setJobStatus(cwd, version, status);
1872
+ const { output: out } = require('./lib/core.cjs');
1873
+ out(result, raw);
1874
+ } catch (err) {
1875
+ error(err.message);
1876
+ }
1672
1877
  } 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');
1878
+ 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, generate-review, record-start-shas, rollback, set-status');
1674
1879
  }
1675
1880
  break;
1676
1881
  }
@@ -1708,6 +1913,12 @@ async function main() {
1708
1913
  break;
1709
1914
  }
1710
1915
 
1916
+ case 'package-scan': {
1917
+ const packageScan = require('./lib/package-scan.cjs');
1918
+ packageScan.cmdPackageScan(cwd, args, raw);
1919
+ break;
1920
+ }
1921
+
1711
1922
  case 'phase-uat-status': {
1712
1923
  const autoTest = require('./lib/auto-test.cjs');
1713
1924
  autoTest.cmdPhaseUatStatus(cwd, args[1], raw);
@@ -1747,38 +1958,196 @@ async function main() {
1747
1958
  break;
1748
1959
  }
1749
1960
 
1961
+ case 'worktrees': {
1962
+ const subcommand = args[1];
1963
+ const worktrees = require('./lib/worktrees.cjs');
1964
+ const { output: wtOutput } = require('./lib/core.cjs');
1965
+ if (subcommand === 'create') {
1966
+ worktrees.cmdWorktreesCreate(cwd, args.slice(2));
1967
+ } else if (subcommand === 'remove') {
1968
+ worktrees.cmdWorktreesRemove(cwd, args.slice(2));
1969
+ } else if (subcommand === 'list') {
1970
+ worktrees.cmdWorktreesList(cwd, args.slice(2));
1971
+ } else if (subcommand === 'setup') {
1972
+ worktrees.cmdWorktreesSetup(cwd, args.slice(2));
1973
+ } else if (subcommand === 'prune') {
1974
+ worktrees.cmdWorktreesPrune(cwd, args.slice(2));
1975
+ } else if (subcommand === 'rebase-and-merge') {
1976
+ const slug = args[2];
1977
+ if (!slug) error('Usage: worktrees rebase-and-merge <slug> --repo <name>');
1978
+ const repoIdx = args.indexOf('--repo');
1979
+ const repoName = repoIdx !== -1 ? args[repoIdx + 1] : null;
1980
+ if (!repoName) error('--repo required for rebase-and-merge');
1981
+ const noPush = args.includes('--no-push');
1982
+ const result = worktrees.rebaseAndMerge(cwd, repoName, slug, { push: !noPush });
1983
+ wtOutput(result);
1984
+ } else if (subcommand === 'health') {
1985
+ const slug = args[2];
1986
+ if (!slug) error('Usage: worktrees health <slug>');
1987
+ const result = worktrees.checkWorktreeHealth(cwd, slug);
1988
+ wtOutput(result);
1989
+ } else {
1990
+ error('Unknown worktrees subcommand: ' + subcommand + '. Available: create, remove, list, setup, prune, rebase-and-merge, health');
1991
+ }
1992
+ break;
1993
+ }
1994
+
1750
1995
  case 'migrate': {
1751
1996
  const layoutIdx = args.indexOf('--layout');
1752
1997
  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');
1998
+
1999
+ if (layout === 'root') {
2000
+ // Existing .planning/ to root migration
2001
+ const dryRun = args.includes('--dry-run');
2002
+ const result = migrateDotPlanningToRoot(cwd, { dryRun });
2003
+ if (raw) {
2004
+ const { output: out } = require('./lib/core.cjs');
2005
+ out(result, raw);
2006
+ } else if (result.dryRun) {
2007
+ if (result.actions.length === 0) {
2008
+ process.stderr.write('Nothing to migrate. Already in root layout.\n');
2009
+ } else {
2010
+ process.stderr.write('Dry run — the following changes would be made:\n');
2011
+ for (const action of result.actions) {
2012
+ const label = action.type === 'identical' ? '(identical, delete .planning copy)' : '';
2013
+ process.stderr.write(` ${action.from} -> ${action.to} ${label}\n`);
2014
+ }
2015
+ process.stderr.write(`\n${result.filesMoved} file(s) to move, ${result.identicalResolved} identical conflict(s) to resolve.\n`);
2016
+ }
2017
+ } else if (result.migrated) {
2018
+ process.stderr.write(`Migration complete. ${result.filesMoved} file(s) moved.`);
2019
+ if (result.commitHash) process.stderr.write(` Commit: ${result.commitHash}`);
2020
+ process.stderr.write('\n');
1764
2021
  } 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`);
2022
+ process.stderr.write('Nothing to migrate. Already in root layout.\n');
2023
+ }
2024
+ } else if (layout === 'flat') {
2025
+ // Flat status migration (v20.0)
2026
+ const apply = args.includes('--apply');
2027
+ const result = migrateFlatStatus(cwd, { apply });
2028
+ if (raw) {
2029
+ const { output: out } = require('./lib/core.cjs');
2030
+ out(result, raw);
2031
+ } else if (!apply) {
2032
+ // Dry-run mode (default)
2033
+ if (result.actions.length === 0) {
2034
+ process.stderr.write('Nothing to migrate. All files already in flat layout (or migration already done).\n');
2035
+ } else {
2036
+ process.stderr.write('Dry run — the following changes would be made:\n\n');
2037
+ // Group by subsystem
2038
+ const grouped = {};
2039
+ for (const action of result.actions) {
2040
+ const key = action.subsystem || 'research';
2041
+ if (!grouped[key]) grouped[key] = [];
2042
+ grouped[key].push(action);
2043
+ }
2044
+ for (const [sub, subActions] of Object.entries(grouped)) {
2045
+ process.stderr.write(` ${sub}:\n`);
2046
+ for (const action of subActions) {
2047
+ const statusNote = action.mappedStatus ? ` (status: ${action.mappedStatus})` : '';
2048
+ process.stderr.write(` ${action.from} -> ${action.to}${statusNote}\n`);
2049
+ }
2050
+ }
2051
+ process.stderr.write(`\n${result.filesMoved} file(s) to move, ${result.statusFieldsAdded} status field(s) to add.\n`);
2052
+ process.stderr.write('\nTo apply: dgs-tools migrate --layout flat --apply\n');
1769
2053
  }
1770
- process.stderr.write(`\n${result.filesMoved} file(s) to move, ${result.identicalResolved} identical conflict(s) to resolve.\n`);
2054
+ } else if (result.migrated) {
2055
+ process.stderr.write(`Flat status migration complete. ${result.filesMoved} file(s) moved, ${result.statusFieldsAdded} status field(s) added, ${result.pathsNormalized} path(s) normalized.`);
2056
+ if (result.commitHash) process.stderr.write(` Commit: ${result.commitHash}`);
2057
+ process.stderr.write('\n');
2058
+ } else {
2059
+ process.stderr.write('Nothing to migrate. All files already in flat layout (or migration already done).\n');
1771
2060
  }
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
2061
  } else {
1777
- process.stderr.write('Nothing to migrate. Already in root layout.\n');
2062
+ error('Usage: dgs-tools migrate --layout root|flat [--dry-run] [--apply] [--raw]');
1778
2063
  }
1779
2064
  break;
1780
2065
  }
1781
2066
 
2067
+ case 'complete-quick':
2068
+ case 'quick-complete': {
2069
+ const { cmdQuickComplete } = require('./lib/quick.cjs');
2070
+ cmdQuickComplete(cwd, args);
2071
+ break;
2072
+ }
2073
+
2074
+ case 'abandon-quick':
2075
+ case 'quick-abandon': {
2076
+ const { cmdQuickAbandon } = require('./lib/quick.cjs');
2077
+ cmdQuickAbandon(cwd, args.slice(1));
2078
+ break;
2079
+ }
2080
+
2081
+ case 'quick': {
2082
+ const subcommand = args[1];
2083
+ if (subcommand === 'generate-review') {
2084
+ const review = require('./lib/review.cjs');
2085
+ const detailed = args.includes('--detailed');
2086
+ const slugArg = args.slice(2).filter(a => a !== '--detailed' && a !== '--raw')[0];
2087
+ review.cmdQuickGenerateReview(cwd, slugArg, raw, detailed);
2088
+ break;
2089
+ }
2090
+ if (subcommand !== 'finalize') {
2091
+ error('Usage: dgs-tools quick <generate-review [slug]|finalize <quick_id> [options]>');
2092
+ return;
2093
+ }
2094
+ gateIdentity();
2095
+ const quickId = args[2];
2096
+ if (!quickId) {
2097
+ error('quick_id required');
2098
+ return;
2099
+ }
2100
+
2101
+ // Parse flags starting at args[3]
2102
+ let description = null;
2103
+ let quickDir = null;
2104
+ let statePath = null;
2105
+ let push = false;
2106
+ let repoCwd = null;
2107
+ let fast = false;
2108
+
2109
+ for (let i = 3; i < args.length; i++) {
2110
+ const a = args[i];
2111
+ if (a === '--description') {
2112
+ // Multi-word: consume args until next --flag or end
2113
+ const parts = [];
2114
+ let j = i + 1;
2115
+ while (j < args.length && !args[j].startsWith('--')) {
2116
+ parts.push(args[j]);
2117
+ j++;
2118
+ }
2119
+ description = parts.join(' ');
2120
+ i = j - 1;
2121
+ } else if (a === '--quick-dir') {
2122
+ quickDir = args[++i];
2123
+ } else if (a === '--state-path') {
2124
+ statePath = args[++i];
2125
+ } else if (a === '--push') {
2126
+ push = true;
2127
+ } else if (a === '--repo-cwd') {
2128
+ repoCwd = args[++i];
2129
+ } else if (a === '--fast') {
2130
+ fast = true;
2131
+ }
2132
+ }
2133
+
2134
+ const { cmdQuickFinalize } = require('./lib/quick.cjs');
2135
+ cmdQuickFinalize(cwd, quickId, { description, quickDir, statePath, push, repoCwd, fast }, raw);
2136
+ break;
2137
+ }
2138
+
2139
+ case 'fast-route': {
2140
+ // REL-05/06: fast-mode commit routing helper. Surveys planning root +
2141
+ // registered sub-repos for dirty state, then computes a routing decision.
2142
+ // Used by /dgs:fast workflow F0.5 (pre-edit dirt check, REL-06) and F4/F5
2143
+ // (post-edit routing, REL-05). Exits 1 if action == 'fail'.
2144
+ const { surveyDirty, decideRouting } = require('./lib/fast-routing.cjs');
2145
+ const survey = surveyDirty(cwd);
2146
+ const decision = decideRouting(survey);
2147
+ process.stdout.write(JSON.stringify({ survey, decision }, null, 2));
2148
+ process.exit(decision.action === 'fail' ? 1 : 0);
2149
+ }
2150
+
1782
2151
  default:
1783
2152
  error(`Unknown command: ${command}`);
1784
2153
  }