@ktpartners/dgs-platform 2.7.5 → 2.8.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.
- package/CHANGELOG.md +16 -0
- package/agents/dgs-executor.md +0 -52
- package/deliver-great-systems/bin/dgs-tools.cjs +66 -10
- package/deliver-great-systems/bin/lib/commands.cjs +1 -8
- package/deliver-great-systems/bin/lib/config.cjs +9 -90
- package/deliver-great-systems/bin/lib/context.cjs +2 -2
- package/deliver-great-systems/bin/lib/context.test.cjs +100 -100
- package/deliver-great-systems/bin/lib/core.cjs +17 -57
- package/deliver-great-systems/bin/lib/core.test.cjs +166 -170
- package/deliver-great-systems/bin/lib/docs.cjs +3 -3
- package/deliver-great-systems/bin/lib/docs.test.cjs +14 -7
- package/deliver-great-systems/bin/lib/execution.cjs +2 -2
- package/deliver-great-systems/bin/lib/execution.test.cjs +65 -67
- package/deliver-great-systems/bin/lib/ideas.cjs +4 -4
- package/deliver-great-systems/bin/lib/ideas.test.cjs +45 -44
- package/deliver-great-systems/bin/lib/init.cjs +9 -4
- package/deliver-great-systems/bin/lib/init.test.cjs +242 -175
- package/deliver-great-systems/bin/lib/jobs.cjs +1 -1
- package/deliver-great-systems/bin/lib/jobs.test.cjs +203 -202
- package/deliver-great-systems/bin/lib/migration.cjs +256 -281
- package/deliver-great-systems/bin/lib/migration.test.cjs +385 -440
- package/deliver-great-systems/bin/lib/milestone.cjs +1 -1
- package/deliver-great-systems/bin/lib/overlap.cjs +4 -4
- package/deliver-great-systems/bin/lib/overlap.test.cjs +45 -44
- package/deliver-great-systems/bin/lib/path-audit.test.cjs +16 -22
- package/deliver-great-systems/bin/lib/paths.cjs +60 -59
- package/deliver-great-systems/bin/lib/paths.test.cjs +192 -225
- package/deliver-great-systems/bin/lib/phase.cjs +5 -4
- package/deliver-great-systems/bin/lib/projects.cjs +8 -8
- package/deliver-great-systems/bin/lib/projects.test.cjs +75 -74
- package/deliver-great-systems/bin/lib/repos.cjs +94 -230
- package/deliver-great-systems/bin/lib/repos.test.cjs +84 -75
- package/deliver-great-systems/bin/lib/search.cjs +4 -4
- package/deliver-great-systems/bin/lib/specs.cjs +2 -2
- package/deliver-great-systems/bin/lib/sync.cjs +1 -1
- package/deliver-great-systems/bin/lib/template.cjs +3 -3
- package/deliver-great-systems/bin/lib/test-helpers.cjs +59 -162
- package/deliver-great-systems/bin/lib/verify.cjs +3 -3
- package/deliver-great-systems/references/planning-config.md +7 -8
- package/deliver-great-systems/workflows/add-tests.md +1 -1
- package/deliver-great-systems/workflows/approve-spec.md +1 -11
- package/deliver-great-systems/workflows/complete-milestone.md +2 -2
- package/deliver-great-systems/workflows/consolidate-ideas.md +1 -1
- package/deliver-great-systems/workflows/create-milestone-job.md +2 -2
- package/deliver-great-systems/workflows/discuss-phase.md +2 -2
- package/deliver-great-systems/workflows/execute-phase.md +63 -4
- package/deliver-great-systems/workflows/execute-plan.md +0 -51
- package/deliver-great-systems/workflows/find-related-ideas.md +1 -1
- package/deliver-great-systems/workflows/help.md +25 -58
- package/deliver-great-systems/workflows/init-product.md +14 -451
- package/deliver-great-systems/workflows/map-codebase.md +109 -0
- package/deliver-great-systems/workflows/new-project.md +0 -1
- package/deliver-great-systems/workflows/quick.md +2 -2
- package/deliver-great-systems/workflows/run-job.md +56 -0
- package/package.json +1 -1
|
@@ -676,8 +676,8 @@ describe('jobs', () => {
|
|
|
676
676
|
assert.equal(steps[1].args, '50 --non-interactive');
|
|
677
677
|
assert.equal(steps[2].command, 'execute-phase');
|
|
678
678
|
assert.equal(steps[2].args, '50 --non-interactive');
|
|
679
|
-
assert.equal(steps[3].command, '
|
|
680
|
-
assert.equal(steps[3].args, '50
|
|
679
|
+
assert.equal(steps[3].command, 'audit-phase');
|
|
680
|
+
assert.equal(steps[3].args, '50');
|
|
681
681
|
});
|
|
682
682
|
|
|
683
683
|
it('produces 4 steps for unplanned phase (empty)', () => {
|
|
@@ -690,7 +690,7 @@ describe('jobs', () => {
|
|
|
690
690
|
assert.equal(steps[0].command, 'map-codebase');
|
|
691
691
|
assert.equal(steps[1].command, 'plan-phase');
|
|
692
692
|
assert.equal(steps[2].command, 'execute-phase');
|
|
693
|
-
assert.equal(steps[3].command, '
|
|
693
|
+
assert.equal(steps[3].command, 'audit-phase');
|
|
694
694
|
});
|
|
695
695
|
|
|
696
696
|
it('produces 4 steps for discussed phase (context but no plan)', () => {
|
|
@@ -703,7 +703,7 @@ describe('jobs', () => {
|
|
|
703
703
|
assert.equal(steps[0].command, 'map-codebase');
|
|
704
704
|
assert.equal(steps[1].command, 'plan-phase');
|
|
705
705
|
assert.equal(steps[2].command, 'execute-phase');
|
|
706
|
-
assert.equal(steps[3].command, '
|
|
706
|
+
assert.equal(steps[3].command, 'audit-phase');
|
|
707
707
|
});
|
|
708
708
|
|
|
709
709
|
it('produces 4 steps for researched phase', () => {
|
|
@@ -716,7 +716,7 @@ describe('jobs', () => {
|
|
|
716
716
|
assert.equal(steps[0].command, 'map-codebase');
|
|
717
717
|
assert.equal(steps[1].command, 'plan-phase');
|
|
718
718
|
assert.equal(steps[2].command, 'execute-phase');
|
|
719
|
-
assert.equal(steps[3].command, '
|
|
719
|
+
assert.equal(steps[3].command, 'audit-phase');
|
|
720
720
|
});
|
|
721
721
|
|
|
722
722
|
it('produces 2 steps for planned phase', () => {
|
|
@@ -728,8 +728,8 @@ describe('jobs', () => {
|
|
|
728
728
|
assert.equal(steps.length, 2);
|
|
729
729
|
assert.equal(steps[0].command, 'execute-phase');
|
|
730
730
|
assert.equal(steps[0].args, '50 --non-interactive');
|
|
731
|
-
assert.equal(steps[1].command, '
|
|
732
|
-
assert.equal(steps[1].args, '50
|
|
731
|
+
assert.equal(steps[1].command, 'audit-phase');
|
|
732
|
+
assert.equal(steps[1].args, '50');
|
|
733
733
|
});
|
|
734
734
|
|
|
735
735
|
it('produces 2 steps for partially executed phase', () => {
|
|
@@ -740,8 +740,8 @@ describe('jobs', () => {
|
|
|
740
740
|
|
|
741
741
|
assert.equal(steps.length, 2);
|
|
742
742
|
assert.equal(steps[0].command, 'execute-phase');
|
|
743
|
-
assert.equal(steps[1].command, '
|
|
744
|
-
assert.equal(steps[1].args, '50
|
|
743
|
+
assert.equal(steps[1].command, 'audit-phase');
|
|
744
|
+
assert.equal(steps[1].args, '50');
|
|
745
745
|
});
|
|
746
746
|
|
|
747
747
|
it('produces 0 steps for completed phase (disk_status complete)', () => {
|
|
@@ -776,16 +776,16 @@ describe('jobs', () => {
|
|
|
776
776
|
assert.equal(steps.length, 6);
|
|
777
777
|
assert.equal(steps[0].command, 'execute-phase');
|
|
778
778
|
assert.equal(steps[0].args, '50 --non-interactive');
|
|
779
|
-
assert.equal(steps[1].command, '
|
|
780
|
-
assert.equal(steps[1].args, '50
|
|
779
|
+
assert.equal(steps[1].command, 'audit-phase');
|
|
780
|
+
assert.equal(steps[1].args, '50');
|
|
781
781
|
assert.equal(steps[2].command, 'map-codebase');
|
|
782
782
|
assert.equal(steps[2].args, '51 --auto');
|
|
783
783
|
assert.equal(steps[3].command, 'plan-phase');
|
|
784
784
|
assert.equal(steps[3].args, '51 --non-interactive');
|
|
785
785
|
assert.equal(steps[4].command, 'execute-phase');
|
|
786
786
|
assert.equal(steps[4].args, '51 --non-interactive');
|
|
787
|
-
assert.equal(steps[5].command, '
|
|
788
|
-
assert.equal(steps[5].args, '51
|
|
787
|
+
assert.equal(steps[5].command, 'audit-phase');
|
|
788
|
+
assert.equal(steps[5].args, '51');
|
|
789
789
|
});
|
|
790
790
|
|
|
791
791
|
it('appends audit and complete steps when check=true', () => {
|
|
@@ -855,7 +855,7 @@ describe('jobs', () => {
|
|
|
855
855
|
assert.equal(steps[6].args, '51 --non-interactive');
|
|
856
856
|
});
|
|
857
857
|
|
|
858
|
-
it('includes correct flags on plan-phase (--non-interactive), execute-phase (--non-interactive),
|
|
858
|
+
it('includes correct flags on plan-phase (--non-interactive), execute-phase (--non-interactive), map-codebase (--auto), and audit-phase (phase number only) steps', () => {
|
|
859
859
|
const phases = [
|
|
860
860
|
{ number: '50', name: 'Job Creation', disk_status: 'no_directory', roadmap_complete: false },
|
|
861
861
|
];
|
|
@@ -864,12 +864,12 @@ describe('jobs', () => {
|
|
|
864
864
|
const mapStep = steps.find(s => s.command === 'map-codebase');
|
|
865
865
|
const planStep = steps.find(s => s.command === 'plan-phase');
|
|
866
866
|
const executeStep = steps.find(s => s.command === 'execute-phase');
|
|
867
|
-
const
|
|
867
|
+
const auditStep = steps.find(s => s.command === 'audit-phase');
|
|
868
868
|
|
|
869
869
|
assert.ok(mapStep.args.includes('--auto'), 'map-codebase should have --auto');
|
|
870
870
|
assert.ok(planStep.args.includes('--non-interactive'), 'plan-phase should have --non-interactive');
|
|
871
871
|
assert.ok(executeStep.args.includes('--non-interactive'), 'execute-phase should have --non-interactive');
|
|
872
|
-
assert.
|
|
872
|
+
assert.strictEqual(auditStep.args, '50', 'audit-phase should have just the phase number');
|
|
873
873
|
});
|
|
874
874
|
|
|
875
875
|
it('sorts phases by number numerically, not lexicographically', () => {
|
|
@@ -883,9 +883,9 @@ describe('jobs', () => {
|
|
|
883
883
|
// Phase 49 complete (0 steps), Phase 50 planned (2 steps), Phase 51 planned (2 steps) = 4
|
|
884
884
|
assert.equal(steps.length, 4);
|
|
885
885
|
assert.equal(steps[0].args, '50 --non-interactive');
|
|
886
|
-
assert.equal(steps[1].args, '50
|
|
886
|
+
assert.equal(steps[1].args, '50');
|
|
887
887
|
assert.equal(steps[2].args, '51 --non-interactive');
|
|
888
|
-
assert.equal(steps[3].args, '51
|
|
888
|
+
assert.equal(steps[3].args, '51');
|
|
889
889
|
});
|
|
890
890
|
|
|
891
891
|
it('returns steps as objects with command and args properties', () => {
|
|
@@ -914,17 +914,18 @@ describe('jobs', () => {
|
|
|
914
914
|
}
|
|
915
915
|
});
|
|
916
916
|
|
|
917
|
-
it('
|
|
917
|
+
it('audit-phase steps use just the phase number (no extra flags)', () => {
|
|
918
918
|
const phases = [
|
|
919
919
|
{ number: '50', name: 'Job Creation', disk_status: 'planned', roadmap_complete: false },
|
|
920
920
|
{ number: '51', name: 'Job Execution', disk_status: 'no_directory', roadmap_complete: false },
|
|
921
921
|
];
|
|
922
922
|
const steps = generateMilestoneSteps(phases, { check: false, version: 'v6.0' });
|
|
923
923
|
|
|
924
|
-
const
|
|
925
|
-
assert.ok(
|
|
926
|
-
for (const step of
|
|
927
|
-
assert.
|
|
924
|
+
const auditSteps = steps.filter(s => s.command === 'audit-phase');
|
|
925
|
+
assert.ok(auditSteps.length > 0, 'Should have audit-phase steps');
|
|
926
|
+
for (const step of auditSteps) {
|
|
927
|
+
assert.strictEqual(step.args, step.args.trim(), 'audit-phase args should be just the phase number');
|
|
928
|
+
assert.ok(!step.args.includes('--'), 'audit-phase should not have flag arguments');
|
|
928
929
|
}
|
|
929
930
|
});
|
|
930
931
|
|
|
@@ -1070,13 +1071,13 @@ Plans:
|
|
|
1070
1071
|
|
|
1071
1072
|
it('auto-detects active milestone version from ROADMAP.md', () => {
|
|
1072
1073
|
fixture = createFixture({
|
|
1073
|
-
'
|
|
1074
|
-
'
|
|
1075
|
-
'
|
|
1076
|
-
'
|
|
1077
|
-
'
|
|
1078
|
-
'
|
|
1079
|
-
'
|
|
1074
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1075
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1076
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1077
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1078
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1079
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1080
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1080
1081
|
});
|
|
1081
1082
|
|
|
1082
1083
|
const result = cmdJobsCreateMilestone(fixture.cwd, null, true, false);
|
|
@@ -1084,15 +1085,15 @@ Plans:
|
|
|
1084
1085
|
assert.equal(result.created, true);
|
|
1085
1086
|
});
|
|
1086
1087
|
|
|
1087
|
-
it('writes job file to
|
|
1088
|
+
it('writes job file to jobs/pending/', () => {
|
|
1088
1089
|
fixture = createFixture({
|
|
1089
|
-
'
|
|
1090
|
-
'
|
|
1091
|
-
'
|
|
1092
|
-
'
|
|
1093
|
-
'
|
|
1094
|
-
'
|
|
1095
|
-
'
|
|
1090
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1091
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1092
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1093
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1094
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1095
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1096
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1096
1097
|
});
|
|
1097
1098
|
|
|
1098
1099
|
const result = cmdJobsCreateMilestone(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1103,19 +1104,19 @@ Plans:
|
|
|
1103
1104
|
assert.ok(fs.existsSync(jobFilePath), 'Job file should exist on disk');
|
|
1104
1105
|
});
|
|
1105
1106
|
|
|
1106
|
-
it('auto-creates
|
|
1107
|
+
it('auto-creates jobs/pending/ directory', () => {
|
|
1107
1108
|
fixture = createFixture({
|
|
1108
|
-
'
|
|
1109
|
-
'
|
|
1110
|
-
'
|
|
1111
|
-
'
|
|
1112
|
-
'
|
|
1113
|
-
'
|
|
1114
|
-
'
|
|
1109
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1110
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1111
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1112
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1113
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1114
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1115
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1115
1116
|
});
|
|
1116
1117
|
|
|
1117
1118
|
// Ensure pending dir does not exist yet
|
|
1118
|
-
const pendingDir = path.join(fixture.cwd, '
|
|
1119
|
+
const pendingDir = path.join(fixture.cwd, 'jobs', 'pending');
|
|
1119
1120
|
assert.ok(!fs.existsSync(pendingDir), 'pending dir should not exist before call');
|
|
1120
1121
|
|
|
1121
1122
|
cmdJobsCreateMilestone(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1124,13 +1125,13 @@ Plans:
|
|
|
1124
1125
|
|
|
1125
1126
|
it('returns JSON with expected fields', () => {
|
|
1126
1127
|
fixture = createFixture({
|
|
1127
|
-
'
|
|
1128
|
-
'
|
|
1129
|
-
'
|
|
1130
|
-
'
|
|
1131
|
-
'
|
|
1132
|
-
'
|
|
1133
|
-
'
|
|
1128
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1129
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1130
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1131
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1132
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1133
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1134
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1134
1135
|
});
|
|
1135
1136
|
|
|
1136
1137
|
const result = cmdJobsCreateMilestone(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1145,7 +1146,7 @@ Plans:
|
|
|
1145
1146
|
|
|
1146
1147
|
it('throws error when no ROADMAP.md exists', () => {
|
|
1147
1148
|
fixture = createFixture({
|
|
1148
|
-
'
|
|
1149
|
+
'phases/': null,
|
|
1149
1150
|
});
|
|
1150
1151
|
|
|
1151
1152
|
assert.throws(
|
|
@@ -1156,8 +1157,8 @@ Plans:
|
|
|
1156
1157
|
|
|
1157
1158
|
it('throws error when specified version not found in ROADMAP', () => {
|
|
1158
1159
|
fixture = createFixture({
|
|
1159
|
-
'
|
|
1160
|
-
'
|
|
1160
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1161
|
+
'phases/': null,
|
|
1161
1162
|
});
|
|
1162
1163
|
|
|
1163
1164
|
assert.throws(
|
|
@@ -1212,13 +1213,13 @@ Plans:
|
|
|
1212
1213
|
|
|
1213
1214
|
it('returns preview JSON with expected fields', () => {
|
|
1214
1215
|
fixture = createFixture({
|
|
1215
|
-
'
|
|
1216
|
-
'
|
|
1217
|
-
'
|
|
1218
|
-
'
|
|
1219
|
-
'
|
|
1220
|
-
'
|
|
1221
|
-
'
|
|
1216
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1217
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1218
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1219
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1220
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1221
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1222
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1222
1223
|
});
|
|
1223
1224
|
|
|
1224
1225
|
const result = cmdJobsMilestonePreview(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1233,30 +1234,30 @@ Plans:
|
|
|
1233
1234
|
|
|
1234
1235
|
it('does NOT write any file to disk', () => {
|
|
1235
1236
|
fixture = createFixture({
|
|
1236
|
-
'
|
|
1237
|
-
'
|
|
1238
|
-
'
|
|
1239
|
-
'
|
|
1240
|
-
'
|
|
1241
|
-
'
|
|
1242
|
-
'
|
|
1237
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1238
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1239
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1240
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1241
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1242
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1243
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1243
1244
|
});
|
|
1244
1245
|
|
|
1245
1246
|
cmdJobsMilestonePreview(fixture.cwd, 'v6.0', true, false);
|
|
1246
1247
|
|
|
1247
|
-
const pendingDir = path.join(fixture.cwd, '
|
|
1248
|
+
const pendingDir = path.join(fixture.cwd, 'jobs', 'pending');
|
|
1248
1249
|
assert.ok(!fs.existsSync(pendingDir), 'No jobs directory should be created for preview');
|
|
1249
1250
|
});
|
|
1250
1251
|
|
|
1251
1252
|
it('steps_preview is array of step command strings', () => {
|
|
1252
1253
|
fixture = createFixture({
|
|
1253
|
-
'
|
|
1254
|
-
'
|
|
1255
|
-
'
|
|
1256
|
-
'
|
|
1257
|
-
'
|
|
1258
|
-
'
|
|
1259
|
-
'
|
|
1254
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1255
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1256
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1257
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1258
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1259
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1260
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1260
1261
|
});
|
|
1261
1262
|
|
|
1262
1263
|
const result = cmdJobsMilestonePreview(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1268,13 +1269,13 @@ Plans:
|
|
|
1268
1269
|
|
|
1269
1270
|
it('content is the full markdown that would be written', () => {
|
|
1270
1271
|
fixture = createFixture({
|
|
1271
|
-
'
|
|
1272
|
-
'
|
|
1273
|
-
'
|
|
1274
|
-
'
|
|
1275
|
-
'
|
|
1276
|
-
'
|
|
1277
|
-
'
|
|
1272
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1273
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1274
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1275
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1276
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1277
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1278
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1278
1279
|
});
|
|
1279
1280
|
|
|
1280
1281
|
const result = cmdJobsMilestonePreview(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1284,13 +1285,13 @@ Plans:
|
|
|
1284
1285
|
|
|
1285
1286
|
it('phase_count counts distinct phases with steps', () => {
|
|
1286
1287
|
fixture = createFixture({
|
|
1287
|
-
'
|
|
1288
|
-
'
|
|
1289
|
-
'
|
|
1290
|
-
'
|
|
1291
|
-
'
|
|
1292
|
-
'
|
|
1293
|
-
'
|
|
1288
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1289
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1290
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1291
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1292
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1293
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1294
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1294
1295
|
});
|
|
1295
1296
|
|
|
1296
1297
|
const result = cmdJobsMilestonePreview(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1300,13 +1301,13 @@ Plans:
|
|
|
1300
1301
|
|
|
1301
1302
|
it('combines correctly with --no-check (omits audit/complete from preview)', () => {
|
|
1302
1303
|
fixture = createFixture({
|
|
1303
|
-
'
|
|
1304
|
-
'
|
|
1305
|
-
'
|
|
1306
|
-
'
|
|
1307
|
-
'
|
|
1308
|
-
'
|
|
1309
|
-
'
|
|
1304
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1305
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1306
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1307
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1308
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1309
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1310
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1310
1311
|
});
|
|
1311
1312
|
|
|
1312
1313
|
const withCheck = cmdJobsMilestonePreview(fixture.cwd, 'v6.0', true, false);
|
|
@@ -1321,13 +1322,13 @@ Plans:
|
|
|
1321
1322
|
|
|
1322
1323
|
it('auto-detects milestone version same as create', () => {
|
|
1323
1324
|
fixture = createFixture({
|
|
1324
|
-
'
|
|
1325
|
-
'
|
|
1326
|
-
'
|
|
1327
|
-
'
|
|
1328
|
-
'
|
|
1329
|
-
'
|
|
1330
|
-
'
|
|
1325
|
+
'ROADMAP.md': FIXTURE_ROADMAP,
|
|
1326
|
+
'phases/49-job-file-format/49-01-PLAN.md': '',
|
|
1327
|
+
'phases/49-job-file-format/49-02-PLAN.md': '',
|
|
1328
|
+
'phases/49-job-file-format/49-01-SUMMARY.md': '',
|
|
1329
|
+
'phases/49-job-file-format/49-02-SUMMARY.md': '',
|
|
1330
|
+
'phases/50-job-creation/50-01-PLAN.md': '',
|
|
1331
|
+
'phases/50-job-creation/50-02-PLAN.md': '',
|
|
1331
1332
|
});
|
|
1332
1333
|
|
|
1333
1334
|
const result = cmdJobsMilestonePreview(fixture.cwd, null, true, false);
|
|
@@ -1336,7 +1337,7 @@ Plans:
|
|
|
1336
1337
|
|
|
1337
1338
|
it('throws error when no ROADMAP.md exists', () => {
|
|
1338
1339
|
fixture = createFixture({
|
|
1339
|
-
'
|
|
1340
|
+
'phases/': null,
|
|
1340
1341
|
});
|
|
1341
1342
|
|
|
1342
1343
|
assert.throws(
|
|
@@ -1357,7 +1358,7 @@ Plans:
|
|
|
1357
1358
|
|
|
1358
1359
|
it('finds job in in-progress/ when file exists there', () => {
|
|
1359
1360
|
fixture = createFixture({
|
|
1360
|
-
'
|
|
1361
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1361
1362
|
});
|
|
1362
1363
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1363
1364
|
assert.equal(result.found, true);
|
|
@@ -1368,7 +1369,7 @@ Plans:
|
|
|
1368
1369
|
|
|
1369
1370
|
it('finds job in pending/ when not in in-progress/', () => {
|
|
1370
1371
|
fixture = createFixture({
|
|
1371
|
-
'
|
|
1372
|
+
'jobs/pending/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1372
1373
|
});
|
|
1373
1374
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1374
1375
|
assert.equal(result.found, true);
|
|
@@ -1378,8 +1379,8 @@ Plans:
|
|
|
1378
1379
|
|
|
1379
1380
|
it('prefers in-progress/ over pending/ when file exists in both', () => {
|
|
1380
1381
|
fixture = createFixture({
|
|
1381
|
-
'
|
|
1382
|
-
'
|
|
1382
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1383
|
+
'jobs/pending/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1383
1384
|
});
|
|
1384
1385
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1385
1386
|
assert.equal(result.found, true);
|
|
@@ -1388,8 +1389,8 @@ Plans:
|
|
|
1388
1389
|
|
|
1389
1390
|
it('returns found:false when file exists in neither directory', () => {
|
|
1390
1391
|
fixture = createFixture({
|
|
1391
|
-
'
|
|
1392
|
-
'
|
|
1392
|
+
'jobs/pending/': null,
|
|
1393
|
+
'jobs/in-progress/': null,
|
|
1393
1394
|
});
|
|
1394
1395
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1395
1396
|
assert.equal(result.found, false);
|
|
@@ -1397,7 +1398,7 @@ Plans:
|
|
|
1397
1398
|
|
|
1398
1399
|
it('checks completed/ as fallback for inspection', () => {
|
|
1399
1400
|
fixture = createFixture({
|
|
1400
|
-
'
|
|
1401
|
+
'jobs/completed/milestone-v6.0.md': ALL_COMPLETED_JOB,
|
|
1401
1402
|
});
|
|
1402
1403
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1403
1404
|
assert.equal(result.found, true);
|
|
@@ -1407,7 +1408,7 @@ Plans:
|
|
|
1407
1408
|
|
|
1408
1409
|
it('handles version without v prefix (e.g., "6.0" -> milestone-v6.0.md)', () => {
|
|
1409
1410
|
fixture = createFixture({
|
|
1410
|
-
'
|
|
1411
|
+
'jobs/pending/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1411
1412
|
});
|
|
1412
1413
|
const result = findJobFile(fixture.cwd, '6.0');
|
|
1413
1414
|
assert.equal(result.found, true);
|
|
@@ -1416,7 +1417,7 @@ Plans:
|
|
|
1416
1417
|
|
|
1417
1418
|
it('handles version with v prefix correctly', () => {
|
|
1418
1419
|
fixture = createFixture({
|
|
1419
|
-
'
|
|
1420
|
+
'jobs/pending/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1420
1421
|
});
|
|
1421
1422
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1422
1423
|
assert.equal(result.found, true);
|
|
@@ -1425,7 +1426,7 @@ Plans:
|
|
|
1425
1426
|
|
|
1426
1427
|
it('finds job in project subdirectory completed/', () => {
|
|
1427
1428
|
fixture = createFixture({
|
|
1428
|
-
'
|
|
1429
|
+
'projects/test-project/jobs/completed/milestone-v6.0.md': ALL_COMPLETED_JOB,
|
|
1429
1430
|
});
|
|
1430
1431
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1431
1432
|
assert.equal(result.found, true);
|
|
@@ -1437,8 +1438,8 @@ Plans:
|
|
|
1437
1438
|
|
|
1438
1439
|
it('prefers top-level jobs/ over project subdirectory', () => {
|
|
1439
1440
|
fixture = createFixture({
|
|
1440
|
-
'
|
|
1441
|
-
'
|
|
1441
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1442
|
+
'projects/test-project/jobs/completed/milestone-v6.0.md': ALL_COMPLETED_JOB,
|
|
1442
1443
|
});
|
|
1443
1444
|
const result = findJobFile(fixture.cwd, 'v6.0');
|
|
1444
1445
|
assert.equal(result.found, true);
|
|
@@ -1448,7 +1449,7 @@ Plans:
|
|
|
1448
1449
|
|
|
1449
1450
|
it('finds job in project subdirectory in-progress/', () => {
|
|
1450
1451
|
fixture = createFixture({
|
|
1451
|
-
'
|
|
1452
|
+
'projects/my-app/jobs/in-progress/milestone-v7.0.md': WELL_FORMED_JOB,
|
|
1452
1453
|
});
|
|
1453
1454
|
const result = findJobFile(fixture.cwd, 'v7.0');
|
|
1454
1455
|
assert.equal(result.found, true);
|
|
@@ -1458,8 +1459,8 @@ Plans:
|
|
|
1458
1459
|
|
|
1459
1460
|
it('returns found:false when not in top-level or project subdirectories', () => {
|
|
1460
1461
|
fixture = createFixture({
|
|
1461
|
-
'
|
|
1462
|
-
'
|
|
1462
|
+
'jobs/pending/': null,
|
|
1463
|
+
'projects/test-project/jobs/pending/': null,
|
|
1463
1464
|
});
|
|
1464
1465
|
const result = findJobFile(fixture.cwd, 'v99.0');
|
|
1465
1466
|
assert.equal(result.found, false);
|
|
@@ -1942,9 +1943,9 @@ Plans:
|
|
|
1942
1943
|
|
|
1943
1944
|
it('returns empty groups when no job files exist in any directory', () => {
|
|
1944
1945
|
fixture = createFixture({
|
|
1945
|
-
'
|
|
1946
|
-
'
|
|
1947
|
-
'
|
|
1946
|
+
'jobs/pending/': null,
|
|
1947
|
+
'jobs/in-progress/': null,
|
|
1948
|
+
'jobs/completed/': null,
|
|
1948
1949
|
});
|
|
1949
1950
|
const result = listJobs(fixture.cwd);
|
|
1950
1951
|
|
|
@@ -1955,8 +1956,8 @@ Plans:
|
|
|
1955
1956
|
|
|
1956
1957
|
it('returns jobs grouped by status with correct fields', () => {
|
|
1957
1958
|
fixture = createFixture({
|
|
1958
|
-
'
|
|
1959
|
-
'
|
|
1959
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
1960
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
1960
1961
|
});
|
|
1961
1962
|
const result = listJobs(fixture.cwd);
|
|
1962
1963
|
|
|
@@ -1980,7 +1981,7 @@ Plans:
|
|
|
1980
1981
|
|
|
1981
1982
|
it('shows check flag false when --no-check was used', () => {
|
|
1982
1983
|
fixture = createFixture({
|
|
1983
|
-
'
|
|
1984
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
1984
1985
|
});
|
|
1985
1986
|
const result = listJobs(fixture.cwd);
|
|
1986
1987
|
|
|
@@ -1990,7 +1991,7 @@ Plans:
|
|
|
1990
1991
|
|
|
1991
1992
|
it('handles missing directories gracefully with empty groups', () => {
|
|
1992
1993
|
fixture = createFixture({
|
|
1993
|
-
'
|
|
1994
|
+
'': null,
|
|
1994
1995
|
});
|
|
1995
1996
|
const result = listJobs(fixture.cwd);
|
|
1996
1997
|
|
|
@@ -2001,7 +2002,7 @@ Plans:
|
|
|
2001
2002
|
|
|
2002
2003
|
it('each entry includes progress as fraction string like "4/12"', () => {
|
|
2003
2004
|
fixture = createFixture({
|
|
2004
|
-
'
|
|
2005
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2005
2006
|
});
|
|
2006
2007
|
const result = listJobs(fixture.cwd);
|
|
2007
2008
|
const entry = result.in_progress[0];
|
|
@@ -2020,8 +2021,8 @@ Plans:
|
|
|
2020
2021
|
|
|
2021
2022
|
it('cancels in-progress job: resets [>] steps to [ ], updates Status, moves to pending/', () => {
|
|
2022
2023
|
fixture = createFixture({
|
|
2023
|
-
'
|
|
2024
|
-
'
|
|
2024
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2025
|
+
'jobs/pending/': null,
|
|
2025
2026
|
});
|
|
2026
2027
|
const result = cancelJob(fixture.cwd, 'v6.0');
|
|
2027
2028
|
|
|
@@ -2031,11 +2032,11 @@ Plans:
|
|
|
2031
2032
|
assert.equal(result.steps_reset, 1); // one [>] step
|
|
2032
2033
|
|
|
2033
2034
|
// Verify file moved to pending
|
|
2034
|
-
assert.ok(fs.existsSync(path.join(fixture.cwd, '
|
|
2035
|
-
assert.ok(!fs.existsSync(path.join(fixture.cwd, '
|
|
2035
|
+
assert.ok(fs.existsSync(path.join(fixture.cwd, 'jobs', 'pending', 'milestone-v6.0.md')));
|
|
2036
|
+
assert.ok(!fs.existsSync(path.join(fixture.cwd, 'jobs', 'in-progress', 'milestone-v6.0.md')));
|
|
2036
2037
|
|
|
2037
2038
|
// Verify content: [>] reset to [ ], [x] preserved
|
|
2038
|
-
const content = fs.readFileSync(path.join(fixture.cwd, '
|
|
2039
|
+
const content = fs.readFileSync(path.join(fixture.cwd, 'jobs', 'pending', 'milestone-v6.0.md'), 'utf-8');
|
|
2039
2040
|
assert.ok(content.includes('**Status:** pending'), 'Status should be pending');
|
|
2040
2041
|
assert.ok(!content.includes('[>]'), 'No in-progress markers should remain');
|
|
2041
2042
|
// completed steps preserved
|
|
@@ -2058,8 +2059,8 @@ Plans:
|
|
|
2058
2059
|
- [ ] \`/dgs:execute-phase 42\`
|
|
2059
2060
|
`;
|
|
2060
2061
|
fixture = createFixture({
|
|
2061
|
-
'
|
|
2062
|
-
'
|
|
2062
|
+
'jobs/in-progress/milestone-v6.0.md': twoInProgress,
|
|
2063
|
+
'jobs/pending/': null,
|
|
2063
2064
|
});
|
|
2064
2065
|
const result = cancelJob(fixture.cwd, 'v6.0');
|
|
2065
2066
|
|
|
@@ -2069,12 +2070,12 @@ Plans:
|
|
|
2069
2070
|
|
|
2070
2071
|
it('keeps completed [x] steps marked done', () => {
|
|
2071
2072
|
fixture = createFixture({
|
|
2072
|
-
'
|
|
2073
|
-
'
|
|
2073
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2074
|
+
'jobs/pending/': null,
|
|
2074
2075
|
});
|
|
2075
2076
|
cancelJob(fixture.cwd, 'v6.0');
|
|
2076
2077
|
|
|
2077
|
-
const content = fs.readFileSync(path.join(fixture.cwd, '
|
|
2078
|
+
const content = fs.readFileSync(path.join(fixture.cwd, 'jobs', 'pending', 'milestone-v6.0.md'), 'utf-8');
|
|
2078
2079
|
const stepLines = content.split('\n').filter(l => l.trim().startsWith('- ['));
|
|
2079
2080
|
const completedSteps = stepLines.filter(l => l.includes('[x]'));
|
|
2080
2081
|
assert.ok(completedSteps.length > 0, 'Completed steps should be preserved');
|
|
@@ -2082,9 +2083,9 @@ Plans:
|
|
|
2082
2083
|
|
|
2083
2084
|
it('returns not_found when no job exists for version', () => {
|
|
2084
2085
|
fixture = createFixture({
|
|
2085
|
-
'
|
|
2086
|
-
'
|
|
2087
|
-
'
|
|
2086
|
+
'jobs/pending/': null,
|
|
2087
|
+
'jobs/in-progress/': null,
|
|
2088
|
+
'jobs/completed/': null,
|
|
2088
2089
|
});
|
|
2089
2090
|
const result = cancelJob(fixture.cwd, 'v99.0');
|
|
2090
2091
|
|
|
@@ -2094,7 +2095,7 @@ Plans:
|
|
|
2094
2095
|
|
|
2095
2096
|
it('returns not_in_progress when job is in pending/', () => {
|
|
2096
2097
|
fixture = createFixture({
|
|
2097
|
-
'
|
|
2098
|
+
'jobs/pending/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2098
2099
|
});
|
|
2099
2100
|
const result = cancelJob(fixture.cwd, 'v6.0');
|
|
2100
2101
|
|
|
@@ -2104,7 +2105,7 @@ Plans:
|
|
|
2104
2105
|
|
|
2105
2106
|
it('returns not_in_progress when job is in completed/', () => {
|
|
2106
2107
|
fixture = createFixture({
|
|
2107
|
-
'
|
|
2108
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
2108
2109
|
});
|
|
2109
2110
|
const result = cancelJob(fixture.cwd, 'v5.0');
|
|
2110
2111
|
|
|
@@ -2124,9 +2125,9 @@ Plans:
|
|
|
2124
2125
|
|
|
2125
2126
|
it('returns healthy: true with valid directory structure', () => {
|
|
2126
2127
|
fixture = createFixture({
|
|
2127
|
-
'
|
|
2128
|
-
'
|
|
2129
|
-
'
|
|
2128
|
+
'jobs/pending/': null,
|
|
2129
|
+
'jobs/in-progress/': null,
|
|
2130
|
+
'jobs/completed/': null,
|
|
2130
2131
|
});
|
|
2131
2132
|
const result = healthCheck(fixture.cwd);
|
|
2132
2133
|
|
|
@@ -2137,16 +2138,16 @@ Plans:
|
|
|
2137
2138
|
|
|
2138
2139
|
it('returns healthy: false listing issues for missing directories, then auto-creates them', () => {
|
|
2139
2140
|
fixture = createFixture({
|
|
2140
|
-
'
|
|
2141
|
+
'': null,
|
|
2141
2142
|
});
|
|
2142
2143
|
const result = healthCheck(fixture.cwd);
|
|
2143
2144
|
|
|
2144
2145
|
// Should report missing directories but auto-create them
|
|
2145
2146
|
assert.ok(Array.isArray(result.directories));
|
|
2146
2147
|
// After auto-create, directories should exist
|
|
2147
|
-
assert.ok(fs.existsSync(path.join(fixture.cwd, '
|
|
2148
|
-
assert.ok(fs.existsSync(path.join(fixture.cwd, '
|
|
2149
|
-
assert.ok(fs.existsSync(path.join(fixture.cwd, '
|
|
2148
|
+
assert.ok(fs.existsSync(path.join(fixture.cwd, 'jobs', 'pending')));
|
|
2149
|
+
assert.ok(fs.existsSync(path.join(fixture.cwd, 'jobs', 'in-progress')));
|
|
2150
|
+
assert.ok(fs.existsSync(path.join(fixture.cwd, 'jobs', 'completed')));
|
|
2150
2151
|
});
|
|
2151
2152
|
|
|
2152
2153
|
it('validates each job file parses successfully; reports parse failures as issues', () => {
|
|
@@ -2157,9 +2158,9 @@ No version or anything
|
|
|
2157
2158
|
- [ ] random line
|
|
2158
2159
|
`;
|
|
2159
2160
|
fixture = createFixture({
|
|
2160
|
-
'
|
|
2161
|
-
'
|
|
2162
|
-
'
|
|
2161
|
+
'jobs/pending/milestone-v99.0.md': malformedJob,
|
|
2162
|
+
'jobs/in-progress/': null,
|
|
2163
|
+
'jobs/completed/': null,
|
|
2163
2164
|
});
|
|
2164
2165
|
const result = healthCheck(fixture.cwd);
|
|
2165
2166
|
|
|
@@ -2170,9 +2171,9 @@ No version or anything
|
|
|
2170
2171
|
|
|
2171
2172
|
it('counts total job files across all directories', () => {
|
|
2172
2173
|
fixture = createFixture({
|
|
2173
|
-
'
|
|
2174
|
-
'
|
|
2175
|
-
'
|
|
2174
|
+
'jobs/pending/milestone-v7.0.md': EMPTY_STEPS_JOB,
|
|
2175
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2176
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
2176
2177
|
});
|
|
2177
2178
|
const result = healthCheck(fixture.cwd);
|
|
2178
2179
|
|
|
@@ -2191,8 +2192,8 @@ No version or anything
|
|
|
2191
2192
|
|
|
2192
2193
|
it('returns step list with status annotations', () => {
|
|
2193
2194
|
fixture = createFixture({
|
|
2194
|
-
'
|
|
2195
|
-
'
|
|
2195
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2196
|
+
'ROADMAP.md': '# Roadmap',
|
|
2196
2197
|
});
|
|
2197
2198
|
const result = dryRunPreview(fixture.cwd, 'v6.0');
|
|
2198
2199
|
|
|
@@ -2204,8 +2205,8 @@ No version or anything
|
|
|
2204
2205
|
|
|
2205
2206
|
it('each step includes index, command, args, status, display', () => {
|
|
2206
2207
|
fixture = createFixture({
|
|
2207
|
-
'
|
|
2208
|
-
'
|
|
2208
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2209
|
+
'ROADMAP.md': '# Roadmap',
|
|
2209
2210
|
});
|
|
2210
2211
|
const result = dryRunPreview(fixture.cwd, 'v6.0');
|
|
2211
2212
|
|
|
@@ -2220,8 +2221,8 @@ No version or anything
|
|
|
2220
2221
|
|
|
2221
2222
|
it('shows resume_from as first non-completed step', () => {
|
|
2222
2223
|
fixture = createFixture({
|
|
2223
|
-
'
|
|
2224
|
-
'
|
|
2224
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2225
|
+
'ROADMAP.md': '# Roadmap',
|
|
2225
2226
|
});
|
|
2226
2227
|
const result = dryRunPreview(fixture.cwd, 'v6.0');
|
|
2227
2228
|
|
|
@@ -2232,18 +2233,18 @@ No version or anything
|
|
|
2232
2233
|
|
|
2233
2234
|
it('returns found: false when job does not exist', () => {
|
|
2234
2235
|
fixture = createFixture({
|
|
2235
|
-
'
|
|
2236
|
-
'
|
|
2237
|
-
'
|
|
2236
|
+
'jobs/pending/': null,
|
|
2237
|
+
'jobs/in-progress/': null,
|
|
2238
|
+
'jobs/completed/': null,
|
|
2238
2239
|
});
|
|
2239
2240
|
const result = dryRunPreview(fixture.cwd, 'v99.0');
|
|
2240
2241
|
|
|
2241
2242
|
assert.equal(result.found, false);
|
|
2242
2243
|
});
|
|
2243
2244
|
|
|
2244
|
-
it('validates preconditions: warns if
|
|
2245
|
+
it('validates preconditions: warns if ROADMAP.md missing', () => {
|
|
2245
2246
|
fixture = createFixture({
|
|
2246
|
-
'
|
|
2247
|
+
'jobs/in-progress/milestone-v6.0.md': WELL_FORMED_JOB,
|
|
2247
2248
|
});
|
|
2248
2249
|
// No ROADMAP.md
|
|
2249
2250
|
const result = dryRunPreview(fixture.cwd, 'v6.0');
|
|
@@ -2265,7 +2266,7 @@ No version or anything
|
|
|
2265
2266
|
|
|
2266
2267
|
it('produces markdown string with correct header', () => {
|
|
2267
2268
|
fixture = createFixture({
|
|
2268
|
-
'
|
|
2269
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
2269
2270
|
});
|
|
2270
2271
|
const result = generateJobSummary(fixture.cwd, 'v5.0');
|
|
2271
2272
|
|
|
@@ -2277,7 +2278,7 @@ No version or anything
|
|
|
2277
2278
|
|
|
2278
2279
|
it('includes per-step timing table', () => {
|
|
2279
2280
|
fixture = createFixture({
|
|
2280
|
-
'
|
|
2281
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
2281
2282
|
});
|
|
2282
2283
|
const result = generateJobSummary(fixture.cwd, 'v5.0');
|
|
2283
2284
|
|
|
@@ -2301,7 +2302,7 @@ No version or anything
|
|
|
2301
2302
|
- [ ] \`/dgs:verify-work 41\`
|
|
2302
2303
|
`;
|
|
2303
2304
|
fixture = createFixture({
|
|
2304
|
-
'
|
|
2305
|
+
'jobs/in-progress/milestone-v6.0.md': failedJob,
|
|
2305
2306
|
});
|
|
2306
2307
|
const result = generateJobSummary(fixture.cwd, 'v6.0');
|
|
2307
2308
|
|
|
@@ -2324,7 +2325,7 @@ No version or anything
|
|
|
2324
2325
|
- [x] \`/dgs:verify-work 41\` \u2014 completed 2026-03-02T15:30:00Z
|
|
2325
2326
|
`;
|
|
2326
2327
|
fixture = createFixture({
|
|
2327
|
-
'
|
|
2328
|
+
'jobs/completed/milestone-v6.0.md': autoJob,
|
|
2328
2329
|
});
|
|
2329
2330
|
const result = generateJobSummary(fixture.cwd, 'v6.0');
|
|
2330
2331
|
|
|
@@ -2333,7 +2334,7 @@ No version or anything
|
|
|
2333
2334
|
|
|
2334
2335
|
it('handles completed, failed, and cancelled jobs', () => {
|
|
2335
2336
|
fixture = createFixture({
|
|
2336
|
-
'
|
|
2337
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
2337
2338
|
});
|
|
2338
2339
|
const result = generateJobSummary(fixture.cwd, 'v5.0');
|
|
2339
2340
|
assert.equal(result.found, true);
|
|
@@ -2342,9 +2343,9 @@ No version or anything
|
|
|
2342
2343
|
|
|
2343
2344
|
it('returns found: false when job does not exist', () => {
|
|
2344
2345
|
fixture = createFixture({
|
|
2345
|
-
'
|
|
2346
|
-
'
|
|
2347
|
-
'
|
|
2346
|
+
'jobs/pending/': null,
|
|
2347
|
+
'jobs/in-progress/': null,
|
|
2348
|
+
'jobs/completed/': null,
|
|
2348
2349
|
});
|
|
2349
2350
|
const result = generateJobSummary(fixture.cwd, 'v99.0');
|
|
2350
2351
|
|
|
@@ -2353,9 +2354,9 @@ No version or anything
|
|
|
2353
2354
|
|
|
2354
2355
|
it('includes human verifications section when UAT has human_needed entries', () => {
|
|
2355
2356
|
fixture = createFixture({
|
|
2356
|
-
'
|
|
2357
|
-
'
|
|
2358
|
-
'
|
|
2357
|
+
'jobs/completed/milestone-v6.0.md': COMPLETED_JOB_V6,
|
|
2358
|
+
'ROADMAP.md': ROADMAP_WITH_PHASE_50,
|
|
2359
|
+
'phases/50-test-phase/50-UAT.md': UAT_WITH_HUMAN_NEEDED,
|
|
2359
2360
|
});
|
|
2360
2361
|
const result = generateJobSummary(fixture.cwd, 'v6.0');
|
|
2361
2362
|
|
|
@@ -2368,9 +2369,9 @@ No version or anything
|
|
|
2368
2369
|
|
|
2369
2370
|
it('omits human verifications section when no human_needed entries', () => {
|
|
2370
2371
|
fixture = createFixture({
|
|
2371
|
-
'
|
|
2372
|
-
'
|
|
2373
|
-
'
|
|
2372
|
+
'jobs/completed/milestone-v6.0.md': COMPLETED_JOB_V6,
|
|
2373
|
+
'ROADMAP.md': ROADMAP_WITH_PHASE_50,
|
|
2374
|
+
'phases/50-test-phase/50-UAT.md': UAT_ALL_PASSED,
|
|
2374
2375
|
});
|
|
2375
2376
|
const result = generateJobSummary(fixture.cwd, 'v6.0');
|
|
2376
2377
|
|
|
@@ -2381,9 +2382,9 @@ No version or anything
|
|
|
2381
2382
|
|
|
2382
2383
|
it('omits human verifications when no UAT files exist', () => {
|
|
2383
2384
|
fixture = createFixture({
|
|
2384
|
-
'
|
|
2385
|
-
'
|
|
2386
|
-
'
|
|
2385
|
+
'jobs/completed/milestone-v6.0.md': COMPLETED_JOB_V6,
|
|
2386
|
+
'ROADMAP.md': ROADMAP_WITH_PHASE_50,
|
|
2387
|
+
'phases/50-test-phase/': null,
|
|
2387
2388
|
});
|
|
2388
2389
|
const result = generateJobSummary(fixture.cwd, 'v6.0');
|
|
2389
2390
|
|
|
@@ -2394,9 +2395,9 @@ No version or anything
|
|
|
2394
2395
|
|
|
2395
2396
|
it('skips UAT files without mode: auto-test', () => {
|
|
2396
2397
|
fixture = createFixture({
|
|
2397
|
-
'
|
|
2398
|
-
'
|
|
2399
|
-
'
|
|
2398
|
+
'jobs/completed/milestone-v6.0.md': COMPLETED_JOB_V6,
|
|
2399
|
+
'ROADMAP.md': ROADMAP_WITH_PHASE_50,
|
|
2400
|
+
'phases/50-test-phase/50-UAT.md': UAT_MANUAL_WITH_HUMAN_NEEDED,
|
|
2400
2401
|
});
|
|
2401
2402
|
const result = generateJobSummary(fixture.cwd, 'v6.0');
|
|
2402
2403
|
|
|
@@ -2454,7 +2455,7 @@ No version or anything
|
|
|
2454
2455
|
it('generateJobSummary includes Created_by in overview when present', () => {
|
|
2455
2456
|
const jobWithCreatedBy = WELL_FORMED_JOB_WITH_CREATED_BY.replace('in-progress', 'completed');
|
|
2456
2457
|
fixture = createFixture({
|
|
2457
|
-
'
|
|
2458
|
+
'jobs/completed/milestone-v6.0.md': jobWithCreatedBy,
|
|
2458
2459
|
});
|
|
2459
2460
|
const result = generateJobSummary(fixture.cwd, 'v6.0');
|
|
2460
2461
|
assert.equal(result.found, true);
|
|
@@ -2463,7 +2464,7 @@ No version or anything
|
|
|
2463
2464
|
|
|
2464
2465
|
it('generateJobSummary omits Created_by in overview when absent', () => {
|
|
2465
2466
|
fixture = createFixture({
|
|
2466
|
-
'
|
|
2467
|
+
'jobs/completed/milestone-v5.0.md': ALL_COMPLETED_JOB,
|
|
2467
2468
|
});
|
|
2468
2469
|
const result = generateJobSummary(fixture.cwd, 'v5.0');
|
|
2469
2470
|
assert.equal(result.found, true);
|
|
@@ -2485,7 +2486,7 @@ describe('jobs root-layout', () => {
|
|
|
2485
2486
|
|
|
2486
2487
|
it('findJobFile resolves jobs dir at root layout', () => {
|
|
2487
2488
|
fixture = createTempProject({ layout: 'root' });
|
|
2488
|
-
// Create a job file at
|
|
2489
|
+
// Create a job file at jobs/pending/
|
|
2489
2490
|
const jobsDir = path.join(fixture.cwd, 'jobs', 'pending');
|
|
2490
2491
|
fs.mkdirSync(jobsDir, { recursive: true });
|
|
2491
2492
|
const jobContent = `# Milestone Job: v1.0\n\n**Version:** v1.0\n**Created:** 2026-01-01T00:00:00Z\n**Status:** pending\n**Check:** true\n\n## Steps\n\n- [ ] \`/dgs:plan-phase 1\`\n`;
|
|
@@ -2494,16 +2495,16 @@ describe('jobs root-layout', () => {
|
|
|
2494
2495
|
const result = findJobFile(fixture.cwd, 'v1.0');
|
|
2495
2496
|
assert.equal(result.found, true);
|
|
2496
2497
|
assert.equal(result.directory, 'pending');
|
|
2497
|
-
// Should
|
|
2498
|
+
// Should be at root jobs/
|
|
2498
2499
|
assert.ok(result.path.includes(path.join(fixture.cwd, 'jobs')));
|
|
2499
|
-
|
|
2500
|
+
|
|
2500
2501
|
});
|
|
2501
2502
|
|
|
2502
2503
|
it('healthCheck creates jobs dirs at root layout', () => {
|
|
2503
2504
|
fixture = createTempProject({ layout: 'root' });
|
|
2504
2505
|
const result = healthCheck(fixture.cwd);
|
|
2505
2506
|
assert.ok(result.directories.length >= 3);
|
|
2506
|
-
// Verify dirs were created at root
|
|
2507
|
+
// Verify dirs were created at root
|
|
2507
2508
|
assert.ok(fs.existsSync(path.join(fixture.cwd, 'jobs', 'pending')));
|
|
2508
2509
|
assert.ok(fs.existsSync(path.join(fixture.cwd, 'jobs', 'in-progress')));
|
|
2509
2510
|
assert.ok(fs.existsSync(path.join(fixture.cwd, 'jobs', 'completed')));
|
|
@@ -2573,11 +2574,11 @@ describe('parseJobFile with StartShas', () => {
|
|
|
2573
2574
|
const jobContent = `# Milestone Job: v1.0\n\n**Version:** v1.0\n**Created:** 2026-01-01T00:00:00Z\n**Status:** in-progress\n**Check:** true\n**StartShas:** ${JSON.stringify(shaObj)}\n\n## Steps\n\n- [ ] \`/dgs:plan-phase 1\`\n`;
|
|
2574
2575
|
|
|
2575
2576
|
fixture = createFixture({
|
|
2576
|
-
'
|
|
2577
|
-
'
|
|
2577
|
+
'config.json': '{}',
|
|
2578
|
+
'job.md': jobContent,
|
|
2578
2579
|
});
|
|
2579
2580
|
|
|
2580
|
-
const parsed = parseJobFile(path.join(fixture.cwd, '
|
|
2581
|
+
const parsed = parseJobFile(path.join(fixture.cwd, 'job.md'));
|
|
2581
2582
|
assert.deepEqual(parsed.startShas, shaObj);
|
|
2582
2583
|
});
|
|
2583
2584
|
|
|
@@ -2585,11 +2586,11 @@ describe('parseJobFile with StartShas', () => {
|
|
|
2585
2586
|
const jobContent = `# Milestone Job: v1.0\n\n**Version:** v1.0\n**Created:** 2026-01-01T00:00:00Z\n**Status:** pending\n**Check:** true\n\n## Steps\n\n- [ ] \`/dgs:plan-phase 1\`\n`;
|
|
2586
2587
|
|
|
2587
2588
|
fixture = createFixture({
|
|
2588
|
-
'
|
|
2589
|
-
'
|
|
2589
|
+
'config.json': '{}',
|
|
2590
|
+
'job.md': jobContent,
|
|
2590
2591
|
});
|
|
2591
2592
|
|
|
2592
|
-
const parsed = parseJobFile(path.join(fixture.cwd, '
|
|
2593
|
+
const parsed = parseJobFile(path.join(fixture.cwd, 'job.md'));
|
|
2593
2594
|
assert.equal(parsed.startShas, null);
|
|
2594
2595
|
});
|
|
2595
2596
|
});
|