@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.
- package/CHANGELOG.md +96 -0
- package/README.md +41 -13
- package/agents/dgs-plan-checker.md +29 -3
- package/agents/dgs-planner.md +10 -0
- package/commands/dgs/abandon-quick.md +28 -0
- package/commands/dgs/add-tests.md +2 -2
- package/commands/dgs/audit-milestone.md +2 -2
- package/commands/dgs/capture-principle.md +11 -11
- package/commands/dgs/cleanup.md +2 -2
- package/commands/dgs/complete-milestone.md +11 -11
- package/commands/dgs/complete-quick.md +28 -0
- package/commands/dgs/create-milestone-job.md +2 -2
- package/commands/dgs/debug.md +3 -3
- package/commands/dgs/develop-idea.md +1 -1
- package/commands/dgs/fast.md +3 -1
- package/commands/dgs/health.md +1 -1
- package/commands/dgs/map-codebase.md +6 -6
- package/commands/dgs/new-milestone.md +5 -5
- package/commands/dgs/new-project.md +6 -6
- package/commands/dgs/plan-milestone-gaps.md +1 -1
- package/commands/dgs/progress.md +3 -3
- package/commands/dgs/quick-abandon.md +8 -0
- package/commands/dgs/quick-complete.md +8 -0
- package/commands/dgs/quick.md +10 -3
- package/commands/dgs/research-idea.md +2 -2
- package/commands/dgs/research-phase.md +3 -3
- package/commands/dgs/switch-project.md +1 -1
- package/commands/dgs/write-spec.md +3 -3
- package/deliver-great-systems/bin/dgs-tools.cjs +284 -30
- package/deliver-great-systems/bin/lib/commands.cjs +316 -31
- package/deliver-great-systems/bin/lib/commands.test.cjs +336 -0
- package/deliver-great-systems/bin/lib/config.cjs +39 -6
- package/deliver-great-systems/bin/lib/context.cjs +120 -0
- package/deliver-great-systems/bin/lib/core.cjs +28 -11
- package/deliver-great-systems/bin/lib/execution.cjs +49 -17
- package/deliver-great-systems/bin/lib/flat-migration.test.cjs +396 -0
- package/deliver-great-systems/bin/lib/ideas.cjs +206 -91
- package/deliver-great-systems/bin/lib/ideas.test.cjs +244 -1
- package/deliver-great-systems/bin/lib/init.cjs +306 -39
- package/deliver-great-systems/bin/lib/init.test.cjs +416 -6
- package/deliver-great-systems/bin/lib/jobs.cjs +124 -21
- package/deliver-great-systems/bin/lib/jobs.test.cjs +193 -74
- package/deliver-great-systems/bin/lib/migration.cjs +409 -1
- package/deliver-great-systems/bin/lib/migration.test.cjs +158 -1
- package/deliver-great-systems/bin/lib/milestone.cjs +54 -29
- package/deliver-great-systems/bin/lib/phase.cjs +128 -2
- package/deliver-great-systems/bin/lib/phase.test.cjs +420 -0
- package/deliver-great-systems/bin/lib/projects.cjs +28 -8
- package/deliver-great-systems/bin/lib/projects.test.cjs +86 -0
- package/deliver-great-systems/bin/lib/quick.cjs +584 -0
- package/deliver-great-systems/bin/lib/quick.test.cjs +596 -0
- package/deliver-great-systems/bin/lib/repos.cjs +25 -1
- package/deliver-great-systems/bin/lib/roadmap.cjs +34 -13
- package/deliver-great-systems/bin/lib/specs.cjs +3 -81
- package/deliver-great-systems/bin/lib/state-transition-gate.test.cjs +160 -0
- package/deliver-great-systems/bin/lib/state.cjs +142 -54
- package/deliver-great-systems/bin/lib/sync.cjs +75 -0
- package/deliver-great-systems/bin/lib/verify.cjs +80 -1
- package/deliver-great-systems/bin/lib/worktrees.cjs +764 -0
- package/deliver-great-systems/bin/lib/worktrees.test.cjs +887 -0
- package/deliver-great-systems/templates/claude-md.md +16 -0
- package/deliver-great-systems/workflows/abandon-quick.md +89 -0
- package/deliver-great-systems/workflows/add-idea.md +3 -3
- package/deliver-great-systems/workflows/add-tests.md +14 -0
- package/deliver-great-systems/workflows/add-todo.md +1 -0
- package/deliver-great-systems/workflows/approve-spec.md +25 -4
- package/deliver-great-systems/workflows/audit-phase.md +15 -5
- package/deliver-great-systems/workflows/cancel-job.md +1 -1
- package/deliver-great-systems/workflows/check-todos.md +2 -3
- package/deliver-great-systems/workflows/complete-milestone.md +197 -22
- package/deliver-great-systems/workflows/complete-quick.md +68 -0
- package/deliver-great-systems/workflows/consolidate-ideas.md +1 -1
- package/deliver-great-systems/workflows/create-milestone-job.md +4 -4
- package/deliver-great-systems/workflows/develop-idea.md +11 -11
- package/deliver-great-systems/workflows/diagnose-issues.md +14 -0
- package/deliver-great-systems/workflows/discuss-idea.md +1 -1
- package/deliver-great-systems/workflows/execute-phase.md +121 -32
- package/deliver-great-systems/workflows/execute-plan.md +12 -21
- package/deliver-great-systems/workflows/help.md +33 -29
- package/deliver-great-systems/workflows/init-product.md +2 -18
- package/deliver-great-systems/workflows/new-milestone.md +40 -24
- package/deliver-great-systems/workflows/new-project.md +22 -680
- package/deliver-great-systems/workflows/progress-all.md +133 -0
- package/deliver-great-systems/workflows/quick-abandon.md +89 -0
- package/deliver-great-systems/workflows/quick-complete.md +68 -0
- package/deliver-great-systems/workflows/quick.md +152 -23
- package/deliver-great-systems/workflows/refine-spec.md +1 -1
- package/deliver-great-systems/workflows/research-idea.md +8 -8
- package/deliver-great-systems/workflows/resume-project.md +2 -2
- package/deliver-great-systems/workflows/run-job.md +8 -8
- package/deliver-great-systems/workflows/validate-phase.md +39 -1
- package/deliver-great-systems/workflows/verify-work.md +14 -0
- package/deliver-great-systems/workflows/write-spec.md +2 -2
- 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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
22
|
+
const projectRootRel = getProjectRoot(cwd);
|
|
23
|
+
const reqPath = path.join(getPlanningRoot(cwd), projectRootRel, 'REQUIREMENTS.md');
|
|
30
24
|
if (!fs.existsSync(reqPath)) {
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
87
|
-
const
|
|
88
|
-
const
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
};
|