@ktpartners/dgs-platform 2.7.4 → 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.
Files changed (56) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/agents/dgs-executor.md +0 -52
  3. package/deliver-great-systems/bin/dgs-tools.cjs +66 -10
  4. package/deliver-great-systems/bin/lib/commands.cjs +1 -8
  5. package/deliver-great-systems/bin/lib/config.cjs +9 -90
  6. package/deliver-great-systems/bin/lib/context.cjs +2 -2
  7. package/deliver-great-systems/bin/lib/context.test.cjs +100 -100
  8. package/deliver-great-systems/bin/lib/core.cjs +17 -57
  9. package/deliver-great-systems/bin/lib/core.test.cjs +166 -170
  10. package/deliver-great-systems/bin/lib/docs.cjs +3 -3
  11. package/deliver-great-systems/bin/lib/docs.test.cjs +14 -7
  12. package/deliver-great-systems/bin/lib/execution.cjs +2 -2
  13. package/deliver-great-systems/bin/lib/execution.test.cjs +65 -67
  14. package/deliver-great-systems/bin/lib/ideas.cjs +4 -4
  15. package/deliver-great-systems/bin/lib/ideas.test.cjs +45 -44
  16. package/deliver-great-systems/bin/lib/init.cjs +9 -4
  17. package/deliver-great-systems/bin/lib/init.test.cjs +242 -175
  18. package/deliver-great-systems/bin/lib/jobs.cjs +1 -1
  19. package/deliver-great-systems/bin/lib/jobs.test.cjs +203 -202
  20. package/deliver-great-systems/bin/lib/migration.cjs +256 -281
  21. package/deliver-great-systems/bin/lib/migration.test.cjs +385 -440
  22. package/deliver-great-systems/bin/lib/milestone.cjs +1 -1
  23. package/deliver-great-systems/bin/lib/overlap.cjs +4 -4
  24. package/deliver-great-systems/bin/lib/overlap.test.cjs +45 -44
  25. package/deliver-great-systems/bin/lib/path-audit.test.cjs +16 -22
  26. package/deliver-great-systems/bin/lib/paths.cjs +60 -59
  27. package/deliver-great-systems/bin/lib/paths.test.cjs +192 -225
  28. package/deliver-great-systems/bin/lib/phase.cjs +5 -4
  29. package/deliver-great-systems/bin/lib/projects.cjs +8 -8
  30. package/deliver-great-systems/bin/lib/projects.test.cjs +75 -74
  31. package/deliver-great-systems/bin/lib/repos.cjs +94 -230
  32. package/deliver-great-systems/bin/lib/repos.test.cjs +84 -75
  33. package/deliver-great-systems/bin/lib/search.cjs +4 -4
  34. package/deliver-great-systems/bin/lib/specs.cjs +2 -2
  35. package/deliver-great-systems/bin/lib/sync.cjs +1 -1
  36. package/deliver-great-systems/bin/lib/template.cjs +3 -3
  37. package/deliver-great-systems/bin/lib/test-helpers.cjs +59 -162
  38. package/deliver-great-systems/bin/lib/verify.cjs +3 -3
  39. package/deliver-great-systems/references/planning-config.md +7 -8
  40. package/deliver-great-systems/workflows/add-tests.md +1 -1
  41. package/deliver-great-systems/workflows/approve-spec.md +1 -11
  42. package/deliver-great-systems/workflows/complete-milestone.md +2 -2
  43. package/deliver-great-systems/workflows/consolidate-ideas.md +1 -1
  44. package/deliver-great-systems/workflows/create-milestone-job.md +2 -2
  45. package/deliver-great-systems/workflows/discuss-phase.md +2 -2
  46. package/deliver-great-systems/workflows/execute-phase.md +63 -4
  47. package/deliver-great-systems/workflows/execute-plan.md +0 -51
  48. package/deliver-great-systems/workflows/find-related-ideas.md +1 -1
  49. package/deliver-great-systems/workflows/help.md +25 -58
  50. package/deliver-great-systems/workflows/init-product.md +14 -451
  51. package/deliver-great-systems/workflows/map-codebase.md +109 -0
  52. package/deliver-great-systems/workflows/new-project.md +0 -1
  53. package/deliver-great-systems/workflows/quick.md +6 -7
  54. package/deliver-great-systems/workflows/run-job.md +56 -0
  55. package/deliver-great-systems/workflows/settings.md +30 -0
  56. package/package.json +5 -1
