gsd-pi 2.45.0 → 2.46.0-dev.cc9d310
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/dist/help-text.js +1 -1
- package/dist/loader.js +34 -0
- package/dist/resources/extensions/gsd/auto/phases.js +27 -42
- package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
- package/dist/resources/extensions/gsd/auto/session.js +0 -11
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
- package/dist/resources/extensions/gsd/auto-start.js +2 -3
- package/dist/resources/extensions/gsd/auto-worktree.js +5 -4
- package/dist/resources/extensions/gsd/auto.js +12 -57
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +15 -12
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
- package/dist/resources/extensions/gsd/commands/context.js +0 -4
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
- package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
- package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
- package/dist/resources/extensions/gsd/db-writer.js +9 -9
- package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
- package/dist/resources/extensions/gsd/doctor.js +5 -3
- package/dist/resources/extensions/gsd/gsd-db.js +16 -3
- package/dist/resources/extensions/gsd/guided-flow.js +1 -2
- package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
- package/dist/resources/extensions/gsd/preferences-types.js +2 -2
- package/dist/resources/extensions/gsd/preferences.js +8 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -8
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
- package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
- package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
- package/dist/resources/extensions/gsd/prompts/rethink.md +7 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/session-lock.js +1 -3
- package/dist/resources/extensions/gsd/state.js +7 -0
- package/dist/resources/extensions/gsd/sync-lock.js +89 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
- package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
- package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +30 -1
- package/dist/resources/extensions/gsd/tools/plan-task.js +27 -1
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +32 -2
- package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
- package/dist/resources/extensions/gsd/workflow-events.js +102 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
- package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
- package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +4 -3
- package/dist/resources/extensions/gsd/worktree-resolver.js +37 -0
- package/dist/resources/extensions/gsd/write-intercept.js +84 -0
- package/dist/resources/extensions/voice/index.js +11 -16
- package/dist/resources/extensions/voice/linux-ready.js +67 -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 +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 +17 -17
- 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-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.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 +2 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +2 -1
- 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 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
- package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
- package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
- package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
- package/packages/pi-coding-agent/src/core/model-registry.ts +30 -3
- package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
- package/src/resources/extensions/gsd/auto/phases.ts +24 -44
- package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
- package/src/resources/extensions/gsd/auto/session.ts +0 -18
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
- package/src/resources/extensions/gsd/auto-start.ts +1 -3
- package/src/resources/extensions/gsd/auto-worktree.ts +8 -5
- package/src/resources/extensions/gsd/auto.ts +7 -83
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -12
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
- package/src/resources/extensions/gsd/commands/context.ts +0 -5
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
- package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
- package/src/resources/extensions/gsd/db-writer.ts +9 -17
- package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
- package/src/resources/extensions/gsd/doctor-types.ts +7 -1
- package/src/resources/extensions/gsd/doctor.ts +6 -3
- package/src/resources/extensions/gsd/gsd-db.ts +16 -3
- package/src/resources/extensions/gsd/guided-flow.ts +1 -2
- package/src/resources/extensions/gsd/journal.ts +6 -1
- package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
- package/src/resources/extensions/gsd/preferences-types.ts +2 -2
- package/src/resources/extensions/gsd/preferences.ts +7 -3
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -8
- package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
- package/src/resources/extensions/gsd/prompts/queue.md +2 -2
- package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/rethink.md +7 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/session-lock.ts +0 -4
- package/src/resources/extensions/gsd/state.ts +8 -0
- package/src/resources/extensions/gsd/sync-lock.ts +94 -0
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +5 -13
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +264 -228
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +317 -250
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +2 -8
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +15 -24
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
- package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -7
- package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -2
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +15 -14
- package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +1 -4
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
- package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
- package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
- package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +38 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +35 -1
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +38 -1
- package/src/resources/extensions/gsd/types.ts +8 -0
- package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
- package/src/resources/extensions/gsd/workflow-events.ts +154 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
- package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
- package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +4 -9
- package/src/resources/extensions/gsd/worktree-resolver.ts +37 -0
- package/src/resources/extensions/gsd/write-intercept.ts +90 -0
- package/src/resources/extensions/voice/index.ts +11 -21
- package/src/resources/extensions/voice/linux-ready.ts +87 -0
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
- package/dist/web/standalone/.next/static/chunks/app/page-12dd5ece0df4badc.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- /package/dist/web/standalone/.next/static/{wUzEX1U3CmFcMry2SUDJn → ZIDqryyYDroh_8AnaAOSG}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{wUzEX1U3CmFcMry2SUDJn → ZIDqryyYDroh_8AnaAOSG}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// GSD Extension — post-mutation hook regression tests
|
|
2
|
+
// Verifies that after a successful handleCompleteTask call, the post-mutation
|
|
3
|
+
// hook fires: event-log.jsonl and state-manifest.json are both written.
|
|
4
|
+
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import * as os from 'node:os';
|
|
10
|
+
import { openDatabase, closeDatabase } from '../gsd-db.ts';
|
|
11
|
+
import { handleCompleteTask } from '../tools/complete-task.ts';
|
|
12
|
+
import { readEvents } from '../workflow-events.ts';
|
|
13
|
+
import { readManifest } from '../workflow-manifest.ts';
|
|
14
|
+
|
|
15
|
+
function tempDir(): string {
|
|
16
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-post-hook-'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function cleanupDir(dirPath: string): void {
|
|
20
|
+
try { fs.rmSync(dirPath, { recursive: true, force: true }); } catch { /* best effort */ }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Create a minimal project directory with a PLAN.md for complete-task to find. */
|
|
24
|
+
function createProject(basePath: string): void {
|
|
25
|
+
const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
|
|
26
|
+
const tasksDir = path.join(sliceDir, 'tasks');
|
|
27
|
+
fs.mkdirSync(tasksDir, { recursive: true });
|
|
28
|
+
fs.writeFileSync(path.join(sliceDir, 'S01-PLAN.md'), `# S01: Test Slice
|
|
29
|
+
|
|
30
|
+
## Tasks
|
|
31
|
+
|
|
32
|
+
- [ ] **T01: Test task** \`est:30m\`
|
|
33
|
+
- Do: Implement the thing
|
|
34
|
+
- Verify: Run tests
|
|
35
|
+
|
|
36
|
+
- [ ] **T02: Second task** \`est:1h\`
|
|
37
|
+
- Do: Implement more
|
|
38
|
+
- Verify: Run more tests
|
|
39
|
+
`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function makeCompleteTaskParams() {
|
|
43
|
+
return {
|
|
44
|
+
taskId: 'T01',
|
|
45
|
+
sliceId: 'S01',
|
|
46
|
+
milestoneId: 'M001',
|
|
47
|
+
oneLiner: 'Implemented auth middleware',
|
|
48
|
+
narrative: 'Added JWT validation middleware with proper error handling.',
|
|
49
|
+
verification: 'Ran npm test — all tests pass.',
|
|
50
|
+
deviations: 'None.',
|
|
51
|
+
knownIssues: 'None.',
|
|
52
|
+
keyFiles: ['src/middleware/auth.ts'],
|
|
53
|
+
keyDecisions: [],
|
|
54
|
+
blockerDiscovered: false,
|
|
55
|
+
verificationEvidence: [
|
|
56
|
+
{ command: 'npm test', exitCode: 0, verdict: '✅ pass', durationMs: 2500 },
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ─── Post-mutation hook: event log ───────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
test('post-mutation-hook: event-log.jsonl exists after handleCompleteTask', async () => {
|
|
64
|
+
const base = tempDir();
|
|
65
|
+
const dbPath = path.join(base, 'test.db');
|
|
66
|
+
openDatabase(dbPath);
|
|
67
|
+
createProject(base);
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const result = await handleCompleteTask(makeCompleteTaskParams(), base);
|
|
71
|
+
assert.ok(!('error' in result), `handler should succeed, got: ${JSON.stringify(result)}`);
|
|
72
|
+
|
|
73
|
+
const logPath = path.join(base, '.gsd', 'event-log.jsonl');
|
|
74
|
+
assert.ok(fs.existsSync(logPath), 'event-log.jsonl should exist after handler completes');
|
|
75
|
+
} finally {
|
|
76
|
+
closeDatabase();
|
|
77
|
+
cleanupDir(base);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('post-mutation-hook: event log contains complete-task event with correct params', async () => {
|
|
82
|
+
const base = tempDir();
|
|
83
|
+
const dbPath = path.join(base, 'test.db');
|
|
84
|
+
openDatabase(dbPath);
|
|
85
|
+
createProject(base);
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
await handleCompleteTask(makeCompleteTaskParams(), base);
|
|
89
|
+
|
|
90
|
+
const logPath = path.join(base, '.gsd', 'event-log.jsonl');
|
|
91
|
+
const events = readEvents(logPath);
|
|
92
|
+
assert.ok(events.length > 0, 'event log should have at least one event');
|
|
93
|
+
|
|
94
|
+
const ev = events.find((e) => e.cmd === 'complete-task');
|
|
95
|
+
assert.ok(ev !== undefined, 'should have a complete-task event');
|
|
96
|
+
assert.strictEqual((ev!.params as { milestoneId?: string }).milestoneId, 'M001');
|
|
97
|
+
assert.strictEqual((ev!.params as { sliceId?: string }).sliceId, 'S01');
|
|
98
|
+
assert.strictEqual((ev!.params as { taskId?: string }).taskId, 'T01');
|
|
99
|
+
assert.strictEqual(ev!.actor, 'agent');
|
|
100
|
+
} finally {
|
|
101
|
+
closeDatabase();
|
|
102
|
+
cleanupDir(base);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// ─── Post-mutation hook: manifest ────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
test('post-mutation-hook: state-manifest.json exists after handleCompleteTask', async () => {
|
|
109
|
+
const base = tempDir();
|
|
110
|
+
const dbPath = path.join(base, 'test.db');
|
|
111
|
+
openDatabase(dbPath);
|
|
112
|
+
createProject(base);
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const result = await handleCompleteTask(makeCompleteTaskParams(), base);
|
|
116
|
+
assert.ok(!('error' in result), `handler should succeed, got: ${JSON.stringify(result)}`);
|
|
117
|
+
|
|
118
|
+
const manifestPath = path.join(base, '.gsd', 'state-manifest.json');
|
|
119
|
+
assert.ok(fs.existsSync(manifestPath), 'state-manifest.json should exist after handler completes');
|
|
120
|
+
} finally {
|
|
121
|
+
closeDatabase();
|
|
122
|
+
cleanupDir(base);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('post-mutation-hook: manifest has version 1 and includes completed task', async () => {
|
|
127
|
+
const base = tempDir();
|
|
128
|
+
const dbPath = path.join(base, 'test.db');
|
|
129
|
+
openDatabase(dbPath);
|
|
130
|
+
createProject(base);
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await handleCompleteTask(makeCompleteTaskParams(), base);
|
|
134
|
+
|
|
135
|
+
const manifest = readManifest(base);
|
|
136
|
+
assert.ok(manifest !== null, 'manifest should be readable');
|
|
137
|
+
assert.strictEqual(manifest!.version, 1);
|
|
138
|
+
|
|
139
|
+
const task = manifest!.tasks.find((t) => t.id === 'T01');
|
|
140
|
+
assert.ok(task !== undefined, 'T01 should appear in manifest');
|
|
141
|
+
assert.strictEqual(task!.status, 'complete');
|
|
142
|
+
assert.strictEqual(task!.milestone_id, 'M001');
|
|
143
|
+
assert.strictEqual(task!.slice_id, 'S01');
|
|
144
|
+
} finally {
|
|
145
|
+
closeDatabase();
|
|
146
|
+
cleanupDir(base);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// ─── Post-mutation hook: non-fatal on hook failure ───────────────────────
|
|
151
|
+
|
|
152
|
+
test('post-mutation-hook: handler still returns success even if projections dir is missing', async () => {
|
|
153
|
+
// basePath with NO .gsd directory — projections will fail to find milestones
|
|
154
|
+
// but handler should still return a result (not throw)
|
|
155
|
+
const base = tempDir();
|
|
156
|
+
const dbPath = path.join(base, 'test.db');
|
|
157
|
+
openDatabase(dbPath);
|
|
158
|
+
|
|
159
|
+
// Create tasks dir but NO plan file (projections will soft-fail)
|
|
160
|
+
const tasksDir = path.join(base, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'tasks');
|
|
161
|
+
fs.mkdirSync(tasksDir, { recursive: true });
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const result = await handleCompleteTask(makeCompleteTaskParams(), base);
|
|
165
|
+
// Handler should succeed (post-hook failures are non-fatal)
|
|
166
|
+
assert.ok(!('error' in result), `handler should not propagate hook errors, got: ${JSON.stringify(result)}`);
|
|
167
|
+
} finally {
|
|
168
|
+
closeDatabase();
|
|
169
|
+
cleanupDir(base);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
@@ -41,18 +41,16 @@ test("git.merge_to_main produces deprecation warning", () => {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
test("getIsolationMode defaults to
|
|
44
|
+
test("getIsolationMode defaults to none when preferences have no isolation setting", () => {
|
|
45
45
|
// Validate the default via validatePreferences: when no isolation is set,
|
|
46
|
-
// preferences.git.isolation is undefined, and getIsolationMode returns "
|
|
47
|
-
//
|
|
46
|
+
// preferences.git.isolation is undefined, and getIsolationMode returns "none".
|
|
47
|
+
// Default changed from "worktree" to "none" so GSD works out of the box
|
|
48
|
+
// without preferences.md (#2480).
|
|
48
49
|
const { preferences } = validatePreferences({});
|
|
49
50
|
assert.equal(preferences.git?.isolation, undefined, "no isolation in empty prefs");
|
|
50
|
-
// The function returns "worktree" when prefs?.git?.isolation is not "none" or "branch"
|
|
51
|
-
// This is a compile-time-verifiable truth from the function body — test it directly
|
|
52
|
-
// by constructing the same conditions getIsolationMode checks.
|
|
53
51
|
const isolation = preferences.git?.isolation;
|
|
54
|
-
const expected = isolation === "
|
|
55
|
-
assert.equal(expected, "
|
|
52
|
+
const expected = isolation === "worktree" ? "worktree" : isolation === "branch" ? "branch" : "none";
|
|
53
|
+
assert.equal(expected, "none", "default isolation mode is none");
|
|
56
54
|
});
|
|
57
55
|
|
|
58
56
|
// ── Mode defaults ────────────────────────────────────────────────────────────
|
|
@@ -63,7 +61,7 @@ test("solo mode applies correct defaults", () => {
|
|
|
63
61
|
assert.equal(result.git?.push_branches, false);
|
|
64
62
|
assert.equal(result.git?.pre_merge_check, false);
|
|
65
63
|
assert.equal(result.git?.merge_strategy, "squash");
|
|
66
|
-
assert.equal(result.git?.isolation, "
|
|
64
|
+
assert.equal(result.git?.isolation, "none");
|
|
67
65
|
assert.equal(result.unique_milestone_ids, false);
|
|
68
66
|
});
|
|
69
67
|
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// GSD — projection renderer regression tests
|
|
2
|
+
// Verifies that "done" vs "complete" status mismatch doesn't recur.
|
|
3
|
+
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
4
|
+
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
|
|
8
|
+
import { renderPlanContent, renderRoadmapContent } from '../workflow-projections.ts';
|
|
9
|
+
import type { SliceRow, TaskRow } from '../gsd-db.ts';
|
|
10
|
+
|
|
11
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
function makeSliceRow(overrides?: Partial<SliceRow>): SliceRow {
|
|
14
|
+
return {
|
|
15
|
+
milestone_id: 'M001',
|
|
16
|
+
id: 'S01',
|
|
17
|
+
title: 'Test Slice',
|
|
18
|
+
status: 'pending',
|
|
19
|
+
risk: 'medium',
|
|
20
|
+
depends: [],
|
|
21
|
+
demo: 'Demo.',
|
|
22
|
+
created_at: '2026-01-01T00:00:00Z',
|
|
23
|
+
completed_at: null,
|
|
24
|
+
full_summary_md: '',
|
|
25
|
+
full_uat_md: '',
|
|
26
|
+
goal: 'Test goal',
|
|
27
|
+
success_criteria: '',
|
|
28
|
+
proof_level: '',
|
|
29
|
+
integration_closure: '',
|
|
30
|
+
observability_impact: '',
|
|
31
|
+
sequence: 0,
|
|
32
|
+
replan_triggered_at: null,
|
|
33
|
+
...overrides,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function makeTaskRow(overrides?: Partial<TaskRow>): TaskRow {
|
|
38
|
+
return {
|
|
39
|
+
milestone_id: 'M001',
|
|
40
|
+
slice_id: 'S01',
|
|
41
|
+
id: 'T01',
|
|
42
|
+
title: 'Test Task',
|
|
43
|
+
status: 'pending',
|
|
44
|
+
one_liner: '',
|
|
45
|
+
narrative: '',
|
|
46
|
+
verification_result: '',
|
|
47
|
+
duration: '',
|
|
48
|
+
completed_at: null,
|
|
49
|
+
blocker_discovered: false,
|
|
50
|
+
deviations: '',
|
|
51
|
+
known_issues: '',
|
|
52
|
+
key_files: [],
|
|
53
|
+
key_decisions: [],
|
|
54
|
+
full_summary_md: '',
|
|
55
|
+
full_plan_md: '',
|
|
56
|
+
description: 'Test description',
|
|
57
|
+
estimate: '30m',
|
|
58
|
+
files: ['src/test.ts'],
|
|
59
|
+
verify: 'npm test',
|
|
60
|
+
inputs: [],
|
|
61
|
+
expected_output: [],
|
|
62
|
+
observability_impact: '',
|
|
63
|
+
sequence: 0,
|
|
64
|
+
...overrides,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function makeMilestoneRow() {
|
|
69
|
+
return {
|
|
70
|
+
id: 'M001',
|
|
71
|
+
title: 'Test Milestone',
|
|
72
|
+
status: 'active',
|
|
73
|
+
depends_on: [],
|
|
74
|
+
created_at: '2026-01-01T00:00:00Z',
|
|
75
|
+
completed_at: null,
|
|
76
|
+
vision: 'Test vision',
|
|
77
|
+
success_criteria: [],
|
|
78
|
+
key_risks: [],
|
|
79
|
+
proof_strategy: [],
|
|
80
|
+
verification_contract: '',
|
|
81
|
+
verification_integration: '',
|
|
82
|
+
verification_operational: '',
|
|
83
|
+
verification_uat: '',
|
|
84
|
+
definition_of_done: [],
|
|
85
|
+
requirement_coverage: '',
|
|
86
|
+
boundary_map_markdown: '',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─── renderPlanContent: checkbox regression ──────────────────────────────
|
|
91
|
+
|
|
92
|
+
test('renderPlanContent: task with status "complete" renders [x] checkbox', () => {
|
|
93
|
+
const slice = makeSliceRow();
|
|
94
|
+
const tasks = [makeTaskRow({ id: 'T01', status: 'complete', title: 'Completed Task' })];
|
|
95
|
+
|
|
96
|
+
const content = renderPlanContent(slice, tasks);
|
|
97
|
+
|
|
98
|
+
assert.match(content, /\[x\]\s+\*\*T01:/, 'complete task should have [x] checkbox');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('renderPlanContent: task with status "done" renders [x] checkbox', () => {
|
|
102
|
+
const slice = makeSliceRow();
|
|
103
|
+
const tasks = [makeTaskRow({ id: 'T01', status: 'done', title: 'Done Task' })];
|
|
104
|
+
|
|
105
|
+
const content = renderPlanContent(slice, tasks);
|
|
106
|
+
|
|
107
|
+
assert.match(content, /\[x\]\s+\*\*T01:/, 'done task should have [x] checkbox');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('renderPlanContent: task with status "pending" renders [ ] checkbox', () => {
|
|
111
|
+
const slice = makeSliceRow();
|
|
112
|
+
const tasks = [makeTaskRow({ id: 'T01', status: 'pending', title: 'Pending Task' })];
|
|
113
|
+
|
|
114
|
+
const content = renderPlanContent(slice, tasks);
|
|
115
|
+
|
|
116
|
+
assert.match(content, /\[ \]\s+\*\*T01:/, 'pending task should have [ ] checkbox');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('renderPlanContent: mixed statuses render correct checkboxes', () => {
|
|
120
|
+
const slice = makeSliceRow();
|
|
121
|
+
const tasks = [
|
|
122
|
+
makeTaskRow({ id: 'T01', status: 'complete', title: 'Done One' }),
|
|
123
|
+
makeTaskRow({ id: 'T02', status: 'pending', title: 'Pending One' }),
|
|
124
|
+
makeTaskRow({ id: 'T03', status: 'done', title: 'Done Two' }),
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
const content = renderPlanContent(slice, tasks);
|
|
128
|
+
|
|
129
|
+
assert.match(content, /\[x\]\s+\*\*T01:/, 'T01 (complete) should be checked');
|
|
130
|
+
assert.match(content, /\[ \]\s+\*\*T02:/, 'T02 (pending) should be unchecked');
|
|
131
|
+
assert.match(content, /\[x\]\s+\*\*T03:/, 'T03 (done) should be checked');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// ─── renderPlanContent: format regression (parsePlan compatibility) ──────
|
|
135
|
+
|
|
136
|
+
test('renderPlanContent: format matches parsePlan regex **ID: title**', () => {
|
|
137
|
+
const slice = makeSliceRow();
|
|
138
|
+
const tasks = [makeTaskRow({ id: 'T01', status: 'pending', title: 'My Task' })];
|
|
139
|
+
|
|
140
|
+
const content = renderPlanContent(slice, tasks);
|
|
141
|
+
|
|
142
|
+
// parsePlan expects: **T01: My Task** (both ID and title inside bold)
|
|
143
|
+
// NOT: **T01:** My Task (only ID in bold)
|
|
144
|
+
assert.match(content, /\*\*T01: My Task\*\*/, 'ID and title should both be inside bold markers');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// ─── renderRoadmapContent: status regression ─────────────────────────────
|
|
148
|
+
|
|
149
|
+
test('renderRoadmapContent: slice with status "complete" shows ✅', () => {
|
|
150
|
+
const milestone = makeMilestoneRow();
|
|
151
|
+
const slices = [makeSliceRow({ id: 'S01', status: 'complete' })];
|
|
152
|
+
|
|
153
|
+
const content = renderRoadmapContent(milestone, slices);
|
|
154
|
+
|
|
155
|
+
assert.ok(content.includes('✅'), 'complete slice should show ✅');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('renderRoadmapContent: slice with status "done" shows ✅', () => {
|
|
159
|
+
const milestone = makeMilestoneRow();
|
|
160
|
+
const slices = [makeSliceRow({ id: 'S01', status: 'done' })];
|
|
161
|
+
|
|
162
|
+
const content = renderRoadmapContent(milestone, slices);
|
|
163
|
+
|
|
164
|
+
assert.ok(content.includes('✅'), 'done slice should show ✅');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('renderRoadmapContent: slice with status "pending" shows ⬜', () => {
|
|
168
|
+
const milestone = makeMilestoneRow();
|
|
169
|
+
const slices = [makeSliceRow({ id: 'S01', status: 'pending' })];
|
|
170
|
+
|
|
171
|
+
const content = renderRoadmapContent(milestone, slices);
|
|
172
|
+
|
|
173
|
+
assert.ok(content.includes('⬜'), 'pending slice should show ⬜');
|
|
174
|
+
});
|
|
@@ -58,17 +58,18 @@ test("guided-resume-task prompt preserves recovery state until work is supersede
|
|
|
58
58
|
assert.doesNotMatch(prompt, /Delete the continue file after reading it/i);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
// ─── Prompt migration: execute-task →
|
|
61
|
+
// ─── Prompt migration: execute-task → gsd_complete_task ───────────────
|
|
62
62
|
|
|
63
|
-
test("execute-task prompt references
|
|
63
|
+
test("execute-task prompt references gsd_complete_task tool", () => {
|
|
64
64
|
const prompt = readPrompt("execute-task");
|
|
65
|
-
assert.match(prompt, /
|
|
65
|
+
assert.match(prompt, /gsd_complete_task/);
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
test("execute-task prompt
|
|
68
|
+
test("execute-task prompt instructs writing task summary before tool call", () => {
|
|
69
69
|
const prompt = readPrompt("execute-task");
|
|
70
|
-
//
|
|
71
|
-
assert.
|
|
70
|
+
// The prompt instructs writing the summary file AND calling the tool
|
|
71
|
+
assert.match(prompt, /\{\{taskSummaryPath\}\}/);
|
|
72
|
+
assert.match(prompt, /gsd_complete_task/);
|
|
72
73
|
});
|
|
73
74
|
|
|
74
75
|
test("execute-task prompt does not instruct LLM to toggle checkboxes manually", () => {
|
|
@@ -93,12 +94,11 @@ test("guided-execute-task prompt does not instruct manual file write", () => {
|
|
|
93
94
|
assert.doesNotMatch(prompt, /Write `?\{\{taskId\}\}-SUMMARY\.md`?.*mark it done/i);
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
// ─── Prompt migration: complete-slice →
|
|
97
|
-
// These tests are for T02 — expected to fail until that task runs.
|
|
97
|
+
// ─── Prompt migration: complete-slice → gsd_complete_slice ────────────
|
|
98
98
|
|
|
99
|
-
test("complete-slice prompt references
|
|
99
|
+
test("complete-slice prompt references gsd_complete_slice tool", () => {
|
|
100
100
|
const prompt = readPrompt("complete-slice");
|
|
101
|
-
assert.match(prompt, /
|
|
101
|
+
assert.match(prompt, /gsd_complete_slice/);
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
test("complete-slice prompt does not instruct LLM to toggle checkboxes manually", () => {
|
|
@@ -111,10 +111,12 @@ test("guided-complete-slice prompt references gsd_slice_complete tool", () => {
|
|
|
111
111
|
assert.match(prompt, /gsd_slice_complete/);
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
test("complete-slice prompt
|
|
114
|
+
test("complete-slice prompt instructs writing summary and UAT files before tool call", () => {
|
|
115
115
|
const prompt = readPrompt("complete-slice");
|
|
116
|
-
|
|
117
|
-
assert.
|
|
116
|
+
// The prompt instructs writing the summary AND UAT files, then calling the tool
|
|
117
|
+
assert.match(prompt, /\{\{sliceSummaryPath\}\}/);
|
|
118
|
+
assert.match(prompt, /\{\{sliceUatPath\}\}/);
|
|
119
|
+
assert.match(prompt, /gsd_complete_slice/);
|
|
118
120
|
});
|
|
119
121
|
|
|
120
122
|
test("complete-slice prompt preserves decisions and knowledge review steps", () => {
|
|
@@ -127,7 +129,6 @@ test("complete-slice prompt still contains template variables for context", () =
|
|
|
127
129
|
const prompt = readPrompt("complete-slice");
|
|
128
130
|
assert.match(prompt, /\{\{sliceSummaryPath\}\}/);
|
|
129
131
|
assert.match(prompt, /\{\{sliceUatPath\}\}/);
|
|
130
|
-
assert.match(prompt, /\{\{roadmapPath\}\}/);
|
|
131
132
|
});
|
|
132
133
|
|
|
133
134
|
test("plan-milestone prompt references DB-backed planning tool and explicitly forbids manual roadmap writes", () => {
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// GSD — reopen-slice handler tests
|
|
2
|
+
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
3
|
+
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import { mkdtempSync, mkdirSync, rmSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
openDatabase,
|
|
12
|
+
closeDatabase,
|
|
13
|
+
insertMilestone,
|
|
14
|
+
insertSlice,
|
|
15
|
+
insertTask,
|
|
16
|
+
getSlice,
|
|
17
|
+
getSliceTasks,
|
|
18
|
+
} from '../gsd-db.ts';
|
|
19
|
+
import { handleReopenSlice } from '../tools/reopen-slice.ts';
|
|
20
|
+
|
|
21
|
+
function makeTmpBase(): string {
|
|
22
|
+
const base = mkdtempSync(join(tmpdir(), 'gsd-reopen-slice-'));
|
|
23
|
+
mkdirSync(join(base, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'tasks'), { recursive: true });
|
|
24
|
+
return base;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function cleanup(base: string): void {
|
|
28
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
29
|
+
try { rmSync(base, { recursive: true, force: true }); } catch { /* noop */ }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function seedCompleteSlice(): void {
|
|
33
|
+
insertMilestone({ id: 'M001', title: 'Test Milestone', status: 'active' });
|
|
34
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', status: 'complete' });
|
|
35
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Task One', status: 'complete' });
|
|
36
|
+
insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', title: 'Task Two', status: 'complete' });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─── Success path ────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
test('handleReopenSlice: resets a complete slice to in_progress and all tasks to pending', async () => {
|
|
42
|
+
const base = makeTmpBase();
|
|
43
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
44
|
+
try {
|
|
45
|
+
seedCompleteSlice();
|
|
46
|
+
|
|
47
|
+
const result = await handleReopenSlice({
|
|
48
|
+
milestoneId: 'M001',
|
|
49
|
+
sliceId: 'S01',
|
|
50
|
+
reason: 'need to redo after requirements change',
|
|
51
|
+
}, base);
|
|
52
|
+
|
|
53
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
54
|
+
assert.equal(result.sliceId, 'S01');
|
|
55
|
+
assert.equal(result.tasksReset, 2, 'should report 2 tasks reset');
|
|
56
|
+
|
|
57
|
+
const slice = getSlice('M001', 'S01');
|
|
58
|
+
assert.ok(slice, 'slice should still exist');
|
|
59
|
+
assert.equal(slice!.status, 'in_progress', 'slice status should be in_progress');
|
|
60
|
+
|
|
61
|
+
const tasks = getSliceTasks('M001', 'S01');
|
|
62
|
+
assert.equal(tasks.length, 2, 'both tasks should still exist');
|
|
63
|
+
assert.ok(tasks.every(t => t.status === 'pending'), 'all tasks should be pending');
|
|
64
|
+
} finally {
|
|
65
|
+
cleanup(base);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('handleReopenSlice: works with a single task', async () => {
|
|
70
|
+
const base = makeTmpBase();
|
|
71
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
72
|
+
try {
|
|
73
|
+
insertMilestone({ id: 'M001', title: 'Test', status: 'active' });
|
|
74
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', status: 'complete' });
|
|
75
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete' });
|
|
76
|
+
|
|
77
|
+
const result = await handleReopenSlice({ milestoneId: 'M001', sliceId: 'S01' }, base);
|
|
78
|
+
|
|
79
|
+
assert.ok(!('error' in result));
|
|
80
|
+
assert.equal(result.tasksReset, 1);
|
|
81
|
+
} finally {
|
|
82
|
+
cleanup(base);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// ─── Failure paths ───────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
test('handleReopenSlice: rejects empty sliceId', async () => {
|
|
89
|
+
const base = makeTmpBase();
|
|
90
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
91
|
+
try {
|
|
92
|
+
const result = await handleReopenSlice({ milestoneId: 'M001', sliceId: '' }, base);
|
|
93
|
+
assert.ok('error' in result);
|
|
94
|
+
assert.match(result.error, /sliceId/);
|
|
95
|
+
} finally {
|
|
96
|
+
cleanup(base);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('handleReopenSlice: rejects non-existent milestone', async () => {
|
|
101
|
+
const base = makeTmpBase();
|
|
102
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
103
|
+
try {
|
|
104
|
+
const result = await handleReopenSlice({ milestoneId: 'M999', sliceId: 'S01' }, base);
|
|
105
|
+
assert.ok('error' in result);
|
|
106
|
+
assert.match(result.error, /milestone not found/);
|
|
107
|
+
} finally {
|
|
108
|
+
cleanup(base);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('handleReopenSlice: rejects slice in a closed milestone', async () => {
|
|
113
|
+
const base = makeTmpBase();
|
|
114
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
115
|
+
try {
|
|
116
|
+
insertMilestone({ id: 'M001', title: 'Done', status: 'complete' });
|
|
117
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', status: 'complete' });
|
|
118
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete' });
|
|
119
|
+
|
|
120
|
+
const result = await handleReopenSlice({ milestoneId: 'M001', sliceId: 'S01' }, base);
|
|
121
|
+
assert.ok('error' in result);
|
|
122
|
+
assert.match(result.error, /closed milestone/);
|
|
123
|
+
} finally {
|
|
124
|
+
cleanup(base);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('handleReopenSlice: rejects reopening a slice that is not complete', async () => {
|
|
129
|
+
const base = makeTmpBase();
|
|
130
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
131
|
+
try {
|
|
132
|
+
insertMilestone({ id: 'M001', title: 'Active', status: 'active' });
|
|
133
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', status: 'in_progress' });
|
|
134
|
+
|
|
135
|
+
const result = await handleReopenSlice({ milestoneId: 'M001', sliceId: 'S01' }, base);
|
|
136
|
+
assert.ok('error' in result);
|
|
137
|
+
assert.match(result.error, /not complete/);
|
|
138
|
+
} finally {
|
|
139
|
+
cleanup(base);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('handleReopenSlice: rejects non-existent slice', async () => {
|
|
144
|
+
const base = makeTmpBase();
|
|
145
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
146
|
+
try {
|
|
147
|
+
insertMilestone({ id: 'M001', title: 'Active', status: 'active' });
|
|
148
|
+
|
|
149
|
+
const result = await handleReopenSlice({ milestoneId: 'M001', sliceId: 'S99' }, base);
|
|
150
|
+
assert.ok('error' in result);
|
|
151
|
+
assert.match(result.error, /slice not found/);
|
|
152
|
+
} finally {
|
|
153
|
+
cleanup(base);
|
|
154
|
+
}
|
|
155
|
+
});
|