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
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { ensureManagedTools } from './tool-bootstrap.js';
|
|
|
7
7
|
import { loadStoredEnvKeys } from './wizard.js';
|
|
8
8
|
import { migratePiCredentials } from './pi-migration.js';
|
|
9
9
|
import { validateConfiguredModel } from './startup-model-validation.js';
|
|
10
|
+
import { shouldMigrateAnthropicToClaudeCode } from './provider-migrations.js';
|
|
10
11
|
import { shouldRunOnboarding, runOnboarding } from './onboarding.js';
|
|
11
12
|
import chalk from 'chalk';
|
|
12
13
|
import { checkForUpdates } from './update-check.js';
|
|
@@ -285,7 +286,7 @@ const { resolveModelsJsonPath } = await import('./models-resolver.js');
|
|
|
285
286
|
const modelsJsonPath = resolveModelsJsonPath();
|
|
286
287
|
const modelRegistry = new ModelRegistry(authStorage, modelsJsonPath);
|
|
287
288
|
markStartup('ModelRegistry');
|
|
288
|
-
const settingsManager = SettingsManager.create(agentDir);
|
|
289
|
+
const settingsManager = SettingsManager.create(process.cwd(), agentDir);
|
|
289
290
|
applySecurityOverrides(settingsManager);
|
|
290
291
|
markStartup('SettingsManager.create');
|
|
291
292
|
// Run onboarding wizard on first launch (no LLM provider configured)
|
|
@@ -401,7 +402,11 @@ if (isPrintMode) {
|
|
|
401
402
|
// Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
|
|
402
403
|
// Anthropic blocks third-party apps from using subscription quotas — routing through
|
|
403
404
|
// the local claude CLI binary is TOS-compliant.
|
|
404
|
-
if (
|
|
405
|
+
if (shouldMigrateAnthropicToClaudeCode({
|
|
406
|
+
authStorage,
|
|
407
|
+
isClaudeCodeReady: modelRegistry.isProviderRequestReady('claude-code'),
|
|
408
|
+
defaultProvider: settingsManager.getDefaultProvider(),
|
|
409
|
+
})) {
|
|
405
410
|
const currentModelId = settingsManager.getDefaultModel();
|
|
406
411
|
if (currentModelId) {
|
|
407
412
|
const ccModel = modelRegistry.find('claude-code', currentModelId);
|
|
@@ -576,7 +581,11 @@ markStartup('createAgentSession');
|
|
|
576
581
|
// Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
|
|
577
582
|
// Anthropic blocks third-party apps from using subscription quotas — routing through
|
|
578
583
|
// the local claude CLI binary is TOS-compliant.
|
|
579
|
-
if (
|
|
584
|
+
if (shouldMigrateAnthropicToClaudeCode({
|
|
585
|
+
authStorage,
|
|
586
|
+
isClaudeCodeReady: modelRegistry.isProviderRequestReady('claude-code'),
|
|
587
|
+
defaultProvider: settingsManager.getDefaultProvider(),
|
|
588
|
+
})) {
|
|
580
589
|
const currentModelId = settingsManager.getDefaultModel();
|
|
581
590
|
if (currentModelId) {
|
|
582
591
|
const ccModel = modelRegistry.find('claude-code', currentModelId);
|
|
@@ -43,6 +43,8 @@ export declare const NEW_MILESTONE_IDLE_TIMEOUT_MS = 120000;
|
|
|
43
43
|
export declare function isTerminalNotification(event: Record<string, unknown>): boolean;
|
|
44
44
|
export declare function isBlockedNotification(event: Record<string, unknown>): boolean;
|
|
45
45
|
export declare function isMilestoneReadyNotification(event: Record<string, unknown>): boolean;
|
|
46
|
+
export declare function isInteractiveHeadlessTool(toolName: string | undefined): boolean;
|
|
47
|
+
export declare function shouldArmHeadlessIdleTimeout(toolCallCount: number, interactiveToolCount: number): boolean;
|
|
46
48
|
export declare const FIRE_AND_FORGET_METHODS: Set<string>;
|
|
47
49
|
export declare const QUICK_COMMANDS: Set<string>;
|
|
48
50
|
export declare function isQuickCommand(command: string): boolean;
|
package/dist/headless-events.js
CHANGED
|
@@ -65,6 +65,7 @@ export const IDLE_TIMEOUT_MS = 15_000;
|
|
|
65
65
|
// between tool calls (e.g. after mkdir, before writing files). Use a
|
|
66
66
|
// longer idle timeout to avoid killing the session prematurely (#808).
|
|
67
67
|
export const NEW_MILESTONE_IDLE_TIMEOUT_MS = 120_000;
|
|
68
|
+
const INTERACTIVE_HEADLESS_TOOLS = new Set(['ask_user_questions', 'secure_env_collect']);
|
|
68
69
|
export function isTerminalNotification(event) {
|
|
69
70
|
if (event.type !== 'extension_ui_request' || event.method !== 'notify')
|
|
70
71
|
return false;
|
|
@@ -83,6 +84,12 @@ export function isMilestoneReadyNotification(event) {
|
|
|
83
84
|
return false;
|
|
84
85
|
return /milestone\s+m\d+.*ready/i.test(String(event.message ?? ''));
|
|
85
86
|
}
|
|
87
|
+
export function isInteractiveHeadlessTool(toolName) {
|
|
88
|
+
return INTERACTIVE_HEADLESS_TOOLS.has(String(toolName ?? ''));
|
|
89
|
+
}
|
|
90
|
+
export function shouldArmHeadlessIdleTimeout(toolCallCount, interactiveToolCount) {
|
|
91
|
+
return toolCallCount > 0 && interactiveToolCount === 0;
|
|
92
|
+
}
|
|
86
93
|
// ---------------------------------------------------------------------------
|
|
87
94
|
// Quick Command Detection
|
|
88
95
|
// ---------------------------------------------------------------------------
|
package/dist/headless.js
CHANGED
|
@@ -17,7 +17,7 @@ import { resolve } from 'node:path';
|
|
|
17
17
|
import { RpcClient, SessionManager } from '@gsd/pi-coding-agent';
|
|
18
18
|
import { getProjectSessionsDir } from './project-sessions.js';
|
|
19
19
|
import { loadAndValidateAnswerFile, AnswerInjector } from './headless-answers.js';
|
|
20
|
-
import { isTerminalNotification, isBlockedNotification, isMilestoneReadyNotification, isQuickCommand, FIRE_AND_FORGET_METHODS, IDLE_TIMEOUT_MS, NEW_MILESTONE_IDLE_TIMEOUT_MS, EXIT_SUCCESS, EXIT_ERROR, EXIT_BLOCKED, EXIT_CANCELLED, mapStatusToExitCode, } from './headless-events.js';
|
|
20
|
+
import { isTerminalNotification, isBlockedNotification, isMilestoneReadyNotification, isQuickCommand, FIRE_AND_FORGET_METHODS, IDLE_TIMEOUT_MS, NEW_MILESTONE_IDLE_TIMEOUT_MS, isInteractiveHeadlessTool, shouldArmHeadlessIdleTimeout, EXIT_SUCCESS, EXIT_ERROR, EXIT_BLOCKED, EXIT_CANCELLED, mapStatusToExitCode, } from './headless-events.js';
|
|
21
21
|
import { VALID_OUTPUT_FORMATS } from './headless-types.js';
|
|
22
22
|
import { handleExtensionUIRequest, formatProgress, formatThinkingLine, formatTextStart, formatTextEnd, formatThinkingStart, formatThinkingEnd, startSupervisedStdinReader, } from './headless-ui.js';
|
|
23
23
|
import { loadContext, bootstrapGsdProject, } from './headless-context.js';
|
|
@@ -282,6 +282,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
282
282
|
let exitCode = 0;
|
|
283
283
|
let milestoneReady = false; // tracks "Milestone X ready." for auto-chaining
|
|
284
284
|
const recentEvents = [];
|
|
285
|
+
const interactiveToolCallIds = new Set();
|
|
285
286
|
// JSON batch mode: cost aggregation (cumulative-max pattern per K004)
|
|
286
287
|
let cumulativeCostUsd = 0;
|
|
287
288
|
let cumulativeInputTokens = 0;
|
|
@@ -365,7 +366,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
365
366
|
function resetIdleTimer() {
|
|
366
367
|
if (idleTimer)
|
|
367
368
|
clearTimeout(idleTimer);
|
|
368
|
-
if (toolCallCount
|
|
369
|
+
if (shouldArmHeadlessIdleTimeout(toolCallCount, interactiveToolCallIds.size)) {
|
|
369
370
|
idleTimer = setTimeout(() => {
|
|
370
371
|
completed = true;
|
|
371
372
|
resolveCompletion();
|
|
@@ -386,13 +387,25 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
386
387
|
client.onEvent((event) => {
|
|
387
388
|
const eventObj = event;
|
|
388
389
|
trackEvent(eventObj);
|
|
390
|
+
const eventType = String(eventObj.type ?? '');
|
|
391
|
+
if (eventType === 'tool_execution_start') {
|
|
392
|
+
const toolCallId = String(eventObj.toolCallId ?? eventObj.id ?? '');
|
|
393
|
+
if (toolCallId && isInteractiveHeadlessTool(String(eventObj.toolName ?? ''))) {
|
|
394
|
+
interactiveToolCallIds.add(toolCallId);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else if (eventType === 'tool_execution_end') {
|
|
398
|
+
const toolCallId = String(eventObj.toolCallId ?? eventObj.id ?? '');
|
|
399
|
+
if (toolCallId) {
|
|
400
|
+
interactiveToolCallIds.delete(toolCallId);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
389
403
|
resetIdleTimer();
|
|
390
404
|
// Answer injector: observe events for question metadata
|
|
391
405
|
injector?.observeEvent(eventObj);
|
|
392
406
|
// --json / --output-format stream-json: forward events as JSONL to stdout (filtered if --events)
|
|
393
407
|
// --output-format json (batch mode): suppress streaming, track cost for final result
|
|
394
408
|
if (options.json && options.outputFormat === 'stream-json') {
|
|
395
|
-
const eventType = String(eventObj.type ?? '');
|
|
396
409
|
if (!options.eventFilter || options.eventFilter.has(eventType)) {
|
|
397
410
|
process.stdout.write(JSON.stringify(eventObj) + '\n');
|
|
398
411
|
}
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// MCP SDK subpath imports use wildcard exports (./*) that NodeNext resolves
|
|
2
2
|
// at runtime but TypeScript cannot statically type-check. We construct the
|
|
3
3
|
// specifiers dynamically so tsc treats them as `any`.
|
|
4
|
-
//
|
|
5
|
-
// .js
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
//
|
|
5
|
+
// Use explicit .js subpaths for modules that are loaded dynamically at runtime.
|
|
6
|
+
// Recent Node / SDK combinations do not reliably resolve the extensionless
|
|
7
|
+
// wildcard targets for `server/stdio` and `types` (#3914).
|
|
8
8
|
const MCP_PKG = '@modelcontextprotocol/sdk';
|
|
9
9
|
/**
|
|
10
10
|
* Starts a native MCP (Model Context Protocol) server over stdin/stdout.
|
|
@@ -23,8 +23,8 @@ const MCP_PKG = '@modelcontextprotocol/sdk';
|
|
|
23
23
|
export async function startMcpServer(options) {
|
|
24
24
|
const { tools, version = '0.0.0' } = options;
|
|
25
25
|
const serverMod = await import(`${MCP_PKG}/server`);
|
|
26
|
-
const stdioMod = await import(
|
|
27
|
-
const typesMod = await import(
|
|
26
|
+
const stdioMod = await import(`${MCP_PKG}/server/stdio.js`);
|
|
27
|
+
const typesMod = await import(`${MCP_PKG}/types.js`);
|
|
28
28
|
const Server = serverMod.Server;
|
|
29
29
|
const StdioServerTransport = stdioMod.StdioServerTransport;
|
|
30
30
|
const { ListToolsRequestSchema, CallToolRequestSchema } = typesMod;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuthStorage } from "@gsd/pi-coding-agent";
|
|
2
|
+
type AnthropicMigrationDeps = {
|
|
3
|
+
authStorage: Pick<AuthStorage, "getCredentialsForProvider">;
|
|
4
|
+
isClaudeCodeReady: boolean;
|
|
5
|
+
defaultProvider: string | undefined;
|
|
6
|
+
env?: NodeJS.ProcessEnv;
|
|
7
|
+
};
|
|
8
|
+
export declare function hasDirectAnthropicApiKey(authStorage: Pick<AuthStorage, "getCredentialsForProvider">, env?: NodeJS.ProcessEnv): boolean;
|
|
9
|
+
export declare function shouldMigrateAnthropicToClaudeCode({ authStorage, isClaudeCodeReady, defaultProvider, env, }: AnthropicMigrationDeps): boolean;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function hasDirectAnthropicApiKey(authStorage, env = process.env) {
|
|
2
|
+
if ((env.ANTHROPIC_API_KEY ?? "").trim()) {
|
|
3
|
+
return true;
|
|
4
|
+
}
|
|
5
|
+
return authStorage.getCredentialsForProvider("anthropic").some((credential) => credential?.type === "api_key" && typeof credential?.key === "string" && credential.key.trim().length > 0);
|
|
6
|
+
}
|
|
7
|
+
export function shouldMigrateAnthropicToClaudeCode({ authStorage, isClaudeCodeReady, defaultProvider, env = process.env, }) {
|
|
8
|
+
if (!isClaudeCodeReady || defaultProvider !== "anthropic") {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return !hasDirectAnthropicApiKey(authStorage, env);
|
|
12
|
+
}
|
package/dist/resource-loader.js
CHANGED
|
@@ -2,7 +2,7 @@ import { DefaultResourceLoader, sortExtensionPaths } from '@gsd/pi-coding-agent'
|
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { chmodSync, copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, openSync, closeSync, readFileSync, readlinkSync, readdirSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
5
|
-
import { dirname, join, relative, resolve } from 'node:path';
|
|
5
|
+
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { compareSemver } from './update-check.js';
|
|
8
8
|
import { discoverExtensionEntryPaths } from './extension-discovery.js';
|
|
@@ -254,34 +254,160 @@ function copyDirRecursive(src, dest) {
|
|
|
254
254
|
* ~/.gsd/agent/extensions/ have no ancestor node_modules, so imports of
|
|
255
255
|
* @gsd/* packages fail. The symlink makes Node's standard resolution find
|
|
256
256
|
* them without requiring every call site to use jiti.
|
|
257
|
+
*
|
|
258
|
+
* Layout differences by install method:
|
|
259
|
+
* - Source/monorepo: packageRoot/node_modules has everything → simple symlink
|
|
260
|
+
* - npm/bun global: deps hoisted to dirname(packageRoot), including @gsd/* → simple symlink
|
|
261
|
+
* - pnpm global: external deps hoisted, but @gsd/* stays in packageRoot/node_modules
|
|
262
|
+
* → merged directory with symlinks from both roots (#3529, #3564)
|
|
257
263
|
*/
|
|
258
264
|
function ensureNodeModulesSymlink(agentDir) {
|
|
259
265
|
const agentNodeModules = join(agentDir, 'node_modules');
|
|
260
|
-
const
|
|
266
|
+
const internalNodeModules = join(packageRoot, 'node_modules');
|
|
267
|
+
const hoistedNodeModules = dirname(packageRoot);
|
|
268
|
+
const isGlobalInstall = basename(hoistedNodeModules) === 'node_modules';
|
|
269
|
+
if (!isGlobalInstall) {
|
|
270
|
+
// Source/monorepo: internal node_modules has everything
|
|
271
|
+
reconcileSymlink(agentNodeModules, internalNodeModules);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
// Global install: check if workspace scopes (@gsd/*) are hoisted.
|
|
275
|
+
// npm/bun hoist everything; pnpm keeps workspace packages internal.
|
|
276
|
+
if (!hasMissingWorkspaceScopes(hoistedNodeModules, internalNodeModules)) {
|
|
277
|
+
// Everything is hoisted — simple symlink to parent node_modules
|
|
278
|
+
reconcileSymlink(agentNodeModules, hoistedNodeModules);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// pnpm-style layout: create a real directory merging both roots
|
|
282
|
+
reconcileMergedNodeModules(agentNodeModules, hoistedNodeModules, internalNodeModules);
|
|
283
|
+
}
|
|
284
|
+
/** Check if any @gsd* scopes exist in internal but not in hoisted node_modules */
|
|
285
|
+
function hasMissingWorkspaceScopes(hoisted, internal) {
|
|
286
|
+
if (!existsSync(internal))
|
|
287
|
+
return false;
|
|
261
288
|
try {
|
|
262
|
-
const
|
|
289
|
+
for (const entry of readdirSync(internal, { withFileTypes: true })) {
|
|
290
|
+
if (entry.isDirectory() && entry.name.startsWith('@gsd') &&
|
|
291
|
+
!existsSync(join(hoisted, entry.name))) {
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
catch { /* non-fatal */ }
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
/** Ensure a symlink at `link` points to `target`, fixing stale/wrong entries */
|
|
300
|
+
function reconcileSymlink(link, target) {
|
|
301
|
+
try {
|
|
302
|
+
const stat = lstatSync(link);
|
|
263
303
|
if (stat.isSymbolicLink()) {
|
|
264
|
-
const existing = readlinkSync(
|
|
265
|
-
|
|
266
|
-
if (existing === gsdNodeModules && existsSync(agentNodeModules))
|
|
304
|
+
const existing = readlinkSync(link);
|
|
305
|
+
if (existing === target && existsSync(link))
|
|
267
306
|
return; // correct and target exists
|
|
268
|
-
|
|
307
|
+
unlinkSync(link);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
// Real directory (or merged dir from previous pnpm fix) — remove it
|
|
311
|
+
rmSync(link, { recursive: true, force: true });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
// lstatSync throws if path doesn't exist — fine, we'll create below
|
|
316
|
+
}
|
|
317
|
+
try {
|
|
318
|
+
symlinkSync(target, link, 'junction');
|
|
319
|
+
}
|
|
320
|
+
catch (err) {
|
|
321
|
+
console.error(`[gsd] WARN: Failed to symlink ${link} → ${target}: ${err instanceof Error ? err.message : err}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Create a real node_modules directory containing symlinks from both the
|
|
326
|
+
* hoisted root (external deps) and internal root (@gsd/* workspace packages).
|
|
327
|
+
* Used for pnpm global installs where @gsd/* isn't hoisted.
|
|
328
|
+
*/
|
|
329
|
+
function reconcileMergedNodeModules(agentNodeModules, hoisted, internal) {
|
|
330
|
+
// Fast path: if already merged for this packageRoot + same directory contents, skip.
|
|
331
|
+
// The fingerprint includes entry names from both roots so `pnpm add/remove` triggers rebuild.
|
|
332
|
+
const marker = join(agentNodeModules, '.gsd-merged');
|
|
333
|
+
const fingerprint = mergedFingerprint(hoisted, internal);
|
|
334
|
+
try {
|
|
335
|
+
if (existsSync(marker) && readFileSync(marker, 'utf-8').trim() === fingerprint)
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
catch { /* rebuild */ }
|
|
339
|
+
// Remove any existing symlink or stale merged directory
|
|
340
|
+
try {
|
|
341
|
+
const stat = lstatSync(agentNodeModules);
|
|
342
|
+
if (stat.isSymbolicLink()) {
|
|
269
343
|
unlinkSync(agentNodeModules);
|
|
270
344
|
}
|
|
271
345
|
else {
|
|
272
|
-
// Real directory (not a symlink) is blocking — remove it
|
|
273
346
|
rmSync(agentNodeModules, { recursive: true, force: true });
|
|
274
347
|
}
|
|
275
348
|
}
|
|
276
|
-
catch {
|
|
277
|
-
|
|
349
|
+
catch { /* doesn't exist */ }
|
|
350
|
+
mkdirSync(agentNodeModules, { recursive: true });
|
|
351
|
+
let linkedCount = 0;
|
|
352
|
+
// Symlink entries from the hoisted node_modules (external deps)
|
|
353
|
+
try {
|
|
354
|
+
for (const entry of readdirSync(hoisted, { withFileTypes: true })) {
|
|
355
|
+
// Skip the gsd-pi package itself and dotfiles
|
|
356
|
+
if (entry.name === basename(packageRoot))
|
|
357
|
+
continue;
|
|
358
|
+
if (entry.name.startsWith('.'))
|
|
359
|
+
continue;
|
|
360
|
+
try {
|
|
361
|
+
symlinkSync(join(hoisted, entry.name), join(agentNodeModules, entry.name));
|
|
362
|
+
linkedCount++;
|
|
363
|
+
}
|
|
364
|
+
catch { /* skip individual */ }
|
|
365
|
+
}
|
|
278
366
|
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
console.error(`[gsd] WARN: Failed to read hoisted node_modules at ${hoisted}: ${err instanceof Error ? err.message : err}`);
|
|
369
|
+
}
|
|
370
|
+
// Overlay internal node_modules entries that weren't hoisted.
|
|
371
|
+
// This covers @gsd/* workspace packages AND optional deps like
|
|
372
|
+
// @anthropic-ai/claude-agent-sdk that npm keeps internal.
|
|
279
373
|
try {
|
|
280
|
-
|
|
374
|
+
for (const entry of readdirSync(internal, { withFileTypes: true })) {
|
|
375
|
+
if (entry.name.startsWith('.'))
|
|
376
|
+
continue;
|
|
377
|
+
const link = join(agentNodeModules, entry.name);
|
|
378
|
+
// Replace hoisted symlink with internal version (internal takes precedence)
|
|
379
|
+
try {
|
|
380
|
+
lstatSync(link);
|
|
381
|
+
unlinkSync(link);
|
|
382
|
+
}
|
|
383
|
+
catch { /* didn't exist — will create below */ }
|
|
384
|
+
try {
|
|
385
|
+
symlinkSync(join(internal, entry.name), link);
|
|
386
|
+
linkedCount++;
|
|
387
|
+
}
|
|
388
|
+
catch { /* skip individual */ }
|
|
389
|
+
}
|
|
281
390
|
}
|
|
282
391
|
catch (err) {
|
|
283
|
-
|
|
284
|
-
|
|
392
|
+
console.error(`[gsd] WARN: Failed to read internal node_modules at ${internal}: ${err instanceof Error ? err.message : err}`);
|
|
393
|
+
}
|
|
394
|
+
// Only stamp marker if we actually linked something — avoids caching a broken state
|
|
395
|
+
if (linkedCount > 0) {
|
|
396
|
+
try {
|
|
397
|
+
writeFileSync(marker, fingerprint);
|
|
398
|
+
}
|
|
399
|
+
catch { /* non-fatal */ }
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/** Build a cache fingerprint from packageRoot + sorted entry names of both directories */
|
|
403
|
+
function mergedFingerprint(hoisted, internal) {
|
|
404
|
+
try {
|
|
405
|
+
const h = readdirSync(hoisted).sort().join(',');
|
|
406
|
+
const i = readdirSync(internal).sort().join(',');
|
|
407
|
+
return `${packageRoot}\n${h}\n${i}`;
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
return packageRoot; // fallback: at least invalidate on version change
|
|
285
411
|
}
|
|
286
412
|
}
|
|
287
413
|
/**
|
|
@@ -275,7 +275,7 @@ Work flows through these phases. Each phase produces a file.
|
|
|
275
275
|
**How to do it manually:**
|
|
276
276
|
1. Read the roadmap to understand the scope.
|
|
277
277
|
2. Identify 3-5 gray areas — implementation decisions the user cares about.
|
|
278
|
-
3. Use `ask_user_questions` to discuss each area.
|
|
278
|
+
3. Use `ask_user_questions` to discuss each area, one round at a time. Never fabricate user input; wait for the user's actual response before the next round.
|
|
279
279
|
4. Write decisions to the appropriate context file (`M###-CONTEXT.md` or `S##-CONTEXT.md`).
|
|
280
280
|
5. Do NOT discuss how to implement — only what the user wants.
|
|
281
281
|
|
|
@@ -29,6 +29,15 @@ function createAssistantStream() {
|
|
|
29
29
|
throw new Error("Unexpected event type for final result");
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
+
export function getResultErrorMessage(result) {
|
|
33
|
+
if ("errors" in result && Array.isArray(result.errors) && result.errors.length > 0) {
|
|
34
|
+
return result.errors.join("; ");
|
|
35
|
+
}
|
|
36
|
+
if ("result" in result && typeof result.result === "string" && result.result.trim().length > 0) {
|
|
37
|
+
return result.result.trim();
|
|
38
|
+
}
|
|
39
|
+
return result.subtype === "success" ? "claude_code_request_failed" : result.subtype;
|
|
40
|
+
}
|
|
32
41
|
// ---------------------------------------------------------------------------
|
|
33
42
|
// Claude binary resolution
|
|
34
43
|
// ---------------------------------------------------------------------------
|
|
@@ -666,10 +675,7 @@ async function pumpSdkMessages(model, context, options, stream) {
|
|
|
666
675
|
timestamp: Date.now(),
|
|
667
676
|
};
|
|
668
677
|
if (result.is_error) {
|
|
669
|
-
|
|
670
|
-
? result.errors?.join("; ")
|
|
671
|
-
: result.subtype;
|
|
672
|
-
finalMessage.errorMessage = errText;
|
|
678
|
+
finalMessage.errorMessage = getResultErrorMessage(result);
|
|
673
679
|
stream.push({ type: "error", reason: "error", error: finalMessage });
|
|
674
680
|
}
|
|
675
681
|
else {
|
|
@@ -47,3 +47,37 @@ export function isInfrastructureError(err) {
|
|
|
47
47
|
return "SQLITE_CORRUPT";
|
|
48
48
|
return null;
|
|
49
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
|
+
/** Maximum consecutive cooldown retries before the auto-loop gives up. */
|
|
57
|
+
export const MAX_COOLDOWN_RETRIES = 5;
|
|
58
|
+
/**
|
|
59
|
+
* Detect whether an error is a transient credential cooldown that should
|
|
60
|
+
* be waited out rather than counted as a consecutive failure.
|
|
61
|
+
*
|
|
62
|
+
* Prefers the structured `CredentialCooldownError` (code: AUTH_COOLDOWN)
|
|
63
|
+
* thrown by sdk.ts. Falls back to message matching for errors that
|
|
64
|
+
* propagated across process boundaries without the typed class.
|
|
65
|
+
*/
|
|
66
|
+
export function isTransientCooldownError(err) {
|
|
67
|
+
if (err && typeof err === "object" && err.code === "AUTH_COOLDOWN") {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
// Fallback: message match for cross-process error propagation
|
|
71
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
72
|
+
return /in a cooldown window/i.test(msg);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Extract retryAfterMs from a CredentialCooldownError, if available.
|
|
76
|
+
* Returns undefined for unstructured errors or when no retry hint exists.
|
|
77
|
+
*/
|
|
78
|
+
export function getCooldownRetryAfterMs(err) {
|
|
79
|
+
if (err && typeof err === "object" && err.code === "AUTH_COOLDOWN") {
|
|
80
|
+
return err.retryAfterMs;
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
@@ -11,7 +11,7 @@ import { MAX_LOOP_ITERATIONS, } from "./types.js";
|
|
|
11
11
|
import { _clearCurrentResolve } from "./resolve.js";
|
|
12
12
|
import { runPreDispatch, runDispatch, runGuards, runUnitPhase, runFinalize, } from "./phases.js";
|
|
13
13
|
import { debugLog } from "../debug-logger.js";
|
|
14
|
-
import { isInfrastructureError } from "./infra-errors.js";
|
|
14
|
+
import { isInfrastructureError, isTransientCooldownError, getCooldownRetryAfterMs, COOLDOWN_FALLBACK_WAIT_MS, MAX_COOLDOWN_RETRIES } from "./infra-errors.js";
|
|
15
15
|
import { resolveEngine } from "../engine-resolver.js";
|
|
16
16
|
/**
|
|
17
17
|
* Main auto-mode execution loop. Iterates: derive → dispatch → guards →
|
|
@@ -26,6 +26,7 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|
|
26
26
|
let iteration = 0;
|
|
27
27
|
const loopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
|
|
28
28
|
let consecutiveErrors = 0;
|
|
29
|
+
let consecutiveCooldowns = 0;
|
|
29
30
|
const recentErrorMessages = [];
|
|
30
31
|
while (s.active) {
|
|
31
32
|
iteration++;
|
|
@@ -158,6 +159,7 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|
|
158
159
|
});
|
|
159
160
|
deps.clearUnitTimeout();
|
|
160
161
|
consecutiveErrors = 0;
|
|
162
|
+
consecutiveCooldowns = 0;
|
|
161
163
|
recentErrorMessages.length = 0;
|
|
162
164
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
163
165
|
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
@@ -220,6 +222,7 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|
|
220
222
|
if (finalizeResult.action === "continue")
|
|
221
223
|
continue;
|
|
222
224
|
consecutiveErrors = 0; // Iteration completed successfully
|
|
225
|
+
consecutiveCooldowns = 0;
|
|
223
226
|
recentErrorMessages.length = 0;
|
|
224
227
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
225
228
|
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
@@ -246,6 +249,34 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|
|
246
249
|
await deps.stopAuto(ctx, pi, `Infrastructure error (${infraCode}): not recoverable by retry`);
|
|
247
250
|
break;
|
|
248
251
|
}
|
|
252
|
+
// ── Credential cooldown: wait and retry with bounded budget ──
|
|
253
|
+
// A 429 triggers a 30s credential backoff in AuthStorage. If the SDK's
|
|
254
|
+
// getApiKey() retries couldn't outlast the window, the error surfaces
|
|
255
|
+
// here. Wait for the cooldown to clear rather than counting it as a
|
|
256
|
+
// consecutive failure — but cap retries so we don't spin for hours
|
|
257
|
+
// on persistent quota exhaustion.
|
|
258
|
+
if (isTransientCooldownError(loopErr)) {
|
|
259
|
+
consecutiveCooldowns++;
|
|
260
|
+
const retryAfterMs = getCooldownRetryAfterMs(loopErr);
|
|
261
|
+
debugLog("autoLoop", {
|
|
262
|
+
phase: "cooldown-wait",
|
|
263
|
+
iteration,
|
|
264
|
+
consecutiveCooldowns,
|
|
265
|
+
retryAfterMs,
|
|
266
|
+
error: msg,
|
|
267
|
+
});
|
|
268
|
+
if (consecutiveCooldowns > MAX_COOLDOWN_RETRIES) {
|
|
269
|
+
ctx.ui.notify(`Auto-mode stopped: ${consecutiveCooldowns} consecutive credential cooldowns — rate limit or quota may be persistently exhausted.`, "error");
|
|
270
|
+
await deps.stopAuto(ctx, pi, `${consecutiveCooldowns} consecutive credential cooldowns exceeded retry budget`);
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
const waitMs = (retryAfterMs !== undefined && retryAfterMs > 0 && retryAfterMs <= 60_000)
|
|
274
|
+
? retryAfterMs + 500 // Use structured hint + small buffer
|
|
275
|
+
: COOLDOWN_FALLBACK_WAIT_MS;
|
|
276
|
+
ctx.ui.notify(`Credentials in cooldown (${consecutiveCooldowns}/${MAX_COOLDOWN_RETRIES}) — waiting ${Math.round(waitMs / 1000)}s before retrying.`, "warning");
|
|
277
|
+
await new Promise(resolve => setTimeout(resolve, waitMs));
|
|
278
|
+
continue; // Retry iteration without incrementing consecutiveErrors
|
|
279
|
+
}
|
|
249
280
|
consecutiveErrors++;
|
|
250
281
|
recentErrorMessages.push(msg.length > 120 ? msg.slice(0, 120) + "..." : msg);
|
|
251
282
|
debugLog("autoLoop", {
|
|
@@ -857,7 +857,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
857
857
|
logWarning("engine", "Prompt reorder failed", { error: msg });
|
|
858
858
|
}
|
|
859
859
|
// Select and apply model (with tier escalation on retry — normal units only)
|
|
860
|
-
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier });
|
|
860
|
+
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride);
|
|
861
861
|
s.currentUnitRouting =
|
|
862
862
|
modelResult.routing;
|
|
863
863
|
s.currentUnitModel =
|
|
@@ -36,6 +36,10 @@ export class AutoSession {
|
|
|
36
36
|
previousProjectRootEnv = null;
|
|
37
37
|
hadProjectRootEnv = false;
|
|
38
38
|
projectRootEnvCaptured = false;
|
|
39
|
+
previousMilestoneLockEnv = null;
|
|
40
|
+
hadMilestoneLockEnv = false;
|
|
41
|
+
milestoneLockEnvCaptured = false;
|
|
42
|
+
sessionMilestoneLock = null;
|
|
39
43
|
gitService = null;
|
|
40
44
|
// ── Dispatch counters ────────────────────────────────────────────────────
|
|
41
45
|
unitDispatchCount = new Map();
|
|
@@ -52,6 +56,8 @@ export class AutoSession {
|
|
|
52
56
|
currentMilestoneId = null;
|
|
53
57
|
// ── Model state ──────────────────────────────────────────────────────────
|
|
54
58
|
autoModeStartModel = null;
|
|
59
|
+
/** Explicit /gsd model pin captured at bootstrap (session-scoped policy override). */
|
|
60
|
+
manualSessionModelOverride = null;
|
|
55
61
|
currentUnitModel = null;
|
|
56
62
|
/** Fully-qualified model ID (provider/id) set after selectAndApplyModel + hook overrides (#2899). */
|
|
57
63
|
currentDispatchedModelId = null;
|
|
@@ -140,6 +146,10 @@ export class AutoSession {
|
|
|
140
146
|
this.previousProjectRootEnv = null;
|
|
141
147
|
this.hadProjectRootEnv = false;
|
|
142
148
|
this.projectRootEnvCaptured = false;
|
|
149
|
+
this.previousMilestoneLockEnv = null;
|
|
150
|
+
this.hadMilestoneLockEnv = false;
|
|
151
|
+
this.milestoneLockEnvCaptured = false;
|
|
152
|
+
this.sessionMilestoneLock = null;
|
|
143
153
|
this.gitService = null;
|
|
144
154
|
// Dispatch
|
|
145
155
|
this.unitDispatchCount.clear();
|
|
@@ -151,6 +161,7 @@ export class AutoSession {
|
|
|
151
161
|
this.currentMilestoneId = null;
|
|
152
162
|
// Model
|
|
153
163
|
this.autoModeStartModel = null;
|
|
164
|
+
this.manualSessionModelOverride = null;
|
|
154
165
|
this.currentUnitModel = null;
|
|
155
166
|
this.currentDispatchedModelId = null;
|
|
156
167
|
this.originalModelId = null;
|
|
@@ -10,7 +10,6 @@ import { getActiveHook } from "./post-unit-hooks.js";
|
|
|
10
10
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
11
11
|
import { getErrorMessage } from "./error-utils.js";
|
|
12
12
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
13
|
-
import { formatShortcut } from "./files.js";
|
|
14
13
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
15
14
|
import { execFileSync } from "node:child_process";
|
|
16
15
|
import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
@@ -23,6 +22,7 @@ import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.
|
|
|
23
22
|
import { parseUnitId } from "./unit-id.js";
|
|
24
23
|
import { formatRtkSavingsLabel, getRtkSessionSavings, } from "../shared/rtk-session-stats.js";
|
|
25
24
|
import { logWarning } from "./workflow-logger.js";
|
|
25
|
+
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
26
26
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
27
27
|
/**
|
|
28
28
|
* Extract the target slice ID from a run-uat unit ID (e.g. "M001/S01" → "S01").
|
|
@@ -282,12 +282,23 @@ function getLastCommit(basePath) {
|
|
|
282
282
|
}
|
|
283
283
|
// ─── Footer Factory ───────────────────────────────────────────────────────────
|
|
284
284
|
/**
|
|
285
|
-
* Footer factory
|
|
286
|
-
*
|
|
287
|
-
* progress widget instead, so there's no gap or redundancy.
|
|
285
|
+
* Footer factory used by auto-mode.
|
|
286
|
+
* Keep footer minimal but preserve extension status context from setStatus().
|
|
288
287
|
*/
|
|
289
|
-
|
|
290
|
-
|
|
288
|
+
function sanitizeFooterStatus(text) {
|
|
289
|
+
return text.replace(/\s+/g, " ").trim();
|
|
290
|
+
}
|
|
291
|
+
export const hideFooter = (_tui, theme, footerData) => ({
|
|
292
|
+
render(width) {
|
|
293
|
+
const extensionStatuses = footerData.getExtensionStatuses();
|
|
294
|
+
if (extensionStatuses.size === 0)
|
|
295
|
+
return [];
|
|
296
|
+
const statusLine = Array.from(extensionStatuses.entries())
|
|
297
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
298
|
+
.map(([, text]) => sanitizeFooterStatus(text))
|
|
299
|
+
.join(" ");
|
|
300
|
+
return [truncateToWidth(theme.fg("dim", statusLine), width, theme.fg("dim", "..."))];
|
|
301
|
+
},
|
|
291
302
|
invalidate() { },
|
|
292
303
|
dispose() { },
|
|
293
304
|
});
|
|
@@ -522,13 +533,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
522
533
|
: theme.fg("dim", elapsed))
|
|
523
534
|
: "";
|
|
524
535
|
lines.push(rightAlign(headerLeft, headerRight, width));
|
|
525
|
-
// Worktree/branch right-aligned below header
|
|
526
|
-
const branchLabel = worktreeName && cachedBranch
|
|
527
|
-
? `${worktreeName} (${cachedBranch})`
|
|
528
|
-
: cachedBranch ?? "";
|
|
529
|
-
if (branchLabel) {
|
|
530
|
-
lines.push(rightAlign("", theme.fg("dim", branchLabel), width));
|
|
531
|
-
}
|
|
532
536
|
// Show health signal details when degraded (yellow/red)
|
|
533
537
|
if (score.level !== "green" && score.signals.length > 0 && widgetMode !== "min") {
|
|
534
538
|
// Show up to 3 most relevant signals in compact form
|
|
@@ -776,16 +780,18 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
776
780
|
// Hints line
|
|
777
781
|
const hintParts = [];
|
|
778
782
|
hintParts.push("esc pause");
|
|
779
|
-
hintParts.push(`${
|
|
783
|
+
hintParts.push(`${formattedShortcutPair("dashboard")} dashboard`);
|
|
784
|
+
hintParts.push(`${formattedShortcutPair("parallel")} parallel`);
|
|
780
785
|
const hintStr = theme.fg("dim", hintParts.join(" | "));
|
|
781
786
|
const commitStr = lastCommit
|
|
782
787
|
? theme.fg("dim", `${lastCommit.timeAgo} ago: ${commitMsg}`)
|
|
783
788
|
: "";
|
|
789
|
+
const locationStr = theme.fg("dim", widgetPwd);
|
|
784
790
|
if (commitStr) {
|
|
785
|
-
lines.push(rightAlign(`${pad}${commitStr}`, hintStr, width));
|
|
791
|
+
lines.push(rightAlign(`${pad}${locationStr} · ${commitStr}`, hintStr, width));
|
|
786
792
|
}
|
|
787
793
|
else {
|
|
788
|
-
lines.push(rightAlign(
|
|
794
|
+
lines.push(rightAlign(`${pad}${locationStr}`, hintStr, width));
|
|
789
795
|
}
|
|
790
796
|
lines.push(...ui.bar());
|
|
791
797
|
cachedLines = lines;
|