@@ -34,13 +34,13 @@ function runInit(cwd, command) {
34
34
 
35
35
  function v1Fixture() {
36
36
  return createFixture({
37
- '.planning/config.json': JSON.stringify({}),
38
- '.planning/STATE.md': '# State',
39
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
40
- '.planning/REQUIREMENTS.md': '# Requirements',
41
- '.planning/PROJECT.md': '# Project',
42
- '.planning/phases/01-test-phase/01-CONTEXT.md': '# Context',
43
- '.planning/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
37
+ 'config.json': JSON.stringify({}),
38
+ 'STATE.md': '# State',
39
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
40
+ 'REQUIREMENTS.md': '# Requirements',
41
+ 'PROJECT.md': '# Project',
42
+ 'phases/01-test-phase/01-CONTEXT.md': '# Context',
43
+ 'phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
44
44
  });
45
45
  }
46
46
 
@@ -48,15 +48,15 @@ function v1Fixture() {
48
48
 
49
49
  function v2FixtureWithProject() {
50
50
  return createFixture({
51
- '.planning/config.json': JSON.stringify({ current_project: 'test-project' }),
52
- '.planning/PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| test-project | Active |\n',
53
- '.planning/REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
54
- '.planning/projects/test-project/STATE.md': '# State',
55
- '.planning/projects/test-project/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
56
- '.planning/projects/test-project/REQUIREMENTS.md': '# Requirements',
57
- '.planning/projects/test-project/PROJECT.md': '# Project',
58
- '.planning/projects/test-project/phases/01-test-phase/01-CONTEXT.md': '# Context',
59
- '.planning/projects/test-project/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
51
+ 'config.json': JSON.stringify({ current_project: 'test-project' }),
52
+ 'PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| test-project | Active |\n',
53
+ 'REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
54
+ 'projects/test-project/STATE.md': '# State',
55
+ 'projects/test-project/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
56
+ 'projects/test-project/REQUIREMENTS.md': '# Requirements',
57
+ 'projects/test-project/PROJECT.md': '# Project',
58
+ 'projects/test-project/phases/01-test-phase/01-CONTEXT.md': '# Context',
59
+ 'projects/test-project/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
60
60
  });
61
61
  }
62
62
 
@@ -64,28 +64,28 @@ function v2FixtureWithProject() {
64
64
 
65
65
  function v2FixtureOneProject() {
66
66
  return createFixture({
67
- '.planning/config.json': JSON.stringify({}),
68
- '.planning/PROJECTS.md': '# Projects\n\n| Project | Status |\n',
69
- '.planning/REPOS.md': '# Repos\n\n| Name | Path |\n',
70
- '.planning/projects/test-project/STATE.md': '# State',
67
+ 'config.json': JSON.stringify({}),
68
+ 'PROJECTS.md': '# Projects\n\n| Project | Status |\n',
69
+ 'REPOS.md': '# Repos\n\n| Name | Path |\n',
70
+ 'projects/test-project/STATE.md': '# State',
71
71
  });
72
72
  }
73
73
 
74
74
  function v2FixtureZeroProjects() {
75
75
  return createFixture({
76
- '.planning/config.json': JSON.stringify({}),
77
- '.planning/PROJECTS.md': '# Projects\n\n| Project | Status |\n',
78
- '.planning/REPOS.md': '# Repos\n\n| Name | Path |\n',
76
+ 'config.json': JSON.stringify({}),
77
+ 'PROJECTS.md': '# Projects\n\n| Project | Status |\n',
78
+ 'REPOS.md': '# Repos\n\n| Name | Path |\n',
79
79
  });
80
80
  }
81
81
 
82
82
  function v2FixtureMultipleProjects() {
83
83
  return createFixture({
84
- '.planning/config.json': JSON.stringify({}),
85
- '.planning/PROJECTS.md': '# Projects\n\n| Project | Status |\n',
86
- '.planning/REPOS.md': '# Repos\n\n| Name | Path |\n',
87
- '.planning/projects/alpha-project/STATE.md': '# State',
88
- '.planning/projects/beta-project/STATE.md': '# State',
84
+ 'config.json': JSON.stringify({}),
85
+ 'PROJECTS.md': '# Projects\n\n| Project | Status |\n',
86
+ 'REPOS.md': '# Repos\n\n| Name | Path |\n',
87
+ 'projects/alpha-project/STATE.md': '# State',
88
+ 'projects/beta-project/STATE.md': '# State',
89
89
  });
90
90
  }
91
91
 
@@ -104,16 +104,16 @@ describe('v1 mode: init plan-phase', () => {
104
104
  fixture.cleanup();
105
105
  });
106
106
 
107
- it('returns state_path as .planning/STATE.md', () => {
108
- assert.equal(result.state_path, '.planning/STATE.md');
107
+ it('returns state_path as STATE.md', () => {
108
+ assert.equal(result.state_path, 'STATE.md');
109
109
  });
110
110
 
111
- it('returns roadmap_path as .planning/ROADMAP.md', () => {
112
- assert.equal(result.roadmap_path, '.planning/ROADMAP.md');
111
+ it('returns roadmap_path as ROADMAP.md', () => {
112
+ assert.equal(result.roadmap_path, 'ROADMAP.md');
113
113
  });
114
114
 
115
- it('returns requirements_path as .planning/REQUIREMENTS.md', () => {
116
- assert.equal(result.requirements_path, '.planning/REQUIREMENTS.md');
115
+ it('returns requirements_path as REQUIREMENTS.md', () => {
116
+ assert.equal(result.requirements_path, 'REQUIREMENTS.md');
117
117
  });
118
118
 
119
119
  it('returns dgs_mode v1', () => {
@@ -128,8 +128,8 @@ describe('v1 mode: init plan-phase', () => {
128
128
  assert.equal(result.guard, null);
129
129
  });
130
130
 
131
- it('returns project_root as .planning', () => {
132
- assert.equal(result.project_root, '.planning');
131
+ it('returns project_root as .', () => {
132
+ assert.equal(result.project_root, '.');
133
133
  });
134
134
 
135
135
  it('preserves phase_found', () => {
@@ -156,24 +156,24 @@ describe('v1 mode: init execute-phase', () => {
156
156
  fixture.cleanup();
157
157
  });
158
158
 
159
- it('returns state_path as .planning/STATE.md', () => {
160
- assert.equal(result.state_path, '.planning/STATE.md');
159
+ it('returns state_path as STATE.md', () => {
160
+ assert.equal(result.state_path, 'STATE.md');
161
161
  });
162
162
 
163
- it('returns roadmap_path as .planning/ROADMAP.md', () => {
164
- assert.equal(result.roadmap_path, '.planning/ROADMAP.md');
163
+ it('returns roadmap_path as ROADMAP.md', () => {
164
+ assert.equal(result.roadmap_path, 'ROADMAP.md');
165
165
  });
166
166
 
167
- it('returns config_path as .planning/config.json (always product-level)', () => {
168
- assert.equal(result.config_path, '.planning/config.json');
167
+ it('returns config_path as config.json (always product-level)', () => {
168
+ assert.equal(result.config_path, 'config.json');
169
169
  });
170
170
 
171
- it('returns project_path as .planning/PROJECT.md', () => {
172
- assert.equal(result.project_path, '.planning/PROJECT.md');
171
+ it('returns project_path as PROJECT.md', () => {
172
+ assert.equal(result.project_path, 'PROJECT.md');
173
173
  });
174
174
 
175
- it('returns debug_dir as .planning/debug', () => {
176
- assert.equal(result.debug_dir, '.planning/debug');
175
+ it('returns debug_dir as debug', () => {
176
+ assert.equal(result.debug_dir, 'debug');
177
177
  });
178
178
 
179
179
  it('returns dgs_mode v1', () => {
@@ -204,24 +204,24 @@ describe('v1 mode: init new-project', () => {
204
204
  fixture.cleanup();
205
205
  });
206
206
 
207
- it('returns state_path as .planning/STATE.md', () => {
208
- assert.equal(result.state_path, '.planning/STATE.md');
207
+ it('returns state_path as STATE.md', () => {
208
+ assert.equal(result.state_path, 'STATE.md');
209
209
  });
210
210
 
211
- it('returns roadmap_path as .planning/ROADMAP.md', () => {
212
- assert.equal(result.roadmap_path, '.planning/ROADMAP.md');
211
+ it('returns roadmap_path as ROADMAP.md', () => {
212
+ assert.equal(result.roadmap_path, 'ROADMAP.md');
213
213
  });
214
214
 
215
- it('returns requirements_path as .planning/REQUIREMENTS.md', () => {
216
- assert.equal(result.requirements_path, '.planning/REQUIREMENTS.md');
215
+ it('returns requirements_path as REQUIREMENTS.md', () => {
216
+ assert.equal(result.requirements_path, 'REQUIREMENTS.md');
217
217
  });
218
218
 
219
- it('returns research_dir as .planning/research', () => {
220
- assert.equal(result.research_dir, '.planning/research');
219
+ it('returns research_dir as research', () => {
220
+ assert.equal(result.research_dir, 'research');
221
221
  });
222
222
 
223
- it('returns project_path as .planning/PROJECT.md', () => {
224
- assert.equal(result.project_path, '.planning/PROJECT.md');
223
+ it('returns project_path as PROJECT.md', () => {
224
+ assert.equal(result.project_path, 'PROJECT.md');
225
225
  });
226
226
 
227
227
  it('returns dgs_mode v1', () => {
@@ -253,10 +253,10 @@ describe('v1 mode: init progress', () => {
253
253
  });
254
254
 
255
255
  it('returns v1 file paths', () => {
256
- assert.equal(result.state_path, '.planning/STATE.md');
257
- assert.equal(result.roadmap_path, '.planning/ROADMAP.md');
258
- assert.equal(result.project_path, '.planning/PROJECT.md');
259
- assert.equal(result.config_path, '.planning/config.json');
256
+ assert.equal(result.state_path, 'STATE.md');
257
+ assert.equal(result.roadmap_path, 'ROADMAP.md');
258
+ assert.equal(result.project_path, 'PROJECT.md');
259
+ assert.equal(result.config_path, 'config.json');
260
260
  });
261
261
 
262
262
  it('returns dgs_mode v1', () => {
@@ -278,11 +278,11 @@ describe('v1 mode: init todos', () => {
278
278
  });
279
279
 
280
280
  it('returns v1 pending_dir path', () => {
281
- assert.equal(result.pending_dir, '.planning/todos/pending');
281
+ assert.equal(result.pending_dir, 'todos/pending');
282
282
  });
283
283
 
284
284
  it('returns v1 completed_dir path', () => {
285
- assert.equal(result.completed_dir, '.planning/todos/completed');
285
+ assert.equal(result.completed_dir, 'todos/completed');
286
286
  });
287
287
 
288
288
  it('returns dgs_mode v1', () => {
@@ -304,9 +304,9 @@ describe('v1 mode: init milestone-op', () => {
304
304
  });
305
305
 
306
306
  it('returns v1 file paths', () => {
307
- assert.equal(result.project_path, '.planning/PROJECT.md');
308
- assert.equal(result.roadmap_path, '.planning/ROADMAP.md');
309
- assert.equal(result.state_path, '.planning/STATE.md');
307
+ assert.equal(result.project_path, 'PROJECT.md');
308
+ assert.equal(result.roadmap_path, 'ROADMAP.md');
309
+ assert.equal(result.state_path, 'STATE.md');
310
310
  });
311
311
 
312
312
  it('returns dgs_mode v1', () => {
@@ -332,7 +332,7 @@ describe('v1 mode: init map-codebase', () => {
332
332
  });
333
333
 
334
334
  it('keeps codebase_dir product-level (not project-qualified)', () => {
335
- assert.equal(result.codebase_dir, '.planning/codebase');
335
+ assert.equal(result.codebase_dir, 'codebase');
336
336
  });
337
337
 
338
338
  it('returns dgs_mode v1', () => {
@@ -356,15 +356,15 @@ describe('v2 mode with project: init plan-phase', () => {
356
356
  });
357
357
 
358
358
  it('returns project-qualified state_path', () => {
359
- assert.equal(result.state_path, path.join('.planning', 'projects', 'test-project', 'STATE.md'));
359
+ assert.equal(result.state_path, path.join('projects', 'test-project', 'STATE.md'));
360
360
  });
361
361
 
362
362
  it('returns project-qualified roadmap_path', () => {
363
- assert.equal(result.roadmap_path, path.join('.planning', 'projects', 'test-project', 'ROADMAP.md'));
363
+ assert.equal(result.roadmap_path, path.join('projects', 'test-project', 'ROADMAP.md'));
364
364
  });
365
365
 
366
366
  it('returns project-qualified requirements_path', () => {
367
- assert.equal(result.requirements_path, path.join('.planning', 'projects', 'test-project', 'REQUIREMENTS.md'));
367
+ assert.equal(result.requirements_path, path.join('projects', 'test-project', 'REQUIREMENTS.md'));
368
368
  });
369
369
 
370
370
  it('returns dgs_mode v2', () => {
@@ -376,7 +376,7 @@ describe('v2 mode with project: init plan-phase', () => {
376
376
  });
377
377
 
378
378
  it('returns project_root', () => {
379
- assert.equal(result.project_root, path.join('.planning', 'projects', 'test-project'));
379
+ assert.equal(result.project_root, path.join('projects', 'test-project'));
380
380
  });
381
381
 
382
382
  it('returns guard null (project is set)', () => {
@@ -386,7 +386,7 @@ describe('v2 mode with project: init plan-phase', () => {
386
386
  it('finds phase in project-scoped phases directory', () => {
387
387
  assert.equal(result.phase_found, true);
388
388
  assert.equal(result.phase_number, '01');
389
- assert.equal(result.phase_dir, path.join('.planning', 'projects', 'test-project', 'phases', '01-test-phase'));
389
+ assert.equal(result.phase_dir, path.join('projects', 'test-project', 'phases', '01-test-phase'));
390
390
  });
391
391
  });
392
392
 
@@ -404,23 +404,23 @@ describe('v2 mode with project: init execute-phase', () => {
404
404
  });
405
405
 
406
406
  it('returns project-qualified state_path', () => {
407
- assert.equal(result.state_path, path.join('.planning', 'projects', 'test-project', 'STATE.md'));
407
+ assert.equal(result.state_path, path.join('projects', 'test-project', 'STATE.md'));
408
408
  });
409
409
 
410
410
  it('returns project-qualified roadmap_path', () => {
411
- assert.equal(result.roadmap_path, path.join('.planning', 'projects', 'test-project', 'ROADMAP.md'));
411
+ assert.equal(result.roadmap_path, path.join('projects', 'test-project', 'ROADMAP.md'));
412
412
  });
413
413
 
414
414
  it('config_path stays product-level', () => {
415
- assert.equal(result.config_path, '.planning/config.json');
415
+ assert.equal(result.config_path, 'config.json');
416
416
  });
417
417
 
418
418
  it('returns project-qualified project_path', () => {
419
- assert.equal(result.project_path, path.join('.planning', 'projects', 'test-project', 'PROJECT.md'));
419
+ assert.equal(result.project_path, path.join('projects', 'test-project', 'PROJECT.md'));
420
420
  });
421
421
 
422
422
  it('returns project-qualified debug_dir', () => {
423
- assert.equal(result.debug_dir, path.join('.planning', 'projects', 'test-project', 'debug'));
423
+ assert.equal(result.debug_dir, path.join('projects', 'test-project', 'debug'));
424
424
  });
425
425
 
426
426
  it('returns dgs_mode v2', () => {
@@ -430,7 +430,7 @@ describe('v2 mode with project: init execute-phase', () => {
430
430
  it('finds phase in project-scoped phases directory', () => {
431
431
  assert.equal(result.phase_found, true);
432
432
  assert.equal(result.phase_number, '01');
433
- assert.equal(result.phase_dir, path.join('.planning', 'projects', 'test-project', 'phases', '01-test-phase'));
433
+ assert.equal(result.phase_dir, path.join('projects', 'test-project', 'phases', '01-test-phase'));
434
434
  });
435
435
  });
436
436
 
@@ -448,23 +448,23 @@ describe('v2 mode with project: init new-project', () => {
448
448
  });
449
449
 
450
450
  it('returns project-qualified state_path', () => {
451
- assert.equal(result.state_path, path.join('.planning', 'projects', 'test-project', 'STATE.md'));
451
+ assert.equal(result.state_path, path.join('projects', 'test-project', 'STATE.md'));
452
452
  });
453
453
 
454
454
  it('returns project-qualified roadmap_path', () => {
455
- assert.equal(result.roadmap_path, path.join('.planning', 'projects', 'test-project', 'ROADMAP.md'));
455
+ assert.equal(result.roadmap_path, path.join('projects', 'test-project', 'ROADMAP.md'));
456
456
  });
457
457
 
458
458
  it('returns project-qualified requirements_path', () => {
459
- assert.equal(result.requirements_path, path.join('.planning', 'projects', 'test-project', 'REQUIREMENTS.md'));
459
+ assert.equal(result.requirements_path, path.join('projects', 'test-project', 'REQUIREMENTS.md'));
460
460
  });
461
461
 
462
462
  it('returns project-qualified research_dir', () => {
463
- assert.equal(result.research_dir, path.join('.planning', 'projects', 'test-project', 'research'));
463
+ assert.equal(result.research_dir, path.join('projects', 'test-project', 'research'));
464
464
  });
465
465
 
466
466
  it('returns project-qualified project_path', () => {
467
- assert.equal(result.project_path, path.join('.planning', 'projects', 'test-project', 'PROJECT.md'));
467
+ assert.equal(result.project_path, path.join('projects', 'test-project', 'PROJECT.md'));
468
468
  });
469
469
 
470
470
  it('returns dgs_mode v2', () => {
@@ -490,16 +490,16 @@ describe('v2 mode with project: init progress', () => {
490
490
  });
491
491
 
492
492
  it('returns project-qualified state_path', () => {
493
- assert.equal(result.state_path, path.join('.planning', 'projects', 'test-project', 'STATE.md'));
493
+ assert.equal(result.state_path, path.join('projects', 'test-project', 'STATE.md'));
494
494
  });
495
495
 
496
496
  it('config_path stays product-level', () => {
497
- assert.equal(result.config_path, '.planning/config.json');
497
+ assert.equal(result.config_path, 'config.json');
498
498
  });
499
499
 
500
500
  it('phase directory is project-qualified', () => {
501
501
  if (result.phases.length > 0) {
502
- assert.ok(result.phases[0].directory.startsWith(path.join('.planning', 'projects', 'test-project', 'phases')));
502
+ assert.ok(result.phases[0].directory.startsWith(path.join('projects', 'test-project', 'phases')));
503
503
  }
504
504
  });
505
505
  });
@@ -518,11 +518,11 @@ describe('v2 mode with project: init todos', () => {
518
518
  });
519
519
 
520
520
  it('returns product-level pending_dir', () => {
521
- assert.equal(result.pending_dir, path.join('.planning', 'todos', 'pending'));
521
+ assert.equal(result.pending_dir, path.join('todos', 'pending'));
522
522
  });
523
523
 
524
524
  it('returns product-level completed_dir', () => {
525
- assert.equal(result.completed_dir, path.join('.planning', 'todos', 'completed'));
525
+ assert.equal(result.completed_dir, path.join('todos', 'completed'));
526
526
  });
527
527
 
528
528
  it('returns dgs_mode v2', () => {
@@ -544,9 +544,9 @@ describe('v2 mode with project: init milestone-op', () => {
544
544
  });
545
545
 
546
546
  it('returns project-qualified file paths', () => {
547
- assert.equal(result.project_path, path.join('.planning', 'projects', 'test-project', 'PROJECT.md'));
548
- assert.equal(result.roadmap_path, path.join('.planning', 'projects', 'test-project', 'ROADMAP.md'));
549
- assert.equal(result.state_path, path.join('.planning', 'projects', 'test-project', 'STATE.md'));
547
+ assert.equal(result.project_path, path.join('projects', 'test-project', 'PROJECT.md'));
548
+ assert.equal(result.roadmap_path, path.join('projects', 'test-project', 'ROADMAP.md'));
549
+ assert.equal(result.state_path, path.join('projects', 'test-project', 'STATE.md'));
550
550
  });
551
551
 
552
552
  it('returns dgs_mode v2', () => {
@@ -568,7 +568,7 @@ describe('v2 mode with project: init map-codebase', () => {
568
568
  });
569
569
 
570
570
  it('keeps codebase_dir product-level (shared, not project-qualified)', () => {
571
- assert.equal(result.codebase_dir, '.planning/codebase');
571
+ assert.equal(result.codebase_dir, 'codebase');
572
572
  });
573
573
 
574
574
  it('returns dgs_mode v2', () => {
@@ -589,10 +589,10 @@ describe('init map-codebase: multi-repo with valid repos', () => {
589
589
 
590
590
  // Use a fixture with REPOS.md containing the sibling repo via relative path
591
591
  fixture = createFixture({
592
- '.planning/config.json': JSON.stringify({}),
593
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories for this product. Managed by DGS — manual edits may be overwritten.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| testrepo | ../${path.basename(repoDir)} | | Test repo |\n`,
594
- '.planning/STATE.md': '# State',
595
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
592
+ 'config.json': JSON.stringify({}),
593
+ 'REPOS.md': `# Repos\n\nRegistered repositories for this product. Managed by DGS — manual edits may be overwritten.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| testrepo | ../${path.basename(repoDir)} | | Test repo |\n`,
594
+ 'STATE.md': '# State',
595
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
596
596
  });
597
597
  });
598
598
 
@@ -626,7 +626,7 @@ describe('init map-codebase: multi-repo with valid repos', () => {
626
626
 
627
627
  it('preserves backward-compatible codebase_dir field', () => {
628
628
  const result = runInit(fixture.cwd, 'map-codebase');
629
- assert.equal(result.codebase_dir, '.planning/codebase');
629
+ assert.equal(result.codebase_dir, 'codebase');
630
630
  });
631
631
  });
632
632
 
@@ -635,9 +635,9 @@ describe('init map-codebase: no repos registered', () => {
635
635
 
636
636
  beforeEach(() => {
637
637
  fixture = createFixture({
638
- '.planning/config.json': JSON.stringify({}),
639
- '.planning/STATE.md': '# State',
640
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
638
+ 'config.json': JSON.stringify({}),
639
+ 'STATE.md': '# State',
640
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
641
641
  });
642
642
  });
643
643
 
@@ -666,10 +666,10 @@ describe('init map-codebase: empty REPOS.md table', () => {
666
666
 
667
667
  beforeEach(() => {
668
668
  fixture = createFixture({
669
- '.planning/config.json': JSON.stringify({}),
670
- '.planning/REPOS.md': '# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n',
671
- '.planning/STATE.md': '# State',
672
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
669
+ 'config.json': JSON.stringify({}),
670
+ 'REPOS.md': '# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n',
671
+ 'STATE.md': '# State',
672
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
673
673
  });
674
674
  });
675
675
 
@@ -697,12 +697,12 @@ describe('init map-codebase: existing per-repo maps detected', () => {
697
697
  fs.mkdirSync(path.join(repoDir, '.git'));
698
698
 
699
699
  fixture = createFixture({
700
- '.planning/config.json': JSON.stringify({}),
701
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| myrepo | ../${path.basename(repoDir)} | | My repo |\n`,
702
- '.planning/STATE.md': '# State',
703
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
704
- '.planning/codebase/myrepo/STACK.md': '# Stack\n',
705
- '.planning/codebase/myrepo/ARCHITECTURE.md': '# Architecture\n',
700
+ 'config.json': JSON.stringify({}),
701
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| myrepo | ../${path.basename(repoDir)} | | My repo |\n`,
702
+ 'STATE.md': '# State',
703
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
704
+ 'codebase/myrepo/STACK.md': '# Stack\n',
705
+ 'codebase/myrepo/ARCHITECTURE.md': '# Architecture\n',
706
706
  });
707
707
  });
708
708
 
@@ -725,10 +725,10 @@ describe('init map-codebase: invalid repo paths produce errors', () => {
725
725
 
726
726
  beforeEach(() => {
727
727
  fixture = createFixture({
728
- '.planning/config.json': JSON.stringify({}),
729
- '.planning/REPOS.md': '# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| badrepo | ../nonexistent-path-nowhere | | Bad repo |\n',
730
- '.planning/STATE.md': '# State',
731
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
728
+ 'config.json': JSON.stringify({}),
729
+ 'REPOS.md': '# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| badrepo | ../nonexistent-path-nowhere | | Bad repo |\n',
730
+ 'STATE.md': '# State',
731
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
732
732
  });
733
733
  });
734
734
 
@@ -766,10 +766,10 @@ describe('init map-codebase: --only with valid repo name returns only that repo'
766
766
  fs.mkdirSync(path.join(repoDirB, '.git'));
767
767
 
768
768
  fixture = createFixture({
769
- '.planning/config.json': JSON.stringify({}),
770
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n| repo-b | ../${path.basename(repoDirB)} | | Repo B |\n`,
771
- '.planning/STATE.md': '# State',
772
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
769
+ 'config.json': JSON.stringify({}),
770
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n| repo-b | ../${path.basename(repoDirB)} | | Repo B |\n`,
771
+ 'STATE.md': '# State',
772
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
773
773
  });
774
774
  });
775
775
 
@@ -811,10 +811,10 @@ describe('init map-codebase: --only with invalid repo name throws error', () =>
811
811
  fs.mkdirSync(path.join(repoDirA, '.git'));
812
812
 
813
813
  fixture = createFixture({
814
- '.planning/config.json': JSON.stringify({}),
815
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
816
- '.planning/STATE.md': '# State',
817
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
814
+ 'config.json': JSON.stringify({}),
815
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
816
+ 'STATE.md': '# State',
817
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
818
818
  });
819
819
  });
820
820
 
@@ -854,10 +854,10 @@ describe('init map-codebase: without --only returns refresh mode', () => {
854
854
  fs.mkdirSync(path.join(repoDirB, '.git'));
855
855
 
856
856
  fixture = createFixture({
857
- '.planning/config.json': JSON.stringify({}),
858
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n| repo-b | ../${path.basename(repoDirB)} | | Repo B |\n`,
859
- '.planning/STATE.md': '# State',
860
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
857
+ 'config.json': JSON.stringify({}),
858
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n| repo-b | ../${path.basename(repoDirB)} | | Repo B |\n`,
859
+ 'STATE.md': '# State',
860
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
861
861
  });
862
862
  });
863
863
 
@@ -894,10 +894,10 @@ describe('init map-codebase: --only without repo name argument throws error', ()
894
894
  fs.mkdirSync(path.join(repoDirA, '.git'));
895
895
 
896
896
  fixture = createFixture({
897
- '.planning/config.json': JSON.stringify({}),
898
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
899
- '.planning/STATE.md': '# State',
900
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
897
+ 'config.json': JSON.stringify({}),
898
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
899
+ 'STATE.md': '# State',
900
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
901
901
  });
902
902
  });
903
903
 
@@ -937,10 +937,10 @@ describe('init map-codebase: positional argument with valid repo name', () => {
937
937
  fs.mkdirSync(path.join(repoDirB, '.git'));
938
938
 
939
939
  fixture = createFixture({
940
- '.planning/config.json': JSON.stringify({}),
941
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n| repo-b | ../${path.basename(repoDirB)} | | Repo B |\n`,
942
- '.planning/STATE.md': '# State',
943
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
940
+ 'config.json': JSON.stringify({}),
941
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n| repo-b | ../${path.basename(repoDirB)} | | Repo B |\n`,
942
+ 'STATE.md': '# State',
943
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
944
944
  });
945
945
  });
946
946
 
@@ -985,10 +985,10 @@ describe('init map-codebase: positional argument with invalid repo name', () =>
985
985
  fs.mkdirSync(path.join(repoDirA, '.git'));
986
986
 
987
987
  fixture = createFixture({
988
- '.planning/config.json': JSON.stringify({}),
989
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
990
- '.planning/STATE.md': '# State',
991
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
988
+ 'config.json': JSON.stringify({}),
989
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
990
+ 'STATE.md': '# State',
991
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
992
992
  });
993
993
  });
994
994
 
@@ -1017,10 +1017,10 @@ describe('init map-codebase: argument starting with -- is not treated as positio
1017
1017
  fs.mkdirSync(path.join(repoDirA, '.git'));
1018
1018
 
1019
1019
  fixture = createFixture({
1020
- '.planning/config.json': JSON.stringify({}),
1021
- '.planning/REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
1022
- '.planning/STATE.md': '# State',
1023
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
1020
+ 'config.json': JSON.stringify({}),
1021
+ 'REPOS.md': `# Repos\n\nRegistered repositories.\n\n| Name | Path | GitHub URL | Description |\n|------|------|------------|-------------|\n| repo-a | ../${path.basename(repoDirA)} | | Repo A |\n`,
1022
+ 'STATE.md': '# State',
1023
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n',
1024
1024
  });
1025
1025
  });
1026
1026
 
@@ -1066,7 +1066,7 @@ describe('v2 guard: one project, no current_project (auto-select)', () => {
1066
1066
  });
1067
1067
 
1068
1068
  it('project_root is set to the auto-selected project root', () => {
1069
- assert.equal(result.project_root, path.join('.planning', 'projects', 'test-project'));
1069
+ assert.equal(result.project_root, path.join('projects', 'test-project'));
1070
1070
  });
1071
1071
 
1072
1072
  it('dgs_mode is v2', () => {
@@ -1148,12 +1148,12 @@ describe('v2 guard: multiple projects (prompt)', () => {
1148
1148
  describe('branch_name with {project} resolution', () => {
1149
1149
  it('v1 execute-phase branch_name resolves {project} from current_project', () => {
1150
1150
  const fixture = createFixture({
1151
- '.planning/config.json': JSON.stringify({ current_project: 'myapp', git: { branching_strategy: 'phase' } }),
1152
- '.planning/STATE.md': '# State',
1153
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 3: Auth** - Auth\n',
1154
- '.planning/REQUIREMENTS.md': '# Requirements',
1155
- '.planning/PROJECT.md': '# Project',
1156
- '.planning/phases/03-auth/03-01-PLAN.md': '---\nphase: 03-auth\nplan: 01\n---\n# Plan',
1151
+ 'config.json': JSON.stringify({ current_project: 'myapp', git: { branching_strategy: 'phase' } }),
1152
+ 'STATE.md': '# State',
1153
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 3: Auth** - Auth\n',
1154
+ 'REQUIREMENTS.md': '# Requirements',
1155
+ 'PROJECT.md': '# Project',
1156
+ 'phases/03-auth/03-01-PLAN.md': '---\nphase: 03-auth\nplan: 01\n---\n# Plan',
1157
1157
  });
1158
1158
  try {
1159
1159
  const result = runInit(fixture.cwd, 'execute-phase 3');
@@ -1165,14 +1165,14 @@ describe('branch_name with {project} resolution', () => {
1165
1165
 
1166
1166
  it('v2 execute-phase branch_name resolves {project} from current_project', () => {
1167
1167
  const fixture = createFixture({
1168
- '.planning/config.json': JSON.stringify({ current_project: 'checkout', git: { branching_strategy: 'phase' } }),
1169
- '.planning/PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| checkout | Active |\n',
1170
- '.planning/REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
1171
- '.planning/projects/checkout/STATE.md': '# State',
1172
- '.planning/projects/checkout/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Init** - Init\n',
1173
- '.planning/projects/checkout/REQUIREMENTS.md': '# Requirements',
1174
- '.planning/projects/checkout/PROJECT.md': '# Project',
1175
- '.planning/projects/checkout/phases/01-init/01-01-PLAN.md': '---\nphase: 01-init\nplan: 01\n---\n# Plan',
1168
+ 'config.json': JSON.stringify({ current_project: 'checkout', git: { branching_strategy: 'phase' } }),
1169
+ 'PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| checkout | Active |\n',
1170
+ 'REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
1171
+ 'projects/checkout/STATE.md': '# State',
1172
+ 'projects/checkout/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Init** - Init\n',
1173
+ 'projects/checkout/REQUIREMENTS.md': '# Requirements',
1174
+ 'projects/checkout/PROJECT.md': '# Project',
1175
+ 'projects/checkout/phases/01-init/01-01-PLAN.md': '---\nphase: 01-init\nplan: 01\n---\n# Plan',
1176
1176
  });
1177
1177
  try {
1178
1178
  const result = runInit(fixture.cwd, 'execute-phase 1');
@@ -1184,15 +1184,15 @@ describe('branch_name with {project} resolution', () => {
1184
1184
 
1185
1185
  it('branch_name with custom template without {project} is unchanged', () => {
1186
1186
  const fixture = createFixture({
1187
- '.planning/config.json': JSON.stringify({
1187
+ 'config.json': JSON.stringify({
1188
1188
  current_project: 'myapp',
1189
1189
  git: { branching_strategy: 'phase', phase_branch_template: 'feature/phase-{phase}-{slug}' }
1190
1190
  }),
1191
- '.planning/STATE.md': '# State',
1192
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 3: Auth** - Auth\n',
1193
- '.planning/REQUIREMENTS.md': '# Requirements',
1194
- '.planning/PROJECT.md': '# Project',
1195
- '.planning/phases/03-auth/03-01-PLAN.md': '---\nphase: 03-auth\nplan: 01\n---\n# Plan',
1191
+ 'STATE.md': '# State',
1192
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 3: Auth** - Auth\n',
1193
+ 'REQUIREMENTS.md': '# Requirements',
1194
+ 'PROJECT.md': '# Project',
1195
+ 'phases/03-auth/03-01-PLAN.md': '---\nphase: 03-auth\nplan: 01\n---\n# Plan',
1196
1196
  });
1197
1197
  try {
1198
1198
  const result = runInit(fixture.cwd, 'execute-phase 3');
@@ -1204,12 +1204,12 @@ describe('branch_name with {project} resolution', () => {
1204
1204
 
1205
1205
  it('branch_name errors when {project} in template but current_project is null', () => {
1206
1206
  const fixture = createFixture({
1207
- '.planning/config.json': JSON.stringify({ git: { branching_strategy: 'phase' } }),
1208
- '.planning/STATE.md': '# State',
1209
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 3: Auth** - Auth\n',
1210
- '.planning/REQUIREMENTS.md': '# Requirements',
1211
- '.planning/PROJECT.md': '# Project',
1212
- '.planning/phases/03-auth/03-01-PLAN.md': '---\nphase: 03-auth\nplan: 01\n---\n# Plan',
1207
+ 'config.json': JSON.stringify({ git: { branching_strategy: 'phase' } }),
1208
+ 'STATE.md': '# State',
1209
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 3: Auth** - Auth\n',
1210
+ 'REQUIREMENTS.md': '# Requirements',
1211
+ 'PROJECT.md': '# Project',
1212
+ 'phases/03-auth/03-01-PLAN.md': '---\nphase: 03-auth\nplan: 01\n---\n# Plan',
1213
1213
  });
1214
1214
  try {
1215
1215
  const result = runInit(fixture.cwd, 'execute-phase 3');
@@ -1227,13 +1227,13 @@ describe('branch_name with {project} resolution', () => {
1227
1227
  // Helper: v1 fixture with custom git.sync_pull setting
1228
1228
  function v1FixtureWithSyncPull(syncPull) {
1229
1229
  return createFixture({
1230
- '.planning/config.json': JSON.stringify({ git: { sync_pull: syncPull } }),
1231
- '.planning/STATE.md': '# State',
1232
- '.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
1233
- '.planning/REQUIREMENTS.md': '# Requirements',
1234
- '.planning/PROJECT.md': '# Project',
1235
- '.planning/phases/01-test-phase/01-CONTEXT.md': '# Context',
1236
- '.planning/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
1230
+ 'config.json': JSON.stringify({ git: { sync_pull: syncPull } }),
1231
+ 'STATE.md': '# State',
1232
+ 'ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
1233
+ 'REQUIREMENTS.md': '# Requirements',
1234
+ 'PROJECT.md': '# Project',
1235
+ 'phases/01-test-phase/01-CONTEXT.md': '# Context',
1236
+ 'phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
1237
1237
  });
1238
1238
  }
1239
1239
 
@@ -1454,3 +1454,70 @@ describe('backward compatibility: v1 output is superset of old shape', () => {
1454
1454
  assert.ok('dgs_mode' in result);
1455
1455
  });
1456
1456
  });
1457
+
1458
+ // ─── Archived milestone phase rejection ───────────────────────────────────────
1459
+
1460
+ describe('archived milestone phase rejection', () => {
1461
+ let fixture;
1462
+
1463
+ beforeEach(() => {
1464
+ // v2 fixture with:
1465
+ // - Active project with phase 01
1466
+ // - Archived milestone v16.0 with phase 50 (NOT in active project)
1467
+ // - ROADMAP.md does NOT list phase 50
1468
+ fixture = createFixture({
1469
+ 'config.json': JSON.stringify({ current_project: 'test-project' }),
1470
+ 'PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| test-project | Active |\n',
1471
+ 'REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
1472
+ 'projects/test-project/STATE.md': '# State',
1473
+ 'projects/test-project/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
1474
+ 'projects/test-project/REQUIREMENTS.md': '# Requirements',
1475
+ 'projects/test-project/PROJECT.md': '# Project',
1476
+ 'projects/test-project/phases/01-test-phase/01-CONTEXT.md': '# Context',
1477
+ 'projects/test-project/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
1478
+ // Archived milestone phase 50 — exists ONLY in archive
1479
+ 'milestones/v16.0-phases/50-old-phase/50-CONTEXT.md': '# Old Context',
1480
+ 'milestones/v16.0-phases/50-old-phase/50-01-PLAN.md': '---\nphase: 50-old-phase\nplan: 01\n---\n# Old Plan',
1481
+ });
1482
+ });
1483
+
1484
+ afterEach(() => {
1485
+ fixture.cleanup();
1486
+ });
1487
+
1488
+ it('execute-phase rejects archived-only phase 50', () => {
1489
+ const result = runInit(fixture.cwd, 'execute-phase 50');
1490
+ assert.equal(result.phase_found, false);
1491
+ assert.equal(result.phase_dir, null);
1492
+ });
1493
+
1494
+ it('plan-phase rejects archived-only phase 50', () => {
1495
+ const result = runInit(fixture.cwd, 'plan-phase 50');
1496
+ assert.equal(result.phase_found, false);
1497
+ assert.equal(result.phase_dir, null);
1498
+ });
1499
+
1500
+ it('verify-work rejects archived-only phase 50', () => {
1501
+ const result = runInit(fixture.cwd, 'verify-work 50');
1502
+ assert.equal(result.phase_found, false);
1503
+ assert.equal(result.phase_dir, null);
1504
+ });
1505
+
1506
+ it('audit-phase rejects archived-only phase 50', () => {
1507
+ const result = runInit(fixture.cwd, 'audit-phase 50');
1508
+ assert.equal(result.phase_found, false);
1509
+ assert.equal(result.phase_dir, null);
1510
+ });
1511
+
1512
+ it('phase-op rejects archived-only phase 50', () => {
1513
+ const result = runInit(fixture.cwd, 'phase-op 50');
1514
+ assert.equal(result.phase_found, false);
1515
+ assert.equal(result.phase_dir, null);
1516
+ });
1517
+
1518
+ it('execute-phase still finds active phase 1', () => {
1519
+ const result = runInit(fixture.cwd, 'execute-phase 1');
1520
+ assert.equal(result.phase_found, true);
1521
+ assert.ok(result.phase_dir);
1522
+ });
1523
+ });