@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
|
@@ -1148,7 +1148,7 @@ 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
|
-
'config.json': JSON.stringify({ current_project: 'myapp'
|
|
1151
|
+
'config.json': JSON.stringify({ current_project: 'myapp' }),
|
|
1152
1152
|
'STATE.md': '# State',
|
|
1153
1153
|
'ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 3: Auth** - Auth\n',
|
|
1154
1154
|
'REQUIREMENTS.md': '# Requirements',
|
|
@@ -1157,7 +1157,7 @@ describe('branch_name with {project} resolution', () => {
|
|
|
1157
1157
|
});
|
|
1158
1158
|
try {
|
|
1159
1159
|
const result = runInit(fixture.cwd, 'execute-phase 3');
|
|
1160
|
-
assert.equal(result.branch_name, 'dgs/myapp/
|
|
1160
|
+
assert.equal(result.branch_name, 'dgs/myapp/v1.0-milestone');
|
|
1161
1161
|
} finally {
|
|
1162
1162
|
fixture.cleanup();
|
|
1163
1163
|
}
|
|
@@ -1165,7 +1165,7 @@ 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
|
-
'config.json': JSON.stringify({ current_project: 'checkout'
|
|
1168
|
+
'config.json': JSON.stringify({ current_project: 'checkout' }),
|
|
1169
1169
|
'PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| checkout | Active |\n',
|
|
1170
1170
|
'REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
|
|
1171
1171
|
'projects/checkout/STATE.md': '# State',
|
|
@@ -1176,13 +1176,13 @@ describe('branch_name with {project} resolution', () => {
|
|
|
1176
1176
|
});
|
|
1177
1177
|
try {
|
|
1178
1178
|
const result = runInit(fixture.cwd, 'execute-phase 1');
|
|
1179
|
-
assert.equal(result.branch_name, 'dgs/checkout/
|
|
1179
|
+
assert.equal(result.branch_name, 'dgs/checkout/v1.0-milestone');
|
|
1180
1180
|
} finally {
|
|
1181
1181
|
fixture.cleanup();
|
|
1182
1182
|
}
|
|
1183
1183
|
});
|
|
1184
1184
|
|
|
1185
|
-
it('branch_name
|
|
1185
|
+
it('branch_name always uses milestone template regardless of config', () => {
|
|
1186
1186
|
const fixture = createFixture({
|
|
1187
1187
|
'config.json': JSON.stringify({
|
|
1188
1188
|
current_project: 'myapp',
|
|
@@ -1196,7 +1196,7 @@ describe('branch_name with {project} resolution', () => {
|
|
|
1196
1196
|
});
|
|
1197
1197
|
try {
|
|
1198
1198
|
const result = runInit(fixture.cwd, 'execute-phase 3');
|
|
1199
|
-
assert.equal(result.branch_name, '
|
|
1199
|
+
assert.equal(result.branch_name, 'dgs/myapp/v1.0-milestone');
|
|
1200
1200
|
} finally {
|
|
1201
1201
|
fixture.cleanup();
|
|
1202
1202
|
}
|
|
@@ -1521,3 +1521,413 @@ describe('archived milestone phase rejection', () => {
|
|
|
1521
1521
|
assert.ok(result.phase_dir);
|
|
1522
1522
|
});
|
|
1523
1523
|
});
|
|
1524
|
+
|
|
1525
|
+
// ─── cmdInitQuick quick_dir resolution ──────────────────────────────────────
|
|
1526
|
+
|
|
1527
|
+
describe('cmdInitQuick quick_dir resolution', () => {
|
|
1528
|
+
describe('product mode (no active milestone)', () => {
|
|
1529
|
+
let fixture;
|
|
1530
|
+
|
|
1531
|
+
beforeEach(() => {
|
|
1532
|
+
fixture = v2FixtureWithProject();
|
|
1533
|
+
});
|
|
1534
|
+
|
|
1535
|
+
afterEach(() => {
|
|
1536
|
+
fixture.cleanup();
|
|
1537
|
+
});
|
|
1538
|
+
|
|
1539
|
+
it('init quick uses product-root quick_dir in product mode (no active milestone)', () => {
|
|
1540
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1541
|
+
assert.equal(result.quick_dir, 'quick');
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
it('task_dir follows quick_dir in product mode', () => {
|
|
1545
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1546
|
+
assert.ok(result.task_dir, 'task_dir should be set');
|
|
1547
|
+
assert.ok(result.task_dir.startsWith('quick/'), 'task_dir should start with quick/');
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
it('state_path resolves to product-root in product mode', () => {
|
|
1551
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1552
|
+
assert.equal(result.state_path, 'STATE.md');
|
|
1553
|
+
});
|
|
1554
|
+
|
|
1555
|
+
it('roadmap_exists remains project-scoped in product mode', () => {
|
|
1556
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1557
|
+
assert.equal(result.roadmap_exists, true);
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
it('creates planning-root STATE.md on demand when missing', () => {
|
|
1561
|
+
// Remove the planning-root STATE.md if present (fixture has a project STATE.md but not a product one)
|
|
1562
|
+
const productStatePath = path.join(fixture.cwd, 'STATE.md');
|
|
1563
|
+
if (fs.existsSync(productStatePath)) {
|
|
1564
|
+
fs.unlinkSync(productStatePath);
|
|
1565
|
+
}
|
|
1566
|
+
assert.equal(fs.existsSync(productStatePath), false, 'precondition: product STATE.md absent');
|
|
1567
|
+
|
|
1568
|
+
runInit(fixture.cwd, 'quick "test task"');
|
|
1569
|
+
|
|
1570
|
+
assert.equal(fs.existsSync(productStatePath), true, 'product STATE.md should be auto-created');
|
|
1571
|
+
const contents = fs.readFileSync(productStatePath, 'utf-8');
|
|
1572
|
+
assert.match(contents, /### Blockers\/Concerns/, 'skeleton should contain Blockers/Concerns anchor');
|
|
1573
|
+
});
|
|
1574
|
+
});
|
|
1575
|
+
|
|
1576
|
+
describe('milestone-context mode (active milestone)', () => {
|
|
1577
|
+
let fixture;
|
|
1578
|
+
|
|
1579
|
+
beforeEach(() => {
|
|
1580
|
+
fixture = createFixture({
|
|
1581
|
+
'config.json': JSON.stringify({ current_project: 'test-project' }),
|
|
1582
|
+
'config.local.json': JSON.stringify({
|
|
1583
|
+
execution: { active_context: 'v19-git-worktrees' },
|
|
1584
|
+
projects: {
|
|
1585
|
+
'test-project': {
|
|
1586
|
+
worktrees: {
|
|
1587
|
+
'v19-git-worktrees': { type: 'milestone' }
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
}),
|
|
1592
|
+
'PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| test-project | Active |\n',
|
|
1593
|
+
'REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
|
|
1594
|
+
'projects/test-project/STATE.md': '# State',
|
|
1595
|
+
'projects/test-project/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
|
|
1596
|
+
'projects/test-project/REQUIREMENTS.md': '# Requirements',
|
|
1597
|
+
'projects/test-project/PROJECT.md': '# Project',
|
|
1598
|
+
'projects/test-project/phases/01-test-phase/01-CONTEXT.md': '# Context',
|
|
1599
|
+
'projects/test-project/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
|
|
1600
|
+
});
|
|
1601
|
+
});
|
|
1602
|
+
|
|
1603
|
+
afterEach(() => {
|
|
1604
|
+
fixture.cleanup();
|
|
1605
|
+
});
|
|
1606
|
+
|
|
1607
|
+
it('init quick uses project quick_dir when in milestone context', () => {
|
|
1608
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1609
|
+
assert.equal(result.quick_dir, 'projects/test-project/quick');
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
it('state_path remains project-scoped in milestone-context mode', () => {
|
|
1613
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1614
|
+
assert.equal(result.state_path, 'projects/test-project/STATE.md');
|
|
1615
|
+
});
|
|
1616
|
+
});
|
|
1617
|
+
|
|
1618
|
+
describe('--main flag override', () => {
|
|
1619
|
+
let fixture;
|
|
1620
|
+
|
|
1621
|
+
beforeEach(() => {
|
|
1622
|
+
fixture = createFixture({
|
|
1623
|
+
'config.json': JSON.stringify({ current_project: 'test-project' }),
|
|
1624
|
+
'config.local.json': JSON.stringify({
|
|
1625
|
+
execution: { active_context: 'v19-git-worktrees' },
|
|
1626
|
+
projects: {
|
|
1627
|
+
'test-project': {
|
|
1628
|
+
worktrees: {
|
|
1629
|
+
'v19-git-worktrees': { type: 'milestone' }
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
}),
|
|
1634
|
+
'PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| test-project | Active |\n',
|
|
1635
|
+
'REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
|
|
1636
|
+
'projects/test-project/STATE.md': '# State',
|
|
1637
|
+
'projects/test-project/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
|
|
1638
|
+
'projects/test-project/REQUIREMENTS.md': '# Requirements',
|
|
1639
|
+
'projects/test-project/PROJECT.md': '# Project',
|
|
1640
|
+
'projects/test-project/phases/01-test-phase/01-CONTEXT.md': '# Context',
|
|
1641
|
+
'projects/test-project/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
|
|
1642
|
+
});
|
|
1643
|
+
});
|
|
1644
|
+
|
|
1645
|
+
afterEach(() => {
|
|
1646
|
+
fixture.cleanup();
|
|
1647
|
+
});
|
|
1648
|
+
|
|
1649
|
+
it('init quick --main forces product-level quick_dir even with active milestone', () => {
|
|
1650
|
+
const result = runInit(fixture.cwd, 'quick --main "test task"');
|
|
1651
|
+
assert.equal(result.quick_dir, 'quick');
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
it('init quick --main forces product-level state_path even with active milestone', () => {
|
|
1655
|
+
const result = runInit(fixture.cwd, 'quick --main "test task"');
|
|
1656
|
+
assert.equal(result.state_path, 'STATE.md');
|
|
1657
|
+
});
|
|
1658
|
+
|
|
1659
|
+
it('init quick --main strips flag from description', () => {
|
|
1660
|
+
const result = runInit(fixture.cwd, 'quick --main "test task"');
|
|
1661
|
+
assert.equal(result.description, 'test task');
|
|
1662
|
+
});
|
|
1663
|
+
});
|
|
1664
|
+
});
|
|
1665
|
+
|
|
1666
|
+
// ─── init progress-all ───────────────────────────────────────────────────────
|
|
1667
|
+
|
|
1668
|
+
describe('init progress-all: v2 fixture with 1 active project', () => {
|
|
1669
|
+
let fixture;
|
|
1670
|
+
let result;
|
|
1671
|
+
|
|
1672
|
+
beforeEach(() => {
|
|
1673
|
+
fixture = createFixture({
|
|
1674
|
+
'config.json': JSON.stringify({ current_project: 'alpha' }),
|
|
1675
|
+
'PROJECTS.md': '# Projects\n\n| Project | Status |\n|---------|--------|\n| alpha | Active |\n',
|
|
1676
|
+
'REPOS.md': '# Repos\n\n| Name | Path |\n|------|------|\n',
|
|
1677
|
+
'projects/alpha/STATE.md': '# Project State\n\nPhase: 3\nStatus: In progress\nProgress: [####------] 40%\n',
|
|
1678
|
+
'projects/alpha/ROADMAP.md': '# Roadmap\n\n- 🚧 **v2.0 Auth** — Phases 1-5 (in progress)\n',
|
|
1679
|
+
'projects/alpha/PROJECT.md': '# Project',
|
|
1680
|
+
});
|
|
1681
|
+
result = runInit(fixture.cwd, 'progress-all --raw');
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1684
|
+
afterEach(() => {
|
|
1685
|
+
fixture.cleanup();
|
|
1686
|
+
});
|
|
1687
|
+
|
|
1688
|
+
it('returns valid JSON with product and projects keys', () => {
|
|
1689
|
+
assert.ok(result.product, 'result.product must exist');
|
|
1690
|
+
assert.ok(Array.isArray(result.projects), 'result.projects must be an array');
|
|
1691
|
+
});
|
|
1692
|
+
|
|
1693
|
+
it('product has active_count, completed_count, and backlog', () => {
|
|
1694
|
+
assert.equal(typeof result.product.active_count, 'number');
|
|
1695
|
+
assert.equal(typeof result.product.completed_count, 'number');
|
|
1696
|
+
assert.ok(result.product.backlog, 'product.backlog must exist');
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
it('product.backlog has all four int fields (todos, ideas, specs, debug_active)', () => {
|
|
1700
|
+
assert.equal(typeof result.product.backlog.todos, 'number');
|
|
1701
|
+
assert.equal(typeof result.product.backlog.ideas, 'number');
|
|
1702
|
+
assert.equal(typeof result.product.backlog.specs, 'number');
|
|
1703
|
+
assert.equal(typeof result.product.backlog.debug_active, 'number');
|
|
1704
|
+
});
|
|
1705
|
+
|
|
1706
|
+
it('product.backlog counts are all zero on empty fixture', () => {
|
|
1707
|
+
assert.equal(result.product.backlog.todos, 0);
|
|
1708
|
+
assert.equal(result.product.backlog.ideas, 0);
|
|
1709
|
+
assert.equal(result.product.backlog.specs, 0);
|
|
1710
|
+
assert.equal(result.product.backlog.debug_active, 0);
|
|
1711
|
+
});
|
|
1712
|
+
|
|
1713
|
+
it('product.quick_tasks_recent is [] when product-level STATE.md has no Quick Tasks table', () => {
|
|
1714
|
+
assert.deepEqual(result.product.quick_tasks_recent, []);
|
|
1715
|
+
});
|
|
1716
|
+
|
|
1717
|
+
it('product.shipped_milestones_recent is [] when product-level MILESTONES.md is missing', () => {
|
|
1718
|
+
assert.deepEqual(result.product.shipped_milestones_recent, []);
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
it('projects array has 1 active project', () => {
|
|
1722
|
+
assert.equal(result.projects.length, 1);
|
|
1723
|
+
assert.equal(result.projects[0].name, 'alpha');
|
|
1724
|
+
});
|
|
1725
|
+
|
|
1726
|
+
it('project entry has expected fields', () => {
|
|
1727
|
+
const p = result.projects[0];
|
|
1728
|
+
assert.equal(typeof p.name, 'string');
|
|
1729
|
+
assert.equal(typeof p.status, 'string');
|
|
1730
|
+
assert.equal(typeof p.current_phase, 'string');
|
|
1731
|
+
assert.equal(typeof p.progress, 'number');
|
|
1732
|
+
assert.equal(typeof p.repos_touched, 'string');
|
|
1733
|
+
assert.ok('milestone_version' in p);
|
|
1734
|
+
assert.ok('milestone_name' in p);
|
|
1735
|
+
});
|
|
1736
|
+
|
|
1737
|
+
it('project milestone_version is parsed from ROADMAP.md', () => {
|
|
1738
|
+
assert.equal(result.projects[0].milestone_version, 'v2.0');
|
|
1739
|
+
assert.equal(result.projects[0].milestone_name, 'Auth');
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
it('returns top-level auth, dgs_mode, planner_model, executor_model', () => {
|
|
1743
|
+
assert.ok('author' in result);
|
|
1744
|
+
assert.equal(typeof result.dgs_mode, 'string');
|
|
1745
|
+
assert.ok('planner_model' in result);
|
|
1746
|
+
assert.ok('executor_model' in result);
|
|
1747
|
+
});
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1750
|
+
describe('init progress-all: excludes completed projects', () => {
|
|
1751
|
+
let fixture;
|
|
1752
|
+
let result;
|
|
1753
|
+
|
|
1754
|
+
beforeEach(() => {
|
|
1755
|
+
fixture = createFixture({
|
|
1756
|
+
'config.json': JSON.stringify({}),
|
|
1757
|
+
'PROJECTS.md': '# Projects\n',
|
|
1758
|
+
'REPOS.md': '# Repos\n',
|
|
1759
|
+
'projects/active-x/STATE.md': '# Project State\n\nPhase: 1\nStatus: In progress\nProgress: [#---------] 10%\n',
|
|
1760
|
+
'projects/done-y/STATE.md': '# Project State\n\nPhase: 5\nStatus: completed\nProgress: [##########] 100%\nCompleted: 2026-01-20\n',
|
|
1761
|
+
});
|
|
1762
|
+
result = runInit(fixture.cwd, 'progress-all --raw');
|
|
1763
|
+
});
|
|
1764
|
+
|
|
1765
|
+
afterEach(() => {
|
|
1766
|
+
fixture.cleanup();
|
|
1767
|
+
});
|
|
1768
|
+
|
|
1769
|
+
it('projects array excludes completed projects', () => {
|
|
1770
|
+
assert.equal(result.projects.length, 1);
|
|
1771
|
+
assert.equal(result.projects[0].name, 'active-x');
|
|
1772
|
+
});
|
|
1773
|
+
|
|
1774
|
+
it('product.active_count and completed_count reflect the split', () => {
|
|
1775
|
+
assert.equal(result.product.active_count, 1);
|
|
1776
|
+
assert.equal(result.product.completed_count, 1);
|
|
1777
|
+
});
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1780
|
+
describe('init progress-all: empty projects dir', () => {
|
|
1781
|
+
let fixture;
|
|
1782
|
+
let result;
|
|
1783
|
+
|
|
1784
|
+
beforeEach(() => {
|
|
1785
|
+
fixture = createFixture({
|
|
1786
|
+
'config.json': JSON.stringify({}),
|
|
1787
|
+
'PROJECTS.md': '# Projects\n',
|
|
1788
|
+
'REPOS.md': '# Repos\n',
|
|
1789
|
+
});
|
|
1790
|
+
result = runInit(fixture.cwd, 'progress-all --raw');
|
|
1791
|
+
});
|
|
1792
|
+
|
|
1793
|
+
afterEach(() => {
|
|
1794
|
+
fixture.cleanup();
|
|
1795
|
+
});
|
|
1796
|
+
|
|
1797
|
+
it('projects is [] and active_count is 0', () => {
|
|
1798
|
+
assert.deepEqual(result.projects, []);
|
|
1799
|
+
assert.equal(result.product.active_count, 0);
|
|
1800
|
+
});
|
|
1801
|
+
});
|
|
1802
|
+
|
|
1803
|
+
describe('init progress-all: parses product-level STATE.md quick tasks', () => {
|
|
1804
|
+
let fixture;
|
|
1805
|
+
let result;
|
|
1806
|
+
|
|
1807
|
+
beforeEach(() => {
|
|
1808
|
+
const productState = `# Project State
|
|
1809
|
+
|
|
1810
|
+
## Accumulated Context
|
|
1811
|
+
|
|
1812
|
+
### Quick Tasks Completed
|
|
1813
|
+
|
|
1814
|
+
| # | Description | Date | Commit | Status | Directory |
|
|
1815
|
+
|---|-------------|------|--------|--------|-----------|
|
|
1816
|
+
| 260405-laf | Route product quick tasks | 2026-04-05 | 368074f | Verified | [260405-laf](./quick/260405-laf/) |
|
|
1817
|
+
| 260405-lvk | Strip trailing hyphen | 2026-04-05 | 536382a | | fast |
|
|
1818
|
+
| 260405-mbu | Make fast context-aware | 2026-04-05 | d79ffbc | Verified | [260405-mbu](./quick/260405-mbu/) |
|
|
1819
|
+
`;
|
|
1820
|
+
fixture = createFixture({
|
|
1821
|
+
'config.json': JSON.stringify({}),
|
|
1822
|
+
'PROJECTS.md': '# Projects\n',
|
|
1823
|
+
'REPOS.md': '# Repos\n',
|
|
1824
|
+
'STATE.md': productState,
|
|
1825
|
+
'projects/alpha/STATE.md': '# Project State\n\nPhase: 1\nStatus: In progress\n',
|
|
1826
|
+
});
|
|
1827
|
+
result = runInit(fixture.cwd, 'progress-all --raw');
|
|
1828
|
+
});
|
|
1829
|
+
|
|
1830
|
+
afterEach(() => {
|
|
1831
|
+
fixture.cleanup();
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
it('parses quick_tasks_recent with 3 entries', () => {
|
|
1835
|
+
assert.equal(result.product.quick_tasks_recent.length, 3);
|
|
1836
|
+
});
|
|
1837
|
+
|
|
1838
|
+
it('quick task entries have id, description, date, commit fields', () => {
|
|
1839
|
+
const q = result.product.quick_tasks_recent[0];
|
|
1840
|
+
assert.ok(q.id);
|
|
1841
|
+
assert.ok(q.description);
|
|
1842
|
+
assert.ok(q.date);
|
|
1843
|
+
assert.ok(q.commit);
|
|
1844
|
+
});
|
|
1845
|
+
});
|
|
1846
|
+
|
|
1847
|
+
describe('init progress-all: parses product-level MILESTONES.md shipped milestones', () => {
|
|
1848
|
+
let fixture;
|
|
1849
|
+
let result;
|
|
1850
|
+
|
|
1851
|
+
beforeEach(() => {
|
|
1852
|
+
const milestones = `# Milestones
|
|
1853
|
+
|
|
1854
|
+
## v19.0 Git Worktrees (Shipped: 2026-03-27)
|
|
1855
|
+
|
|
1856
|
+
Some content.
|
|
1857
|
+
|
|
1858
|
+
## v18.0 Root Layout (Shipped: 2026-03-25)
|
|
1859
|
+
|
|
1860
|
+
Some content.
|
|
1861
|
+
|
|
1862
|
+
## v1.0 Multi-Project Platform (Shipped: 2026-02-24)
|
|
1863
|
+
|
|
1864
|
+
Some content.
|
|
1865
|
+
`;
|
|
1866
|
+
fixture = createFixture({
|
|
1867
|
+
'config.json': JSON.stringify({}),
|
|
1868
|
+
'PROJECTS.md': '# Projects\n',
|
|
1869
|
+
'REPOS.md': '# Repos\n',
|
|
1870
|
+
'MILESTONES.md': milestones,
|
|
1871
|
+
'projects/alpha/STATE.md': '# Project State\n\nPhase: 1\nStatus: In progress\n',
|
|
1872
|
+
});
|
|
1873
|
+
result = runInit(fixture.cwd, 'progress-all --raw');
|
|
1874
|
+
});
|
|
1875
|
+
|
|
1876
|
+
afterEach(() => {
|
|
1877
|
+
fixture.cleanup();
|
|
1878
|
+
});
|
|
1879
|
+
|
|
1880
|
+
it('parses shipped_milestones_recent with 3 entries', () => {
|
|
1881
|
+
assert.equal(result.product.shipped_milestones_recent.length, 3);
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
it('shipped milestone entries have version, name, shipped_date fields', () => {
|
|
1885
|
+
const m = result.product.shipped_milestones_recent[0];
|
|
1886
|
+
assert.equal(m.version, 'v19.0');
|
|
1887
|
+
assert.equal(m.name, 'Git Worktrees');
|
|
1888
|
+
assert.equal(m.shipped_date, '2026-03-27');
|
|
1889
|
+
});
|
|
1890
|
+
});
|
|
1891
|
+
|
|
1892
|
+
describe('init progress-all: counts backlog files', () => {
|
|
1893
|
+
let fixture;
|
|
1894
|
+
let result;
|
|
1895
|
+
|
|
1896
|
+
beforeEach(() => {
|
|
1897
|
+
fixture = createFixture({
|
|
1898
|
+
'config.json': JSON.stringify({}),
|
|
1899
|
+
'PROJECTS.md': '# Projects\n',
|
|
1900
|
+
'REPOS.md': '# Repos\n',
|
|
1901
|
+
'todos/pending/todo-1.md': '# todo 1',
|
|
1902
|
+
'todos/pending/todo-2.md': '# todo 2',
|
|
1903
|
+
'ideas/pending/idea-1.md': '# idea 1',
|
|
1904
|
+
'specs/spec-1.md': '# spec 1',
|
|
1905
|
+
'specs/spec-2.md': '# spec 2',
|
|
1906
|
+
'specs/spec-3.md': '# spec 3',
|
|
1907
|
+
'debug/active-session.md': '# debug',
|
|
1908
|
+
'debug/session-resolved.md': '# resolved',
|
|
1909
|
+
'projects/alpha/STATE.md': '# Project State\n\nPhase: 1\nStatus: In progress\n',
|
|
1910
|
+
});
|
|
1911
|
+
result = runInit(fixture.cwd, 'progress-all --raw');
|
|
1912
|
+
});
|
|
1913
|
+
|
|
1914
|
+
afterEach(() => {
|
|
1915
|
+
fixture.cleanup();
|
|
1916
|
+
});
|
|
1917
|
+
|
|
1918
|
+
it('counts todos in todos/pending/', () => {
|
|
1919
|
+
assert.equal(result.product.backlog.todos, 2);
|
|
1920
|
+
});
|
|
1921
|
+
|
|
1922
|
+
it('counts ideas in ideas/pending/', () => {
|
|
1923
|
+
assert.equal(result.product.backlog.ideas, 1);
|
|
1924
|
+
});
|
|
1925
|
+
|
|
1926
|
+
it('counts specs in specs/ (top-level only)', () => {
|
|
1927
|
+
assert.equal(result.product.backlog.specs, 3);
|
|
1928
|
+
});
|
|
1929
|
+
|
|
1930
|
+
it('counts debug files excluding those with "resolved" in name', () => {
|
|
1931
|
+
assert.equal(result.product.backlog.debug_active, 1);
|
|
1932
|
+
});
|
|
1933
|
+
});
|