gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.73f2fd5
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/infra-errors.js +3 -0
- package/dist/resources/extensions/gsd/auto/phases.js +36 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
- package/dist/resources/extensions/gsd/auto-start.js +10 -0
- package/dist/resources/extensions/gsd/auto-timers.js +57 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +34 -16
- package/dist/resources/extensions/gsd/doctor.js +8 -0
- package/dist/resources/extensions/gsd/git-service.js +8 -3
- package/dist/resources/extensions/gsd/gsd-db.js +12 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
- package/dist/resources/extensions/gsd/state.js +19 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- 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 +17 -17
- 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.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +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/local-model-check.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
- package/packages/pi-coding-agent/dist/core/model-registry.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/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.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/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.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/auth-storage.ts +15 -1
- 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/local-model-check.ts +45 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
- 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/settings-manager.ts +9 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/main.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/phases.ts +45 -48
- package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +14 -0
- package/src/resources/extensions/gsd/auto-timers.ts +64 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
- package/src/resources/extensions/gsd/auto.ts +37 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
- package/src/resources/extensions/gsd/db-writer.ts +39 -17
- package/src/resources/extensions/gsd/doctor.ts +7 -1
- package/src/resources/extensions/gsd/git-service.ts +6 -2
- package/src/resources/extensions/gsd/gsd-db.ts +16 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
- package/src/resources/extensions/gsd/state.ts +19 -1
- 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-pr-bugs.test.ts +88 -0
- 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/completed-units-metrics-sync.test.ts +114 -0
- 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 +465 -416
- 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 +210 -181
- 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/est-annotation-timeout.test.ts +120 -0
- 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/infra-error.test.ts +20 -2
- 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/knowledge.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
- 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/merge-conflict-stops-loop.test.ts +66 -0
- 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/preferences.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
- 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/stop-auto-merge-back.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
- 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 +10 -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/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
- package/src/resources/extensions/mcp-client/index.ts +20 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* merge-conflict-stops-loop.test.ts — #2330
|
|
3
|
+
*
|
|
4
|
+
* When a squash merge has real code conflicts (not just .gsd/ files),
|
|
5
|
+
* the merge retries forever because MergeConflictError is caught
|
|
6
|
+
* silently in mergeAndExit. This test verifies that:
|
|
7
|
+
* 1. worktree-resolver re-throws MergeConflictError for code conflicts
|
|
8
|
+
* 2. auto/phases.ts wraps mergeAndExit calls to stop the loop on conflict
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
14
|
+
|
|
15
|
+
const { assertTrue, report } = createTestContext();
|
|
16
|
+
|
|
17
|
+
const resolverPath = join(import.meta.dirname, "..", "worktree-resolver.ts");
|
|
18
|
+
const resolverSrc = readFileSync(resolverPath, "utf-8");
|
|
19
|
+
|
|
20
|
+
const phasesPath = join(import.meta.dirname, "..", "auto", "phases.ts");
|
|
21
|
+
const phasesSrc = readFileSync(phasesPath, "utf-8");
|
|
22
|
+
|
|
23
|
+
console.log("\n=== #2330: Merge conflict stops auto loop ===");
|
|
24
|
+
|
|
25
|
+
// ── Test 1: worktree-resolver re-throws MergeConflictError ──────────────
|
|
26
|
+
|
|
27
|
+
const methodStart = resolverSrc.indexOf("Worktree-mode merge:");
|
|
28
|
+
assertTrue(methodStart > 0, "worktree-resolver has _mergeWorktreeMode method");
|
|
29
|
+
|
|
30
|
+
const methodBody = resolverSrc.slice(methodStart, methodStart + 5000);
|
|
31
|
+
const rethrowsConflict =
|
|
32
|
+
methodBody.includes("MergeConflictError") &&
|
|
33
|
+
methodBody.includes("throw err");
|
|
34
|
+
|
|
35
|
+
assertTrue(
|
|
36
|
+
rethrowsConflict,
|
|
37
|
+
"worktree-resolver._mergeWorktreeMode re-throws MergeConflictError (#2330)",
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// ── Test 2: auto/phases.ts imports and uses MergeConflictError ──────────
|
|
41
|
+
|
|
42
|
+
assertTrue(
|
|
43
|
+
phasesSrc.includes("MergeConflictError") && phasesSrc.includes("mergeAndExit"),
|
|
44
|
+
"auto/phases.ts handles MergeConflictError from mergeAndExit (#2330)",
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// ── Test 3: The handler stops the loop (doesn't just warn) ──────────────
|
|
48
|
+
|
|
49
|
+
// Find the instanceof MergeConflictError check (not the import line)
|
|
50
|
+
const instanceofIdx = phasesSrc.indexOf("instanceof MergeConflictError");
|
|
51
|
+
assertTrue(instanceofIdx > 0, "auto/phases.ts has instanceof MergeConflictError check");
|
|
52
|
+
|
|
53
|
+
if (instanceofIdx > 0) {
|
|
54
|
+
const afterHandler = phasesSrc.slice(instanceofIdx, instanceofIdx + 500);
|
|
55
|
+
const stopsLoop =
|
|
56
|
+
afterHandler.includes("stopAuto") ||
|
|
57
|
+
afterHandler.includes('action: "break"') ||
|
|
58
|
+
afterHandler.includes("reason: \"merge-conflict\"");
|
|
59
|
+
|
|
60
|
+
assertTrue(
|
|
61
|
+
stopsLoop,
|
|
62
|
+
"auto/phases.ts stops the loop when merge conflict is detected (#2330)",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
report();
|
|
@@ -15,9 +15,9 @@ import {
|
|
|
15
15
|
writeGSDDirectory,
|
|
16
16
|
} from '../migrate/index.ts';
|
|
17
17
|
import { deriveState } from '../state.ts';
|
|
18
|
-
import {
|
|
18
|
+
import { describe, test, beforeEach, afterEach } from 'node:test';
|
|
19
|
+
import assert from 'node:assert/strict';
|
|
19
20
|
|
|
20
|
-
const { assertEq, assertTrue, report } = createTestContext();
|
|
21
21
|
// ─── Fixture Helpers ───────────────────────────────────────────────────────
|
|
22
22
|
|
|
23
23
|
const SAMPLE_PROJECT = `# Integration Test Project
|
|
@@ -195,11 +195,9 @@ function createCompleteFixture(): string {
|
|
|
195
195
|
// Tests
|
|
196
196
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
197
197
|
|
|
198
|
-
async function main(): Promise<void> {
|
|
199
|
-
|
|
200
198
|
// ─── Test 1: Path resolution — .planning appended when missing ─────────
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
|
|
200
|
+
test('Path resolution: .planning appended when source path lacks it', () => {
|
|
203
201
|
const base = createCompleteFixture();
|
|
204
202
|
try {
|
|
205
203
|
// Simulate the command's path resolution logic
|
|
@@ -207,16 +205,16 @@ async function main(): Promise<void> {
|
|
|
207
205
|
if (!sourcePath.endsWith('.planning')) {
|
|
208
206
|
sourcePath = join(sourcePath, '.planning');
|
|
209
207
|
}
|
|
210
|
-
|
|
211
|
-
|
|
208
|
+
assert.ok(sourcePath.endsWith('.planning'), 'path-resolution: .planning appended');
|
|
209
|
+
assert.ok(existsSync(sourcePath), 'path-resolution: appended path exists');
|
|
212
210
|
} finally {
|
|
213
211
|
rmSync(base, { recursive: true, force: true });
|
|
214
212
|
}
|
|
215
|
-
|
|
213
|
+
});
|
|
216
214
|
|
|
217
215
|
// ─── Test 2: Path resolution — .planning used as-is ────────────────────
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
|
|
217
|
+
test('Path resolution: .planning used as-is when already present', () => {
|
|
220
218
|
const base = createCompleteFixture();
|
|
221
219
|
try {
|
|
222
220
|
const planningPath = join(base, '.planning');
|
|
@@ -224,39 +222,39 @@ async function main(): Promise<void> {
|
|
|
224
222
|
if (!sourcePath.endsWith('.planning')) {
|
|
225
223
|
sourcePath = join(sourcePath, '.planning');
|
|
226
224
|
}
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
assert.deepStrictEqual(sourcePath, resolve(planningPath), 'path-resolution: .planning not double-appended');
|
|
226
|
+
assert.ok(existsSync(sourcePath), 'path-resolution: direct path exists');
|
|
229
227
|
} finally {
|
|
230
228
|
rmSync(base, { recursive: true, force: true });
|
|
231
229
|
}
|
|
232
|
-
|
|
230
|
+
});
|
|
233
231
|
|
|
234
232
|
// ─── Test 3: Validation gating — non-existent path ─────────────────────
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
|
|
234
|
+
test('Validation gating: non-existent path returns invalid', async () => {
|
|
237
235
|
const fakePath = join(tmpdir(), 'gsd-cmd-nonexistent-' + Date.now(), '.planning');
|
|
238
236
|
const result = await validatePlanningDirectory(fakePath);
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
assert.deepStrictEqual(result.valid, false, 'validation: non-existent path is invalid');
|
|
238
|
+
assert.ok(result.issues.length > 0, 'validation: has issues for non-existent path');
|
|
241
239
|
const hasFatal = result.issues.some(i => i.severity === 'fatal');
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
assert.ok(hasFatal, 'validation: non-existent path has fatal issue');
|
|
241
|
+
});
|
|
244
242
|
|
|
245
243
|
// ─── Test 4: Validation gating — valid fixture passes ──────────────────
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
|
|
245
|
+
test('Validation gating: valid fixture passes validation', async () => {
|
|
248
246
|
const base = createCompleteFixture();
|
|
249
247
|
try {
|
|
250
248
|
const result = await validatePlanningDirectory(join(base, '.planning'));
|
|
251
|
-
|
|
249
|
+
assert.ok(result.valid === true, 'validation: valid fixture passes');
|
|
252
250
|
} finally {
|
|
253
251
|
rmSync(base, { recursive: true, force: true });
|
|
254
252
|
}
|
|
255
|
-
|
|
253
|
+
});
|
|
256
254
|
|
|
257
255
|
// ─── Test 5: Full pipeline round-trip ──────────────────────────────────
|
|
258
|
-
|
|
259
|
-
|
|
256
|
+
|
|
257
|
+
test('Full pipeline: parse → transform → preview → write → deriveState', async () => {
|
|
260
258
|
const base = createCompleteFixture();
|
|
261
259
|
const writeTarget = mkdtempSync(join(tmpdir(), 'gsd-cmd-write-'));
|
|
262
260
|
try {
|
|
@@ -264,17 +262,17 @@ async function main(): Promise<void> {
|
|
|
264
262
|
|
|
265
263
|
// (a) Validate
|
|
266
264
|
const validation = await validatePlanningDirectory(planningPath);
|
|
267
|
-
|
|
265
|
+
assert.ok(validation.valid === true, 'pipeline: validation passes');
|
|
268
266
|
|
|
269
267
|
// (b) Parse
|
|
270
268
|
const parsed = await parsePlanningDirectory(planningPath);
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
assert.ok(parsed.roadmap !== null, 'pipeline: roadmap parsed');
|
|
270
|
+
assert.ok(Object.keys(parsed.phases).length >= 2, 'pipeline: phases parsed');
|
|
273
271
|
|
|
274
272
|
// (c) Transform
|
|
275
273
|
const project = transformToGSD(parsed);
|
|
276
|
-
|
|
277
|
-
|
|
274
|
+
assert.ok(project.milestones.length >= 1, 'pipeline: has milestones');
|
|
275
|
+
assert.ok(project.milestones[0].slices.length >= 1, 'pipeline: has slices');
|
|
278
276
|
|
|
279
277
|
// Count totals for preview verification
|
|
280
278
|
let totalTasks = 0;
|
|
@@ -294,76 +292,69 @@ async function main(): Promise<void> {
|
|
|
294
292
|
|
|
295
293
|
// (d) Preview — verify counts match project data
|
|
296
294
|
const preview = generatePreview(project);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
295
|
+
assert.deepStrictEqual(preview.milestoneCount, project.milestones.length, 'pipeline: preview milestoneCount');
|
|
296
|
+
assert.deepStrictEqual(preview.totalSlices, totalSlices, 'pipeline: preview totalSlices');
|
|
297
|
+
assert.deepStrictEqual(preview.totalTasks, totalTasks, 'pipeline: preview totalTasks');
|
|
298
|
+
assert.deepStrictEqual(preview.doneSlices, doneSlices, 'pipeline: preview doneSlices');
|
|
299
|
+
assert.deepStrictEqual(preview.doneTasks, doneTasks, 'pipeline: preview doneTasks');
|
|
302
300
|
|
|
303
301
|
// Completion percentages
|
|
304
302
|
const expectedSlicePct = totalSlices > 0 ? Math.round((doneSlices / totalSlices) * 100) : 0;
|
|
305
303
|
const expectedTaskPct = totalTasks > 0 ? Math.round((doneTasks / totalTasks) * 100) : 0;
|
|
306
|
-
|
|
307
|
-
|
|
304
|
+
assert.deepStrictEqual(preview.sliceCompletionPct, expectedSlicePct, 'pipeline: preview sliceCompletionPct');
|
|
305
|
+
assert.deepStrictEqual(preview.taskCompletionPct, expectedTaskPct, 'pipeline: preview taskCompletionPct');
|
|
308
306
|
|
|
309
307
|
// Requirements in preview
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
308
|
+
assert.deepStrictEqual(preview.requirements.active, 1, 'pipeline: preview requirements active');
|
|
309
|
+
assert.deepStrictEqual(preview.requirements.validated, 1, 'pipeline: preview requirements validated');
|
|
310
|
+
assert.deepStrictEqual(preview.requirements.total, 2, 'pipeline: preview requirements total');
|
|
313
311
|
|
|
314
312
|
// (e) Write
|
|
315
313
|
const result = await writeGSDDirectory(project, writeTarget);
|
|
316
|
-
|
|
314
|
+
assert.ok(result.paths.length > 0, 'pipeline: files written');
|
|
317
315
|
|
|
318
316
|
// Key files exist
|
|
319
317
|
const gsd = join(writeTarget, '.gsd');
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
318
|
+
assert.ok(existsSync(join(gsd, 'PROJECT.md')), 'pipeline: PROJECT.md written');
|
|
319
|
+
assert.ok(existsSync(join(gsd, 'STATE.md')), 'pipeline: STATE.md written');
|
|
320
|
+
assert.ok(existsSync(join(gsd, 'REQUIREMENTS.md')), 'pipeline: REQUIREMENTS.md written');
|
|
323
321
|
|
|
324
322
|
const m001 = join(gsd, 'milestones', 'M001');
|
|
325
|
-
|
|
326
|
-
|
|
323
|
+
assert.ok(existsSync(join(m001, 'M001-ROADMAP.md')), 'pipeline: M001-ROADMAP.md written');
|
|
324
|
+
assert.ok(existsSync(join(m001, 'M001-CONTEXT.md')), 'pipeline: M001-CONTEXT.md written');
|
|
327
325
|
|
|
328
326
|
// At least one slice plan exists
|
|
329
327
|
const s01Plan = join(m001, 'slices', 'S01', 'S01-PLAN.md');
|
|
330
|
-
|
|
328
|
+
assert.ok(existsSync(s01Plan), 'pipeline: S01-PLAN.md written');
|
|
331
329
|
|
|
332
330
|
// (f) deriveState — coherent state from written output
|
|
333
331
|
console.log(' --- deriveState ---');
|
|
334
332
|
const state = await deriveState(writeTarget);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
333
|
+
assert.ok(state.phase !== undefined, 'pipeline: deriveState returns phase');
|
|
334
|
+
assert.ok(state.activeMilestone !== null, 'pipeline: deriveState has activeMilestone');
|
|
335
|
+
assert.deepStrictEqual(state.activeMilestone!.id, 'M001', 'pipeline: deriveState activeMilestone is M001');
|
|
336
|
+
assert.ok(state.progress!.slices !== undefined, 'pipeline: deriveState has slices progress');
|
|
337
|
+
assert.ok(state.progress!.tasks !== undefined, 'pipeline: deriveState has tasks progress');
|
|
340
338
|
|
|
341
339
|
} finally {
|
|
342
340
|
rmSync(base, { recursive: true, force: true });
|
|
343
341
|
rmSync(writeTarget, { recursive: true, force: true });
|
|
344
342
|
}
|
|
345
|
-
|
|
343
|
+
});
|
|
346
344
|
|
|
347
345
|
// ─── Test 6: .gsd/ exists detection ────────────────────────────────────
|
|
348
|
-
|
|
349
|
-
|
|
346
|
+
|
|
347
|
+
test('.gsd/ exists detection', () => {
|
|
350
348
|
const base = mkdtempSync(join(tmpdir(), 'gsd-cmd-exists-'));
|
|
351
349
|
try {
|
|
352
350
|
// No .gsd/ yet
|
|
353
|
-
|
|
351
|
+
assert.ok(!existsSync(join(base, '.gsd')), 'exists-detection: .gsd absent initially');
|
|
354
352
|
|
|
355
353
|
// Create .gsd/
|
|
356
354
|
mkdirSync(join(base, '.gsd'), { recursive: true });
|
|
357
|
-
|
|
355
|
+
assert.ok(existsSync(join(base, '.gsd')), 'exists-detection: .gsd detected after creation');
|
|
358
356
|
} finally {
|
|
359
357
|
rmSync(base, { recursive: true, force: true });
|
|
360
358
|
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
report();
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
main().catch((err) => {
|
|
367
|
-
console.error('Unhandled error:', err);
|
|
368
|
-
process.exit(1);
|
|
369
359
|
});
|
|
360
|
+
|
|
@@ -18,9 +18,8 @@ import {
|
|
|
18
18
|
getActiveTaskFromDb,
|
|
19
19
|
} from '../gsd-db.ts';
|
|
20
20
|
import { migrateHierarchyToDb } from '../md-importer.ts';
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
const { assertEq, assertTrue, report } = createTestContext();
|
|
21
|
+
import { describe, test, beforeEach, afterEach } from 'node:test';
|
|
22
|
+
import assert from 'node:assert/strict';
|
|
24
23
|
|
|
25
24
|
// ─── Fixture Helpers ───────────────────────────────────────────────────────
|
|
26
25
|
|
|
@@ -98,11 +97,9 @@ const PLAN_S02_1_TASK = `# S02: Second Slice
|
|
|
98
97
|
// Test Cases
|
|
99
98
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
100
99
|
|
|
101
|
-
async function main(): Promise<void> {
|
|
102
|
-
|
|
103
100
|
// ─── Test (a): Single milestone with 2 slices, 3 tasks ────────────────
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
|
|
102
|
+
test('migrate-hier: single milestone with 2 slices, 3 tasks', () => {
|
|
106
103
|
const base = createFixtureBase();
|
|
107
104
|
try {
|
|
108
105
|
writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_2_SLICES);
|
|
@@ -112,48 +109,48 @@ async function main(): Promise<void> {
|
|
|
112
109
|
openDatabase(':memory:');
|
|
113
110
|
const counts = migrateHierarchyToDb(base);
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
112
|
+
assert.deepStrictEqual(counts.milestones, 1, 'single-ms: 1 milestone inserted');
|
|
113
|
+
assert.deepStrictEqual(counts.slices, 2, 'single-ms: 2 slices inserted');
|
|
114
|
+
assert.deepStrictEqual(counts.tasks, 4, 'single-ms: 4 tasks inserted (3 + 1)');
|
|
118
115
|
|
|
119
116
|
const milestones = getAllMilestones();
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
assert.deepStrictEqual(milestones.length, 1, 'single-ms: 1 milestone in DB');
|
|
118
|
+
assert.deepStrictEqual(milestones[0]!.id, 'M001', 'single-ms: milestone ID is M001');
|
|
119
|
+
assert.deepStrictEqual(milestones[0]!.title, 'M001: Test Milestone', 'single-ms: milestone title correct');
|
|
120
|
+
assert.deepStrictEqual(milestones[0]!.status, 'active', 'single-ms: milestone status is active');
|
|
124
121
|
|
|
125
122
|
const slices = getMilestoneSlices('M001');
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
123
|
+
assert.deepStrictEqual(slices.length, 2, 'single-ms: 2 slices in DB');
|
|
124
|
+
assert.deepStrictEqual(slices[0]!.id, 'S01', 'single-ms: first slice is S01');
|
|
125
|
+
assert.deepStrictEqual(slices[0]!.title, 'First Slice', 'single-ms: S01 title correct');
|
|
126
|
+
assert.deepStrictEqual(slices[0]!.risk, 'low', 'single-ms: S01 risk is low');
|
|
127
|
+
assert.deepStrictEqual(slices[0]!.status, 'pending', 'single-ms: S01 status is pending');
|
|
128
|
+
assert.deepStrictEqual(slices[1]!.id, 'S02', 'single-ms: second slice is S02');
|
|
129
|
+
assert.deepStrictEqual(slices[1]!.risk, 'high', 'single-ms: S02 risk is high');
|
|
133
130
|
|
|
134
131
|
const s01Tasks = getSliceTasks('M001', 'S01');
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
132
|
+
assert.deepStrictEqual(s01Tasks.length, 3, 'single-ms: 3 tasks for S01');
|
|
133
|
+
assert.deepStrictEqual(s01Tasks[0]!.id, 'T01', 'single-ms: first task is T01');
|
|
134
|
+
assert.deepStrictEqual(s01Tasks[0]!.title, 'First Task', 'single-ms: T01 title correct');
|
|
135
|
+
assert.deepStrictEqual(s01Tasks[0]!.status, 'pending', 'single-ms: T01 status is pending');
|
|
136
|
+
assert.deepStrictEqual(s01Tasks[1]!.id, 'T02', 'single-ms: second task is T02');
|
|
137
|
+
assert.deepStrictEqual(s01Tasks[1]!.status, 'complete', 'single-ms: T02 status is complete (was [x])');
|
|
138
|
+
assert.deepStrictEqual(s01Tasks[2]!.id, 'T03', 'single-ms: third task is T03');
|
|
142
139
|
|
|
143
140
|
const s02Tasks = getSliceTasks('M001', 'S02');
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
assert.deepStrictEqual(s02Tasks.length, 1, 'single-ms: 1 task for S02');
|
|
142
|
+
assert.deepStrictEqual(s02Tasks[0]!.id, 'T01', 'single-ms: S02 T01 correct');
|
|
146
143
|
|
|
147
144
|
closeDatabase();
|
|
148
145
|
} finally {
|
|
149
146
|
closeDatabase();
|
|
150
147
|
cleanup(base);
|
|
151
148
|
}
|
|
152
|
-
|
|
149
|
+
});
|
|
153
150
|
|
|
154
151
|
// ─── Test (b): Multi-milestone — M001 complete, M002 active with deps ─
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
|
|
153
|
+
test('migrate-hier: multi-milestone with deps', () => {
|
|
157
154
|
const base = createFixtureBase();
|
|
158
155
|
try {
|
|
159
156
|
// M001: complete (has SUMMARY)
|
|
@@ -197,35 +194,35 @@ Depends on M001 completion.
|
|
|
197
194
|
openDatabase(':memory:');
|
|
198
195
|
const counts = migrateHierarchyToDb(base);
|
|
199
196
|
|
|
200
|
-
|
|
197
|
+
assert.deepStrictEqual(counts.milestones, 2, 'multi-ms: 2 milestones inserted');
|
|
201
198
|
|
|
202
199
|
const m001 = getMilestone('M001');
|
|
203
|
-
|
|
204
|
-
|
|
200
|
+
assert.ok(m001 !== null, 'multi-ms: M001 exists');
|
|
201
|
+
assert.deepStrictEqual(m001!.status, 'complete', 'multi-ms: M001 is complete');
|
|
205
202
|
|
|
206
203
|
const m002 = getMilestone('M002');
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
204
|
+
assert.ok(m002 !== null, 'multi-ms: M002 exists');
|
|
205
|
+
assert.deepStrictEqual(m002!.status, 'active', 'multi-ms: M002 is active');
|
|
206
|
+
assert.deepStrictEqual(m002!.depends_on, ['M001'], 'multi-ms: M002 depends on M001');
|
|
210
207
|
|
|
211
208
|
// Active milestone should be M002
|
|
212
209
|
const active = getActiveMilestoneFromDb();
|
|
213
|
-
|
|
210
|
+
assert.deepStrictEqual(active?.id, 'M002', 'multi-ms: active milestone is M002');
|
|
214
211
|
|
|
215
212
|
// Active slice in M002 should be S01 (S02 depends on S01)
|
|
216
213
|
const activeSlice = getActiveSliceFromDb('M002');
|
|
217
|
-
|
|
214
|
+
assert.deepStrictEqual(activeSlice?.id, 'S01', 'multi-ms: active slice is S01');
|
|
218
215
|
|
|
219
216
|
closeDatabase();
|
|
220
217
|
} finally {
|
|
221
218
|
closeDatabase();
|
|
222
219
|
cleanup(base);
|
|
223
220
|
}
|
|
224
|
-
|
|
221
|
+
});
|
|
225
222
|
|
|
226
223
|
// ─── Test (c): Partially-completed slice — some tasks [x], some [ ] ───
|
|
227
|
-
|
|
228
|
-
|
|
224
|
+
|
|
225
|
+
test('migrate-hier: partially-completed slice', () => {
|
|
229
226
|
const base = createFixtureBase();
|
|
230
227
|
try {
|
|
231
228
|
const roadmap = `# M001: Partial
|
|
@@ -260,25 +257,25 @@ Depends on M001 completion.
|
|
|
260
257
|
migrateHierarchyToDb(base);
|
|
261
258
|
|
|
262
259
|
const tasks = getSliceTasks('M001', 'S01');
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
260
|
+
assert.deepStrictEqual(tasks.length, 3, 'partial: 3 tasks');
|
|
261
|
+
assert.deepStrictEqual(tasks[0]!.status, 'complete', 'partial: T01 is complete');
|
|
262
|
+
assert.deepStrictEqual(tasks[1]!.status, 'complete', 'partial: T02 is complete');
|
|
263
|
+
assert.deepStrictEqual(tasks[2]!.status, 'pending', 'partial: T03 is pending');
|
|
267
264
|
|
|
268
265
|
// Active task should be T03
|
|
269
266
|
const activeTask = getActiveTaskFromDb('M001', 'S01');
|
|
270
|
-
|
|
267
|
+
assert.deepStrictEqual(activeTask?.id, 'T03', 'partial: active task is T03');
|
|
271
268
|
|
|
272
269
|
closeDatabase();
|
|
273
270
|
} finally {
|
|
274
271
|
closeDatabase();
|
|
275
272
|
cleanup(base);
|
|
276
273
|
}
|
|
277
|
-
|
|
274
|
+
});
|
|
278
275
|
|
|
279
276
|
// ─── Test (d): Ghost milestone skipped ────────────────────────────────
|
|
280
|
-
|
|
281
|
-
|
|
277
|
+
|
|
278
|
+
test('migrate-hier: ghost milestone skipped', () => {
|
|
282
279
|
const base = createFixtureBase();
|
|
283
280
|
try {
|
|
284
281
|
// M001: real milestone
|
|
@@ -289,21 +286,21 @@ Depends on M001 completion.
|
|
|
289
286
|
openDatabase(':memory:');
|
|
290
287
|
const counts = migrateHierarchyToDb(base);
|
|
291
288
|
|
|
292
|
-
|
|
289
|
+
assert.deepStrictEqual(counts.milestones, 1, 'ghost: only 1 milestone inserted');
|
|
293
290
|
const milestones = getAllMilestones();
|
|
294
|
-
|
|
295
|
-
|
|
291
|
+
assert.deepStrictEqual(milestones.length, 1, 'ghost: 1 milestone in DB');
|
|
292
|
+
assert.deepStrictEqual(milestones[0]!.id, 'M001', 'ghost: only M001 in DB');
|
|
296
293
|
|
|
297
294
|
closeDatabase();
|
|
298
295
|
} finally {
|
|
299
296
|
closeDatabase();
|
|
300
297
|
cleanup(base);
|
|
301
298
|
}
|
|
302
|
-
|
|
299
|
+
});
|
|
303
300
|
|
|
304
301
|
// ─── Test (e): Idempotent re-run — calling twice doesn't duplicate ────
|
|
305
|
-
|
|
306
|
-
|
|
302
|
+
|
|
303
|
+
test('migrate-hier: idempotent re-run', () => {
|
|
307
304
|
const base = createFixtureBase();
|
|
308
305
|
try {
|
|
309
306
|
writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_2_SLICES);
|
|
@@ -313,31 +310,31 @@ Depends on M001 completion.
|
|
|
313
310
|
|
|
314
311
|
// First run
|
|
315
312
|
const counts1 = migrateHierarchyToDb(base);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
313
|
+
assert.deepStrictEqual(counts1.milestones, 1, 'idempotent-1: 1 milestone first run');
|
|
314
|
+
assert.deepStrictEqual(counts1.slices, 2, 'idempotent-1: 2 slices first run');
|
|
315
|
+
assert.deepStrictEqual(counts1.tasks, 3, 'idempotent-1: 3 tasks first run');
|
|
319
316
|
|
|
320
317
|
// Second run — INSERT OR IGNORE means no duplicates
|
|
321
318
|
const counts2 = migrateHierarchyToDb(base);
|
|
322
319
|
// Counts reflect attempts, not actual inserts (INSERT OR IGNORE silently skips)
|
|
323
320
|
// The important thing: DB doesn't have duplicates
|
|
324
321
|
const milestones = getAllMilestones();
|
|
325
|
-
|
|
322
|
+
assert.deepStrictEqual(milestones.length, 1, 'idempotent-2: still 1 milestone after second run');
|
|
326
323
|
const slices = getMilestoneSlices('M001');
|
|
327
|
-
|
|
324
|
+
assert.deepStrictEqual(slices.length, 2, 'idempotent-2: still 2 slices after second run');
|
|
328
325
|
const tasks = getSliceTasks('M001', 'S01');
|
|
329
|
-
|
|
326
|
+
assert.deepStrictEqual(tasks.length, 3, 'idempotent-2: still 3 tasks for S01 after second run');
|
|
330
327
|
|
|
331
328
|
closeDatabase();
|
|
332
329
|
} finally {
|
|
333
330
|
closeDatabase();
|
|
334
331
|
cleanup(base);
|
|
335
332
|
}
|
|
336
|
-
|
|
333
|
+
});
|
|
337
334
|
|
|
338
335
|
// ─── Test (f): Empty roadmap — milestone inserted but no slices ───────
|
|
339
|
-
|
|
340
|
-
|
|
336
|
+
|
|
337
|
+
test('migrate-hier: empty roadmap, no slices', () => {
|
|
341
338
|
const base = createFixtureBase();
|
|
342
339
|
try {
|
|
343
340
|
const emptyRoadmap = `# M001: Empty Milestone
|
|
@@ -353,27 +350,27 @@ Depends on M001 completion.
|
|
|
353
350
|
openDatabase(':memory:');
|
|
354
351
|
const counts = migrateHierarchyToDb(base);
|
|
355
352
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
353
|
+
assert.deepStrictEqual(counts.milestones, 1, 'empty-roadmap: 1 milestone inserted');
|
|
354
|
+
assert.deepStrictEqual(counts.slices, 0, 'empty-roadmap: 0 slices inserted');
|
|
355
|
+
assert.deepStrictEqual(counts.tasks, 0, 'empty-roadmap: 0 tasks inserted');
|
|
359
356
|
|
|
360
357
|
const milestones = getAllMilestones();
|
|
361
|
-
|
|
362
|
-
|
|
358
|
+
assert.deepStrictEqual(milestones.length, 1, 'empty-roadmap: 1 milestone in DB');
|
|
359
|
+
assert.deepStrictEqual(milestones[0]!.title, 'M001: Empty Milestone', 'empty-roadmap: title correct');
|
|
363
360
|
|
|
364
361
|
const slices = getMilestoneSlices('M001');
|
|
365
|
-
|
|
362
|
+
assert.deepStrictEqual(slices.length, 0, 'empty-roadmap: no slices in DB');
|
|
366
363
|
|
|
367
364
|
closeDatabase();
|
|
368
365
|
} finally {
|
|
369
366
|
closeDatabase();
|
|
370
367
|
cleanup(base);
|
|
371
368
|
}
|
|
372
|
-
|
|
369
|
+
});
|
|
373
370
|
|
|
374
371
|
// ─── Test (g): Slice depends parsed correctly ─────────────────────────
|
|
375
|
-
|
|
376
|
-
|
|
372
|
+
|
|
373
|
+
test('migrate-hier: slice depends parsed', () => {
|
|
377
374
|
const base = createFixtureBase();
|
|
378
375
|
try {
|
|
379
376
|
const roadmap = `# M001: Deps Test
|
|
@@ -397,21 +394,21 @@ Depends on M001 completion.
|
|
|
397
394
|
migrateHierarchyToDb(base);
|
|
398
395
|
|
|
399
396
|
const slices = getMilestoneSlices('M001');
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
397
|
+
assert.deepStrictEqual(slices.length, 3, 'depends: 3 slices');
|
|
398
|
+
assert.deepStrictEqual(slices[0]!.depends, [], 'depends: S01 has no deps');
|
|
399
|
+
assert.deepStrictEqual(slices[1]!.depends, ['S01'], 'depends: S02 depends on S01');
|
|
400
|
+
assert.deepStrictEqual(slices[2]!.depends, ['S01', 'S02'], 'depends: S03 depends on S01,S02');
|
|
404
401
|
|
|
405
402
|
closeDatabase();
|
|
406
403
|
} finally {
|
|
407
404
|
closeDatabase();
|
|
408
405
|
cleanup(base);
|
|
409
406
|
}
|
|
410
|
-
|
|
407
|
+
});
|
|
411
408
|
|
|
412
409
|
// ─── Test (h): Demo text extracted from roadmap ───────────────────────
|
|
413
|
-
|
|
414
|
-
|
|
410
|
+
|
|
411
|
+
test('migrate-hier: demo text extracted', () => {
|
|
415
412
|
const base = createFixtureBase();
|
|
416
413
|
try {
|
|
417
414
|
writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_2_SLICES);
|
|
@@ -420,20 +417,13 @@ Depends on M001 completion.
|
|
|
420
417
|
migrateHierarchyToDb(base);
|
|
421
418
|
|
|
422
419
|
const slices = getMilestoneSlices('M001');
|
|
423
|
-
|
|
424
|
-
|
|
420
|
+
assert.deepStrictEqual(slices[0]!.demo, 'First slice done.', 'demo: S01 demo text correct');
|
|
421
|
+
assert.deepStrictEqual(slices[1]!.demo, 'All slices done.', 'demo: S02 demo text correct');
|
|
425
422
|
|
|
426
423
|
closeDatabase();
|
|
427
424
|
} finally {
|
|
428
425
|
closeDatabase();
|
|
429
426
|
cleanup(base);
|
|
430
427
|
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
report();
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
main().catch((error) => {
|
|
437
|
-
console.error(error);
|
|
438
|
-
process.exit(1);
|
|
439
428
|
});
|
|
429
|
+
|