gsd-pi 2.77.0-dev.1d17f366c → 2.77.0-dev.2daa994b6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/headless.js +25 -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/gsd/auto/phases.js +5 -18
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +37 -8
- package/dist/resources/extensions/gsd/auto-post-unit.js +79 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-start.js +75 -24
- package/dist/resources/extensions/gsd/auto.js +34 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -1
- 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/context-store.js +23 -7
- 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/forensics.js +106 -0
- package/dist/resources/extensions/gsd/gsd-db.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +2 -4
- 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/preferences-validation.js +23 -0
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +334 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +51 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
- package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
- 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 +17 -17
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- 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 +1 -3
- 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/workflow-tools.test.ts +80 -39
- 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/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 +29 -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/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 +39 -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/__tests__/tool-execution.test.js +36 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.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/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.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/__tests__/tool-execution.test.ts +49 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
- 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/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.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/image.test.ts +10 -5
- 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/tests/stream-adapter.test.ts +80 -72
- 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/phases.ts +6 -17
- package/src/resources/extensions/gsd/auto/session.ts +7 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +40 -8
- package/src/resources/extensions/gsd/auto-post-unit.ts +81 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-start.ts +97 -4
- package/src/resources/extensions/gsd/auto.ts +37 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -1
- 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/context-store.ts +25 -8
- 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/forensics.ts +118 -1
- package/src/resources/extensions/gsd/git-service.ts +16 -0
- package/src/resources/extensions/gsd/gsd-db.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +2 -4
- package/src/resources/extensions/gsd/journal.ts +11 -1
- 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/preferences-validation.ts +21 -0
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +25 -292
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -4
- 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/context-store.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
- 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 -56
- 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 +1 -1
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
- 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 -55
- 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 -48
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +22 -16
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
- 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/restore-tools-after-discuss.test.ts +6 -3
- 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/sidecar-queue.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- 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-cadence.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
- package/src/resources/extensions/gsd/tests/token-profile.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 +203 -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 -80
- 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/worktree-telemetry.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +492 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +53 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
- package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
- 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 -143
- 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 -74
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- 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 -125
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
- /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_ssgManifest.js +0 -0
|
@@ -1,57 +1,133 @@
|
|
|
1
|
-
|
|
1
|
+
// Regression test for #4243 — abort() must be called BEFORE
|
|
2
|
+
// _disconnectFromAgent() inside newSession() and switchSession() so that
|
|
3
|
+
// message_end/agent_end events (and the #4216 finalization code) fire
|
|
4
|
+
// before we unsubscribe from the event bus.
|
|
5
|
+
//
|
|
6
|
+
// Verified behaviourally: we construct a real AgentSession, wrap `abort`
|
|
7
|
+
// and `_disconnectFromAgent` with call-order recording, trigger each
|
|
8
|
+
// session-transition method, and assert the observed call order.
|
|
9
|
+
|
|
2
10
|
import assert from "node:assert/strict";
|
|
3
|
-
import {
|
|
11
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
4
13
|
import { join } from "node:path";
|
|
14
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
15
|
+
|
|
16
|
+
import { Agent } from "@gsd/pi-agent-core";
|
|
17
|
+
import { AgentSession } from "./agent-session.js";
|
|
18
|
+
import { AuthStorage } from "./auth-storage.js";
|
|
19
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
20
|
+
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
21
|
+
import { SessionManager } from "./session-manager.js";
|
|
22
|
+
import { SettingsManager } from "./settings-manager.js";
|
|
5
23
|
|
|
6
|
-
|
|
7
|
-
join(process.cwd(), "packages/pi-coding-agent/src/core/agent-session.ts"),
|
|
8
|
-
"utf-8",
|
|
9
|
-
);
|
|
24
|
+
let testDir: string;
|
|
10
25
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
async function createSession(opts: { persistSessions?: boolean } = {}): Promise<AgentSession> {
|
|
27
|
+
const agentDir = join(testDir, "agent-home");
|
|
28
|
+
const authStorage = AuthStorage.inMemory({});
|
|
29
|
+
const modelRegistry = new ModelRegistry(authStorage, join(agentDir, "models.json"));
|
|
30
|
+
const settingsManager = SettingsManager.inMemory();
|
|
31
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
32
|
+
cwd: testDir,
|
|
33
|
+
agentDir,
|
|
34
|
+
settingsManager,
|
|
35
|
+
noExtensions: true,
|
|
36
|
+
noPromptTemplates: true,
|
|
37
|
+
noThemes: true,
|
|
38
|
+
});
|
|
39
|
+
await resourceLoader.reload();
|
|
16
40
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
41
|
+
// switchSession() needs a sessionFile; in-memory manager returns undefined.
|
|
42
|
+
// Use file-backed manager when the test needs to resume.
|
|
43
|
+
const sessionManager = opts.persistSessions
|
|
44
|
+
? SessionManager.create(testDir, join(testDir, "sessions"))
|
|
45
|
+
: SessionManager.inMemory(testDir);
|
|
46
|
+
|
|
47
|
+
return new AgentSession({
|
|
48
|
+
agent: new Agent(),
|
|
49
|
+
sessionManager,
|
|
50
|
+
settingsManager,
|
|
51
|
+
cwd: testDir,
|
|
52
|
+
resourceLoader,
|
|
53
|
+
modelRegistry,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
20
56
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Wrap two methods on the same object so their call order is recorded.
|
|
59
|
+
* Returns the recording array — assertions use index lookups.
|
|
60
|
+
*/
|
|
61
|
+
function recordCallOrder<O extends object>(
|
|
62
|
+
target: O,
|
|
63
|
+
methods: Array<keyof O>,
|
|
64
|
+
): string[] {
|
|
65
|
+
const order: string[] = [];
|
|
66
|
+
for (const method of methods) {
|
|
67
|
+
const name = String(method);
|
|
68
|
+
const original = (target as any)[name] as (...args: unknown[]) => unknown;
|
|
69
|
+
if (typeof original !== "function") {
|
|
70
|
+
throw new Error(`recordCallOrder: ${name} is not a function on target`);
|
|
71
|
+
}
|
|
72
|
+
(target as any)[name] = function (this: O, ...args: unknown[]) {
|
|
73
|
+
order.push(name);
|
|
74
|
+
return original.apply(this, args);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return order;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
describe("#4243 — abort() must run before _disconnectFromAgent()", () => {
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
testDir = mkdtempSync(join(tmpdir(), "agent-session-abort-"));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
87
|
+
});
|
|
24
88
|
|
|
25
|
-
|
|
26
|
-
|
|
89
|
+
it("newSession() invokes abort() before _disconnectFromAgent()", async () => {
|
|
90
|
+
const session = await createSession();
|
|
91
|
+
const order = recordCallOrder(session as any, ["abort", "_disconnectFromAgent"]);
|
|
92
|
+
|
|
93
|
+
const ok = await session.newSession();
|
|
94
|
+
assert.equal(ok, true);
|
|
95
|
+
|
|
96
|
+
const abortIdx = order.indexOf("abort");
|
|
97
|
+
const disconnectIdx = order.indexOf("_disconnectFromAgent");
|
|
98
|
+
assert.ok(abortIdx >= 0, `newSession should call abort(); order=${order.join(",")}`);
|
|
99
|
+
assert.ok(
|
|
100
|
+
disconnectIdx >= 0,
|
|
101
|
+
`newSession should call _disconnectFromAgent(); order=${order.join(",")}`,
|
|
102
|
+
);
|
|
27
103
|
assert.ok(
|
|
28
104
|
abortIdx < disconnectIdx,
|
|
29
|
-
|
|
105
|
+
`abort() must run before _disconnectFromAgent(); order=${order.join(",")}`,
|
|
30
106
|
);
|
|
31
107
|
});
|
|
32
108
|
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// Find the switchSession method body
|
|
40
|
-
const switchStart = source.indexOf("async switchSession(sessionPath:");
|
|
41
|
-
assert.ok(switchStart >= 0, "should find switchSession method");
|
|
109
|
+
it("switchSession() invokes abort() before _disconnectFromAgent()", async () => {
|
|
110
|
+
const session = await createSession({ persistSessions: true });
|
|
111
|
+
// Seed a session file to switch to (switchSession reads from the session manager).
|
|
112
|
+
await session.newSession();
|
|
113
|
+
const sessionFile = session.sessionFile;
|
|
114
|
+
assert.ok(typeof sessionFile === "string" && sessionFile.length > 0, "need a session file to switch to");
|
|
42
115
|
|
|
43
|
-
|
|
44
|
-
const window = source.slice(switchStart, switchStart + 800);
|
|
116
|
+
const order = recordCallOrder(session as any, ["abort", "_disconnectFromAgent"]);
|
|
45
117
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const disconnectIdx = window.indexOf("this._disconnectFromAgent();");
|
|
118
|
+
const ok = await session.switchSession(sessionFile);
|
|
119
|
+
assert.equal(ok, true);
|
|
49
120
|
|
|
50
|
-
|
|
51
|
-
|
|
121
|
+
const abortIdx = order.indexOf("abort");
|
|
122
|
+
const disconnectIdx = order.indexOf("_disconnectFromAgent");
|
|
123
|
+
assert.ok(abortIdx >= 0, `switchSession should call abort(); order=${order.join(",")}`);
|
|
124
|
+
assert.ok(
|
|
125
|
+
disconnectIdx >= 0,
|
|
126
|
+
`switchSession should call _disconnectFromAgent(); order=${order.join(",")}`,
|
|
127
|
+
);
|
|
52
128
|
assert.ok(
|
|
53
129
|
abortIdx < disconnectIdx,
|
|
54
|
-
|
|
130
|
+
`abort() must run before _disconnectFromAgent() in switchSession; order=${order.join(",")}`,
|
|
55
131
|
);
|
|
56
132
|
});
|
|
57
133
|
});
|
|
@@ -1,21 +1,93 @@
|
|
|
1
|
-
|
|
1
|
+
// Regression test: explicit model switches must cancel any in-flight retry
|
|
2
|
+
// BEFORE applying the new model. Otherwise stale provider backoff errors
|
|
3
|
+
// from the previous model can continue to land after the switch.
|
|
4
|
+
//
|
|
5
|
+
// Verified behaviourally: construct a real AgentSession, wrap
|
|
6
|
+
// `_retryHandler.abortRetry` and `agent.setModel` to record call order,
|
|
7
|
+
// invoke setModel(), and assert the observed order.
|
|
8
|
+
|
|
2
9
|
import assert from "node:assert/strict";
|
|
3
|
-
import {
|
|
10
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
4
12
|
import { join } from "node:path";
|
|
13
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
14
|
+
|
|
15
|
+
import { Agent } from "@gsd/pi-agent-core";
|
|
16
|
+
import { getModel } from "@gsd/pi-ai";
|
|
17
|
+
import { AgentSession } from "./agent-session.js";
|
|
18
|
+
import { AuthStorage } from "./auth-storage.js";
|
|
19
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
20
|
+
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
21
|
+
import { SessionManager } from "./session-manager.js";
|
|
22
|
+
import { SettingsManager } from "./settings-manager.js";
|
|
23
|
+
|
|
24
|
+
let testDir: string;
|
|
25
|
+
|
|
26
|
+
async function createSession(): Promise<AgentSession> {
|
|
27
|
+
const agentDir = join(testDir, "agent-home");
|
|
28
|
+
const authStorage = AuthStorage.inMemory({});
|
|
29
|
+
// Seed a runtime anthropic API key so modelRegistry.isProviderRequestReady()
|
|
30
|
+
// returns true and setModel() doesn't throw on missing credentials.
|
|
31
|
+
authStorage.setRuntimeApiKey("anthropic", "sk-test-not-used");
|
|
32
|
+
const modelRegistry = new ModelRegistry(authStorage, join(agentDir, "models.json"));
|
|
33
|
+
const settingsManager = SettingsManager.inMemory();
|
|
34
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
35
|
+
cwd: testDir,
|
|
36
|
+
agentDir,
|
|
37
|
+
settingsManager,
|
|
38
|
+
noExtensions: true,
|
|
39
|
+
noPromptTemplates: true,
|
|
40
|
+
noThemes: true,
|
|
41
|
+
});
|
|
42
|
+
await resourceLoader.reload();
|
|
43
|
+
|
|
44
|
+
return new AgentSession({
|
|
45
|
+
agent: new Agent(),
|
|
46
|
+
sessionManager: SessionManager.inMemory(testDir),
|
|
47
|
+
settingsManager,
|
|
48
|
+
cwd: testDir,
|
|
49
|
+
resourceLoader,
|
|
50
|
+
modelRegistry,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe("AgentSession — explicit model switch cancels retry before applying new model", () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
testDir = mkdtempSync(join(tmpdir(), "agent-session-model-switch-"));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("setModel() calls _retryHandler.abortRetry() before agent.setModel()", async () => {
|
|
64
|
+
const session = await createSession();
|
|
65
|
+
|
|
66
|
+
const order: string[] = [];
|
|
67
|
+
const retryHandler = (session as any)._retryHandler;
|
|
68
|
+
const originalAbortRetry = retryHandler.abortRetry.bind(retryHandler);
|
|
69
|
+
retryHandler.abortRetry = () => {
|
|
70
|
+
order.push("abortRetry");
|
|
71
|
+
return originalAbortRetry();
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const agent = (session as any).agent;
|
|
75
|
+
const originalSetModel = agent.setModel.bind(agent);
|
|
76
|
+
agent.setModel = (model: unknown) => {
|
|
77
|
+
order.push("setModel");
|
|
78
|
+
return originalSetModel(model);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const newModel = getModel("anthropic", "claude-3-5-sonnet-20241022");
|
|
82
|
+
await session.setModel(newModel, { persist: false });
|
|
5
83
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
assert.ok(abortIdx >= 0, "_applyModelChange should cancel any in-flight retry");
|
|
16
|
-
assert.ok(setModelIdx >= 0, "_applyModelChange should set the new model");
|
|
17
|
-
assert.ok(
|
|
18
|
-
abortIdx < setModelIdx,
|
|
19
|
-
"retry cancellation must happen before applying the new model to prevent stale provider retries",
|
|
20
|
-
);
|
|
84
|
+
const abortIdx = order.indexOf("abortRetry");
|
|
85
|
+
const setIdx = order.indexOf("setModel");
|
|
86
|
+
assert.ok(abortIdx >= 0, `setModel should cancel in-flight retry; order=${order.join(",")}`);
|
|
87
|
+
assert.ok(setIdx >= 0, `setModel should call agent.setModel; order=${order.join(",")}`);
|
|
88
|
+
assert.ok(
|
|
89
|
+
abortIdx < setIdx,
|
|
90
|
+
`retry cancellation must happen before applying the new model; order=${order.join(",")}`,
|
|
91
|
+
);
|
|
92
|
+
});
|
|
21
93
|
});
|
|
@@ -1,64 +1,133 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Regression test for #3616: newSession() must restore the full tool set
|
|
2
|
+
// when cwd is unchanged.
|
|
3
|
+
//
|
|
4
|
+
// The bug: extensions may narrow the active tool list via setActiveTools()
|
|
5
|
+
// during a session. Without a refresh in the else branch of newSession(),
|
|
6
|
+
// the narrowed set persists into the next session — breaking auto-mode
|
|
7
|
+
// subagent sessions that expect a full tool palette.
|
|
8
|
+
//
|
|
9
|
+
// Verified behaviourally: construct an AgentSession, wrap _refreshToolRegistry
|
|
10
|
+
// to record its args, call newSession() with cwd unchanged, and assert that
|
|
11
|
+
// a refresh was requested with includeAllExtensionTools: true.
|
|
3
12
|
|
|
4
|
-
import test, { describe } from "node:test";
|
|
5
13
|
import assert from "node:assert/strict";
|
|
6
|
-
import {
|
|
14
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
7
16
|
import { join } from "node:path";
|
|
17
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
import { Agent } from "@gsd/pi-agent-core";
|
|
20
|
+
import { AgentSession } from "./agent-session.js";
|
|
21
|
+
import { AuthStorage } from "./auth-storage.js";
|
|
22
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
23
|
+
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
24
|
+
import { SessionManager } from "./session-manager.js";
|
|
25
|
+
import { SettingsManager } from "./settings-manager.js";
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
test("newSession() calls _refreshToolRegistry with includeAllExtensionTools when cwd is unchanged", () => {
|
|
16
|
-
// Find the newSession method
|
|
17
|
-
const newSessionStart = source.indexOf("async newSession(options?:");
|
|
18
|
-
assert.ok(newSessionStart >= 0, "should find newSession method");
|
|
27
|
+
let testDir: string;
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
async function createSession(): Promise<AgentSession> {
|
|
30
|
+
const agentDir = join(testDir, "agent-home");
|
|
31
|
+
const authStorage = AuthStorage.inMemory({});
|
|
32
|
+
const modelRegistry = new ModelRegistry(authStorage, join(agentDir, "models.json"));
|
|
33
|
+
const settingsManager = SettingsManager.inMemory();
|
|
34
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
35
|
+
cwd: testDir,
|
|
36
|
+
agentDir,
|
|
37
|
+
settingsManager,
|
|
38
|
+
noExtensions: true,
|
|
39
|
+
noPromptTemplates: true,
|
|
40
|
+
noThemes: true,
|
|
41
|
+
});
|
|
42
|
+
await resourceLoader.reload();
|
|
22
43
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
return new AgentSession({
|
|
45
|
+
agent: new Agent(),
|
|
46
|
+
sessionManager: SessionManager.inMemory(testDir),
|
|
47
|
+
settingsManager,
|
|
48
|
+
cwd: testDir,
|
|
49
|
+
resourceLoader,
|
|
50
|
+
modelRegistry,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe("#3616 — newSession() restores narrowed tool set when cwd unchanged", () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
testDir = mkdtempSync(join(tmpdir(), "agent-session-tool-refresh-"));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
61
|
+
});
|
|
28
62
|
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
63
|
+
it("calls _refreshToolRegistry with includeAllExtensionTools: true when cwd unchanged", async () => {
|
|
64
|
+
const session = await createSession();
|
|
65
|
+
// Pin _cwd so newSession()'s `process.cwd()` branch takes the
|
|
66
|
+
// cwd-unchanged path. The production code compares `this._cwd !==
|
|
67
|
+
// previousCwd`; we force equality by setting _cwd to current cwd.
|
|
68
|
+
(session as any)._cwd = process.cwd();
|
|
69
|
+
|
|
70
|
+
const refreshCalls: Array<{ includeAllExtensionTools?: boolean }> = [];
|
|
71
|
+
const originalRefresh = (session as any)._refreshToolRegistry.bind(session);
|
|
72
|
+
(session as any)._refreshToolRegistry = (options?: { includeAllExtensionTools?: boolean }) => {
|
|
73
|
+
refreshCalls.push(options ?? {});
|
|
74
|
+
return originalRefresh(options);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const ok = await session.newSession();
|
|
78
|
+
assert.equal(ok, true);
|
|
32
79
|
|
|
33
|
-
const elseBranch = methodBody.slice(elseIdx, elseIdx + 800);
|
|
34
80
|
assert.ok(
|
|
35
|
-
|
|
36
|
-
"
|
|
81
|
+
refreshCalls.length > 0,
|
|
82
|
+
"newSession() should invoke _refreshToolRegistry in the cwd-unchanged branch",
|
|
37
83
|
);
|
|
38
84
|
assert.ok(
|
|
39
|
-
|
|
40
|
-
|
|
85
|
+
refreshCalls.some((o) => o.includeAllExtensionTools === true),
|
|
86
|
+
`at least one _refreshToolRegistry call must pass includeAllExtensionTools: true; observed=${JSON.stringify(refreshCalls)}`,
|
|
41
87
|
);
|
|
42
88
|
});
|
|
43
89
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
90
|
+
it("agent.reset() does not clear _state.tools (tools persist across reset)", () => {
|
|
91
|
+
// Structural invariant protecting #3616: if reset() starts clearing
|
|
92
|
+
// tools, newSession()'s refresh becomes the only defense against loss.
|
|
93
|
+
// Assertion is behavioural — seed tools, call reset(), observe survival.
|
|
94
|
+
const agent = new Agent();
|
|
95
|
+
const tool = {
|
|
96
|
+
name: "test_tool",
|
|
97
|
+
description: "x",
|
|
98
|
+
schema: { type: "object", properties: {}, additionalProperties: false } as any,
|
|
99
|
+
execute: async () => ({ content: [] }),
|
|
100
|
+
};
|
|
101
|
+
(agent as any)._state.tools = [tool];
|
|
102
|
+
agent.reset();
|
|
103
|
+
assert.deepEqual(
|
|
104
|
+
(agent as any)._state.tools,
|
|
105
|
+
[tool],
|
|
106
|
+
"Agent.reset() must preserve _state.tools",
|
|
107
|
+
);
|
|
47
108
|
});
|
|
48
109
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// the
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
110
|
+
it("takes the cwd-changed branch (rebuilds runtime) when cwd differs", async () => {
|
|
111
|
+
const session = await createSession();
|
|
112
|
+
// Force the cwd-changed branch: set _cwd to something that won't equal process.cwd().
|
|
113
|
+
(session as any)._cwd = join(testDir, "some", "other", "cwd");
|
|
114
|
+
|
|
115
|
+
let buildRuntimeCalled = false;
|
|
116
|
+
let buildRuntimeIncludedAll = false;
|
|
117
|
+
const originalBuild = (session as any)._buildRuntime.bind(session);
|
|
118
|
+
(session as any)._buildRuntime = (options?: { includeAllExtensionTools?: boolean }) => {
|
|
119
|
+
buildRuntimeCalled = true;
|
|
120
|
+
if (options?.includeAllExtensionTools === true) buildRuntimeIncludedAll = true;
|
|
121
|
+
return originalBuild(options);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const ok = await session.newSession();
|
|
125
|
+
assert.equal(ok, true);
|
|
126
|
+
|
|
127
|
+
assert.ok(buildRuntimeCalled, "cwd-changed branch must rebuild the tool runtime");
|
|
59
128
|
assert.ok(
|
|
60
|
-
|
|
61
|
-
"
|
|
129
|
+
buildRuntimeIncludedAll,
|
|
130
|
+
"cwd-changed branch must rebuild with includeAllExtensionTools: true",
|
|
62
131
|
);
|
|
63
132
|
});
|
|
64
133
|
});
|
|
@@ -653,15 +653,72 @@ export function containsTypeScriptSyntax(source: string): boolean {
|
|
|
653
653
|
* are compiled once and reused across all extensions.
|
|
654
654
|
*/
|
|
655
655
|
let _extensionLoaderJiti: ReturnType<typeof createJiti> | null = null;
|
|
656
|
+
// Tracks every extension-module path that jiti has compiled through the shared
|
|
657
|
+
// singleton so resetExtensionLoaderCache() can also evict Node's global
|
|
658
|
+
// require.cache entries for those modules. jiti stores compiled modules under
|
|
659
|
+
// `nativeRequire.cache[filename]` when `moduleCache: true`, so a new singleton
|
|
660
|
+
// still returns the stale cached module on re-import without this eviction.
|
|
661
|
+
const _loadedExtensionPaths = new Set<string>();
|
|
662
|
+
const _extensionRequire = createRequire(import.meta.url);
|
|
656
663
|
|
|
657
664
|
/**
|
|
658
665
|
* Reset the shared jiti singleton so the next call to getExtensionLoaderJiti()
|
|
659
666
|
* creates a fresh instance. This prevents memory leaks in long-running daemon
|
|
660
667
|
* processes (every loaded module stays cached forever) and ensures stale modules
|
|
661
668
|
* are not returned when extension source changes on disk.
|
|
669
|
+
*
|
|
670
|
+
* #3616: resetting the singleton alone is insufficient — jiti stores compiled
|
|
671
|
+
* modules in Node's global require.cache when `moduleCache: true`, which is
|
|
672
|
+
* shared across singletons. We also evict cached entries for every extension
|
|
673
|
+
* path we've previously loaded so the next import recompiles from disk.
|
|
662
674
|
*/
|
|
663
675
|
export function resetExtensionLoaderCache(): void {
|
|
664
676
|
_extensionLoaderJiti = null;
|
|
677
|
+
// Build a set of exact cache keys we expect (raw path, resolved path,
|
|
678
|
+
// realpath) AND a set of (basename, containing-directory) pairs so we
|
|
679
|
+
// can also catch entries that jiti/Node wrote under a canonicalized
|
|
680
|
+
// form (Windows drive-letter case, separator swap, UNC prefix, symlink
|
|
681
|
+
// resolution). require.cache is shared across all createRequire
|
|
682
|
+
// instances for CJS, so iterating any instance's cache covers jiti's
|
|
683
|
+
// internal `nativeRequire.cache` writes.
|
|
684
|
+
const exact = new Set<string>();
|
|
685
|
+
const signatures = new Set<string>();
|
|
686
|
+
const makeSignature = (p: string): string => {
|
|
687
|
+
const normalized = p.replace(/\\/g, "/").toLowerCase();
|
|
688
|
+
const slash = normalized.lastIndexOf("/");
|
|
689
|
+
const base = slash >= 0 ? normalized.slice(slash + 1) : normalized;
|
|
690
|
+
// Use the trailing two path segments as the signature — unique
|
|
691
|
+
// enough to avoid collisions in typical filesystems while tolerating
|
|
692
|
+
// drive-letter / separator variations that differ in the prefix.
|
|
693
|
+
const parent = slash >= 0 ? normalized.slice(0, slash) : "";
|
|
694
|
+
const parentSlash = parent.lastIndexOf("/");
|
|
695
|
+
const parentSeg = parentSlash >= 0 ? parent.slice(parentSlash + 1) : parent;
|
|
696
|
+
return `${parentSeg}/${base}`;
|
|
697
|
+
};
|
|
698
|
+
for (const raw of _loadedExtensionPaths) {
|
|
699
|
+
exact.add(raw);
|
|
700
|
+
try {
|
|
701
|
+
exact.add(_extensionRequire.resolve(raw));
|
|
702
|
+
} catch {
|
|
703
|
+
// unresolvable — fall through; signature scan may still hit it
|
|
704
|
+
}
|
|
705
|
+
try {
|
|
706
|
+
exact.add(fs.realpathSync(raw));
|
|
707
|
+
} catch {
|
|
708
|
+
// file may have been deleted already; ignore
|
|
709
|
+
}
|
|
710
|
+
signatures.add(makeSignature(raw));
|
|
711
|
+
}
|
|
712
|
+
for (const key of Object.keys(_extensionRequire.cache)) {
|
|
713
|
+
if (exact.has(key) || signatures.has(makeSignature(key))) {
|
|
714
|
+
try {
|
|
715
|
+
delete _extensionRequire.cache[key];
|
|
716
|
+
} catch {
|
|
717
|
+
// require.cache is best-effort; ignore failures (e.g. frozen cache).
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
_loadedExtensionPaths.clear();
|
|
665
722
|
}
|
|
666
723
|
|
|
667
724
|
function getExtensionLoaderJiti() {
|
|
@@ -696,6 +753,7 @@ async function loadExtensionModule(extensionPath: string) {
|
|
|
696
753
|
const jiti = getExtensionLoaderJiti();
|
|
697
754
|
|
|
698
755
|
const module = await jiti.import(extensionPath, { default: true });
|
|
756
|
+
_loadedExtensionPaths.add(extensionPath);
|
|
699
757
|
const factory = module as ExtensionFactory;
|
|
700
758
|
return typeof factory !== "function" ? undefined : factory;
|
|
701
759
|
}
|
|
@@ -315,8 +315,19 @@ test("LSP integration: typescript-language-server", async (t) => {
|
|
|
315
315
|
textDocument: { uri: mathUri, languageId: "typescript", version: 1, text: mathContent },
|
|
316
316
|
});
|
|
317
317
|
|
|
318
|
-
//
|
|
319
|
-
|
|
318
|
+
// Poll for a published diagnostics notification on main.ts, which
|
|
319
|
+
// is the observable signal that TypeScript has finished indexing
|
|
320
|
+
// the opened file. Previous magic-sleep (3000ms) was too short on
|
|
321
|
+
// slow CI machines and wasteful on fast ones (#4798).
|
|
322
|
+
const INDEX_DEADLINE_MS = 15_000;
|
|
323
|
+
const indexDeadline = Date.now() + INDEX_DEADLINE_MS;
|
|
324
|
+
while (Date.now() < indexDeadline) {
|
|
325
|
+
const diags = lsp
|
|
326
|
+
.getNotifications("textDocument/publishDiagnostics")
|
|
327
|
+
.filter((n) => (n.params as { uri: string }).uri === mainUri);
|
|
328
|
+
if (diags.length > 0) break;
|
|
329
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
330
|
+
}
|
|
320
331
|
|
|
321
332
|
// ---- Hover ----
|
|
322
333
|
await t.test("hover on 'add' call", async () => {
|
|
@@ -381,8 +392,28 @@ test("LSP integration: typescript-language-server", async (t) => {
|
|
|
381
392
|
|
|
382
393
|
// ---- Diagnostics (published via notification) ----
|
|
383
394
|
await t.test("diagnostics for type error", async () => {
|
|
384
|
-
//
|
|
385
|
-
|
|
395
|
+
// Poll for the specific type-error diagnostic on main.ts
|
|
396
|
+
// instead of sleeping a fixed 2s. tsserver pushes diagnostics
|
|
397
|
+
// incrementally — we need to wait until at least one diag
|
|
398
|
+
// contains a type-error signal, not just any diag.
|
|
399
|
+
const DIAG_DEADLINE_MS = 10_000;
|
|
400
|
+
const diagDeadline = Date.now() + DIAG_DEADLINE_MS;
|
|
401
|
+
while (Date.now() < diagDeadline) {
|
|
402
|
+
const candidates = lsp
|
|
403
|
+
.getNotifications("textDocument/publishDiagnostics")
|
|
404
|
+
.filter((n) => (n.params as { uri: string }).uri === mainUri)
|
|
405
|
+
.flatMap(
|
|
406
|
+
(n) => (n.params as { diagnostics: Array<{ message: string }> }).diagnostics,
|
|
407
|
+
);
|
|
408
|
+
if (
|
|
409
|
+
candidates.some(
|
|
410
|
+
(d) => d.message.includes("not assignable") || d.message.includes("Type"),
|
|
411
|
+
)
|
|
412
|
+
) {
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
416
|
+
}
|
|
386
417
|
|
|
387
418
|
const diagNotifications = lsp.getNotifications("textDocument/publishDiagnostics");
|
|
388
419
|
const mainDiags = diagNotifications.filter(
|
|
@@ -39,6 +39,10 @@ function findModel(registry: ModelRegistry, provider: string, id: string): Model
|
|
|
39
39
|
return registry.getAvailable().find((m) => m.provider === provider && m.id === id);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function availableModelIds(registry: ModelRegistry): Set<string> {
|
|
43
|
+
return new Set(registry.getAvailable().map((model) => `${model.provider}/${model.id}`));
|
|
44
|
+
}
|
|
45
|
+
|
|
42
46
|
function makeModel(provider: string, id: string, api: string): Model<Api> {
|
|
43
47
|
return {
|
|
44
48
|
id,
|
|
@@ -93,6 +97,22 @@ function createStreamSpy(): {
|
|
|
93
97
|
// ─── Registration ─────────────────────────────────────────────────────────────
|
|
94
98
|
|
|
95
99
|
describe("ModelRegistry authMode — registration", () => {
|
|
100
|
+
it("includes GPT-5.5 in the authenticated all-models menu backing list", () => {
|
|
101
|
+
const registry = createInMemoryRegistry({
|
|
102
|
+
openai: { type: "api_key", key: "sk-test" },
|
|
103
|
+
"openai-codex": {
|
|
104
|
+
type: "oauth",
|
|
105
|
+
access: "codex-access",
|
|
106
|
+
refresh: "codex-refresh",
|
|
107
|
+
expires: Date.now() + 60_000,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const ids = availableModelIds(registry);
|
|
112
|
+
assert.ok(ids.has("openai/gpt-5.5"), "all-models menu backing list should include openai/gpt-5.5");
|
|
113
|
+
assert.ok(ids.has("openai-codex/gpt-5.5"), "all-models menu backing list should include openai-codex/gpt-5.5");
|
|
114
|
+
});
|
|
115
|
+
|
|
96
116
|
it("registers externalCli provider with streamSimple and without apiKey/oauth", () => {
|
|
97
117
|
const registry = createRegistry();
|
|
98
118
|
const spy = createStreamSpy();
|