gsd-pi 2.65.0 → 2.66.0-dev.6c91c1f
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/mcp-server.js +6 -2
- package/dist/resources/extensions/browser-tools/capture.js +20 -1
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/dist/resources/extensions/gsd/auto/finalize-timeout.js +2 -0
- package/dist/resources/extensions/gsd/auto/loop.js +2 -2
- package/dist/resources/extensions/gsd/auto/phases.js +48 -5
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto/types.js +2 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +2 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
- package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
- package/dist/resources/extensions/gsd/auto-start.js +175 -12
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
- package/dist/resources/extensions/gsd/auto.js +21 -15
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -3
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +31 -1
- package/dist/resources/extensions/gsd/commands/context.js +8 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +312 -0
- package/dist/resources/extensions/gsd/db-writer.js +13 -3
- package/dist/resources/extensions/gsd/detection.js +1 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/dist/resources/extensions/gsd/doctor.js +2 -1
- package/dist/resources/extensions/gsd/files.js +17 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +47 -4
- package/dist/resources/extensions/gsd/guided-flow.js +220 -29
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/json-persistence.js +5 -2
- package/dist/resources/extensions/gsd/md-importer.js +14 -7
- package/dist/resources/extensions/gsd/notification-overlay.js +1 -1
- package/dist/resources/extensions/gsd/notification-widget.js +2 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
- package/dist/resources/extensions/gsd/pre-execution-checks.js +26 -5
- package/dist/resources/extensions/gsd/preferences-types.js +3 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -2
- package/dist/resources/extensions/gsd/preparation.js +1092 -0
- package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/dist/resources/extensions/gsd/prompts/queue.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/dist/resources/extensions/gsd/quick.js +19 -15
- package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
- package/dist/resources/extensions/gsd/session-lock.js +23 -1
- package/dist/resources/extensions/gsd/state.js +115 -28
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
- package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
- package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
- package/dist/resources/extensions/gsd/undo.js +3 -2
- package/dist/resources/extensions/gsd/workflow-events.js +1 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +7 -9
- package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
- package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
- package/dist/resources/extensions/gsd/worktree.js +9 -0
- package/dist/resources/extensions/shared/interview-ui.js +1 -1
- package/dist/resources/extensions/subagent/agents.js +19 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- 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 +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/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/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/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/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 +2 -2
- 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 +11 -11
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/chunks/7471.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/6502.8874bcae249c02e1.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-0c485498795110d6.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-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.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/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +20 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.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 +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
- package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
- package/packages/pi-tui/dist/components/image.d.ts +2 -0
- package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/image.js +4 -0
- package/packages/pi-tui/dist/components/image.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
- package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/image.test.js +32 -0
- package/packages/pi-tui/dist/components/image.test.js.map +1 -0
- package/packages/pi-tui/src/components/image.test.ts +36 -0
- package/packages/pi-tui/src/components/image.ts +5 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/capture.ts +19 -1
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/src/resources/extensions/gsd/auto/finalize-timeout.ts +3 -0
- package/src/resources/extensions/gsd/auto/loop.ts +2 -2
- package/src/resources/extensions/gsd/auto/phases.ts +68 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto/types.ts +5 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
- package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
- package/src/resources/extensions/gsd/auto-start.ts +188 -10
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
- package/src/resources/extensions/gsd/auto.ts +19 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +36 -1
- package/src/resources/extensions/gsd/commands/context.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +26 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +331 -0
- package/src/resources/extensions/gsd/db-writer.ts +11 -3
- package/src/resources/extensions/gsd/detection.ts +1 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -1
- package/src/resources/extensions/gsd/files.ts +19 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +46 -4
- package/src/resources/extensions/gsd/guided-flow.ts +254 -30
- package/src/resources/extensions/gsd/index.ts +1 -0
- package/src/resources/extensions/gsd/json-persistence.ts +6 -3
- package/src/resources/extensions/gsd/md-importer.ts +13 -6
- package/src/resources/extensions/gsd/notification-overlay.ts +1 -1
- package/src/resources/extensions/gsd/notification-widget.ts +2 -1
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -7
- package/src/resources/extensions/gsd/preferences-types.ts +25 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- package/src/resources/extensions/gsd/preparation.ts +1419 -0
- package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/src/resources/extensions/gsd/prompts/queue.md +2 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/src/resources/extensions/gsd/quick.ts +20 -15
- package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
- package/src/resources/extensions/gsd/session-lock.ts +17 -1
- package/src/resources/extensions/gsd/state.ts +115 -26
- package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +11 -10
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +284 -20
- package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/subagent-agent-discovery.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/wave5-consistency-regressions.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +127 -2
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
- package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
- package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
- package/src/resources/extensions/gsd/types.ts +4 -0
- package/src/resources/extensions/gsd/undo.ts +3 -2
- package/src/resources/extensions/gsd/workflow-events.ts +5 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +7 -8
- package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
- package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
- package/src/resources/extensions/gsd/worktree.ts +10 -0
- package/src/resources/extensions/shared/interview-ui.ts +1 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
- package/src/resources/extensions/subagent/agents.ts +30 -6
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.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/{MRM3OSYIAa4HMDqVGQ9nt → _X1i-S7l1jZfb7lmIZozb}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → _X1i-S7l1jZfb7lmIZozb}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stale-lockfile-recovery.test.ts — #3668
|
|
3
|
+
*
|
|
4
|
+
* Verify that session-lock.ts contains pre-flight stale lock cleanup logic
|
|
5
|
+
* that removes orphaned lock directories when the owning PID is dead,
|
|
6
|
+
* preventing the 30-min stale window from blocking /gsd after crashes.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, test } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { join, dirname } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const sourceFile = join(__dirname, "..", "session-lock.ts");
|
|
17
|
+
|
|
18
|
+
describe("stale lockfile auto-recovery (#3668)", () => {
|
|
19
|
+
const source = readFileSync(sourceFile, "utf-8");
|
|
20
|
+
|
|
21
|
+
test("checks for orphan lock with isPidAlive", () => {
|
|
22
|
+
assert.match(source, /isPidAlive\(existingData\.pid\)/);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("removes stale lock directory with rmSync", () => {
|
|
26
|
+
assert.match(source, /rmSync\(lockDir,\s*\{\s*recursive:\s*true/);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("references issue #3218 in pre-flight cleanup comment", () => {
|
|
30
|
+
assert.match(source, /#3218.*Pre-flight stale lock cleanup/);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("provides actionable rm -rf workaround in error message", () => {
|
|
34
|
+
assert.match(source, /rm\s+-rf/);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3470: DB-backed active milestone selection must not
|
|
3
|
+
* prefer a stale queued shell over the real active milestone.
|
|
4
|
+
*
|
|
5
|
+
* Scenario: M068 is a queued placeholder (DB row, no files, no slices).
|
|
6
|
+
* M070 is the real active milestone (context, roadmap, slices, tasks).
|
|
7
|
+
* deriveStateFromDb() must select M070 as active, not M068.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, test, afterEach } from "node:test";
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { tmpdir } from "node:os";
|
|
15
|
+
|
|
16
|
+
import { deriveStateFromDb, invalidateStateCache } from "../state.ts";
|
|
17
|
+
import {
|
|
18
|
+
openDatabase,
|
|
19
|
+
closeDatabase,
|
|
20
|
+
insertMilestone,
|
|
21
|
+
insertSlice,
|
|
22
|
+
insertTask,
|
|
23
|
+
} from "../gsd-db.ts";
|
|
24
|
+
|
|
25
|
+
function createFixtureBase(): string {
|
|
26
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-stale-milestone-"));
|
|
27
|
+
mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
|
|
28
|
+
return base;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function writeFile(base: string, relativePath: string, content: string): void {
|
|
32
|
+
const full = join(base, ".gsd", relativePath);
|
|
33
|
+
mkdirSync(join(full, ".."), { recursive: true });
|
|
34
|
+
writeFileSync(full, content);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe("stale queued milestone selection (#3470)", () => {
|
|
38
|
+
let base: string;
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
closeDatabase();
|
|
42
|
+
if (base) rmSync(base, { recursive: true, force: true });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("queued shell with no content does not block real active milestone", async () => {
|
|
46
|
+
base = createFixtureBase();
|
|
47
|
+
openDatabase(":memory:");
|
|
48
|
+
|
|
49
|
+
// M068: queued shell — DB row exists, no files, no slices
|
|
50
|
+
insertMilestone({ id: "M068", title: "Queued Shell", status: "queued" });
|
|
51
|
+
|
|
52
|
+
// M070: real active milestone — context, roadmap, slices, tasks
|
|
53
|
+
insertMilestone({ id: "M070", title: "Real Active", status: "active" });
|
|
54
|
+
insertSlice({ id: "S01", milestoneId: "M070", title: "Slice One", status: "active", risk: "low", depends: [] });
|
|
55
|
+
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M070", title: "Task One", status: "pending" });
|
|
56
|
+
|
|
57
|
+
writeFile(base, "milestones/M070/M070-CONTEXT.md", "# M070: Real Active\n\nThis is the real milestone.");
|
|
58
|
+
writeFile(base, "milestones/M070/M070-ROADMAP.md", "# M070: Real Active\n\n## Slices\n\n- [ ] **S01: Slice One**");
|
|
59
|
+
writeFile(base, "milestones/M070/slices/S01/S01-PLAN.md", "# S01: Slice One\n\n## Tasks\n\n- [ ] **T01: Task One**");
|
|
60
|
+
|
|
61
|
+
invalidateStateCache();
|
|
62
|
+
const state = await deriveStateFromDb(base);
|
|
63
|
+
|
|
64
|
+
assert.equal(state.activeMilestone?.id, "M070", "Active milestone must be M070, not queued shell M068");
|
|
65
|
+
|
|
66
|
+
// M068 should appear as pending in registry, not active
|
|
67
|
+
const m068Entry = state.registry.find((e: any) => e.id === "M068");
|
|
68
|
+
assert.ok(m068Entry, "M068 should still appear in registry");
|
|
69
|
+
assert.equal(m068Entry!.status, "pending", "M068 should be pending, not active");
|
|
70
|
+
|
|
71
|
+
// M070 should be active in registry
|
|
72
|
+
const m070Entry = state.registry.find((e: any) => e.id === "M070");
|
|
73
|
+
assert.ok(m070Entry, "M070 should appear in registry");
|
|
74
|
+
assert.equal(m070Entry!.status, "active", "M070 should be active in registry");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("queued milestone WITH context file can still be selected as active", async () => {
|
|
78
|
+
base = createFixtureBase();
|
|
79
|
+
openDatabase(":memory:");
|
|
80
|
+
|
|
81
|
+
// M068: queued but has context (discussion started) — should be activatable
|
|
82
|
+
insertMilestone({ id: "M068", title: "Queued With Context", status: "queued" });
|
|
83
|
+
writeFile(base, "milestones/M068/M068-CONTEXT.md", "# M068: Queued With Context\n\nDiscussion started.");
|
|
84
|
+
|
|
85
|
+
invalidateStateCache();
|
|
86
|
+
const state = await deriveStateFromDb(base);
|
|
87
|
+
|
|
88
|
+
assert.equal(state.activeMilestone?.id, "M068", "Queued milestone with context should become active");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("queued milestone WITH context-draft can still be selected as active", async () => {
|
|
92
|
+
base = createFixtureBase();
|
|
93
|
+
openDatabase(":memory:");
|
|
94
|
+
|
|
95
|
+
// M068: queued but has draft (discussion in progress)
|
|
96
|
+
insertMilestone({ id: "M068", title: "Queued With Draft", status: "queued" });
|
|
97
|
+
writeFile(base, "milestones/M068/M068-CONTEXT-DRAFT.md", "# M068: Queued With Draft\n\nDraft in progress.");
|
|
98
|
+
|
|
99
|
+
invalidateStateCache();
|
|
100
|
+
const state = await deriveStateFromDb(base);
|
|
101
|
+
|
|
102
|
+
assert.equal(state.activeMilestone?.id, "M068", "Queued milestone with draft should become active");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("queued milestone WITH slices can still be selected as active", async () => {
|
|
106
|
+
base = createFixtureBase();
|
|
107
|
+
openDatabase(":memory:");
|
|
108
|
+
|
|
109
|
+
// M068: queued but has slices (planning started)
|
|
110
|
+
insertMilestone({ id: "M068", title: "Queued With Slices", status: "queued" });
|
|
111
|
+
insertSlice({ id: "S01", milestoneId: "M068", title: "Slice One", status: "pending", risk: "low", depends: [] });
|
|
112
|
+
writeFile(base, "milestones/M068/M068-ROADMAP.md", "# M068\n\n## Slices\n\n- [ ] **S01: Slice One**");
|
|
113
|
+
|
|
114
|
+
invalidateStateCache();
|
|
115
|
+
const state = await deriveStateFromDb(base);
|
|
116
|
+
|
|
117
|
+
assert.equal(state.activeMilestone?.id, "M068", "Queued milestone with slices should become active");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("multiple queued shells all skipped in favor of real active", async () => {
|
|
121
|
+
base = createFixtureBase();
|
|
122
|
+
openDatabase(":memory:");
|
|
123
|
+
|
|
124
|
+
// Three queued shells before the real milestone
|
|
125
|
+
insertMilestone({ id: "M065", title: "Shell 1", status: "queued" });
|
|
126
|
+
insertMilestone({ id: "M066", title: "Shell 2", status: "queued" });
|
|
127
|
+
insertMilestone({ id: "M068", title: "Shell 3", status: "queued" });
|
|
128
|
+
|
|
129
|
+
// M070: real active
|
|
130
|
+
insertMilestone({ id: "M070", title: "Real Active", status: "active" });
|
|
131
|
+
insertSlice({ id: "S01", milestoneId: "M070", title: "Slice One", status: "active", risk: "low", depends: [] });
|
|
132
|
+
writeFile(base, "milestones/M070/M070-CONTEXT.md", "# M070: Real Active");
|
|
133
|
+
writeFile(base, "milestones/M070/M070-ROADMAP.md", "# M070\n\n## Slices\n\n- [ ] **S01: Slice One**");
|
|
134
|
+
|
|
135
|
+
invalidateStateCache();
|
|
136
|
+
const state = await deriveStateFromDb(base);
|
|
137
|
+
|
|
138
|
+
assert.equal(state.activeMilestone?.id, "M070", "Must skip all queued shells to reach M070");
|
|
139
|
+
|
|
140
|
+
// All shells should be pending
|
|
141
|
+
for (const id of ["M065", "M066", "M068"]) {
|
|
142
|
+
const entry = state.registry.find((e: any) => e.id === id);
|
|
143
|
+
assert.ok(entry, `${id} should be in registry`);
|
|
144
|
+
assert.equal(entry!.status, "pending", `${id} should be pending, not active`);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
teardownAutoWorktree,
|
|
18
18
|
mergeMilestoneToMain,
|
|
19
19
|
} from "../auto-worktree.ts";
|
|
20
|
+
import { _resetServiceCache } from "../worktree.ts";
|
|
21
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
20
22
|
|
|
21
23
|
function run(command: string, cwd: string): string {
|
|
22
24
|
return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
@@ -62,6 +64,13 @@ test("mergeMilestoneToMain restores cwd to project root", () => {
|
|
|
62
64
|
const savedCwd = process.cwd();
|
|
63
65
|
let tempDir = "";
|
|
64
66
|
|
|
67
|
+
// Isolate from user's global preferences (which may have git.main_branch set)
|
|
68
|
+
const originalHome = process.env.HOME;
|
|
69
|
+
const fakeHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-fake-home-")));
|
|
70
|
+
process.env.HOME = fakeHome;
|
|
71
|
+
_clearGsdRootCache();
|
|
72
|
+
_resetServiceCache();
|
|
73
|
+
|
|
65
74
|
try {
|
|
66
75
|
tempDir = createTempRepo();
|
|
67
76
|
|
|
@@ -97,9 +106,13 @@ test("mergeMilestoneToMain restores cwd to project root", () => {
|
|
|
97
106
|
assert.ok(!existsSync(wtPath), "worktree directory removed after merge");
|
|
98
107
|
} finally {
|
|
99
108
|
process.chdir(savedCwd);
|
|
109
|
+
process.env.HOME = originalHome;
|
|
110
|
+
_clearGsdRootCache();
|
|
111
|
+
_resetServiceCache();
|
|
100
112
|
if (tempDir && existsSync(tempDir)) {
|
|
101
113
|
rmSync(tempDir, { recursive: true, force: true });
|
|
102
114
|
}
|
|
115
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
103
116
|
}
|
|
104
117
|
});
|
|
105
118
|
|
|
@@ -15,6 +15,27 @@ import { tmpdir } from "node:os";
|
|
|
15
15
|
import { execSync } from "node:child_process";
|
|
16
16
|
|
|
17
17
|
import { createAutoWorktree, mergeMilestoneToMain } from "../auto-worktree.ts";
|
|
18
|
+
import { _resetServiceCache } from "../worktree.ts";
|
|
19
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
20
|
+
|
|
21
|
+
// Isolate from user's global preferences (which may have git.main_branch set)
|
|
22
|
+
let originalHome: string | undefined;
|
|
23
|
+
let fakeHome: string;
|
|
24
|
+
|
|
25
|
+
test.before(() => {
|
|
26
|
+
originalHome = process.env.HOME;
|
|
27
|
+
fakeHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-fake-home-")));
|
|
28
|
+
process.env.HOME = fakeHome;
|
|
29
|
+
_clearGsdRootCache();
|
|
30
|
+
_resetServiceCache();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test.after(() => {
|
|
34
|
+
process.env.HOME = originalHome;
|
|
35
|
+
_clearGsdRootCache();
|
|
36
|
+
_resetServiceCache();
|
|
37
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
38
|
+
});
|
|
18
39
|
|
|
19
40
|
function run(cmd: string, cwd: string): string {
|
|
20
41
|
return execSync(cmd, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
@@ -27,6 +27,27 @@ import { tmpdir } from "node:os";
|
|
|
27
27
|
import { execSync } from "node:child_process";
|
|
28
28
|
|
|
29
29
|
import { createAutoWorktree, mergeMilestoneToMain } from "../auto-worktree.ts";
|
|
30
|
+
import { _resetServiceCache } from "../worktree.ts";
|
|
31
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
32
|
+
|
|
33
|
+
// Isolate from user's global preferences (which may have git.main_branch set)
|
|
34
|
+
let originalHome: string | undefined;
|
|
35
|
+
let fakeHome: string;
|
|
36
|
+
|
|
37
|
+
test.before(() => {
|
|
38
|
+
originalHome = process.env.HOME;
|
|
39
|
+
fakeHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-fake-home-")));
|
|
40
|
+
process.env.HOME = fakeHome;
|
|
41
|
+
_clearGsdRootCache();
|
|
42
|
+
_resetServiceCache();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test.after(() => {
|
|
46
|
+
process.env.HOME = originalHome;
|
|
47
|
+
_clearGsdRootCache();
|
|
48
|
+
_resetServiceCache();
|
|
49
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
50
|
+
});
|
|
30
51
|
|
|
31
52
|
function run(cmd: string, cwd: string): string {
|
|
32
53
|
return execSync(cmd, {
|
|
@@ -1040,8 +1040,8 @@ describe("state-machine-full-walkthrough", () => {
|
|
|
1040
1040
|
// FAILURE MODES: What happens when things go wrong
|
|
1041
1041
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1042
1042
|
|
|
1043
|
-
describe("
|
|
1044
|
-
test("DB tasks empty but PLAN on disk has tasks →
|
|
1043
|
+
describe("Recovery: DB has slice but no task rows (partial migration)", () => {
|
|
1044
|
+
test("DB tasks empty but PLAN on disk has tasks → reconciles to executing", async () => {
|
|
1045
1045
|
const base = createFixtureBase();
|
|
1046
1046
|
const dbPath = join(base, ".gsd", "gsd.db");
|
|
1047
1047
|
openDatabase(dbPath);
|
|
@@ -1056,11 +1056,10 @@ describe("state-machine-full-walkthrough", () => {
|
|
|
1056
1056
|
invalidateStateCache();
|
|
1057
1057
|
const state = await deriveStateFromDb(base);
|
|
1058
1058
|
|
|
1059
|
-
//
|
|
1060
|
-
//
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
"KNOWN ISSUE: DB empty tasks → planning even though PLAN has tasks on disk");
|
|
1059
|
+
// FIX (#3600): plan-file tasks are now reconciled into the DB,
|
|
1060
|
+
// so the phase correctly advances to executing instead of planning.
|
|
1061
|
+
assert.equal(state.phase, "executing",
|
|
1062
|
+
"reconciled plan-file tasks → executing (not stuck in planning)");
|
|
1064
1063
|
});
|
|
1065
1064
|
});
|
|
1066
1065
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3691 — /gsd status opens DB before deriveState
|
|
3
|
+
*
|
|
4
|
+
* In cold sessions the DB was not opened before deriveState, causing
|
|
5
|
+
* status to fall back to filesystem-only state. The fix adds an
|
|
6
|
+
* ensureDbOpen() call before deriveState in handleStatus.
|
|
7
|
+
*
|
|
8
|
+
* Also verifies that quick.ts checks getIsolationMode before branching.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, test } from 'node:test';
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { dirname, join } from 'node:path';
|
|
16
|
+
|
|
17
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname = dirname(__filename);
|
|
19
|
+
|
|
20
|
+
const coreSrc = readFileSync(
|
|
21
|
+
join(__dirname, '..', 'commands', 'handlers', 'core.ts'),
|
|
22
|
+
'utf-8',
|
|
23
|
+
);
|
|
24
|
+
const quickSrc = readFileSync(
|
|
25
|
+
join(__dirname, '..', 'quick.ts'),
|
|
26
|
+
'utf-8',
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
describe('status opens DB before deriveState (#3691)', () => {
|
|
30
|
+
test('handleStatus calls ensureDbOpen before deriveState', () => {
|
|
31
|
+
const ensureIdx = coreSrc.indexOf('ensureDbOpen');
|
|
32
|
+
const deriveIdx = coreSrc.indexOf('deriveState(basePath)');
|
|
33
|
+
assert.ok(ensureIdx > -1, 'ensureDbOpen call should exist in core.ts');
|
|
34
|
+
assert.ok(deriveIdx > -1, 'deriveState(basePath) call should exist in core.ts');
|
|
35
|
+
assert.ok(
|
|
36
|
+
ensureIdx < deriveIdx,
|
|
37
|
+
'ensureDbOpen must appear before deriveState so DB is ready',
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('quick.ts checks getIsolationMode before branching', () => {
|
|
42
|
+
assert.match(quickSrc, /getIsolationMode\(\)/,
|
|
43
|
+
'quick.ts should call getIsolationMode()');
|
|
44
|
+
assert.match(quickSrc, /getIsolationMode\(\)\s*!==\s*"none"/,
|
|
45
|
+
'quick.ts should compare isolation mode against "none"');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -165,6 +165,7 @@ test("Rule 4: ENOENT paths non-consecutive still triggers", () => {
|
|
|
165
165
|
assert.ok(result!.reason.includes("/missing/skill"), `reason was: ${result!.reason}`);
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
+
|
|
168
169
|
// ─── Gap documentation: 3-unit cycle evades detection ────────────────────────
|
|
169
170
|
|
|
170
171
|
test("Three-unit cycle A-B-C-A-B-C does NOT trigger stuck (documents gap L13)", () => {
|
|
@@ -42,3 +42,50 @@ test("discoverAgents falls back to legacy .pi/agents when needed", (t) => {
|
|
|
42
42
|
assert.equal(discovery.projectAgentsDir, agentsDir);
|
|
43
43
|
assert.deepEqual(discovery.agents.map((agent) => agent.name), ["ping"]);
|
|
44
44
|
});
|
|
45
|
+
|
|
46
|
+
test("discoverAgents accepts tools frontmatter as a YAML list", (t) => {
|
|
47
|
+
const root = makeProjectRoot(t);
|
|
48
|
+
const agentsDir = join(root, ".gsd", "agents");
|
|
49
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
50
|
+
writeFileSync(
|
|
51
|
+
join(agentsDir, "reviewer.md"),
|
|
52
|
+
[
|
|
53
|
+
"---",
|
|
54
|
+
"name: reviewer",
|
|
55
|
+
"description: review agent",
|
|
56
|
+
"tools:",
|
|
57
|
+
" - bash",
|
|
58
|
+
" - read",
|
|
59
|
+
"---",
|
|
60
|
+
"Review code",
|
|
61
|
+
"",
|
|
62
|
+
].join("\n"),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const discovery = discoverAgents(root, "project");
|
|
66
|
+
|
|
67
|
+
assert.deepEqual(discovery.agents.map((agent) => agent.name), ["reviewer"]);
|
|
68
|
+
assert.deepEqual(discovery.agents[0]?.tools, ["bash", "read"]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("discoverAgents still accepts comma-separated tools frontmatter", (t) => {
|
|
72
|
+
const root = makeProjectRoot(t);
|
|
73
|
+
const agentsDir = join(root, ".gsd", "agents");
|
|
74
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
75
|
+
writeFileSync(
|
|
76
|
+
join(agentsDir, "reviewer.md"),
|
|
77
|
+
[
|
|
78
|
+
"---",
|
|
79
|
+
"name: reviewer",
|
|
80
|
+
"description: review agent",
|
|
81
|
+
"tools: bash, read",
|
|
82
|
+
"---",
|
|
83
|
+
"Review code",
|
|
84
|
+
"",
|
|
85
|
+
].join("\n"),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const discovery = discoverAgents(root, "project");
|
|
89
|
+
|
|
90
|
+
assert.deepEqual(discovery.agents[0]?.tools, ["bash", "read"]);
|
|
91
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Regression test for: discoverManifests() skips symlinked extension directories
|
|
2
|
+
//
|
|
3
|
+
// The bug: Dirent.isDirectory() returns false for symlinks, so extensions installed
|
|
4
|
+
// as directory symlinks under ~/.gsd/agent/extensions/ were invisible to all
|
|
5
|
+
// management commands (list, enable, disable, info).
|
|
6
|
+
//
|
|
7
|
+
// The fix: check `entry.isDirectory() || entry.isSymbolicLink()`, matching the
|
|
8
|
+
// pattern already used in loader.ts discoverExtensionsInDir().
|
|
9
|
+
|
|
10
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import {
|
|
13
|
+
mkdtempSync,
|
|
14
|
+
mkdirSync,
|
|
15
|
+
writeFileSync,
|
|
16
|
+
symlinkSync,
|
|
17
|
+
readdirSync,
|
|
18
|
+
existsSync,
|
|
19
|
+
rmSync,
|
|
20
|
+
} from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
|
|
24
|
+
// Inline the discovery logic so the test is self-contained and can verify both
|
|
25
|
+
// the buggy and fixed behaviour without importing the private function.
|
|
26
|
+
function discoverManifestsBuggy(extDir: string): string[] {
|
|
27
|
+
const found: string[] = [];
|
|
28
|
+
if (!existsSync(extDir)) return found;
|
|
29
|
+
for (const entry of readdirSync(extDir, { withFileTypes: true })) {
|
|
30
|
+
if (!entry.isDirectory()) continue; // BUG: skips symlinks
|
|
31
|
+
const mPath = join(extDir, entry.name, "extension-manifest.json");
|
|
32
|
+
if (existsSync(mPath)) found.push(entry.name);
|
|
33
|
+
}
|
|
34
|
+
return found;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function discoverManifestsFixed(extDir: string): string[] {
|
|
38
|
+
const found: string[] = [];
|
|
39
|
+
if (!existsSync(extDir)) return found;
|
|
40
|
+
for (const entry of readdirSync(extDir, { withFileTypes: true })) {
|
|
41
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue; // FIX
|
|
42
|
+
const mPath = join(extDir, entry.name, "extension-manifest.json");
|
|
43
|
+
if (existsSync(mPath)) found.push(entry.name);
|
|
44
|
+
}
|
|
45
|
+
return found;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const MANIFEST = JSON.stringify({
|
|
49
|
+
id: "test-ext",
|
|
50
|
+
name: "Test Extension",
|
|
51
|
+
version: "1.0.0",
|
|
52
|
+
description: "A test extension",
|
|
53
|
+
tier: "community",
|
|
54
|
+
requires: { platform: "linux" },
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("symlink extension discovery", () => {
|
|
58
|
+
let tmp: string;
|
|
59
|
+
let extDir: string;
|
|
60
|
+
let realExtDir: string;
|
|
61
|
+
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
tmp = mkdtempSync(join(tmpdir(), "gsd-ext-test-"));
|
|
64
|
+
extDir = join(tmp, "agent", "extensions");
|
|
65
|
+
realExtDir = join(tmp, "my-ext-source");
|
|
66
|
+
|
|
67
|
+
// Create the real extension directory outside extDir (simulates a dev checkout)
|
|
68
|
+
mkdirSync(realExtDir, { recursive: true });
|
|
69
|
+
writeFileSync(join(realExtDir, "extension-manifest.json"), MANIFEST, "utf-8");
|
|
70
|
+
|
|
71
|
+
// Create the extensions scan directory
|
|
72
|
+
mkdirSync(extDir, { recursive: true });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
afterEach(() => {
|
|
76
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("real directory is discovered by both implementations", () => {
|
|
80
|
+
// Install extension as a real directory copy
|
|
81
|
+
const realCopy = join(extDir, "my-ext");
|
|
82
|
+
mkdirSync(realCopy);
|
|
83
|
+
writeFileSync(join(realCopy, "extension-manifest.json"), MANIFEST, "utf-8");
|
|
84
|
+
|
|
85
|
+
assert.deepEqual(discoverManifestsBuggy(extDir), ["my-ext"]);
|
|
86
|
+
assert.deepEqual(discoverManifestsFixed(extDir), ["my-ext"]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("symlinked directory is missed by buggy implementation", () => {
|
|
90
|
+
// Install extension as a directory symlink — the common dev workflow
|
|
91
|
+
symlinkSync(realExtDir, join(extDir, "my-ext"));
|
|
92
|
+
|
|
93
|
+
// Buggy: symlink is invisible
|
|
94
|
+
assert.deepEqual(discoverManifestsBuggy(extDir), []);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("symlinked directory is discovered by fixed implementation", () => {
|
|
98
|
+
symlinkSync(realExtDir, join(extDir, "my-ext"));
|
|
99
|
+
|
|
100
|
+
// Fixed: symlink is visible
|
|
101
|
+
assert.deepEqual(discoverManifestsFixed(extDir), ["my-ext"]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("non-manifest symlinks are ignored", () => {
|
|
105
|
+
// Symlink to a dir that has no manifest — should not appear
|
|
106
|
+
const noManifestDir = join(tmp, "no-manifest");
|
|
107
|
+
mkdirSync(noManifestDir);
|
|
108
|
+
symlinkSync(noManifestDir, join(extDir, "no-manifest"));
|
|
109
|
+
|
|
110
|
+
assert.deepEqual(discoverManifestsFixed(extDir), []);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("mix of real dirs and symlinks are all discovered", () => {
|
|
114
|
+
// Real dir
|
|
115
|
+
const realCopy = join(extDir, "ext-real");
|
|
116
|
+
mkdirSync(realCopy);
|
|
117
|
+
writeFileSync(join(realCopy, "extension-manifest.json"), MANIFEST, "utf-8");
|
|
118
|
+
|
|
119
|
+
// Symlink dir
|
|
120
|
+
symlinkSync(realExtDir, join(extDir, "ext-symlink"));
|
|
121
|
+
|
|
122
|
+
const found = discoverManifestsFixed(extDir).sort();
|
|
123
|
+
assert.deepEqual(found, ["ext-real", "ext-symlink"]);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3641 — syncWorktreeStateBack skips current milestone
|
|
3
|
+
*
|
|
4
|
+
* When syncing worktree state back to main, the current milestone being
|
|
5
|
+
* merged should be skipped. Its files are already in the milestone branch
|
|
6
|
+
* and copying them back would conflict with the squash merge.
|
|
7
|
+
*
|
|
8
|
+
* The fix adds a `mid === milestoneId` skip guard inside the milestone
|
|
9
|
+
* iteration loop in syncWorktreeStateBack.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, it } from 'node:test'
|
|
13
|
+
import assert from 'node:assert/strict'
|
|
14
|
+
import { readFileSync } from 'node:fs'
|
|
15
|
+
import { resolve } from 'node:path'
|
|
16
|
+
|
|
17
|
+
const src = readFileSync(
|
|
18
|
+
resolve(process.cwd(), 'src', 'resources', 'extensions', 'gsd', 'auto-worktree.ts'),
|
|
19
|
+
'utf-8',
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
describe('syncWorktreeStateBack skips current milestone (#3641)', () => {
|
|
23
|
+
it('syncWorktreeStateBack function exists', () => {
|
|
24
|
+
assert.ok(
|
|
25
|
+
src.includes('function syncWorktreeStateBack('),
|
|
26
|
+
'syncWorktreeStateBack function must be defined',
|
|
27
|
+
)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('mid === milestoneId skip guard exists in the milestone loop', () => {
|
|
31
|
+
// Find syncWorktreeStateBack
|
|
32
|
+
const fnStart = src.indexOf('function syncWorktreeStateBack(')
|
|
33
|
+
assert.ok(fnStart !== -1)
|
|
34
|
+
|
|
35
|
+
// Get a reasonable portion of the function
|
|
36
|
+
const fnBlock = src.slice(fnStart, fnStart + 3000)
|
|
37
|
+
|
|
38
|
+
// Find the for loop iterating milestones
|
|
39
|
+
const loopIdx = fnBlock.indexOf('for (const mid of wtMilestones)')
|
|
40
|
+
assert.ok(loopIdx !== -1, 'milestone iteration loop must exist')
|
|
41
|
+
|
|
42
|
+
// After the loop, there should be the skip guard
|
|
43
|
+
const loopBody = fnBlock.slice(loopIdx, loopIdx + 300)
|
|
44
|
+
assert.ok(
|
|
45
|
+
loopBody.includes('mid === milestoneId'),
|
|
46
|
+
'mid === milestoneId skip guard must exist inside the milestone loop',
|
|
47
|
+
)
|
|
48
|
+
assert.ok(
|
|
49
|
+
loopBody.includes('continue'),
|
|
50
|
+
'skip guard must use continue to skip the current milestone',
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('syncMilestoneDir is still called for non-current milestones', () => {
|
|
55
|
+
const fnStart = src.indexOf('function syncWorktreeStateBack(')
|
|
56
|
+
assert.ok(fnStart !== -1)
|
|
57
|
+
|
|
58
|
+
const fnBlock = src.slice(fnStart, fnStart + 3000)
|
|
59
|
+
|
|
60
|
+
assert.ok(
|
|
61
|
+
fnBlock.includes('syncMilestoneDir('),
|
|
62
|
+
'syncMilestoneDir must still be called for other milestones',
|
|
63
|
+
)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -44,7 +44,7 @@ describe("#2883: tool invocation error tracking on AutoSession", () => {
|
|
|
44
44
|
|
|
45
45
|
// ─── isToolInvocationError classifier ────────────────────────────────────
|
|
46
46
|
|
|
47
|
-
import { isToolInvocationError } from "../auto-tool-tracking.ts";
|
|
47
|
+
import { isToolInvocationError, isQueuedUserMessageSkip } from "../auto-tool-tracking.ts";
|
|
48
48
|
|
|
49
49
|
describe("#2883: isToolInvocationError classification", () => {
|
|
50
50
|
test("detects JSON validation failure pattern", () => {
|
|
@@ -101,3 +101,31 @@ describe("#2883: isToolInvocationError classification", () => {
|
|
|
101
101
|
assert.equal(isToolInvocationError("ECONNRESET"), false);
|
|
102
102
|
});
|
|
103
103
|
});
|
|
104
|
+
|
|
105
|
+
// ─── isQueuedUserMessageSkip classifier (#3595) ─────────────────────────
|
|
106
|
+
|
|
107
|
+
describe("#3595: isQueuedUserMessageSkip classification", () => {
|
|
108
|
+
test("detects exact skip message with period", () => {
|
|
109
|
+
assert.equal(isQueuedUserMessageSkip("Skipped due to queued user message."), true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("detects skip message without period", () => {
|
|
113
|
+
assert.equal(isQueuedUserMessageSkip("Skipped due to queued user message"), true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("detects skip message with surrounding whitespace", () => {
|
|
117
|
+
assert.equal(isQueuedUserMessageSkip(" Skipped due to queued user message. "), true);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("returns false for normal tool errors", () => {
|
|
121
|
+
assert.equal(isQueuedUserMessageSkip("Slice S01 is already complete"), false);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("returns false for empty string", () => {
|
|
125
|
+
assert.equal(isQueuedUserMessageSkip(""), false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("returns false for partial match (substring)", () => {
|
|
129
|
+
assert.equal(isQueuedUserMessageSkip("Error: Skipped due to queued user message. Retry later."), false);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -387,7 +387,8 @@ test("resolution: executeTriageResolutions handles mixed classifications", () =>
|
|
|
387
387
|
assert.strictEqual(result.injected, 1, "should inject 1 task");
|
|
388
388
|
assert.strictEqual(result.replanned, 0);
|
|
389
389
|
assert.strictEqual(result.quickTasks.length, 1, "should queue 1 quick-task");
|
|
390
|
-
|
|
390
|
+
// inject + quick-task + note acknowledged = 3 actions (defer still excluded)
|
|
391
|
+
assert.strictEqual(result.actions.length, 3, "should have 3 action entries (defer excluded, note now included)");
|
|
391
392
|
} finally {
|
|
392
393
|
rmSync(tmp, { recursive: true, force: true });
|
|
393
394
|
}
|