gsd-pi 2.71.0-dev.977c553 → 2.71.0-dev.d4d916a
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/cli.js +12 -3
- package/dist/headless-events.d.ts +2 -0
- package/dist/headless-events.js +7 -0
- package/dist/headless.js +16 -3
- package/dist/mcp-server.js +6 -6
- package/dist/provider-migrations.d.ts +10 -0
- package/dist/provider-migrations.js +12 -0
- package/dist/resource-loader.js +139 -13
- package/dist/resources/GSD-WORKFLOW.md +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +10 -4
- package/dist/resources/extensions/gsd/auto/infra-errors.js +34 -0
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +1 -1
- package/dist/resources/extensions/gsd/auto/session.js +11 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +22 -16
- package/dist/resources/extensions/gsd/auto-model-selection.js +10 -2
- package/dist/resources/extensions/gsd/auto-start.js +31 -7
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +52 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +63 -51
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -0
- package/dist/resources/extensions/gsd/commands/context.js +15 -6
- package/dist/resources/extensions/gsd/commands/dispatcher.js +12 -2
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -33
- package/dist/resources/extensions/gsd/commands/handlers/core.js +56 -11
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +15 -6
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +4 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +8 -3
- package/dist/resources/extensions/gsd/dispatch-guard.js +18 -1
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/forensics.js +19 -6
- package/dist/resources/extensions/gsd/guided-flow.js +5 -10
- package/dist/resources/extensions/gsd/metrics.js +1 -0
- package/dist/resources/extensions/gsd/milestone-actions.js +10 -4
- package/dist/resources/extensions/gsd/notification-overlay.js +42 -13
- package/dist/resources/extensions/gsd/notification-store.js +56 -5
- package/dist/resources/extensions/gsd/notification-widget.js +5 -13
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +8 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -2
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +20 -19
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +3 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -1
- package/dist/resources/extensions/gsd/session-model-override.js +25 -0
- package/dist/resources/extensions/gsd/shortcut-defs.js +40 -0
- package/dist/resources/extensions/ollama/index.js +13 -5
- package/dist/resources/skills/create-skill/SKILL.md +2 -0
- package/dist/startup-model-validation.d.ts +0 -1
- package/dist/startup-model-validation.js +6 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- 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/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 +14 -14
- 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/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +21 -11
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +110 -0
- package/packages/mcp-server/src/workflow-tools.ts +31 -11
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +11 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +20 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +4 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +8 -3
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js +44 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts +2 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +7 -4
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +11 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/src/providers/amazon-bedrock.ts +13 -1
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +32 -0
- package/packages/pi-ai/src/providers/anthropic-shared.test.ts +55 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +14 -3
- package/packages/pi-ai/src/providers/anthropic.ts +8 -4
- package/packages/pi-ai/src/providers/openai-completions.ts +14 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js +61 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +2 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +27 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +85 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js +64 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +22 -18
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js +75 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +38 -5
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.js +71 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +24 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +43 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +7 -2
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +6 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +4 -2
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-renderable-tools.test.ts +70 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +2 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +108 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -0
- package/packages/pi-coding-agent/src/core/model-resolver-initial-model-auth.test.ts +78 -0
- package/packages/pi-coding-agent/src/core/model-resolver.test.ts +85 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +22 -18
- package/packages/pi-coding-agent/src/core/sdk.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +45 -9
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/login-dialog.test.ts +24 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +30 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +15 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +47 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -2
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +6 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +4 -3
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +4 -2
- package/src/resources/GSD-WORKFLOW.md +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +13 -5
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +56 -4
- package/src/resources/extensions/gsd/auto/infra-errors.ts +38 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop.ts +45 -1
- package/src/resources/extensions/gsd/auto/phases.ts +2 -0
- package/src/resources/extensions/gsd/auto/session.ts +11 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +29 -18
- package/src/resources/extensions/gsd/auto-model-selection.ts +9 -1
- package/src/resources/extensions/gsd/auto-start.ts +38 -7
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +68 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +79 -60
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +7 -0
- package/src/resources/extensions/gsd/commands/context.ts +16 -5
- package/src/resources/extensions/gsd/commands/dispatcher.ts +14 -2
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +10 -36
- package/src/resources/extensions/gsd/commands/handlers/core.ts +58 -11
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +17 -7
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +4 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +18 -1
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/forensics.ts +23 -7
- package/src/resources/extensions/gsd/guided-flow.ts +5 -10
- package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
- package/src/resources/extensions/gsd/metrics.ts +12 -1
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -3
- package/src/resources/extensions/gsd/notification-overlay.ts +47 -14
- package/src/resources/extensions/gsd/notification-store.ts +54 -5
- package/src/resources/extensions/gsd/notification-widget.ts +5 -14
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -3
- package/src/resources/extensions/gsd/pre-execution-checks.ts +39 -2
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +20 -19
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +3 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -1
- package/src/resources/extensions/gsd/session-model-override.ts +36 -0
- package/src/resources/extensions/gsd/shortcut-defs.ts +56 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +25 -9
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/complete-slice-prompt-task-summary-layout.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/execute-task-prompt-existing-artifact-guard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +66 -1
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +36 -51
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +63 -5
- package/src/resources/extensions/gsd/tests/session-model-override.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +18 -0
- package/src/resources/extensions/ollama/index.ts +13 -3
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +28 -0
- package/src/resources/skills/create-skill/SKILL.md +2 -0
- /package/dist/web/standalone/.next/static/{4xyaXTn7-shVHaGMcl75o → IRnpNeY-_eO7SxKBIkTbL}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{4xyaXTn7-shVHaGMcl75o → IRnpNeY-_eO7SxKBIkTbL}/_ssgManifest.js +0 -0
|
@@ -46,3 +46,41 @@ export function isInfrastructureError(err: unknown): string | null {
|
|
|
46
46
|
if (msg.includes("database disk image is malformed")) return "SQLITE_CORRUPT";
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default wait duration when a cooldown error is detected but no specific
|
|
52
|
+
* expiry is available from AuthStorage (e.g., error propagated across
|
|
53
|
+
* process boundary without structured backoff data).
|
|
54
|
+
*/
|
|
55
|
+
export const COOLDOWN_FALLBACK_WAIT_MS = 35_000; // 35s — slightly longer than the 30s rate-limit backoff
|
|
56
|
+
|
|
57
|
+
/** Maximum consecutive cooldown retries before the auto-loop gives up. */
|
|
58
|
+
export const MAX_COOLDOWN_RETRIES = 5;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Detect whether an error is a transient credential cooldown that should
|
|
62
|
+
* be waited out rather than counted as a consecutive failure.
|
|
63
|
+
*
|
|
64
|
+
* Prefers the structured `CredentialCooldownError` (code: AUTH_COOLDOWN)
|
|
65
|
+
* thrown by sdk.ts. Falls back to message matching for errors that
|
|
66
|
+
* propagated across process boundaries without the typed class.
|
|
67
|
+
*/
|
|
68
|
+
export function isTransientCooldownError(err: unknown): boolean {
|
|
69
|
+
if (err && typeof err === "object" && (err as Record<string, unknown>).code === "AUTH_COOLDOWN") {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
// Fallback: message match for cross-process error propagation
|
|
73
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
74
|
+
return /in a cooldown window/i.test(msg);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extract retryAfterMs from a CredentialCooldownError, if available.
|
|
79
|
+
* Returns undefined for unstructured errors or when no retry hint exists.
|
|
80
|
+
*/
|
|
81
|
+
export function getCooldownRetryAfterMs(err: unknown): number | undefined {
|
|
82
|
+
if (err && typeof err === "object" && (err as Record<string, unknown>).code === "AUTH_COOLDOWN") {
|
|
83
|
+
return (err as Record<string, unknown>).retryAfterMs as number | undefined;
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
@@ -211,6 +211,8 @@ export interface LoopDeps {
|
|
|
211
211
|
verbose: boolean,
|
|
212
212
|
startModel: { provider: string; id: string } | null,
|
|
213
213
|
retryContext?: { isRetry: boolean; previousTier?: string },
|
|
214
|
+
isAutoMode?: boolean,
|
|
215
|
+
sessionModelOverride?: { provider: string; id: string } | null,
|
|
214
216
|
) => Promise<{
|
|
215
217
|
routing: { tier: string; modelDowngraded: boolean } | null;
|
|
216
218
|
appliedModel: { provider: string; id: string } | null;
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
runFinalize,
|
|
28
28
|
} from "./phases.js";
|
|
29
29
|
import { debugLog } from "../debug-logger.js";
|
|
30
|
-
import { isInfrastructureError } from "./infra-errors.js";
|
|
30
|
+
import { isInfrastructureError, isTransientCooldownError, getCooldownRetryAfterMs, COOLDOWN_FALLBACK_WAIT_MS, MAX_COOLDOWN_RETRIES } from "./infra-errors.js";
|
|
31
31
|
import { resolveEngine } from "../engine-resolver.js";
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -48,6 +48,7 @@ export async function autoLoop(
|
|
|
48
48
|
let iteration = 0;
|
|
49
49
|
const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
|
|
50
50
|
let consecutiveErrors = 0;
|
|
51
|
+
let consecutiveCooldowns = 0;
|
|
51
52
|
const recentErrorMessages: string[] = [];
|
|
52
53
|
|
|
53
54
|
while (s.active) {
|
|
@@ -203,6 +204,7 @@ export async function autoLoop(
|
|
|
203
204
|
|
|
204
205
|
deps.clearUnitTimeout();
|
|
205
206
|
consecutiveErrors = 0;
|
|
207
|
+
consecutiveCooldowns = 0;
|
|
206
208
|
recentErrorMessages.length = 0;
|
|
207
209
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
208
210
|
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
@@ -265,6 +267,7 @@ export async function autoLoop(
|
|
|
265
267
|
if (finalizeResult.action === "continue") continue;
|
|
266
268
|
|
|
267
269
|
consecutiveErrors = 0; // Iteration completed successfully
|
|
270
|
+
consecutiveCooldowns = 0;
|
|
268
271
|
recentErrorMessages.length = 0;
|
|
269
272
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
270
273
|
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
@@ -300,6 +303,47 @@ export async function autoLoop(
|
|
|
300
303
|
break;
|
|
301
304
|
}
|
|
302
305
|
|
|
306
|
+
// ── Credential cooldown: wait and retry with bounded budget ──
|
|
307
|
+
// A 429 triggers a 30s credential backoff in AuthStorage. If the SDK's
|
|
308
|
+
// getApiKey() retries couldn't outlast the window, the error surfaces
|
|
309
|
+
// here. Wait for the cooldown to clear rather than counting it as a
|
|
310
|
+
// consecutive failure — but cap retries so we don't spin for hours
|
|
311
|
+
// on persistent quota exhaustion.
|
|
312
|
+
if (isTransientCooldownError(loopErr)) {
|
|
313
|
+
consecutiveCooldowns++;
|
|
314
|
+
const retryAfterMs = getCooldownRetryAfterMs(loopErr);
|
|
315
|
+
debugLog("autoLoop", {
|
|
316
|
+
phase: "cooldown-wait",
|
|
317
|
+
iteration,
|
|
318
|
+
consecutiveCooldowns,
|
|
319
|
+
retryAfterMs,
|
|
320
|
+
error: msg,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (consecutiveCooldowns > MAX_COOLDOWN_RETRIES) {
|
|
324
|
+
ctx.ui.notify(
|
|
325
|
+
`Auto-mode stopped: ${consecutiveCooldowns} consecutive credential cooldowns — rate limit or quota may be persistently exhausted.`,
|
|
326
|
+
"error",
|
|
327
|
+
);
|
|
328
|
+
await deps.stopAuto(
|
|
329
|
+
ctx,
|
|
330
|
+
pi,
|
|
331
|
+
`${consecutiveCooldowns} consecutive credential cooldowns exceeded retry budget`,
|
|
332
|
+
);
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const waitMs = (retryAfterMs !== undefined && retryAfterMs > 0 && retryAfterMs <= 60_000)
|
|
337
|
+
? retryAfterMs + 500 // Use structured hint + small buffer
|
|
338
|
+
: COOLDOWN_FALLBACK_WAIT_MS;
|
|
339
|
+
ctx.ui.notify(
|
|
340
|
+
`Credentials in cooldown (${consecutiveCooldowns}/${MAX_COOLDOWN_RETRIES}) — waiting ${Math.round(waitMs / 1000)}s before retrying.`,
|
|
341
|
+
"warning",
|
|
342
|
+
);
|
|
343
|
+
await new Promise(resolve => setTimeout(resolve, waitMs));
|
|
344
|
+
continue; // Retry iteration without incrementing consecutiveErrors
|
|
345
|
+
}
|
|
346
|
+
|
|
303
347
|
consecutiveErrors++;
|
|
304
348
|
recentErrorMessages.push(msg.length > 120 ? msg.slice(0, 120) + "..." : msg);
|
|
305
349
|
debugLog("autoLoop", {
|
|
@@ -1183,6 +1183,8 @@ export async function runUnitPhase(
|
|
|
1183
1183
|
s.verbose,
|
|
1184
1184
|
s.autoModeStartModel,
|
|
1185
1185
|
sidecarItem ? undefined : { isRetry, previousTier },
|
|
1186
|
+
undefined,
|
|
1187
|
+
s.manualSessionModelOverride,
|
|
1186
1188
|
);
|
|
1187
1189
|
s.currentUnitRouting =
|
|
1188
1190
|
modelResult.routing as AutoSession["currentUnitRouting"];
|
|
@@ -87,6 +87,10 @@ export class AutoSession {
|
|
|
87
87
|
previousProjectRootEnv: string | null = null;
|
|
88
88
|
hadProjectRootEnv = false;
|
|
89
89
|
projectRootEnvCaptured = false;
|
|
90
|
+
previousMilestoneLockEnv: string | null = null;
|
|
91
|
+
hadMilestoneLockEnv = false;
|
|
92
|
+
milestoneLockEnvCaptured = false;
|
|
93
|
+
sessionMilestoneLock: string | null = null;
|
|
90
94
|
gitService: GitServiceImpl | null = null;
|
|
91
95
|
|
|
92
96
|
// ── Dispatch counters ────────────────────────────────────────────────────
|
|
@@ -107,6 +111,8 @@ export class AutoSession {
|
|
|
107
111
|
|
|
108
112
|
// ── Model state ──────────────────────────────────────────────────────────
|
|
109
113
|
autoModeStartModel: StartModel | null = null;
|
|
114
|
+
/** Explicit /gsd model pin captured at bootstrap (session-scoped policy override). */
|
|
115
|
+
manualSessionModelOverride: StartModel | null = null;
|
|
110
116
|
currentUnitModel: Model<Api> | null = null;
|
|
111
117
|
/** Fully-qualified model ID (provider/id) set after selectAndApplyModel + hook overrides (#2899). */
|
|
112
118
|
currentDispatchedModelId: string | null = null;
|
|
@@ -200,6 +206,10 @@ export class AutoSession {
|
|
|
200
206
|
this.previousProjectRootEnv = null;
|
|
201
207
|
this.hadProjectRootEnv = false;
|
|
202
208
|
this.projectRootEnvCaptured = false;
|
|
209
|
+
this.previousMilestoneLockEnv = null;
|
|
210
|
+
this.hadMilestoneLockEnv = false;
|
|
211
|
+
this.milestoneLockEnvCaptured = false;
|
|
212
|
+
this.sessionMilestoneLock = null;
|
|
203
213
|
this.gitService = null;
|
|
204
214
|
|
|
205
215
|
// Dispatch
|
|
@@ -214,6 +224,7 @@ export class AutoSession {
|
|
|
214
224
|
|
|
215
225
|
// Model
|
|
216
226
|
this.autoModeStartModel = null;
|
|
227
|
+
this.manualSessionModelOverride = null;
|
|
217
228
|
this.currentUnitModel = null;
|
|
218
229
|
this.currentDispatchedModelId = null;
|
|
219
230
|
this.originalModelId = null;
|
|
@@ -6,7 +6,13 @@
|
|
|
6
6
|
* or AutoContext dependency. State accessors are passed as callbacks.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
ExtensionContext,
|
|
11
|
+
ExtensionCommandContext,
|
|
12
|
+
SessionMessageEntry,
|
|
13
|
+
ReadonlyFooterDataProvider,
|
|
14
|
+
Theme,
|
|
15
|
+
} from "@gsd/pi-coding-agent";
|
|
10
16
|
import type { GSDState } from "./types.js";
|
|
11
17
|
import { getCurrentBranch } from "./worktree.js";
|
|
12
18
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
@@ -17,7 +23,6 @@ import {
|
|
|
17
23
|
resolveSliceFile,
|
|
18
24
|
} from "./paths.js";
|
|
19
25
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
20
|
-
import { formatShortcut } from "./files.js";
|
|
21
26
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
22
27
|
import { execFileSync } from "node:child_process";
|
|
23
28
|
import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
@@ -38,6 +43,7 @@ import {
|
|
|
38
43
|
type RtkSessionSavings,
|
|
39
44
|
} from "../shared/rtk-session-stats.js";
|
|
40
45
|
import { logWarning } from "./workflow-logger.js";
|
|
46
|
+
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
41
47
|
|
|
42
48
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
43
49
|
|
|
@@ -358,12 +364,23 @@ function getLastCommit(basePath: string): { timeAgo: string; message: string } |
|
|
|
358
364
|
// ─── Footer Factory ───────────────────────────────────────────────────────────
|
|
359
365
|
|
|
360
366
|
/**
|
|
361
|
-
* Footer factory
|
|
362
|
-
*
|
|
363
|
-
* progress widget instead, so there's no gap or redundancy.
|
|
367
|
+
* Footer factory used by auto-mode.
|
|
368
|
+
* Keep footer minimal but preserve extension status context from setStatus().
|
|
364
369
|
*/
|
|
365
|
-
|
|
366
|
-
|
|
370
|
+
function sanitizeFooterStatus(text: string): string {
|
|
371
|
+
return text.replace(/\s+/g, " ").trim();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export const hideFooter = (_tui: unknown, theme: Theme, footerData: ReadonlyFooterDataProvider) => ({
|
|
375
|
+
render(width: number): string[] {
|
|
376
|
+
const extensionStatuses = footerData.getExtensionStatuses();
|
|
377
|
+
if (extensionStatuses.size === 0) return [];
|
|
378
|
+
const statusLine = Array.from(extensionStatuses.entries())
|
|
379
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
380
|
+
.map(([, text]) => sanitizeFooterStatus(text))
|
|
381
|
+
.join(" ");
|
|
382
|
+
return [truncateToWidth(theme.fg("dim", statusLine), width, theme.fg("dim", "..."))];
|
|
383
|
+
},
|
|
367
384
|
invalidate() {},
|
|
368
385
|
dispose() {},
|
|
369
386
|
});
|
|
@@ -646,14 +663,6 @@ export function updateProgressWidget(
|
|
|
646
663
|
: "";
|
|
647
664
|
lines.push(rightAlign(headerLeft, headerRight, width));
|
|
648
665
|
|
|
649
|
-
// Worktree/branch right-aligned below header
|
|
650
|
-
const branchLabel = worktreeName && cachedBranch
|
|
651
|
-
? `${worktreeName} (${cachedBranch})`
|
|
652
|
-
: cachedBranch ?? "";
|
|
653
|
-
if (branchLabel) {
|
|
654
|
-
lines.push(rightAlign("", theme.fg("dim", branchLabel), width));
|
|
655
|
-
}
|
|
656
|
-
|
|
657
666
|
// Show health signal details when degraded (yellow/red)
|
|
658
667
|
if (score.level !== "green" && score.signals.length > 0 && widgetMode !== "min") {
|
|
659
668
|
// Show up to 3 most relevant signals in compact form
|
|
@@ -917,15 +926,17 @@ export function updateProgressWidget(
|
|
|
917
926
|
// Hints line
|
|
918
927
|
const hintParts: string[] = [];
|
|
919
928
|
hintParts.push("esc pause");
|
|
920
|
-
hintParts.push(`${
|
|
929
|
+
hintParts.push(`${formattedShortcutPair("dashboard")} dashboard`);
|
|
930
|
+
hintParts.push(`${formattedShortcutPair("parallel")} parallel`);
|
|
921
931
|
const hintStr = theme.fg("dim", hintParts.join(" | "));
|
|
922
932
|
const commitStr = lastCommit
|
|
923
933
|
? theme.fg("dim", `${lastCommit.timeAgo} ago: ${commitMsg}`)
|
|
924
934
|
: "";
|
|
935
|
+
const locationStr = theme.fg("dim", widgetPwd);
|
|
925
936
|
if (commitStr) {
|
|
926
|
-
lines.push(rightAlign(`${pad}${commitStr}`, hintStr, width));
|
|
937
|
+
lines.push(rightAlign(`${pad}${locationStr} · ${commitStr}`, hintStr, width));
|
|
927
938
|
} else {
|
|
928
|
-
lines.push(rightAlign(
|
|
939
|
+
lines.push(rightAlign(`${pad}${locationStr}`, hintStr, width));
|
|
929
940
|
}
|
|
930
941
|
|
|
931
942
|
lines.push(...ui.bar());
|
|
@@ -14,6 +14,7 @@ import { classifyUnitComplexity, tierLabel } from "./complexity-classifier.js";
|
|
|
14
14
|
import { resolveModelForComplexity, escalateTier, getEligibleModels, loadCapabilityOverrides, adjustToolSet, filterToolsForProvider } from "./model-router.js";
|
|
15
15
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
16
16
|
import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
17
|
+
import { getSessionModelOverride } from "./session-model-override.js";
|
|
17
18
|
|
|
18
19
|
export interface ModelSelectionResult {
|
|
19
20
|
/** Routing metadata for metrics recording */
|
|
@@ -72,8 +73,15 @@ export async function selectAndApplyModel(
|
|
|
72
73
|
/** When false (interactive/guided-flow), skip dynamic routing and use the session model.
|
|
73
74
|
* Dynamic routing only applies in auto-mode where cost optimization is expected. (#3962) */
|
|
74
75
|
isAutoMode = true,
|
|
76
|
+
/** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
|
|
77
|
+
sessionModelOverride?: { provider: string; id: string } | null,
|
|
75
78
|
): Promise<ModelSelectionResult> {
|
|
76
|
-
const
|
|
79
|
+
const effectiveSessionModelOverride = sessionModelOverride === undefined
|
|
80
|
+
? getSessionModelOverride(ctx.sessionManager.getSessionId())
|
|
81
|
+
: (sessionModelOverride ?? undefined);
|
|
82
|
+
const modelConfig = effectiveSessionModelOverride
|
|
83
|
+
? undefined
|
|
84
|
+
: resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode);
|
|
77
85
|
let routing: { tier: string; modelDowngraded: boolean } | null = null;
|
|
78
86
|
let appliedModel: Model<Api> | null = null;
|
|
79
87
|
|
|
@@ -85,6 +85,7 @@ import { sep as pathSep } from "node:path";
|
|
|
85
85
|
import { resolveProjectRootDbPath } from "./bootstrap/dynamic-tools.js";
|
|
86
86
|
import { resolveDefaultSessionModel, resolveDynamicRoutingConfig } from "./preferences-models.js";
|
|
87
87
|
import type { WorktreeResolver } from "./worktree-resolver.js";
|
|
88
|
+
import { getSessionModelOverride } from "./session-model-override.js";
|
|
88
89
|
|
|
89
90
|
export interface BootstrapDeps {
|
|
90
91
|
shouldUseWorktreeIsolation: () => boolean;
|
|
@@ -266,13 +267,42 @@ export async function bootstrapAutoSession(
|
|
|
266
267
|
// Capture the user's session model before guided-flow dispatch can apply a
|
|
267
268
|
// phase-specific planning model for a discuss turn (#2829).
|
|
268
269
|
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
270
|
+
// Precedence:
|
|
271
|
+
// 1) Explicit session override via /gsd model (this session)
|
|
272
|
+
// 2) GSD model preferences from PREFERENCES.md (validated against live auth)
|
|
273
|
+
// 3) Current session model from settings/session restore (if provider ready)
|
|
274
|
+
//
|
|
275
|
+
// This preserves #3517 defaults while honoring explicit runtime model
|
|
276
|
+
// selection for subsequent /gsd runs in the same session.
|
|
277
|
+
const manualSessionOverride = getSessionModelOverride(ctx.sessionManager.getSessionId());
|
|
273
278
|
const preferredModel = resolveDefaultSessionModel(ctx.model?.provider);
|
|
274
|
-
|
|
275
|
-
|
|
279
|
+
// Validate the preferred model against the live registry + provider auth so
|
|
280
|
+
// an unconfigured PREFERENCES.md entry (no API key / OAuth) can't become the
|
|
281
|
+
// start-model snapshot. Without this, every subsequent unit would try to
|
|
282
|
+
// fall back to an unusable model.
|
|
283
|
+
let validatedPreferredModel: { provider: string; id: string } | undefined;
|
|
284
|
+
if (preferredModel) {
|
|
285
|
+
const { resolveModelId } = await import("./auto-model-selection.js");
|
|
286
|
+
const available = ctx.modelRegistry.getAvailable();
|
|
287
|
+
const match = resolveModelId(
|
|
288
|
+
`${preferredModel.provider}/${preferredModel.id}`,
|
|
289
|
+
available,
|
|
290
|
+
ctx.model?.provider,
|
|
291
|
+
);
|
|
292
|
+
if (match) {
|
|
293
|
+
validatedPreferredModel = { provider: match.provider, id: match.id };
|
|
294
|
+
} else {
|
|
295
|
+
ctx.ui.notify(
|
|
296
|
+
`Preferred model ${preferredModel.provider}/${preferredModel.id} from PREFERENCES.md is not configured; falling back to session default.`,
|
|
297
|
+
"warning",
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const sessionModelReady =
|
|
302
|
+
ctx.model && ctx.modelRegistry.isProviderRequestReady(ctx.model.provider);
|
|
303
|
+
const startModelSnapshot = manualSessionOverride
|
|
304
|
+
?? validatedPreferredModel
|
|
305
|
+
?? (sessionModelReady && ctx.model
|
|
276
306
|
? { provider: ctx.model.provider, id: ctx.model.id }
|
|
277
307
|
: null);
|
|
278
308
|
|
|
@@ -678,7 +708,7 @@ export async function bootstrapAutoSession(
|
|
|
678
708
|
}
|
|
679
709
|
|
|
680
710
|
// ── DB lifecycle ──
|
|
681
|
-
const gsdDbPath =
|
|
711
|
+
const gsdDbPath = resolveProjectRootDbPath(s.basePath);
|
|
682
712
|
const gsdDirPath = join(s.basePath, ".gsd");
|
|
683
713
|
if (existsSync(gsdDirPath) && !existsSync(gsdDbPath)) {
|
|
684
714
|
const hasDecisions = existsSync(join(gsdDirPath, "DECISIONS.md"));
|
|
@@ -731,6 +761,7 @@ export async function bootstrapAutoSession(
|
|
|
731
761
|
id: startModelSnapshot.id,
|
|
732
762
|
};
|
|
733
763
|
}
|
|
764
|
+
s.manualSessionModelOverride = manualSessionOverride ?? null;
|
|
734
765
|
|
|
735
766
|
// Apply worker model override from parallel orchestrator (#worker-model).
|
|
736
767
|
// GSD_WORKER_MODEL is injected by the coordinator when parallel.worker_model
|
|
@@ -92,7 +92,7 @@ export function clearInFlightTools(): void {
|
|
|
92
92
|
* handler. When these errors occur, retrying the same unit will produce the same
|
|
93
93
|
* failure, so the retry loop must be broken.
|
|
94
94
|
*/
|
|
95
|
-
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}' in JSON
|
|
95
|
+
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON/i;
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* Returns true if the error message indicates a tool invocation failure due to
|
|
@@ -2043,7 +2043,7 @@ export function mergeMilestoneToMain(
|
|
|
2043
2043
|
// 12. Remove worktree directory first (must happen before branch deletion)
|
|
2044
2044
|
try {
|
|
2045
2045
|
removeWorktree(originalBasePath_, milestoneId, {
|
|
2046
|
-
branch:
|
|
2046
|
+
branch: milestoneBranch,
|
|
2047
2047
|
deleteBranch: false,
|
|
2048
2048
|
});
|
|
2049
2049
|
} catch (err) {
|
|
@@ -165,6 +165,7 @@ import {
|
|
|
165
165
|
reconcileMergeState,
|
|
166
166
|
} from "./auto-recovery.js";
|
|
167
167
|
import { resolveDispatch, DISPATCH_RULES } from "./auto-dispatch.js";
|
|
168
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
168
169
|
import { initRegistry, convertDispatchRules } from "./rule-registry.js";
|
|
169
170
|
import { emitJournalEvent as _emitJournalEvent, type JournalEntry } from "./journal.js";
|
|
170
171
|
import {
|
|
@@ -272,6 +273,53 @@ function restoreProjectRootEnv(): void {
|
|
|
272
273
|
s.projectRootEnvCaptured = false;
|
|
273
274
|
}
|
|
274
275
|
|
|
276
|
+
function captureMilestoneLockEnv(milestoneId: string | null): void {
|
|
277
|
+
if (!s.milestoneLockEnvCaptured) {
|
|
278
|
+
s.hadMilestoneLockEnv = Object.prototype.hasOwnProperty.call(process.env, "GSD_MILESTONE_LOCK");
|
|
279
|
+
s.previousMilestoneLockEnv = process.env.GSD_MILESTONE_LOCK ?? null;
|
|
280
|
+
s.milestoneLockEnvCaptured = true;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (milestoneId) {
|
|
284
|
+
process.env.GSD_MILESTONE_LOCK = milestoneId;
|
|
285
|
+
} else {
|
|
286
|
+
delete process.env.GSD_MILESTONE_LOCK;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function restoreMilestoneLockEnv(): void {
|
|
291
|
+
if (!s.milestoneLockEnvCaptured) return;
|
|
292
|
+
|
|
293
|
+
if (s.hadMilestoneLockEnv && s.previousMilestoneLockEnv !== null) {
|
|
294
|
+
process.env.GSD_MILESTONE_LOCK = s.previousMilestoneLockEnv;
|
|
295
|
+
} else {
|
|
296
|
+
delete process.env.GSD_MILESTONE_LOCK;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
s.previousMilestoneLockEnv = null;
|
|
300
|
+
s.hadMilestoneLockEnv = false;
|
|
301
|
+
s.milestoneLockEnvCaptured = false;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function startAutoDetached(
|
|
305
|
+
ctx: ExtensionCommandContext,
|
|
306
|
+
pi: ExtensionAPI,
|
|
307
|
+
base: string,
|
|
308
|
+
verboseMode: boolean,
|
|
309
|
+
options?: {
|
|
310
|
+
step?: boolean;
|
|
311
|
+
interrupted?: InterruptedSessionAssessment;
|
|
312
|
+
milestoneLock?: string | null;
|
|
313
|
+
},
|
|
314
|
+
): void {
|
|
315
|
+
void startAuto(ctx, pi, base, verboseMode, options).catch((err) => {
|
|
316
|
+
const message = getErrorMessage(err);
|
|
317
|
+
ctx.ui.notify(`Auto-start failed: ${message}`, "error");
|
|
318
|
+
logWarning("engine", `auto start error: ${message}`, { file: "auto.ts" });
|
|
319
|
+
debugLog("auto-start-failed", { error: message });
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
275
323
|
export function shouldUseWorktreeIsolation(): boolean {
|
|
276
324
|
const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
277
325
|
if (prefs?.isolation === "worktree") return true;
|
|
@@ -549,11 +597,13 @@ function buildSnapshotOpts(
|
|
|
549
597
|
_unitType: string,
|
|
550
598
|
_unitId: string,
|
|
551
599
|
): {
|
|
600
|
+
autoSessionKey?: string;
|
|
552
601
|
continueHereFired?: boolean;
|
|
553
602
|
promptCharCount?: number;
|
|
554
603
|
baselineCharCount?: number;
|
|
555
604
|
} & Record<string, unknown> {
|
|
556
605
|
return {
|
|
606
|
+
...(s.autoStartTime > 0 ? { autoSessionKey: String(s.autoStartTime) } : {}),
|
|
557
607
|
promptCharCount: s.lastPromptCharCount,
|
|
558
608
|
baselineCharCount: s.lastBaselineCharCount,
|
|
559
609
|
...(s.currentUnitRouting ?? {}),
|
|
@@ -574,6 +624,7 @@ function handleLostSessionLock(
|
|
|
574
624
|
s.paused = false;
|
|
575
625
|
clearUnitTimeout();
|
|
576
626
|
restoreProjectRootEnv();
|
|
627
|
+
restoreMilestoneLockEnv();
|
|
577
628
|
deregisterSigtermHandler();
|
|
578
629
|
clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
|
|
579
630
|
const base = lockBase();
|
|
@@ -610,6 +661,7 @@ function cleanupAfterLoopExit(ctx: ExtensionContext): void {
|
|
|
610
661
|
s.active = false;
|
|
611
662
|
clearUnitTimeout();
|
|
612
663
|
restoreProjectRootEnv();
|
|
664
|
+
restoreMilestoneLockEnv();
|
|
613
665
|
|
|
614
666
|
// Clear crash lock and release session lock so the next `/gsd next` does
|
|
615
667
|
// not see a stale lock with the current PID and treat it as a "remote"
|
|
@@ -880,6 +932,7 @@ export async function stopAuto(
|
|
|
880
932
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
881
933
|
ctx?.ui.setFooter(undefined);
|
|
882
934
|
restoreProjectRootEnv();
|
|
935
|
+
restoreMilestoneLockEnv();
|
|
883
936
|
|
|
884
937
|
// Reset all session state in one call
|
|
885
938
|
s.reset();
|
|
@@ -933,6 +986,7 @@ export async function pauseAuto(
|
|
|
933
986
|
activeEngineId: s.activeEngineId,
|
|
934
987
|
activeRunDir: s.activeRunDir,
|
|
935
988
|
autoStartTime: s.autoStartTime,
|
|
989
|
+
milestoneLock: s.sessionMilestoneLock ?? undefined,
|
|
936
990
|
};
|
|
937
991
|
const runtimeDir = join(gsdRoot(s.originalBasePath || s.basePath), "runtime");
|
|
938
992
|
mkdirSync(runtimeDir, { recursive: true });
|
|
@@ -971,6 +1025,7 @@ export async function pauseAuto(
|
|
|
971
1025
|
s.active = false;
|
|
972
1026
|
s.paused = true;
|
|
973
1027
|
restoreProjectRootEnv();
|
|
1028
|
+
restoreMilestoneLockEnv();
|
|
974
1029
|
s.pendingVerificationRetry = null;
|
|
975
1030
|
s.verificationRetryCount.clear();
|
|
976
1031
|
ctx?.ui.setStatus("gsd-auto", "paused");
|
|
@@ -1154,6 +1209,7 @@ export async function startAuto(
|
|
|
1154
1209
|
options?: {
|
|
1155
1210
|
step?: boolean;
|
|
1156
1211
|
interrupted?: InterruptedSessionAssessment;
|
|
1212
|
+
milestoneLock?: string | null;
|
|
1157
1213
|
},
|
|
1158
1214
|
): Promise<void> {
|
|
1159
1215
|
if (s.active) {
|
|
@@ -1163,6 +1219,12 @@ export async function startAuto(
|
|
|
1163
1219
|
|
|
1164
1220
|
const requestedStepMode = options?.step ?? false;
|
|
1165
1221
|
const interruptedAssessment = options?.interrupted ?? null;
|
|
1222
|
+
if (options?.milestoneLock !== undefined) {
|
|
1223
|
+
s.sessionMilestoneLock = options.milestoneLock ?? null;
|
|
1224
|
+
}
|
|
1225
|
+
if (s.sessionMilestoneLock) {
|
|
1226
|
+
captureMilestoneLockEnv(s.sessionMilestoneLock);
|
|
1227
|
+
}
|
|
1166
1228
|
|
|
1167
1229
|
// Escape stale worktree cwd from a previous milestone (#608).
|
|
1168
1230
|
base = escapeStaleWorktree(base);
|
|
@@ -1194,6 +1256,7 @@ export async function startAuto(
|
|
|
1194
1256
|
s.originalBasePath = meta.originalBasePath || base;
|
|
1195
1257
|
s.stepMode = meta.stepMode ?? requestedStepMode;
|
|
1196
1258
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
1259
|
+
s.sessionMilestoneLock = meta.milestoneLock ?? null;
|
|
1197
1260
|
s.paused = true;
|
|
1198
1261
|
try { unlinkSync(pausedPath); } catch (e) { logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" }); }
|
|
1199
1262
|
ctx.ui.notify(
|
|
@@ -1228,6 +1291,7 @@ export async function startAuto(
|
|
|
1228
1291
|
s.pausedUnitType = meta.unitType ?? null;
|
|
1229
1292
|
s.pausedUnitId = meta.unitId ?? null;
|
|
1230
1293
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
1294
|
+
s.sessionMilestoneLock = meta.milestoneLock ?? null;
|
|
1231
1295
|
s.paused = true;
|
|
1232
1296
|
try { unlinkSync(pausedPath); } catch (e) { logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" }); }
|
|
1233
1297
|
ctx.ui.notify(
|
|
@@ -1247,6 +1311,10 @@ export async function startAuto(
|
|
|
1247
1311
|
if (!s.autoStartTime || s.autoStartTime <= 0) s.autoStartTime = Date.now();
|
|
1248
1312
|
}
|
|
1249
1313
|
|
|
1314
|
+
if (s.sessionMilestoneLock) {
|
|
1315
|
+
captureMilestoneLockEnv(s.sessionMilestoneLock);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1250
1318
|
if (!s.paused) {
|
|
1251
1319
|
s.stepMode = requestedStepMode;
|
|
1252
1320
|
}
|
|
@@ -121,6 +121,8 @@ export function registerHooks(pi: ExtensionAPI): void {
|
|
|
121
121
|
return { cancel: true };
|
|
122
122
|
}
|
|
123
123
|
const basePath = process.cwd();
|
|
124
|
+
const { ensureDbOpen } = await import("./dynamic-tools.js");
|
|
125
|
+
await ensureDbOpen();
|
|
124
126
|
const state = await deriveState(basePath);
|
|
125
127
|
if (!state.activeMilestone || !state.activeSlice || !state.activeTask) return;
|
|
126
128
|
if (state.phase !== "executing") return;
|