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
|
@@ -66,7 +66,7 @@ function createFixture(): string {
|
|
|
66
66
|
return base;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
test("dispatch uat targets last completed slice, not activeSlice (#1693)", async () => {
|
|
69
|
+
test("dispatch uat targets last completed slice, not activeSlice (#1693)", async (t) => {
|
|
70
70
|
const base = createFixture();
|
|
71
71
|
invalidateStateCache();
|
|
72
72
|
|
|
@@ -88,31 +88,29 @@ test("dispatch uat targets last completed slice, not activeSlice (#1693)", async
|
|
|
88
88
|
},
|
|
89
89
|
} as any;
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
rmSync(base, { recursive: true, force: true });
|
|
112
|
-
}
|
|
91
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
92
|
+
|
|
93
|
+
await dispatchDirectPhase(ctx, pi, "uat", base);
|
|
94
|
+
|
|
95
|
+
// Should have dispatched (sendMessage called)
|
|
96
|
+
assert.ok(sentPrompt, "sendMessage should have been called with a prompt");
|
|
97
|
+
|
|
98
|
+
// The dispatch notification should reference M001/S01 (completed), not M001/S02 (active)
|
|
99
|
+
const dispatchNotification = notifications.find(n => n.message.startsWith("Dispatching"));
|
|
100
|
+
assert.ok(dispatchNotification, "dispatch notification should be present");
|
|
101
|
+
assert.match(
|
|
102
|
+
dispatchNotification.message,
|
|
103
|
+
/M001\/S01/,
|
|
104
|
+
"dispatch should target completed slice S01, not active slice S02",
|
|
105
|
+
);
|
|
106
|
+
assert.doesNotMatch(
|
|
107
|
+
dispatchNotification.message,
|
|
108
|
+
/M001\/S02/,
|
|
109
|
+
"dispatch should NOT target active (next incomplete) slice S02",
|
|
110
|
+
);
|
|
113
111
|
});
|
|
114
112
|
|
|
115
|
-
test("dispatch uat warns when no completed slices exist", async () => {
|
|
113
|
+
test("dispatch uat warns when no completed slices exist", async (t) => {
|
|
116
114
|
const base = mkdtempSync(join(tmpdir(), "gsd-dispatch-uat-none-"));
|
|
117
115
|
invalidateStateCache();
|
|
118
116
|
|
|
@@ -164,13 +162,11 @@ test("dispatch uat warns when no completed slices exist", async () => {
|
|
|
164
162
|
},
|
|
165
163
|
} as any;
|
|
166
164
|
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
166
|
+
|
|
167
|
+
await dispatchDirectPhase(ctx, pi, "uat", base);
|
|
169
168
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
} finally {
|
|
174
|
-
rmSync(base, { recursive: true, force: true });
|
|
175
|
-
}
|
|
169
|
+
const warning = notifications.find(n => n.level === "warning");
|
|
170
|
+
assert.ok(warning, "should show a warning notification");
|
|
171
|
+
assert.match(warning.message, /no completed slices/, "warning should mention no completed slices");
|
|
176
172
|
});
|
|
@@ -56,35 +56,33 @@ Done.
|
|
|
56
56
|
`);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
test("doctor does not report any reconciliation issue codes", async () => {
|
|
59
|
+
test("doctor does not report any reconciliation issue codes", async (t) => {
|
|
60
60
|
const tmp = makeTmp("no-reconciliation");
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// No summary or UAT stubs should be created
|
|
82
|
-
const sliceSummaryPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
|
|
83
|
-
assert.ok(!existsSync(sliceSummaryPath), "should NOT have created summary stub");
|
|
84
|
-
|
|
85
|
-
const sliceUatPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-UAT.md");
|
|
86
|
-
assert.ok(!existsSync(sliceUatPath), "should NOT have created UAT stub");
|
|
87
|
-
} finally {
|
|
88
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
61
|
+
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
62
|
+
|
|
63
|
+
buildScaffold(tmp);
|
|
64
|
+
|
|
65
|
+
const report = await runGSDDoctor(tmp, { fix: true, fixLevel: "task" });
|
|
66
|
+
|
|
67
|
+
const REMOVED_CODES = [
|
|
68
|
+
"task_done_missing_summary",
|
|
69
|
+
"task_summary_without_done_checkbox",
|
|
70
|
+
"all_tasks_done_missing_slice_summary",
|
|
71
|
+
"all_tasks_done_missing_slice_uat",
|
|
72
|
+
"all_tasks_done_roadmap_not_checked",
|
|
73
|
+
"slice_checked_missing_summary",
|
|
74
|
+
"slice_checked_missing_uat",
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const codes = report.issues.map(i => i.code);
|
|
78
|
+
for (const removed of REMOVED_CODES) {
|
|
79
|
+
assert.ok(!codes.includes(removed as any), `should NOT report removed code: ${removed}`);
|
|
89
80
|
}
|
|
81
|
+
|
|
82
|
+
// No summary or UAT stubs should be created
|
|
83
|
+
const sliceSummaryPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
|
|
84
|
+
assert.ok(!existsSync(sliceSummaryPath), "should NOT have created summary stub");
|
|
85
|
+
|
|
86
|
+
const sliceUatPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-UAT.md");
|
|
87
|
+
assert.ok(!existsSync(sliceUatPath), "should NOT have created UAT stub");
|
|
90
88
|
});
|
|
@@ -12,7 +12,7 @@ import { join } from "node:path";
|
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { runGSDDoctor } from "../doctor.js";
|
|
14
14
|
|
|
15
|
-
test("doctor fix=true sanitizes em-dash in milestone title", async () => {
|
|
15
|
+
test("doctor fix=true sanitizes em-dash in milestone title", async (t) => {
|
|
16
16
|
const tmpBase = mkdtempSync(join(tmpdir(), "gsd-doctor-delim-"));
|
|
17
17
|
const gsd = join(tmpBase, ".gsd");
|
|
18
18
|
const mDir = join(gsd, "milestones", "M001");
|
|
@@ -34,33 +34,31 @@ test("doctor fix=true sanitizes em-dash in milestone title", async () => {
|
|
|
34
34
|
writeFileSync(join(sDir, "S01-PLAN.md"), `# S01: Initial Setup\n\n## Tasks\n- [ ] **T01: Scaffold** \`est:15m\`\n`);
|
|
35
35
|
writeFileSync(join(tDir, "T01-PLAN.md"), "# T01: Scaffold\n");
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
rmSync(tmpBase, { recursive: true, force: true });
|
|
60
|
-
}
|
|
37
|
+
t.after(() => rmSync(tmpBase, { recursive: true, force: true }));
|
|
38
|
+
|
|
39
|
+
// Run doctor with fix=true
|
|
40
|
+
const report = await runGSDDoctor(tmpBase, { fix: true });
|
|
41
|
+
|
|
42
|
+
// The em-dash should have been replaced
|
|
43
|
+
const fixed = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
|
|
44
|
+
const h1 = fixed.split("\n").find(l => l.startsWith("# "))!;
|
|
45
|
+
assert.ok(h1, "H1 line should exist");
|
|
46
|
+
assert.ok(!h1.includes("\u2014"), "em-dash should be replaced");
|
|
47
|
+
assert.ok(!h1.includes("\u2013"), "en-dash should be replaced");
|
|
48
|
+
assert.ok(h1.includes("-"), "should contain ASCII hyphen as replacement");
|
|
49
|
+
|
|
50
|
+
// Should have recorded the fix
|
|
51
|
+
assert.ok(
|
|
52
|
+
report.fixesApplied.some(f => f.includes("sanitized")),
|
|
53
|
+
`fixesApplied should mention sanitization, got: ${JSON.stringify(report.fixesApplied)}`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// The issue should NOT appear in the report (it was fixed)
|
|
57
|
+
const delimIssues = report.issues.filter(i => i.code === "delimiter_in_title" && i.unitId === "M001");
|
|
58
|
+
assert.equal(delimIssues.length, 0, "fixed issue should not appear in issues list");
|
|
61
59
|
});
|
|
62
60
|
|
|
63
|
-
test("doctor fix=false still reports delimiter_in_title as warning", async () => {
|
|
61
|
+
test("doctor fix=false still reports delimiter_in_title as warning", async (t) => {
|
|
64
62
|
const tmpBase = mkdtempSync(join(tmpdir(), "gsd-doctor-delim-nf-"));
|
|
65
63
|
const gsd = join(tmpBase, ".gsd");
|
|
66
64
|
const mDir = join(gsd, "milestones", "M001");
|
|
@@ -72,16 +70,14 @@ test("doctor fix=false still reports delimiter_in_title as warning", async () =>
|
|
|
72
70
|
writeFileSync(join(sDir, "S01-PLAN.md"), `# S01: Setup\n\n## Tasks\n- [ ] **T01: Init** \`est:10m\`\n`);
|
|
73
71
|
writeFileSync(join(tDir, "T01-PLAN.md"), "# T01: Init\n");
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
rmSync(tmpBase, { recursive: true, force: true });
|
|
86
|
-
}
|
|
73
|
+
t.after(() => rmSync(tmpBase, { recursive: true, force: true }));
|
|
74
|
+
|
|
75
|
+
const report = await runGSDDoctor(tmpBase, { fix: false });
|
|
76
|
+
const delimIssues = report.issues.filter(i => i.code === "delimiter_in_title");
|
|
77
|
+
assert.ok(delimIssues.length > 0, "should report delimiter_in_title as issue when fix=false");
|
|
78
|
+
assert.equal(delimIssues[0].severity, "warning");
|
|
79
|
+
|
|
80
|
+
// File should be unchanged
|
|
81
|
+
const content = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
|
|
82
|
+
assert.ok(content.includes("\u2014"), "file should not be modified when fix=false");
|
|
87
83
|
});
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
+
import { describe, test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
1
3
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:fs";
|
|
2
4
|
import { join } from "node:path";
|
|
3
5
|
import { tmpdir } from "node:os";
|
|
4
6
|
|
|
5
7
|
import { runGSDDoctor } from "../doctor.js";
|
|
6
8
|
import { formatDoctorReportJson } from "../doctor-format.js";
|
|
7
|
-
import { createTestContext } from "./test-helpers.ts";
|
|
8
|
-
|
|
9
|
-
const { assertEq, assertTrue, assertMatch, report } = createTestContext();
|
|
10
|
-
|
|
11
9
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
12
10
|
|
|
13
11
|
function makeBase(): { base: string; gsd: string; mDir: string } {
|
|
@@ -30,41 +28,38 @@ function writeSlice(mDir: string, sliceId: string, planContent: string): string
|
|
|
30
28
|
return sDir;
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
async
|
|
31
|
+
describe('doctor-enhancements', async () => {
|
|
34
32
|
// ── 1. Circular dependency detection ──────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
{
|
|
33
|
+
test('circular dependency detection', async () => {
|
|
37
34
|
const { base, mDir } = makeBase();
|
|
38
35
|
writeRoadmap(mDir, `# M001: Circular Test\n\n## Slices\n- [ ] **S01: Slice A** \`risk:low\` \`depends:[S02]\`\n > After this: done\n- [ ] **S02: Slice B** \`risk:low\` \`depends:[S01]\`\n > After this: done\n`);
|
|
39
36
|
writeSlice(mDir, "S01", "# S01: Slice A\n\n**Goal:** A\n**Demo:** A\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
40
37
|
writeSlice(mDir, "S02", "# S02: Slice B\n\n**Goal:** B\n**Demo:** B\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
41
38
|
|
|
42
39
|
const result = await runGSDDoctor(base, { fix: false });
|
|
43
|
-
|
|
40
|
+
assert.ok(
|
|
44
41
|
result.issues.some(i => i.code === "circular_slice_dependency"),
|
|
45
42
|
"detects circular dependency S01 → S02 → S01",
|
|
46
43
|
);
|
|
47
44
|
rmSync(base, { recursive: true, force: true });
|
|
48
|
-
}
|
|
45
|
+
});
|
|
49
46
|
|
|
50
47
|
// ── 2. Duplicate task IDs ──────────────────────────────────────────────────
|
|
51
|
-
|
|
52
|
-
{
|
|
48
|
+
test('duplicate task IDs', async () => {
|
|
53
49
|
const { base, mDir } = makeBase();
|
|
54
50
|
writeRoadmap(mDir, `# M001: Dup Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
55
51
|
writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: First** `est:10m`\n Task one.\n- [ ] **T01: Duplicate** `est:10m`\n Task dup.\n");
|
|
56
52
|
|
|
57
53
|
const result = await runGSDDoctor(base, { fix: false });
|
|
58
|
-
|
|
54
|
+
assert.ok(
|
|
59
55
|
result.issues.some(i => i.code === "duplicate_task_id"),
|
|
60
56
|
"detects duplicate task ID T01",
|
|
61
57
|
);
|
|
62
58
|
rmSync(base, { recursive: true, force: true });
|
|
63
|
-
}
|
|
59
|
+
});
|
|
64
60
|
|
|
65
61
|
// ── 3. Orphaned slice directory ──────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
{
|
|
62
|
+
test('orphaned slice directory', async () => {
|
|
68
63
|
const { base, mDir } = makeBase();
|
|
69
64
|
writeRoadmap(mDir, `# M001: Orphan Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
70
65
|
writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
@@ -72,16 +67,15 @@ async function main(): Promise<void> {
|
|
|
72
67
|
mkdirSync(join(mDir, "slices", "S99"), { recursive: true });
|
|
73
68
|
|
|
74
69
|
const result = await runGSDDoctor(base, { fix: false });
|
|
75
|
-
|
|
70
|
+
assert.ok(
|
|
76
71
|
result.issues.some(i => i.code === "orphaned_slice_directory" && i.message.includes("S99")),
|
|
77
72
|
"detects orphaned slice directory S99",
|
|
78
73
|
);
|
|
79
74
|
rmSync(base, { recursive: true, force: true });
|
|
80
|
-
}
|
|
75
|
+
});
|
|
81
76
|
|
|
82
77
|
// ── 4. Task file not in plan ───────────────────────────────────────────────
|
|
83
|
-
|
|
84
|
-
{
|
|
78
|
+
test('task file not in plan', async () => {
|
|
85
79
|
const { base, mDir } = makeBase();
|
|
86
80
|
writeRoadmap(mDir, `# M001: Extra Task Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
87
81
|
const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [x] **T01: Task** `est:10m`\n Done.\n");
|
|
@@ -91,16 +85,15 @@ async function main(): Promise<void> {
|
|
|
91
85
|
writeFileSync(join(sDir, "tasks", "T99-SUMMARY.md"), "---\nstatus: done\n---\n# T99\nExtra.\n");
|
|
92
86
|
|
|
93
87
|
const result = await runGSDDoctor(base, { fix: false });
|
|
94
|
-
|
|
88
|
+
assert.ok(
|
|
95
89
|
result.issues.some(i => i.code === "task_file_not_in_plan" && i.message.includes("T99")),
|
|
96
90
|
"detects task summary T99 not in plan",
|
|
97
91
|
);
|
|
98
92
|
rmSync(base, { recursive: true, force: true });
|
|
99
|
-
}
|
|
93
|
+
});
|
|
100
94
|
|
|
101
95
|
// ── 5. Stale REPLAN file ────────────────────────────────────────────────────
|
|
102
|
-
|
|
103
|
-
{
|
|
96
|
+
test('stale REPLAN detection', async () => {
|
|
104
97
|
const { base, mDir } = makeBase();
|
|
105
98
|
writeRoadmap(mDir, `# M001: Replan Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
106
99
|
const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [x] **T01: Task** `est:10m`\n Done.\n");
|
|
@@ -109,16 +102,15 @@ async function main(): Promise<void> {
|
|
|
109
102
|
writeFileSync(join(sDir, "S01-REPLAN.md"), "# S01 REPLAN\nSomething changed.\n");
|
|
110
103
|
|
|
111
104
|
const result = await runGSDDoctor(base, { fix: false });
|
|
112
|
-
|
|
105
|
+
assert.ok(
|
|
113
106
|
result.issues.some(i => i.code === "stale_replan_file"),
|
|
114
107
|
"detects stale REPLAN when all tasks are done",
|
|
115
108
|
);
|
|
116
109
|
rmSync(base, { recursive: true, force: true });
|
|
117
|
-
}
|
|
110
|
+
});
|
|
118
111
|
|
|
119
112
|
// ── 6. Metrics ledger corrupt ───────────────────────────────────────────────
|
|
120
|
-
|
|
121
|
-
{
|
|
113
|
+
test('metrics ledger corrupt', async () => {
|
|
122
114
|
const { base, gsd, mDir } = makeBase();
|
|
123
115
|
writeRoadmap(mDir, `# M001: Metrics Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
124
116
|
writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
@@ -126,16 +118,15 @@ async function main(): Promise<void> {
|
|
|
126
118
|
writeFileSync(join(gsd, "metrics.json"), '{"version":2,"data":[]}');
|
|
127
119
|
|
|
128
120
|
const result = await runGSDDoctor(base, { fix: false });
|
|
129
|
-
|
|
121
|
+
assert.ok(
|
|
130
122
|
result.issues.some(i => i.code === "metrics_ledger_corrupt"),
|
|
131
123
|
"detects corrupt metrics ledger (version != 1)",
|
|
132
124
|
);
|
|
133
125
|
rmSync(base, { recursive: true, force: true });
|
|
134
|
-
}
|
|
126
|
+
});
|
|
135
127
|
|
|
136
128
|
// ── 7. Large planning file ──────────────────────────────────────────────────
|
|
137
|
-
|
|
138
|
-
{
|
|
129
|
+
test('large planning file', async () => {
|
|
139
130
|
const { base, mDir } = makeBase();
|
|
140
131
|
writeRoadmap(mDir, `# M001: Large File Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
141
132
|
const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
@@ -144,16 +135,15 @@ async function main(): Promise<void> {
|
|
|
144
135
|
writeFileSync(join(sDir, "BIGFILE.md"), bigContent);
|
|
145
136
|
|
|
146
137
|
const result = await runGSDDoctor(base, { fix: false });
|
|
147
|
-
|
|
138
|
+
assert.ok(
|
|
148
139
|
result.issues.some(i => i.code === "large_planning_file"),
|
|
149
140
|
"detects large planning file over 100KB",
|
|
150
141
|
);
|
|
151
142
|
rmSync(base, { recursive: true, force: true });
|
|
152
|
-
}
|
|
143
|
+
});
|
|
153
144
|
|
|
154
145
|
// ── 8. Future timestamp ─────────────────────────────────────────────────────
|
|
155
|
-
|
|
156
|
-
{
|
|
146
|
+
test('future timestamp', async () => {
|
|
157
147
|
const { base, mDir } = makeBase();
|
|
158
148
|
writeRoadmap(mDir, `# M001: Timestamp Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
159
149
|
const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [x] **T01: Task** `est:10m`\n Done.\n");
|
|
@@ -165,16 +155,15 @@ async function main(): Promise<void> {
|
|
|
165
155
|
);
|
|
166
156
|
|
|
167
157
|
const result = await runGSDDoctor(base, { fix: false });
|
|
168
|
-
|
|
158
|
+
assert.ok(
|
|
169
159
|
result.issues.some(i => i.code === "future_timestamp"),
|
|
170
160
|
"detects future completed_at timestamp",
|
|
171
161
|
);
|
|
172
162
|
rmSync(base, { recursive: true, force: true });
|
|
173
|
-
}
|
|
163
|
+
});
|
|
174
164
|
|
|
175
165
|
// ── 9. JSON output format ───────────────────────────────────────────────────
|
|
176
|
-
|
|
177
|
-
{
|
|
166
|
+
test('JSON output format', async () => {
|
|
178
167
|
const { base, mDir } = makeBase();
|
|
179
168
|
writeRoadmap(mDir, `# M001: JSON Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
180
169
|
writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
@@ -189,19 +178,18 @@ async function main(): Promise<void> {
|
|
|
189
178
|
parsed = null;
|
|
190
179
|
}
|
|
191
180
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
181
|
+
assert.ok(parsed !== null, "formatDoctorReportJson produces valid JSON");
|
|
182
|
+
assert.ok(typeof (parsed as Record<string, unknown>)?.ok === "boolean", "JSON has ok field");
|
|
183
|
+
assert.ok(Array.isArray((parsed as Record<string, unknown>)?.issues), "JSON has issues array");
|
|
184
|
+
assert.ok(Array.isArray((parsed as Record<string, unknown>)?.fixesApplied), "JSON has fixesApplied array");
|
|
185
|
+
assert.ok(typeof (parsed as Record<string, unknown>)?.generatedAt === "string", "JSON has generatedAt field");
|
|
186
|
+
assert.ok(typeof (parsed as Record<string, unknown>)?.summary === "object", "JSON has summary object");
|
|
198
187
|
|
|
199
188
|
rmSync(base, { recursive: true, force: true });
|
|
200
|
-
}
|
|
189
|
+
});
|
|
201
190
|
|
|
202
191
|
// ── 10. Dry-run mode ────────────────────────────────────────────────────────
|
|
203
|
-
|
|
204
|
-
{
|
|
192
|
+
test('dry-run mode', async () => {
|
|
205
193
|
const { base, mDir } = makeBase();
|
|
206
194
|
writeRoadmap(mDir, `# M001: Dry Run Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
207
195
|
writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
@@ -209,32 +197,30 @@ async function main(): Promise<void> {
|
|
|
209
197
|
const result = await runGSDDoctor(base, { fix: true, dryRun: true });
|
|
210
198
|
// dry-run with fix:true still runs the doctor; shouldFix() returns false
|
|
211
199
|
// so no reconciliation fixes are applied through that path
|
|
212
|
-
|
|
213
|
-
|
|
200
|
+
assert.ok(result.issues !== undefined, "dry-run still produces issue list");
|
|
201
|
+
assert.ok(Array.isArray(result.fixesApplied), "dry-run report has fixesApplied array");
|
|
214
202
|
|
|
215
203
|
rmSync(base, { recursive: true, force: true });
|
|
216
|
-
}
|
|
204
|
+
});
|
|
217
205
|
|
|
218
206
|
// ── 11. Per-check timing ─────────────────────────────────────────────────────
|
|
219
|
-
|
|
220
|
-
{
|
|
207
|
+
test('per-check timing', async () => {
|
|
221
208
|
const { base, mDir } = makeBase();
|
|
222
209
|
writeRoadmap(mDir, `# M001: Timing Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
223
210
|
writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
224
211
|
|
|
225
212
|
const result = await runGSDDoctor(base, { fix: false });
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
213
|
+
assert.ok(result.timing !== undefined, "report includes timing");
|
|
214
|
+
assert.ok(typeof result.timing?.git === "number", "timing.git is a number");
|
|
215
|
+
assert.ok(typeof result.timing?.runtime === "number", "timing.runtime is a number");
|
|
216
|
+
assert.ok(typeof result.timing?.environment === "number", "timing.environment is a number");
|
|
217
|
+
assert.ok(typeof result.timing?.gsdState === "number", "timing.gsdState is a number");
|
|
231
218
|
|
|
232
219
|
rmSync(base, { recursive: true, force: true });
|
|
233
|
-
}
|
|
220
|
+
});
|
|
234
221
|
|
|
235
222
|
// ── 12. Doctor history ───────────────────────────────────────────────────────
|
|
236
|
-
|
|
237
|
-
{
|
|
223
|
+
test('doctor history', async () => {
|
|
238
224
|
const { base, gsd, mDir } = makeBase();
|
|
239
225
|
writeRoadmap(mDir, `# M001: History Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
|
|
240
226
|
writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
|
|
@@ -242,23 +228,16 @@ async function main(): Promise<void> {
|
|
|
242
228
|
await runGSDDoctor(base, { fix: false });
|
|
243
229
|
|
|
244
230
|
const historyPath = join(gsd, "doctor-history.jsonl");
|
|
245
|
-
|
|
231
|
+
assert.ok(existsSync(historyPath), "doctor-history.jsonl is created after run");
|
|
246
232
|
|
|
247
233
|
const { readDoctorHistory } = await import("../doctor.js");
|
|
248
234
|
const history = await readDoctorHistory(base);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
235
|
+
assert.ok(history.length >= 1, "history has at least one entry");
|
|
236
|
+
assert.ok(typeof history[0]?.ts === "string", "history entry has ts field");
|
|
237
|
+
assert.ok(typeof history[0]?.ok === "boolean", "history entry has ok field");
|
|
238
|
+
assert.ok(typeof history[0]?.errors === "number", "history entry has errors count");
|
|
239
|
+
assert.ok(Array.isArray(history[0]?.codes), "history entry has codes array");
|
|
254
240
|
|
|
255
241
|
rmSync(base, { recursive: true, force: true });
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
report();
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
main().catch(err => {
|
|
262
|
-
console.error(err);
|
|
263
|
-
process.exit(1);
|
|
242
|
+
});
|
|
264
243
|
});
|