gsd-pi 2.57.0-dev.f22a903 → 2.58.0-dev.394cb18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +58 -35
- package/dist/headless-ui.d.ts +17 -0
- package/dist/headless-ui.js +97 -3
- package/dist/headless.js +67 -6
- package/dist/help-text.js +1 -0
- package/dist/onboarding.js +44 -0
- package/dist/resource-loader.js +16 -1
- package/dist/resources/agents/researcher.md +1 -1
- package/dist/resources/extensions/ask-user-questions.js +16 -3
- package/dist/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/dist/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +14 -6
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +59 -36
- package/dist/resources/extensions/context7/extension-manifest.json +1 -1
- package/dist/resources/extensions/get-secrets-from-user.js +8 -5
- package/dist/resources/extensions/google-search/extension-manifest.json +1 -1
- package/dist/resources/extensions/google-search/index.js +2 -1
- package/dist/resources/extensions/gsd/auto/phases.js +25 -21
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dashboard.js +37 -20
- package/dist/resources/extensions/gsd/auto-dispatch.js +17 -2
- package/dist/resources/extensions/gsd/auto-model-selection.js +26 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +16 -4
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +13 -5
- package/dist/resources/extensions/gsd/auto-start.js +35 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +199 -12
- package/dist/resources/extensions/gsd/auto.js +4 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -8
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +42 -34
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +66 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -0
- package/dist/resources/extensions/gsd/captures.js +56 -4
- package/dist/resources/extensions/gsd/codebase-generator.js +279 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +10 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-codebase.js +115 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +41 -4
- package/dist/resources/extensions/gsd/complexity-classifier.js +8 -6
- package/dist/resources/extensions/gsd/db-writer.js +116 -8
- package/dist/resources/extensions/gsd/doctor-git-checks.js +76 -1
- package/dist/resources/extensions/gsd/doctor-proactive.js +34 -1
- package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +5 -4
- package/dist/resources/extensions/gsd/doctor.js +3 -1
- package/dist/resources/extensions/gsd/error-classifier.js +12 -10
- package/dist/resources/extensions/gsd/extension-manifest.json +16 -1
- package/dist/resources/extensions/gsd/forensics.js +123 -20
- package/dist/resources/extensions/gsd/git-service.js +105 -2
- package/dist/resources/extensions/gsd/gitignore.js +33 -0
- package/dist/resources/extensions/gsd/gsd-db.js +36 -9
- package/dist/resources/extensions/gsd/guided-flow.js +106 -44
- package/dist/resources/extensions/gsd/health-widget-core.js +31 -0
- package/dist/resources/extensions/gsd/health-widget.js +17 -0
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -0
- package/dist/resources/extensions/gsd/migrate-external.js +8 -1
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +45 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +18 -0
- package/dist/resources/extensions/gsd/model-router.js +35 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +39 -0
- package/dist/resources/extensions/gsd/notifications.js +16 -1
- package/dist/resources/extensions/gsd/parallel-eligibility.js +13 -2
- package/dist/resources/extensions/gsd/parallel-merge.js +78 -5
- package/dist/resources/extensions/gsd/parsers-legacy.js +20 -3
- package/dist/resources/extensions/gsd/paths.js +45 -0
- package/dist/resources/extensions/gsd/preferences-models.js +14 -1
- package/dist/resources/extensions/gsd/preferences-types.js +3 -1
- package/dist/resources/extensions/gsd/preferences.js +13 -16
- package/dist/resources/extensions/gsd/prompt-loader.js +4 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -2
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -1
- package/dist/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -0
- package/dist/resources/extensions/gsd/repo-identity.js +205 -11
- package/dist/resources/extensions/gsd/rethink.js +5 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -4
- package/dist/resources/extensions/gsd/state.js +85 -27
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +34 -71
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +12 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +29 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +14 -3
- package/dist/resources/extensions/gsd/triage-resolution.js +22 -7
- package/dist/resources/extensions/gsd/undo.js +2 -2
- package/dist/resources/extensions/gsd/unit-ownership.js +164 -33
- package/dist/resources/extensions/gsd/verdict-parser.js +20 -8
- package/dist/resources/extensions/gsd/watch/header-renderer.js +241 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +24 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +95 -63
- package/dist/resources/extensions/gsd/workflow-reconcile.js +35 -5
- package/dist/resources/extensions/gsd/workspace-index.js +24 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +105 -1
- package/dist/resources/extensions/gsd/worktree-resolver.js +20 -3
- package/dist/resources/extensions/mcp-client/index.js +11 -7
- package/dist/resources/extensions/ollama/index.js +112 -0
- package/dist/resources/extensions/ollama/model-capabilities.js +115 -0
- package/dist/resources/extensions/ollama/ollama-client.js +168 -0
- package/dist/resources/extensions/ollama/ollama-commands.js +194 -0
- package/dist/resources/extensions/ollama/ollama-discovery.js +69 -0
- package/dist/resources/extensions/ollama/ollama-tool.js +184 -0
- package/dist/resources/extensions/ollama/types.js +2 -0
- package/dist/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/dist/resources/extensions/shared/interview-ui.js +11 -1
- package/dist/resources/skills/create-gsd-extension/SKILL.md +5 -3
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
- package/dist/startup-model-validation.d.ts +39 -0
- package/dist/startup-model-validation.js +50 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-61d3afac6d0f0ce7.js → webpack-a1c1e452c6b32d04.js} +1 -1
- package/dist/web/standalone/.next/static/css/f6e8833d46e738d8.css +1 -0
- package/dist/web-mode.js +2 -1
- package/dist/welcome-screen.d.ts +1 -0
- package/dist/welcome-screen.js +32 -6
- package/package.json +2 -2
- package/packages/daemon/src/cli.ts +49 -0
- package/packages/daemon/src/daemon.test.ts +104 -1
- package/packages/daemon/src/daemon.ts +24 -1
- package/packages/daemon/src/discord-bot.ts +73 -3
- package/packages/daemon/src/event-bridge.ts +15 -9
- package/packages/daemon/src/event-formatter.ts +30 -2
- package/packages/daemon/src/index.ts +9 -0
- package/packages/daemon/src/launchd.test.ts +356 -0
- package/packages/daemon/src/launchd.ts +242 -0
- package/packages/daemon/src/message-batcher.test.ts +2 -2
- package/packages/daemon/src/message-batcher.ts +9 -3
- package/packages/daemon/src/orchestrator.test.ts +1 -0
- package/packages/daemon/src/orchestrator.ts +106 -2
- package/packages/native/dist/ast/index.js +9 -5
- package/packages/native/dist/ast/types.js +2 -1
- package/packages/native/dist/clipboard/index.js +12 -7
- package/packages/native/dist/clipboard/types.js +2 -1
- package/packages/native/dist/diff/index.js +12 -7
- package/packages/native/dist/diff/types.js +2 -1
- package/packages/native/dist/fd/index.js +6 -3
- package/packages/native/dist/fd/types.js +2 -1
- package/packages/native/dist/glob/index.js +9 -5
- package/packages/native/dist/glob/types.js +2 -1
- package/packages/native/dist/grep/index.js +9 -5
- package/packages/native/dist/grep/types.js +2 -1
- package/packages/native/dist/gsd-parser/index.js +18 -11
- package/packages/native/dist/gsd-parser/types.js +2 -1
- package/packages/native/dist/highlight/index.js +12 -7
- package/packages/native/dist/highlight/types.js +2 -1
- package/packages/native/dist/html/index.js +6 -3
- package/packages/native/dist/html/types.js +2 -1
- package/packages/native/dist/image/index.js +10 -5
- package/packages/native/dist/image/types.js +7 -4
- package/packages/native/dist/index.js +70 -17
- package/packages/native/dist/json-parse/index.js +13 -8
- package/packages/native/dist/native.js +47 -10
- package/packages/native/dist/ps/index.js +15 -9
- package/packages/native/dist/ps/types.js +2 -1
- package/packages/native/dist/stream-process/index.js +12 -7
- package/packages/native/dist/text/index.js +24 -14
- package/packages/native/dist/text/types.js +5 -2
- package/packages/native/dist/truncate/index.js +12 -7
- package/packages/native/dist/ttsr/index.js +12 -7
- package/packages/native/dist/ttsr/types.js +2 -1
- package/packages/native/dist/xxhash/index.js +9 -5
- package/packages/native/package.json +19 -19
- package/packages/native/src/__tests__/module-compat.test.mjs +91 -0
- package/packages/native/src/native.ts +9 -8
- package/packages/pi-agent-core/dist/agent-loop.js +3 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/proxy.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +45 -0
- package/packages/pi-agent-core/src/agent-loop.ts +3 -2
- package/packages/pi-agent-core/src/proxy.ts +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +1 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +19 -2
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js +25 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -0
- package/packages/pi-ai/dist/types.d.ts +3 -3
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.d.ts +3 -0
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +24 -1
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts +37 -0
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/repair-tool-json.js +75 -0
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +73 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -0
- package/packages/pi-ai/src/env-api-keys.ts +1 -0
- package/packages/pi-ai/src/index.ts +1 -0
- package/packages/pi-ai/src/providers/anthropic-shared.test.ts +29 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +17 -2
- package/packages/pi-ai/src/types.ts +3 -2
- package/packages/pi-ai/src/utils/json-parse.ts +28 -1
- package/packages/pi-ai/src/utils/repair-tool-json.ts +88 -0
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +102 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -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 +31 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +17 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +62 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +176 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/exec.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/exec.js +3 -1
- package/packages/pi-coding-agent/dist/core/exec.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts +28 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js +37 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js +63 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js +115 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js +109 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts +44 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js +97 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js +181 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -1
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.js +31 -2
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/messages.test.js +86 -0
- package/packages/pi-coding-agent/dist/core/messages.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 +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +12 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +48 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +193 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +10 -3
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +13 -4
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts +16 -0
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +80 -0
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +2 -2
- 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/armin.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/armin.js +9 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/armin.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +0 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.js +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/custom-message.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.js +4 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +26 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/oauth-selector.js +4 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +46 -14
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js +4 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- 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 +8 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.js +3 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.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 +19 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +16 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -0
- 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 +27 -4
- 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.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js +5 -0
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +38 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +236 -0
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +94 -1
- package/packages/pi-coding-agent/src/core/exec.ts +3 -1
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.test.ts +77 -0
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.ts +62 -0
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.test.ts +134 -0
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.ts +137 -0
- package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.test.ts +228 -0
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.ts +118 -0
- package/packages/pi-coding-agent/src/core/index.ts +6 -0
- package/packages/pi-coding-agent/src/core/lsp/index.ts +3 -0
- package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +3 -0
- package/packages/pi-coding-agent/src/core/messages.test.ts +114 -0
- package/packages/pi-coding-agent/src/core/messages.ts +29 -2
- package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
- package/packages/pi-coding-agent/src/core/resource-loader.ts +20 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +255 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +52 -1
- package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +11 -3
- package/packages/pi-coding-agent/src/core/tools/read.ts +14 -4
- package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +92 -0
- package/packages/pi-coding-agent/src/index.ts +6 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/armin.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +0 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/bordered-loader.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/config-selector.ts +7 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/countdown-timer.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/custom-message.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/daxnuts.ts +4 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-selector.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +27 -13
- package/packages/pi-coding-agent/src/modes/interactive/components/oauth-selector.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +45 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +8 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message-selector.ts +3 -2
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +24 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +14 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +35 -3
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +7 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +1 -1
- package/packages/pi-coding-agent/src/modes/rpc/remote-terminal.ts +6 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +9 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +9 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/terminal.ts +14 -0
- package/packages/pi-tui/src/tui.ts +8 -0
- package/pkg/dist/modes/interactive/theme/themes.js +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/scripts/ensure-workspace-builds.cjs +45 -14
- package/src/resources/agents/researcher.md +1 -1
- package/src/resources/extensions/ask-user-questions.ts +21 -3
- package/src/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/src/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +13 -6
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +63 -35
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +28 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -1
- package/src/resources/extensions/context7/extension-manifest.json +1 -1
- package/src/resources/extensions/get-secrets-from-user.ts +8 -5
- package/src/resources/extensions/google-search/extension-manifest.json +1 -1
- package/src/resources/extensions/google-search/index.ts +2 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +43 -34
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
- package/src/resources/extensions/gsd/auto-dashboard.ts +37 -19
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -2
- package/src/resources/extensions/gsd/auto-model-selection.ts +26 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +12 -5
- package/src/resources/extensions/gsd/auto-start.ts +35 -26
- package/src/resources/extensions/gsd/auto-worktree.ts +193 -9
- package/src/resources/extensions/gsd/auto.ts +5 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +31 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +85 -8
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +38 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -35
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +72 -12
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +75 -0
- package/src/resources/extensions/gsd/captures.ts +63 -3
- package/src/resources/extensions/gsd/codebase-generator.ts +351 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +10 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-codebase.ts +164 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +46 -4
- package/src/resources/extensions/gsd/complexity-classifier.ts +8 -6
- package/src/resources/extensions/gsd/db-writer.ts +140 -7
- package/src/resources/extensions/gsd/doctor-git-checks.ts +75 -1
- package/src/resources/extensions/gsd/doctor-proactive.ts +35 -1
- package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +5 -4
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +3 -1
- package/src/resources/extensions/gsd/error-classifier.ts +13 -11
- package/src/resources/extensions/gsd/extension-manifest.json +16 -1
- package/src/resources/extensions/gsd/forensics.ts +144 -20
- package/src/resources/extensions/gsd/git-service.ts +119 -3
- package/src/resources/extensions/gsd/gitignore.ts +33 -0
- package/src/resources/extensions/gsd/gsd-db.ts +43 -7
- package/src/resources/extensions/gsd/guided-flow.ts +114 -45
- package/src/resources/extensions/gsd/health-widget-core.ts +34 -0
- package/src/resources/extensions/gsd/health-widget.ts +17 -0
- package/src/resources/extensions/gsd/index.ts +1 -0
- package/src/resources/extensions/gsd/memory-extractor.ts +8 -0
- package/src/resources/extensions/gsd/migrate-external.ts +9 -1
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +56 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +19 -0
- package/src/resources/extensions/gsd/model-router.ts +35 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +41 -0
- package/src/resources/extensions/gsd/notifications.ts +16 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +15 -2
- package/src/resources/extensions/gsd/parallel-merge.ts +87 -4
- package/src/resources/extensions/gsd/parsers-legacy.ts +22 -3
- package/src/resources/extensions/gsd/paths.ts +44 -0
- package/src/resources/extensions/gsd/preferences-models.ts +14 -1
- package/src/resources/extensions/gsd/preferences-types.ts +10 -1
- package/src/resources/extensions/gsd/preferences.ts +13 -15
- package/src/resources/extensions/gsd/prompt-loader.ts +4 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -2
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -1
- package/src/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -0
- package/src/resources/extensions/gsd/repo-identity.ts +186 -11
- package/src/resources/extensions/gsd/rethink.ts +6 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +5 -4
- package/src/resources/extensions/gsd/state.ts +84 -32
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +71 -1
- package/src/resources/extensions/gsd/tests/captures.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +488 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +131 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +7 -12
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +78 -5
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +129 -0
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +125 -12
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +164 -0
- package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +135 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +134 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +243 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +959 -0
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +85 -2
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +68 -3
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/notifications.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +297 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +178 -0
- package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +162 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +134 -0
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +233 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +305 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +405 -0
- package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +257 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +1628 -0
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +221 -0
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +289 -0
- package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +100 -17
- package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +154 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +95 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +36 -74
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +13 -1
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +36 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +20 -2
- package/src/resources/extensions/gsd/triage-resolution.ts +23 -6
- package/src/resources/extensions/gsd/types.ts +4 -2
- package/src/resources/extensions/gsd/undo.ts +2 -2
- package/src/resources/extensions/gsd/unit-ownership.ts +206 -35
- package/src/resources/extensions/gsd/verdict-parser.ts +21 -6
- package/src/resources/extensions/gsd/watch/header-renderer.ts +275 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
- package/src/resources/extensions/gsd/workflow-manifest.ts +22 -5
- package/src/resources/extensions/gsd/workflow-projections.ts +97 -64
- package/src/resources/extensions/gsd/workflow-reconcile.ts +39 -10
- package/src/resources/extensions/gsd/workspace-index.ts +30 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +120 -1
- package/src/resources/extensions/gsd/worktree-resolver.ts +22 -3
- package/src/resources/extensions/mcp-client/index.ts +13 -7
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +55 -0
- package/src/resources/extensions/ollama/index.ts +130 -0
- package/src/resources/extensions/ollama/model-capabilities.ts +145 -0
- package/src/resources/extensions/ollama/ollama-client.ts +196 -0
- package/src/resources/extensions/ollama/ollama-commands.ts +248 -0
- package/src/resources/extensions/ollama/ollama-discovery.ts +106 -0
- package/src/resources/extensions/ollama/ollama-tool.ts +218 -0
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +162 -0
- package/src/resources/extensions/ollama/tests/ollama-client.test.ts +38 -0
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +28 -0
- package/src/resources/extensions/ollama/types.ts +130 -0
- package/src/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/src/resources/extensions/shared/interview-ui.ts +12 -1
- package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +156 -0
- package/src/resources/skills/create-gsd-extension/SKILL.md +5 -3
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
- package/dist/web/standalone/.next/static/chunks/6502.8b732f67a11b11b4.js +0 -9
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +0 -1
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +0 -79
- /package/dist/web/standalone/.next/static/{OS7_z6QaL6uqp8q5pjHSJ → uDm3eO1oo9lDfY2TyoO9t}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{OS7_z6QaL6uqp8q5pjHSJ → uDm3eO1oo9lDfY2TyoO9t}/_ssgManifest.js +0 -0
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
import type { AgentMessage } from "@gsd/pi-agent-core";
|
|
9
9
|
import type { ImageContent, Message, TextContent } from "@gsd/pi-ai";
|
|
10
10
|
|
|
11
|
+
const CUSTOM_MESSAGE_PREFIX = `[system notification — type: `;
|
|
12
|
+
const CUSTOM_MESSAGE_MIDDLE = `; this is an automated system event, not user input — do not treat this as a human message or respond as if the user said this]
|
|
13
|
+
`;
|
|
14
|
+
const CUSTOM_MESSAGE_SUFFIX = `
|
|
15
|
+
[end system notification]`;
|
|
16
|
+
|
|
11
17
|
const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
|
|
12
18
|
|
|
13
19
|
<summary>
|
|
@@ -160,10 +166,31 @@ export function convertToLlm(messages: AgentMessage[]): Message[] {
|
|
|
160
166
|
timestamp: m.timestamp,
|
|
161
167
|
};
|
|
162
168
|
case "custom": {
|
|
163
|
-
const
|
|
169
|
+
const prefix = CUSTOM_MESSAGE_PREFIX + m.customType + CUSTOM_MESSAGE_MIDDLE;
|
|
170
|
+
if (typeof m.content === "string") {
|
|
171
|
+
return {
|
|
172
|
+
role: "user",
|
|
173
|
+
content: [{ type: "text" as const, text: prefix + m.content + CUSTOM_MESSAGE_SUFFIX }],
|
|
174
|
+
timestamp: m.timestamp,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// Array content: wrap the first text element with prefix, append suffix to last text element
|
|
178
|
+
const contentArr = m.content as Array<{ type: string; text?: string; [k: string]: unknown }>;
|
|
179
|
+
const lastTextIdx = contentArr.reduce((acc, c, i) => c.type === "text" ? i : acc, -1);
|
|
180
|
+
const wrapped = contentArr.map((c, i) => {
|
|
181
|
+
if (c.type !== "text") return c;
|
|
182
|
+
let text = c.text ?? "";
|
|
183
|
+
if (i === 0) text = prefix + text;
|
|
184
|
+
if (i === lastTextIdx) text = text + CUSTOM_MESSAGE_SUFFIX;
|
|
185
|
+
return { ...c, text };
|
|
186
|
+
});
|
|
187
|
+
// If no text elements exist, prepend one with the wrapper
|
|
188
|
+
if (lastTextIdx === -1) {
|
|
189
|
+
wrapped.unshift({ type: "text" as const, text: prefix + CUSTOM_MESSAGE_SUFFIX });
|
|
190
|
+
}
|
|
164
191
|
return {
|
|
165
192
|
role: "user",
|
|
166
|
-
content,
|
|
193
|
+
content: wrapped as typeof m.content,
|
|
167
194
|
timestamp: m.timestamp,
|
|
168
195
|
};
|
|
169
196
|
}
|
|
@@ -129,6 +129,12 @@ export interface DefaultResourceLoaderOptions {
|
|
|
129
129
|
appendSystemPrompt?: string;
|
|
130
130
|
/** Names of bundled extensions (used to identify built-in extensions in conflict detection). */
|
|
131
131
|
bundledExtensionNames?: Set<string>;
|
|
132
|
+
/**
|
|
133
|
+
* Transform extension paths before loading. Receives the merged list of all
|
|
134
|
+
* discovered extension paths and returns a (possibly reordered/filtered) list.
|
|
135
|
+
* Use this to apply dependency sorting or registry-based filtering.
|
|
136
|
+
*/
|
|
137
|
+
extensionPathsTransform?: (paths: string[]) => { paths: string[]; diagnostics?: string[] };
|
|
132
138
|
extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;
|
|
133
139
|
skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {
|
|
134
140
|
skills: Skill[];
|
|
@@ -167,6 +173,7 @@ export class DefaultResourceLoader implements ResourceLoader {
|
|
|
167
173
|
private systemPromptSource?: string;
|
|
168
174
|
private appendSystemPromptSource?: string;
|
|
169
175
|
private bundledExtensionNames: Set<string>;
|
|
176
|
+
private extensionPathsTransform?: (paths: string[]) => { paths: string[]; diagnostics?: string[] };
|
|
170
177
|
private extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;
|
|
171
178
|
private skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {
|
|
172
179
|
skills: Skill[];
|
|
@@ -223,6 +230,7 @@ export class DefaultResourceLoader implements ResourceLoader {
|
|
|
223
230
|
this.systemPromptSource = options.systemPrompt;
|
|
224
231
|
this.appendSystemPromptSource = options.appendSystemPrompt;
|
|
225
232
|
this.bundledExtensionNames = options.bundledExtensionNames ?? new Set();
|
|
233
|
+
this.extensionPathsTransform = options.extensionPathsTransform;
|
|
226
234
|
this.extensionsOverride = options.extensionsOverride;
|
|
227
235
|
this.skillsOverride = options.skillsOverride;
|
|
228
236
|
this.promptsOverride = options.promptsOverride;
|
|
@@ -378,10 +386,21 @@ export class DefaultResourceLoader implements ResourceLoader {
|
|
|
378
386
|
const cliEnabledPrompts = getEnabledPaths(cliExtensionPaths.prompts);
|
|
379
387
|
const cliEnabledThemes = getEnabledPaths(cliExtensionPaths.themes);
|
|
380
388
|
|
|
381
|
-
|
|
389
|
+
let extensionPaths = this.noExtensions
|
|
382
390
|
? cliEnabledExtensions
|
|
383
391
|
: this.mergePaths(cliEnabledExtensions, enabledExtensions);
|
|
384
392
|
|
|
393
|
+
// Apply path transform (dependency sorting, registry filtering) if provided
|
|
394
|
+
if (this.extensionPathsTransform) {
|
|
395
|
+
const transformed = this.extensionPathsTransform(extensionPaths);
|
|
396
|
+
extensionPaths = transformed.paths;
|
|
397
|
+
if (transformed.diagnostics?.length) {
|
|
398
|
+
for (const msg of transformed.diagnostics) {
|
|
399
|
+
process.stderr.write(`[extensions] ${msg}\n`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
385
404
|
const extensionsResult = await loadExtensions(extensionPaths, this.cwd, this.eventBus);
|
|
386
405
|
const inlineExtensions = await this.loadExtensionFactories(extensionsResult.runtime);
|
|
387
406
|
extensionsResult.extensions.push(...inlineExtensions.extensions);
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RetryHandler tests — long-context entitlement 429 error handling (#2803)
|
|
3
|
+
*
|
|
4
|
+
* Verifies that "Extra usage is required for long context requests" errors
|
|
5
|
+
* are classified as quota_exhausted (not rate_limit) and trigger a model
|
|
6
|
+
* downgrade from [1m] to base when no cross-provider fallback exists.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, beforeEach, mock, type Mock } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import { RetryHandler, type RetryHandlerDeps } from "./retry-handler.js";
|
|
12
|
+
import type { Api, AssistantMessage, Model } from "@gsd/pi-ai";
|
|
13
|
+
import type { FallbackResolver } from "./fallback-resolver.js";
|
|
14
|
+
import type { ModelRegistry } from "./model-registry.js";
|
|
15
|
+
import type { SettingsManager } from "./settings-manager.js";
|
|
16
|
+
|
|
17
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
function createMockModel(provider: string, id: string): Model<Api> {
|
|
20
|
+
return {
|
|
21
|
+
id,
|
|
22
|
+
name: id,
|
|
23
|
+
api: "anthropic" as Api,
|
|
24
|
+
provider,
|
|
25
|
+
baseUrl: "https://api.anthropic.com",
|
|
26
|
+
reasoning: false,
|
|
27
|
+
input: ["text"],
|
|
28
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
29
|
+
contextWindow: 1_000_000,
|
|
30
|
+
maxTokens: 16384,
|
|
31
|
+
} as Model<Api>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function errorMessage(msg: string): AssistantMessage {
|
|
35
|
+
return {
|
|
36
|
+
role: "assistant",
|
|
37
|
+
content: [],
|
|
38
|
+
api: "anthropic-messages",
|
|
39
|
+
provider: "anthropic",
|
|
40
|
+
model: "claude-opus-4-6[1m]",
|
|
41
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
42
|
+
stopReason: "error",
|
|
43
|
+
errorMessage: msg,
|
|
44
|
+
timestamp: Date.now(),
|
|
45
|
+
} as AssistantMessage;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface MockDeps {
|
|
49
|
+
deps: RetryHandlerDeps;
|
|
50
|
+
emittedEvents: Array<Record<string, any>>;
|
|
51
|
+
continueFn: Mock<() => Promise<void>>;
|
|
52
|
+
onModelChangeFn: Mock<(model: Model<any>) => void>;
|
|
53
|
+
markUsageLimitReached: Mock<(...args: any[]) => boolean>;
|
|
54
|
+
findFallback: Mock<(...args: any[]) => Promise<any>>;
|
|
55
|
+
findModel: Mock<(provider: string, modelId: string) => Model<Api> | undefined>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createMockDeps(overrides?: {
|
|
59
|
+
model?: Model<Api>;
|
|
60
|
+
retryEnabled?: boolean;
|
|
61
|
+
markUsageLimitReachedResult?: boolean;
|
|
62
|
+
fallbackResult?: any;
|
|
63
|
+
findModelResult?: (provider: string, modelId: string) => Model<Api> | undefined;
|
|
64
|
+
}): MockDeps {
|
|
65
|
+
const model = overrides?.model ?? createMockModel("anthropic", "claude-opus-4-6[1m]");
|
|
66
|
+
const emittedEvents: Array<Record<string, any>> = [];
|
|
67
|
+
const continueFn = mock.fn(async () => {});
|
|
68
|
+
const onModelChangeFn = mock.fn((_model: Model<any>) => {});
|
|
69
|
+
const markUsageLimitReached = mock.fn(
|
|
70
|
+
() => overrides?.markUsageLimitReachedResult ?? false,
|
|
71
|
+
);
|
|
72
|
+
const findFallback = mock.fn(async () => overrides?.fallbackResult ?? null);
|
|
73
|
+
const findModel = mock.fn(
|
|
74
|
+
overrides?.findModelResult ?? ((_provider: string, _modelId: string) => undefined),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const messages: Array<{ role: string } & Record<string, any>> = [];
|
|
78
|
+
|
|
79
|
+
const deps: RetryHandlerDeps = {
|
|
80
|
+
agent: {
|
|
81
|
+
continue: continueFn,
|
|
82
|
+
state: { messages },
|
|
83
|
+
setModel: mock.fn(),
|
|
84
|
+
replaceMessages: mock.fn((newMessages: any[]) => {
|
|
85
|
+
messages.length = 0;
|
|
86
|
+
messages.push(...newMessages);
|
|
87
|
+
}),
|
|
88
|
+
} as any,
|
|
89
|
+
settingsManager: {
|
|
90
|
+
getRetryEnabled: () => overrides?.retryEnabled ?? true,
|
|
91
|
+
getRetrySettings: () => ({
|
|
92
|
+
enabled: overrides?.retryEnabled ?? true,
|
|
93
|
+
maxRetries: 5,
|
|
94
|
+
baseDelayMs: 1000,
|
|
95
|
+
maxDelayMs: 30000,
|
|
96
|
+
}),
|
|
97
|
+
} as unknown as SettingsManager,
|
|
98
|
+
modelRegistry: {
|
|
99
|
+
authStorage: {
|
|
100
|
+
markUsageLimitReached,
|
|
101
|
+
},
|
|
102
|
+
find: findModel,
|
|
103
|
+
} as unknown as ModelRegistry,
|
|
104
|
+
fallbackResolver: {
|
|
105
|
+
findFallback,
|
|
106
|
+
} as unknown as FallbackResolver,
|
|
107
|
+
getModel: () => model,
|
|
108
|
+
getSessionId: () => "test-session",
|
|
109
|
+
emit: (event: any) => emittedEvents.push(event),
|
|
110
|
+
onModelChange: onModelChangeFn,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return { deps, emittedEvents, continueFn, onModelChangeFn, markUsageLimitReached, findFallback, findModel };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── _classifyErrorType (tested via handleRetryableError behavior) ──────────
|
|
117
|
+
|
|
118
|
+
describe("RetryHandler — long-context entitlement 429 (#2803)", () => {
|
|
119
|
+
|
|
120
|
+
describe("error classification", () => {
|
|
121
|
+
it("classifies 'Extra usage is required for long context requests' as quota_exhausted, not rate_limit", async () => {
|
|
122
|
+
// When the error is classified as quota_exhausted AND no alternate credentials
|
|
123
|
+
// AND no fallback, the handler should emit fallback_chain_exhausted and stop.
|
|
124
|
+
// If misclassified as rate_limit, it would enter the backoff loop instead.
|
|
125
|
+
const { deps, emittedEvents, findModel } = createMockDeps({
|
|
126
|
+
model: createMockModel("anthropic", "claude-opus-4-6[1m]"),
|
|
127
|
+
markUsageLimitReachedResult: false, // no alternate credentials
|
|
128
|
+
fallbackResult: null, // no cross-provider fallback
|
|
129
|
+
findModelResult: () => undefined, // no base model either
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const handler = new RetryHandler(deps);
|
|
133
|
+
const msg = errorMessage(
|
|
134
|
+
'429 {"type":"error","error":{"type":"rate_limit_error","message":"Extra usage is required for long context requests."}}'
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const result = await handler.handleRetryableError(msg);
|
|
138
|
+
|
|
139
|
+
// Should NOT retry (would be true if misclassified as rate_limit entering backoff)
|
|
140
|
+
assert.equal(result, false);
|
|
141
|
+
|
|
142
|
+
// Should emit fallback_chain_exhausted (quota_exhausted path), NOT auto_retry_start (backoff path)
|
|
143
|
+
const chainExhausted = emittedEvents.find((e) => e.type === "fallback_chain_exhausted");
|
|
144
|
+
assert.ok(chainExhausted, "Expected fallback_chain_exhausted event for entitlement error");
|
|
145
|
+
|
|
146
|
+
const retryStart = emittedEvents.find((e) => e.type === "auto_retry_start");
|
|
147
|
+
assert.equal(retryStart, undefined, "Should NOT emit auto_retry_start for entitlement error");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("still classifies regular 429 rate limits as rate_limit", async () => {
|
|
151
|
+
// A normal "rate limit" 429 should still be classified as rate_limit
|
|
152
|
+
const { deps, emittedEvents } = createMockDeps({
|
|
153
|
+
model: createMockModel("anthropic", "claude-opus-4-6"),
|
|
154
|
+
markUsageLimitReachedResult: false,
|
|
155
|
+
fallbackResult: null,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const handler = new RetryHandler(deps);
|
|
159
|
+
const msg = errorMessage("429 Too Many Requests");
|
|
160
|
+
|
|
161
|
+
const result = await handler.handleRetryableError(msg);
|
|
162
|
+
|
|
163
|
+
// Should enter the backoff loop (rate_limit path, not quota_exhausted)
|
|
164
|
+
assert.equal(result, true);
|
|
165
|
+
|
|
166
|
+
const retryStart = emittedEvents.find((e) => e.type === "auto_retry_start");
|
|
167
|
+
assert.ok(retryStart, "Regular 429 should enter backoff retry");
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("long-context model downgrade", () => {
|
|
172
|
+
it("downgrades from [1m] to base model when entitlement error and no fallback", async () => {
|
|
173
|
+
const baseModel = createMockModel("anthropic", "claude-opus-4-6");
|
|
174
|
+
const { deps, emittedEvents, onModelChangeFn, continueFn } = createMockDeps({
|
|
175
|
+
model: createMockModel("anthropic", "claude-opus-4-6[1m]"),
|
|
176
|
+
markUsageLimitReachedResult: false,
|
|
177
|
+
fallbackResult: null,
|
|
178
|
+
findModelResult: (provider: string, modelId: string) => {
|
|
179
|
+
if (provider === "anthropic" && modelId === "claude-opus-4-6") return baseModel;
|
|
180
|
+
return undefined;
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const handler = new RetryHandler(deps);
|
|
185
|
+
const msg = errorMessage("Extra usage is required for long context requests.");
|
|
186
|
+
|
|
187
|
+
const result = await handler.handleRetryableError(msg);
|
|
188
|
+
|
|
189
|
+
assert.equal(result, true, "Should retry after downgrade");
|
|
190
|
+
|
|
191
|
+
// Should have called setModel with the base model
|
|
192
|
+
const setModelCalls = (deps.agent.setModel as any).mock.calls;
|
|
193
|
+
assert.equal(setModelCalls.length, 1);
|
|
194
|
+
assert.equal(setModelCalls[0].arguments[0].id, "claude-opus-4-6");
|
|
195
|
+
|
|
196
|
+
// Should have notified about model change
|
|
197
|
+
assert.equal(onModelChangeFn.mock.calls.length, 1);
|
|
198
|
+
|
|
199
|
+
// Should emit a fallback_provider_switch event indicating downgrade
|
|
200
|
+
const switchEvent = emittedEvents.find((e) => e.type === "fallback_provider_switch");
|
|
201
|
+
assert.ok(switchEvent, "Expected fallback_provider_switch event for downgrade");
|
|
202
|
+
assert.ok(switchEvent!.reason.includes("long context downgrade"), `reason should mention downgrade: ${switchEvent!.reason}`);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("emits fallback_chain_exhausted when base model is also unavailable", async () => {
|
|
206
|
+
const { deps, emittedEvents } = createMockDeps({
|
|
207
|
+
model: createMockModel("anthropic", "claude-opus-4-6[1m]"),
|
|
208
|
+
markUsageLimitReachedResult: false,
|
|
209
|
+
fallbackResult: null,
|
|
210
|
+
findModelResult: () => undefined, // base model not found
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const handler = new RetryHandler(deps);
|
|
214
|
+
const msg = errorMessage("Extra usage is required for long context requests.");
|
|
215
|
+
|
|
216
|
+
const result = await handler.handleRetryableError(msg);
|
|
217
|
+
|
|
218
|
+
assert.equal(result, false);
|
|
219
|
+
const chainExhausted = emittedEvents.find((e) => e.type === "fallback_chain_exhausted");
|
|
220
|
+
assert.ok(chainExhausted, "Expected fallback_chain_exhausted when base model unavailable");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("does not attempt downgrade for non-[1m] models", async () => {
|
|
224
|
+
// When a regular model (no [1m] suffix) gets a quota_exhausted error
|
|
225
|
+
// with no fallback, it should just stop — no downgrade attempt.
|
|
226
|
+
const { deps, emittedEvents } = createMockDeps({
|
|
227
|
+
model: createMockModel("anthropic", "claude-opus-4-6"),
|
|
228
|
+
markUsageLimitReachedResult: false,
|
|
229
|
+
fallbackResult: null,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const handler = new RetryHandler(deps);
|
|
233
|
+
const msg = errorMessage("Extra usage is required for long context requests.");
|
|
234
|
+
|
|
235
|
+
const result = await handler.handleRetryableError(msg);
|
|
236
|
+
|
|
237
|
+
assert.equal(result, false);
|
|
238
|
+
const chainExhausted = emittedEvents.find((e) => e.type === "fallback_chain_exhausted");
|
|
239
|
+
assert.ok(chainExhausted);
|
|
240
|
+
|
|
241
|
+
// No downgrade switch should occur
|
|
242
|
+
const switchEvent = emittedEvents.find((e) => e.type === "fallback_provider_switch");
|
|
243
|
+
assert.equal(switchEvent, undefined, "Should not switch for non-[1m] models");
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe("isRetryableError", () => {
|
|
248
|
+
it("considers long-context entitlement error as retryable", () => {
|
|
249
|
+
const { deps } = createMockDeps();
|
|
250
|
+
const handler = new RetryHandler(deps);
|
|
251
|
+
const msg = errorMessage("Extra usage is required for long context requests.");
|
|
252
|
+
assert.equal(handler.isRetryableError(msg), true);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|
|
@@ -107,7 +107,7 @@ export class RetryHandler {
|
|
|
107
107
|
if (isContextOverflow(message, contextWindow)) return false;
|
|
108
108
|
|
|
109
109
|
const err = message.errorMessage;
|
|
110
|
-
return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated|retry delay|network.?(?:is\s+)?unavailable|credentials.*expired|temporarily backed off/i.test(
|
|
110
|
+
return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated|retry delay|network.?(?:is\s+)?unavailable|credentials.*expired|temporarily backed off|extra usage is required/i.test(
|
|
111
111
|
err,
|
|
112
112
|
);
|
|
113
113
|
}
|
|
@@ -202,6 +202,10 @@ export class RetryHandler {
|
|
|
202
202
|
|
|
203
203
|
// No fallback available either
|
|
204
204
|
if (errorType === "quota_exhausted") {
|
|
205
|
+
// Try long-context model downgrade ([1m] → base) before giving up
|
|
206
|
+
const downgraded = this._tryLongContextDowngrade(message);
|
|
207
|
+
if (downgraded) return true;
|
|
208
|
+
|
|
205
209
|
this._deps.emit({
|
|
206
210
|
type: "fallback_chain_exhausted",
|
|
207
211
|
reason: `All providers exhausted for ${this._deps.getModel()!.provider}/${this._deps.getModel()!.id}`,
|
|
@@ -343,12 +347,59 @@ export class RetryHandler {
|
|
|
343
347
|
*/
|
|
344
348
|
private _classifyErrorType(errorMessage: string): UsageLimitErrorType {
|
|
345
349
|
const err = errorMessage.toLowerCase();
|
|
350
|
+
// Long-context entitlement errors are billing gates, not transient rate limits.
|
|
351
|
+
// Must be checked before the generic 429/rate_limit regex.
|
|
352
|
+
if (/extra usage is required|long context required/i.test(err)) return "quota_exhausted";
|
|
346
353
|
if (/quota|billing|exceeded.*limit|usage.*limit/i.test(err)) return "quota_exhausted";
|
|
347
354
|
if (/rate.?limit|too many requests|429/i.test(err)) return "rate_limit";
|
|
348
355
|
if (/500|502|503|504|server.?error|internal.?error|service.?unavailable/i.test(err)) return "server_error";
|
|
349
356
|
return "unknown";
|
|
350
357
|
}
|
|
351
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Attempt to downgrade a long-context model (e.g. claude-opus-4-6[1m]) to its
|
|
361
|
+
* base model (claude-opus-4-6) when the account lacks the long-context billing
|
|
362
|
+
* entitlement. Returns true if the downgrade was initiated.
|
|
363
|
+
*/
|
|
364
|
+
private _tryLongContextDowngrade(message: AssistantMessage): boolean {
|
|
365
|
+
const currentModel = this._deps.getModel();
|
|
366
|
+
if (!currentModel) return false;
|
|
367
|
+
|
|
368
|
+
// Only attempt downgrade for [1m] (or similar long-context) model IDs
|
|
369
|
+
const match = currentModel.id.match(/^(.+)\[\d+m\]$/);
|
|
370
|
+
if (!match) return false;
|
|
371
|
+
|
|
372
|
+
const baseModelId = match[1];
|
|
373
|
+
const baseModel = this._deps.modelRegistry.find(currentModel.provider, baseModelId);
|
|
374
|
+
if (!baseModel) return false;
|
|
375
|
+
|
|
376
|
+
const previousId = currentModel.id;
|
|
377
|
+
this._deps.agent.setModel(baseModel);
|
|
378
|
+
this._deps.onModelChange(baseModel);
|
|
379
|
+
this._removeLastAssistantError();
|
|
380
|
+
|
|
381
|
+
this._deps.emit({
|
|
382
|
+
type: "fallback_provider_switch",
|
|
383
|
+
from: `${currentModel.provider}/${previousId}`,
|
|
384
|
+
to: `${baseModel.provider}/${baseModel.id}`,
|
|
385
|
+
reason: `long context downgrade: ${previousId} → ${baseModel.id}`,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
this._deps.emit({
|
|
389
|
+
type: "auto_retry_start",
|
|
390
|
+
attempt: this._retryAttempt + 1,
|
|
391
|
+
maxAttempts: this._deps.settingsManager.getRetrySettings().maxRetries,
|
|
392
|
+
delayMs: 0,
|
|
393
|
+
errorMessage: `${message.errorMessage} (long context downgrade)`,
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
setTimeout(() => {
|
|
397
|
+
this._deps.agent.continue().catch(() => {});
|
|
398
|
+
}, 0);
|
|
399
|
+
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
|
|
352
403
|
/** Remove the last assistant error message from agent state */
|
|
353
404
|
private _removeLastAssistantError(): void {
|
|
354
405
|
const messages = this._deps.agent.state.messages;
|
|
@@ -123,12 +123,15 @@ export function createHashlineReadTool(cwd: string, options?: HashlineReadToolOp
|
|
|
123
123
|
const allLines = textContent.split("\n");
|
|
124
124
|
const totalFileLines = allLines.length;
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
const startLineDisplay = startLine + 1;
|
|
126
|
+
let startLine = offset ? Math.max(0, offset - 1) : 0;
|
|
128
127
|
|
|
128
|
+
// Clamp offset to file bounds instead of throwing (#3007)
|
|
129
|
+
let offsetClamped = false;
|
|
129
130
|
if (startLine >= allLines.length) {
|
|
130
|
-
|
|
131
|
+
startLine = Math.max(0, allLines.length - 1);
|
|
132
|
+
offsetClamped = true;
|
|
131
133
|
}
|
|
134
|
+
const startLineDisplay = startLine + 1;
|
|
132
135
|
|
|
133
136
|
let selectedContent: string;
|
|
134
137
|
let userLimitedLines: number | undefined;
|
|
@@ -172,6 +175,11 @@ export function createHashlineReadTool(cwd: string, options?: HashlineReadToolOp
|
|
|
172
175
|
outputText = formatHashLines(truncation.content, startLineDisplay);
|
|
173
176
|
}
|
|
174
177
|
|
|
178
|
+
// Prepend clamp notice so the agent knows offset was adjusted
|
|
179
|
+
if (offsetClamped) {
|
|
180
|
+
outputText = `[Offset ${offset} beyond end of file (${totalFileLines} lines). Clamped to line ${startLineDisplay}.]\n\n${outputText}`;
|
|
181
|
+
}
|
|
182
|
+
|
|
175
183
|
content = [{ type: "text", text: outputText }];
|
|
176
184
|
}
|
|
177
185
|
|
|
@@ -133,13 +133,18 @@ export function createReadTool(cwd: string, options?: ReadToolOptions): AgentToo
|
|
|
133
133
|
const totalFileLines = allLines.length;
|
|
134
134
|
|
|
135
135
|
// Apply offset if specified (1-indexed to 0-indexed)
|
|
136
|
-
|
|
137
|
-
const startLineDisplay = startLine + 1; // For display (1-indexed)
|
|
136
|
+
let startLine = offset ? Math.max(0, offset - 1) : 0;
|
|
138
137
|
|
|
139
|
-
//
|
|
138
|
+
// Clamp offset to file bounds instead of throwing (#3007).
|
|
139
|
+
// When an agent requests offset:30 on a 13-line file, return
|
|
140
|
+
// the last line with a notice rather than an error that
|
|
141
|
+
// propagates as invalid JSON downstream.
|
|
142
|
+
let offsetClamped = false;
|
|
140
143
|
if (startLine >= allLines.length) {
|
|
141
|
-
|
|
144
|
+
startLine = Math.max(0, allLines.length - 1);
|
|
145
|
+
offsetClamped = true;
|
|
142
146
|
}
|
|
147
|
+
const startLineDisplay = startLine + 1; // For display (1-indexed)
|
|
143
148
|
|
|
144
149
|
// If limit is specified by user, use it; otherwise we'll let truncateHead decide
|
|
145
150
|
let selectedContent: string;
|
|
@@ -187,6 +192,11 @@ export function createReadTool(cwd: string, options?: ReadToolOptions): AgentToo
|
|
|
187
192
|
outputText = truncation.content;
|
|
188
193
|
}
|
|
189
194
|
|
|
195
|
+
// Prepend clamp notice so the agent knows offset was adjusted
|
|
196
|
+
if (offsetClamped) {
|
|
197
|
+
outputText = `[Offset ${offset} beyond end of file (${totalFileLines} lines). Clamped to line ${startLineDisplay}.]\n\n${outputText}`;
|
|
198
|
+
}
|
|
199
|
+
|
|
190
200
|
content = [{ type: "text", text: outputText }];
|
|
191
201
|
}
|
|
192
202
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spawn-shell-windows.test.ts — Regression test for Windows spawn ENOENT/EINVAL.
|
|
3
|
+
*
|
|
4
|
+
* On Windows, npm/npx/tsc and other tools are installed as .cmd batch scripts.
|
|
5
|
+
* Node's `spawn()` without `shell: true` cannot execute .cmd files, resulting
|
|
6
|
+
* in ENOENT or EINVAL errors. Every spawn site that may invoke a user-installed
|
|
7
|
+
* binary (not `node` or a shell like `sh`/`bash`/`cmd`) must include
|
|
8
|
+
* `shell: process.platform === "win32"` so the call is resolved through cmd.exe
|
|
9
|
+
* on Windows while remaining a direct exec on POSIX.
|
|
10
|
+
*
|
|
11
|
+
* This test structurally scans all spawn sites and verifies the guard is present.
|
|
12
|
+
*
|
|
13
|
+
* Fixes: gsd-build/gsd-2#2854
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import test from "node:test";
|
|
17
|
+
import assert from "node:assert/strict";
|
|
18
|
+
import { readFileSync } from "node:fs";
|
|
19
|
+
import { join, dirname, relative } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
|
|
22
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const coreDir = join(__dirname, "..");
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Files that call `spawn()` with a user-facing binary (not `node`, `sh`, `bash`,
|
|
27
|
+
* or `cmd`) and therefore need the Windows shell guard.
|
|
28
|
+
*
|
|
29
|
+
* If a file spawns only hardcoded system binaries (like `node` in rpc-client.ts),
|
|
30
|
+
* it does not need the guard and should NOT appear here.
|
|
31
|
+
*/
|
|
32
|
+
const SPAWN_FILES_NEEDING_SHELL_GUARD = [
|
|
33
|
+
// Extension's GSD client — spawns the `gsd` binary which is a .cmd on Windows
|
|
34
|
+
join(coreDir, "..", "..", "..", "vscode-extension", "src", "gsd-client.ts"),
|
|
35
|
+
// exec.ts — used by extensions to run arbitrary commands
|
|
36
|
+
join(coreDir, "exec.ts"),
|
|
37
|
+
// LSP index — spawns project-type commands (tsc, cargo, etc.)
|
|
38
|
+
join(coreDir, "lsp", "index.ts"),
|
|
39
|
+
// LSP client — spawns LSP server binaries (npx, etc.)
|
|
40
|
+
join(coreDir, "lsp", "client.ts"),
|
|
41
|
+
// LSP mux — spawns lspmux binary
|
|
42
|
+
join(coreDir, "lsp", "lspmux.ts"),
|
|
43
|
+
// Package manager — spawns npm/yarn/pnpm
|
|
44
|
+
join(coreDir, "package-manager.ts"),
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
test("all spawn sites that invoke user-facing binaries include shell: process.platform === 'win32'", () => {
|
|
48
|
+
const failures: string[] = [];
|
|
49
|
+
|
|
50
|
+
for (const file of SPAWN_FILES_NEEDING_SHELL_GUARD) {
|
|
51
|
+
let content: string;
|
|
52
|
+
try {
|
|
53
|
+
content = readFileSync(file, "utf-8");
|
|
54
|
+
} catch {
|
|
55
|
+
// File may not exist in this checkout — skip
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const lines = content.split("\n");
|
|
60
|
+
|
|
61
|
+
// Find all spawn(..., { ... }) call sites and check each one
|
|
62
|
+
// for the presence of `shell: process.platform === "win32"` within
|
|
63
|
+
// 5 lines after the spawn call.
|
|
64
|
+
for (let i = 0; i < lines.length; i++) {
|
|
65
|
+
const line = lines[i]!;
|
|
66
|
+
// Skip comments
|
|
67
|
+
if (line.trim().startsWith("//") || line.trim().startsWith("*")) continue;
|
|
68
|
+
|
|
69
|
+
// Detect a spawn() call
|
|
70
|
+
if (/\bspawn\(/.test(line)) {
|
|
71
|
+
// Look ahead up to 8 lines for the shell guard
|
|
72
|
+
const lookahead = lines.slice(i, i + 8).join("\n");
|
|
73
|
+
const hasShellGuard =
|
|
74
|
+
/shell:\s*process\.platform\s*===\s*["']win32["']/.test(lookahead);
|
|
75
|
+
|
|
76
|
+
if (!hasShellGuard) {
|
|
77
|
+
const relPath = relative(join(coreDir, "..", ".."), file);
|
|
78
|
+
failures.push(`${relPath}:${i + 1}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
assert.deepEqual(
|
|
85
|
+
failures,
|
|
86
|
+
[],
|
|
87
|
+
`The following spawn sites are missing 'shell: process.platform === "win32"':\n` +
|
|
88
|
+
failures.map(f => ` - ${f}`).join("\n") +
|
|
89
|
+
`\nOn Windows, .cmd wrapper scripts (npm, npx, tsc, gsd) require shell ` +
|
|
90
|
+
`resolution. Without this guard, spawn fails with ENOENT or EINVAL.`,
|
|
91
|
+
);
|
|
92
|
+
});
|
|
@@ -68,6 +68,7 @@ export type {
|
|
|
68
68
|
Extension,
|
|
69
69
|
ExtensionActions,
|
|
70
70
|
ExtensionAPI,
|
|
71
|
+
ExtensionManifest,
|
|
71
72
|
ExtensionCommandContext,
|
|
72
73
|
ExtensionCommandContextActions,
|
|
73
74
|
ExtensionContext,
|
|
@@ -119,6 +120,8 @@ export type {
|
|
|
119
120
|
ToolCallEvent,
|
|
120
121
|
ToolDefinition,
|
|
121
122
|
ToolInfo,
|
|
123
|
+
SortResult,
|
|
124
|
+
SortWarning,
|
|
122
125
|
ToolRenderResultOptions,
|
|
123
126
|
ToolResultEvent,
|
|
124
127
|
TurnEndEvent,
|
|
@@ -137,6 +140,9 @@ export {
|
|
|
137
140
|
importExtensionModule,
|
|
138
141
|
isToolCallEventType,
|
|
139
142
|
isToolResultEventType,
|
|
143
|
+
readManifest,
|
|
144
|
+
readManifestFromEntryPath,
|
|
145
|
+
sortExtensionPaths,
|
|
140
146
|
wrapRegisteredTool,
|
|
141
147
|
wrapRegisteredTools,
|
|
142
148
|
wrapToolsWithExtensions,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Armin says hi! A fun easter egg with animated XBM art.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type
|
|
5
|
+
import { type Component, type TUI, visibleWidth } from "@gsd/pi-tui";
|
|
6
6
|
import { theme } from "../theme/theme.js";
|
|
7
7
|
|
|
8
8
|
// XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground
|
|
@@ -88,20 +88,20 @@ export class ArminComponent implements Component {
|
|
|
88
88
|
return this.cachedLines;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const
|
|
92
|
-
|
|
91
|
+
const center = (s: string) => {
|
|
92
|
+
const visible = visibleWidth(s);
|
|
93
|
+
const left = Math.max(0, Math.floor((width - visible) / 2));
|
|
94
|
+
return " ".repeat(left) + s;
|
|
95
|
+
};
|
|
93
96
|
|
|
94
97
|
this.cachedLines = this.currentGrid.map((row) => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const padRight = Math.max(0, width - padding - clipped.length);
|
|
98
|
-
return ` ${theme.fg("accent", clipped)}${" ".repeat(padRight)}`;
|
|
98
|
+
const clipped = row.slice(0, width).join("");
|
|
99
|
+
return center(theme.fg("accent", clipped));
|
|
99
100
|
});
|
|
100
101
|
|
|
101
102
|
// Add "ARMIN SAYS HI" at the end
|
|
102
103
|
const message = "ARMIN SAYS HI";
|
|
103
|
-
|
|
104
|
-
this.cachedLines.push(` ${theme.fg("accent", message)}${" ".repeat(msgPadRight)}`);
|
|
104
|
+
this.cachedLines.push(center(theme.fg("accent", message)));
|
|
105
105
|
|
|
106
106
|
this.cachedWidth = width;
|
|
107
107
|
this.cachedVersion = this.gridVersion;
|
|
@@ -105,8 +105,6 @@ export class AssistantMessageComponent extends Container {
|
|
|
105
105
|
: "Operation aborted";
|
|
106
106
|
if (hasVisibleContent) {
|
|
107
107
|
this.contentContainer.addChild(new Spacer(1));
|
|
108
|
-
} else {
|
|
109
|
-
this.contentContainer.addChild(new Spacer(1));
|
|
110
108
|
}
|
|
111
109
|
this.contentContainer.addChild(new Text(theme.fg("error", abortMessage), 1, 0));
|
|
112
110
|
} else if (message.stopReason === "error") {
|