gsd-pi 2.77.0-dev.58d3d4d6c → 2.77.0-dev.cfd69e714
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/claude-cli-check.js +5 -1
- package/dist/headless.js +49 -4
- package/dist/resource-loader.d.ts +40 -0
- package/dist/resource-loader.js +32 -13
- package/dist/resources/extensions/browser-tools/capture.js +9 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/gsd/auto/loop.js +43 -0
- package/dist/resources/extensions/gsd/auto/phases.js +15 -21
- package/dist/resources/extensions/gsd/auto/session.js +0 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
- package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
- package/dist/resources/extensions/gsd/auto-start.js +34 -24
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
- package/dist/resources/extensions/gsd/auto.js +31 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
- package/dist/resources/extensions/gsd/component-loader.js +447 -0
- package/dist/resources/extensions/gsd/component-types.js +69 -0
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/gate-registry.js +2 -2
- package/dist/resources/extensions/gsd/git-constants.js +28 -1
- package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
- package/dist/resources/extensions/gsd/git-service.js +126 -2
- package/dist/resources/extensions/gsd/gsd-db.js +6 -3
- package/dist/resources/extensions/gsd/guided-flow.js +17 -5
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
- package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
- package/dist/resources/extensions/gsd/model-router.js +6 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/session-lock.js +19 -10
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state.js +44 -33
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
- package/dist/resources/extensions/mcp-client/index.js +3 -1
- package/dist/resources/extensions/ollama/index.js +5 -1
- package/dist/resources/extensions/remote-questions/manager.js +11 -5
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +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 +5 -5
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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/package.json +2 -3
- package/packages/daemon/src/logger.ts +4 -3
- package/packages/mcp-server/dist/server.d.ts +24 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +88 -87
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +25 -3
- package/packages/mcp-server/src/readers/graph.test.ts +87 -15
- package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
- package/packages/mcp-server/src/server.ts +131 -105
- package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
- package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
- package/packages/native/src/__tests__/ps.test.mjs +14 -8
- package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
- package/packages/native/src/__tests__/truncate.test.mjs +17 -2
- package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
- package/packages/pi-agent-core/src/agent.test.ts +96 -102
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.js +9 -2
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
- package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +43 -70
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +36 -11
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +44 -0
- package/packages/pi-ai/src/models/capability-patches.ts +10 -2
- package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
- package/packages/pi-ai/src/models/generated/openai.ts +17 -0
- package/packages/pi-ai/src/models.generated.test.ts +46 -73
- package/packages/pi-ai/src/models.test.ts +48 -11
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.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 +61 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.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 +18 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -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 +105 -13
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
- package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
- package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
- package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
- package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
- package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +14 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +19 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.js.map +1 -1
- package/packages/pi-tui/dist/editor-component.d.ts +2 -0
- package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/packages/pi-tui/dist/editor-component.js.map +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
- package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
- package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
- package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
- package/packages/pi-tui/src/components/editor.ts +22 -0
- package/packages/pi-tui/src/components/image.test.ts +10 -5
- package/packages/pi-tui/src/editor-component.ts +3 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/dist/rpc-client.test.js +101 -51
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/scripts/install.js +15 -1
- package/src/resources/extensions/browser-tools/capture.ts +12 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
- package/src/resources/extensions/gsd/auto/loop.ts +47 -0
- package/src/resources/extensions/gsd/auto/phases.ts +16 -20
- package/src/resources/extensions/gsd/auto/session.ts +0 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
- package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
- package/src/resources/extensions/gsd/auto-start.ts +54 -6
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
- package/src/resources/extensions/gsd/auto.ts +43 -22
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
- package/src/resources/extensions/gsd/component-loader.ts +598 -0
- package/src/resources/extensions/gsd/component-types.ts +362 -0
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/gate-registry.ts +2 -2
- package/src/resources/extensions/gsd/git-constants.ts +30 -1
- package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
- package/src/resources/extensions/gsd/git-service.ts +133 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +20 -5
- package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
- package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/session-lock.ts +20 -10
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state.ts +49 -44
- package/src/resources/extensions/gsd/sync-lock.ts +97 -39
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +94 -289
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -197
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
- package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
- package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -62
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -49
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +12 -61
- package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/types.ts +3 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
- package/src/resources/extensions/mcp-client/index.ts +3 -1
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
- package/src/resources/extensions/ollama/index.ts +5 -1
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
- package/src/resources/extensions/remote-questions/manager.ts +36 -4
- package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
- package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -144
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -75
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -130
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_ssgManifest.js +0 -0
|
@@ -33,6 +33,7 @@ const MCP_WORKFLOW_TOOL_SURFACE = new Set([
|
|
|
33
33
|
"gsd_journal_query",
|
|
34
34
|
"gsd_milestone_complete",
|
|
35
35
|
"gsd_milestone_generate_id",
|
|
36
|
+
"gsd_milestone_reopen",
|
|
36
37
|
"gsd_checkpoint_db",
|
|
37
38
|
"gsd_milestone_status",
|
|
38
39
|
"gsd_milestone_validate",
|
|
@@ -41,6 +42,9 @@ const MCP_WORKFLOW_TOOL_SURFACE = new Set([
|
|
|
41
42
|
"gsd_plan_slice",
|
|
42
43
|
"gsd_replan_slice",
|
|
43
44
|
"gsd_reassess_roadmap",
|
|
45
|
+
"gsd_reopen_milestone",
|
|
46
|
+
"gsd_reopen_slice",
|
|
47
|
+
"gsd_reopen_task",
|
|
44
48
|
"gsd_requirement_save",
|
|
45
49
|
"gsd_requirement_update",
|
|
46
50
|
"gsd_roadmap_reassess",
|
|
@@ -50,9 +54,11 @@ const MCP_WORKFLOW_TOOL_SURFACE = new Set([
|
|
|
50
54
|
"gsd_skip_slice",
|
|
51
55
|
"gsd_slice_replan",
|
|
52
56
|
"gsd_slice_complete",
|
|
57
|
+
"gsd_slice_reopen",
|
|
53
58
|
"gsd_summary_save",
|
|
54
59
|
"gsd_task_plan",
|
|
55
60
|
"gsd_task_complete",
|
|
61
|
+
"gsd_task_reopen",
|
|
56
62
|
"gsd_update_requirement",
|
|
57
63
|
"gsd_validate_milestone",
|
|
58
64
|
]);
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
nativeDiffNameStatus,
|
|
31
31
|
nativeDiffNumstat,
|
|
32
32
|
nativeGetCurrentBranch,
|
|
33
|
+
nativeIsAncestor,
|
|
33
34
|
nativeLogOneline,
|
|
34
35
|
nativeMergeSquash,
|
|
35
36
|
nativeWorktreeAdd,
|
|
@@ -227,6 +228,17 @@ export function createWorktree(basePath: string, name: string, opts: { branch?:
|
|
|
227
228
|
// otherwise fall back to the repo's detected main branch.
|
|
228
229
|
const startPoint = opts.startPoint ?? nativeDetectMainBranch(basePath);
|
|
229
230
|
|
|
231
|
+
// Reject early if startPoint resolves to an empty/invalid ref. On an
|
|
232
|
+
// unborn branch (zero-commit repo) nativeDetectMainBranch returns "",
|
|
233
|
+
// which would flow into `git worktree add ... ""` and crash with
|
|
234
|
+
// `fatal: not a valid object name`. (Issue #4980 HIGH-9)
|
|
235
|
+
if (!startPoint || startPoint.length === 0) {
|
|
236
|
+
throw new GSDError(
|
|
237
|
+
GSD_GIT_ERROR,
|
|
238
|
+
"Repository has no commits yet (unborn branch). Make an initial commit before creating worktrees.",
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
230
242
|
// Check if the branch already exists (leftover from a previous worktree)
|
|
231
243
|
const branchAlreadyExists = nativeBranchExists(basePath, branch);
|
|
232
244
|
|
|
@@ -249,6 +261,21 @@ export function createWorktree(basePath: string, name: string, opts: { branch?:
|
|
|
249
261
|
// from prior sessions that must not be reset.
|
|
250
262
|
nativeWorktreeAdd(basePath, wtPath, branch);
|
|
251
263
|
} else {
|
|
264
|
+
// Ancestry guard: refuse to force-reset a branch that has commits not
|
|
265
|
+
// reachable from startPoint. A crash-then-resume cycle that didn't
|
|
266
|
+
// write the resume file would silently orphan prior-session commits
|
|
267
|
+
// (recoverable from reflog for 90d, then gone — branch is also
|
|
268
|
+
// deleted at teardown). (Issue #4980 HIGH-3)
|
|
269
|
+
const branchIsAncestor = nativeIsAncestor(basePath, branch, startPoint);
|
|
270
|
+
if (!branchIsAncestor) {
|
|
271
|
+
throw new GSDError(
|
|
272
|
+
GSD_GIT_ERROR,
|
|
273
|
+
`Branch "${branch}" already exists with commits not reachable from "${startPoint}". ` +
|
|
274
|
+
`Refusing to force-reset — would orphan prior work. ` +
|
|
275
|
+
`If you intend to keep those commits, retry with reuseExistingBranch=true. ` +
|
|
276
|
+
`If you intend to discard, run \`git branch -D ${branch}\` manually first.`,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
252
279
|
// Reset the stale branch to the start point, then attach worktree to it
|
|
253
280
|
nativeBranchForceReset(basePath, branch, startPoint);
|
|
254
281
|
nativeWorktreeAdd(basePath, wtPath, branch);
|
|
@@ -504,17 +531,38 @@ export function removeWorktree(
|
|
|
504
531
|
(line: string) => line.startsWith("+") || line.startsWith("-"),
|
|
505
532
|
);
|
|
506
533
|
if (hasSubmoduleChanges) {
|
|
507
|
-
//
|
|
508
|
-
//
|
|
534
|
+
// Save submodule changes to a labeled rescue branch instead of the
|
|
535
|
+
// shared stash list. Stash is per-repo (not per-worktree), so an
|
|
536
|
+
// entry created here would appear in the user's main-tree stash
|
|
537
|
+
// list and reference paths that disappear after worktree removal.
|
|
538
|
+
// A branch persists in the shared .git refs after worktree removal
|
|
539
|
+
// and is discoverable via `git branch --list 'gsd/submodule-rescue/*'`.
|
|
540
|
+
// (Issue #4980 HIGH-11)
|
|
541
|
+
const rescueBranch = `gsd/submodule-rescue/${name}-${Date.now()}`;
|
|
509
542
|
try {
|
|
510
543
|
execFileSync(
|
|
511
|
-
"git", ["
|
|
544
|
+
"git", ["add", "-A"],
|
|
512
545
|
{ cwd: resolvedWtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
513
546
|
);
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
547
|
+
execFileSync(
|
|
548
|
+
"git", ["commit", "-m", `gsd: rescue submodule changes from worktree ${name}`, "--allow-empty"],
|
|
549
|
+
{ cwd: resolvedWtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
550
|
+
);
|
|
551
|
+
execFileSync(
|
|
552
|
+
"git", ["branch", rescueBranch, "HEAD"],
|
|
553
|
+
{ cwd: resolvedWtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
554
|
+
);
|
|
555
|
+
logWarning(
|
|
556
|
+
"reconcile",
|
|
557
|
+
`Saved uncommitted submodule changes to rescue branch ${rescueBranch}`,
|
|
558
|
+
{ worktree: name, path: resolvedWtPath, rescueBranch },
|
|
559
|
+
);
|
|
560
|
+
} catch (err) {
|
|
561
|
+
logWarning(
|
|
562
|
+
"reconcile",
|
|
563
|
+
`Submodule rescue branch creation failed — changes may be lost during force removal: ${err instanceof Error ? err.message : String(err)}`,
|
|
564
|
+
{ worktree: name, path: resolvedWtPath },
|
|
565
|
+
);
|
|
518
566
|
}
|
|
519
567
|
}
|
|
520
568
|
} catch (e) {
|
|
@@ -203,7 +203,9 @@ async function assertTrustedStdioServer(
|
|
|
203
203
|
return trustKey;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
// Exported for tests (see tests/server-name-spaces.test.ts).
|
|
207
|
+
// Production call sites treat this as module-private.
|
|
208
|
+
export function getServerConfig(name: string): McpServerConfig | undefined {
|
|
207
209
|
const trimmed = name.trim();
|
|
208
210
|
return readConfigs().find((s) =>
|
|
209
211
|
s.name === trimmed ||
|
|
@@ -1,55 +1,89 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Regression test for #3029 — mcp_discover fails for server names with spaces.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* 1. Exact match
|
|
4
|
+
* getServerConfig must handle:
|
|
5
|
+
* 1. Exact match
|
|
6
6
|
* 2. Names with leading/trailing whitespace (trimming)
|
|
7
7
|
* 3. Case-insensitive matching (e.g. "Langgraph code" vs "langgraph Code")
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* getOrConnect must use the canonical (config.name) as the cache key so that
|
|
10
|
+
* subsequent lookups with variant casing/whitespace hit the same connection.
|
|
11
|
+
*
|
|
12
|
+
* These are behaviour tests against the real exported getServerConfig — no
|
|
13
|
+
* source grep.
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
|
-
import test from "node:test";
|
|
16
|
+
import test, { before, after } from "node:test";
|
|
13
17
|
import assert from "node:assert/strict";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
18
|
+
import { writeFileSync, unlinkSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
import { mkdtempSync } from "node:fs";
|
|
21
|
+
import { tmpdir } from "node:os";
|
|
22
|
+
|
|
23
|
+
import { getServerConfig } from "../index.js";
|
|
24
|
+
|
|
25
|
+
// readConfigs() anchors to process.cwd() — run each test in a sandbox dir
|
|
26
|
+
// with a purpose-built .mcp.json so the extension reads our fixture, not
|
|
27
|
+
// whatever .mcp.json happens to live in the current working directory.
|
|
28
|
+
let sandboxDir: string;
|
|
29
|
+
let originalCwd: string;
|
|
30
|
+
|
|
31
|
+
before(() => {
|
|
32
|
+
originalCwd = process.cwd();
|
|
33
|
+
sandboxDir = mkdtempSync(join(tmpdir(), "mcp-name-spaces-"));
|
|
34
|
+
const mcpConfig = {
|
|
35
|
+
mcpServers: {
|
|
36
|
+
"Langgraph Code": {
|
|
37
|
+
command: "echo",
|
|
38
|
+
args: ["test"],
|
|
39
|
+
},
|
|
40
|
+
"other-server": {
|
|
41
|
+
url: "https://example.com",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
writeFileSync(join(sandboxDir, ".mcp.json"), JSON.stringify(mcpConfig), "utf-8");
|
|
46
|
+
process.chdir(sandboxDir);
|
|
47
|
+
});
|
|
17
48
|
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
after(() => {
|
|
50
|
+
process.chdir(originalCwd);
|
|
51
|
+
try {
|
|
52
|
+
rmSync(sandboxDir, { recursive: true, force: true });
|
|
53
|
+
} catch {
|
|
54
|
+
// Best-effort cleanup
|
|
55
|
+
}
|
|
56
|
+
});
|
|
20
57
|
|
|
21
|
-
|
|
58
|
+
test("#3029: getServerConfig finds exact match", () => {
|
|
59
|
+
const cfg = getServerConfig("Langgraph Code");
|
|
60
|
+
assert.ok(cfg, "exact name must resolve");
|
|
61
|
+
assert.equal(cfg?.name, "Langgraph Code");
|
|
62
|
+
});
|
|
22
63
|
|
|
23
64
|
test("#3029: getServerConfig trims whitespace from input name", () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
65
|
+
const cfg = getServerConfig(" Langgraph Code ");
|
|
66
|
+
assert.ok(cfg, "whitespace-padded name must resolve to the same server");
|
|
67
|
+
assert.equal(cfg?.name, "Langgraph Code");
|
|
28
68
|
});
|
|
29
69
|
|
|
30
70
|
test("#3029: getServerConfig performs case-insensitive matching", () => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
71
|
+
const cfg = getServerConfig("langgraph code");
|
|
72
|
+
assert.ok(cfg, "lower-cased name must resolve");
|
|
73
|
+
assert.equal(cfg?.name, "Langgraph Code");
|
|
74
|
+
|
|
75
|
+
const mixed = getServerConfig("LANGGRAPH CODE");
|
|
76
|
+
assert.ok(mixed, "upper-cased name must resolve");
|
|
77
|
+
assert.equal(mixed?.name, "Langgraph Code");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("#3029: getServerConfig combines trim + case-insensitive", () => {
|
|
81
|
+
const cfg = getServerConfig(" LANGGRAPH code ");
|
|
82
|
+
assert.ok(cfg, "padded + mixed-case must resolve");
|
|
83
|
+
assert.equal(cfg?.name, "Langgraph Code");
|
|
35
84
|
});
|
|
36
85
|
|
|
37
|
-
test("#3029:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// user's casing differs.
|
|
41
|
-
const getOrConnectMatch = source.match(
|
|
42
|
-
/async function getOrConnect\(name: string[\s\S]*?const existing = connections\.get\(/,
|
|
43
|
-
);
|
|
44
|
-
assert.ok(
|
|
45
|
-
getOrConnectMatch,
|
|
46
|
-
"getOrConnect function should exist",
|
|
47
|
-
);
|
|
48
|
-
// After the fix, getOrConnect should normalize the name via getServerConfig
|
|
49
|
-
// or use config.name as the canonical cache key.
|
|
50
|
-
assert.ok(
|
|
51
|
-
source.includes("connections.get(config.name") ||
|
|
52
|
-
source.includes("connections.set(config.name"),
|
|
53
|
-
"getOrConnect should use config.name (canonical) as the connections cache key",
|
|
54
|
-
);
|
|
86
|
+
test("#3029: getServerConfig returns undefined for unknown name", () => {
|
|
87
|
+
const cfg = getServerConfig("does-not-exist");
|
|
88
|
+
assert.equal(cfg, undefined);
|
|
55
89
|
});
|
|
@@ -45,8 +45,12 @@ let providerRegistered = false;
|
|
|
45
45
|
/**
|
|
46
46
|
* Probe Ollama and register discovered models.
|
|
47
47
|
* Safe to call multiple times — re-discovers and re-registers.
|
|
48
|
+
*
|
|
49
|
+
* Exported for tests (see ollama-auth-mode.test.ts, ollama-status-indicator.test.ts)
|
|
50
|
+
* so a fake HTTP endpoint can drive the registration/unregistration paths.
|
|
51
|
+
* Production callers always go through the session_start handler below.
|
|
48
52
|
*/
|
|
49
|
-
async function probeAndRegister(pi: ExtensionAPI): Promise<boolean> {
|
|
53
|
+
export async function probeAndRegister(pi: ExtensionAPI): Promise<boolean> {
|
|
50
54
|
const running = await client.isRunning();
|
|
51
55
|
if (!running) {
|
|
52
56
|
if (providerRegistered) {
|
|
@@ -1,20 +1,128 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Regression test for #3440: Ollama extension must register with
|
|
3
|
-
* authMode "apiKey" (not "none")
|
|
3
|
+
* authMode "apiKey" (not "none"), otherwise the core bails out because
|
|
4
|
+
* the provider has no streamSimple.
|
|
5
|
+
*
|
|
6
|
+
* Behaviour test: spin up a fake Ollama endpoint, point OLLAMA_HOST at
|
|
7
|
+
* it, and invoke probeAndRegister with a mock pi. Assert that
|
|
8
|
+
* registerProvider was called with authMode "apiKey".
|
|
4
9
|
*/
|
|
5
|
-
import { test } from "node:test";
|
|
10
|
+
import { test, before, after, beforeEach } from "node:test";
|
|
6
11
|
import assert from "node:assert/strict";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
import { createServer, type Server } from "node:http";
|
|
13
|
+
import type { AddressInfo } from "node:net";
|
|
14
|
+
|
|
15
|
+
import { probeAndRegister } from "./index.js";
|
|
16
|
+
|
|
17
|
+
type RegisterCall = [string, Record<string, unknown>];
|
|
18
|
+
|
|
19
|
+
function makeMockPi() {
|
|
20
|
+
const calls: { registerProvider: RegisterCall[]; unregisterProvider: string[] } = {
|
|
21
|
+
registerProvider: [],
|
|
22
|
+
unregisterProvider: [],
|
|
23
|
+
};
|
|
24
|
+
const pi = {
|
|
25
|
+
registerProvider(id: string, spec: Record<string, unknown>) {
|
|
26
|
+
calls.registerProvider.push([id, spec]);
|
|
27
|
+
},
|
|
28
|
+
unregisterProvider(id: string) {
|
|
29
|
+
calls.unregisterProvider.push(id);
|
|
30
|
+
},
|
|
31
|
+
} as unknown as Parameters<typeof probeAndRegister>[0];
|
|
32
|
+
return { pi, calls };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let server: Server;
|
|
36
|
+
let savedHost: string | undefined;
|
|
37
|
+
|
|
38
|
+
before(async () => {
|
|
39
|
+
// Fake Ollama endpoint that:
|
|
40
|
+
// GET / → 200 (isRunning probe)
|
|
41
|
+
// GET /api/tags → one model
|
|
42
|
+
// POST /api/show → minimal capability info
|
|
43
|
+
server = createServer((req, res) => {
|
|
44
|
+
if (req.method === "GET" && req.url === "/") {
|
|
45
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
46
|
+
res.end("Ollama is running");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (req.method === "GET" && req.url === "/api/tags") {
|
|
50
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
51
|
+
res.end(
|
|
52
|
+
JSON.stringify({
|
|
53
|
+
models: [
|
|
54
|
+
{
|
|
55
|
+
name: "llama3:latest",
|
|
56
|
+
modified_at: new Date().toISOString(),
|
|
57
|
+
size: 1_000_000,
|
|
58
|
+
digest: "abc",
|
|
59
|
+
details: {
|
|
60
|
+
parent_model: "",
|
|
61
|
+
format: "gguf",
|
|
62
|
+
family: "llama",
|
|
63
|
+
families: ["llama"],
|
|
64
|
+
parameter_size: "8B",
|
|
65
|
+
quantization_level: "Q4_0",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
}),
|
|
70
|
+
);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (req.method === "POST" && req.url === "/api/show") {
|
|
74
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
75
|
+
res.end(
|
|
76
|
+
JSON.stringify({
|
|
77
|
+
modelfile: "",
|
|
78
|
+
parameters: "",
|
|
79
|
+
template: "",
|
|
80
|
+
details: {
|
|
81
|
+
parent_model: "",
|
|
82
|
+
format: "gguf",
|
|
83
|
+
family: "llama",
|
|
84
|
+
families: ["llama"],
|
|
85
|
+
parameter_size: "8B",
|
|
86
|
+
quantization_level: "Q4_0",
|
|
87
|
+
},
|
|
88
|
+
model_info: { "llama.context_length": 8192 },
|
|
89
|
+
capabilities: [],
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
res.writeHead(404);
|
|
95
|
+
res.end();
|
|
96
|
+
});
|
|
97
|
+
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
98
|
+
const { port } = server.address() as AddressInfo;
|
|
99
|
+
savedHost = process.env.OLLAMA_HOST;
|
|
100
|
+
process.env.OLLAMA_HOST = `http://127.0.0.1:${port}`;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
after(async () => {
|
|
104
|
+
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
105
|
+
if (savedHost === undefined) delete process.env.OLLAMA_HOST;
|
|
106
|
+
else process.env.OLLAMA_HOST = savedHost;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
// Each test starts from a clean providerRegistered state in the module.
|
|
111
|
+
// probeAndRegister is idempotent — calling it is safe regardless.
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("Ollama registers with authMode apiKey, not none (#3440)", async () => {
|
|
115
|
+
const { pi, calls } = makeMockPi();
|
|
116
|
+
|
|
117
|
+
const found = await probeAndRegister(pi);
|
|
118
|
+
assert.equal(found, true, "probeAndRegister should return true when models are discovered");
|
|
119
|
+
|
|
120
|
+
assert.equal(calls.registerProvider.length, 1, "registerProvider should be called exactly once");
|
|
121
|
+
const [providerId, spec] = calls.registerProvider[0];
|
|
122
|
+
assert.equal(providerId, "ollama");
|
|
123
|
+
assert.equal(
|
|
124
|
+
spec.authMode,
|
|
125
|
+
"apiKey",
|
|
126
|
+
"authMode must be apiKey so the core doesn't require streamSimple for every model",
|
|
127
|
+
);
|
|
20
128
|
});
|
|
@@ -1,28 +1,215 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Regression test: don't show an Ollama footer status unless Ollama is
|
|
3
3
|
* actually usable (running with at least one discovered model).
|
|
4
|
+
*
|
|
5
|
+
* Behaviour tests:
|
|
6
|
+
* 1. probeAndRegister returns false when /api/tags returns no models
|
|
7
|
+
* (running-without-models should not be treated as available).
|
|
8
|
+
* 2. The session_start handler calls ctx.ui.setStatus("ollama", "Ollama")
|
|
9
|
+
* when probeAndRegister reports true, and setStatus("ollama", undefined)
|
|
10
|
+
* when it reports false — keeping the footer clean on unavailable Ollama.
|
|
4
11
|
*/
|
|
5
|
-
import { test } from "node:test";
|
|
12
|
+
import { test, before, after } from "node:test";
|
|
6
13
|
import assert from "node:assert/strict";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
import { createServer, type Server } from "node:http";
|
|
15
|
+
import type { AddressInfo } from "node:net";
|
|
16
|
+
|
|
17
|
+
import ollamaExtension, { probeAndRegister } from "./index.js";
|
|
18
|
+
|
|
19
|
+
type RegisterCall = [string, Record<string, unknown>];
|
|
20
|
+
|
|
21
|
+
function makeMockPi() {
|
|
22
|
+
const calls: {
|
|
23
|
+
registerProvider: RegisterCall[];
|
|
24
|
+
unregisterProvider: string[];
|
|
25
|
+
registerTool: unknown[];
|
|
26
|
+
onHandlers: Map<string, Array<(...args: unknown[]) => unknown>>;
|
|
27
|
+
} = {
|
|
28
|
+
registerProvider: [],
|
|
29
|
+
unregisterProvider: [],
|
|
30
|
+
registerTool: [],
|
|
31
|
+
onHandlers: new Map(),
|
|
32
|
+
};
|
|
33
|
+
const pi = {
|
|
34
|
+
registerProvider(id: string, spec: Record<string, unknown>) {
|
|
35
|
+
calls.registerProvider.push([id, spec]);
|
|
36
|
+
},
|
|
37
|
+
unregisterProvider(id: string) {
|
|
38
|
+
calls.unregisterProvider.push(id);
|
|
39
|
+
},
|
|
40
|
+
registerTool(tool: unknown) {
|
|
41
|
+
calls.registerTool.push(tool);
|
|
42
|
+
},
|
|
43
|
+
registerCommand() {
|
|
44
|
+
/* no-op */
|
|
45
|
+
},
|
|
46
|
+
on(event: string, handler: (...args: unknown[]) => unknown) {
|
|
47
|
+
if (!calls.onHandlers.has(event)) calls.onHandlers.set(event, []);
|
|
48
|
+
calls.onHandlers.get(event)!.push(handler);
|
|
49
|
+
},
|
|
50
|
+
} as unknown as Parameters<typeof probeAndRegister>[0];
|
|
51
|
+
return { pi, calls };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Server mode:
|
|
55
|
+
// "empty" → /api/tags returns { models: [] }
|
|
56
|
+
// "loaded" → /api/tags returns one model + /api/show with 8k context
|
|
57
|
+
let server: Server;
|
|
58
|
+
let serverMode: "empty" | "loaded" = "empty";
|
|
59
|
+
let savedHost: string | undefined;
|
|
60
|
+
|
|
61
|
+
before(async () => {
|
|
62
|
+
server = createServer((req, res) => {
|
|
63
|
+
if (req.method === "GET" && req.url === "/") {
|
|
64
|
+
res.writeHead(200);
|
|
65
|
+
res.end("Ollama is running");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (req.method === "GET" && req.url === "/api/tags") {
|
|
69
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
70
|
+
if (serverMode === "empty") {
|
|
71
|
+
res.end(JSON.stringify({ models: [] }));
|
|
72
|
+
} else {
|
|
73
|
+
res.end(
|
|
74
|
+
JSON.stringify({
|
|
75
|
+
models: [
|
|
76
|
+
{
|
|
77
|
+
name: "llama3:latest",
|
|
78
|
+
modified_at: new Date().toISOString(),
|
|
79
|
+
size: 1_000_000,
|
|
80
|
+
digest: "abc",
|
|
81
|
+
details: {
|
|
82
|
+
parent_model: "",
|
|
83
|
+
format: "gguf",
|
|
84
|
+
family: "llama",
|
|
85
|
+
families: ["llama"],
|
|
86
|
+
parameter_size: "8B",
|
|
87
|
+
quantization_level: "Q4_0",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (req.method === "POST" && req.url === "/api/show") {
|
|
97
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
98
|
+
res.end(
|
|
99
|
+
JSON.stringify({
|
|
100
|
+
modelfile: "",
|
|
101
|
+
parameters: "",
|
|
102
|
+
template: "",
|
|
103
|
+
details: {
|
|
104
|
+
parent_model: "",
|
|
105
|
+
format: "gguf",
|
|
106
|
+
family: "llama",
|
|
107
|
+
families: ["llama"],
|
|
108
|
+
parameter_size: "8B",
|
|
109
|
+
quantization_level: "Q4_0",
|
|
110
|
+
},
|
|
111
|
+
model_info: { "llama.context_length": 8192 },
|
|
112
|
+
capabilities: [],
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
res.writeHead(404);
|
|
118
|
+
res.end();
|
|
119
|
+
});
|
|
120
|
+
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
121
|
+
const { port } = server.address() as AddressInfo;
|
|
122
|
+
savedHost = process.env.OLLAMA_HOST;
|
|
123
|
+
process.env.OLLAMA_HOST = `http://127.0.0.1:${port}`;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
after(async () => {
|
|
127
|
+
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
128
|
+
if (savedHost === undefined) delete process.env.OLLAMA_HOST;
|
|
129
|
+
else process.env.OLLAMA_HOST = savedHost;
|
|
20
130
|
});
|
|
21
131
|
|
|
22
|
-
test("
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
132
|
+
test("probeAndRegister returns false when no Ollama models are discovered", async () => {
|
|
133
|
+
serverMode = "empty";
|
|
134
|
+
const { pi, calls } = makeMockPi();
|
|
135
|
+
const found = await probeAndRegister(pi);
|
|
136
|
+
assert.equal(found, false, "no models should be reported as unavailable");
|
|
137
|
+
assert.equal(
|
|
138
|
+
calls.registerProvider.length,
|
|
139
|
+
0,
|
|
140
|
+
"provider must not be registered when no models are discoverable",
|
|
27
141
|
);
|
|
28
142
|
});
|
|
143
|
+
|
|
144
|
+
test("probeAndRegister returns true when Ollama has at least one model", async () => {
|
|
145
|
+
serverMode = "loaded";
|
|
146
|
+
const { pi, calls } = makeMockPi();
|
|
147
|
+
const found = await probeAndRegister(pi);
|
|
148
|
+
assert.equal(found, true);
|
|
149
|
+
assert.equal(calls.registerProvider.length, 1);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("interactive session sets ollama status based on probeAndRegister result", async () => {
|
|
153
|
+
// Load case: status should be set to "Ollama".
|
|
154
|
+
{
|
|
155
|
+
serverMode = "loaded";
|
|
156
|
+
const { pi, calls } = makeMockPi();
|
|
157
|
+
ollamaExtension(pi);
|
|
158
|
+
const handlers = calls.onHandlers.get("session_start") ?? [];
|
|
159
|
+
assert.equal(handlers.length, 1, "extension registers one session_start handler");
|
|
160
|
+
|
|
161
|
+
const statusCalls: Array<[string, string | undefined]> = [];
|
|
162
|
+
const ctx = {
|
|
163
|
+
hasUI: true,
|
|
164
|
+
ui: {
|
|
165
|
+
setStatus: (slot: string, value: string | undefined) => {
|
|
166
|
+
statusCalls.push([slot, value]);
|
|
167
|
+
},
|
|
168
|
+
notify: () => {},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Fire session_start; wait a tick for the internal promise chain to resolve.
|
|
173
|
+
await handlers[0]({}, ctx);
|
|
174
|
+
// Give probeAndRegister + .then(setStatus) time to complete.
|
|
175
|
+
for (let i = 0; i < 50; i++) {
|
|
176
|
+
if (statusCalls.length > 0) break;
|
|
177
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
178
|
+
}
|
|
179
|
+
assert.deepEqual(
|
|
180
|
+
statusCalls,
|
|
181
|
+
[["ollama", "Ollama"]],
|
|
182
|
+
"status should be set to 'Ollama' when probe reports available",
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Unavailable case: status should be cleared (undefined).
|
|
187
|
+
{
|
|
188
|
+
serverMode = "empty";
|
|
189
|
+
const { pi, calls } = makeMockPi();
|
|
190
|
+
ollamaExtension(pi);
|
|
191
|
+
const handlers = calls.onHandlers.get("session_start") ?? [];
|
|
192
|
+
|
|
193
|
+
const statusCalls: Array<[string, string | undefined]> = [];
|
|
194
|
+
const ctx = {
|
|
195
|
+
hasUI: true,
|
|
196
|
+
ui: {
|
|
197
|
+
setStatus: (slot: string, value: string | undefined) => {
|
|
198
|
+
statusCalls.push([slot, value]);
|
|
199
|
+
},
|
|
200
|
+
notify: () => {},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
await handlers[0]({}, ctx);
|
|
205
|
+
for (let i = 0; i < 50; i++) {
|
|
206
|
+
if (statusCalls.length > 0) break;
|
|
207
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
208
|
+
}
|
|
209
|
+
assert.deepEqual(
|
|
210
|
+
statusCalls,
|
|
211
|
+
[["ollama", undefined]],
|
|
212
|
+
"status must be cleared (undefined) when probe reports unavailable",
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
});
|