gsd-pi 2.44.0-dev.848dd4c → 2.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -30
- package/dist/resources/extensions/gsd/auto-start.js +0 -10
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +0 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
- package/dist/web/standalone/.next/server/chunks/229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- 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/dist/web/standalone/.next/static/chunks/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +8 -6
- 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 +26 -24
- 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 +48 -29
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +44 -34
- 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 +34 -30
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +12 -10
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +47 -43
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +43 -31
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +45 -40
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto-start.ts +0 -14
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +0 -8
- 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 +16 -14
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +57 -43
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +13 -11
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +523 -465
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +75 -73
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +56 -34
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +656 -533
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +143 -165
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +52 -29
- package/src/resources/extensions/gsd/tests/captures.test.ts +176 -148
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +33 -32
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +143 -141
- 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 +59 -38
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +263 -228
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +302 -250
- package/src/resources/extensions/gsd/tests/context-store.test.ts +367 -354
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +72 -68
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +106 -92
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +35 -27
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +237 -220
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +420 -390
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +92 -76
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +83 -68
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +183 -152
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +101 -78
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +227 -192
- package/src/resources/extensions/gsd/tests/detection.test.ts +278 -232
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +34 -30
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +180 -164
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +49 -43
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +32 -28
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +29 -27
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +38 -34
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +75 -54
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +32 -21
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +97 -72
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +44 -38
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +145 -104
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +106 -84
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +60 -54
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +93 -72
- package/src/resources/extensions/gsd/tests/doctor.test.ts +134 -104
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +131 -123
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +24 -20
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +57 -48
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +42 -30
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +206 -198
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +27 -13
- package/src/resources/extensions/gsd/tests/git-service.test.ts +388 -285
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +39 -31
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +69 -63
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +264 -255
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +119 -108
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +103 -81
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +262 -229
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +102 -81
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +18 -16
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +46 -41
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +53 -42
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +91 -75
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +194 -150
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +125 -101
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +54 -45
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +93 -80
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +66 -57
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +93 -83
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +170 -161
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +141 -125
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +131 -107
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +96 -87
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +164 -125
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +94 -81
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +36 -35
- package/src/resources/extensions/gsd/tests/overrides.test.ts +106 -99
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +47 -40
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +28 -25
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +83 -66
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +77 -54
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +115 -68
- package/src/resources/extensions/gsd/tests/parsers.test.ts +611 -546
- package/src/resources/extensions/gsd/tests/paths.test.ts +87 -72
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +117 -77
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +119 -93
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +82 -70
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +55 -42
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +73 -45
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +38 -28
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +80 -73
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +74 -71
- package/src/resources/extensions/gsd/tests/requirements.test.ts +75 -70
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +66 -44
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +181 -114
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +65 -63
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +128 -66
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +25 -18
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +44 -37
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +26 -19
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +28 -22
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +56 -54
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +25 -23
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +82 -66
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +47 -46
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +22 -20
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +86 -84
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +43 -41
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +96 -94
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +13 -11
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +29 -27
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +52 -50
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +13 -10
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +18 -14
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +39 -38
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +21 -17
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +30 -25
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +37 -30
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +22 -15
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +66 -59
- package/src/resources/extensions/gsd/tests/worktree.test.ts +50 -44
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +0 -100
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +0 -63
- /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_ssgManifest.js +0 -0
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* Runs in a real temp git repo.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { describe, test, afterEach } from "node:test";
|
|
9
|
-
import assert from "node:assert/strict";
|
|
10
8
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync } from "node:fs";
|
|
11
9
|
import { join } from "node:path";
|
|
12
10
|
import { tmpdir } from "node:os";
|
|
@@ -22,9 +20,10 @@ import {
|
|
|
22
20
|
getActiveAutoWorktreeContext,
|
|
23
21
|
} from "../auto-worktree.ts";
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
24
|
+
|
|
25
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
26
|
+
|
|
28
27
|
function run(command: string, cwd: string): string {
|
|
29
28
|
return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
30
29
|
}
|
|
@@ -43,19 +42,11 @@ function createTempRepo(): string {
|
|
|
43
42
|
return dir;
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
async function main(): Promise<void> {
|
|
47
46
|
const savedCwd = process.cwd();
|
|
48
47
|
let tempDir = "";
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
process.chdir(savedCwd);
|
|
52
|
-
if (tempDir && existsSync(tempDir)) {
|
|
53
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
54
|
-
}
|
|
55
|
-
tempDir = "";
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("create → detect → teardown", () => {
|
|
49
|
+
try {
|
|
59
50
|
tempDir = createTempRepo();
|
|
60
51
|
|
|
61
52
|
// Create .gsd/milestones/M003 with a dummy file (simulates planning artifacts)
|
|
@@ -65,26 +56,28 @@ describe("auto-worktree lifecycle", () => {
|
|
|
65
56
|
run("git add .", tempDir);
|
|
66
57
|
run("git commit -m \"add milestone\"", tempDir);
|
|
67
58
|
|
|
59
|
+
console.log("\n=== auto-worktree lifecycle ===");
|
|
60
|
+
|
|
68
61
|
// ─── createAutoWorktree ──────────────────────────────────────────
|
|
69
62
|
const wtPath = createAutoWorktree(tempDir, "M003");
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
assertTrue(existsSync(wtPath), "worktree directory exists after create");
|
|
65
|
+
assertEq(process.cwd(), wtPath, "process.cwd() is worktree path after create");
|
|
73
66
|
|
|
74
67
|
const branch = run("git branch --show-current", wtPath);
|
|
75
|
-
|
|
68
|
+
assertEq(branch, "milestone/M003", "git branch is milestone/M003");
|
|
76
69
|
|
|
77
|
-
|
|
70
|
+
assertTrue(
|
|
78
71
|
existsSync(join(wtPath, ".gsd", "milestones", "M003", "CONTEXT.md")),
|
|
79
72
|
"planning files inherited in worktree",
|
|
80
73
|
);
|
|
81
74
|
|
|
82
75
|
// ─── isInAutoWorktree ────────────────────────────────────────────
|
|
83
|
-
|
|
76
|
+
assertTrue(isInAutoWorktree(tempDir), "isInAutoWorktree returns true when inside");
|
|
84
77
|
|
|
85
78
|
// ─── getAutoWorktreeOriginalBase ─────────────────────────────────
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
assertEq(getAutoWorktreeOriginalBase(), tempDir, "originalBase returns temp dir");
|
|
80
|
+
assertEq(
|
|
88
81
|
getActiveAutoWorktreeContext(),
|
|
89
82
|
{
|
|
90
83
|
originalBase: tempDir,
|
|
@@ -95,39 +88,33 @@ describe("auto-worktree lifecycle", () => {
|
|
|
95
88
|
);
|
|
96
89
|
|
|
97
90
|
// ─── getAutoWorktreePath ─────────────────────────────────────────
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
assertEq(getAutoWorktreePath(tempDir, "M003"), wtPath, "getAutoWorktreePath returns correct path");
|
|
92
|
+
assertEq(getAutoWorktreePath(tempDir, "M999"), null, "getAutoWorktreePath returns null for nonexistent");
|
|
100
93
|
|
|
101
94
|
// ─── teardownAutoWorktree ────────────────────────────────────────
|
|
102
95
|
teardownAutoWorktree(tempDir, "M003");
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
});
|
|
97
|
+
assertEq(process.cwd(), tempDir, "process.cwd() back to original after teardown");
|
|
98
|
+
assertTrue(!existsSync(wtPath), "worktree directory removed after teardown");
|
|
99
|
+
assertTrue(!isInAutoWorktree(tempDir), "isInAutoWorktree returns false after teardown");
|
|
100
|
+
assertEq(getAutoWorktreeOriginalBase(), null, "originalBase is null after teardown");
|
|
101
|
+
assertEq(getActiveAutoWorktreeContext(), null, "active auto-worktree context clears after teardown");
|
|
110
102
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const msDir = join(tempDir, ".gsd", "milestones", "M003");
|
|
114
|
-
mkdirSync(msDir, { recursive: true });
|
|
115
|
-
writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n");
|
|
116
|
-
run("git add .", tempDir);
|
|
117
|
-
run("git commit -m \"add milestone\"", tempDir);
|
|
103
|
+
// ─── Re-entry: create again, exit without teardown, re-enter ─────
|
|
104
|
+
console.log("\n=== re-entry ===");
|
|
118
105
|
|
|
119
106
|
const wtPath2 = createAutoWorktree(tempDir, "M003");
|
|
120
|
-
|
|
107
|
+
assertTrue(existsSync(wtPath2), "worktree re-created");
|
|
121
108
|
|
|
122
109
|
// Manually chdir out (simulates pause/crash)
|
|
123
110
|
process.chdir(tempDir);
|
|
124
111
|
|
|
125
112
|
// enterAutoWorktree should re-enter
|
|
126
113
|
const entered = enterAutoWorktree(tempDir, "M003");
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
assertEq(process.cwd(), entered, "re-entered worktree via enterAutoWorktree");
|
|
115
|
+
assertEq(getAutoWorktreeOriginalBase(), tempDir, "originalBase restored on re-entry");
|
|
116
|
+
assertTrue(isInAutoWorktree(tempDir), "isInAutoWorktree true after re-entry");
|
|
117
|
+
assertEq(
|
|
131
118
|
getActiveAutoWorktreeContext(),
|
|
132
119
|
{
|
|
133
120
|
originalBase: tempDir,
|
|
@@ -139,151 +126,142 @@ describe("auto-worktree lifecycle", () => {
|
|
|
139
126
|
|
|
140
127
|
// Cleanup
|
|
141
128
|
teardownAutoWorktree(tempDir, "M003");
|
|
142
|
-
});
|
|
143
129
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const msDir = join(tempDir, ".gsd", "milestones", "M003");
|
|
147
|
-
mkdirSync(msDir, { recursive: true });
|
|
148
|
-
writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n");
|
|
149
|
-
run("git add .", tempDir);
|
|
150
|
-
run("git commit -m \"add milestone\"", tempDir);
|
|
130
|
+
// ─── Coexistence with manual worktree ─────────────────────────────
|
|
131
|
+
console.log("\n=== coexistence ===");
|
|
151
132
|
|
|
152
133
|
// Import createWorktree directly for manual worktree
|
|
153
134
|
const { createWorktree } = await import("../worktree-manager.ts");
|
|
154
135
|
|
|
155
136
|
// Create manual worktree (uses worktree/<name> branch)
|
|
156
137
|
const manualWt = createWorktree(tempDir, "feature-x");
|
|
157
|
-
|
|
158
|
-
|
|
138
|
+
assertTrue(existsSync(manualWt.path), "manual worktree exists");
|
|
139
|
+
assertEq(manualWt.branch, "worktree/feature-x", "manual worktree uses worktree/ prefix");
|
|
159
140
|
|
|
160
141
|
// Create auto-worktree alongside
|
|
161
142
|
const autoWtPath = createAutoWorktree(tempDir, "M003");
|
|
162
|
-
|
|
163
|
-
|
|
143
|
+
assertTrue(existsSync(autoWtPath), "auto-worktree coexists with manual");
|
|
144
|
+
assertTrue(existsSync(manualWt.path), "manual worktree still exists");
|
|
164
145
|
|
|
165
146
|
// Cleanup both
|
|
166
147
|
teardownAutoWorktree(tempDir, "M003");
|
|
167
148
|
const { removeWorktree } = await import("../worktree-manager.ts");
|
|
168
149
|
removeWorktree(tempDir, "feature-x");
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test("split-brain prevention: originalBase cleared after teardown", () => {
|
|
172
|
-
tempDir = createTempRepo();
|
|
173
|
-
const msDir = join(tempDir, ".gsd", "milestones", "M003");
|
|
174
|
-
mkdirSync(msDir, { recursive: true });
|
|
175
|
-
writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n");
|
|
176
|
-
run("git add .", tempDir);
|
|
177
|
-
run("git commit -m \"add milestone\"", tempDir);
|
|
178
|
-
|
|
179
|
-
createAutoWorktree(tempDir, "M003");
|
|
180
|
-
teardownAutoWorktree(tempDir, "M003");
|
|
181
|
-
|
|
182
|
-
assert.strictEqual(getAutoWorktreeOriginalBase(), null, "no split-brain: originalBase cleared");
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
test("#1526: getMainBranch returns milestone/<MID> in auto-worktree", async () => {
|
|
186
|
-
tempDir = createTempRepo();
|
|
187
|
-
const msDir = join(tempDir, ".gsd", "milestones", "M005");
|
|
188
|
-
mkdirSync(msDir, { recursive: true });
|
|
189
|
-
writeFileSync(join(msDir, "CONTEXT.md"), "# M005 Context\n");
|
|
190
|
-
run("git add .", tempDir);
|
|
191
|
-
run("git commit -m \"add milestone\"", tempDir);
|
|
192
|
-
|
|
193
|
-
const { GitServiceImpl } = await import("../git-service.ts");
|
|
194
|
-
|
|
195
|
-
// Create worktree
|
|
196
|
-
const wtPath = createAutoWorktree(tempDir, "M005");
|
|
197
|
-
// Don't set main_branch pref so getMainBranch falls through to worktree detection
|
|
198
|
-
const gitService = new GitServiceImpl(wtPath);
|
|
199
|
-
gitService.setMilestoneId("M005");
|
|
200
|
-
|
|
201
|
-
// Verify getMainBranch returns the milestone branch
|
|
202
|
-
const mainBranch = gitService.getMainBranch();
|
|
203
|
-
assert.strictEqual(mainBranch, "milestone/M005", "getMainBranch returns milestone/<MID> in auto-worktree");
|
|
204
|
-
|
|
205
|
-
// Cleanup
|
|
206
|
-
teardownAutoWorktree(tempDir, "M005");
|
|
207
|
-
});
|
|
208
150
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
writeFileSync(join(msDir, "CONTEXT.md"), "# M010 Context\n");
|
|
214
|
-
run("git add .", tempDir);
|
|
215
|
-
run("git commit -m \"add milestone\"", tempDir);
|
|
151
|
+
// ─── Failure: split-brain prevention ──────────────────────────────
|
|
152
|
+
console.log("\n=== split-brain prevention ===");
|
|
153
|
+
// After teardown, originalBase should be null
|
|
154
|
+
assertEq(getAutoWorktreeOriginalBase(), null, "no split-brain: originalBase cleared");
|
|
216
155
|
|
|
217
|
-
//
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
writeFileSync(join(staleDir, "orphan.txt"), "stale leftover\n");
|
|
222
|
-
assert.ok(existsSync(staleDir), "stale directory exists before recovery");
|
|
223
|
-
assert.ok(!existsSync(join(staleDir, ".git")), "stale directory has no .git file");
|
|
156
|
+
// ─── #1526: getMainBranch returns milestone branch in auto-worktree ──
|
|
157
|
+
console.log("\n=== #1526: getMainBranch() returns milestone/<MID> in auto-worktree ===");
|
|
158
|
+
{
|
|
159
|
+
const { GitServiceImpl } = await import("../git-service.ts");
|
|
224
160
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
teardownAutoWorktree(tempDir, "M010");
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
test("#778: reconcile plan checkboxes on re-attach", async () => {
|
|
235
|
-
tempDir = createTempRepo();
|
|
236
|
-
const msDir = join(tempDir, ".gsd", "milestones", "M003");
|
|
237
|
-
mkdirSync(msDir, { recursive: true });
|
|
238
|
-
writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n");
|
|
239
|
-
run("git add .", tempDir);
|
|
240
|
-
run("git commit -m \"add milestone\"", tempDir);
|
|
161
|
+
// Create worktree
|
|
162
|
+
const wtPath = createAutoWorktree(tempDir, "M005");
|
|
163
|
+
// Don't set main_branch pref so getMainBranch falls through to worktree detection
|
|
164
|
+
const gitService = new GitServiceImpl(wtPath);
|
|
165
|
+
gitService.setMilestoneId("M005");
|
|
241
166
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
167
|
+
// Verify getMainBranch returns the milestone branch
|
|
168
|
+
const mainBranch = gitService.getMainBranch();
|
|
169
|
+
assertEq(mainBranch, "milestone/M005", "getMainBranch returns milestone/<MID> in auto-worktree");
|
|
245
170
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
join(tempDir, planRelPath),
|
|
250
|
-
"# S01 Plan\n- [x] **T01:** task one\n- [x] **T02:** task two\n- [ ] **T03:** task three\n",
|
|
251
|
-
);
|
|
171
|
+
// Cleanup
|
|
172
|
+
teardownAutoWorktree(tempDir, "M005");
|
|
173
|
+
}
|
|
252
174
|
|
|
253
|
-
|
|
254
|
-
|
|
175
|
+
// ─── #1713: stale worktree directory recovery ─────────────────────
|
|
176
|
+
console.log("\n=== #1713: stale worktree directory without .git file ===");
|
|
177
|
+
{
|
|
178
|
+
// Simulate a crash leaving a stale directory with no .git file.
|
|
179
|
+
// createAutoWorktree should detect and remove the stale directory,
|
|
180
|
+
// then successfully create a fresh worktree.
|
|
181
|
+
const { worktreePath } = await import("../worktree-manager.ts");
|
|
182
|
+
const staleDir = worktreePath(tempDir, "M010");
|
|
183
|
+
mkdirSync(staleDir, { recursive: true });
|
|
184
|
+
// Write a dummy file to prove it's not an empty directory
|
|
185
|
+
writeFileSync(join(staleDir, "orphan.txt"), "stale leftover\n");
|
|
186
|
+
assertTrue(existsSync(staleDir), "stale directory exists before recovery");
|
|
187
|
+
assertTrue(!existsSync(join(staleDir, ".git")), "stale directory has no .git file");
|
|
188
|
+
|
|
189
|
+
// createAutoWorktree should remove the stale dir and create a real worktree
|
|
190
|
+
const recoveredPath = createAutoWorktree(tempDir, "M010");
|
|
191
|
+
assertTrue(existsSync(recoveredPath), "worktree created after stale dir recovery");
|
|
192
|
+
assertTrue(existsSync(join(recoveredPath, ".git")), "recovered worktree has .git file");
|
|
193
|
+
assertTrue(!existsSync(join(recoveredPath, "orphan.txt")), "stale file removed by recovery");
|
|
194
|
+
|
|
195
|
+
teardownAutoWorktree(tempDir, "M010");
|
|
196
|
+
}
|
|
255
197
|
|
|
256
|
-
//
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
198
|
+
// ─── #778: reconcile plan checkboxes on re-attach ─────────────────
|
|
199
|
+
console.log("\n=== #778: reconcile plan checkboxes on re-attach ===");
|
|
200
|
+
{
|
|
201
|
+
// Simulate: T01 [x] was committed to milestone branch, T02 [x] was
|
|
202
|
+
// written to project root by syncStateToProjectRoot() but the
|
|
203
|
+
// auto-commit crashed before it fired. On restart the worktree is
|
|
204
|
+
// re-created from the milestone branch HEAD (T02 still [ ]).
|
|
205
|
+
// reconcilePlanCheckboxes should forward-apply T02 [x] from the root.
|
|
206
|
+
|
|
207
|
+
const planRelPath = join(".gsd", "milestones", "M004", "slices", "S01", "S01-PLAN.md");
|
|
208
|
+
const planDir = join(tempDir, ".gsd", "milestones", "M004", "slices", "S01");
|
|
209
|
+
const { mkdirSync: mkdir, writeFileSync: write, readFileSync: read } = await import("node:fs");
|
|
210
|
+
|
|
211
|
+
// Plan on integration branch (project root): T01 [x], T02 [x]
|
|
212
|
+
mkdir(planDir, { recursive: true });
|
|
213
|
+
write(
|
|
214
|
+
join(tempDir, planRelPath),
|
|
215
|
+
"# S01 Plan\n- [x] **T01:** task one\n- [x] **T02:** task two\n- [ ] **T03:** task three\n",
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// Write integration-branch plan to git so milestone branch starts from it
|
|
219
|
+
run(`git add .`, tempDir);
|
|
220
|
+
run(`git commit -m "add plan with T01 and T02 checked" --allow-empty`, tempDir);
|
|
221
|
+
|
|
222
|
+
// Create milestone branch with only T01 [x] (simulating crash before T02 commit)
|
|
223
|
+
const milestoneBranch = "milestone/M004";
|
|
224
|
+
run(`git checkout -b ${milestoneBranch}`, tempDir);
|
|
225
|
+
mkdir(planDir, { recursive: true });
|
|
226
|
+
write(
|
|
227
|
+
join(tempDir, planRelPath),
|
|
228
|
+
"# S01 Plan\n- [x] **T01:** task one\n- [ ] **T02:** task two\n- [ ] **T03:** task three\n",
|
|
229
|
+
);
|
|
230
|
+
run(`git add .`, tempDir);
|
|
231
|
+
run(`git commit -m "milestone: only T01 checked"`, tempDir);
|
|
232
|
+
run(`git checkout main`, tempDir);
|
|
233
|
+
|
|
234
|
+
// Restore project root plan (T01+T02 [x]) — simulates syncStateToProjectRoot
|
|
235
|
+
write(
|
|
236
|
+
join(tempDir, planRelPath),
|
|
237
|
+
"# S01 Plan\n- [x] **T01:** task one\n- [x] **T02:** task two\n- [ ] **T03:** task three\n",
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
// Create worktree re-attached to existing milestone branch (T02 still [ ] in branch)
|
|
241
|
+
const wtPath = createAutoWorktree(tempDir, "M004");
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const wtPlanPath = join(wtPath, planRelPath);
|
|
245
|
+
assertTrue(existsSync(wtPlanPath), "plan file exists in worktree after re-attach");
|
|
246
|
+
|
|
247
|
+
const wtPlan = read(wtPlanPath, "utf-8");
|
|
248
|
+
assertTrue(wtPlan.includes("- [x] **T02:"), "T02 should be [x] after reconciliation (was [ ] on branch)");
|
|
249
|
+
assertTrue(wtPlan.includes("- [x] **T01:"), "T01 stays [x]");
|
|
250
|
+
assertTrue(wtPlan.includes("- [ ] **T03:"), "T03 stays [ ] (not in root either)");
|
|
251
|
+
} finally {
|
|
252
|
+
teardownAutoWorktree(tempDir, "M004");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
273
255
|
|
|
274
|
-
|
|
275
|
-
|
|
256
|
+
} finally {
|
|
257
|
+
// Always restore cwd and clean up
|
|
258
|
+
process.chdir(savedCwd);
|
|
259
|
+
if (tempDir && existsSync(tempDir)) {
|
|
260
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
276
263
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
assert.ok(existsSync(wtPlanPath), "plan file exists in worktree after re-attach");
|
|
264
|
+
report();
|
|
265
|
+
}
|
|
280
266
|
|
|
281
|
-
|
|
282
|
-
assert.ok(wtPlan.includes("- [x] **T02:"), "T02 should be [x] after reconciliation (was [ ] on branch)");
|
|
283
|
-
assert.ok(wtPlan.includes("- [x] **T01:"), "T01 stays [x]");
|
|
284
|
-
assert.ok(wtPlan.includes("- [ ] **T03:"), "T03 stays [ ] (not in root either)");
|
|
285
|
-
} finally {
|
|
286
|
-
teardownAutoWorktree(tempDir, "M004");
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
});
|
|
267
|
+
main();
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
* Pattern: derive state → write file → invalidate cache → derive again → verify update
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import {
|
|
16
|
-
import assert from "node:assert/strict";
|
|
17
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
15
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync } from 'node:fs';
|
|
18
16
|
import { join } from 'node:path';
|
|
19
17
|
import { tmpdir } from 'node:os';
|
|
20
18
|
|
|
21
19
|
import { deriveState, invalidateStateCache } from '../state.ts';
|
|
22
20
|
import { invalidateAllCaches } from '../cache.ts';
|
|
21
|
+
import { createTestContext } from './test-helpers.ts';
|
|
22
|
+
|
|
23
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
23
24
|
|
|
24
25
|
function createBase(): string {
|
|
25
26
|
const base = mkdtempSync(join(tmpdir(), 'gsd-cache-stale-'));
|
|
@@ -43,9 +44,11 @@ function writeSliceFile(base: string, mid: string, sid: string, suffix: string,
|
|
|
43
44
|
writeFileSync(join(dir, `${sid}-${suffix}.md`), content);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
async function main(): Promise<void> {
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
// ─── 1. Regression #1240: New roadmap detected after cache invalidation ─
|
|
50
|
+
console.log('\n=== 1. #1240: roadmap written after first derive → detected after invalidation ===');
|
|
51
|
+
{
|
|
49
52
|
const base = createBase();
|
|
50
53
|
try {
|
|
51
54
|
// Step 1: Create milestone with just context (no roadmap)
|
|
@@ -54,7 +57,7 @@ describe("cache-staleness-regression", () => {
|
|
|
54
57
|
invalidateAllCaches();
|
|
55
58
|
invalidateStateCache();
|
|
56
59
|
const state1 = await deriveState(base);
|
|
57
|
-
|
|
60
|
+
assertEq(state1.phase, 'pre-planning', 'initial: pre-planning (no roadmap)');
|
|
58
61
|
|
|
59
62
|
// Step 2: Write roadmap (simulating what the LLM does during planning)
|
|
60
63
|
const roadmap = [
|
|
@@ -77,14 +80,16 @@ describe("cache-staleness-regression", () => {
|
|
|
77
80
|
invalidateAllCaches();
|
|
78
81
|
invalidateStateCache();
|
|
79
82
|
const state2 = await deriveState(base);
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
assertEq(state2.phase, 'planning', '#1240: after roadmap write + invalidation → planning phase');
|
|
84
|
+
assertEq(state2.activeSlice?.id, 'S01', '#1240: S01 is now the active slice');
|
|
82
85
|
} finally {
|
|
83
86
|
cleanup(base);
|
|
84
87
|
}
|
|
85
|
-
}
|
|
88
|
+
}
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
// ─── 2. Regression #1249: Slice context detected after cache invalidation ─
|
|
91
|
+
console.log('\n=== 2. #1249: slice context written mid-loop → detected after invalidation ===');
|
|
92
|
+
{
|
|
88
93
|
const base = createBase();
|
|
89
94
|
try {
|
|
90
95
|
// Create a milestone in needs-discussion phase (CONTEXT-DRAFT, no CONTEXT)
|
|
@@ -95,7 +100,7 @@ describe("cache-staleness-regression", () => {
|
|
|
95
100
|
invalidateAllCaches();
|
|
96
101
|
invalidateStateCache();
|
|
97
102
|
const state1 = await deriveState(base);
|
|
98
|
-
|
|
103
|
+
assertEq(state1.phase, 'needs-discussion', 'initial: needs-discussion');
|
|
99
104
|
|
|
100
105
|
// Simulate: discussion completes, CONTEXT.md is written
|
|
101
106
|
writeMilestoneFile(base, 'M001', 'CONTEXT', '# M001: Test\n\nFull context after discussion.\n');
|
|
@@ -107,16 +112,21 @@ describe("cache-staleness-regression", () => {
|
|
|
107
112
|
invalidateAllCaches();
|
|
108
113
|
invalidateStateCache();
|
|
109
114
|
const state2 = await deriveState(base);
|
|
110
|
-
|
|
115
|
+
// Should now be pre-planning (has context, but no roadmap yet)
|
|
116
|
+
// Actually needs-discussion won't trigger because now CONTEXT exists
|
|
117
|
+
// The state should advance past needs-discussion
|
|
118
|
+
assertTrue(
|
|
111
119
|
state2.phase !== 'needs-discussion',
|
|
112
120
|
'#1249: after context write + invalidation → not stuck in needs-discussion',
|
|
113
121
|
);
|
|
114
122
|
} finally {
|
|
115
123
|
cleanup(base);
|
|
116
124
|
}
|
|
117
|
-
}
|
|
125
|
+
}
|
|
118
126
|
|
|
119
|
-
|
|
127
|
+
// ─── 3. State cache TTL expires naturally ─────────────────────────────
|
|
128
|
+
console.log('\n=== 3. state cache TTL: fresh reads after 100ms ===');
|
|
129
|
+
{
|
|
120
130
|
const base = createBase();
|
|
121
131
|
try {
|
|
122
132
|
writeMilestoneFile(base, 'M001', 'CONTEXT', '# M001\n\nDesc.\n');
|
|
@@ -124,7 +134,7 @@ describe("cache-staleness-regression", () => {
|
|
|
124
134
|
invalidateAllCaches();
|
|
125
135
|
invalidateStateCache();
|
|
126
136
|
const state1 = await deriveState(base);
|
|
127
|
-
|
|
137
|
+
assertEq(state1.phase, 'pre-planning', 'initial: pre-planning');
|
|
128
138
|
|
|
129
139
|
// Write roadmap immediately
|
|
130
140
|
writeMilestoneFile(base, 'M001', 'ROADMAP', [
|
|
@@ -147,13 +157,15 @@ describe("cache-staleness-regression", () => {
|
|
|
147
157
|
invalidateAllCaches();
|
|
148
158
|
invalidateStateCache();
|
|
149
159
|
const state3 = await deriveState(base);
|
|
150
|
-
|
|
160
|
+
assertEq(state3.phase, 'planning', 'after TTL expiry + invalidation → planning');
|
|
151
161
|
} finally {
|
|
152
162
|
cleanup(base);
|
|
153
163
|
}
|
|
154
|
-
}
|
|
164
|
+
}
|
|
155
165
|
|
|
156
|
-
|
|
166
|
+
// ─── 4. Task completion detection after file write ────────────────────
|
|
167
|
+
console.log('\n=== 4. task marked done in plan → state advances ===');
|
|
168
|
+
{
|
|
157
169
|
const base = createBase();
|
|
158
170
|
try {
|
|
159
171
|
writeMilestoneFile(base, 'M001', 'CONTEXT', '# M001\n\nDesc.\n');
|
|
@@ -182,7 +194,7 @@ describe("cache-staleness-regression", () => {
|
|
|
182
194
|
invalidateAllCaches();
|
|
183
195
|
invalidateStateCache();
|
|
184
196
|
const state1 = await deriveState(base);
|
|
185
|
-
|
|
197
|
+
assertEq(state1.activeTask?.id, 'T01', 'initial: T01 is active task');
|
|
186
198
|
|
|
187
199
|
// Mark T01 as done by rewriting the plan
|
|
188
200
|
writeSliceFile(base, 'M001', 'S01', 'PLAN', [
|
|
@@ -198,13 +210,15 @@ describe("cache-staleness-regression", () => {
|
|
|
198
210
|
invalidateAllCaches();
|
|
199
211
|
invalidateStateCache();
|
|
200
212
|
const state2 = await deriveState(base);
|
|
201
|
-
|
|
213
|
+
assertEq(state2.activeTask?.id, 'T02', 'after T01 done → T02 is active task');
|
|
202
214
|
} finally {
|
|
203
215
|
cleanup(base);
|
|
204
216
|
}
|
|
205
|
-
}
|
|
217
|
+
}
|
|
206
218
|
|
|
207
|
-
|
|
219
|
+
// ─── 5. Slice completion detection ────────────────────────────────────
|
|
220
|
+
console.log('\n=== 5. all tasks done → summarizing phase ===');
|
|
221
|
+
{
|
|
208
222
|
const base = createBase();
|
|
209
223
|
try {
|
|
210
224
|
writeMilestoneFile(base, 'M001', 'CONTEXT', '# M001\n\nDesc.\n');
|
|
@@ -231,7 +245,7 @@ describe("cache-staleness-regression", () => {
|
|
|
231
245
|
invalidateAllCaches();
|
|
232
246
|
invalidateStateCache();
|
|
233
247
|
const state1 = await deriveState(base);
|
|
234
|
-
|
|
248
|
+
assertEq(state1.phase, 'executing', 'initial: executing');
|
|
235
249
|
|
|
236
250
|
// Mark task done
|
|
237
251
|
writeSliceFile(base, 'M001', 'S01', 'PLAN', [
|
|
@@ -246,13 +260,15 @@ describe("cache-staleness-regression", () => {
|
|
|
246
260
|
invalidateAllCaches();
|
|
247
261
|
invalidateStateCache();
|
|
248
262
|
const state2 = await deriveState(base);
|
|
249
|
-
|
|
263
|
+
assertEq(state2.phase, 'summarizing', 'after all tasks done → summarizing');
|
|
250
264
|
} finally {
|
|
251
265
|
cleanup(base);
|
|
252
266
|
}
|
|
253
|
-
}
|
|
267
|
+
}
|
|
254
268
|
|
|
255
|
-
|
|
269
|
+
// ─── 6. Roadmap slice marked done → advance to next slice ─────────────
|
|
270
|
+
console.log('\n=== 6. roadmap slice marked [x] → next slice active ===');
|
|
271
|
+
{
|
|
256
272
|
const base = createBase();
|
|
257
273
|
try {
|
|
258
274
|
writeMilestoneFile(base, 'M001', 'CONTEXT', '# M001\n\nDesc.\n');
|
|
@@ -269,7 +285,7 @@ describe("cache-staleness-regression", () => {
|
|
|
269
285
|
invalidateAllCaches();
|
|
270
286
|
invalidateStateCache();
|
|
271
287
|
const state1 = await deriveState(base);
|
|
272
|
-
|
|
288
|
+
assertEq(state1.activeSlice?.id, 'S01', 'initial: S01 active');
|
|
273
289
|
|
|
274
290
|
// Mark S01 as done in roadmap
|
|
275
291
|
writeMilestoneFile(base, 'M001', 'ROADMAP', [
|
|
@@ -286,9 +302,16 @@ describe("cache-staleness-regression", () => {
|
|
|
286
302
|
invalidateAllCaches();
|
|
287
303
|
invalidateStateCache();
|
|
288
304
|
const state2 = await deriveState(base);
|
|
289
|
-
|
|
305
|
+
assertEq(state2.activeSlice?.id, 'S02', 'after S01 done → S02 active');
|
|
290
306
|
} finally {
|
|
291
307
|
cleanup(base);
|
|
292
308
|
}
|
|
293
|
-
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
report();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
main().catch((error) => {
|
|
315
|
+
console.error(error);
|
|
316
|
+
process.exit(1);
|
|
294
317
|
});
|