gsd-pi 2.76.0 → 2.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -25
- package/dist/claude-cli-check.js +32 -3
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.js +35 -1
- package/dist/onboarding.js +45 -0
- package/dist/resource-loader.d.ts +1 -1
- package/dist/resource-loader.js +2 -8
- package/dist/resources/agents/researcher.md +1 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
- package/dist/resources/extensions/gsd/auto/loop.js +9 -0
- package/dist/resources/extensions/gsd/auto/phases.js +104 -11
- package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
- package/dist/resources/extensions/gsd/auto/session.js +22 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
- package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
- package/dist/resources/extensions/gsd/auto-start.js +58 -57
- package/dist/resources/extensions/gsd/auto-verification.js +33 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
- package/dist/resources/extensions/gsd/auto.js +70 -28
- package/dist/resources/extensions/gsd/blocked-models.js +68 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
- package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
- package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
- package/dist/resources/extensions/gsd/db-writer.js +88 -16
- package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
- package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
- package/dist/resources/extensions/gsd/error-classifier.js +31 -3
- package/dist/resources/extensions/gsd/exec-history.js +120 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +168 -23
- package/dist/resources/extensions/gsd/guided-flow.js +190 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -1
- package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
- package/dist/resources/extensions/gsd/init-wizard.js +15 -1
- package/dist/resources/extensions/gsd/key-manager.js +28 -0
- package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
- package/dist/resources/extensions/gsd/memory-store.js +19 -0
- package/dist/resources/extensions/gsd/model-router.js +36 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
- package/dist/resources/extensions/gsd/preferences-types.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
- package/dist/resources/extensions/gsd/preferences.js +17 -17
- package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
- package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
- package/dist/resources/extensions/gsd/state.js +43 -4
- package/dist/resources/extensions/gsd/token-counter.js +22 -5
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
- package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
- package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
- package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
- package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
- package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
- package/dist/resources/extensions/search-the-web/native-search.js +45 -13
- package/dist/resources/skills/api-design/SKILL.md +190 -0
- package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
- package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
- package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
- package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
- package/dist/resources/skills/forensics/SKILL.md +153 -0
- package/dist/resources/skills/grill-me/SKILL.md +93 -0
- package/dist/resources/skills/handoff/SKILL.md +121 -0
- package/dist/resources/skills/observability/SKILL.md +174 -0
- package/dist/resources/skills/security-review/SKILL.md +181 -0
- package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
- package/dist/resources/skills/tdd/SKILL.md +112 -0
- package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
- package/dist/resources/skills/write-docs/SKILL.md +82 -0
- package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/required-server-files.json +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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-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/server.js +1 -1
- package/dist/welcome-screen.js +6 -1
- package/dist/wizard.js +2 -0
- package/package.json +1 -1
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
- package/packages/mcp-server/dist/remote-questions.js +732 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +7 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +70 -8
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.d.ts +14 -0
- package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +49 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +163 -25
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -3
- package/packages/mcp-server/src/mcp-server.test.ts +67 -0
- package/packages/mcp-server/src/remote-questions.test.ts +294 -0
- package/packages/mcp-server/src/remote-questions.ts +916 -0
- package/packages/mcp-server/src/server.ts +89 -14
- package/packages/mcp-server/src/session-manager.ts +43 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
- package/packages/mcp-server/src/workflow-tools.ts +215 -43
- package/packages/mcp-server/tsconfig.test.json +19 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +12 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +30 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +14 -0
- package/packages/pi-agent-core/src/types.ts +34 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/custom.d.ts +38 -0
- package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/custom.js +41 -0
- package/packages/pi-ai/dist/models/custom.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +13 -4
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +16 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/models/custom.ts +42 -0
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
- package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
- package/packages/pi-ai/src/providers/anthropic.ts +15 -4
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
- package/packages/pi-ai/src/providers/simple-options.ts +17 -1
- package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
- package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
- package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
- package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
- package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
- package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -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 +32 -2
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
- 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/hooks-runner.d.ts +53 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
- package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- 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.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -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 +13 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.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 +13 -1
- 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/agent-session-abort-order.test.ts +3 -2
- package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
- package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
- package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
- package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
- package/packages/pi-coding-agent/src/core/index.ts +10 -0
- package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
- package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
- package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
- package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
- package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
- package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
- package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
- package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
- package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
- package/packages/pi-coding-agent/src/index.ts +16 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/scripts/link-workspace-packages.cjs +1 -0
- package/src/resources/agents/researcher.md +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
- package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
- package/src/resources/extensions/gsd/auto/loop.ts +9 -0
- package/src/resources/extensions/gsd/auto/phases.ts +131 -10
- package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
- package/src/resources/extensions/gsd/auto/session.ts +35 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
- package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
- package/src/resources/extensions/gsd/auto-start.ts +60 -68
- package/src/resources/extensions/gsd/auto-verification.ts +33 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
- package/src/resources/extensions/gsd/auto.ts +73 -28
- package/src/resources/extensions/gsd/blocked-models.ts +98 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
- package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
- package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
- package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
- package/src/resources/extensions/gsd/db-writer.ts +88 -17
- package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
- package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
- package/src/resources/extensions/gsd/error-classifier.ts +36 -3
- package/src/resources/extensions/gsd/exec-history.ts +153 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -1
- package/src/resources/extensions/gsd/gsd-db.ts +186 -23
- package/src/resources/extensions/gsd/guided-flow.ts +222 -1
- package/src/resources/extensions/gsd/health-widget.ts +3 -1
- package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
- package/src/resources/extensions/gsd/init-wizard.ts +15 -1
- package/src/resources/extensions/gsd/journal.ts +2 -1
- package/src/resources/extensions/gsd/key-manager.ts +28 -0
- package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
- package/src/resources/extensions/gsd/memory-store.ts +26 -0
- package/src/resources/extensions/gsd/model-router.ts +42 -1
- package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
- package/src/resources/extensions/gsd/preferences-types.ts +46 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
- package/src/resources/extensions/gsd/preferences.ts +17 -17
- package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
- package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
- package/src/resources/extensions/gsd/state.ts +45 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
- package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
- package/src/resources/extensions/gsd/token-counter.ts +22 -5
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
- package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
- package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
- package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
- package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
- package/src/resources/extensions/search-the-web/native-search.ts +48 -12
- package/src/resources/skills/api-design/SKILL.md +190 -0
- package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
- package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
- package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
- package/src/resources/skills/design-an-interface/SKILL.md +102 -0
- package/src/resources/skills/forensics/SKILL.md +153 -0
- package/src/resources/skills/grill-me/SKILL.md +93 -0
- package/src/resources/skills/handoff/SKILL.md +121 -0
- package/src/resources/skills/observability/SKILL.md +174 -0
- package/src/resources/skills/security-review/SKILL.md +181 -0
- package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
- package/src/resources/skills/tdd/SKILL.md +112 -0
- package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
- package/src/resources/skills/write-docs/SKILL.md +82 -0
- package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
- /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
|
@@ -54,7 +54,8 @@ import type { MinimalModelRegistry } from "../context-budget.js";
|
|
|
54
54
|
import { ensurePlanV2Graph } from "../uok/plan-v2.js";
|
|
55
55
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
56
56
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
57
|
-
import { resetEvidence } from "../safety/evidence-collector.js";
|
|
57
|
+
import { resetEvidence, loadEvidenceFromDisk } from "../safety/evidence-collector.js";
|
|
58
|
+
import { parseUnitId } from "../unit-id.js";
|
|
58
59
|
import { createCheckpoint, cleanupCheckpoint, rollbackToCheckpoint } from "../safety/git-checkpoint.js";
|
|
59
60
|
import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
|
|
60
61
|
import {
|
|
@@ -80,7 +81,11 @@ export function resetSessionTimeoutState(): void {
|
|
|
80
81
|
* Exported for testing as _resolveReportBasePath.
|
|
81
82
|
*/
|
|
82
83
|
export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" | "basePath">): string {
|
|
83
|
-
|
|
84
|
+
// Strip /.gsd/worktrees/ suffix when basePath is itself a worktree path and
|
|
85
|
+
// originalBasePath is falsy — prevents reports landing in the worktree (#3729).
|
|
86
|
+
const resolved = s.originalBasePath || s.basePath;
|
|
87
|
+
const markerIdx = resolved.indexOf("/.gsd/worktrees/");
|
|
88
|
+
return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
/**
|
|
@@ -91,7 +96,12 @@ export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" |
|
|
|
91
96
|
export function _resolveDispatchGuardBasePath(
|
|
92
97
|
s: Pick<AutoSession, "originalBasePath" | "basePath">,
|
|
93
98
|
): string {
|
|
94
|
-
|
|
99
|
+
// Strip /.gsd/worktrees/ suffix when basePath is itself a worktree path and
|
|
100
|
+
// originalBasePath is falsy — prevents guard checks running against the
|
|
101
|
+
// worktree instead of the project root (#3729).
|
|
102
|
+
const resolved = s.originalBasePath || s.basePath;
|
|
103
|
+
const markerIdx = resolved.indexOf("/.gsd/worktrees/");
|
|
104
|
+
return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
|
|
95
105
|
}
|
|
96
106
|
|
|
97
107
|
const PLAN_V2_GATE_PHASES: ReadonlySet<Phase> = new Set([
|
|
@@ -419,7 +429,7 @@ export async function runPreDispatch(
|
|
|
419
429
|
findings: reason,
|
|
420
430
|
milestoneId: state.activeMilestone?.id ?? undefined,
|
|
421
431
|
});
|
|
422
|
-
ctx.ui.notify(`Plan gate failed-closed: ${reason}`, "error");
|
|
432
|
+
ctx.ui.notify(`Plan gate failed-closed: ${reason}\n\nIf this keeps happening, try: /gsd doctor heal`, "error");
|
|
423
433
|
await deps.pauseAuto(ctx, pi);
|
|
424
434
|
return { action: "break", reason: "plan-v2-gate-failed" };
|
|
425
435
|
}
|
|
@@ -545,6 +555,12 @@ export async function runPreDispatch(
|
|
|
545
555
|
loopState.stuckRecoveryAttempts = 0;
|
|
546
556
|
|
|
547
557
|
// Worktree lifecycle on milestone transition — merge current, enter next
|
|
558
|
+
// #2909: preflight — warn + stash dirty working tree before merge
|
|
559
|
+
const preflightTransition = deps.preflightCleanRoot(
|
|
560
|
+
s.originalBasePath || s.basePath,
|
|
561
|
+
s.currentMilestoneId!,
|
|
562
|
+
ctx.ui.notify.bind(ctx.ui),
|
|
563
|
+
);
|
|
548
564
|
try {
|
|
549
565
|
deps.resolver.mergeAndExit(s.currentMilestoneId!, ctx.ui);
|
|
550
566
|
} catch (mergeErr) {
|
|
@@ -566,6 +582,14 @@ export async function runPreDispatch(
|
|
|
566
582
|
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
567
583
|
return { action: "break", reason: "merge-failed" };
|
|
568
584
|
}
|
|
585
|
+
// #2909: postflight — restore stashed changes after successful merge
|
|
586
|
+
if (preflightTransition.stashPushed) {
|
|
587
|
+
deps.postflightPopStash(
|
|
588
|
+
s.originalBasePath || s.basePath,
|
|
589
|
+
s.currentMilestoneId!,
|
|
590
|
+
ctx.ui.notify.bind(ctx.ui),
|
|
591
|
+
);
|
|
592
|
+
}
|
|
569
593
|
|
|
570
594
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
571
595
|
|
|
@@ -644,6 +668,12 @@ export async function runPreDispatch(
|
|
|
644
668
|
if (incomplete.length === 0 && state.registry.length > 0) {
|
|
645
669
|
// All milestones complete — merge milestone branch before stopping
|
|
646
670
|
if (s.currentMilestoneId) {
|
|
671
|
+
// #2909: preflight — warn + stash dirty working tree before merge
|
|
672
|
+
const preflightAllComplete = deps.preflightCleanRoot(
|
|
673
|
+
s.originalBasePath || s.basePath,
|
|
674
|
+
s.currentMilestoneId,
|
|
675
|
+
ctx.ui.notify.bind(ctx.ui),
|
|
676
|
+
);
|
|
647
677
|
try {
|
|
648
678
|
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
649
679
|
// Prevent stopAuto from attempting the same merge (#2645)
|
|
@@ -665,6 +695,14 @@ export async function runPreDispatch(
|
|
|
665
695
|
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
666
696
|
return { action: "break", reason: "merge-failed" };
|
|
667
697
|
}
|
|
698
|
+
// #2909: postflight — restore stashed changes after successful merge
|
|
699
|
+
if (preflightAllComplete.stashPushed) {
|
|
700
|
+
deps.postflightPopStash(
|
|
701
|
+
s.originalBasePath || s.basePath,
|
|
702
|
+
s.currentMilestoneId,
|
|
703
|
+
ctx.ui.notify.bind(ctx.ui),
|
|
704
|
+
);
|
|
705
|
+
}
|
|
668
706
|
|
|
669
707
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
670
708
|
}
|
|
@@ -758,6 +796,12 @@ export async function runPreDispatch(
|
|
|
758
796
|
if (state.phase === "complete") {
|
|
759
797
|
// Milestone merge on complete (before closeout so branch state is clean)
|
|
760
798
|
if (s.currentMilestoneId) {
|
|
799
|
+
// #2909: preflight — warn + stash dirty working tree before merge
|
|
800
|
+
const preflightComplete = deps.preflightCleanRoot(
|
|
801
|
+
s.originalBasePath || s.basePath,
|
|
802
|
+
s.currentMilestoneId,
|
|
803
|
+
ctx.ui.notify.bind(ctx.ui),
|
|
804
|
+
);
|
|
761
805
|
try {
|
|
762
806
|
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
763
807
|
// Prevent stopAuto from attempting the same merge (#2645)
|
|
@@ -779,6 +823,14 @@ export async function runPreDispatch(
|
|
|
779
823
|
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
780
824
|
return { action: "break", reason: "merge-failed" };
|
|
781
825
|
}
|
|
826
|
+
// #2909: postflight — restore stashed changes after successful merge
|
|
827
|
+
if (preflightComplete.stashPushed) {
|
|
828
|
+
deps.postflightPopStash(
|
|
829
|
+
s.originalBasePath || s.basePath,
|
|
830
|
+
s.currentMilestoneId,
|
|
831
|
+
ctx.ui.notify.bind(ctx.ui),
|
|
832
|
+
);
|
|
833
|
+
}
|
|
782
834
|
|
|
783
835
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
784
836
|
}
|
|
@@ -1131,16 +1183,42 @@ export async function runGuards(
|
|
|
1131
1183
|
s.lastBudgetAlertLevel =
|
|
1132
1184
|
newBudgetAlertLevel as AutoSession["lastBudgetAlertLevel"];
|
|
1133
1185
|
|
|
1134
|
-
|
|
1186
|
+
// Emit Layer 2 budget_threshold event (post-plan hook recommendation).
|
|
1187
|
+
// Extensions / Layer 0 shell hooks may return an action override.
|
|
1188
|
+
let hookAction: "pause" | "downgrade" | "continue" | undefined;
|
|
1189
|
+
try {
|
|
1190
|
+
const { emitBudgetThreshold } = await import("../hook-emitter.js");
|
|
1191
|
+
const hookResult = await emitBudgetThreshold({
|
|
1192
|
+
fraction: budgetPct,
|
|
1193
|
+
spent: totalCost,
|
|
1194
|
+
limit: budgetCeiling,
|
|
1195
|
+
});
|
|
1196
|
+
if (hookResult?.action) hookAction = hookResult.action;
|
|
1197
|
+
} catch (hookErr) {
|
|
1198
|
+
logWarning("engine", `budget_threshold hook emission failed: ${(hookErr as Error).message}`);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// Apply hook override to enforcement action. "continue" → "none" (no enforcement),
|
|
1202
|
+
// "pause" and "downgrade" map to the matching enforcement path below.
|
|
1203
|
+
let effectiveAction = budgetEnforcementAction;
|
|
1204
|
+
if (hookAction === "continue") {
|
|
1205
|
+
effectiveAction = "none";
|
|
1206
|
+
} else if (hookAction === "pause") {
|
|
1207
|
+
effectiveAction = "pause";
|
|
1208
|
+
} else if (hookAction === "downgrade") {
|
|
1209
|
+
effectiveAction = "warn";
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
if (threshold.pct === 100 && effectiveAction !== "none") {
|
|
1135
1213
|
// 100% — special enforcement logic (halt/pause/warn)
|
|
1136
1214
|
const msg = `Budget ceiling ${deps.formatCost(budgetCeiling)} reached (spent ${deps.formatCost(totalCost)}).`;
|
|
1137
|
-
if (
|
|
1215
|
+
if (effectiveAction === "halt") {
|
|
1138
1216
|
deps.sendDesktopNotification("GSD", msg, "error", "budget", basename(s.originalBasePath || s.basePath));
|
|
1139
1217
|
await deps.stopAuto(ctx, pi, "Budget ceiling reached");
|
|
1140
1218
|
debugLog("autoLoop", { phase: "exit", reason: "budget-halt" });
|
|
1141
1219
|
return { action: "break", reason: "budget-halt" };
|
|
1142
1220
|
}
|
|
1143
|
-
if (
|
|
1221
|
+
if (effectiveAction === "pause") {
|
|
1144
1222
|
ctx.ui.notify(
|
|
1145
1223
|
`${msg} Pausing auto-mode — /gsd auto to override and continue.`,
|
|
1146
1224
|
"warning",
|
|
@@ -1359,6 +1437,14 @@ export async function runUnitPhase(
|
|
|
1359
1437
|
);
|
|
1360
1438
|
if (safetyConfig.enabled && safetyConfig.evidence_collection) {
|
|
1361
1439
|
resetEvidence();
|
|
1440
|
+
// Restore persisted evidence so session-restart resumes don't produce
|
|
1441
|
+
// false-positive "no bash calls" warnings (Bug #4385).
|
|
1442
|
+
if (s.basePath && unitType === "execute-task") {
|
|
1443
|
+
const { milestone: eMid, slice: eSid, task: eTid } = parseUnitId(unitId);
|
|
1444
|
+
if (eMid && eSid && eTid) {
|
|
1445
|
+
loadEvidenceFromDisk(s.basePath, eMid, eSid, eTid);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1362
1448
|
}
|
|
1363
1449
|
// Only checkpoint code-executing units (not lifecycle/planning units)
|
|
1364
1450
|
if (safetyConfig.enabled && safetyConfig.checkpoints && unitType === "execute-task") {
|
|
@@ -1445,6 +1531,7 @@ export async function runUnitPhase(
|
|
|
1445
1531
|
sidecarItem ? undefined : { isRetry, previousTier },
|
|
1446
1532
|
undefined,
|
|
1447
1533
|
s.manualSessionModelOverride,
|
|
1534
|
+
s.autoModeStartThinkingLevel,
|
|
1448
1535
|
);
|
|
1449
1536
|
s.currentUnitRouting =
|
|
1450
1537
|
modelResult.routing as AutoSession["currentUnitRouting"];
|
|
@@ -1459,6 +1546,9 @@ export async function runUnitPhase(
|
|
|
1459
1546
|
if (match) {
|
|
1460
1547
|
const ok = await pi.setModel(match, { persist: false });
|
|
1461
1548
|
if (ok) {
|
|
1549
|
+
if (s.autoModeStartThinkingLevel) {
|
|
1550
|
+
pi.setThinkingLevel(s.autoModeStartThinkingLevel);
|
|
1551
|
+
}
|
|
1462
1552
|
s.currentUnitModel = match as AutoSession["currentUnitModel"];
|
|
1463
1553
|
ctx.ui.notify(`Hook model override: ${match.provider}/${match.id}`, "info");
|
|
1464
1554
|
} else {
|
|
@@ -1589,21 +1679,24 @@ export async function runUnitPhase(
|
|
|
1589
1679
|
}
|
|
1590
1680
|
|
|
1591
1681
|
if (unitResult.status === "cancelled") {
|
|
1682
|
+
const errorCategory = unitResult.errorContext?.category;
|
|
1592
1683
|
// Provider-error pause: pauseAuto already handled cleanup and scheduled
|
|
1593
1684
|
// recovery. Don't hard-stop — just break out of the loop (#2762).
|
|
1594
|
-
if (
|
|
1685
|
+
if (errorCategory === "provider") {
|
|
1595
1686
|
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1596
|
-
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext
|
|
1687
|
+
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext?.isTransient });
|
|
1597
1688
|
return { action: "break", reason: "provider-pause" };
|
|
1598
1689
|
}
|
|
1599
1690
|
// Timeout category covers two distinct scenarios:
|
|
1600
1691
|
// 1. Session creation timeout (120s) — transient, auto-resume with backoff
|
|
1601
1692
|
// 2. Unit hard timeout (30min+) — stuck agent, pause for manual review
|
|
1693
|
+
// Transient session-failed covers recoverable newSession failures and should
|
|
1694
|
+
// pause instead of hard-stopping.
|
|
1602
1695
|
// Structural errors (TypeError, is not a function) are NOT transient
|
|
1603
1696
|
// and must hard-stop to avoid infinite retry loops.
|
|
1604
1697
|
if (
|
|
1605
1698
|
unitResult.errorContext?.isTransient &&
|
|
1606
|
-
|
|
1699
|
+
errorCategory === "timeout"
|
|
1607
1700
|
) {
|
|
1608
1701
|
const isSessionCreationTimeout = unitResult.errorContext.message?.includes("Session creation timed out");
|
|
1609
1702
|
|
|
@@ -1666,6 +1759,20 @@ export async function runUnitPhase(
|
|
|
1666
1759
|
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1667
1760
|
return { action: "break", reason: "unit-hard-timeout" };
|
|
1668
1761
|
}
|
|
1762
|
+
if (
|
|
1763
|
+
unitResult.errorContext?.isTransient &&
|
|
1764
|
+
errorCategory === "session-failed"
|
|
1765
|
+
) {
|
|
1766
|
+
ctx.ui.notify(
|
|
1767
|
+
`Session creation failed transiently for ${unitType} ${unitId}: ${unitResult.errorContext?.message ?? "unknown"}. Pausing auto-mode (recoverable).`,
|
|
1768
|
+
"warning",
|
|
1769
|
+
);
|
|
1770
|
+
debugLog("autoLoop", { phase: "session-start-transient-pause", unitType, unitId, category: errorCategory });
|
|
1771
|
+
await deps.pauseAuto(ctx, pi);
|
|
1772
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
1773
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1774
|
+
return { action: "break", reason: "session-timeout" };
|
|
1775
|
+
}
|
|
1669
1776
|
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
1670
1777
|
if (s.currentUnit) {
|
|
1671
1778
|
await deps.closeoutUnit(
|
|
@@ -1881,6 +1988,20 @@ export async function runFinalize(
|
|
|
1881
1988
|
debugLog("autoLoop", { phase: "sidecar-artifact-retry-skipped", iteration: ic.iteration });
|
|
1882
1989
|
} else {
|
|
1883
1990
|
// s.pendingVerificationRetry was set by postUnitPreVerification.
|
|
1991
|
+
// Emit a dedicated journal event so forensics can distinguish bounded
|
|
1992
|
+
// verification retries from genuine stuck-loop dispatch repetitions (#4540).
|
|
1993
|
+
const retryInfo = s.pendingVerificationRetry;
|
|
1994
|
+
deps.emitJournalEvent({
|
|
1995
|
+
ts: new Date().toISOString(),
|
|
1996
|
+
flowId: ic.flowId,
|
|
1997
|
+
seq: ic.nextSeq(),
|
|
1998
|
+
eventType: "artifact-verification-retry",
|
|
1999
|
+
data: {
|
|
2000
|
+
unitType: preUnitSnapshot?.type,
|
|
2001
|
+
unitId: retryInfo?.unitId,
|
|
2002
|
+
attempt: retryInfo?.attempt,
|
|
2003
|
+
},
|
|
2004
|
+
});
|
|
1884
2005
|
// Continue the loop — next iteration will inject the retry context into the prompt.
|
|
1885
2006
|
debugLog("autoLoop", { phase: "artifact-verification-retry", iteration: ic.iteration });
|
|
1886
2007
|
return { action: "continue" };
|
|
@@ -42,16 +42,25 @@ export async function runUnit(
|
|
|
42
42
|
let sessionResult: { cancelled: boolean };
|
|
43
43
|
let sessionTimeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
44
44
|
const mySessionSwitchGeneration = ++sessionSwitchGeneration;
|
|
45
|
+
// #3731: Cancellation controller for newSession(). When the session-creation
|
|
46
|
+
// timeout fires, we abort this controller so that the still-in-flight
|
|
47
|
+
// newSession() discards itself after await this.abort() completes, preventing
|
|
48
|
+
// it from capturing the (now-root) process.cwd() and rebuilding the tool
|
|
49
|
+
// runtime with the wrong cwd.
|
|
50
|
+
const sessionAbortController = new AbortController();
|
|
45
51
|
_setSessionSwitchInFlight(true);
|
|
46
52
|
try {
|
|
47
|
-
const sessionPromise = s.cmdCtx!.newSession().finally(() => {
|
|
53
|
+
const sessionPromise = s.cmdCtx!.newSession({ abortSignal: sessionAbortController.signal }).finally(() => {
|
|
48
54
|
if (sessionSwitchGeneration === mySessionSwitchGeneration) {
|
|
49
55
|
_setSessionSwitchInFlight(false);
|
|
50
56
|
}
|
|
51
57
|
});
|
|
52
58
|
const timeoutPromise = new Promise<{ cancelled: true }>((resolve) => {
|
|
53
59
|
sessionTimeoutHandle = setTimeout(
|
|
54
|
-
() =>
|
|
60
|
+
() => {
|
|
61
|
+
sessionAbortController.abort();
|
|
62
|
+
resolve({ cancelled: true });
|
|
63
|
+
},
|
|
55
64
|
NEW_SESSION_TIMEOUT_MS,
|
|
56
65
|
);
|
|
57
66
|
});
|
|
@@ -118,6 +127,35 @@ export async function runUnit(
|
|
|
118
127
|
logWarning("engine", "Failed to chdir to basePath before dispatch", { basePath: s.basePath, error: String(e) });
|
|
119
128
|
}
|
|
120
129
|
|
|
130
|
+
// ── Provider request-readiness pre-check (#4555) ──
|
|
131
|
+
// Verify the provider can accept requests before dispatching. If the token
|
|
132
|
+
// has expired since bootstrap, return cancelled immediately so the unit is
|
|
133
|
+
// not wasted on a guaranteed 401.
|
|
134
|
+
{
|
|
135
|
+
const provider = s.currentUnitModel?.provider ?? ctx.model?.provider;
|
|
136
|
+
const registry = (ctx as any).modelRegistry;
|
|
137
|
+
|
|
138
|
+
if (provider && registry != null && typeof registry.isProviderRequestReady === "function") {
|
|
139
|
+
let ready = false;
|
|
140
|
+
try {
|
|
141
|
+
ready = registry.isProviderRequestReady(provider);
|
|
142
|
+
} catch {
|
|
143
|
+
ready = false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!ready) {
|
|
147
|
+
return {
|
|
148
|
+
status: "cancelled",
|
|
149
|
+
errorContext: {
|
|
150
|
+
message: `Provider ${provider} is not request-ready (login/token expired)`,
|
|
151
|
+
category: "provider",
|
|
152
|
+
isTransient: false,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
121
159
|
// ── Send the prompt ──
|
|
122
160
|
debugLog("runUnit", { phase: "send-message", unitType, unitId });
|
|
123
161
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import type { Api, Model } from "@gsd/pi-ai";
|
|
20
|
-
import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
20
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
21
21
|
import type { GitServiceImpl } from "../git-service.js";
|
|
22
22
|
import type { CaptureEntry } from "../captures.js";
|
|
23
23
|
import type { BudgetAlertLevel } from "../auto-budget.js";
|
|
@@ -40,6 +40,8 @@ export interface StartModel {
|
|
|
40
40
|
id: string;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export type ThinkingLevelSnapshot = ReturnType<ExtensionAPI["getThinkingLevel"]>;
|
|
44
|
+
|
|
43
45
|
export interface PendingVerificationRetry {
|
|
44
46
|
unitId: string;
|
|
45
47
|
failureContext: string;
|
|
@@ -62,6 +64,15 @@ export interface SidecarItem {
|
|
|
62
64
|
captureId?: string;
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
export interface PreExecFailure {
|
|
68
|
+
/** Milestone/slice that failed (e.g. "M001/S02"). */
|
|
69
|
+
unitId: string;
|
|
70
|
+
/** Verbatim blocking check strings from the failed gate run. */
|
|
71
|
+
blockingFindings: string[];
|
|
72
|
+
/** Condensed gate verdict excerpt for context (status + rationale). */
|
|
73
|
+
verdictExcerpt: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
66
77
|
|
|
67
78
|
export const MAX_UNIT_DISPATCHES = 3;
|
|
@@ -120,6 +131,8 @@ export class AutoSession {
|
|
|
120
131
|
currentDispatchedModelId: string | null = null;
|
|
121
132
|
originalModelId: string | null = null;
|
|
122
133
|
originalModelProvider: string | null = null;
|
|
134
|
+
autoModeStartThinkingLevel: ThinkingLevelSnapshot | null = null;
|
|
135
|
+
originalThinkingLevel: ThinkingLevelSnapshot | null = null;
|
|
123
136
|
lastBudgetAlertLevel: BudgetAlertLevel = 0;
|
|
124
137
|
|
|
125
138
|
// ── Recovery ─────────────────────────────────────────────────────────────
|
|
@@ -135,6 +148,18 @@ export class AutoSession {
|
|
|
135
148
|
// ── Sidecar queue ─────────────────────────────────────────────────────
|
|
136
149
|
sidecarQueue: SidecarItem[] = [];
|
|
137
150
|
|
|
151
|
+
// ── Pre-exec gate failure context (#4551) ───────────────────────────
|
|
152
|
+
/**
|
|
153
|
+
* Persisted when a pre-execution gate fails on a plan-slice or refine-slice
|
|
154
|
+
* unit. The planning → plan-slice dispatch rule reads this field and injects
|
|
155
|
+
* the failure details into the next re-dispatch prompt so the LLM can fix the
|
|
156
|
+
* specific issues instead of producing an identical plan.
|
|
157
|
+
*
|
|
158
|
+
* Cleared after it has been consumed (injected into the prompt) to avoid
|
|
159
|
+
* stale context bleeding into unrelated slices.
|
|
160
|
+
*/
|
|
161
|
+
lastPreExecFailure: PreExecFailure | null = null;
|
|
162
|
+
|
|
138
163
|
// ── Tool invocation errors (#2883) ──────────────────────────────────
|
|
139
164
|
/** Set when a GSD tool execution ends with isError due to malformed/truncated
|
|
140
165
|
* JSON arguments. Checked by postUnitPreVerification to break retry loops. */
|
|
@@ -195,7 +220,12 @@ export class AutoSession {
|
|
|
195
220
|
}
|
|
196
221
|
|
|
197
222
|
get lockBasePath(): string {
|
|
198
|
-
|
|
223
|
+
// Prefer originalBasePath (project root); fall back to basePath.
|
|
224
|
+
// Strip /.gsd/worktrees/ suffix if basePath is itself a worktree path
|
|
225
|
+
// to avoid reading/writing the lock inside the worktree (#3729).
|
|
226
|
+
const resolved = this.originalBasePath || this.basePath;
|
|
227
|
+
const markerIdx = resolved.indexOf("/.gsd/worktrees/");
|
|
228
|
+
return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
|
|
199
229
|
}
|
|
200
230
|
|
|
201
231
|
reset(): void {
|
|
@@ -241,6 +271,8 @@ export class AutoSession {
|
|
|
241
271
|
this.currentDispatchedModelId = null;
|
|
242
272
|
this.originalModelId = null;
|
|
243
273
|
this.originalModelProvider = null;
|
|
274
|
+
this.autoModeStartThinkingLevel = null;
|
|
275
|
+
this.originalThinkingLevel = null;
|
|
244
276
|
this.lastBudgetAlertLevel = 0;
|
|
245
277
|
|
|
246
278
|
// Recovery
|
|
@@ -261,6 +293,7 @@ export class AutoSession {
|
|
|
261
293
|
this.sidecarQueue = [];
|
|
262
294
|
this.rewriteAttemptCount = 0;
|
|
263
295
|
this.consecutiveCompleteBootstraps = 0;
|
|
296
|
+
this.lastPreExecFailure = null;
|
|
264
297
|
this.lastToolInvocationError = null;
|
|
265
298
|
this.lastGitActionFailure = null;
|
|
266
299
|
this.lastGitActionStatus = null;
|
|
@@ -568,15 +568,28 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
568
568
|
},
|
|
569
569
|
{
|
|
570
570
|
name: "planning → plan-slice",
|
|
571
|
-
match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry }) => {
|
|
571
|
+
match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry, session }) => {
|
|
572
572
|
if (state.phase !== "planning") return null;
|
|
573
573
|
if (!state.activeSlice) return missingSliceStop(mid, state.phase);
|
|
574
574
|
const sid = state.activeSlice!.id;
|
|
575
575
|
const sTitle = state.activeSlice!.title;
|
|
576
|
+
// #4551: Consume any persisted pre-exec failure for this slice so the
|
|
577
|
+
// re-dispatched prompt includes the exact blocked references. Clear the
|
|
578
|
+
// field immediately after reading to prevent stale context leaking into
|
|
579
|
+
// a later, unrelated plan-slice run.
|
|
580
|
+
const unitId = `${mid}/${sid}`;
|
|
581
|
+
let priorPreExecFailure: { blockingFindings: string[]; verdictExcerpt: string } | undefined;
|
|
582
|
+
if (session?.lastPreExecFailure?.unitId === unitId) {
|
|
583
|
+
priorPreExecFailure = {
|
|
584
|
+
blockingFindings: session.lastPreExecFailure.blockingFindings,
|
|
585
|
+
verdictExcerpt: session.lastPreExecFailure.verdictExcerpt,
|
|
586
|
+
};
|
|
587
|
+
session.lastPreExecFailure = null;
|
|
588
|
+
}
|
|
576
589
|
return {
|
|
577
590
|
action: "dispatch",
|
|
578
591
|
unitType: "plan-slice",
|
|
579
|
-
unitId
|
|
592
|
+
unitId,
|
|
580
593
|
prompt: await buildPlanSlicePrompt(
|
|
581
594
|
mid,
|
|
582
595
|
midTitle,
|
|
@@ -584,7 +597,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
584
597
|
sTitle,
|
|
585
598
|
basePath,
|
|
586
599
|
undefined,
|
|
587
|
-
{ sessionContextWindow, modelRegistry },
|
|
600
|
+
{ sessionContextWindow, modelRegistry, priorPreExecFailure },
|
|
588
601
|
),
|
|
589
602
|
};
|
|
590
603
|
},
|
|
@@ -18,6 +18,7 @@ import { getSessionModelOverride } from "./session-model-override.js";
|
|
|
18
18
|
import { logWarning } from "./workflow-logger.js";
|
|
19
19
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
20
20
|
import { applyModelPolicyFilter } from "./uok/model-policy.js";
|
|
21
|
+
import { isModelBlocked } from "./blocked-models.js";
|
|
21
22
|
|
|
22
23
|
export interface ModelSelectionResult {
|
|
23
24
|
/** Routing metadata for metrics recording */
|
|
@@ -26,13 +27,32 @@ export interface ModelSelectionResult {
|
|
|
26
27
|
appliedModel: Model<Api> | null;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
export interface PreferredModelConfig {
|
|
31
|
+
primary: string;
|
|
32
|
+
fallbacks: string[];
|
|
33
|
+
source: "explicit" | "synthesized";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function reapplyThinkingLevel(
|
|
37
|
+
pi: ExtensionAPI,
|
|
38
|
+
level: ReturnType<ExtensionAPI["getThinkingLevel"]> | null | undefined,
|
|
39
|
+
): void {
|
|
40
|
+
if (!level) return;
|
|
41
|
+
pi.setThinkingLevel(level);
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
export function resolvePreferredModelConfig(
|
|
30
45
|
unitType: string,
|
|
31
46
|
autoModeStartModel: { provider: string; id: string; flatRateCtx?: FlatRateContext } | null,
|
|
32
47
|
isAutoMode = true,
|
|
33
|
-
) {
|
|
48
|
+
): PreferredModelConfig | undefined {
|
|
34
49
|
const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
35
|
-
if (explicitConfig)
|
|
50
|
+
if (explicitConfig) {
|
|
51
|
+
return {
|
|
52
|
+
...explicitConfig,
|
|
53
|
+
source: "explicit",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
36
56
|
|
|
37
57
|
// In interactive mode, don't synthesize a routing-based model config.
|
|
38
58
|
// The user's session model (/model) should be used as-is (#3962).
|
|
@@ -59,6 +79,7 @@ export function resolvePreferredModelConfig(
|
|
|
59
79
|
return {
|
|
60
80
|
primary: ceilingModel,
|
|
61
81
|
fallbacks: [],
|
|
82
|
+
source: "synthesized",
|
|
62
83
|
};
|
|
63
84
|
}
|
|
64
85
|
|
|
@@ -84,6 +105,8 @@ export async function selectAndApplyModel(
|
|
|
84
105
|
isAutoMode = true,
|
|
85
106
|
/** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
|
|
86
107
|
sessionModelOverride?: { provider: string; id: string } | null,
|
|
108
|
+
/** Thinking level captured at auto-mode start and re-applied after model swaps. */
|
|
109
|
+
autoModeStartThinkingLevel?: ReturnType<ExtensionAPI["getThinkingLevel"]> | null,
|
|
87
110
|
): Promise<ModelSelectionResult> {
|
|
88
111
|
const uokFlags = resolveUokFlags(prefs);
|
|
89
112
|
const effectiveSessionModelOverride = sessionModelOverride === undefined
|
|
@@ -124,6 +147,11 @@ export async function selectAndApplyModel(
|
|
|
124
147
|
if (prefs?.token_profile === "burn-max") {
|
|
125
148
|
routingConfig.enabled = false;
|
|
126
149
|
}
|
|
150
|
+
if (modelConfig.source === "explicit") {
|
|
151
|
+
// Explicit per-phase model preferences express hard user intent.
|
|
152
|
+
// Dynamic routing may only treat synthesized tier ceilings as downgradeable.
|
|
153
|
+
routingConfig.enabled = false;
|
|
154
|
+
}
|
|
127
155
|
let effectiveModelConfig = modelConfig;
|
|
128
156
|
let routingTierLabel = "";
|
|
129
157
|
let routingEligibleModels = availableModels;
|
|
@@ -286,6 +314,7 @@ export async function selectAndApplyModel(
|
|
|
286
314
|
effectiveModelConfig = {
|
|
287
315
|
primary: routingResult.modelId,
|
|
288
316
|
fallbacks: routingResult.fallbacks,
|
|
317
|
+
source: modelConfig.source,
|
|
289
318
|
};
|
|
290
319
|
// Always notify on model downgrade — users should see when their
|
|
291
320
|
// model selection is overridden, not just in verbose mode (#3962).
|
|
@@ -334,6 +363,18 @@ export async function selectAndApplyModel(
|
|
|
334
363
|
attemptedPolicyEligible = true;
|
|
335
364
|
}
|
|
336
365
|
|
|
366
|
+
// Skip models the provider has previously rejected for this account
|
|
367
|
+
// (issue #4513). The block is persisted in .gsd/runtime/blocked-models.json
|
|
368
|
+
// so it survives /gsd auto restarts — without this, the same dead model
|
|
369
|
+
// gets reselected after every restart.
|
|
370
|
+
if (isModelBlocked(basePath, model.provider, model.id)) {
|
|
371
|
+
ctx.ui.notify(
|
|
372
|
+
`Skipping blocked model ${model.provider}/${model.id} (provider rejected it for this account).`,
|
|
373
|
+
"warning",
|
|
374
|
+
);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
|
|
337
378
|
// Warn if the ID is ambiguous across providers
|
|
338
379
|
if (!modelId.includes("/")) {
|
|
339
380
|
const providers = availableModels.filter(m => m.id === modelId).map(m => m.provider);
|
|
@@ -349,11 +390,12 @@ export async function selectAndApplyModel(
|
|
|
349
390
|
const ok = await pi.setModel(model, { persist: false });
|
|
350
391
|
if (ok) {
|
|
351
392
|
appliedModel = model;
|
|
393
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
352
394
|
|
|
353
395
|
// ADR-005: Adjust active tool set for the selected model's provider capabilities.
|
|
354
396
|
// Hard-filter incompatible tools, then let extensions override via adjust_tool_set hook.
|
|
355
397
|
const activeToolNames = pi.getActiveTools();
|
|
356
|
-
const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api);
|
|
398
|
+
const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api, model.provider);
|
|
357
399
|
let finalToolNames = compatibleTools;
|
|
358
400
|
|
|
359
401
|
// Fire adjust_tool_set hook — extensions can override the filtered tool set
|
|
@@ -407,19 +449,33 @@ export async function selectAndApplyModel(
|
|
|
407
449
|
// No model preference for this unit type — re-apply the model captured
|
|
408
450
|
// at auto-mode start to prevent bleed from shared global settings.json (#650).
|
|
409
451
|
const availableModels = ctx.modelRegistry.getAvailable();
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
452
|
+
const startBlocked = isModelBlocked(basePath, autoModeStartModel.provider, autoModeStartModel.id);
|
|
453
|
+
if (startBlocked) {
|
|
454
|
+
ctx.ui.notify(
|
|
455
|
+
`Auto-mode start model ${autoModeStartModel.provider}/${autoModeStartModel.id} is blocked for this account. Using current session model instead.`,
|
|
456
|
+
"warning",
|
|
457
|
+
);
|
|
458
|
+
} else {
|
|
459
|
+
const startModel = availableModels.find(
|
|
460
|
+
m => m.provider === autoModeStartModel.provider && m.id === autoModeStartModel.id,
|
|
461
|
+
);
|
|
462
|
+
if (startModel) {
|
|
463
|
+
const ok = await pi.setModel(startModel, { persist: false });
|
|
464
|
+
if (!ok) {
|
|
465
|
+
const byId = availableModels.find(
|
|
466
|
+
m => m.id === autoModeStartModel.id && !isModelBlocked(basePath, m.provider, m.id),
|
|
467
|
+
);
|
|
468
|
+
if (byId) {
|
|
469
|
+
const fallbackOk = await pi.setModel(byId, { persist: false });
|
|
470
|
+
if (fallbackOk) {
|
|
471
|
+
appliedModel = byId;
|
|
472
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
appliedModel = startModel;
|
|
477
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
420
478
|
}
|
|
421
|
-
} else {
|
|
422
|
-
appliedModel = startModel;
|
|
423
479
|
}
|
|
424
480
|
}
|
|
425
481
|
}
|