@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
@@ -4,32 +4,29 @@
4
4
 
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
- const { escapeRegex, getMilestonePhaseFilter, output, error } = require('./core.cjs');
7
+ const { escapeRegex, getMilestonePhaseFilter, getProjectRoot, output, error } = require('./core.cjs');
8
8
  const { extractFrontmatter } = require('./frontmatter.cjs');
9
9
  const { getPlanningRoot } = require('./paths.cjs');
10
10
  const { writeStateMd } = require('./state.cjs');
11
11
 
12
- function cmdRequirementsMarkComplete(cwd, reqIdsRaw, raw) {
13
- if (!reqIdsRaw || reqIdsRaw.length === 0) {
14
- error('requirement IDs required. Usage: requirements mark-complete REQ-01,REQ-02 or REQ-01 REQ-02');
15
- }
16
-
17
- // Accept comma-separated, space-separated, or bracket-wrapped: [REQ-01, REQ-02]
18
- const reqIds = reqIdsRaw
19
- .join(' ')
20
- .replace(/[\[\]]/g, '')
21
- .split(/[,\s]+/)
22
- .map(r => r.trim())
23
- .filter(Boolean);
24
-
25
- if (reqIds.length === 0) {
12
+ /**
13
+ * Internal helper: marks requirement IDs complete in REQUIREMENTS.md.
14
+ * Accepts an already-parsed array of IDs. Returns { result, reqPath, rawValue }
15
+ * WITHOUT calling output()/exit.
16
+ */
17
+ function requirementsMarkCompleteInternal(cwd, reqIds) {
18
+ if (!Array.isArray(reqIds) || reqIds.length === 0) {
26
19
  error('no valid requirement IDs found');
27
20
  }
28
21
 
29
- const reqPath = path.join(getPlanningRoot(cwd), 'REQUIREMENTS.md');
22
+ const projectRootRel = getProjectRoot(cwd);
23
+ const reqPath = path.join(getPlanningRoot(cwd), projectRootRel, 'REQUIREMENTS.md');
30
24
  if (!fs.existsSync(reqPath)) {
31
- output({ updated: false, reason: 'REQUIREMENTS.md not found', ids: reqIds }, raw, 'no requirements file');
32
- return;
25
+ return {
26
+ result: { updated: false, reason: 'REQUIREMENTS.md not found', ids: reqIds },
27
+ reqPath,
28
+ rawValue: 'no requirements file',
29
+ };
33
30
  }
34
31
 
35
32
  let reqContent = fs.readFileSync(reqPath, 'utf-8');
@@ -69,12 +66,37 @@ function cmdRequirementsMarkComplete(cwd, reqIdsRaw, raw) {
69
66
  fs.writeFileSync(reqPath, reqContent, 'utf-8');
70
67
  }
71
68
 
72
- output({
73
- updated: updated.length > 0,
74
- marked_complete: updated,
75
- not_found: notFound,
76
- total: reqIds.length,
77
- }, raw, `${updated.length}/${reqIds.length} requirements marked complete`);
69
+ return {
70
+ result: {
71
+ updated: updated.length > 0,
72
+ marked_complete: updated,
73
+ not_found: notFound,
74
+ total: reqIds.length,
75
+ },
76
+ reqPath,
77
+ rawValue: `${updated.length}/${reqIds.length} requirements marked complete`,
78
+ };
79
+ }
80
+
81
+ function cmdRequirementsMarkComplete(cwd, reqIdsRaw, raw) {
82
+ if (!reqIdsRaw || reqIdsRaw.length === 0) {
83
+ error('requirement IDs required. Usage: requirements mark-complete REQ-01,REQ-02 or REQ-01 REQ-02');
84
+ }
85
+
86
+ // Accept comma-separated, space-separated, or bracket-wrapped: [REQ-01, REQ-02]
87
+ const reqIds = reqIdsRaw
88
+ .join(' ')
89
+ .replace(/[\[\]]/g, '')
90
+ .split(/[,\s]+/)
91
+ .map(r => r.trim())
92
+ .filter(Boolean);
93
+
94
+ if (reqIds.length === 0) {
95
+ error('no valid requirement IDs found');
96
+ }
97
+
98
+ const { result, rawValue } = requirementsMarkCompleteInternal(cwd, reqIds);
99
+ output(result, raw, rawValue);
78
100
  }
79
101
 
80
102
  function cmdMilestoneComplete(cwd, version, options, raw) {
@@ -83,12 +105,14 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
83
105
  }
84
106
 
85
107
  const planRoot = getPlanningRoot(cwd);
86
- const roadmapPath = path.join(planRoot, 'ROADMAP.md');
87
- const reqPath = path.join(planRoot, 'REQUIREMENTS.md');
88
- const statePath = path.join(planRoot, 'STATE.md');
108
+ const projectRootRel = getProjectRoot(cwd);
109
+ const projectRoot = path.join(planRoot, projectRootRel);
110
+ const roadmapPath = path.join(projectRoot, 'ROADMAP.md');
111
+ const reqPath = path.join(projectRoot, 'REQUIREMENTS.md');
112
+ const statePath = path.join(projectRoot, 'STATE.md');
89
113
  const milestonesPath = path.join(planRoot, 'MILESTONES.md');
90
114
  const archiveDir = path.join(planRoot, 'milestones');
91
- const phasesDir = path.join(planRoot, 'phases');
115
+ const phasesDir = path.join(projectRoot, 'phases');
92
116
  const today = new Date().toISOString().split('T')[0];
93
117
  const milestoneName = options.name || version;
94
118
 
@@ -149,7 +173,7 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
149
173
  }
150
174
 
151
175
  // Archive audit file if exists
152
- const auditFile = path.join(planRoot, `${version}-MILESTONE-AUDIT.md`);
176
+ const auditFile = path.join(projectRoot, `${version}-MILESTONE-AUDIT.md`);
153
177
  if (fs.existsSync(auditFile)) {
154
178
  fs.renameSync(auditFile, path.join(archiveDir, `${version}-MILESTONE-AUDIT.md`));
155
179
  }
@@ -239,5 +263,6 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
239
263
 
240
264
  module.exports = {
241
265
  cmdRequirementsMarkComplete,
266
+ requirementsMarkCompleteInternal,
242
267
  cmdMilestoneComplete,
243
268
  };
@@ -4,7 +4,7 @@
4
4
 
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
- const { escapeRegex, normalizePhaseName, comparePhaseNum, findPhaseInternal, getArchivedPhaseDirs, generateSlugInternal, getMilestonePhaseFilter, toPosixPath, output, error, getProjectRoot } = require('./core.cjs');
7
+ const { escapeRegex, normalizePhaseName, comparePhaseNum, findPhaseInternal, getArchivedPhaseDirs, generateSlugInternal, getMilestonePhaseFilter, toPosixPath, output, error, getProjectRoot, loadConfig, execGit } = require('./core.cjs');
8
8
  const { extractFrontmatter } = require('./frontmatter.cjs');
9
9
  const { writeStateMd } = require('./state.cjs');
10
10
 
@@ -381,6 +381,17 @@ function cmdPhaseAdd(cwd, description, raw) {
381
381
  updatedContent = content + phaseEntry;
382
382
  }
383
383
 
384
+ // Update milestone summary range (e.g., "Phases 124-128" -> "Phases 124-129")
385
+ const rangePattern = /Phases\s+(\d+)-(\d+)\s*\(in progress\)/;
386
+ const rangeMatch = updatedContent.match(rangePattern);
387
+ if (rangeMatch) {
388
+ const rangeEnd = parseInt(rangeMatch[2], 10);
389
+ if (newPhaseNum > rangeEnd) {
390
+ updatedContent = updatedContent.replace(rangePattern,
391
+ `Phases ${rangeMatch[1]}-${newPhaseNum} (in progress)`);
392
+ }
393
+ }
394
+
384
395
  fs.writeFileSync(roadmapPath, updatedContent, 'utf-8');
385
396
 
386
397
  const relPhasesDir = path.relative(cwd, phasesDir);
@@ -732,7 +743,16 @@ function cmdPhaseRemove(cwd, targetPhase, options, raw) {
732
743
  output(result, raw);
733
744
  }
734
745
 
735
- function cmdPhaseComplete(cwd, phaseNum, raw) {
746
+ /**
747
+ * Internal helper: executes the phase-complete logic (ROADMAP/STATE/REQUIREMENTS
748
+ * updates + next-phase lookup) WITHOUT emitting output/exit.
749
+ *
750
+ * Returns { result, roadmapPath, statePath, requirementsPath, phaseDir }.
751
+ * The `result` object matches what cmdPhaseComplete emits. Paths are absolute.
752
+ * `requirementsPath` is returned even when the file doesn't exist (caller decides).
753
+ * `phaseDir` is the absolute path to the phase directory on disk.
754
+ */
755
+ function phaseCompleteInternal(cwd, phaseNum) {
736
756
  if (!phaseNum) {
737
757
  error('phase number required for phase complete');
738
758
  }
@@ -740,6 +760,7 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
740
760
  const projRoot = resolveProjectRoot(cwd);
741
761
  const roadmapPath = path.join(cwd, projRoot, 'ROADMAP.md');
742
762
  const statePath = path.join(cwd, projRoot, 'STATE.md');
763
+ const requirementsPath = path.join(cwd, projRoot, 'REQUIREMENTS.md');
743
764
  const phasesDir = resolvePhasesDir(cwd);
744
765
  const normalized = normalizePhaseName(phaseNum);
745
766
  const today = new Date().toISOString().split('T')[0];
@@ -750,6 +771,11 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
750
771
  error(`Phase ${phaseNum} not found`);
751
772
  }
752
773
 
774
+ // Absolute phase directory (phaseInfo.directory is relative to cwd)
775
+ const phaseDir = phaseInfo.directory
776
+ ? path.join(cwd, phaseInfo.directory)
777
+ : null;
778
+
753
779
  const planCount = phaseInfo.plans.length;
754
780
  const summaryCount = phaseInfo.summaries.length;
755
781
 
@@ -896,6 +922,104 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
896
922
  state_updated: fs.existsSync(statePath),
897
923
  };
898
924
 
925
+ return { result, roadmapPath, statePath, requirementsPath, phaseDir };
926
+ }
927
+
928
+ /**
929
+ * CLI: `phase complete <phase>`. Thin wrapper over phaseCompleteInternal that
930
+ * emits the result and exits. External behavior unchanged from prior versions.
931
+ */
932
+ function cmdPhaseComplete(cwd, phaseNum, raw) {
933
+ const { result } = phaseCompleteInternal(cwd, phaseNum);
934
+ output(result, raw);
935
+ }
936
+
937
+ /**
938
+ * CLI: `phase finalize <phase> [--push]`.
939
+ *
940
+ * Runs phaseCompleteInternal (ROADMAP/STATE/REQUIREMENTS updates) AND commits
941
+ * the modified tracking files + any `*-VERIFICATION.md` files in the phase dir
942
+ * in a single atomic call. Respects config.commit_docs (skip commit if false;
943
+ * still writes files). Handles --push for sync_push=auto|prompt modes.
944
+ *
945
+ * Does NOT call cmdCommit (which exits). Uses execGit directly.
946
+ */
947
+ function cmdPhaseFinalize(cwd, phaseNum, options, raw) {
948
+ if (!phaseNum) {
949
+ error('phase number required for phase finalize');
950
+ }
951
+
952
+ const { result, roadmapPath, statePath, requirementsPath, phaseDir } =
953
+ phaseCompleteInternal(cwd, phaseNum);
954
+
955
+ // Gather tracking files that exist on disk (skip missing files gracefully)
956
+ const filesToStage = [];
957
+ for (const p of [roadmapPath, statePath, requirementsPath]) {
958
+ if (p && fs.existsSync(p)) {
959
+ filesToStage.push(path.relative(cwd, p));
960
+ }
961
+ }
962
+ // Include every *-VERIFICATION.md in the phase directory
963
+ if (phaseDir && fs.existsSync(phaseDir)) {
964
+ try {
965
+ const entries = fs.readdirSync(phaseDir).filter(f => /-VERIFICATION\.md$/i.test(f));
966
+ for (const f of entries) {
967
+ filesToStage.push(path.relative(cwd, path.join(phaseDir, f)));
968
+ }
969
+ } catch { /* ignore */ }
970
+ }
971
+
972
+ // Honor config.commit_docs — file writes already happened, just skip commit.
973
+ const config = loadConfig(cwd);
974
+ if (!config.commit_docs) {
975
+ result.committed = false;
976
+ result.commit_reason = 'skipped_commit_docs_false';
977
+ result.files_committed = [];
978
+ output(result, raw);
979
+ return;
980
+ }
981
+
982
+ // Stage + commit atomically (cmdCommit calls output/exit — inline instead).
983
+ for (const f of filesToStage) {
984
+ execGit(cwd, ['add', f]);
985
+ }
986
+ const message = `docs(phase-${phaseNum}): complete phase execution`;
987
+ const commitResult = execGit(cwd, ['commit', '-m', message]);
988
+ if (commitResult.exitCode !== 0) {
989
+ const nothing =
990
+ commitResult.stdout.includes('nothing to commit') ||
991
+ commitResult.stderr.includes('nothing to commit');
992
+ result.committed = false;
993
+ result.commit_reason = nothing ? 'nothing_to_commit' : 'commit_failed';
994
+ if (!nothing) result.commit_error = commitResult.stderr;
995
+ result.files_committed = [];
996
+ output(result, raw);
997
+ return;
998
+ }
999
+ const hashResult = execGit(cwd, ['rev-parse', '--short', 'HEAD']);
1000
+ result.committed = true;
1001
+ result.hash = hashResult.exitCode === 0 ? hashResult.stdout : null;
1002
+ result.commit_reason = 'committed';
1003
+ result.files_committed = filesToStage;
1004
+
1005
+ // Optional push (same semantics as cmdCommit)
1006
+ if (options && options.push) {
1007
+ const syncPush = config.sync_push || 'off';
1008
+ if (syncPush === 'auto') {
1009
+ try {
1010
+ const { pushAll } = require('./sync.cjs');
1011
+ const pushRes = pushAll(cwd, { force: true });
1012
+ result.pushed = pushRes.ok;
1013
+ result.push_result = pushRes;
1014
+ } catch (err) {
1015
+ result.pushed = false;
1016
+ result.push_result = { ok: false, error: err.message };
1017
+ }
1018
+ } else if (syncPush === 'prompt') {
1019
+ result.needs_push = true;
1020
+ }
1021
+ }
1022
+
899
1023
  output(result, raw);
900
1024
  }
901
1025
 
@@ -908,4 +1032,6 @@ module.exports = {
908
1032
  cmdPhaseInsert,
909
1033
  cmdPhaseRemove,
910
1034
  cmdPhaseComplete,
1035
+ cmdPhaseFinalize,
1036
+ phaseCompleteInternal,
911
1037
  };