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
|
@@ -30,7 +30,8 @@ import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
|
|
|
30
30
|
import { ensurePlanV2Graph } from "../uok/plan-v2.js";
|
|
31
31
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
32
32
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
33
|
-
import { resetEvidence } from "../safety/evidence-collector.js";
|
|
33
|
+
import { resetEvidence, loadEvidenceFromDisk } from "../safety/evidence-collector.js";
|
|
34
|
+
import { parseUnitId } from "../unit-id.js";
|
|
34
35
|
import { createCheckpoint, cleanupCheckpoint, rollbackToCheckpoint } from "../safety/git-checkpoint.js";
|
|
35
36
|
import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
|
|
36
37
|
import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, supportsStructuredQuestions, } from "../workflow-mcp.js";
|
|
@@ -47,7 +48,11 @@ export function resetSessionTimeoutState() {
|
|
|
47
48
|
* Exported for testing as _resolveReportBasePath.
|
|
48
49
|
*/
|
|
49
50
|
export function _resolveReportBasePath(s) {
|
|
50
|
-
|
|
51
|
+
// Strip /.gsd/worktrees/ suffix when basePath is itself a worktree path and
|
|
52
|
+
// originalBasePath is falsy — prevents reports landing in the worktree (#3729).
|
|
53
|
+
const resolved = s.originalBasePath || s.basePath;
|
|
54
|
+
const markerIdx = resolved.indexOf("/.gsd/worktrees/");
|
|
55
|
+
return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
|
|
51
56
|
}
|
|
52
57
|
/**
|
|
53
58
|
* Resolve the authoritative project base for dispatch guards.
|
|
@@ -55,7 +60,12 @@ export function _resolveReportBasePath(s) {
|
|
|
55
60
|
* unit is running inside an auto worktree.
|
|
56
61
|
*/
|
|
57
62
|
export function _resolveDispatchGuardBasePath(s) {
|
|
58
|
-
|
|
63
|
+
// Strip /.gsd/worktrees/ suffix when basePath is itself a worktree path and
|
|
64
|
+
// originalBasePath is falsy — prevents guard checks running against the
|
|
65
|
+
// worktree instead of the project root (#3729).
|
|
66
|
+
const resolved = s.originalBasePath || s.basePath;
|
|
67
|
+
const markerIdx = resolved.indexOf("/.gsd/worktrees/");
|
|
68
|
+
return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
|
|
59
69
|
}
|
|
60
70
|
const PLAN_V2_GATE_PHASES = new Set([
|
|
61
71
|
"executing",
|
|
@@ -295,7 +305,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
295
305
|
findings: reason,
|
|
296
306
|
milestoneId: state.activeMilestone?.id ?? undefined,
|
|
297
307
|
});
|
|
298
|
-
ctx.ui.notify(`Plan gate failed-closed: ${reason}`, "error");
|
|
308
|
+
ctx.ui.notify(`Plan gate failed-closed: ${reason}\n\nIf this keeps happening, try: /gsd doctor heal`, "error");
|
|
299
309
|
await deps.pauseAuto(ctx, pi);
|
|
300
310
|
return { action: "break", reason: "plan-v2-gate-failed" };
|
|
301
311
|
}
|
|
@@ -389,6 +399,8 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
389
399
|
loopState.recentUnits.length = 0;
|
|
390
400
|
loopState.stuckRecoveryAttempts = 0;
|
|
391
401
|
// Worktree lifecycle on milestone transition — merge current, enter next
|
|
402
|
+
// #2909: preflight — warn + stash dirty working tree before merge
|
|
403
|
+
const preflightTransition = deps.preflightCleanRoot(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
392
404
|
try {
|
|
393
405
|
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
394
406
|
}
|
|
@@ -405,6 +417,10 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
405
417
|
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
406
418
|
return { action: "break", reason: "merge-failed" };
|
|
407
419
|
}
|
|
420
|
+
// #2909: postflight — restore stashed changes after successful merge
|
|
421
|
+
if (preflightTransition.stashPushed) {
|
|
422
|
+
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
423
|
+
}
|
|
408
424
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
409
425
|
deps.invalidateAllCaches();
|
|
410
426
|
state = await deps.deriveState(s.basePath);
|
|
@@ -459,6 +475,8 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
459
475
|
if (incomplete.length === 0 && state.registry.length > 0) {
|
|
460
476
|
// All milestones complete — merge milestone branch before stopping
|
|
461
477
|
if (s.currentMilestoneId) {
|
|
478
|
+
// #2909: preflight — warn + stash dirty working tree before merge
|
|
479
|
+
const preflightAllComplete = deps.preflightCleanRoot(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
462
480
|
try {
|
|
463
481
|
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
464
482
|
// Prevent stopAuto from attempting the same merge (#2645)
|
|
@@ -475,6 +493,10 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
475
493
|
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
476
494
|
return { action: "break", reason: "merge-failed" };
|
|
477
495
|
}
|
|
496
|
+
// #2909: postflight — restore stashed changes after successful merge
|
|
497
|
+
if (preflightAllComplete.stashPushed) {
|
|
498
|
+
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
499
|
+
}
|
|
478
500
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
479
501
|
}
|
|
480
502
|
deps.sendDesktopNotification("GSD", "All milestones complete!", "success", "milestone", basename(s.originalBasePath || s.basePath));
|
|
@@ -539,6 +561,8 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
539
561
|
if (state.phase === "complete") {
|
|
540
562
|
// Milestone merge on complete (before closeout so branch state is clean)
|
|
541
563
|
if (s.currentMilestoneId) {
|
|
564
|
+
// #2909: preflight — warn + stash dirty working tree before merge
|
|
565
|
+
const preflightComplete = deps.preflightCleanRoot(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
542
566
|
try {
|
|
543
567
|
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
544
568
|
// Prevent stopAuto from attempting the same merge (#2645)
|
|
@@ -555,6 +579,10 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
555
579
|
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
556
580
|
return { action: "break", reason: "merge-failed" };
|
|
557
581
|
}
|
|
582
|
+
// #2909: postflight — restore stashed changes after successful merge
|
|
583
|
+
if (preflightComplete.stashPushed) {
|
|
584
|
+
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
585
|
+
}
|
|
558
586
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
559
587
|
}
|
|
560
588
|
deps.sendDesktopNotification("GSD", `Milestone ${mid} complete!`, "success", "milestone", basename(s.originalBasePath || s.basePath));
|
|
@@ -823,16 +851,44 @@ export async function runGuards(ic, mid) {
|
|
|
823
851
|
if (threshold) {
|
|
824
852
|
s.lastBudgetAlertLevel =
|
|
825
853
|
newBudgetAlertLevel;
|
|
826
|
-
|
|
854
|
+
// Emit Layer 2 budget_threshold event (post-plan hook recommendation).
|
|
855
|
+
// Extensions / Layer 0 shell hooks may return an action override.
|
|
856
|
+
let hookAction;
|
|
857
|
+
try {
|
|
858
|
+
const { emitBudgetThreshold } = await import("../hook-emitter.js");
|
|
859
|
+
const hookResult = await emitBudgetThreshold({
|
|
860
|
+
fraction: budgetPct,
|
|
861
|
+
spent: totalCost,
|
|
862
|
+
limit: budgetCeiling,
|
|
863
|
+
});
|
|
864
|
+
if (hookResult?.action)
|
|
865
|
+
hookAction = hookResult.action;
|
|
866
|
+
}
|
|
867
|
+
catch (hookErr) {
|
|
868
|
+
logWarning("engine", `budget_threshold hook emission failed: ${hookErr.message}`);
|
|
869
|
+
}
|
|
870
|
+
// Apply hook override to enforcement action. "continue" → "none" (no enforcement),
|
|
871
|
+
// "pause" and "downgrade" map to the matching enforcement path below.
|
|
872
|
+
let effectiveAction = budgetEnforcementAction;
|
|
873
|
+
if (hookAction === "continue") {
|
|
874
|
+
effectiveAction = "none";
|
|
875
|
+
}
|
|
876
|
+
else if (hookAction === "pause") {
|
|
877
|
+
effectiveAction = "pause";
|
|
878
|
+
}
|
|
879
|
+
else if (hookAction === "downgrade") {
|
|
880
|
+
effectiveAction = "warn";
|
|
881
|
+
}
|
|
882
|
+
if (threshold.pct === 100 && effectiveAction !== "none") {
|
|
827
883
|
// 100% — special enforcement logic (halt/pause/warn)
|
|
828
884
|
const msg = `Budget ceiling ${deps.formatCost(budgetCeiling)} reached (spent ${deps.formatCost(totalCost)}).`;
|
|
829
|
-
if (
|
|
885
|
+
if (effectiveAction === "halt") {
|
|
830
886
|
deps.sendDesktopNotification("GSD", msg, "error", "budget", basename(s.originalBasePath || s.basePath));
|
|
831
887
|
await deps.stopAuto(ctx, pi, "Budget ceiling reached");
|
|
832
888
|
debugLog("autoLoop", { phase: "exit", reason: "budget-halt" });
|
|
833
889
|
return { action: "break", reason: "budget-halt" };
|
|
834
890
|
}
|
|
835
|
-
if (
|
|
891
|
+
if (effectiveAction === "pause") {
|
|
836
892
|
ctx.ui.notify(`${msg} Pausing auto-mode — /gsd auto to override and continue.`, "warning");
|
|
837
893
|
deps.sendDesktopNotification("GSD", msg, "warning", "budget", basename(s.originalBasePath || s.basePath));
|
|
838
894
|
deps.logCmuxEvent(prefs, msg, "warning");
|
|
@@ -1000,6 +1056,14 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1000
1056
|
const safetyConfig = resolveSafetyHarnessConfig(prefs?.safety_harness);
|
|
1001
1057
|
if (safetyConfig.enabled && safetyConfig.evidence_collection) {
|
|
1002
1058
|
resetEvidence();
|
|
1059
|
+
// Restore persisted evidence so session-restart resumes don't produce
|
|
1060
|
+
// false-positive "no bash calls" warnings (Bug #4385).
|
|
1061
|
+
if (s.basePath && unitType === "execute-task") {
|
|
1062
|
+
const { milestone: eMid, slice: eSid, task: eTid } = parseUnitId(unitId);
|
|
1063
|
+
if (eMid && eSid && eTid) {
|
|
1064
|
+
loadEvidenceFromDisk(s.basePath, eMid, eSid, eTid);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1003
1067
|
}
|
|
1004
1068
|
// Only checkpoint code-executing units (not lifecycle/planning units)
|
|
1005
1069
|
if (safetyConfig.enabled && safetyConfig.checkpoints && unitType === "execute-task") {
|
|
@@ -1066,7 +1130,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1066
1130
|
logWarning("engine", "Prompt reorder failed", { error: msg });
|
|
1067
1131
|
}
|
|
1068
1132
|
// Select and apply model (with tier escalation on retry — normal units only)
|
|
1069
|
-
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride);
|
|
1133
|
+
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride, s.autoModeStartThinkingLevel);
|
|
1070
1134
|
s.currentUnitRouting =
|
|
1071
1135
|
modelResult.routing;
|
|
1072
1136
|
s.currentUnitModel =
|
|
@@ -1079,6 +1143,9 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1079
1143
|
if (match) {
|
|
1080
1144
|
const ok = await pi.setModel(match, { persist: false });
|
|
1081
1145
|
if (ok) {
|
|
1146
|
+
if (s.autoModeStartThinkingLevel) {
|
|
1147
|
+
pi.setThinkingLevel(s.autoModeStartThinkingLevel);
|
|
1148
|
+
}
|
|
1082
1149
|
s.currentUnitModel = match;
|
|
1083
1150
|
ctx.ui.notify(`Hook model override: ${match.provider}/${match.id}`, "info");
|
|
1084
1151
|
}
|
|
@@ -1173,20 +1240,23 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1173
1240
|
}
|
|
1174
1241
|
}
|
|
1175
1242
|
if (unitResult.status === "cancelled") {
|
|
1243
|
+
const errorCategory = unitResult.errorContext?.category;
|
|
1176
1244
|
// Provider-error pause: pauseAuto already handled cleanup and scheduled
|
|
1177
1245
|
// recovery. Don't hard-stop — just break out of the loop (#2762).
|
|
1178
|
-
if (
|
|
1246
|
+
if (errorCategory === "provider") {
|
|
1179
1247
|
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1180
|
-
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext
|
|
1248
|
+
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext?.isTransient });
|
|
1181
1249
|
return { action: "break", reason: "provider-pause" };
|
|
1182
1250
|
}
|
|
1183
1251
|
// Timeout category covers two distinct scenarios:
|
|
1184
1252
|
// 1. Session creation timeout (120s) — transient, auto-resume with backoff
|
|
1185
1253
|
// 2. Unit hard timeout (30min+) — stuck agent, pause for manual review
|
|
1254
|
+
// Transient session-failed covers recoverable newSession failures and should
|
|
1255
|
+
// pause instead of hard-stopping.
|
|
1186
1256
|
// Structural errors (TypeError, is not a function) are NOT transient
|
|
1187
1257
|
// and must hard-stop to avoid infinite retry loops.
|
|
1188
1258
|
if (unitResult.errorContext?.isTransient &&
|
|
1189
|
-
|
|
1259
|
+
errorCategory === "timeout") {
|
|
1190
1260
|
const isSessionCreationTimeout = unitResult.errorContext.message?.includes("Session creation timed out");
|
|
1191
1261
|
if (isSessionCreationTimeout) {
|
|
1192
1262
|
consecutiveSessionTimeouts += 1;
|
|
@@ -1229,6 +1299,15 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1229
1299
|
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1230
1300
|
return { action: "break", reason: "unit-hard-timeout" };
|
|
1231
1301
|
}
|
|
1302
|
+
if (unitResult.errorContext?.isTransient &&
|
|
1303
|
+
errorCategory === "session-failed") {
|
|
1304
|
+
ctx.ui.notify(`Session creation failed transiently for ${unitType} ${unitId}: ${unitResult.errorContext?.message ?? "unknown"}. Pausing auto-mode (recoverable).`, "warning");
|
|
1305
|
+
debugLog("autoLoop", { phase: "session-start-transient-pause", unitType, unitId, category: errorCategory });
|
|
1306
|
+
await deps.pauseAuto(ctx, pi);
|
|
1307
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
1308
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1309
|
+
return { action: "break", reason: "session-timeout" };
|
|
1310
|
+
}
|
|
1232
1311
|
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
1233
1312
|
if (s.currentUnit) {
|
|
1234
1313
|
await deps.closeoutUnit(ctx, s.basePath, unitType, unitId, s.currentUnit.startedAt, deps.buildSnapshotOpts(unitType, unitId));
|
|
@@ -1387,6 +1466,20 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1387
1466
|
}
|
|
1388
1467
|
else {
|
|
1389
1468
|
// s.pendingVerificationRetry was set by postUnitPreVerification.
|
|
1469
|
+
// Emit a dedicated journal event so forensics can distinguish bounded
|
|
1470
|
+
// verification retries from genuine stuck-loop dispatch repetitions (#4540).
|
|
1471
|
+
const retryInfo = s.pendingVerificationRetry;
|
|
1472
|
+
deps.emitJournalEvent({
|
|
1473
|
+
ts: new Date().toISOString(),
|
|
1474
|
+
flowId: ic.flowId,
|
|
1475
|
+
seq: ic.nextSeq(),
|
|
1476
|
+
eventType: "artifact-verification-retry",
|
|
1477
|
+
data: {
|
|
1478
|
+
unitType: preUnitSnapshot?.type,
|
|
1479
|
+
unitId: retryInfo?.unitId,
|
|
1480
|
+
attempt: retryInfo?.attempt,
|
|
1481
|
+
},
|
|
1482
|
+
});
|
|
1390
1483
|
// Continue the loop — next iteration will inject the retry context into the prompt.
|
|
1391
1484
|
debugLog("autoLoop", { phase: "artifact-verification-retry", iteration: ic.iteration });
|
|
1392
1485
|
return { action: "continue" };
|
|
@@ -26,15 +26,24 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
26
26
|
let sessionResult;
|
|
27
27
|
let sessionTimeoutHandle;
|
|
28
28
|
const mySessionSwitchGeneration = ++sessionSwitchGeneration;
|
|
29
|
+
// #3731: Cancellation controller for newSession(). When the session-creation
|
|
30
|
+
// timeout fires, we abort this controller so that the still-in-flight
|
|
31
|
+
// newSession() discards itself after await this.abort() completes, preventing
|
|
32
|
+
// it from capturing the (now-root) process.cwd() and rebuilding the tool
|
|
33
|
+
// runtime with the wrong cwd.
|
|
34
|
+
const sessionAbortController = new AbortController();
|
|
29
35
|
_setSessionSwitchInFlight(true);
|
|
30
36
|
try {
|
|
31
|
-
const sessionPromise = s.cmdCtx.newSession().finally(() => {
|
|
37
|
+
const sessionPromise = s.cmdCtx.newSession({ abortSignal: sessionAbortController.signal }).finally(() => {
|
|
32
38
|
if (sessionSwitchGeneration === mySessionSwitchGeneration) {
|
|
33
39
|
_setSessionSwitchInFlight(false);
|
|
34
40
|
}
|
|
35
41
|
});
|
|
36
42
|
const timeoutPromise = new Promise((resolve) => {
|
|
37
|
-
sessionTimeoutHandle = setTimeout(() =>
|
|
43
|
+
sessionTimeoutHandle = setTimeout(() => {
|
|
44
|
+
sessionAbortController.abort();
|
|
45
|
+
resolve({ cancelled: true });
|
|
46
|
+
}, NEW_SESSION_TIMEOUT_MS);
|
|
38
47
|
});
|
|
39
48
|
sessionResult = await Promise.race([sessionPromise, timeoutPromise]);
|
|
40
49
|
}
|
|
@@ -92,6 +101,33 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
92
101
|
catch (e) {
|
|
93
102
|
logWarning("engine", "Failed to chdir to basePath before dispatch", { basePath: s.basePath, error: String(e) });
|
|
94
103
|
}
|
|
104
|
+
// ── Provider request-readiness pre-check (#4555) ──
|
|
105
|
+
// Verify the provider can accept requests before dispatching. If the token
|
|
106
|
+
// has expired since bootstrap, return cancelled immediately so the unit is
|
|
107
|
+
// not wasted on a guaranteed 401.
|
|
108
|
+
{
|
|
109
|
+
const provider = s.currentUnitModel?.provider ?? ctx.model?.provider;
|
|
110
|
+
const registry = ctx.modelRegistry;
|
|
111
|
+
if (provider && registry != null && typeof registry.isProviderRequestReady === "function") {
|
|
112
|
+
let ready = false;
|
|
113
|
+
try {
|
|
114
|
+
ready = registry.isProviderRequestReady(provider);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
ready = false;
|
|
118
|
+
}
|
|
119
|
+
if (!ready) {
|
|
120
|
+
return {
|
|
121
|
+
status: "cancelled",
|
|
122
|
+
errorContext: {
|
|
123
|
+
message: `Provider ${provider} is not request-ready (login/token expired)`,
|
|
124
|
+
category: "provider",
|
|
125
|
+
isTransient: false,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
95
131
|
// ── Send the prompt ──
|
|
96
132
|
debugLog("runUnit", { phase: "send-message", unitType, unitId });
|
|
97
133
|
pi.sendMessage({ customType: "gsd-auto", content: prompt, display: s.verbose }, { triggerTurn: true });
|
|
@@ -65,6 +65,8 @@ export class AutoSession {
|
|
|
65
65
|
currentDispatchedModelId = null;
|
|
66
66
|
originalModelId = null;
|
|
67
67
|
originalModelProvider = null;
|
|
68
|
+
autoModeStartThinkingLevel = null;
|
|
69
|
+
originalThinkingLevel = null;
|
|
68
70
|
lastBudgetAlertLevel = 0;
|
|
69
71
|
// ── Recovery ─────────────────────────────────────────────────────────────
|
|
70
72
|
pendingCrashRecovery = null;
|
|
@@ -77,6 +79,17 @@ export class AutoSession {
|
|
|
77
79
|
lastStateRebuildAt = 0;
|
|
78
80
|
// ── Sidecar queue ─────────────────────────────────────────────────────
|
|
79
81
|
sidecarQueue = [];
|
|
82
|
+
// ── Pre-exec gate failure context (#4551) ───────────────────────────
|
|
83
|
+
/**
|
|
84
|
+
* Persisted when a pre-execution gate fails on a plan-slice or refine-slice
|
|
85
|
+
* unit. The planning → plan-slice dispatch rule reads this field and injects
|
|
86
|
+
* the failure details into the next re-dispatch prompt so the LLM can fix the
|
|
87
|
+
* specific issues instead of producing an identical plan.
|
|
88
|
+
*
|
|
89
|
+
* Cleared after it has been consumed (injected into the prompt) to avoid
|
|
90
|
+
* stale context bleeding into unrelated slices.
|
|
91
|
+
*/
|
|
92
|
+
lastPreExecFailure = null;
|
|
80
93
|
// ── Tool invocation errors (#2883) ──────────────────────────────────
|
|
81
94
|
/** Set when a GSD tool execution ends with isError due to malformed/truncated
|
|
82
95
|
* JSON arguments. Checked by postUnitPreVerification to break retry loops. */
|
|
@@ -137,7 +150,12 @@ export class AutoSession {
|
|
|
137
150
|
this.unitLifetimeDispatches.clear();
|
|
138
151
|
}
|
|
139
152
|
get lockBasePath() {
|
|
140
|
-
|
|
153
|
+
// Prefer originalBasePath (project root); fall back to basePath.
|
|
154
|
+
// Strip /.gsd/worktrees/ suffix if basePath is itself a worktree path
|
|
155
|
+
// to avoid reading/writing the lock inside the worktree (#3729).
|
|
156
|
+
const resolved = this.originalBasePath || this.basePath;
|
|
157
|
+
const markerIdx = resolved.indexOf("/.gsd/worktrees/");
|
|
158
|
+
return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
|
|
141
159
|
}
|
|
142
160
|
reset() {
|
|
143
161
|
this.clearTimers();
|
|
@@ -177,6 +195,8 @@ export class AutoSession {
|
|
|
177
195
|
this.currentDispatchedModelId = null;
|
|
178
196
|
this.originalModelId = null;
|
|
179
197
|
this.originalModelProvider = null;
|
|
198
|
+
this.autoModeStartThinkingLevel = null;
|
|
199
|
+
this.originalThinkingLevel = null;
|
|
180
200
|
this.lastBudgetAlertLevel = 0;
|
|
181
201
|
// Recovery
|
|
182
202
|
this.pendingCrashRecovery = null;
|
|
@@ -195,6 +215,7 @@ export class AutoSession {
|
|
|
195
215
|
this.sidecarQueue = [];
|
|
196
216
|
this.rewriteAttemptCount = 0;
|
|
197
217
|
this.consecutiveCompleteBootstraps = 0;
|
|
218
|
+
this.lastPreExecFailure = null;
|
|
198
219
|
this.lastToolInvocationError = null;
|
|
199
220
|
this.lastGitActionFailure = null;
|
|
200
221
|
this.lastGitActionStatus = null;
|
|
@@ -451,18 +451,31 @@ export const DISPATCH_RULES = [
|
|
|
451
451
|
},
|
|
452
452
|
{
|
|
453
453
|
name: "planning → plan-slice",
|
|
454
|
-
match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry }) => {
|
|
454
|
+
match: async ({ state, mid, midTitle, basePath, sessionContextWindow, modelRegistry, session }) => {
|
|
455
455
|
if (state.phase !== "planning")
|
|
456
456
|
return null;
|
|
457
457
|
if (!state.activeSlice)
|
|
458
458
|
return missingSliceStop(mid, state.phase);
|
|
459
459
|
const sid = state.activeSlice.id;
|
|
460
460
|
const sTitle = state.activeSlice.title;
|
|
461
|
+
// #4551: Consume any persisted pre-exec failure for this slice so the
|
|
462
|
+
// re-dispatched prompt includes the exact blocked references. Clear the
|
|
463
|
+
// field immediately after reading to prevent stale context leaking into
|
|
464
|
+
// a later, unrelated plan-slice run.
|
|
465
|
+
const unitId = `${mid}/${sid}`;
|
|
466
|
+
let priorPreExecFailure;
|
|
467
|
+
if (session?.lastPreExecFailure?.unitId === unitId) {
|
|
468
|
+
priorPreExecFailure = {
|
|
469
|
+
blockingFindings: session.lastPreExecFailure.blockingFindings,
|
|
470
|
+
verdictExcerpt: session.lastPreExecFailure.verdictExcerpt,
|
|
471
|
+
};
|
|
472
|
+
session.lastPreExecFailure = null;
|
|
473
|
+
}
|
|
461
474
|
return {
|
|
462
475
|
action: "dispatch",
|
|
463
476
|
unitType: "plan-slice",
|
|
464
|
-
unitId
|
|
465
|
-
prompt: await buildPlanSlicePrompt(mid, midTitle, sid, sTitle, basePath, undefined, { sessionContextWindow, modelRegistry }),
|
|
477
|
+
unitId,
|
|
478
|
+
prompt: await buildPlanSlicePrompt(mid, midTitle, sid, sTitle, basePath, undefined, { sessionContextWindow, modelRegistry, priorPreExecFailure }),
|
|
466
479
|
};
|
|
467
480
|
},
|
|
468
481
|
},
|
|
@@ -12,10 +12,20 @@ import { getSessionModelOverride } from "./session-model-override.js";
|
|
|
12
12
|
import { logWarning } from "./workflow-logger.js";
|
|
13
13
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
14
14
|
import { applyModelPolicyFilter } from "./uok/model-policy.js";
|
|
15
|
+
import { isModelBlocked } from "./blocked-models.js";
|
|
16
|
+
function reapplyThinkingLevel(pi, level) {
|
|
17
|
+
if (!level)
|
|
18
|
+
return;
|
|
19
|
+
pi.setThinkingLevel(level);
|
|
20
|
+
}
|
|
15
21
|
export function resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode = true) {
|
|
16
22
|
const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
17
|
-
if (explicitConfig)
|
|
18
|
-
return
|
|
23
|
+
if (explicitConfig) {
|
|
24
|
+
return {
|
|
25
|
+
...explicitConfig,
|
|
26
|
+
source: "explicit",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
19
29
|
// In interactive mode, don't synthesize a routing-based model config.
|
|
20
30
|
// The user's session model (/model) should be used as-is (#3962).
|
|
21
31
|
if (!isAutoMode)
|
|
@@ -38,6 +48,7 @@ export function resolvePreferredModelConfig(unitType, autoModeStartModel, isAuto
|
|
|
38
48
|
return {
|
|
39
49
|
primary: ceilingModel,
|
|
40
50
|
fallbacks: [],
|
|
51
|
+
source: "synthesized",
|
|
41
52
|
};
|
|
42
53
|
}
|
|
43
54
|
/**
|
|
@@ -52,7 +63,9 @@ export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, p
|
|
|
52
63
|
* Dynamic routing only applies in auto-mode where cost optimization is expected. (#3962) */
|
|
53
64
|
isAutoMode = true,
|
|
54
65
|
/** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
|
|
55
|
-
sessionModelOverride
|
|
66
|
+
sessionModelOverride,
|
|
67
|
+
/** Thinking level captured at auto-mode start and re-applied after model swaps. */
|
|
68
|
+
autoModeStartThinkingLevel) {
|
|
56
69
|
const uokFlags = resolveUokFlags(prefs);
|
|
57
70
|
const effectiveSessionModelOverride = sessionModelOverride === undefined
|
|
58
71
|
? getSessionModelOverride(ctx.sessionManager.getSessionId())
|
|
@@ -90,6 +103,11 @@ sessionModelOverride) {
|
|
|
90
103
|
if (prefs?.token_profile === "burn-max") {
|
|
91
104
|
routingConfig.enabled = false;
|
|
92
105
|
}
|
|
106
|
+
if (modelConfig.source === "explicit") {
|
|
107
|
+
// Explicit per-phase model preferences express hard user intent.
|
|
108
|
+
// Dynamic routing may only treat synthesized tier ceilings as downgradeable.
|
|
109
|
+
routingConfig.enabled = false;
|
|
110
|
+
}
|
|
93
111
|
let effectiveModelConfig = modelConfig;
|
|
94
112
|
let routingTierLabel = "";
|
|
95
113
|
let routingEligibleModels = availableModels;
|
|
@@ -210,6 +228,7 @@ sessionModelOverride) {
|
|
|
210
228
|
effectiveModelConfig = {
|
|
211
229
|
primary: routingResult.modelId,
|
|
212
230
|
fallbacks: routingResult.fallbacks,
|
|
231
|
+
source: modelConfig.source,
|
|
213
232
|
};
|
|
214
233
|
// Always notify on model downgrade — users should see when their
|
|
215
234
|
// model selection is overridden, not just in verbose mode (#3962).
|
|
@@ -249,6 +268,14 @@ sessionModelOverride) {
|
|
|
249
268
|
}
|
|
250
269
|
attemptedPolicyEligible = true;
|
|
251
270
|
}
|
|
271
|
+
// Skip models the provider has previously rejected for this account
|
|
272
|
+
// (issue #4513). The block is persisted in .gsd/runtime/blocked-models.json
|
|
273
|
+
// so it survives /gsd auto restarts — without this, the same dead model
|
|
274
|
+
// gets reselected after every restart.
|
|
275
|
+
if (isModelBlocked(basePath, model.provider, model.id)) {
|
|
276
|
+
ctx.ui.notify(`Skipping blocked model ${model.provider}/${model.id} (provider rejected it for this account).`, "warning");
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
252
279
|
// Warn if the ID is ambiguous across providers
|
|
253
280
|
if (!modelId.includes("/")) {
|
|
254
281
|
const providers = availableModels.filter(m => m.id === modelId).map(m => m.provider);
|
|
@@ -260,10 +287,11 @@ sessionModelOverride) {
|
|
|
260
287
|
const ok = await pi.setModel(model, { persist: false });
|
|
261
288
|
if (ok) {
|
|
262
289
|
appliedModel = model;
|
|
290
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
263
291
|
// ADR-005: Adjust active tool set for the selected model's provider capabilities.
|
|
264
292
|
// Hard-filter incompatible tools, then let extensions override via adjust_tool_set hook.
|
|
265
293
|
const activeToolNames = pi.getActiveTools();
|
|
266
|
-
const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api);
|
|
294
|
+
const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api, model.provider);
|
|
267
295
|
let finalToolNames = compatibleTools;
|
|
268
296
|
// Fire adjust_tool_set hook — extensions can override the filtered tool set
|
|
269
297
|
if (routingConfig.hooks !== false) {
|
|
@@ -314,19 +342,28 @@ sessionModelOverride) {
|
|
|
314
342
|
// No model preference for this unit type — re-apply the model captured
|
|
315
343
|
// at auto-mode start to prevent bleed from shared global settings.json (#650).
|
|
316
344
|
const availableModels = ctx.modelRegistry.getAvailable();
|
|
317
|
-
const
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
345
|
+
const startBlocked = isModelBlocked(basePath, autoModeStartModel.provider, autoModeStartModel.id);
|
|
346
|
+
if (startBlocked) {
|
|
347
|
+
ctx.ui.notify(`Auto-mode start model ${autoModeStartModel.provider}/${autoModeStartModel.id} is blocked for this account. Using current session model instead.`, "warning");
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
const startModel = availableModels.find(m => m.provider === autoModeStartModel.provider && m.id === autoModeStartModel.id);
|
|
351
|
+
if (startModel) {
|
|
352
|
+
const ok = await pi.setModel(startModel, { persist: false });
|
|
353
|
+
if (!ok) {
|
|
354
|
+
const byId = availableModels.find(m => m.id === autoModeStartModel.id && !isModelBlocked(basePath, m.provider, m.id));
|
|
355
|
+
if (byId) {
|
|
356
|
+
const fallbackOk = await pi.setModel(byId, { persist: false });
|
|
357
|
+
if (fallbackOk) {
|
|
358
|
+
appliedModel = byId;
|
|
359
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
appliedModel = startModel;
|
|
365
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
326
366
|
}
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
appliedModel = startModel;
|
|
330
367
|
}
|
|
331
368
|
}
|
|
332
369
|
}
|
|
@@ -30,7 +30,7 @@ import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookSta
|
|
|
30
30
|
import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures } from "./captures.js";
|
|
31
31
|
import { debugLog } from "./debug-logger.js";
|
|
32
32
|
import { runSafely } from "./auto-utils.js";
|
|
33
|
-
import { getEvidence } from "./safety/evidence-collector.js";
|
|
33
|
+
import { getEvidence, clearEvidenceFromDisk } from "./safety/evidence-collector.js";
|
|
34
34
|
import { validateFileChanges } from "./safety/file-change-validator.js";
|
|
35
35
|
// crossReferenceEvidence available for future use when verification_evidence is stored in DB
|
|
36
36
|
// import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
|
|
@@ -535,7 +535,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
535
535
|
if (taskRow) {
|
|
536
536
|
const expectedOutput = taskRow.expected_output ?? [];
|
|
537
537
|
const plannedFiles = taskRow.files ?? [];
|
|
538
|
-
const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles);
|
|
538
|
+
const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
|
|
539
539
|
if (audit && audit.violations.length > 0) {
|
|
540
540
|
const warnings = audit.violations.filter(v => v.severity === "warning");
|
|
541
541
|
for (const v of warnings) {
|
|
@@ -588,6 +588,16 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
588
588
|
debugLog("postUnit", { phase: "safety-content-validation", error: String(e) });
|
|
589
589
|
}
|
|
590
590
|
}
|
|
591
|
+
// Clear persisted evidence file now that post-unit processing is complete
|
|
592
|
+
// (Bug #4385 — prevents stale evidence from affecting retries of same unit ID).
|
|
593
|
+
if (safetyConfig.evidence_collection && s.currentUnit.type === "execute-task" && sMid && sSid && sTid) {
|
|
594
|
+
try {
|
|
595
|
+
clearEvidenceFromDisk(s.basePath, sMid, sSid, sTid);
|
|
596
|
+
}
|
|
597
|
+
catch (e) {
|
|
598
|
+
debugLog("postUnit", { phase: "safety-evidence-clear", error: String(e) });
|
|
599
|
+
}
|
|
600
|
+
}
|
|
591
601
|
}
|
|
592
602
|
}
|
|
593
603
|
catch (e) {
|
|
@@ -950,12 +960,25 @@ export async function postUnitPostVerification(pctx) {
|
|
|
950
960
|
const suffix = blockingChecks.length > 3 ? `\n \u2022 ...and ${blockingChecks.length - 3} more` : "";
|
|
951
961
|
const evidenceNote = `\nSee ${sid}-PRE-EXEC-VERIFY.json for full details.`;
|
|
952
962
|
ctx.ui.notify(`Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found\n${details}${suffix}${evidenceNote}`, "error");
|
|
963
|
+
// Persist failure context so the next plan-slice re-dispatch can inject
|
|
964
|
+
// it into the prompt and break the infinite loop (#4551).
|
|
965
|
+
s.lastPreExecFailure = {
|
|
966
|
+
unitId: currentUnit.id,
|
|
967
|
+
blockingFindings: blockingChecks.map(c => `[${c.category}] ${c.target}: ${c.message}`),
|
|
968
|
+
verdictExcerpt: `status=${result.status}; ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} detected`,
|
|
969
|
+
};
|
|
953
970
|
preExecPauseNeeded = true;
|
|
954
971
|
}
|
|
955
972
|
else if (result.status === "warn") {
|
|
956
973
|
ctx.ui.notify(`Pre-execution checks passed with warnings`, "warning");
|
|
957
974
|
// Strict mode: treat warnings as blocking
|
|
958
975
|
if (prefs?.enhanced_verification_strict === true) {
|
|
976
|
+
const warnChecks = result.checks.filter(c => !c.passed);
|
|
977
|
+
s.lastPreExecFailure = {
|
|
978
|
+
unitId: currentUnit.id,
|
|
979
|
+
blockingFindings: warnChecks.map(c => `[${c.category}] ${c.target}: ${c.message}`),
|
|
980
|
+
verdictExcerpt: `status=${result.status} (strict mode); ${warnChecks.length} warning${warnChecks.length === 1 ? "" : "s"} treated as blocking`,
|
|
981
|
+
};
|
|
959
982
|
preExecPauseNeeded = true;
|
|
960
983
|
}
|
|
961
984
|
}
|
|
@@ -1223,6 +1223,20 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
|
|
|
1223
1223
|
prependBlocks.push(`## Prior Sketch Scope (soft hint — non-binding)\n\n${options.softScopeHint.trim()}\n\n` +
|
|
1224
1224
|
`This scope was captured during an earlier progressive-planning pass that was later disabled. Treat it as context only — you may plan beyond it if the work genuinely requires more scope. Do NOT treat this as a hard boundary.`);
|
|
1225
1225
|
}
|
|
1226
|
+
// #4551: inject pre-exec failure context so the re-dispatched plan-slice
|
|
1227
|
+
// addresses the exact blocked references rather than reproducing the same plan.
|
|
1228
|
+
if (options?.priorPreExecFailure) {
|
|
1229
|
+
const { blockingFindings, verdictExcerpt } = options.priorPreExecFailure;
|
|
1230
|
+
const findingsList = blockingFindings.length > 0
|
|
1231
|
+
? blockingFindings.map(f => `- ${f}`).join("\n")
|
|
1232
|
+
: "- (no specific findings recorded)";
|
|
1233
|
+
prependBlocks.push(`## Fix these specific issues from the prior pre-exec check\n\n` +
|
|
1234
|
+
`The previous plan-slice attempt was blocked by pre-execution validation.\n` +
|
|
1235
|
+
`Gate verdict: ${verdictExcerpt}\n\n` +
|
|
1236
|
+
`Blocked references that must be resolved in this plan:\n${findingsList}\n\n` +
|
|
1237
|
+
`Revise the plan so that every reference listed above is satisfied before execution begins. ` +
|
|
1238
|
+
`Do not reproduce the same file paths, package names, or task ordering that caused these failures.`);
|
|
1239
|
+
}
|
|
1226
1240
|
return renderSlicePrompt({
|
|
1227
1241
|
mid, sid, sTitle, base,
|
|
1228
1242
|
level: level ?? resolveInlineLevel(),
|