@opengsd/gsd-pi 1.2.0-dev.d6c5343c → 1.2.0-dev.ddc97c10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp-server.js +2 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +28 -10
- package/dist/resources/extensions/gsd/auto/phases.js +47 -4
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -2
- package/dist/resources/extensions/gsd/auto-model-selection.js +11 -7
- package/dist/resources/extensions/gsd/auto-post-unit.js +18 -6
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
- package/dist/resources/extensions/gsd/auto-verification.js +14 -2
- package/dist/resources/extensions/gsd/auto.js +37 -1
- package/dist/resources/extensions/gsd/blocked-models.js +28 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +26 -6
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
- package/dist/resources/extensions/gsd/closeout-wizard.js +92 -0
- package/dist/resources/extensions/gsd/commands/context.js +16 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +46 -3
- package/dist/resources/extensions/gsd/consent-question.js +16 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -3
- package/dist/resources/extensions/gsd/doctor-git-checks.js +2 -18
- package/dist/resources/extensions/gsd/gsd-command-home.js +22 -12
- package/dist/resources/extensions/gsd/gsd-db.js +2 -1
- package/dist/resources/extensions/gsd/guided-flow.js +6 -3
- package/dist/resources/extensions/gsd/milestone-closeout.js +73 -2
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
- package/dist/resources/extensions/gsd/projection-flush.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
- package/dist/resources/extensions/gsd/session-lock.js +1 -1
- package/dist/resources/extensions/gsd/tool-contract.js +14 -3
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +67 -2
- package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
- package/dist/resources/extensions/shared/gsd-browser-cli.js +21 -2
- package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
- package/dist/resources/shared/package-manager-detection.js +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-check.d.ts +2 -0
- package/dist/update-check.js +24 -1
- package/dist/update-cmd.js +20 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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 +12 -12
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/cli.js +10 -5
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/moonshot-tool-schema.d.ts +29 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +4 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +18 -18
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +99 -38
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +5 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +2 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +12 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
- package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +12 -3
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.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 +6 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +11 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +28 -10
- package/src/resources/extensions/gsd/auto/phases.ts +63 -24
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +10 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +11 -10
- package/src/resources/extensions/gsd/auto-model-selection.ts +16 -7
- package/src/resources/extensions/gsd/auto-post-unit.ts +21 -6
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
- package/src/resources/extensions/gsd/auto-verification.ts +18 -2
- package/src/resources/extensions/gsd/auto.ts +44 -1
- package/src/resources/extensions/gsd/blocked-models.ts +49 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
- package/src/resources/extensions/gsd/closeout-wizard.ts +102 -0
- package/src/resources/extensions/gsd/commands/context.ts +16 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +46 -3
- package/src/resources/extensions/gsd/consent-question.ts +15 -0
- package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-git-checks.ts +2 -19
- package/src/resources/extensions/gsd/gsd-command-home.ts +13 -3
- package/src/resources/extensions/gsd/gsd-db.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +21 -26
- package/src/resources/extensions/gsd/milestone-closeout.ts +97 -2
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
- package/src/resources/extensions/gsd/projection-flush.ts +20 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
- package/src/resources/extensions/gsd/session-lock.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
- package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/consent-question.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/doctor-git-checks-terminal.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +2 -6
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +95 -4
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
- package/src/resources/extensions/gsd/tool-contract.ts +38 -3
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +3 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +81 -2
- package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
- package/src/resources/extensions/shared/gsd-browser-cli.ts +23 -2
- package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
- package/src/resources/shared/package-manager-detection.ts +1 -1
- /package/dist/web/standalone/.next/static/{jmTLg6xZmAuq_LIqKOxrH → McokybTayhff1xEVc-d3T}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{jmTLg6xZmAuq_LIqKOxrH → McokybTayhff1xEVc-d3T}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsd/pi-coding-agent",
|
|
3
|
-
"version": "1.2.0-dev.
|
|
3
|
+
"version": "1.2.0-dev.ddc97c10",
|
|
4
4
|
"description": "Coding agent CLI (vendored from earendil-works/pi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"gsd": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"copy-assets": "node scripts/copy-assets.cjs"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@opengsd/contracts": "^1.2.0-dev.
|
|
36
|
+
"@opengsd/contracts": "^1.2.0-dev.ddc97c10",
|
|
37
37
|
"@mariozechner/jiti": "^2.6.2",
|
|
38
38
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
39
39
|
"chalk": "5.6.2",
|
|
@@ -53,11 +53,11 @@
|
|
|
53
53
|
"typebox": "1.1.38",
|
|
54
54
|
"undici": "7.26.0",
|
|
55
55
|
"yaml": "2.9.0",
|
|
56
|
-
"@gsd/agent-core": "^1.2.0-dev.
|
|
57
|
-
"@gsd/native": "^1.2.0-dev.
|
|
58
|
-
"@gsd/pi-agent-core": "^1.2.0-dev.
|
|
59
|
-
"@gsd/pi-ai": "^1.2.0-dev.
|
|
60
|
-
"@gsd/pi-tui": "^1.2.0-dev.
|
|
56
|
+
"@gsd/agent-core": "^1.2.0-dev.ddc97c10",
|
|
57
|
+
"@gsd/native": "^1.2.0-dev.ddc97c10",
|
|
58
|
+
"@gsd/pi-agent-core": "^1.2.0-dev.ddc97c10",
|
|
59
|
+
"@gsd/pi-ai": "^1.2.0-dev.ddc97c10",
|
|
60
|
+
"@gsd/pi-tui": "^1.2.0-dev.ddc97c10",
|
|
61
61
|
"@sinclair/typebox": "^0.34.41"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsd/pi-tui",
|
|
3
|
-
"version": "1.2.0-dev.
|
|
3
|
+
"version": "1.2.0-dev.ddc97c10",
|
|
4
4
|
"description": "Terminal UI library (vendored from earendil-works/pi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"gsd": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build": "node ../../scripts/clean-package-dist.cjs && tsc -p tsconfig.json --incremental false"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@gsd/native": "^1.2.0-dev.
|
|
24
|
+
"@gsd/native": "^1.2.0-dev.ddc97c10",
|
|
25
25
|
"get-east-asian-width": "1.6.0",
|
|
26
26
|
"marked": "15.0.12",
|
|
27
27
|
"@sinclair/typebox": "^0.34.41"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengsd/rpc-client",
|
|
3
|
-
"version": "1.2.0-dev.
|
|
3
|
+
"version": "1.2.0-dev.ddc97c10",
|
|
4
4
|
"description": "Standalone RPC client SDK for GSD — zero internal dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"gsd": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "node --test dist/rpc-client.test.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@opengsd/contracts": "^1.2.0-dev.
|
|
37
|
+
"@opengsd/contracts": "^1.2.0-dev.ddc97c10"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22.0.0"
|
package/pkg/package.json
CHANGED
|
@@ -38,6 +38,17 @@ describe("resolveGsdBrowserMcpLaunchConfig identity flags", () => {
|
|
|
38
38
|
assert.equal(args[args.indexOf("--identity-key") + 1], "custom-key");
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
it("splits GSD_BROWSER_MCP_COMMAND command lines before spawning", () => {
|
|
42
|
+
const commandLine = '"C:\\Program Files\\nodejs\\node.exe" "C:\\Users\\Test User\\AppData\\Roaming\\npm\\node_modules\\@opengsd\\gsd-browser\\bin\\gsd-browser"';
|
|
43
|
+
const { command, args } = resolveGsdBrowserMcpLaunchConfig("C:\\Users\\Test User\\project", {
|
|
44
|
+
GSD_BROWSER_MCP_COMMAND: commandLine,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
assert.equal(command, "C:\\Program Files\\nodejs\\node.exe");
|
|
48
|
+
assert.equal(args[0], "C:\\Users\\Test User\\AppData\\Roaming\\npm\\node_modules\\@opengsd\\gsd-browser\\bin\\gsd-browser");
|
|
49
|
+
assert.equal(args[1], "mcp");
|
|
50
|
+
});
|
|
51
|
+
|
|
41
52
|
it("uses a path-safe identity-project identifier", () => {
|
|
42
53
|
const { args } = resolveGsdBrowserMcpLaunchConfig("/tmp/example/project", {});
|
|
43
54
|
const projectId = args[args.indexOf("--identity-project") + 1];
|
|
@@ -22,7 +22,7 @@ type BlockedAdvanceResult = Extract<AutoAdvanceResult, { kind: "blocked" }>;
|
|
|
22
22
|
import { debugCount, debugLog, debugTime } from "../debug-logger.js";
|
|
23
23
|
import { reconcileBeforeDispatch } from "../state-reconciliation.js";
|
|
24
24
|
import { isLegalEdge, IllegalPhaseTransitionError } from "../state-transition-matrix.js";
|
|
25
|
-
import { resolveDispatch } from "../auto-dispatch.js";
|
|
25
|
+
import { hasPendingDeepStage, resolveDispatch } from "../auto-dispatch.js";
|
|
26
26
|
import { classifyFailure } from "../recovery-classification.js";
|
|
27
27
|
import { verifyExpectedArtifact, refreshRecoveryDbForArtifact } from "../auto-recovery.js";
|
|
28
28
|
import { invalidateAllCaches } from "../cache.js";
|
|
@@ -193,14 +193,25 @@ export async function decideOrchestratorDispatch(
|
|
|
193
193
|
): Promise<DispatchDecision> {
|
|
194
194
|
const state = input.stateSnapshot;
|
|
195
195
|
const active = state.activeMilestone;
|
|
196
|
-
if (!active) return null;
|
|
197
|
-
|
|
198
196
|
const activeSession = input.session ?? session;
|
|
199
197
|
const activeDispatchBasePath = activeSession?.basePath || dispatchBasePath;
|
|
200
|
-
|
|
198
|
+
const prefs = loadEffectiveGSDPreferences(activeDispatchBasePath)?.preferences;
|
|
199
|
+
if (!active) {
|
|
200
|
+
if (state.phase !== "pre-planning") return null;
|
|
201
|
+
if (!hasPendingDeepStage(prefs, activeDispatchBasePath)) {
|
|
202
|
+
return {
|
|
203
|
+
kind: "blocked",
|
|
204
|
+
reason: state.nextAction || "No active milestone. Run /gsd unpark <id> or create a new milestone.",
|
|
205
|
+
action: "stop",
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (active && activeSession && shouldAdoptActiveMilestone(state, activeSession, activeDispatchBasePath)) {
|
|
201
211
|
activeSession.currentMilestoneId = active.id;
|
|
202
212
|
}
|
|
203
|
-
const
|
|
213
|
+
const dispatchMid = active?.id ?? activeSession?.currentMilestoneId ?? "";
|
|
214
|
+
const dispatchMidTitle = active?.title ?? "";
|
|
204
215
|
|
|
205
216
|
// Derive session-derived dispatch inputs the same way phases.ts:runDispatch does
|
|
206
217
|
// (#5789). Prefer caller-supplied values when present so test harnesses and
|
|
@@ -232,8 +243,15 @@ export async function decideOrchestratorDispatch(
|
|
|
232
243
|
? "true"
|
|
233
244
|
: "false");
|
|
234
245
|
|
|
246
|
+
// Only replay a milestone-scoped verification retry when a milestone is
|
|
247
|
+
// active. Pre-PR (#712 fix), `!active` returned null before reaching this
|
|
248
|
+
// block, so the retry was preserved for a future tick. The new
|
|
249
|
+
// pre-planning + deep-pending fall-through must keep that contract:
|
|
250
|
+
// otherwise a stale execute-task / complete-slice / complete-milestone
|
|
251
|
+
// retry whose target milestone has since been parked would preempt
|
|
252
|
+
// project-level deep rules like `discuss-project`.
|
|
235
253
|
const pendingRetry = session?.pendingVerificationRetryDispatch;
|
|
236
|
-
if (session && pendingRetry) {
|
|
254
|
+
if (session && pendingRetry && active) {
|
|
237
255
|
session.pendingVerificationRetryDispatch = null;
|
|
238
256
|
const alreadyClosedReason = getAlreadyClosedDispatchReason(
|
|
239
257
|
pendingRetry.unitType,
|
|
@@ -255,8 +273,8 @@ export async function decideOrchestratorDispatch(
|
|
|
255
273
|
|
|
256
274
|
const action = await resolveDispatch({
|
|
257
275
|
basePath: activeDispatchBasePath,
|
|
258
|
-
mid:
|
|
259
|
-
midTitle:
|
|
276
|
+
mid: dispatchMid,
|
|
277
|
+
midTitle: dispatchMidTitle,
|
|
260
278
|
state,
|
|
261
279
|
prefs,
|
|
262
280
|
session: activeSession,
|
|
@@ -300,8 +318,8 @@ export async function decideOrchestratorDispatch(
|
|
|
300
318
|
prompt: action.prompt,
|
|
301
319
|
pauseAfterUatDispatch: action.pauseAfterDispatch ?? false,
|
|
302
320
|
state,
|
|
303
|
-
mid:
|
|
304
|
-
midTitle:
|
|
321
|
+
mid: dispatchMid,
|
|
322
|
+
midTitle: dispatchMidTitle,
|
|
305
323
|
};
|
|
306
324
|
session.pendingOrchestrationDispatch = pending;
|
|
307
325
|
}
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
type PreVerificationOpts,
|
|
21
21
|
} from "../auto-post-unit.js";
|
|
22
22
|
import { lastAssistantText } from "../consent-question.js";
|
|
23
|
-
import { resolveEffectiveUnitIsolationMode } from "../preferences.js";
|
|
24
|
-
import type { Phase } from "../types.js";
|
|
23
|
+
import { resolveEffectiveUnitIsolationMode, getIsolationMode } from "../preferences.js";
|
|
24
|
+
import type { GSDState, Phase } from "../types.js";
|
|
25
25
|
import {
|
|
26
26
|
MAX_RECOVERY_CHARS,
|
|
27
27
|
BUDGET_THRESHOLDS,
|
|
@@ -62,9 +62,10 @@ import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
|
62
62
|
import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "./finalize-timeout.js";
|
|
63
63
|
import { getEligibleSlices } from "../slice-parallel-eligibility.js";
|
|
64
64
|
import { isSliceParallelActive, startSliceParallel } from "../slice-parallel-orchestrator.js";
|
|
65
|
-
import { isDbAvailable, getMilestoneSlices, getSlice, getTask } from "../gsd-db.js";
|
|
65
|
+
import { isDbAvailable, getMilestone, getMilestoneSlices, getSlice, getTask } from "../gsd-db.js";
|
|
66
66
|
import { refreshWorkflowDatabaseFromDisk } from "../db-workspace.js";
|
|
67
67
|
import { isClosedStatus } from "../status-guards.js";
|
|
68
|
+
import { findUnmergedCompletedMilestones } from "../unmerged-milestone-guard.js";
|
|
68
69
|
import { setRuntimeKv } from "../db/runtime-kv.js";
|
|
69
70
|
import { getLatestForUnit } from "../db/unit-dispatches.js";
|
|
70
71
|
import { reconcileBeforeSpawn } from "../state-reconciliation.js";
|
|
@@ -82,11 +83,8 @@ import { parseUnitId } from "../unit-id.js";
|
|
|
82
83
|
import { createCheckpoint, cleanupCheckpoint, rollbackToCheckpoint } from "../safety/git-checkpoint.js";
|
|
83
84
|
import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
|
|
84
85
|
import { getContextPauseAction } from "../auto-budget.js";
|
|
85
|
-
import {
|
|
86
|
-
|
|
87
|
-
getRequiredWorkflowToolsForAutoUnit,
|
|
88
|
-
supportsStructuredQuestions,
|
|
89
|
-
} from "../workflow-mcp.js";
|
|
86
|
+
import { supportsStructuredQuestions } from "../workflow-mcp.js";
|
|
87
|
+
import { getUnitWorkflowDispatchReadinessError } from "../tool-contract.js";
|
|
90
88
|
import { prepareWorkflowMcpForProject } from "../workflow-mcp-auto-prep.js";
|
|
91
89
|
import {
|
|
92
90
|
applyThinkingLevelForModel,
|
|
@@ -838,6 +836,39 @@ async function failClosedOnFinalizeTimeout(
|
|
|
838
836
|
return { action: "break", reason: progressKind };
|
|
839
837
|
}
|
|
840
838
|
|
|
839
|
+
export async function shouldSkipTerminalMilestoneCloseout(
|
|
840
|
+
s: AutoSession,
|
|
841
|
+
state: Pick<GSDState, "phase" | "lastCompletedMilestone" | "activeMilestone">,
|
|
842
|
+
mid?: string | null,
|
|
843
|
+
): Promise<{ skip: boolean; milestoneId?: string }> {
|
|
844
|
+
const closeoutMilestoneId = mid ?? s.currentMilestoneId ?? state.lastCompletedMilestone?.id;
|
|
845
|
+
if (s.completionStopInProgress) {
|
|
846
|
+
return { skip: true, milestoneId: closeoutMilestoneId };
|
|
847
|
+
}
|
|
848
|
+
if (!closeoutMilestoneId) {
|
|
849
|
+
return { skip: false };
|
|
850
|
+
}
|
|
851
|
+
if (isDbAvailable()) refreshWorkflowDatabaseFromDisk();
|
|
852
|
+
const closeoutBasePath = s.originalBasePath || s.canonicalProjectRoot || s.basePath;
|
|
853
|
+
let closeoutMergePending = false;
|
|
854
|
+
if (getIsolationMode(closeoutBasePath) !== "none") {
|
|
855
|
+
try {
|
|
856
|
+
const blockers = await findUnmergedCompletedMilestones(closeoutBasePath);
|
|
857
|
+
closeoutMergePending = blockers.some((blocker) => blocker.milestoneId === closeoutMilestoneId);
|
|
858
|
+
} catch {
|
|
859
|
+
// Fail open: without git/DB inspection we cannot safely treat closeout as done.
|
|
860
|
+
closeoutMergePending = true;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
const milestoneAlreadyClosedOut = isDbAvailable()
|
|
864
|
+
&& isClosedStatus(getMilestone(closeoutMilestoneId)?.status ?? "")
|
|
865
|
+
&& !closeoutMergePending;
|
|
866
|
+
if (milestoneAlreadyClosedOut) {
|
|
867
|
+
return { skip: true, milestoneId: closeoutMilestoneId };
|
|
868
|
+
}
|
|
869
|
+
return { skip: false, milestoneId: closeoutMilestoneId };
|
|
870
|
+
}
|
|
871
|
+
|
|
841
872
|
// ─── runPreDispatch ───────────────────────────────────────────────────────────
|
|
842
873
|
|
|
843
874
|
/**
|
|
@@ -1279,6 +1310,14 @@ export async function runPreDispatch(
|
|
|
1279
1310
|
|
|
1280
1311
|
// ── Terminal conditions ──────────────────────────────────────────────
|
|
1281
1312
|
|
|
1313
|
+
if (state.phase === "complete") {
|
|
1314
|
+
const closeoutSkip = await shouldSkipTerminalMilestoneCloseout(s, state, mid);
|
|
1315
|
+
if (closeoutSkip.skip) {
|
|
1316
|
+
debugLog("autoLoop", { phase: "complete", reason: "milestone-already-closed", milestoneId: closeoutSkip.milestoneId });
|
|
1317
|
+
return { action: "break", reason: "milestone-complete" };
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1282
1321
|
if (!mid) {
|
|
1283
1322
|
if (s.currentUnit) {
|
|
1284
1323
|
await deps.closeoutUnit(
|
|
@@ -2324,22 +2363,19 @@ export async function runUnitPhase(
|
|
|
2324
2363
|
? `${(s.currentUnitModel as any).provider ?? ""}/${(s.currentUnitModel as any).id ?? ""}`
|
|
2325
2364
|
: null;
|
|
2326
2365
|
|
|
2327
|
-
const compatibilityError =
|
|
2328
|
-
s.currentUnitModel?.provider ?? ctx.model?.provider,
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
? ctx.modelRegistry.getProviderAuthMode(
|
|
2336
|
-
:
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
|
|
2341
|
-
},
|
|
2342
|
-
);
|
|
2366
|
+
const compatibilityError = getUnitWorkflowDispatchReadinessError({
|
|
2367
|
+
provider: s.currentUnitModel?.provider ?? ctx.model?.provider,
|
|
2368
|
+
projectRoot: s.basePath,
|
|
2369
|
+
surface: "auto-mode",
|
|
2370
|
+
unitType,
|
|
2371
|
+
authMode: s.currentUnitModel?.provider
|
|
2372
|
+
? ctx.modelRegistry.getProviderAuthMode(s.currentUnitModel.provider)
|
|
2373
|
+
: ctx.model?.provider
|
|
2374
|
+
? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
|
|
2375
|
+
: undefined,
|
|
2376
|
+
baseUrl: (s.currentUnitModel as any)?.baseUrl ?? ctx.model?.baseUrl,
|
|
2377
|
+
activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
|
|
2378
|
+
});
|
|
2343
2379
|
const workflowMcpPrepModel = s.currentUnitModel;
|
|
2344
2380
|
if (compatibilityError) {
|
|
2345
2381
|
s.currentUnitRouting = prevUnitRouting;
|
|
@@ -2409,6 +2445,9 @@ export async function runUnitPhase(
|
|
|
2409
2445
|
causedBy: "unit-start",
|
|
2410
2446
|
});
|
|
2411
2447
|
s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
|
|
2448
|
+
if (nextDispatchCount <= 1) {
|
|
2449
|
+
s.toolUnavailableRetries = 0;
|
|
2450
|
+
}
|
|
2412
2451
|
const unitStartSeq = ic.nextSeq();
|
|
2413
2452
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
|
|
2414
2453
|
deps.captureAvailableSkills();
|
|
@@ -212,6 +212,8 @@ export class AutoSession {
|
|
|
212
212
|
/** Set when a GSD tool execution ends with isError due to malformed/truncated
|
|
213
213
|
* JSON arguments. Checked by postUnitPreVerification to break retry loops. */
|
|
214
214
|
lastToolInvocationError: string | null = null;
|
|
215
|
+
/** Consecutive tool-unavailable retries for the current unit (MCP startup race). */
|
|
216
|
+
toolUnavailableRetries = 0;
|
|
215
217
|
/** Agent-end messages from the just-finished unit, consumed during finalize. */
|
|
216
218
|
lastUnitAgentEndMessages: unknown[] | null = null;
|
|
217
219
|
/** Set when turn-level git action fails during closeout. */
|
|
@@ -406,6 +408,7 @@ export class AutoSession {
|
|
|
406
408
|
this.lastPreExecFailure = null;
|
|
407
409
|
this.preExecRetryCount.clear();
|
|
408
410
|
this.lastToolInvocationError = null;
|
|
411
|
+
this.toolUnavailableRetries = 0;
|
|
409
412
|
this.lastUnitAgentEndMessages = null;
|
|
410
413
|
this.lastGitActionFailure = null;
|
|
411
414
|
this.lastGitActionStatus = null;
|
|
@@ -31,10 +31,7 @@ import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
|
31
31
|
import type { MinimalModelRegistry } from "./context-budget.js";
|
|
32
32
|
import { pauseAuto } from "./auto.js";
|
|
33
33
|
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
34
|
-
import {
|
|
35
|
-
getWorkflowTransportSupportError,
|
|
36
|
-
getRequiredWorkflowToolsForAutoUnit,
|
|
37
|
-
} from "./workflow-mcp.js";
|
|
34
|
+
import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
|
|
38
35
|
|
|
39
36
|
export async function dispatchDirectPhase(
|
|
40
37
|
ctx: ExtensionCommandContext,
|
|
@@ -256,18 +253,15 @@ export async function dispatchDirectPhase(
|
|
|
256
253
|
return;
|
|
257
254
|
}
|
|
258
255
|
|
|
259
|
-
const compatibilityError =
|
|
260
|
-
ctx.model?.provider,
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
|
|
269
|
-
},
|
|
270
|
-
);
|
|
256
|
+
const compatibilityError = getUnitWorkflowDispatchReadinessError({
|
|
257
|
+
provider: ctx.model?.provider,
|
|
258
|
+
projectRoot,
|
|
259
|
+
surface: "direct phase dispatch",
|
|
260
|
+
unitType,
|
|
261
|
+
authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
|
|
262
|
+
baseUrl: ctx.model?.baseUrl,
|
|
263
|
+
activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
|
|
264
|
+
});
|
|
271
265
|
if (compatibilityError) {
|
|
272
266
|
ctx.ui.notify(compatibilityError, "error");
|
|
273
267
|
return;
|
|
@@ -91,11 +91,8 @@ import { isAutoActive } from "./auto.js";
|
|
|
91
91
|
import { hostWriteGateAdapter } from "./bootstrap/write-gate.js";
|
|
92
92
|
import { ensureWorkflowPreferencesCaptured } from "./planning-depth.js";
|
|
93
93
|
import { MILESTONE_ID_RE } from "./milestone-ids.js";
|
|
94
|
-
import {
|
|
95
|
-
|
|
96
|
-
getRequiredWorkflowToolsForAutoUnit,
|
|
97
|
-
resolveWorkflowMcpProjectRoot,
|
|
98
|
-
} from "./workflow-mcp.js";
|
|
94
|
+
import { resolveWorkflowMcpProjectRoot } from "./workflow-mcp.js";
|
|
95
|
+
import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
|
|
99
96
|
import { prepareBrowserDaemonForUat } from "./browser-daemon-auto-prep.js";
|
|
100
97
|
import {
|
|
101
98
|
PROJECT_RESEARCH_INFLIGHT_MARKER,
|
|
@@ -745,11 +742,15 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
745
742
|
// Transport preflight: verify required MCP tools are actually connected
|
|
746
743
|
// before consuming a retry attempt. Fixes tool-starved sessions burning
|
|
747
744
|
// all MAX_UAT_ATTEMPTS before stopping (#477).
|
|
748
|
-
const transportError =
|
|
749
|
-
sessionProvider,
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
745
|
+
const transportError = getUnitWorkflowDispatchReadinessError({
|
|
746
|
+
provider: sessionProvider,
|
|
747
|
+
projectRoot: basePath,
|
|
748
|
+
surface: "auto-mode",
|
|
749
|
+
unitType: "run-uat",
|
|
750
|
+
authMode: sessionAuthMode,
|
|
751
|
+
baseUrl: sessionBaseUrl,
|
|
752
|
+
activeTools,
|
|
753
|
+
});
|
|
753
754
|
if (transportError) {
|
|
754
755
|
return { action: "stop" as const, reason: transportError, level: "warning" as const };
|
|
755
756
|
}
|
|
@@ -18,7 +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
|
+
import { isModelBlocked, isModelTemporarilyUnavailable } from "./blocked-models.js";
|
|
22
22
|
import { getRequiredWorkflowToolsForAutoUnit, isWorkflowMcpSurfaceTool } from "./workflow-mcp.js";
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -272,6 +272,15 @@ function buildModelPolicyBlockReasons(
|
|
|
272
272
|
}];
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
function isModelUnavailable(
|
|
276
|
+
basePath: string,
|
|
277
|
+
provider: string | undefined,
|
|
278
|
+
id: string | undefined,
|
|
279
|
+
): boolean {
|
|
280
|
+
return isModelBlocked(basePath, provider, id) ||
|
|
281
|
+
isModelTemporarilyUnavailable(basePath, provider, id);
|
|
282
|
+
}
|
|
283
|
+
|
|
275
284
|
function restoreToolBaseline(pi: ExtensionAPI): void {
|
|
276
285
|
const key = pi as unknown as object;
|
|
277
286
|
const baseline = TOOL_BASELINE.get(key);
|
|
@@ -817,9 +826,9 @@ export async function selectAndApplyModel(
|
|
|
817
826
|
// (issue #4513). The block is persisted in .gsd/runtime/blocked-models.json
|
|
818
827
|
// so it survives /gsd auto restarts — without this, the same dead model
|
|
819
828
|
// gets reselected after every restart.
|
|
820
|
-
if (
|
|
829
|
+
if (isModelUnavailable(basePath, model.provider, model.id)) {
|
|
821
830
|
ctx.ui.notify(
|
|
822
|
-
`Skipping
|
|
831
|
+
`Skipping unavailable model ${model.provider}/${model.id}.`,
|
|
823
832
|
"warning",
|
|
824
833
|
);
|
|
825
834
|
continue;
|
|
@@ -896,7 +905,7 @@ export async function selectAndApplyModel(
|
|
|
896
905
|
for (const model of buildPolicyEligibleFallbackOrder(ctx, routingEligibleModels, autoModeStartModel)) {
|
|
897
906
|
const key = `${model.provider.toLowerCase()}/${model.id.toLowerCase()}`;
|
|
898
907
|
if (!policyAllowedModelKeys.has(key)) continue;
|
|
899
|
-
if (
|
|
908
|
+
if (isModelUnavailable(basePath, model.provider, model.id)) continue;
|
|
900
909
|
const ok = await pi.setModel(model, { persist: false });
|
|
901
910
|
if (!ok) continue;
|
|
902
911
|
appliedModel = model;
|
|
@@ -926,10 +935,10 @@ export async function selectAndApplyModel(
|
|
|
926
935
|
autoModeStartModel,
|
|
927
936
|
effectiveSessionModelOverride,
|
|
928
937
|
);
|
|
929
|
-
const startBlocked =
|
|
938
|
+
const startBlocked = isModelUnavailable(basePath, autoModeStartModel.provider, autoModeStartModel.id);
|
|
930
939
|
if (startBlocked) {
|
|
931
940
|
ctx.ui.notify(
|
|
932
|
-
`Auto-mode start model ${autoModeStartModel.provider}/${autoModeStartModel.id} is
|
|
941
|
+
`Auto-mode start model ${autoModeStartModel.provider}/${autoModeStartModel.id} is unavailable. Using current session model instead.`,
|
|
933
942
|
"warning",
|
|
934
943
|
);
|
|
935
944
|
} else {
|
|
@@ -940,7 +949,7 @@ export async function selectAndApplyModel(
|
|
|
940
949
|
const ok = await pi.setModel(startModel, { persist: false });
|
|
941
950
|
if (!ok) {
|
|
942
951
|
const byId = availableModels.find(
|
|
943
|
-
m => m.id === autoModeStartModel.id && !
|
|
952
|
+
m => m.id === autoModeStartModel.id && !isModelUnavailable(basePath, m.provider, m.id),
|
|
944
953
|
);
|
|
945
954
|
if (byId) {
|
|
946
955
|
const fallbackOk = await pi.setModel(byId, { persist: false });
|
|
@@ -2025,16 +2025,30 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
2025
2025
|
);
|
|
2026
2026
|
} else if (!triggerArtifactVerified) {
|
|
2027
2027
|
if (s.lastToolInvocationError && isToolUnavailableError(s.lastToolInvocationError)) {
|
|
2028
|
-
// Tool-unavailable is the
|
|
2029
|
-
//
|
|
2030
|
-
//
|
|
2031
|
-
//
|
|
2032
|
-
|
|
2028
|
+
// Tool-unavailable is transient: the workflow MCP server registers
|
|
2029
|
+
// its surface asynchronously, so a Unit's first call can race the
|
|
2030
|
+
// registration. Retry with escalating delay, bounded at 3 attempts.
|
|
2031
|
+
// ponytail: MAX constant so the guard, log, and display all agree
|
|
2032
|
+
const MAX_TOOL_UNAVAIL_RETRIES = 3;
|
|
2033
|
+
if (s.toolUnavailableRetries >= MAX_TOOL_UNAVAIL_RETRIES) {
|
|
2034
|
+
debugLog("postUnit", { phase: "tool-unavailable-exhausted", unitType: s.currentUnit.type, unitId: s.currentUnit.id, retries: s.toolUnavailableRetries });
|
|
2035
|
+
ctx.ui.notify(
|
|
2036
|
+
`Tool unavailable for ${s.currentUnit.type} after ${MAX_TOOL_UNAVAIL_RETRIES} retries: ${s.lastToolInvocationError}. MCP server may not be starting — pausing auto-mode.`,
|
|
2037
|
+
"error",
|
|
2038
|
+
);
|
|
2039
|
+
s.lastToolInvocationError = null;
|
|
2040
|
+
await pauseAuto(ctx, pi);
|
|
2041
|
+
return "dispatched";
|
|
2042
|
+
}
|
|
2043
|
+
s.toolUnavailableRetries++;
|
|
2044
|
+
const delayMs = s.toolUnavailableRetries * 1000;
|
|
2045
|
+
debugLog("postUnit", { phase: "tool-unavailable-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError, attempt: s.toolUnavailableRetries, delayMs });
|
|
2033
2046
|
ctx.ui.notify(
|
|
2034
|
-
`Tool unavailable for ${s.currentUnit.type}: ${s.lastToolInvocationError}.
|
|
2047
|
+
`Tool unavailable for ${s.currentUnit.type}: ${s.lastToolInvocationError}. Waiting ${delayMs}ms for MCP server — retry ${s.toolUnavailableRetries}/${MAX_TOOL_UNAVAIL_RETRIES}.`,
|
|
2035
2048
|
"warning",
|
|
2036
2049
|
);
|
|
2037
2050
|
s.lastToolInvocationError = null;
|
|
2051
|
+
await new Promise(r => setTimeout(r, delayMs));
|
|
2038
2052
|
} else if (s.lastToolInvocationError) {
|
|
2039
2053
|
const isUserSkip = /queued user message/i.test(s.lastToolInvocationError);
|
|
2040
2054
|
const errMsg = isUserSkip
|
|
@@ -2193,6 +2207,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
2193
2207
|
if (s.pendingVerificationRetry?.unitId === s.currentUnit.id) {
|
|
2194
2208
|
s.pendingVerificationRetry = null;
|
|
2195
2209
|
}
|
|
2210
|
+
s.toolUnavailableRetries = 0;
|
|
2196
2211
|
s.verificationRetryCount.delete(retryKey);
|
|
2197
2212
|
s.verificationRetryFailureHashes.delete(retryKey);
|
|
2198
2213
|
s.exhaustedVerificationUnits.delete(retryKey);
|