gsd-pi 2.70.1 → 2.71.0-dev.246c32d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -17
- package/dist/cli.js +29 -3
- package/dist/headless-events.d.ts +2 -0
- package/dist/headless-events.js +7 -0
- package/dist/headless.js +16 -3
- package/dist/mcp-server.js +40 -17
- package/dist/provider-migrations.d.ts +10 -0
- package/dist/provider-migrations.js +12 -0
- package/dist/resource-loader.js +139 -13
- package/dist/resources/GSD-WORKFLOW.md +1 -1
- package/dist/resources/agents/debugger.md +58 -0
- package/dist/resources/agents/doc-writer.md +43 -0
- package/dist/resources/agents/git-ops.md +56 -0
- package/dist/resources/agents/javascript-pro.md +46 -271
- package/dist/resources/agents/planner.md +55 -0
- package/dist/resources/agents/refactorer.md +47 -0
- package/dist/resources/agents/reviewer.md +48 -0
- package/dist/resources/agents/security.md +59 -0
- package/dist/resources/agents/tester.md +50 -0
- package/dist/resources/agents/typescript-pro.md +41 -235
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +242 -40
- package/dist/resources/extensions/get-secrets-from-user.js +17 -1
- package/dist/resources/extensions/gsd/auto/infra-errors.js +34 -0
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +5 -1
- package/dist/resources/extensions/gsd/auto/session.js +11 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +22 -16
- package/dist/resources/extensions/gsd/auto-model-selection.js +10 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +88 -33
- package/dist/resources/extensions/gsd/auto-start.js +37 -18
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +56 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +6 -0
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +63 -51
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -0
- package/dist/resources/extensions/gsd/commands/context.js +15 -6
- package/dist/resources/extensions/gsd/commands/dispatcher.js +12 -2
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -33
- package/dist/resources/extensions/gsd/commands/handlers/core.js +56 -11
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +15 -6
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +4 -10
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +16 -12
- package/dist/resources/extensions/gsd/dashboard-overlay.js +8 -3
- package/dist/resources/extensions/gsd/dispatch-guard.js +18 -1
- package/dist/resources/extensions/gsd/doctor-providers.js +23 -0
- package/dist/resources/extensions/gsd/error-classifier.js +5 -2
- package/dist/resources/extensions/gsd/file-lock.js +60 -0
- package/dist/resources/extensions/gsd/forensics.js +19 -6
- package/dist/resources/extensions/gsd/gate-registry.js +208 -0
- package/dist/resources/extensions/gsd/gsd-db.js +41 -0
- package/dist/resources/extensions/gsd/guided-flow.js +17 -20
- package/dist/resources/extensions/gsd/init-wizard.js +3 -11
- package/dist/resources/extensions/gsd/metrics.js +1 -0
- package/dist/resources/extensions/gsd/milestone-actions.js +10 -4
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +11 -12
- package/dist/resources/extensions/gsd/notification-overlay.js +42 -13
- package/dist/resources/extensions/gsd/notification-store.js +56 -5
- package/dist/resources/extensions/gsd/notification-widget.js +5 -13
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +8 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -2
- package/dist/resources/extensions/gsd/prompt-validation.js +126 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +5 -3
- package/dist/resources/extensions/gsd/prompts/discuss.md +33 -13
- package/dist/resources/extensions/gsd/prompts/execute-task.md +22 -19
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +3 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +4 -1
- package/dist/resources/extensions/gsd/session-model-override.js +25 -0
- package/dist/resources/extensions/gsd/shortcut-defs.js +40 -0
- package/dist/resources/extensions/gsd/state.js +241 -332
- package/dist/resources/extensions/gsd/tools/complete-slice.js +52 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +51 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +38 -1
- package/dist/resources/extensions/gsd/workflow-events.js +25 -13
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +56 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +1 -1
- package/dist/resources/extensions/ollama/index.js +13 -5
- package/dist/resources/extensions/shared/gsd-phase-state.js +35 -0
- package/dist/resources/extensions/subagent/agents.js +8 -0
- package/dist/resources/extensions/subagent/index.js +17 -0
- package/dist/resources/skills/create-skill/SKILL.md +2 -0
- package/dist/startup-model-validation.d.ts +0 -1
- package/dist/startup-model-validation.js +6 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +2 -2
- 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 +19 -19
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2826.dd3dc8bbd3025fa5.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-f1e30ab6bb269149.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-6e4d7e9a4f57bed4.js → webpack-b868033a5834586d.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/mcp-server/dist/env-writer.d.ts +39 -0
- package/packages/mcp-server/dist/env-writer.d.ts.map +1 -0
- package/packages/mcp-server/dist/env-writer.js +158 -0
- package/packages/mcp-server/dist/env-writer.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +23 -3
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +192 -44
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -12
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/env-writer.test.ts +280 -0
- package/packages/mcp-server/src/env-writer.ts +183 -0
- package/packages/mcp-server/src/secure-env-collect.test.ts +265 -0
- package/packages/mcp-server/src/server.ts +247 -41
- package/packages/mcp-server/src/workflow-tools.test.ts +110 -0
- package/packages/mcp-server/src/workflow-tools.ts +32 -12
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +11 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +20 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +4 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +8 -3
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js +44 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts +2 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +7 -4
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +11 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/src/providers/amazon-bedrock.ts +13 -1
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +32 -0
- package/packages/pi-ai/src/providers/anthropic-shared.test.ts +55 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +14 -3
- package/packages/pi-ai/src/providers/anthropic.ts +8 -4
- package/packages/pi-ai/src/providers/openai-completions.ts +14 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js +61 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +2 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +27 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +85 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +388 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js +64 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +22 -18
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js +75 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +55 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +57 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +38 -5
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.js +71 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +19 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +50 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +24 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +4 -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 +43 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +175 -25
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +6 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
- 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 +62 -5
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +4 -2
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.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/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-renderable-tools.test.ts +70 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +2 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +108 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +468 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
- package/packages/pi-coding-agent/src/core/model-resolver-initial-model-auth.test.ts +78 -0
- package/packages/pi-coding-agent/src/core/model-resolver.test.ts +85 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +22 -18
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +83 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +60 -1
- package/packages/pi-coding-agent/src/core/sdk.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +45 -9
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/login-dialog.test.ts +24 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +58 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +30 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +15 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +47 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +205 -31
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +6 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +70 -5
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +4 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +1 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js +9 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +66 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -0
- package/packages/pi-tui/dist/components/input.d.ts +2 -0
- package/packages/pi-tui/dist/components/input.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/input.js +7 -4
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/components/markdown.d.ts +3 -0
- package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/markdown.js +17 -1
- package/packages/pi-tui/dist/components/markdown.js.map +1 -1
- package/packages/pi-tui/src/components/__tests__/input.test.ts +11 -0
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +75 -0
- package/packages/pi-tui/src/components/input.ts +7 -4
- package/packages/pi-tui/src/components/markdown.ts +22 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +1 -1
- package/src/resources/agents/debugger.md +58 -0
- package/src/resources/agents/doc-writer.md +43 -0
- package/src/resources/agents/git-ops.md +56 -0
- package/src/resources/agents/javascript-pro.md +46 -271
- package/src/resources/agents/planner.md +55 -0
- package/src/resources/agents/refactorer.md +47 -0
- package/src/resources/agents/reviewer.md +48 -0
- package/src/resources/agents/security.md +59 -0
- package/src/resources/agents/tester.md +50 -0
- package/src/resources/agents/typescript-pro.md +41 -235
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +288 -39
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +330 -2
- package/src/resources/extensions/get-secrets-from-user.ts +24 -1
- package/src/resources/extensions/gsd/auto/infra-errors.ts +38 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop.ts +45 -1
- package/src/resources/extensions/gsd/auto/phases.ts +6 -0
- package/src/resources/extensions/gsd/auto/session.ts +11 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +29 -18
- package/src/resources/extensions/gsd/auto-model-selection.ts +9 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +111 -33
- package/src/resources/extensions/gsd/auto-start.ts +44 -20
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +72 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +79 -60
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +7 -0
- package/src/resources/extensions/gsd/commands/context.ts +16 -5
- package/src/resources/extensions/gsd/commands/dispatcher.ts +14 -2
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +10 -36
- package/src/resources/extensions/gsd/commands/handlers/core.ts +58 -11
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +17 -7
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +4 -10
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +19 -14
- package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +18 -1
- package/src/resources/extensions/gsd/doctor-providers.ts +24 -0
- package/src/resources/extensions/gsd/error-classifier.ts +5 -2
- package/src/resources/extensions/gsd/file-lock.ts +59 -0
- package/src/resources/extensions/gsd/forensics.ts +23 -7
- package/src/resources/extensions/gsd/gate-registry.ts +251 -0
- package/src/resources/extensions/gsd/gsd-db.ts +51 -0
- package/src/resources/extensions/gsd/guided-flow.ts +17 -19
- package/src/resources/extensions/gsd/init-wizard.ts +3 -13
- package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
- package/src/resources/extensions/gsd/metrics.ts +12 -1
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -3
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +11 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +47 -14
- package/src/resources/extensions/gsd/notification-store.ts +54 -5
- package/src/resources/extensions/gsd/notification-widget.ts +5 -14
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -3
- package/src/resources/extensions/gsd/pre-execution-checks.ts +39 -2
- package/src/resources/extensions/gsd/prompt-validation.ts +157 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +5 -3
- package/src/resources/extensions/gsd/prompts/discuss.md +33 -13
- package/src/resources/extensions/gsd/prompts/execute-task.md +22 -19
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +3 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +4 -1
- package/src/resources/extensions/gsd/session-model-override.ts +36 -0
- package/src/resources/extensions/gsd/shortcut-defs.ts +56 -0
- package/src/resources/extensions/gsd/state.ts +285 -344
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +25 -9
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/complete-slice-gate-closure.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/complete-slice-prompt-task-summary-layout.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/execute-task-prompt-existing-artifact-guard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/file-lock.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/gate-registry.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +66 -1
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +36 -51
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/prompt-system-gate-coverage.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +63 -5
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/session-model-override.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +155 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +22 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +63 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +63 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +64 -26
- package/src/resources/extensions/gsd/types.ts +26 -0
- package/src/resources/extensions/gsd/workflow-events.ts +34 -25
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +76 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +1 -1
- package/src/resources/extensions/ollama/index.ts +13 -3
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +28 -0
- package/src/resources/extensions/shared/gsd-phase-state.ts +42 -0
- package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +48 -0
- package/src/resources/extensions/subagent/agents.ts +10 -0
- package/src/resources/extensions/subagent/index.ts +18 -0
- package/src/resources/extensions/subagent/tests/agents-conflicts.test.ts +33 -0
- package/src/resources/skills/create-skill/SKILL.md +2 -0
- package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.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/{9pw9EXtXjdM7EFrCXUEPf → hnGGkVMxIGGpxSJkf5jIV}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{9pw9EXtXjdM7EFrCXUEPf → hnGGkVMxIGGpxSJkf5jIV}/_ssgManifest.js +0 -0
|
@@ -101,3 +101,65 @@ test("#1943 detectStuckLoops ignores watchdog duplicates but flags real re-dispa
|
|
|
101
101
|
assert.equal(anomalies.length, 1, `expected 1 anomaly (for the 3x dispatched task), got ${anomalies.length}`);
|
|
102
102
|
assert.ok(anomalies[0].summary.includes("3 times"));
|
|
103
103
|
});
|
|
104
|
+
|
|
105
|
+
test("#3760 detectStuckLoops ignores cross-session recovery re-dispatches", () => {
|
|
106
|
+
const anomalies: ForensicAnomaly[] = [];
|
|
107
|
+
|
|
108
|
+
const units: UnitMetrics[] = [
|
|
109
|
+
makeUnit({
|
|
110
|
+
type: "plan-slice",
|
|
111
|
+
id: "M001/S02",
|
|
112
|
+
startedAt: 1000,
|
|
113
|
+
finishedAt: 2000,
|
|
114
|
+
autoSessionKey: "session-a",
|
|
115
|
+
}),
|
|
116
|
+
makeUnit({
|
|
117
|
+
type: "plan-slice",
|
|
118
|
+
id: "M001/S02",
|
|
119
|
+
startedAt: 5000,
|
|
120
|
+
finishedAt: 6000,
|
|
121
|
+
autoSessionKey: "session-b",
|
|
122
|
+
}),
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
detectStuckLoops(units, anomalies);
|
|
126
|
+
|
|
127
|
+
assert.equal(anomalies.length, 0, "cross-session recovery should not be flagged as a stuck loop");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("#3760 detectStuckLoops still flags repeated dispatches within one auto session", () => {
|
|
131
|
+
const anomalies: ForensicAnomaly[] = [];
|
|
132
|
+
|
|
133
|
+
const units: UnitMetrics[] = [
|
|
134
|
+
makeUnit({
|
|
135
|
+
type: "complete-slice",
|
|
136
|
+
id: "M011/S02",
|
|
137
|
+
startedAt: 1000,
|
|
138
|
+
finishedAt: 2000,
|
|
139
|
+
autoSessionKey: "session-a",
|
|
140
|
+
}),
|
|
141
|
+
makeUnit({
|
|
142
|
+
type: "complete-slice",
|
|
143
|
+
id: "M011/S02",
|
|
144
|
+
startedAt: 5000,
|
|
145
|
+
finishedAt: 6000,
|
|
146
|
+
autoSessionKey: "session-a",
|
|
147
|
+
}),
|
|
148
|
+
makeUnit({
|
|
149
|
+
type: "complete-slice",
|
|
150
|
+
id: "M011/S02",
|
|
151
|
+
startedAt: 9000,
|
|
152
|
+
finishedAt: 10000,
|
|
153
|
+
autoSessionKey: "session-b",
|
|
154
|
+
}),
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
detectStuckLoops(units, anomalies);
|
|
158
|
+
|
|
159
|
+
assert.equal(anomalies.length, 1, "within-session retries should still be flagged");
|
|
160
|
+
assert.ok(anomalies[0].summary.includes("2 times"), `summary should reflect the worst same-session loop: ${anomalies[0].summary}`);
|
|
161
|
+
assert.ok(
|
|
162
|
+
anomalies[0].details.includes("Cross-session recovery runs are ignored"),
|
|
163
|
+
`details should explain the session-aware rule: ${anomalies[0].details}`,
|
|
164
|
+
);
|
|
165
|
+
});
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import test from 'node:test';
|
|
5
5
|
import assert from 'node:assert/strict';
|
|
6
6
|
import { formatShortcut } from '../files.ts';
|
|
7
|
+
import { formattedShortcutPair, primaryShortcutCombo, fallbackShortcutCombo } from '../shortcut-defs.ts';
|
|
7
8
|
|
|
8
9
|
// ─── formatShortcut renders per-platform shortcuts ──────────────────────
|
|
9
10
|
|
|
@@ -67,3 +68,33 @@ test('formatShortcut: passes through plain key names', () => {
|
|
|
67
68
|
assert.strictEqual(formatShortcut('Escape'), 'Escape');
|
|
68
69
|
assert.strictEqual(formatShortcut('Enter'), 'Enter');
|
|
69
70
|
});
|
|
71
|
+
|
|
72
|
+
test("shortcut-defs: exposes canonical dashboard combos", () => {
|
|
73
|
+
assert.equal(primaryShortcutCombo("dashboard"), "Ctrl+Alt+G");
|
|
74
|
+
assert.equal(fallbackShortcutCombo("dashboard"), "Ctrl+Shift+G");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("shortcut-defs: formats shortcut pair using platform symbols", () => {
|
|
78
|
+
const pair = formattedShortcutPair("notifications");
|
|
79
|
+
if (process.platform === "darwin") {
|
|
80
|
+
assert.equal(pair, "⌃⌥N / ⌃⇧N");
|
|
81
|
+
} else {
|
|
82
|
+
assert.equal(pair, "Ctrl+Alt+N / Ctrl+Shift+N");
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("shortcut-defs: parallel shortcut omits fallback (hasFallback: false)", () => {
|
|
87
|
+
const pair = formattedShortcutPair("parallel");
|
|
88
|
+
if (process.platform === "darwin") {
|
|
89
|
+
assert.equal(pair, "⌃⌥P", "parallel should only show primary combo");
|
|
90
|
+
} else {
|
|
91
|
+
assert.equal(pair, "Ctrl+Alt+P", "parallel should only show primary combo");
|
|
92
|
+
}
|
|
93
|
+
// Verify it does NOT contain the fallback separator
|
|
94
|
+
assert.ok(!pair.includes("/"), "parallel pair should not contain fallback separator");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("shortcut-defs: dashboard shortcut includes fallback (hasFallback: true)", () => {
|
|
98
|
+
const pair = formattedShortcutPair("dashboard");
|
|
99
|
+
assert.ok(pair.includes("/"), "dashboard pair should contain fallback separator");
|
|
100
|
+
});
|
|
@@ -186,4 +186,31 @@ describe("evaluating-gates phase", () => {
|
|
|
186
186
|
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q5", scope: "task", taskId: "T01" });
|
|
187
187
|
assert.equal(getPendingSliceGateCount("M001", "S01"), 1);
|
|
188
188
|
});
|
|
189
|
+
|
|
190
|
+
test("Q8 (owned by complete-slice) does not block evaluating-gates phase", async () => {
|
|
191
|
+
// Regression: Q8 is stored with scope:"slice" but owned by the
|
|
192
|
+
// complete-slice turn. Before the gate registry landed, deriveState
|
|
193
|
+
// counted Q8 as a blocker for evaluating-gates while the gate-evaluate
|
|
194
|
+
// prompt silently dropped Q8 — an unrecoverable stall. After the
|
|
195
|
+
// registry change, deriveState filters by owner turn, so Q8 never
|
|
196
|
+
// blocks evaluating-gates.
|
|
197
|
+
planSlice(tmpDir);
|
|
198
|
+
await renderPlanFromDb(tmpDir, "M001", "S01");
|
|
199
|
+
|
|
200
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
201
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
|
|
202
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q8", scope: "slice" });
|
|
203
|
+
|
|
204
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", verdict: "pass", rationale: "OK", findings: "" });
|
|
205
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", verdict: "omitted", rationale: "N/A", findings: "" });
|
|
206
|
+
// Q8 deliberately left pending — it's complete-slice's problem.
|
|
207
|
+
|
|
208
|
+
invalidateStateCache();
|
|
209
|
+
const state = await deriveState(tmpDir);
|
|
210
|
+
assert.equal(
|
|
211
|
+
state.phase,
|
|
212
|
+
"executing",
|
|
213
|
+
`pending Q8 must not stall evaluating-gates — got phase=${state.phase}`,
|
|
214
|
+
);
|
|
215
|
+
});
|
|
189
216
|
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate registry tests — enforce that every declared GateId has a registry
|
|
3
|
+
* entry, that every owner-turn bucket is non-empty, and that coverage
|
|
4
|
+
* assertions fail loudly instead of silently skipping unknown gates.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, test } from "node:test";
|
|
8
|
+
import assert from "node:assert/strict";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
GATE_REGISTRY,
|
|
12
|
+
assertGateCoverage,
|
|
13
|
+
getGateDefinition,
|
|
14
|
+
getGateIdsForTurn,
|
|
15
|
+
getGatesForTurn,
|
|
16
|
+
getOwnerTurn,
|
|
17
|
+
type OwnerTurn,
|
|
18
|
+
} from "../gate-registry.ts";
|
|
19
|
+
import type { GateId } from "../types.ts";
|
|
20
|
+
|
|
21
|
+
/** Authoritative list of GateIds as declared in types.ts. */
|
|
22
|
+
const ALL_GATE_IDS: readonly GateId[] = [
|
|
23
|
+
"Q3", "Q4", "Q5", "Q6", "Q7", "Q8",
|
|
24
|
+
"MV01", "MV02", "MV03", "MV04",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const ALL_OWNER_TURNS: readonly OwnerTurn[] = [
|
|
28
|
+
"gate-evaluate",
|
|
29
|
+
"execute-task",
|
|
30
|
+
"complete-slice",
|
|
31
|
+
"validate-milestone",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
describe("gate-registry", () => {
|
|
35
|
+
test("every declared GateId has a registry entry", () => {
|
|
36
|
+
for (const id of ALL_GATE_IDS) {
|
|
37
|
+
const def = GATE_REGISTRY[id];
|
|
38
|
+
assert.ok(def, `missing registry entry for gate ${id}`);
|
|
39
|
+
assert.equal(def.id, id);
|
|
40
|
+
assert.ok(def.question.length > 0, `${id} missing question`);
|
|
41
|
+
assert.ok(def.guidance.length > 0, `${id} missing guidance`);
|
|
42
|
+
assert.ok(def.promptSection.length > 0, `${id} missing promptSection`);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("registry contains no extra gate entries", () => {
|
|
47
|
+
const registryIds = new Set(Object.keys(GATE_REGISTRY));
|
|
48
|
+
const declaredIds = new Set<string>(ALL_GATE_IDS);
|
|
49
|
+
for (const id of registryIds) {
|
|
50
|
+
assert.ok(declaredIds.has(id), `registry has unknown gate ${id}`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("every owner turn owns at least one gate", () => {
|
|
55
|
+
for (const turn of ALL_OWNER_TURNS) {
|
|
56
|
+
const gates = getGatesForTurn(turn);
|
|
57
|
+
assert.ok(
|
|
58
|
+
gates.length > 0,
|
|
59
|
+
`owner turn "${turn}" has no gates — likely a registry mistake`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("owner turn buckets are disjoint", () => {
|
|
65
|
+
const seen = new Set<string>();
|
|
66
|
+
for (const turn of ALL_OWNER_TURNS) {
|
|
67
|
+
for (const def of getGatesForTurn(turn)) {
|
|
68
|
+
assert.ok(!seen.has(def.id), `gate ${def.id} claimed by two turns`);
|
|
69
|
+
seen.add(def.id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Every gate should appear in exactly one bucket.
|
|
73
|
+
assert.equal(seen.size, ALL_GATE_IDS.length);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("getOwnerTurn round-trips against GATE_REGISTRY", () => {
|
|
77
|
+
for (const id of ALL_GATE_IDS) {
|
|
78
|
+
const turn = getOwnerTurn(id);
|
|
79
|
+
const idsForTurn = getGateIdsForTurn(turn);
|
|
80
|
+
assert.ok(idsForTurn.has(id), `${id} not in ${turn} bucket`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("getGateDefinition returns undefined for unknown ids", () => {
|
|
85
|
+
assert.equal(getGateDefinition("Q99"), undefined);
|
|
86
|
+
assert.equal(getGateDefinition("not-a-gate"), undefined);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("assertGateCoverage", () => {
|
|
91
|
+
test("throws when a row is owned by a different turn", () => {
|
|
92
|
+
// Q8 is owned by complete-slice, not gate-evaluate — this used to be
|
|
93
|
+
// silently dropped by the old `if (!meta) continue;` filter, causing
|
|
94
|
+
// the evaluating-gates phase to stall.
|
|
95
|
+
assert.throws(
|
|
96
|
+
() => assertGateCoverage([{ gate_id: "Q8" }], "gate-evaluate"),
|
|
97
|
+
(err: Error) =>
|
|
98
|
+
err.message.includes("Q8") && err.message.includes("gate-evaluate"),
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("throws when a row has an unknown gate id", () => {
|
|
103
|
+
assert.throws(
|
|
104
|
+
() => assertGateCoverage([{ gate_id: "Q999" as GateId }], "gate-evaluate", { requireAll: false }),
|
|
105
|
+
(err: Error) => err.message.includes("Q999"),
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("throws when requireAll is true and an owned gate is missing", () => {
|
|
110
|
+
// gate-evaluate owns Q3 and Q4. Passing only Q3 should fail.
|
|
111
|
+
assert.throws(
|
|
112
|
+
() => assertGateCoverage([{ gate_id: "Q3" }], "gate-evaluate", { requireAll: true }),
|
|
113
|
+
(err: Error) => err.message.includes("Q4"),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("passes when requireAll is false and only a subset is pending", () => {
|
|
118
|
+
// execute-task owns Q5/Q6/Q7, but a task with no external dependencies
|
|
119
|
+
// may only have Q7 seeded. That's still valid coverage.
|
|
120
|
+
assert.doesNotThrow(() =>
|
|
121
|
+
assertGateCoverage([{ gate_id: "Q7" }], "execute-task", { requireAll: false }),
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("passes when requireAll is true and every owned gate is pending", () => {
|
|
126
|
+
assert.doesNotThrow(() =>
|
|
127
|
+
assertGateCoverage(
|
|
128
|
+
[{ gate_id: "Q3" }, { gate_id: "Q4" }],
|
|
129
|
+
"gate-evaluate",
|
|
130
|
+
{ requireAll: true },
|
|
131
|
+
),
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("empty pending list passes when requireAll is false", () => {
|
|
136
|
+
assert.doesNotThrow(() =>
|
|
137
|
+
assertGateCoverage([], "complete-slice", { requireAll: false }),
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSDNoProjectError — tests for friendly home-directory error handling.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that GSDNoProjectError is thrown for blocked directories and
|
|
5
|
+
* that the dispatcher catches it with a user-friendly message.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { join, dirname } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
|
|
16
|
+
const contextSrc = readFileSync(join(__dirname, "..", "commands", "context.ts"), "utf-8");
|
|
17
|
+
const dispatcherSrc = readFileSync(join(__dirname, "..", "commands", "dispatcher.ts"), "utf-8");
|
|
18
|
+
|
|
19
|
+
// ─── GSDNoProjectError class ──────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
test("GSDNoProjectError class is exported from context.ts", () => {
|
|
22
|
+
assert.ok(
|
|
23
|
+
contextSrc.includes("export class GSDNoProjectError extends Error"),
|
|
24
|
+
"GSDNoProjectError should be an exported Error subclass",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("GSDNoProjectError sets name property", () => {
|
|
29
|
+
assert.ok(
|
|
30
|
+
contextSrc.includes('this.name = "GSDNoProjectError"'),
|
|
31
|
+
"GSDNoProjectError should set its name for instanceof checks",
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// ─── projectRoot blocked directory handling ───────────────────────────────
|
|
36
|
+
|
|
37
|
+
test("projectRoot uses validateDirectory and checks for blocked severity", () => {
|
|
38
|
+
assert.ok(
|
|
39
|
+
contextSrc.includes("validateDirectory(pathToCheck)"),
|
|
40
|
+
"projectRoot should call validateDirectory",
|
|
41
|
+
);
|
|
42
|
+
assert.ok(
|
|
43
|
+
contextSrc.includes('result.severity === "blocked"'),
|
|
44
|
+
"projectRoot should check for blocked severity",
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("projectRoot throws GSDNoProjectError on blocked directory", () => {
|
|
49
|
+
assert.ok(
|
|
50
|
+
contextSrc.includes("throw new GSDNoProjectError"),
|
|
51
|
+
"projectRoot should throw GSDNoProjectError when directory is blocked",
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ─── Dispatcher catch ─────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
test("dispatcher catches GSDNoProjectError with user-friendly message", () => {
|
|
58
|
+
assert.ok(
|
|
59
|
+
dispatcherSrc.includes("err instanceof GSDNoProjectError"),
|
|
60
|
+
"dispatcher should catch GSDNoProjectError specifically",
|
|
61
|
+
);
|
|
62
|
+
assert.ok(
|
|
63
|
+
dispatcherSrc.includes("cd"),
|
|
64
|
+
"error message should suggest cd-ing into a project directory",
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("dispatcher re-throws non-GSDNoProjectError exceptions", () => {
|
|
69
|
+
assert.ok(
|
|
70
|
+
dispatcherSrc.includes("throw err"),
|
|
71
|
+
"dispatcher should re-throw unexpected errors",
|
|
72
|
+
);
|
|
73
|
+
});
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// gsd / infra-errors cooldown detection tests
|
|
2
|
+
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
3
|
+
|
|
4
|
+
import test, { describe } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
isTransientCooldownError,
|
|
9
|
+
getCooldownRetryAfterMs,
|
|
10
|
+
MAX_COOLDOWN_RETRIES,
|
|
11
|
+
COOLDOWN_FALLBACK_WAIT_MS,
|
|
12
|
+
} from "../auto/infra-errors.js";
|
|
13
|
+
|
|
14
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
describe("infra-errors cooldown constants", () => {
|
|
17
|
+
test("COOLDOWN_FALLBACK_WAIT_MS is a positive number greater than the 30s rate-limit backoff", () => {
|
|
18
|
+
assert.ok(typeof COOLDOWN_FALLBACK_WAIT_MS === "number");
|
|
19
|
+
assert.ok(COOLDOWN_FALLBACK_WAIT_MS > 30_000, "should exceed the 30s rate-limit window");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("MAX_COOLDOWN_RETRIES is a positive integer", () => {
|
|
23
|
+
assert.ok(typeof MAX_COOLDOWN_RETRIES === "number");
|
|
24
|
+
assert.ok(Number.isInteger(MAX_COOLDOWN_RETRIES));
|
|
25
|
+
assert.ok(MAX_COOLDOWN_RETRIES > 0);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("COOLDOWN_FALLBACK_WAIT_MS is 35_000", () => {
|
|
29
|
+
assert.equal(COOLDOWN_FALLBACK_WAIT_MS, 35_000);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("MAX_COOLDOWN_RETRIES is 5", () => {
|
|
33
|
+
assert.equal(MAX_COOLDOWN_RETRIES, 5);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// ─── isTransientCooldownError: structured detection ──────────────────────────
|
|
38
|
+
|
|
39
|
+
describe("isTransientCooldownError — structured code detection", () => {
|
|
40
|
+
test("returns true for an object with code === AUTH_COOLDOWN", () => {
|
|
41
|
+
const err = { code: "AUTH_COOLDOWN", message: "credentials in cooldown" };
|
|
42
|
+
assert.equal(isTransientCooldownError(err), true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("returns true for a real CredentialCooldownError-shaped error", () => {
|
|
46
|
+
// Simulate CredentialCooldownError without importing sdk.ts (leaf-module rule)
|
|
47
|
+
const err = Object.assign(new Error('All credentials for "anthropic" are in a cooldown window.'), {
|
|
48
|
+
code: "AUTH_COOLDOWN",
|
|
49
|
+
retryAfterMs: 30_000,
|
|
50
|
+
name: "CredentialCooldownError",
|
|
51
|
+
});
|
|
52
|
+
assert.equal(isTransientCooldownError(err), true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("returns false for an object with a different code", () => {
|
|
56
|
+
const err = { code: "ENOSPC", message: "disk full" };
|
|
57
|
+
assert.equal(isTransientCooldownError(err), false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("returns false for an object with no code property", () => {
|
|
61
|
+
const err = { message: "some random error" };
|
|
62
|
+
assert.equal(isTransientCooldownError(err), false);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// ─── isTransientCooldownError: message fallback ───────────────────────────────
|
|
67
|
+
|
|
68
|
+
describe("isTransientCooldownError — message fallback (cross-process)", () => {
|
|
69
|
+
test("returns true when message contains 'in a cooldown window'", () => {
|
|
70
|
+
const err = new Error('All credentials for "openai" are in a cooldown window. Please wait.');
|
|
71
|
+
assert.equal(isTransientCooldownError(err), true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("returns true when message matches case-insensitively", () => {
|
|
75
|
+
const err = new Error("credentials IN A COOLDOWN WINDOW");
|
|
76
|
+
assert.equal(isTransientCooldownError(err), true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("returns true for a plain string containing cooldown window phrase", () => {
|
|
80
|
+
assert.equal(isTransientCooldownError("all keys in a cooldown window"), true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("returns false for a generic error message", () => {
|
|
84
|
+
const err = new Error("rate limit exceeded");
|
|
85
|
+
assert.equal(isTransientCooldownError(err), false);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("returns false for an error message about auth failure without cooldown phrase", () => {
|
|
89
|
+
const err = new Error("Authentication failed: invalid API key");
|
|
90
|
+
assert.equal(isTransientCooldownError(err), false);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// ─── isTransientCooldownError: edge cases ────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
describe("isTransientCooldownError — edge cases", () => {
|
|
97
|
+
test("returns false for null", () => {
|
|
98
|
+
assert.equal(isTransientCooldownError(null), false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("returns false for undefined", () => {
|
|
102
|
+
assert.equal(isTransientCooldownError(undefined), false);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("returns false for a number", () => {
|
|
106
|
+
assert.equal(isTransientCooldownError(42), false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("returns false for an empty object", () => {
|
|
110
|
+
assert.equal(isTransientCooldownError({}), false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("returns false for an object with code === AUTH_COOLDOWN as a non-string", () => {
|
|
114
|
+
// code must be a string matching "AUTH_COOLDOWN" exactly
|
|
115
|
+
const err = { code: 42 };
|
|
116
|
+
assert.equal(isTransientCooldownError(err), false);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// ─── getCooldownRetryAfterMs: structured extraction ──────────────────────────
|
|
121
|
+
|
|
122
|
+
describe("getCooldownRetryAfterMs — structured extraction", () => {
|
|
123
|
+
test("returns retryAfterMs when code is AUTH_COOLDOWN and retryAfterMs is set", () => {
|
|
124
|
+
const err = { code: "AUTH_COOLDOWN", retryAfterMs: 30_000 };
|
|
125
|
+
assert.equal(getCooldownRetryAfterMs(err), 30_000);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("returns undefined when code is AUTH_COOLDOWN but retryAfterMs is absent", () => {
|
|
129
|
+
const err = { code: "AUTH_COOLDOWN" };
|
|
130
|
+
assert.equal(getCooldownRetryAfterMs(err), undefined);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("returns 0 when retryAfterMs is explicitly 0", () => {
|
|
134
|
+
const err = { code: "AUTH_COOLDOWN", retryAfterMs: 0 };
|
|
135
|
+
assert.equal(getCooldownRetryAfterMs(err), 0);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("returns undefined for an error with a different code even if retryAfterMs is set", () => {
|
|
139
|
+
const err = { code: "ENOSPC", retryAfterMs: 5_000 };
|
|
140
|
+
assert.equal(getCooldownRetryAfterMs(err), undefined);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("returns undefined for a plain Error with no code property", () => {
|
|
144
|
+
const err = new Error("something went wrong");
|
|
145
|
+
assert.equal(getCooldownRetryAfterMs(err), undefined);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("returns retryAfterMs from a full CredentialCooldownError-shaped object", () => {
|
|
149
|
+
const err = Object.assign(new Error('All credentials for "anthropic" are in a cooldown window.'), {
|
|
150
|
+
code: "AUTH_COOLDOWN",
|
|
151
|
+
retryAfterMs: 15_000,
|
|
152
|
+
name: "CredentialCooldownError",
|
|
153
|
+
});
|
|
154
|
+
assert.equal(getCooldownRetryAfterMs(err), 15_000);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// ─── getCooldownRetryAfterMs: edge cases ─────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
describe("getCooldownRetryAfterMs — edge cases", () => {
|
|
161
|
+
test("returns undefined for null", () => {
|
|
162
|
+
assert.equal(getCooldownRetryAfterMs(null), undefined);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("returns undefined for undefined", () => {
|
|
166
|
+
assert.equal(getCooldownRetryAfterMs(undefined), undefined);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("returns undefined for a plain string", () => {
|
|
170
|
+
assert.equal(getCooldownRetryAfterMs("AUTH_COOLDOWN"), undefined);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("returns undefined for an empty object", () => {
|
|
174
|
+
assert.equal(getCooldownRetryAfterMs({}), undefined);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("returns undefined for a number", () => {
|
|
178
|
+
assert.equal(getCooldownRetryAfterMs(42), undefined);
|
|
179
|
+
});
|
|
180
|
+
});
|
package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { describe, test, afterEach } from "node:test";
|
|
14
14
|
import assert from "node:assert/strict";
|
|
15
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync, readFileSync } from "node:fs";
|
|
15
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync, readFileSync, symlinkSync, unlinkSync } from "node:fs";
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
import { tmpdir } from "node:os";
|
|
18
18
|
import { execSync } from "node:child_process";
|
|
@@ -44,6 +44,27 @@ function createTempRepo(): string {
|
|
|
44
44
|
return dir;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function createTempRepoWithExternalGsd(): { repo: string; externalState: string } {
|
|
48
|
+
const realTmp = realpathSync(tmpdir());
|
|
49
|
+
const repo = realpathSync(mkdtempSync(join(realTmp, "wt-ms-merge-ext-test-")));
|
|
50
|
+
const externalState = realpathSync(mkdtempSync(join(realTmp, "wt-ms-merge-ext-state-")));
|
|
51
|
+
|
|
52
|
+
run("git init", repo);
|
|
53
|
+
run("git config user.email test@test.com", repo);
|
|
54
|
+
run("git config user.name Test", repo);
|
|
55
|
+
|
|
56
|
+
mkdirSync(join(externalState, "worktrees"), { recursive: true });
|
|
57
|
+
symlinkSync(externalState, join(repo, ".gsd"));
|
|
58
|
+
|
|
59
|
+
writeFileSync(join(repo, "README.md"), "# test\n");
|
|
60
|
+
writeFileSync(join(externalState, "STATE.md"), "# State\n");
|
|
61
|
+
run("git add .", repo);
|
|
62
|
+
run("git commit -m init", repo);
|
|
63
|
+
run("git branch -M main", repo);
|
|
64
|
+
|
|
65
|
+
return { repo, externalState };
|
|
66
|
+
}
|
|
67
|
+
|
|
47
68
|
/** Minimal roadmap content for mergeMilestoneToMain. */
|
|
48
69
|
function makeRoadmap(milestoneId: string, title: string, slices: Array<{ id: string; title: string }>): string {
|
|
49
70
|
const sliceLines = slices.map(s => `- [x] **${s.id}: ${s.title}**`).join("\n");
|
|
@@ -87,6 +108,12 @@ describe("auto-worktree-milestone-merge", { timeout: 300_000 }, () => {
|
|
|
87
108
|
return d;
|
|
88
109
|
}
|
|
89
110
|
|
|
111
|
+
function freshRepoWithExternalGsd(): { repo: string; externalState: string } {
|
|
112
|
+
const { repo, externalState } = createTempRepoWithExternalGsd();
|
|
113
|
+
tempDirs.push(repo, externalState);
|
|
114
|
+
return { repo, externalState };
|
|
115
|
+
}
|
|
116
|
+
|
|
90
117
|
afterEach(() => {
|
|
91
118
|
process.chdir(savedCwd);
|
|
92
119
|
for (const d of tempDirs) {
|
|
@@ -638,6 +665,44 @@ describe("auto-worktree-milestone-merge", { timeout: 300_000 }, () => {
|
|
|
638
665
|
"#1906: codeFilesChanged must be false when only .gsd/ files were merged");
|
|
639
666
|
});
|
|
640
667
|
|
|
668
|
+
test("#2156: mergeMilestoneToMain removes external-state worktrees using the milestone branch name", () => {
|
|
669
|
+
const { repo, externalState } = freshRepoWithExternalGsd();
|
|
670
|
+
const wtPath = createAutoWorktree(repo, "M215");
|
|
671
|
+
|
|
672
|
+
addSliceToMilestone(repo, wtPath, "M215", "S01", "External cleanup", [
|
|
673
|
+
{ file: "external-cleanup.ts", content: "export const externalCleanup = true;\n", message: "add external cleanup" },
|
|
674
|
+
]);
|
|
675
|
+
|
|
676
|
+
const realWtPath = realpathSync(wtPath);
|
|
677
|
+
assert.ok(
|
|
678
|
+
realWtPath.startsWith(externalState),
|
|
679
|
+
`worktree should be registered under external .gsd state, got ${realWtPath}`,
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
// Recreate the exact divergence from #1852: local .gsd/ is replaced with a
|
|
683
|
+
// stale real directory, so worktreePath() no longer matches git's record.
|
|
684
|
+
unlinkSync(join(repo, ".gsd"));
|
|
685
|
+
mkdirSync(join(repo, ".gsd", "worktrees", "M215"), { recursive: true });
|
|
686
|
+
writeFileSync(join(repo, ".gsd", "STATE.md"), "# Local stale state\n");
|
|
687
|
+
writeFileSync(join(repo, ".gsd", "worktrees", "M215", "stale.txt"), "stale local artifact\n");
|
|
688
|
+
|
|
689
|
+
const roadmap = makeRoadmap("M215", "External cleanup", [
|
|
690
|
+
{ id: "S01", title: "External cleanup" },
|
|
691
|
+
]);
|
|
692
|
+
|
|
693
|
+
mergeMilestoneToMain(repo, "M215", roadmap);
|
|
694
|
+
|
|
695
|
+
assert.ok(
|
|
696
|
+
!run("git worktree list", repo).includes("M215"),
|
|
697
|
+
"merged milestone worktree should be removed from git worktree list",
|
|
698
|
+
);
|
|
699
|
+
assert.ok(!existsSync(realWtPath), "real external worktree directory should be removed");
|
|
700
|
+
assert.ok(
|
|
701
|
+
!run("git branch", repo).includes("milestone/M215"),
|
|
702
|
+
"milestone branch should be deleted after merge cleanup",
|
|
703
|
+
);
|
|
704
|
+
});
|
|
705
|
+
|
|
641
706
|
test("#2912: MERGE_HEAD cleaned up after squash-merge conflict", () => {
|
|
642
707
|
const repo = freshRepo();
|
|
643
708
|
const wtPath = createAutoWorktree(repo, "M291");
|