gsd-pi 2.48.0 → 2.49.0-dev.9e177e9
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/headless-ui.js +12 -2
- package/dist/headless.js +29 -13
- package/dist/resources/extensions/gsd/auto/infra-errors.js +1 -0
- package/dist/resources/extensions/gsd/auto/phases.js +11 -11
- package/dist/resources/extensions/gsd/auto/resolve.js +2 -2
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +8 -10
- package/dist/resources/extensions/gsd/auto-dashboard.js +6 -3
- package/dist/resources/extensions/gsd/auto-dispatch.js +34 -7
- package/dist/resources/extensions/gsd/auto-post-unit.js +34 -27
- package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +62 -184
- package/dist/resources/extensions/gsd/auto-start.js +4 -31
- package/dist/resources/extensions/gsd/auto-timers.js +2 -2
- package/dist/resources/extensions/gsd/auto-verification.js +4 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +262 -115
- package/dist/resources/extensions/gsd/auto.js +7 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -1
- package/dist/resources/extensions/gsd/branch-patterns.js +13 -0
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +43 -3
- package/dist/resources/extensions/gsd/doctor-checks.js +5 -1234
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +168 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +28 -7
- package/dist/resources/extensions/gsd/doctor-git-checks.js +405 -0
- package/dist/resources/extensions/gsd/doctor-global-checks.js +74 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +600 -0
- package/dist/resources/extensions/gsd/doctor.js +9 -1
- package/dist/resources/extensions/gsd/extension-manifest.json +1 -1
- package/dist/resources/extensions/gsd/git-service.js +20 -20
- package/dist/resources/extensions/gsd/gsd-db.js +124 -1
- package/dist/resources/extensions/gsd/guided-flow-queue.js +10 -11
- package/dist/resources/extensions/gsd/markdown-renderer.js +33 -5
- package/dist/resources/extensions/gsd/preferences-types.js +2 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +9 -8
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +223 -56
- package/dist/resources/extensions/gsd/prompts/execute-task.md +16 -13
- package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +8 -3
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +4 -4
- package/dist/resources/extensions/gsd/repo-identity.js +29 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +2 -2
- package/dist/resources/extensions/gsd/session-forensics.js +6 -11
- package/dist/resources/extensions/gsd/session-lock.js +67 -56
- package/dist/resources/extensions/gsd/state.js +34 -7
- package/dist/resources/extensions/gsd/templates/milestone-summary.md +8 -0
- package/dist/resources/extensions/gsd/templates/plan.md +16 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +13 -0
- package/dist/resources/extensions/gsd/templates/slice-summary.md +9 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +24 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -3
- package/dist/resources/extensions/gsd/verdict-parser.js +84 -0
- package/dist/resources/extensions/gsd/worktree-command.js +1 -1
- package/dist/resources/extensions/gsd/worktree-resolver.js +24 -0
- package/dist/resources/extensions/gsd/worktree.js +3 -2
- package/dist/resources/extensions/remote-questions/config.js +3 -5
- package/dist/resources/extensions/search-the-web/native-search.js +8 -3
- package/dist/resources/extensions/search-the-web/tool-search.js +19 -2
- package/dist/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
- 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 +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +4 -4
- 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 +2 -2
- 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-react-loadable-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/4024.7c75ac378de0f2b5.js +9 -0
- 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/.next/static/chunks/{webpack-0a4cd455ec4197d2.js → webpack-2473ce2c3879fff4.js} +1 -1
- 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/dist/worktree-cli.js +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +39 -10
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +39 -8
- package/packages/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/blob-store.js +8 -3
- package/packages/pi-coding-agent/dist/core/blob-store.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.js +9 -2
- package/packages/pi-coding-agent/dist/core/discovery-cache.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -32
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js +5 -0
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +0 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/blob-store.ts +6 -3
- package/packages/pi-coding-agent/src/core/discovery-cache.ts +9 -2
- package/packages/pi-coding-agent/src/core/retry-handler.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +7 -32
- package/packages/pi-coding-agent/src/modes/rpc/jsonl.ts +6 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +0 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +8 -4
- package/src/resources/extensions/gsd/auto/infra-errors.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +10 -11
- package/src/resources/extensions/gsd/auto/resolve.ts +3 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -2
- package/src/resources/extensions/gsd/auto/session.ts +5 -0
- package/src/resources/extensions/gsd/auto/types.ts +13 -0
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +19 -21
- package/src/resources/extensions/gsd/auto-dashboard.ts +5 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +40 -5
- package/src/resources/extensions/gsd/auto-loop.ts +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +36 -31
- package/src/resources/extensions/gsd/auto-prompts.ts +113 -19
- package/src/resources/extensions/gsd/auto-recovery.ts +65 -199
- package/src/resources/extensions/gsd/auto-start.ts +7 -27
- package/src/resources/extensions/gsd/auto-timers.ts +2 -2
- package/src/resources/extensions/gsd/auto-verification.ts +4 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +309 -110
- package/src/resources/extensions/gsd/auto.ts +11 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +93 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
- package/src/resources/extensions/gsd/branch-patterns.ts +16 -0
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +46 -3
- package/src/resources/extensions/gsd/doctor-checks.ts +5 -1291
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +182 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +30 -7
- package/src/resources/extensions/gsd/doctor-git-checks.ts +415 -0
- package/src/resources/extensions/gsd/doctor-global-checks.ts +84 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +626 -0
- package/src/resources/extensions/gsd/doctor.ts +9 -1
- package/src/resources/extensions/gsd/extension-manifest.json +1 -1
- package/src/resources/extensions/gsd/git-service.ts +19 -26
- package/src/resources/extensions/gsd/gsd-db.ts +150 -2
- package/src/resources/extensions/gsd/guided-flow-queue.ts +11 -12
- package/src/resources/extensions/gsd/markdown-renderer.ts +37 -4
- package/src/resources/extensions/gsd/preferences-types.ts +5 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +37 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
- package/src/resources/extensions/gsd/prompts/complete-slice.md +9 -8
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +223 -56
- package/src/resources/extensions/gsd/prompts/execute-task.md +16 -13
- package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +8 -3
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +4 -4
- package/src/resources/extensions/gsd/repo-identity.ts +28 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +2 -2
- package/src/resources/extensions/gsd/session-forensics.ts +6 -11
- package/src/resources/extensions/gsd/session-lock.ts +92 -64
- package/src/resources/extensions/gsd/state.ts +38 -5
- package/src/resources/extensions/gsd/templates/milestone-summary.md +8 -0
- package/src/resources/extensions/gsd/templates/plan.md +16 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +13 -0
- package/src/resources/extensions/gsd/templates/slice-summary.md +9 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +24 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +1 -81
- package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +14 -12
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +9 -12
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +115 -1
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +65 -1
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +68 -9
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +39 -0
- 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/milestone-transition-worktree.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/quality-gates.test.ts +347 -0
- package/src/resources/extensions/gsd/tests/queue-completed-milestone-perf.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +87 -15
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +44 -4
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +0 -16
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +204 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +16 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +3 -3
- package/src/resources/extensions/gsd/types.ts +30 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +95 -0
- package/src/resources/extensions/gsd/verification-gate.ts +0 -2
- package/src/resources/extensions/gsd/worktree-command.ts +1 -1
- package/src/resources/extensions/gsd/worktree-resolver.ts +31 -0
- package/src/resources/extensions/gsd/worktree.ts +3 -2
- package/src/resources/extensions/remote-questions/config.ts +3 -5
- package/src/resources/extensions/search-the-web/native-search.ts +8 -3
- package/src/resources/extensions/search-the-web/tool-search.ts +22 -2
- package/src/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -191
- package/dist/resources/extensions/gsd/resource-version.js +0 -97
- package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +0 -9
- 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/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -234
- package/src/resources/extensions/gsd/resource-version.ts +0 -101
- /package/dist/web/standalone/.next/static/{zGWUKFTfjCQerNgsPpAbF → vNN0h0emdEi8l_npi8poE}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zGWUKFTfjCQerNgsPpAbF → vNN0h0emdEi8l_npi8poE}/_ssgManifest.js +0 -0
|
@@ -160,15 +160,17 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
160
160
|
|
|
161
161
|
const result = mergeMilestoneToMain(repo, "M020", roadmap);
|
|
162
162
|
|
|
163
|
-
assert.match(result.commitMessage, /^feat
|
|
163
|
+
assert.match(result.commitMessage, /^feat:/, "subject has conventional commit prefix without milestone ID");
|
|
164
164
|
assert.ok(result.commitMessage.includes("Backend foundation"), "subject includes milestone title");
|
|
165
165
|
assert.ok(result.commitMessage.includes("- S01: Core API"), "body lists S01");
|
|
166
166
|
assert.ok(result.commitMessage.includes("- S02: Error handling"), "body lists S02");
|
|
167
167
|
assert.ok(result.commitMessage.includes("- S03: Logging infra"), "body lists S03");
|
|
168
|
+
assert.ok(result.commitMessage.includes("GSD-Milestone: M020"), "body has GSD-Milestone trailer");
|
|
168
169
|
assert.ok(result.commitMessage.includes("Branch: milestone/M020"), "body has branch metadata");
|
|
169
170
|
|
|
170
171
|
const gitMsg = run("git log -1 --format=%B main", repo).trim();
|
|
171
|
-
assert.match(gitMsg, /^feat
|
|
172
|
+
assert.match(gitMsg, /^feat:/, "git commit message starts with feat:");
|
|
173
|
+
assert.ok(gitMsg.includes("GSD-Milestone: M020"), "git commit has GSD-Milestone trailer");
|
|
172
174
|
assert.ok(gitMsg.includes("- S01: Core API"), "git commit body has S01");
|
|
173
175
|
});
|
|
174
176
|
|
|
@@ -213,11 +215,11 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
213
215
|
const result = mergeMilestoneToMain(repo, "M040", roadmap);
|
|
214
216
|
|
|
215
217
|
const mainLog = run("git log --oneline main", repo);
|
|
216
|
-
assert.ok(mainLog.includes("feat
|
|
218
|
+
assert.ok(mainLog.includes("feat:"), "milestone commit on main");
|
|
217
219
|
|
|
218
220
|
run("git push origin main", repo);
|
|
219
221
|
const remoteLog = run("git log --oneline main", bareDir);
|
|
220
|
-
assert.ok(remoteLog.includes("feat
|
|
222
|
+
assert.ok(remoteLog.includes("feat:"), "milestone commit reachable on remote after manual push");
|
|
221
223
|
|
|
222
224
|
assert.strictEqual(typeof result.pushed, "boolean", "pushed flag remains boolean");
|
|
223
225
|
});
|
|
@@ -248,7 +250,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
248
250
|
let threw = false;
|
|
249
251
|
try {
|
|
250
252
|
const result = mergeMilestoneToMain(repo, "M050", roadmap);
|
|
251
|
-
assert.ok(result.commitMessage.includes("feat(M050
|
|
253
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M050"), "merge commit created despite .gsd conflict");
|
|
252
254
|
} catch (err) {
|
|
253
255
|
threw = true;
|
|
254
256
|
}
|
|
@@ -274,7 +276,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
274
276
|
let threw = false;
|
|
275
277
|
try {
|
|
276
278
|
const result = mergeMilestoneToMain(repo, "M060", roadmap);
|
|
277
|
-
assert.ok(result.commitMessage.includes("feat(M060
|
|
279
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M060"), "merge commit created");
|
|
278
280
|
} catch (err) {
|
|
279
281
|
threw = true;
|
|
280
282
|
}
|
|
@@ -312,7 +314,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
312
314
|
let errMsg = "";
|
|
313
315
|
try {
|
|
314
316
|
const result = mergeMilestoneToMain(dir, "M070", roadmap);
|
|
315
|
-
assert.ok(result.commitMessage.includes("feat(M070
|
|
317
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M070"), "merge commit created on master");
|
|
316
318
|
} catch (err) {
|
|
317
319
|
threw = true;
|
|
318
320
|
errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -392,7 +394,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
392
394
|
let threw = false;
|
|
393
395
|
try {
|
|
394
396
|
const result = mergeMilestoneToMain(repo, "M090", roadmap);
|
|
395
|
-
assert.ok(result.commitMessage.includes("feat(M090
|
|
397
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M090"), "#1738 merge succeeds after cleaning synced dirs");
|
|
396
398
|
} catch (err: unknown) {
|
|
397
399
|
threw = true;
|
|
398
400
|
}
|
|
@@ -419,7 +421,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
419
421
|
let threw = false;
|
|
420
422
|
try {
|
|
421
423
|
const result = mergeMilestoneToMain(repo, "M100", roadmap);
|
|
422
|
-
assert.ok(result.commitMessage.includes("feat(M100
|
|
424
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M100"), "#2151: merge succeeds after stashing dirty files");
|
|
423
425
|
} catch {
|
|
424
426
|
threw = true;
|
|
425
427
|
}
|
|
@@ -519,7 +521,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
519
521
|
let errMsg = "";
|
|
520
522
|
try {
|
|
521
523
|
const result = mergeMilestoneToMain(repo, "M140", roadmap);
|
|
522
|
-
assert.ok(result.commitMessage.includes("feat(M140
|
|
524
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M140"), "merge commit created");
|
|
523
525
|
} catch (err) {
|
|
524
526
|
threw = true;
|
|
525
527
|
errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -589,7 +591,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
589
591
|
assert.ok(existsSync(squashMsgPath), "SQUASH_MSG planted before merge");
|
|
590
592
|
|
|
591
593
|
const result = mergeMilestoneToMain(repo, "M160", roadmap);
|
|
592
|
-
assert.ok(result.commitMessage.includes("feat(M160
|
|
594
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M160"), "merge commit created");
|
|
593
595
|
|
|
594
596
|
assert.ok(!existsSync(squashMsgPath), "#1853: SQUASH_MSG must not persist after successful squash-merge");
|
|
595
597
|
});
|
|
@@ -609,7 +611,7 @@ describe("auto-worktree-milestone-merge", () => {
|
|
|
609
611
|
]);
|
|
610
612
|
|
|
611
613
|
const result = mergeMilestoneToMain(repo, "M170", roadmap);
|
|
612
|
-
assert.ok(result.commitMessage.includes("feat(M170
|
|
614
|
+
assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M170"), "merge commit created");
|
|
613
615
|
|
|
614
616
|
assert.ok(
|
|
615
617
|
existsSync(join(repo, "uncommitted-agent-code.ts")),
|
|
@@ -125,9 +125,9 @@ console.log('\n=== complete-slice: schema v6 migration ===');
|
|
|
125
125
|
|
|
126
126
|
const adapter = _getAdapter()!;
|
|
127
127
|
|
|
128
|
-
// Verify schema version is current (
|
|
128
|
+
// Verify schema version is current (v12 after quality gates table)
|
|
129
129
|
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
130
|
-
assertEq(versionRow?.['v'],
|
|
130
|
+
assertEq(versionRow?.['v'], 12, 'schema version should be 12');
|
|
131
131
|
|
|
132
132
|
// Verify slices table has full_summary_md and full_uat_md columns
|
|
133
133
|
const cols = adapter.prepare("PRAGMA table_info(slices)").all();
|
|
@@ -109,9 +109,9 @@ console.log('\n=== complete-task: schema v5 migration ===');
|
|
|
109
109
|
|
|
110
110
|
const adapter = _getAdapter()!;
|
|
111
111
|
|
|
112
|
-
// Verify schema version is current (
|
|
112
|
+
// Verify schema version is current (v12 after quality gates table)
|
|
113
113
|
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
114
|
-
assertEq(versionRow?.['v'],
|
|
114
|
+
assertEq(versionRow?.['v'], 12, 'schema version should be 12');
|
|
115
115
|
|
|
116
116
|
// Verify all 4 new tables exist
|
|
117
117
|
const tables = adapter.prepare(
|
|
@@ -48,35 +48,32 @@ test("#2313: completed-units.json should not be blindly wiped to [] on milestone
|
|
|
48
48
|
// ─── Bug 2: metrics.json should be in the sync file lists ──────────────────
|
|
49
49
|
|
|
50
50
|
test("#2313: syncStateToProjectRoot should sync metrics.json", () => {
|
|
51
|
-
const syncSrcPath = join(import.meta.dirname, "..", "auto-worktree
|
|
51
|
+
const syncSrcPath = join(import.meta.dirname, "..", "auto-worktree.ts");
|
|
52
52
|
const syncSrc = readFileSync(syncSrcPath, "utf-8");
|
|
53
53
|
|
|
54
54
|
// syncStateToProjectRoot should copy metrics.json from worktree to project root
|
|
55
55
|
assert.ok(
|
|
56
56
|
syncSrc.includes("metrics.json"),
|
|
57
|
-
"auto-worktree
|
|
57
|
+
"auto-worktree.ts should reference metrics.json for sync",
|
|
58
58
|
);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
test("#2313: syncWorktreeStateBack should include metrics.json in
|
|
61
|
+
test("#2313: syncWorktreeStateBack should include metrics.json in ROOT_STATE_FILES", () => {
|
|
62
62
|
const autoWorktreeSrcPath = join(import.meta.dirname, "..", "auto-worktree.ts");
|
|
63
63
|
const autoWorktreeSrc = readFileSync(autoWorktreeSrcPath, "utf-8");
|
|
64
64
|
|
|
65
|
-
// Find the
|
|
66
|
-
const
|
|
67
|
-
assert.ok(
|
|
65
|
+
// Find the ROOT_STATE_FILES constant (single source of truth for both sync directions)
|
|
66
|
+
const constIdx = autoWorktreeSrc.indexOf("ROOT_STATE_FILES");
|
|
67
|
+
assert.ok(constIdx !== -1, "ROOT_STATE_FILES constant exists");
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// Get the rootFiles array content
|
|
73
|
-
const arrayStart = autoWorktreeSrc.indexOf("[", rootFilesIdx);
|
|
69
|
+
// Get the array content
|
|
70
|
+
const arrayStart = autoWorktreeSrc.indexOf("[", constIdx);
|
|
74
71
|
const arrayEnd = autoWorktreeSrc.indexOf("]", arrayStart);
|
|
75
72
|
const rootFilesBlock = autoWorktreeSrc.slice(arrayStart, arrayEnd);
|
|
76
73
|
|
|
77
74
|
assert.ok(
|
|
78
75
|
rootFilesBlock.includes("metrics.json"),
|
|
79
|
-
"metrics.json should be in
|
|
76
|
+
"metrics.json should be in ROOT_STATE_FILES list",
|
|
80
77
|
);
|
|
81
78
|
});
|
|
82
79
|
|
|
@@ -15,7 +15,7 @@ import assert from 'node:assert/strict';
|
|
|
15
15
|
* - Report formatting
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
18
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, utimesSync } from "node:fs";
|
|
19
19
|
import { join, dirname } from "node:path";
|
|
20
20
|
import { tmpdir } from "node:os";
|
|
21
21
|
|
|
@@ -102,6 +102,120 @@ describe('doctor-environment', async () => {
|
|
|
102
102
|
assert.deepStrictEqual(depsCheck!.status, "ok", "existing node_modules is ok");
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
+
// ── Stale Dependencies: marker file check (#1974) ──────────────────
|
|
106
|
+
console.log("\n=== env: npm marker file newer than lockfile → ok (#1974) ===");
|
|
107
|
+
{
|
|
108
|
+
// Simulate the exact bug scenario:
|
|
109
|
+
// 1. node_modules dir mtime is old (no entries added/removed recently)
|
|
110
|
+
// 2. package-lock.json mtime is recent (npm rewrote it)
|
|
111
|
+
// 3. node_modules/.package-lock.json mtime is between dir and lockfile
|
|
112
|
+
// (npm wrote it during the same install that rewrote the lockfile)
|
|
113
|
+
//
|
|
114
|
+
// The bug: code compares lockfile mtime vs dir mtime → false positive warning
|
|
115
|
+
// The fix: compare lockfile mtime vs marker file mtime → correctly ok
|
|
116
|
+
const dir = createProjectDir({
|
|
117
|
+
"package.json": JSON.stringify({ name: "test" }),
|
|
118
|
+
});
|
|
119
|
+
mkdirSync(join(dir, "node_modules"), { recursive: true });
|
|
120
|
+
|
|
121
|
+
// Simulate the exact bug: npm install with "up to date" rewrites the
|
|
122
|
+
// lockfile and the marker, but no packages are added/removed so the
|
|
123
|
+
// directory mtime should be old. We write the marker first (which
|
|
124
|
+
// bumps dir mtime), then force the dir mtime back to the past.
|
|
125
|
+
//
|
|
126
|
+
// Timeline: dir(T-120s) < lockfile(T-5s) ≈ marker(T-5s)
|
|
127
|
+
// Bug: code compares lockfile vs dir → false positive stale warning
|
|
128
|
+
// Fix: code compares lockfile vs marker → correctly reports ok
|
|
129
|
+
const dirTime = new Date(Date.now() - 120_000);
|
|
130
|
+
const installTime = new Date(Date.now() - 5_000);
|
|
131
|
+
|
|
132
|
+
// Write marker file (this bumps dir mtime as a side effect)
|
|
133
|
+
writeFileSync(join(dir, "node_modules", ".package-lock.json"), "{}");
|
|
134
|
+
utimesSync(join(dir, "node_modules", ".package-lock.json"), installTime, installTime);
|
|
135
|
+
|
|
136
|
+
// Force dir mtime back to the past — simulates no top-level entries changed
|
|
137
|
+
utimesSync(join(dir, "node_modules"), dirTime, dirTime);
|
|
138
|
+
|
|
139
|
+
// Lockfile written at install time (same as marker, or slightly after)
|
|
140
|
+
writeFileSync(join(dir, "package-lock.json"), "{}");
|
|
141
|
+
utimesSync(join(dir, "package-lock.json"), installTime, installTime);
|
|
142
|
+
|
|
143
|
+
cleanups.push(dir);
|
|
144
|
+
const results = runEnvironmentChecks(dir);
|
|
145
|
+
const depsCheck = results.find(r => r.name === "dependencies");
|
|
146
|
+
assert.ok(depsCheck !== undefined, "dependencies check runs");
|
|
147
|
+
assert.equal(depsCheck!.status, "ok", "npm marker newer than lockfile → not stale");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
console.log("\n=== env: yarn marker file newer than lockfile → ok (#1974) ===");
|
|
151
|
+
{
|
|
152
|
+
const dir = createProjectDir({
|
|
153
|
+
"package.json": JSON.stringify({ name: "test" }),
|
|
154
|
+
});
|
|
155
|
+
mkdirSync(join(dir, "node_modules"), { recursive: true });
|
|
156
|
+
|
|
157
|
+
const dirTime = new Date(Date.now() - 120_000);
|
|
158
|
+
const installTime = new Date(Date.now() - 5_000);
|
|
159
|
+
|
|
160
|
+
writeFileSync(join(dir, "node_modules", ".yarn-integrity"), "{}");
|
|
161
|
+
utimesSync(join(dir, "node_modules", ".yarn-integrity"), installTime, installTime);
|
|
162
|
+
utimesSync(join(dir, "node_modules"), dirTime, dirTime);
|
|
163
|
+
|
|
164
|
+
writeFileSync(join(dir, "yarn.lock"), "");
|
|
165
|
+
utimesSync(join(dir, "yarn.lock"), installTime, installTime);
|
|
166
|
+
|
|
167
|
+
cleanups.push(dir);
|
|
168
|
+
const results = runEnvironmentChecks(dir);
|
|
169
|
+
const depsCheck = results.find(r => r.name === "dependencies");
|
|
170
|
+
assert.ok(depsCheck !== undefined, "dependencies check runs");
|
|
171
|
+
assert.equal(depsCheck!.status, "ok", "yarn marker newer than lockfile → not stale");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log("\n=== env: pnpm marker file newer than lockfile → ok (#1974) ===");
|
|
175
|
+
{
|
|
176
|
+
const dir = createProjectDir({
|
|
177
|
+
"package.json": JSON.stringify({ name: "test" }),
|
|
178
|
+
});
|
|
179
|
+
mkdirSync(join(dir, "node_modules"), { recursive: true });
|
|
180
|
+
|
|
181
|
+
const dirTime = new Date(Date.now() - 120_000);
|
|
182
|
+
const installTime = new Date(Date.now() - 5_000);
|
|
183
|
+
|
|
184
|
+
writeFileSync(join(dir, "node_modules", ".modules.yaml"), "{}");
|
|
185
|
+
utimesSync(join(dir, "node_modules", ".modules.yaml"), installTime, installTime);
|
|
186
|
+
utimesSync(join(dir, "node_modules"), dirTime, dirTime);
|
|
187
|
+
|
|
188
|
+
writeFileSync(join(dir, "pnpm-lock.yaml"), "");
|
|
189
|
+
utimesSync(join(dir, "pnpm-lock.yaml"), installTime, installTime);
|
|
190
|
+
|
|
191
|
+
cleanups.push(dir);
|
|
192
|
+
const results = runEnvironmentChecks(dir);
|
|
193
|
+
const depsCheck = results.find(r => r.name === "dependencies");
|
|
194
|
+
assert.ok(depsCheck !== undefined, "dependencies check runs");
|
|
195
|
+
assert.equal(depsCheck!.status, "ok", "pnpm marker newer than lockfile → not stale");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
console.log("\n=== env: no marker file falls back to dir mtime → stale warning (#1974) ===");
|
|
199
|
+
{
|
|
200
|
+
// No marker file exists, lockfile newer than dir → should still warn
|
|
201
|
+
const dir = createProjectDir({
|
|
202
|
+
"package.json": JSON.stringify({ name: "test" }),
|
|
203
|
+
});
|
|
204
|
+
mkdirSync(join(dir, "node_modules"), { recursive: true });
|
|
205
|
+
|
|
206
|
+
const past = new Date(Date.now() - 60_000);
|
|
207
|
+
utimesSync(join(dir, "node_modules"), past, past);
|
|
208
|
+
|
|
209
|
+
writeFileSync(join(dir, "package-lock.json"), "{}");
|
|
210
|
+
// No marker file written — fallback to dir mtime comparison
|
|
211
|
+
|
|
212
|
+
cleanups.push(dir);
|
|
213
|
+
const results = runEnvironmentChecks(dir);
|
|
214
|
+
const depsCheck = results.find(r => r.name === "dependencies");
|
|
215
|
+
assert.ok(depsCheck !== undefined, "dependencies check runs");
|
|
216
|
+
assert.equal(depsCheck!.status, "warning", "no marker + lockfile newer → stale warning");
|
|
217
|
+
}
|
|
218
|
+
|
|
105
219
|
// ── Env File Check ─────────────────────────────────────────────────
|
|
106
220
|
test('env: .env.example without .env detected', () => {
|
|
107
221
|
const dir = createProjectDir({
|
|
@@ -15,6 +15,7 @@ import { tmpdir } from "node:os";
|
|
|
15
15
|
import test from "node:test";
|
|
16
16
|
import assert from "node:assert/strict";
|
|
17
17
|
import { runGSDDoctor } from "../doctor.ts";
|
|
18
|
+
import { closeDatabase } from "../gsd-db.ts";
|
|
18
19
|
|
|
19
20
|
function makeTmp(name: string): string {
|
|
20
21
|
const dir = join(tmpdir(), `doctor-fixlevel-${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -112,6 +113,70 @@ test("fixLevel:all — no reconciliation issue codes are reported", async (t) =>
|
|
|
112
113
|
assert.ok(roadmapContent.includes("- [ ] **S01"), "roadmap should remain unchecked");
|
|
113
114
|
});
|
|
114
115
|
|
|
116
|
+
test("legacy roadmap fallback: future slices are treated as pending, active slice is not", async (t) => {
|
|
117
|
+
const tmp = makeTmp("legacy-pending-fallback");
|
|
118
|
+
t.after(() => {
|
|
119
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
120
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Force the legacy parser branch.
|
|
124
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
125
|
+
|
|
126
|
+
const gsd = join(tmp, ".gsd");
|
|
127
|
+
const m = join(gsd, "milestones", "M001");
|
|
128
|
+
const s01 = join(m, "slices", "S01", "tasks");
|
|
129
|
+
mkdirSync(s01, { recursive: true });
|
|
130
|
+
|
|
131
|
+
writeFileSync(join(m, "M001-ROADMAP.md"), `# M001: Test
|
|
132
|
+
|
|
133
|
+
## Slices
|
|
134
|
+
|
|
135
|
+
- [x] **S01: Done Slice** \`risk:low\` \`depends:[]\`
|
|
136
|
+
> Done
|
|
137
|
+
- [ ] **S02: Active Slice** \`risk:medium\` \`depends:[S01]\`
|
|
138
|
+
> In progress
|
|
139
|
+
- [ ] **S03: Future Slice** \`risk:low\` \`depends:[S02]\`
|
|
140
|
+
> Later
|
|
141
|
+
- [ ] **S04: Future Slice Two** \`risk:low\` \`depends:[S03]\`
|
|
142
|
+
> Later
|
|
143
|
+
`);
|
|
144
|
+
|
|
145
|
+
writeFileSync(join(m, "slices", "S01", "S01-PLAN.md"), `# S01: Done Slice
|
|
146
|
+
|
|
147
|
+
**Goal:** done
|
|
148
|
+
|
|
149
|
+
## Tasks
|
|
150
|
+
|
|
151
|
+
- [x] **T01: Done task** \`est:5m\`
|
|
152
|
+
`);
|
|
153
|
+
|
|
154
|
+
// Active slice exists in state/registry but has no directory yet — this should
|
|
155
|
+
// still be reported as a real error, while future untouched slices should be skipped.
|
|
156
|
+
const report = await runGSDDoctor(tmp, { scope: "M001" });
|
|
157
|
+
const missingSliceDirUnits = report.issues
|
|
158
|
+
.filter(i => i.code === "missing_slice_dir")
|
|
159
|
+
.map(i => i.unitId)
|
|
160
|
+
.sort();
|
|
161
|
+
|
|
162
|
+
assert.deepStrictEqual(
|
|
163
|
+
missingSliceDirUnits,
|
|
164
|
+
["M001/S02"],
|
|
165
|
+
"legacy fallback should only report the active slice, not future unstarted slices",
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const missingTasksDirUnits = report.issues
|
|
169
|
+
.filter(i => i.code === "missing_tasks_dir")
|
|
170
|
+
.map(i => i.unitId)
|
|
171
|
+
.sort();
|
|
172
|
+
|
|
173
|
+
assert.deepStrictEqual(
|
|
174
|
+
missingTasksDirUnits,
|
|
175
|
+
[],
|
|
176
|
+
"future slices without directories should be skipped before missing_tasks_dir checks",
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
115
180
|
test("fixLevel:all — delimiter_in_title still fixable", async (t) => {
|
|
116
181
|
const tmp = makeTmp("delimiter-fix");
|
|
117
182
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
@@ -141,7 +206,6 @@ test("fixLevel:all — delimiter_in_title still fixable", async (t) => {
|
|
|
141
206
|
|
|
142
207
|
const report = await runGSDDoctor(tmp, { fix: true });
|
|
143
208
|
|
|
144
|
-
const delimiterIssues = report.issues.filter(i => i.code === "delimiter_in_title");
|
|
145
209
|
// The milestone-level delimiter is auto-fixed, but the report may or may not include it
|
|
146
210
|
// depending on whether it was fixed successfully. Just verify it ran without crashing.
|
|
147
211
|
assert.ok(report.issues !== undefined, "doctor produces a report");
|
|
@@ -145,6 +145,56 @@ describe('doctor-git', async () => {
|
|
|
145
145
|
} else {
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// ─── Test 1b: Orphaned worktree fix when cwd is inside worktree (#1946) ──
|
|
149
|
+
// Reproduces the deadlock: if process.cwd() is inside the orphaned worktree,
|
|
150
|
+
// the doctor must chdir out before removing it — not skip the removal.
|
|
151
|
+
if (process.platform !== "win32") {
|
|
152
|
+
console.log("\n=== orphaned_auto_worktree (cwd inside worktree) ===");
|
|
153
|
+
{
|
|
154
|
+
const dir = createRepoWithCompletedMilestone();
|
|
155
|
+
cleanups.push(dir);
|
|
156
|
+
|
|
157
|
+
// Create worktree with milestone/M001 branch under .gsd/worktrees/
|
|
158
|
+
mkdirSync(join(dir, ".gsd", "worktrees"), { recursive: true });
|
|
159
|
+
run("git worktree add -b milestone/M001 .gsd/worktrees/M001", dir);
|
|
160
|
+
|
|
161
|
+
const wtPath = realpathSync(join(dir, ".gsd", "worktrees", "M001"));
|
|
162
|
+
|
|
163
|
+
// Simulate the deadlock: set cwd inside the orphaned worktree
|
|
164
|
+
const previousCwd = process.cwd();
|
|
165
|
+
process.chdir(wtPath);
|
|
166
|
+
try {
|
|
167
|
+
const fixed = await runGSDDoctor(dir, { fix: true, isolationMode: "worktree" });
|
|
168
|
+
|
|
169
|
+
// The fix must NOT skip removal — it should chdir out and remove
|
|
170
|
+
assert.ok(
|
|
171
|
+
!fixed.fixesApplied.some(f => f.includes("skipped removing worktree")),
|
|
172
|
+
"does NOT skip removal when cwd is inside worktree",
|
|
173
|
+
);
|
|
174
|
+
assert.ok(
|
|
175
|
+
fixed.fixesApplied.some(f => f.includes("removed orphaned worktree")),
|
|
176
|
+
"removes orphaned worktree even when cwd was inside it",
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Verify worktree is gone
|
|
180
|
+
const wtList = run("git worktree list", dir);
|
|
181
|
+
assert.ok(!wtList.includes("milestone/M001"), "worktree removed after fix with cwd inside");
|
|
182
|
+
|
|
183
|
+
// Verify cwd was moved out (should be basePath, not still inside worktree)
|
|
184
|
+
const newCwd = process.cwd();
|
|
185
|
+
assert.ok(
|
|
186
|
+
!newCwd.startsWith(wtPath),
|
|
187
|
+
"cwd moved out of worktree after fix",
|
|
188
|
+
);
|
|
189
|
+
} finally {
|
|
190
|
+
// Restore cwd — the worktree dir may be gone, so chdir to previousCwd
|
|
191
|
+
try { process.chdir(previousCwd); } catch { process.chdir(dir); }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
console.log("\n=== orphaned_auto_worktree (cwd inside worktree — skipped on Windows) ===");
|
|
196
|
+
}
|
|
197
|
+
|
|
148
198
|
// ─── Test 2: Stale milestone branch detection & fix ────────────────
|
|
149
199
|
// Skip on Windows: git branch glob matching and path resolution
|
|
150
200
|
// behave differently in Windows temp dirs.
|
|
@@ -252,7 +252,7 @@ describe('feature-branch-lifecycle-integration', async () => {
|
|
|
252
252
|
// Exactly one new commit on feature branch (the squash merge)
|
|
253
253
|
const featureLog = run(`git log --oneline ${featureBranch}`, repo);
|
|
254
254
|
assert.ok(
|
|
255
|
-
featureLog.includes(
|
|
255
|
+
featureLog.includes("feat:"),
|
|
256
256
|
"feature branch has milestone merge commit",
|
|
257
257
|
);
|
|
258
258
|
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// Quality gate dispatch + state derivation tests
|
|
2
|
+
// Verifies the evaluating-gates phase and dispatch rule behavior.
|
|
3
|
+
|
|
4
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { mkdtempSync, mkdirSync, writeFileSync, 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
|
+
upsertSlicePlanning,
|
|
17
|
+
upsertTaskPlanning,
|
|
18
|
+
insertGateRow,
|
|
19
|
+
saveGateResult,
|
|
20
|
+
markAllGatesOmitted,
|
|
21
|
+
getPendingSliceGateCount,
|
|
22
|
+
} from "../gsd-db.ts";
|
|
23
|
+
import { deriveState, invalidateStateCache } from "../state.ts";
|
|
24
|
+
import { renderPlanFromDb } from "../markdown-renderer.ts";
|
|
25
|
+
import { invalidateAllCaches } from "../cache.ts";
|
|
26
|
+
|
|
27
|
+
function setupTestProject(): { tmpDir: string; dbPath: string } {
|
|
28
|
+
const tmpDir = mkdtempSync(join(tmpdir(), "gate-dispatch-"));
|
|
29
|
+
const dbPath = join(tmpDir, ".gsd", "gsd.db");
|
|
30
|
+
mkdirSync(join(tmpDir, ".gsd"), { recursive: true });
|
|
31
|
+
openDatabase(dbPath);
|
|
32
|
+
|
|
33
|
+
// Create milestone
|
|
34
|
+
insertMilestone({
|
|
35
|
+
id: "M001",
|
|
36
|
+
title: "Test Milestone",
|
|
37
|
+
status: "active",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Create slice
|
|
41
|
+
insertSlice({
|
|
42
|
+
milestoneId: "M001",
|
|
43
|
+
id: "S01",
|
|
44
|
+
title: "Test Slice",
|
|
45
|
+
status: "pending",
|
|
46
|
+
risk: "medium",
|
|
47
|
+
depends: [],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Write roadmap file (required for deriveState)
|
|
51
|
+
const milestoneDir = join(tmpDir, ".gsd", "milestones", "M001");
|
|
52
|
+
mkdirSync(milestoneDir, { recursive: true });
|
|
53
|
+
writeFileSync(
|
|
54
|
+
join(milestoneDir, "M001-ROADMAP.md"),
|
|
55
|
+
[
|
|
56
|
+
"# M001: Test Milestone",
|
|
57
|
+
"",
|
|
58
|
+
"## Vision",
|
|
59
|
+
"Test milestone vision.",
|
|
60
|
+
"",
|
|
61
|
+
"## Success Criteria",
|
|
62
|
+
"- Test criteria",
|
|
63
|
+
"",
|
|
64
|
+
"## Delivery Sequence",
|
|
65
|
+
"- [ ] **S01: Test Slice** `risk:medium`",
|
|
66
|
+
" After this: test demo",
|
|
67
|
+
"",
|
|
68
|
+
].join("\n"),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return { tmpDir, dbPath };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function planSlice(tmpDir: string) {
|
|
75
|
+
upsertSlicePlanning("M001", "S01", {
|
|
76
|
+
goal: "Test goal",
|
|
77
|
+
successCriteria: "Test criteria",
|
|
78
|
+
proofLevel: "contract",
|
|
79
|
+
integrationClosure: "",
|
|
80
|
+
observabilityImpact: "Run tests",
|
|
81
|
+
});
|
|
82
|
+
insertTask({
|
|
83
|
+
id: "T01",
|
|
84
|
+
sliceId: "S01",
|
|
85
|
+
milestoneId: "M001",
|
|
86
|
+
title: "Test Task",
|
|
87
|
+
status: "pending",
|
|
88
|
+
});
|
|
89
|
+
upsertTaskPlanning("M001", "S01", "T01", {
|
|
90
|
+
title: "Test Task",
|
|
91
|
+
description: "Implement test",
|
|
92
|
+
estimate: "1h",
|
|
93
|
+
files: ["src/test.ts"],
|
|
94
|
+
verify: "npm test",
|
|
95
|
+
inputs: [],
|
|
96
|
+
expectedOutput: ["src/test.ts"],
|
|
97
|
+
observabilityImpact: "",
|
|
98
|
+
fullPlanMd: "",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
describe("evaluating-gates phase", () => {
|
|
103
|
+
let tmpDir: string;
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
const setup = setupTestProject();
|
|
107
|
+
tmpDir = setup.tmpDir;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
afterEach(() => {
|
|
111
|
+
invalidateAllCaches();
|
|
112
|
+
invalidateStateCache();
|
|
113
|
+
closeDatabase();
|
|
114
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("state returns evaluating-gates when slice gates are pending", async () => {
|
|
118
|
+
planSlice(tmpDir);
|
|
119
|
+
await renderPlanFromDb(tmpDir, "M001", "S01");
|
|
120
|
+
|
|
121
|
+
// Seed gates as pending
|
|
122
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
123
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
|
|
124
|
+
|
|
125
|
+
invalidateStateCache();
|
|
126
|
+
const state = await deriveState(tmpDir);
|
|
127
|
+
assert.equal(state.phase, "evaluating-gates");
|
|
128
|
+
assert.ok(state.nextAction.includes("quality gate"));
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("state returns executing when all gates are resolved", async () => {
|
|
132
|
+
planSlice(tmpDir);
|
|
133
|
+
await renderPlanFromDb(tmpDir, "M001", "S01");
|
|
134
|
+
|
|
135
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
136
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
|
|
137
|
+
|
|
138
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", verdict: "pass", rationale: "OK", findings: "" });
|
|
139
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", verdict: "omitted", rationale: "N/A", findings: "" });
|
|
140
|
+
|
|
141
|
+
invalidateStateCache();
|
|
142
|
+
const state = await deriveState(tmpDir);
|
|
143
|
+
assert.equal(state.phase, "executing");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("state returns executing when no gates exist (backward compat)", async () => {
|
|
147
|
+
planSlice(tmpDir);
|
|
148
|
+
await renderPlanFromDb(tmpDir, "M001", "S01");
|
|
149
|
+
|
|
150
|
+
// No gates seeded at all
|
|
151
|
+
invalidateStateCache();
|
|
152
|
+
const state = await deriveState(tmpDir);
|
|
153
|
+
assert.equal(state.phase, "executing");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("markAllGatesOmitted clears evaluating-gates phase", async () => {
|
|
157
|
+
planSlice(tmpDir);
|
|
158
|
+
await renderPlanFromDb(tmpDir, "M001", "S01");
|
|
159
|
+
|
|
160
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
161
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
|
|
162
|
+
|
|
163
|
+
invalidateStateCache();
|
|
164
|
+
assert.equal((await deriveState(tmpDir)).phase, "evaluating-gates");
|
|
165
|
+
|
|
166
|
+
markAllGatesOmitted("M001", "S01");
|
|
167
|
+
invalidateStateCache();
|
|
168
|
+
assert.equal((await deriveState(tmpDir)).phase, "executing");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("task-scoped gates do not block evaluating-gates phase", async () => {
|
|
172
|
+
planSlice(tmpDir);
|
|
173
|
+
await renderPlanFromDb(tmpDir, "M001", "S01");
|
|
174
|
+
|
|
175
|
+
// Only task-scoped gates — no slice-scoped gates
|
|
176
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q5", scope: "task", taskId: "T01" });
|
|
177
|
+
|
|
178
|
+
invalidateStateCache();
|
|
179
|
+
const state = await deriveState(tmpDir);
|
|
180
|
+
// Should be executing, not evaluating-gates, because Q5 is task-scoped
|
|
181
|
+
assert.equal(state.phase, "executing");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("getPendingSliceGateCount ignores task-scoped gates", () => {
|
|
185
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
186
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q5", scope: "task", taskId: "T01" });
|
|
187
|
+
assert.equal(getPendingSliceGateCount("M001", "S01"), 1);
|
|
188
|
+
});
|
|
189
|
+
});
|