gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.848dd4c
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/README.md +30 -12
- package/dist/resources/extensions/gsd/auto-start.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto-start.ts +14 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +152 -183
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +9 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_ssgManifest.js +0 -0
|
@@ -20,11 +20,11 @@ import {
|
|
|
20
20
|
parseSliceBranch,
|
|
21
21
|
} from '../worktree.ts';
|
|
22
22
|
import { clearPathCache } from '../paths.ts';
|
|
23
|
-
import {
|
|
23
|
+
import { describe, test, beforeEach, afterEach } from 'node:test';
|
|
24
|
+
import assert from 'node:assert/strict';
|
|
24
25
|
|
|
25
26
|
// ─── Assertion Helpers ────────────────────────────────────────────────────
|
|
26
27
|
|
|
27
|
-
const { assertEq, assertTrue, assertMatch, report } = createTestContext();
|
|
28
28
|
// ─── Fixture Helpers ──────────────────────────────────────────────────────
|
|
29
29
|
|
|
30
30
|
function createFixtureBase(): string {
|
|
@@ -79,11 +79,9 @@ function createGitRepo(): string {
|
|
|
79
79
|
// Test Groups
|
|
80
80
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
81
81
|
|
|
82
|
-
async function main(): Promise<void> {
|
|
83
|
-
|
|
84
82
|
// ─── Group 1: deriveState with new-format-only milestones ─────────────
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
|
|
84
|
+
test('Group 1: deriveState with new-format-only milestones', async () => {
|
|
87
85
|
const base = createFixtureBase();
|
|
88
86
|
try {
|
|
89
87
|
// Create M001-abc123 with roadmap + 2 slices (S01 complete, S02 in-progress)
|
|
@@ -125,32 +123,32 @@ async function main(): Promise<void> {
|
|
|
125
123
|
const state = await deriveState(base);
|
|
126
124
|
|
|
127
125
|
// Phase should be executing (active milestone with incomplete slice + plan + tasks)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
assert.deepStrictEqual(state.phase, 'executing', 'G1: phase is executing');
|
|
127
|
+
assert.ok(state.activeMilestone !== null, 'G1: activeMilestone is not null');
|
|
128
|
+
assert.deepStrictEqual(state.activeMilestone?.id, 'M001-abc123', 'G1: activeMilestone id is M001-abc123');
|
|
129
|
+
assert.deepStrictEqual(state.activeMilestone?.title, 'Test Feature', 'G1: title stripped to Test Feature');
|
|
132
130
|
|
|
133
131
|
// Registry
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
assert.deepStrictEqual(state.registry.length, 1, 'G1: registry has 1 entry');
|
|
133
|
+
assert.deepStrictEqual(state.registry[0]?.id, 'M001-abc123', 'G1: registry entry id');
|
|
134
|
+
assert.deepStrictEqual(state.registry[0]?.status, 'active', 'G1: registry entry status is active');
|
|
135
|
+
assert.deepStrictEqual(state.registry[0]?.title, 'Test Feature', 'G1: registry title stripped');
|
|
138
136
|
|
|
139
137
|
// Active slice
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
assert.ok(state.activeSlice !== null, 'G1: activeSlice is not null');
|
|
139
|
+
assert.deepStrictEqual(state.activeSlice?.id, 'S02', 'G1: activeSlice is S02');
|
|
142
140
|
|
|
143
141
|
// Progress
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
assert.deepStrictEqual(state.progress?.milestones?.done, 0, 'G1: milestones done = 0');
|
|
143
|
+
assert.deepStrictEqual(state.progress?.milestones?.total, 1, 'G1: milestones total = 1');
|
|
146
144
|
} finally {
|
|
147
145
|
cleanup(base);
|
|
148
146
|
}
|
|
149
|
-
|
|
147
|
+
});
|
|
150
148
|
|
|
151
149
|
// ─── Group 2: deriveState with mixed-format milestones ────────────────
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
|
|
151
|
+
test('Group 2: deriveState with mixed old+new format milestones', async () => {
|
|
154
152
|
const base = createFixtureBase();
|
|
155
153
|
try {
|
|
156
154
|
// M001 — complete milestone (all slices done + summary)
|
|
@@ -217,40 +215,40 @@ Everything worked.
|
|
|
217
215
|
const state = await deriveState(base);
|
|
218
216
|
|
|
219
217
|
// Registry — should have 2 entries sorted by seq number
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
218
|
+
assert.deepStrictEqual(state.registry.length, 2, 'G2: registry has 2 entries');
|
|
219
|
+
assert.deepStrictEqual(state.registry[0]?.id, 'M001', 'G2: registry[0] is M001 (sorted first)');
|
|
220
|
+
assert.deepStrictEqual(state.registry[1]?.id, 'M002-abc123', 'G2: registry[1] is M002-abc123 (sorted second)');
|
|
223
221
|
|
|
224
222
|
// M001 is complete
|
|
225
|
-
|
|
226
|
-
|
|
223
|
+
assert.deepStrictEqual(state.registry[0]?.status, 'complete', 'G2: M001 status is complete');
|
|
224
|
+
assert.deepStrictEqual(state.registry[0]?.title, 'Legacy Feature', 'G2: M001 title stripped');
|
|
227
225
|
|
|
228
226
|
// M002-abc123 is active
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
assert.deepStrictEqual(state.registry[1]?.status, 'active', 'G2: M002-abc123 status is active');
|
|
228
|
+
assert.deepStrictEqual(state.registry[1]?.title, 'New Feature', 'G2: M002-abc123 title stripped');
|
|
231
229
|
|
|
232
230
|
// Active milestone
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
231
|
+
assert.ok(state.activeMilestone !== null, 'G2: activeMilestone is not null');
|
|
232
|
+
assert.deepStrictEqual(state.activeMilestone?.id, 'M002-abc123', 'G2: activeMilestone is M002-abc123');
|
|
233
|
+
assert.deepStrictEqual(state.activeMilestone?.title, 'New Feature', 'G2: activeMilestone title stripped');
|
|
236
234
|
|
|
237
235
|
// Phase
|
|
238
|
-
|
|
236
|
+
assert.deepStrictEqual(state.phase, 'executing', 'G2: phase is executing');
|
|
239
237
|
|
|
240
238
|
// Active slice
|
|
241
|
-
|
|
239
|
+
assert.deepStrictEqual(state.activeSlice?.id, 'S02', 'G2: activeSlice is S02');
|
|
242
240
|
|
|
243
241
|
// Progress
|
|
244
|
-
|
|
245
|
-
|
|
242
|
+
assert.deepStrictEqual(state.progress?.milestones?.done, 1, 'G2: milestones done = 1');
|
|
243
|
+
assert.deepStrictEqual(state.progress?.milestones?.total, 2, 'G2: milestones total = 2');
|
|
246
244
|
} finally {
|
|
247
245
|
cleanup(base);
|
|
248
246
|
}
|
|
249
|
-
|
|
247
|
+
});
|
|
250
248
|
|
|
251
249
|
// ─── Group 3: indexWorkspace with mixed-format milestones ─────────────
|
|
252
|
-
|
|
253
|
-
|
|
250
|
+
|
|
251
|
+
test('Group 3: indexWorkspace with mixed-format milestones', async () => {
|
|
254
252
|
const base = createFixtureBase();
|
|
255
253
|
try {
|
|
256
254
|
// Same fixture as Group 2: M001 (complete) + M002-abc123 (active)
|
|
@@ -304,39 +302,39 @@ Everything worked.
|
|
|
304
302
|
const index = await indexWorkspace(base);
|
|
305
303
|
|
|
306
304
|
// Both milestones indexed
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
305
|
+
assert.deepStrictEqual(index.milestones.length, 2, 'G3: 2 milestones in index');
|
|
306
|
+
assert.deepStrictEqual(index.milestones[0]?.id, 'M001', 'G3: index[0] is M001');
|
|
307
|
+
assert.deepStrictEqual(index.milestones[1]?.id, 'M002-abc123', 'G3: index[1] is M002-abc123');
|
|
310
308
|
|
|
311
309
|
// Titles stripped from both formats
|
|
312
|
-
|
|
313
|
-
|
|
310
|
+
assert.deepStrictEqual(index.milestones[0]?.title, 'Legacy Feature', 'G3: M001 title stripped');
|
|
311
|
+
assert.deepStrictEqual(index.milestones[1]?.title, 'New Feature', 'G3: M002-abc123 title stripped');
|
|
314
312
|
|
|
315
313
|
// Active state
|
|
316
|
-
|
|
317
|
-
|
|
314
|
+
assert.deepStrictEqual(index.active.milestoneId, 'M002-abc123', 'G3: active milestone is M002-abc123');
|
|
315
|
+
assert.deepStrictEqual(index.active.sliceId, 'S01', 'G3: active slice is S01');
|
|
318
316
|
|
|
319
317
|
// Scopes include new-format paths
|
|
320
|
-
|
|
318
|
+
assert.ok(
|
|
321
319
|
index.scopes.some(s => s.scope === 'M002-abc123'),
|
|
322
320
|
'G3: scope includes M002-abc123 milestone',
|
|
323
321
|
);
|
|
324
|
-
|
|
322
|
+
assert.ok(
|
|
325
323
|
index.scopes.some(s => s.scope === 'M002-abc123/S01'),
|
|
326
324
|
'G3: scope includes M002-abc123/S01 slice',
|
|
327
325
|
);
|
|
328
|
-
|
|
326
|
+
assert.ok(
|
|
329
327
|
index.scopes.some(s => s.scope === 'M002-abc123/S01/T01'),
|
|
330
328
|
'G3: scope includes M002-abc123/S01/T01 task',
|
|
331
329
|
);
|
|
332
330
|
} finally {
|
|
333
331
|
cleanup(base);
|
|
334
332
|
}
|
|
335
|
-
|
|
333
|
+
});
|
|
336
334
|
|
|
337
335
|
// ─── Group 4: inlinePriorMilestoneSummary with mixed formats ──────────
|
|
338
|
-
|
|
339
|
-
|
|
336
|
+
|
|
337
|
+
test('Group 4: inlinePriorMilestoneSummary with mixed formats', async () => {
|
|
340
338
|
const base = createFixtureBase();
|
|
341
339
|
try {
|
|
342
340
|
// M001 — completed with summary
|
|
@@ -358,21 +356,21 @@ Built the legacy feature successfully.
|
|
|
358
356
|
const result = await inlinePriorMilestoneSummary('M002-abc123', base);
|
|
359
357
|
|
|
360
358
|
// Result should be non-null (M001 is before M002-abc123)
|
|
361
|
-
|
|
362
|
-
|
|
359
|
+
assert.ok(result !== null, 'G4: result is non-null');
|
|
360
|
+
assert.ok(typeof result === 'string', 'G4: result is a string');
|
|
363
361
|
|
|
364
362
|
// Should contain the M001 summary content
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
363
|
+
assert.ok(result!.includes('Prior Milestone Summary'), 'G4: contains Prior Milestone Summary header');
|
|
364
|
+
assert.ok(result!.includes('Built the legacy feature successfully'), 'G4: contains M001 summary content');
|
|
365
|
+
assert.ok(result!.includes('Used old format for milestone IDs'), 'G4: contains M001 key decisions');
|
|
368
366
|
} finally {
|
|
369
367
|
cleanup(base);
|
|
370
368
|
}
|
|
371
|
-
|
|
369
|
+
});
|
|
372
370
|
|
|
373
371
|
// ─── Group 5: dispatch-guard with new-format milestones ──────────────
|
|
374
|
-
|
|
375
|
-
|
|
372
|
+
|
|
373
|
+
test('Group 5: dispatch-guard with new-format milestones', () => {
|
|
376
374
|
const base = createGitRepo();
|
|
377
375
|
try {
|
|
378
376
|
// M001-abc123: all slices complete
|
|
@@ -403,28 +401,28 @@ Built the legacy feature successfully.
|
|
|
403
401
|
run('git commit -m init', base);
|
|
404
402
|
|
|
405
403
|
// No blocker: M001-abc123 is complete, dispatching M002-abc123/S01
|
|
406
|
-
|
|
404
|
+
assert.deepStrictEqual(
|
|
407
405
|
getPriorSliceCompletionBlocker(base, 'main', 'plan-slice', 'M002-abc123/S01'),
|
|
408
406
|
null,
|
|
409
407
|
'G5: no blocker for M002-abc123/S01 when M001-abc123 all complete',
|
|
410
408
|
);
|
|
411
409
|
|
|
412
410
|
// No blocker for first slice of first milestone
|
|
413
|
-
|
|
411
|
+
assert.deepStrictEqual(
|
|
414
412
|
getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M001-abc123/S01/T01'),
|
|
415
413
|
null,
|
|
416
414
|
'G5: no blocker for M001-abc123/S01/T01 (first milestone first slice)',
|
|
417
415
|
);
|
|
418
416
|
|
|
419
417
|
// Blocker: trying to dispatch M002-abc123/S02 when S01 is incomplete
|
|
420
|
-
|
|
418
|
+
assert.match(
|
|
421
419
|
getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M002-abc123/S02/T01') ?? '',
|
|
422
420
|
/M002-abc123\/S01 is not complete/,
|
|
423
421
|
'G5: blocks M002-abc123/S02 when S01 incomplete',
|
|
424
422
|
);
|
|
425
423
|
|
|
426
424
|
// Non-slice dispatch type should not be blocked
|
|
427
|
-
|
|
425
|
+
assert.deepStrictEqual(
|
|
428
426
|
getPriorSliceCompletionBlocker(base, 'main', 'plan-milestone', 'M002-abc123'),
|
|
429
427
|
null,
|
|
430
428
|
'G5: non-slice dispatch type not blocked',
|
|
@@ -447,7 +445,7 @@ Built the legacy feature successfully.
|
|
|
447
445
|
|
|
448
446
|
// M001 (seq=1) < M001-abc123 (seq=1) — but M001 has incomplete S02
|
|
449
447
|
// Since M001 seq=1 and M002-abc123 seq=2, blocker should reference M001/S02
|
|
450
|
-
|
|
448
|
+
assert.match(
|
|
451
449
|
getPriorSliceCompletionBlocker(base, 'main', 'plan-slice', 'M002-abc123/S01') ?? '',
|
|
452
450
|
/earlier slice M001\/S02 is not complete/,
|
|
453
451
|
'G5: mixed-format blocker references M001/S02',
|
|
@@ -468,7 +466,7 @@ Built the legacy feature successfully.
|
|
|
468
466
|
run('git commit -m complete-m001', base);
|
|
469
467
|
clearPathCache();
|
|
470
468
|
|
|
471
|
-
|
|
469
|
+
assert.deepStrictEqual(
|
|
472
470
|
getPriorSliceCompletionBlocker(base, 'main', 'plan-slice', 'M002-abc123/S01'),
|
|
473
471
|
null,
|
|
474
472
|
'G5: no blocker after M001 completed (mixed format)',
|
|
@@ -476,7 +474,7 @@ Built the legacy feature successfully.
|
|
|
476
474
|
|
|
477
475
|
// M001-abc123 still has all complete, M002-abc123/S01 still incomplete
|
|
478
476
|
// Check that S02 of M002-abc123 is still blocked by its own S01
|
|
479
|
-
|
|
477
|
+
assert.match(
|
|
480
478
|
getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M002-abc123/S02/T01') ?? '',
|
|
481
479
|
/M002-abc123\/S01 is not complete/,
|
|
482
480
|
'G5: intra-milestone blocker still works in mixed-format context',
|
|
@@ -508,7 +506,7 @@ Built the legacy feature successfully.
|
|
|
508
506
|
run('git commit -m add-m003', base);
|
|
509
507
|
clearPathCache();
|
|
510
508
|
|
|
511
|
-
|
|
509
|
+
assert.match(
|
|
512
510
|
getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M003-xyz789/S02/T01') ?? '',
|
|
513
511
|
/earlier slice M003-xyz789\/S01 is not complete/,
|
|
514
512
|
'G5: positional path produces "earlier slice" message with new-format milestone ID',
|
|
@@ -516,13 +514,13 @@ Built the legacy feature successfully.
|
|
|
516
514
|
} finally {
|
|
517
515
|
cleanup(base);
|
|
518
516
|
}
|
|
519
|
-
|
|
517
|
+
});
|
|
520
518
|
|
|
521
519
|
// ─── Group 6: Branch name helpers with new-format IDs ───────────────
|
|
522
|
-
|
|
523
|
-
|
|
520
|
+
|
|
521
|
+
test('Group 6: Branch name helpers with new-format IDs', () => {
|
|
524
522
|
// Test getSliceBranchName with new-format ID
|
|
525
|
-
|
|
523
|
+
assert.deepStrictEqual(
|
|
526
524
|
getSliceBranchName('M001-abc123', 'S01'),
|
|
527
525
|
'gsd/M001-abc123/S01',
|
|
528
526
|
'G6: getSliceBranchName returns gsd/M001-abc123/S01',
|
|
@@ -530,26 +528,12 @@ Built the legacy feature successfully.
|
|
|
530
528
|
|
|
531
529
|
// Test parseSliceBranch with new-format branch name
|
|
532
530
|
const parsed = parseSliceBranch('gsd/M001-abc123/S01');
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
531
|
+
assert.ok(parsed !== null, 'G6: parseSliceBranch returns non-null for new-format');
|
|
532
|
+
assert.deepStrictEqual(parsed?.milestoneId, 'M001-abc123', 'G6: parsed milestoneId is M001-abc123');
|
|
533
|
+
assert.deepStrictEqual(parsed?.sliceId, 'S01', 'G6: parsed sliceId is S01');
|
|
534
|
+
assert.deepStrictEqual(parsed?.worktreeName, null, 'G6: parsed worktreeName is null (no worktree)');
|
|
535
|
+
});
|
|
538
536
|
|
|
539
537
|
// ─── Summary ──────────────────────────────────────────────────────────
|
|
540
|
-
report();
|
|
541
|
-
}
|
|
542
538
|
|
|
543
|
-
// When run via vitest, wrap in test(); when run via tsx, call directly.
|
|
544
|
-
const isVitest = typeof globalThis !== 'undefined' && (globalThis as any).__vitest_worker__?.config?.defines != null && 'vitest' in (globalThis as any).__vitest_worker__.config.defines || process.env.VITEST;
|
|
545
|
-
if (isVitest) {
|
|
546
|
-
const { test } = await import('node:test');
|
|
547
|
-
test('integration-mixed-milestones: all groups pass', async () => {
|
|
548
|
-
await main();
|
|
549
|
-
});
|
|
550
|
-
} else {
|
|
551
|
-
main().catch((error) => {
|
|
552
|
-
console.error(error);
|
|
553
|
-
process.exit(1);
|
|
554
|
-
});
|
|
555
|
-
}
|
|
539
|
+
// When run via vitest, wrap in test(); when run via tsx, call directly.
|
|
@@ -278,8 +278,12 @@ test("full lifecycle: migration through completion through doctor", async (t) =>
|
|
|
278
278
|
const base = createRealisticFixture();
|
|
279
279
|
const dbPath = join(base, ".gsd", "gsd.db");
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
t.after(() => {
|
|
282
|
+
closeDatabase();
|
|
283
|
+
rmSync(base, { recursive: true, force: true });
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// ── (a) Open file-backed DB ──────────────────────────────────────
|
|
283
287
|
const opened = openDatabase(dbPath);
|
|
284
288
|
assert.equal(opened, true, "DB should open successfully");
|
|
285
289
|
assert.equal(isDbAvailable(), true, "DB should be available");
|
|
@@ -414,10 +418,6 @@ test("full lifecycle: migration through completion through doctor", async (t) =>
|
|
|
414
418
|
const rogues = detectRogueFileWrites("execute-task", "M001/S01/T99", base);
|
|
415
419
|
assert.ok(rogues.length > 0, "Should detect rogue file write for T99");
|
|
416
420
|
assert.equal(rogues[0].unitId, "M001/S01/T99", "Rogue detection should identify the correct unit");
|
|
417
|
-
} finally {
|
|
418
|
-
closeDatabase();
|
|
419
|
-
rmSync(base, { recursive: true, force: true });
|
|
420
|
-
}
|
|
421
421
|
});
|
|
422
422
|
|
|
423
423
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -429,8 +429,12 @@ test("recovery: DB loss → migrateFromMarkdown restores state, stale render det
|
|
|
429
429
|
const base = createRealisticFixture();
|
|
430
430
|
const dbPath = join(base, ".gsd", "gsd.db");
|
|
431
431
|
|
|
432
|
-
|
|
433
|
-
|
|
432
|
+
t.after(() => {
|
|
433
|
+
closeDatabase();
|
|
434
|
+
rmSync(base, { recursive: true, force: true });
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// Set up a completed state first
|
|
434
438
|
openDatabase(dbPath);
|
|
435
439
|
migrateHierarchyToDb(base);
|
|
436
440
|
await handleCompleteTask(makeCompleteTaskParams("T01"), base);
|
|
@@ -503,10 +507,6 @@ test("recovery: DB loss → migrateFromMarkdown restores state, stale render det
|
|
|
503
507
|
const t2Recovered = getTask("M001", "S01", "T02");
|
|
504
508
|
assert.ok(t2Recovered, "T02 should exist after recovery");
|
|
505
509
|
assert.equal(t2Recovered!.status, "complete", "T02 should be complete after recovery");
|
|
506
|
-
} finally {
|
|
507
|
-
closeDatabase();
|
|
508
|
-
rmSync(base, { recursive: true, force: true });
|
|
509
|
-
}
|
|
510
510
|
});
|
|
511
511
|
|
|
512
512
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -517,8 +517,12 @@ test("undo/reset: undo task and reset slice revert DB + markdown", async (t) =>
|
|
|
517
517
|
const base = createRealisticFixture();
|
|
518
518
|
const dbPath = join(base, ".gsd", "gsd.db");
|
|
519
519
|
|
|
520
|
-
|
|
521
|
-
|
|
520
|
+
t.after(() => {
|
|
521
|
+
closeDatabase();
|
|
522
|
+
rmSync(base, { recursive: true, force: true });
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// Build up completed state
|
|
522
526
|
openDatabase(dbPath);
|
|
523
527
|
migrateHierarchyToDb(base);
|
|
524
528
|
await handleCompleteTask(makeCompleteTaskParams("T01"), base);
|
|
@@ -636,8 +640,4 @@ test("undo/reset: undo task and reset slice revert DB + markdown", async (t) =>
|
|
|
636
640
|
resetNotifs.some(n => n.level === "success"),
|
|
637
641
|
"Reset should produce success notification",
|
|
638
642
|
);
|
|
639
|
-
} finally {
|
|
640
|
-
closeDatabase();
|
|
641
|
-
rmSync(base, { recursive: true, force: true });
|
|
642
|
-
}
|
|
643
643
|
});
|