@kenkaiiii/ggcoder 5.49.4 → 5.49.6
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/app-sidecar.js +3 -1
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/lsp/edit-telemetry.d.ts +27 -0
- package/dist/core/lsp/edit-telemetry.d.ts.map +1 -0
- package/dist/core/lsp/edit-telemetry.js +50 -0
- package/dist/core/lsp/edit-telemetry.js.map +1 -0
- package/dist/core/lsp/manager.d.ts +24 -1
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +53 -2
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/mcp/content.d.ts +5 -0
- package/dist/core/mcp/content.d.ts.map +1 -1
- package/dist/core/mcp/content.js +20 -2
- package/dist/core/mcp/content.js.map +1 -1
- package/dist/core/sandbox.d.ts +17 -1
- package/dist/core/sandbox.d.ts.map +1 -1
- package/dist/core/sandbox.js +74 -8
- package/dist/core/sandbox.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +10 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/tools/edit.d.ts +2 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +21 -5
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +28 -4
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.d.ts +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +1 -1
- package/dist/tools/write.js.map +1 -1
- package/dist/ui/utils/text-utils.d.ts +0 -6
- package/dist/ui/utils/text-utils.d.ts.map +1 -1
- package/dist/ui/utils/text-utils.js +8 -3
- package/dist/ui/utils/text-utils.js.map +1 -1
- package/dist/utils/text.d.ts +41 -0
- package/dist/utils/text.d.ts.map +1 -1
- package/dist/utils/text.js +46 -0
- package/dist/utils/text.js.map +1 -1
- package/package.json +6 -10
- package/dist/app-sidecar-auth-broadcast.test.d.ts +0 -2
- package/dist/app-sidecar-auth-broadcast.test.d.ts.map +0 -1
- package/dist/app-sidecar-auth-broadcast.test.js +0 -383
- package/dist/app-sidecar-auth-broadcast.test.js.map +0 -1
- package/dist/app-sidecar-sessions.test.d.ts +0 -2
- package/dist/app-sidecar-sessions.test.d.ts.map +0 -1
- package/dist/app-sidecar-sessions.test.js +0 -178
- package/dist/app-sidecar-sessions.test.js.map +0 -1
- package/dist/chat-agents/general.test.d.ts +0 -2
- package/dist/chat-agents/general.test.d.ts.map +0 -1
- package/dist/chat-agents/general.test.js +0 -53
- package/dist/chat-agents/general.test.js.map +0 -1
- package/dist/chat-agents/jiwa.test.d.ts +0 -2
- package/dist/chat-agents/jiwa.test.d.ts.map +0 -1
- package/dist/chat-agents/jiwa.test.js +0 -66
- package/dist/chat-agents/jiwa.test.js.map +0 -1
- package/dist/chat-agents/memory.test.d.ts +0 -2
- package/dist/chat-agents/memory.test.d.ts.map +0 -1
- package/dist/chat-agents/memory.test.js +0 -165
- package/dist/chat-agents/memory.test.js.map +0 -1
- package/dist/chat-agents/specialists.test.d.ts +0 -2
- package/dist/chat-agents/specialists.test.d.ts.map +0 -1
- package/dist/chat-agents/specialists.test.js +0 -98
- package/dist/chat-agents/specialists.test.js.map +0 -1
- package/dist/cli/command-routing.test.d.ts +0 -2
- package/dist/cli/command-routing.test.d.ts.map +0 -1
- package/dist/cli/command-routing.test.js +0 -60
- package/dist/cli/command-routing.test.js.map +0 -1
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -148
- package/dist/config.test.js.map +0 -1
- package/dist/core/agent-mcp-passthrough.test.d.ts +0 -2
- package/dist/core/agent-mcp-passthrough.test.d.ts.map +0 -1
- package/dist/core/agent-mcp-passthrough.test.js +0 -61
- package/dist/core/agent-mcp-passthrough.test.js.map +0 -1
- package/dist/core/agent-notifications.test.d.ts +0 -2
- package/dist/core/agent-notifications.test.d.ts.map +0 -1
- package/dist/core/agent-notifications.test.js +0 -97
- package/dist/core/agent-notifications.test.js.map +0 -1
- package/dist/core/agent-session-add-dir.test.d.ts +0 -2
- package/dist/core/agent-session-add-dir.test.d.ts.map +0 -1
- package/dist/core/agent-session-add-dir.test.js +0 -110
- package/dist/core/agent-session-add-dir.test.js.map +0 -1
- package/dist/core/agent-session-checkpoint-flush.test.d.ts +0 -2
- package/dist/core/agent-session-checkpoint-flush.test.d.ts.map +0 -1
- package/dist/core/agent-session-checkpoint-flush.test.js +0 -201
- package/dist/core/agent-session-checkpoint-flush.test.js.map +0 -1
- package/dist/core/agent-session-compaction.test.d.ts +0 -2
- package/dist/core/agent-session-compaction.test.d.ts.map +0 -1
- package/dist/core/agent-session-compaction.test.js +0 -1157
- package/dist/core/agent-session-compaction.test.js.map +0 -1
- package/dist/core/agent-session-crash-durability.test.d.ts +0 -2
- package/dist/core/agent-session-crash-durability.test.d.ts.map +0 -1
- package/dist/core/agent-session-crash-durability.test.js +0 -102
- package/dist/core/agent-session-crash-durability.test.js.map +0 -1
- package/dist/core/agent-session-marker-anchors.test.d.ts +0 -2
- package/dist/core/agent-session-marker-anchors.test.d.ts.map +0 -1
- package/dist/core/agent-session-marker-anchors.test.js +0 -326
- package/dist/core/agent-session-marker-anchors.test.js.map +0 -1
- package/dist/core/agent-session-memory-tail.test.d.ts +0 -2
- package/dist/core/agent-session-memory-tail.test.d.ts.map +0 -1
- package/dist/core/agent-session-memory-tail.test.js +0 -119
- package/dist/core/agent-session-memory-tail.test.js.map +0 -1
- package/dist/core/agent-session-model-switch.test.d.ts +0 -2
- package/dist/core/agent-session-model-switch.test.d.ts.map +0 -1
- package/dist/core/agent-session-model-switch.test.js +0 -161
- package/dist/core/agent-session-model-switch.test.js.map +0 -1
- package/dist/core/agent-session-notifications.test.d.ts +0 -2
- package/dist/core/agent-session-notifications.test.d.ts.map +0 -1
- package/dist/core/agent-session-notifications.test.js +0 -114
- package/dist/core/agent-session-notifications.test.js.map +0 -1
- package/dist/core/agent-session-pre-init-arming.test.d.ts +0 -2
- package/dist/core/agent-session-pre-init-arming.test.d.ts.map +0 -1
- package/dist/core/agent-session-pre-init-arming.test.js +0 -60
- package/dist/core/agent-session-pre-init-arming.test.js.map +0 -1
- package/dist/core/agent-session-process-gate.test.d.ts +0 -2
- package/dist/core/agent-session-process-gate.test.d.ts.map +0 -1
- package/dist/core/agent-session-process-gate.test.js +0 -98
- package/dist/core/agent-session-process-gate.test.js.map +0 -1
- package/dist/core/agent-session-queue.test.d.ts +0 -2
- package/dist/core/agent-session-queue.test.d.ts.map +0 -1
- package/dist/core/agent-session-queue.test.js +0 -184
- package/dist/core/agent-session-queue.test.js.map +0 -1
- package/dist/core/agent-session-review-coverage.test.d.ts +0 -2
- package/dist/core/agent-session-review-coverage.test.d.ts.map +0 -1
- package/dist/core/agent-session-review-coverage.test.js +0 -191
- package/dist/core/agent-session-review-coverage.test.js.map +0 -1
- package/dist/core/agent-session-slash-restore.test.d.ts +0 -2
- package/dist/core/agent-session-slash-restore.test.d.ts.map +0 -1
- package/dist/core/agent-session-slash-restore.test.js +0 -121
- package/dist/core/agent-session-slash-restore.test.js.map +0 -1
- package/dist/core/agent-session-subagent-policy.test.d.ts +0 -2
- package/dist/core/agent-session-subagent-policy.test.d.ts.map +0 -1
- package/dist/core/agent-session-subagent-policy.test.js +0 -40
- package/dist/core/agent-session-subagent-policy.test.js.map +0 -1
- package/dist/core/agent-session-tool-result-policy.test.d.ts +0 -2
- package/dist/core/agent-session-tool-result-policy.test.d.ts.map +0 -1
- package/dist/core/agent-session-tool-result-policy.test.js +0 -25
- package/dist/core/agent-session-tool-result-policy.test.js.map +0 -1
- package/dist/core/agent-session-tool-tiers.test.d.ts +0 -2
- package/dist/core/agent-session-tool-tiers.test.d.ts.map +0 -1
- package/dist/core/agent-session-tool-tiers.test.js +0 -138
- package/dist/core/agent-session-tool-tiers.test.js.map +0 -1
- package/dist/core/agent-session-verification-flow.test.d.ts +0 -2
- package/dist/core/agent-session-verification-flow.test.d.ts.map +0 -1
- package/dist/core/agent-session-verification-flow.test.js +0 -125
- package/dist/core/agent-session-verification-flow.test.js.map +0 -1
- package/dist/core/agent-session-verification-gate.test.d.ts +0 -2
- package/dist/core/agent-session-verification-gate.test.d.ts.map +0 -1
- package/dist/core/agent-session-verification-gate.test.js +0 -137
- package/dist/core/agent-session-verification-gate.test.js.map +0 -1
- package/dist/core/agent-tools-allowlist.test.d.ts +0 -2
- package/dist/core/agent-tools-allowlist.test.d.ts.map +0 -1
- package/dist/core/agent-tools-allowlist.test.js +0 -74
- package/dist/core/agent-tools-allowlist.test.js.map +0 -1
- package/dist/core/agents.test.d.ts +0 -2
- package/dist/core/agents.test.d.ts.map +0 -1
- package/dist/core/agents.test.js +0 -147
- package/dist/core/agents.test.js.map +0 -1
- package/dist/core/auto-update.test.d.ts +0 -2
- package/dist/core/auto-update.test.d.ts.map +0 -1
- package/dist/core/auto-update.test.js +0 -204
- package/dist/core/auto-update.test.js.map +0 -1
- package/dist/core/autopilot-cycle.test.d.ts +0 -2
- package/dist/core/autopilot-cycle.test.d.ts.map +0 -1
- package/dist/core/autopilot-cycle.test.js +0 -375
- package/dist/core/autopilot-cycle.test.js.map +0 -1
- package/dist/core/autopilot-gate.test.d.ts +0 -2
- package/dist/core/autopilot-gate.test.d.ts.map +0 -1
- package/dist/core/autopilot-gate.test.js +0 -298
- package/dist/core/autopilot-gate.test.js.map +0 -1
- package/dist/core/autopilot-verdict.test.d.ts +0 -2
- package/dist/core/autopilot-verdict.test.d.ts.map +0 -1
- package/dist/core/autopilot-verdict.test.js +0 -153
- package/dist/core/autopilot-verdict.test.js.map +0 -1
- package/dist/core/checkpoint-store.test.d.ts +0 -2
- package/dist/core/checkpoint-store.test.d.ts.map +0 -1
- package/dist/core/checkpoint-store.test.js +0 -111
- package/dist/core/checkpoint-store.test.js.map +0 -1
- package/dist/core/code-retrieval-chunkers.test.d.ts +0 -2
- package/dist/core/code-retrieval-chunkers.test.d.ts.map +0 -1
- package/dist/core/code-retrieval-chunkers.test.js +0 -203
- package/dist/core/code-retrieval-chunkers.test.js.map +0 -1
- package/dist/core/compaction/active-context.test.d.ts +0 -2
- package/dist/core/compaction/active-context.test.d.ts.map +0 -1
- package/dist/core/compaction/active-context.test.js +0 -57
- package/dist/core/compaction/active-context.test.js.map +0 -1
- package/dist/core/compaction/compactor.test.d.ts +0 -2
- package/dist/core/compaction/compactor.test.d.ts.map +0 -1
- package/dist/core/compaction/compactor.test.js +0 -1072
- package/dist/core/compaction/compactor.test.js.map +0 -1
- package/dist/core/compaction/policy.test.d.ts +0 -2
- package/dist/core/compaction/policy.test.d.ts.map +0 -1
- package/dist/core/compaction/policy.test.js +0 -35
- package/dist/core/compaction/policy.test.js.map +0 -1
- package/dist/core/compaction/query-aware-selector.test.d.ts +0 -2
- package/dist/core/compaction/query-aware-selector.test.d.ts.map +0 -1
- package/dist/core/compaction/query-aware-selector.test.js +0 -96
- package/dist/core/compaction/query-aware-selector.test.js.map +0 -1
- package/dist/core/compaction/token-estimator.test.d.ts +0 -2
- package/dist/core/compaction/token-estimator.test.d.ts.map +0 -1
- package/dist/core/compaction/token-estimator.test.js +0 -283
- package/dist/core/compaction/token-estimator.test.js.map +0 -1
- package/dist/core/compaction/tool-result-pruner.test.d.ts +0 -2
- package/dist/core/compaction/tool-result-pruner.test.d.ts.map +0 -1
- package/dist/core/compaction/tool-result-pruner.test.js +0 -320
- package/dist/core/compaction/tool-result-pruner.test.js.map +0 -1
- package/dist/core/context-limits.test.d.ts +0 -2
- package/dist/core/context-limits.test.d.ts.map +0 -1
- package/dist/core/context-limits.test.js +0 -55
- package/dist/core/context-limits.test.js.map +0 -1
- package/dist/core/continue-replay-inventory.test.d.ts +0 -2
- package/dist/core/continue-replay-inventory.test.d.ts.map +0 -1
- package/dist/core/continue-replay-inventory.test.js +0 -42
- package/dist/core/continue-replay-inventory.test.js.map +0 -1
- package/dist/core/encode-cwd.test.d.ts +0 -2
- package/dist/core/encode-cwd.test.d.ts.map +0 -1
- package/dist/core/encode-cwd.test.js +0 -80
- package/dist/core/encode-cwd.test.js.map +0 -1
- package/dist/core/event-bus.test.d.ts +0 -2
- package/dist/core/event-bus.test.d.ts.map +0 -1
- package/dist/core/event-bus.test.js +0 -33
- package/dist/core/event-bus.test.js.map +0 -1
- package/dist/core/extensions/plugin-bundles.test.d.ts +0 -2
- package/dist/core/extensions/plugin-bundles.test.d.ts.map +0 -1
- package/dist/core/extensions/plugin-bundles.test.js +0 -110
- package/dist/core/extensions/plugin-bundles.test.js.map +0 -1
- package/dist/core/foreign-session-import.test.d.ts +0 -2
- package/dist/core/foreign-session-import.test.d.ts.map +0 -1
- package/dist/core/foreign-session-import.test.js +0 -220
- package/dist/core/foreign-session-import.test.js.map +0 -1
- package/dist/core/hashline-edit-benchmark.test.d.ts +0 -2
- package/dist/core/hashline-edit-benchmark.test.d.ts.map +0 -1
- package/dist/core/hashline-edit-benchmark.test.js +0 -190
- package/dist/core/hashline-edit-benchmark.test.js.map +0 -1
- package/dist/core/ideal-review.test.d.ts +0 -2
- package/dist/core/ideal-review.test.d.ts.map +0 -1
- package/dist/core/ideal-review.test.js +0 -242
- package/dist/core/ideal-review.test.js.map +0 -1
- package/dist/core/input-normalization.test.d.ts +0 -2
- package/dist/core/input-normalization.test.d.ts.map +0 -1
- package/dist/core/input-normalization.test.js +0 -75
- package/dist/core/input-normalization.test.js.map +0 -1
- package/dist/core/json-mode-flag-parity.test.d.ts +0 -2
- package/dist/core/json-mode-flag-parity.test.d.ts.map +0 -1
- package/dist/core/json-mode-flag-parity.test.js +0 -66
- package/dist/core/json-mode-flag-parity.test.js.map +0 -1
- package/dist/core/ken-context.test.d.ts +0 -2
- package/dist/core/ken-context.test.d.ts.map +0 -1
- package/dist/core/ken-context.test.js +0 -342
- package/dist/core/ken-context.test.js.map +0 -1
- package/dist/core/ken-model.test.d.ts +0 -2
- package/dist/core/ken-model.test.d.ts.map +0 -1
- package/dist/core/ken-model.test.js +0 -51
- package/dist/core/ken-model.test.js.map +0 -1
- package/dist/core/ken-prompt.test.d.ts +0 -2
- package/dist/core/ken-prompt.test.d.ts.map +0 -1
- package/dist/core/ken-prompt.test.js +0 -191
- package/dist/core/ken-prompt.test.js.map +0 -1
- package/dist/core/language-detector.test.d.ts +0 -2
- package/dist/core/language-detector.test.d.ts.map +0 -1
- package/dist/core/language-detector.test.js +0 -109
- package/dist/core/language-detector.test.js.map +0 -1
- package/dist/core/local-endpoint-store.test.d.ts +0 -2
- package/dist/core/local-endpoint-store.test.d.ts.map +0 -1
- package/dist/core/local-endpoint-store.test.js +0 -123
- package/dist/core/local-endpoint-store.test.js.map +0 -1
- package/dist/core/loop-breaker.test.d.ts +0 -2
- package/dist/core/loop-breaker.test.d.ts.map +0 -1
- package/dist/core/loop-breaker.test.js +0 -238
- package/dist/core/loop-breaker.test.js.map +0 -1
- package/dist/core/lsp/client-navigation.test.d.ts +0 -2
- package/dist/core/lsp/client-navigation.test.d.ts.map +0 -1
- package/dist/core/lsp/client-navigation.test.js +0 -135
- package/dist/core/lsp/client-navigation.test.js.map +0 -1
- package/dist/core/lsp/format.test.d.ts +0 -2
- package/dist/core/lsp/format.test.d.ts.map +0 -1
- package/dist/core/lsp/format.test.js +0 -56
- package/dist/core/lsp/format.test.js.map +0 -1
- package/dist/core/lsp/integration.test.d.ts +0 -2
- package/dist/core/lsp/integration.test.d.ts.map +0 -1
- package/dist/core/lsp/integration.test.js +0 -60
- package/dist/core/lsp/integration.test.js.map +0 -1
- package/dist/core/lsp/jsonrpc.test.d.ts +0 -2
- package/dist/core/lsp/jsonrpc.test.d.ts.map +0 -1
- package/dist/core/lsp/jsonrpc.test.js +0 -127
- package/dist/core/lsp/jsonrpc.test.js.map +0 -1
- package/dist/core/lsp/manager-navigation.test.d.ts +0 -2
- package/dist/core/lsp/manager-navigation.test.d.ts.map +0 -1
- package/dist/core/lsp/manager-navigation.test.js +0 -121
- package/dist/core/lsp/manager-navigation.test.js.map +0 -1
- package/dist/core/lsp/manager.test.d.ts +0 -2
- package/dist/core/lsp/manager.test.d.ts.map +0 -1
- package/dist/core/lsp/manager.test.js +0 -220
- package/dist/core/lsp/manager.test.js.map +0 -1
- package/dist/core/lsp/pool.test.d.ts +0 -2
- package/dist/core/lsp/pool.test.d.ts.map +0 -1
- package/dist/core/lsp/pool.test.js +0 -286
- package/dist/core/lsp/pool.test.js.map +0 -1
- package/dist/core/lsp/servers.test.d.ts +0 -2
- package/dist/core/lsp/servers.test.d.ts.map +0 -1
- package/dist/core/lsp/servers.test.js +0 -67
- package/dist/core/lsp/servers.test.js.map +0 -1
- package/dist/core/lsp/uri.test.d.ts +0 -2
- package/dist/core/lsp/uri.test.d.ts.map +0 -1
- package/dist/core/lsp/uri.test.js +0 -56
- package/dist/core/lsp/uri.test.js.map +0 -1
- package/dist/core/lsp/windows.test.d.ts +0 -2
- package/dist/core/lsp/windows.test.d.ts.map +0 -1
- package/dist/core/lsp/windows.test.js +0 -239
- package/dist/core/lsp/windows.test.js.map +0 -1
- package/dist/core/mcp/catalog-cache.test.d.ts +0 -2
- package/dist/core/mcp/catalog-cache.test.d.ts.map +0 -1
- package/dist/core/mcp/catalog-cache.test.js +0 -99
- package/dist/core/mcp/catalog-cache.test.js.map +0 -1
- package/dist/core/mcp/client-session-recovery.test.d.ts +0 -2
- package/dist/core/mcp/client-session-recovery.test.d.ts.map +0 -1
- package/dist/core/mcp/client-session-recovery.test.js +0 -231
- package/dist/core/mcp/client-session-recovery.test.js.map +0 -1
- package/dist/core/mcp/content.test.d.ts +0 -2
- package/dist/core/mcp/content.test.d.ts.map +0 -1
- package/dist/core/mcp/content.test.js +0 -135
- package/dist/core/mcp/content.test.js.map +0 -1
- package/dist/core/mcp/defaults.test.d.ts +0 -2
- package/dist/core/mcp/defaults.test.d.ts.map +0 -1
- package/dist/core/mcp/defaults.test.js +0 -60
- package/dist/core/mcp/defaults.test.js.map +0 -1
- package/dist/core/mcp/elicitation.test.d.ts +0 -2
- package/dist/core/mcp/elicitation.test.d.ts.map +0 -1
- package/dist/core/mcp/elicitation.test.js +0 -158
- package/dist/core/mcp/elicitation.test.js.map +0 -1
- package/dist/core/mcp/legacy-negotiation.test.d.ts +0 -2
- package/dist/core/mcp/legacy-negotiation.test.d.ts.map +0 -1
- package/dist/core/mcp/legacy-negotiation.test.js +0 -80
- package/dist/core/mcp/legacy-negotiation.test.js.map +0 -1
- package/dist/core/mcp/loopback.test.d.ts +0 -2
- package/dist/core/mcp/loopback.test.d.ts.map +0 -1
- package/dist/core/mcp/loopback.test.js +0 -87
- package/dist/core/mcp/loopback.test.js.map +0 -1
- package/dist/core/mcp/oauth-store.test.d.ts +0 -2
- package/dist/core/mcp/oauth-store.test.d.ts.map +0 -1
- package/dist/core/mcp/oauth-store.test.js +0 -94
- package/dist/core/mcp/oauth-store.test.js.map +0 -1
- package/dist/core/mcp/parse-add-command.test.d.ts +0 -2
- package/dist/core/mcp/parse-add-command.test.d.ts.map +0 -1
- package/dist/core/mcp/parse-add-command.test.js +0 -81
- package/dist/core/mcp/parse-add-command.test.js.map +0 -1
- package/dist/core/mcp/resolve-stdio.test.d.ts +0 -2
- package/dist/core/mcp/resolve-stdio.test.d.ts.map +0 -1
- package/dist/core/mcp/resolve-stdio.test.js +0 -239
- package/dist/core/mcp/resolve-stdio.test.js.map +0 -1
- package/dist/core/mcp/session-elicitation-wiring.test.d.ts +0 -2
- package/dist/core/mcp/session-elicitation-wiring.test.d.ts.map +0 -1
- package/dist/core/mcp/session-elicitation-wiring.test.js +0 -138
- package/dist/core/mcp/session-elicitation-wiring.test.js.map +0 -1
- package/dist/core/mcp/shared-pool.test.d.ts +0 -2
- package/dist/core/mcp/shared-pool.test.d.ts.map +0 -1
- package/dist/core/mcp/shared-pool.test.js +0 -425
- package/dist/core/mcp/shared-pool.test.js.map +0 -1
- package/dist/core/mcp/store.test.d.ts +0 -2
- package/dist/core/mcp/store.test.d.ts.map +0 -1
- package/dist/core/mcp/store.test.js +0 -110
- package/dist/core/mcp/store.test.js.map +0 -1
- package/dist/core/mcp/when-connected.test.d.ts +0 -2
- package/dist/core/mcp/when-connected.test.d.ts.map +0 -1
- package/dist/core/mcp/when-connected.test.js +0 -46
- package/dist/core/mcp/when-connected.test.js.map +0 -1
- package/dist/core/message-images.test.d.ts +0 -2
- package/dist/core/message-images.test.d.ts.map +0 -1
- package/dist/core/message-images.test.js +0 -62
- package/dist/core/message-images.test.js.map +0 -1
- package/dist/core/network-guard.test.d.ts +0 -2
- package/dist/core/network-guard.test.d.ts.map +0 -1
- package/dist/core/network-guard.test.js +0 -72
- package/dist/core/network-guard.test.js.map +0 -1
- package/dist/core/persistent-shell.test.d.ts +0 -2
- package/dist/core/persistent-shell.test.d.ts.map +0 -1
- package/dist/core/persistent-shell.test.js +0 -84
- package/dist/core/persistent-shell.test.js.map +0 -1
- package/dist/core/process-gate.test.d.ts +0 -2
- package/dist/core/process-gate.test.d.ts.map +0 -1
- package/dist/core/process-gate.test.js +0 -87
- package/dist/core/process-gate.test.js.map +0 -1
- package/dist/core/process-manager-dev-server-repro.test.d.ts +0 -2
- package/dist/core/process-manager-dev-server-repro.test.d.ts.map +0 -1
- package/dist/core/process-manager-dev-server-repro.test.js +0 -225
- package/dist/core/process-manager-dev-server-repro.test.js.map +0 -1
- package/dist/core/process-manager-notifications.test.d.ts +0 -2
- package/dist/core/process-manager-notifications.test.d.ts.map +0 -1
- package/dist/core/process-manager-notifications.test.js +0 -245
- package/dist/core/process-manager-notifications.test.js.map +0 -1
- package/dist/core/process-manager-wake.test.d.ts +0 -2
- package/dist/core/process-manager-wake.test.d.ts.map +0 -1
- package/dist/core/process-manager-wake.test.js +0 -100
- package/dist/core/process-manager-wake.test.js.map +0 -1
- package/dist/core/progress/engine.test.d.ts +0 -2
- package/dist/core/progress/engine.test.d.ts.map +0 -1
- package/dist/core/progress/engine.test.js +0 -136
- package/dist/core/progress/engine.test.js.map +0 -1
- package/dist/core/progress/git-xp.test.d.ts +0 -2
- package/dist/core/progress/git-xp.test.d.ts.map +0 -1
- package/dist/core/progress/git-xp.test.js +0 -88
- package/dist/core/progress/git-xp.test.js.map +0 -1
- package/dist/core/progress/ranks.test.d.ts +0 -2
- package/dist/core/progress/ranks.test.d.ts.map +0 -1
- package/dist/core/progress/ranks.test.js +0 -100
- package/dist/core/progress/ranks.test.js.map +0 -1
- package/dist/core/progress/rebuild.test.d.ts +0 -2
- package/dist/core/progress/rebuild.test.d.ts.map +0 -1
- package/dist/core/progress/rebuild.test.js +0 -103
- package/dist/core/progress/rebuild.test.js.map +0 -1
- package/dist/core/progress/store.test.d.ts +0 -2
- package/dist/core/progress/store.test.d.ts.map +0 -1
- package/dist/core/progress/store.test.js +0 -108
- package/dist/core/progress/store.test.js.map +0 -1
- package/dist/core/project-discovery.test.d.ts +0 -2
- package/dist/core/project-discovery.test.d.ts.map +0 -1
- package/dist/core/project-discovery.test.js +0 -519
- package/dist/core/project-discovery.test.js.map +0 -1
- package/dist/core/prompt-commands.test.d.ts +0 -2
- package/dist/core/prompt-commands.test.d.ts.map +0 -1
- package/dist/core/prompt-commands.test.js +0 -180
- package/dist/core/prompt-commands.test.js.map +0 -1
- package/dist/core/provider-cache.e2e.test.d.ts +0 -2
- package/dist/core/provider-cache.e2e.test.d.ts.map +0 -1
- package/dist/core/provider-cache.e2e.test.js +0 -125
- package/dist/core/provider-cache.e2e.test.js.map +0 -1
- package/dist/core/radio.test.d.ts +0 -2
- package/dist/core/radio.test.d.ts.map +0 -1
- package/dist/core/radio.test.js +0 -117
- package/dist/core/radio.test.js.map +0 -1
- package/dist/core/regrounding.test.d.ts +0 -2
- package/dist/core/regrounding.test.d.ts.map +0 -1
- package/dist/core/regrounding.test.js +0 -38
- package/dist/core/regrounding.test.js.map +0 -1
- package/dist/core/resolve-start.test.d.ts +0 -2
- package/dist/core/resolve-start.test.d.ts.map +0 -1
- package/dist/core/resolve-start.test.js +0 -68
- package/dist/core/resolve-start.test.js.map +0 -1
- package/dist/core/run-claim.test.d.ts +0 -2
- package/dist/core/run-claim.test.d.ts.map +0 -1
- package/dist/core/run-claim.test.js +0 -107
- package/dist/core/run-claim.test.js.map +0 -1
- package/dist/core/run-journal.test.d.ts +0 -2
- package/dist/core/run-journal.test.d.ts.map +0 -1
- package/dist/core/run-journal.test.js +0 -195
- package/dist/core/run-journal.test.js.map +0 -1
- package/dist/core/run-lifecycle.test.d.ts +0 -2
- package/dist/core/run-lifecycle.test.d.ts.map +0 -1
- package/dist/core/run-lifecycle.test.js +0 -64
- package/dist/core/run-lifecycle.test.js.map +0 -1
- package/dist/core/sandbox-feedback.test.d.ts +0 -2
- package/dist/core/sandbox-feedback.test.d.ts.map +0 -1
- package/dist/core/sandbox-feedback.test.js +0 -32
- package/dist/core/sandbox-feedback.test.js.map +0 -1
- package/dist/core/sandbox.test.d.ts +0 -2
- package/dist/core/sandbox.test.d.ts.map +0 -1
- package/dist/core/sandbox.test.js +0 -221
- package/dist/core/sandbox.test.js.map +0 -1
- package/dist/core/semantic-search-benchmark.test.d.ts +0 -2
- package/dist/core/semantic-search-benchmark.test.d.ts.map +0 -1
- package/dist/core/semantic-search-benchmark.test.js +0 -89
- package/dist/core/semantic-search-benchmark.test.js.map +0 -1
- package/dist/core/session-compaction.test.d.ts +0 -2
- package/dist/core/session-compaction.test.d.ts.map +0 -1
- package/dist/core/session-compaction.test.js +0 -92
- package/dist/core/session-compaction.test.js.map +0 -1
- package/dist/core/session-export.test.d.ts +0 -2
- package/dist/core/session-export.test.d.ts.map +0 -1
- package/dist/core/session-export.test.js +0 -353
- package/dist/core/session-export.test.js.map +0 -1
- package/dist/core/session-history.test.d.ts +0 -2
- package/dist/core/session-history.test.d.ts.map +0 -1
- package/dist/core/session-history.test.js +0 -272
- package/dist/core/session-history.test.js.map +0 -1
- package/dist/core/session-injections.test.d.ts +0 -2
- package/dist/core/session-injections.test.d.ts.map +0 -1
- package/dist/core/session-injections.test.js +0 -117
- package/dist/core/session-injections.test.js.map +0 -1
- package/dist/core/session-manager.test.d.ts +0 -2
- package/dist/core/session-manager.test.d.ts.map +0 -1
- package/dist/core/session-manager.test.js +0 -571
- package/dist/core/session-manager.test.js.map +0 -1
- package/dist/core/session-notification-visibility.test.d.ts +0 -2
- package/dist/core/session-notification-visibility.test.d.ts.map +0 -1
- package/dist/core/session-notification-visibility.test.js +0 -113
- package/dist/core/session-notification-visibility.test.js.map +0 -1
- package/dist/core/session-reconstructability.test.d.ts +0 -2
- package/dist/core/session-reconstructability.test.d.ts.map +0 -1
- package/dist/core/session-reconstructability.test.js +0 -105
- package/dist/core/session-reconstructability.test.js.map +0 -1
- package/dist/core/session-restore-display.test.d.ts +0 -2
- package/dist/core/session-restore-display.test.d.ts.map +0 -1
- package/dist/core/session-restore-display.test.js +0 -103
- package/dist/core/session-restore-display.test.js.map +0 -1
- package/dist/core/session-storage-fd-leak.test.d.ts +0 -2
- package/dist/core/session-storage-fd-leak.test.d.ts.map +0 -1
- package/dist/core/session-storage-fd-leak.test.js +0 -116
- package/dist/core/session-storage-fd-leak.test.js.map +0 -1
- package/dist/core/session-storage.test.d.ts +0 -2
- package/dist/core/session-storage.test.d.ts.map +0 -1
- package/dist/core/session-storage.test.js +0 -277
- package/dist/core/session-storage.test.js.map +0 -1
- package/dist/core/setup-history.test.d.ts +0 -2
- package/dist/core/setup-history.test.d.ts.map +0 -1
- package/dist/core/setup-history.test.js +0 -59
- package/dist/core/setup-history.test.js.map +0 -1
- package/dist/core/shell.test.d.ts +0 -2
- package/dist/core/shell.test.d.ts.map +0 -1
- package/dist/core/shell.test.js +0 -87
- package/dist/core/shell.test.js.map +0 -1
- package/dist/core/shutdown.test.d.ts +0 -2
- package/dist/core/shutdown.test.d.ts.map +0 -1
- package/dist/core/shutdown.test.js +0 -160
- package/dist/core/shutdown.test.js.map +0 -1
- package/dist/core/sidecar-error-reporter.test.d.ts +0 -2
- package/dist/core/sidecar-error-reporter.test.d.ts.map +0 -1
- package/dist/core/sidecar-error-reporter.test.js +0 -61
- package/dist/core/sidecar-error-reporter.test.js.map +0 -1
- package/dist/core/skills-routing.test.d.ts +0 -2
- package/dist/core/skills-routing.test.d.ts.map +0 -1
- package/dist/core/skills-routing.test.js +0 -310
- package/dist/core/skills-routing.test.js.map +0 -1
- package/dist/core/slash-commands.test.d.ts +0 -2
- package/dist/core/slash-commands.test.d.ts.map +0 -1
- package/dist/core/slash-commands.test.js +0 -59
- package/dist/core/slash-commands.test.js.map +0 -1
- package/dist/core/source-maps.test.d.ts +0 -2
- package/dist/core/source-maps.test.d.ts.map +0 -1
- package/dist/core/source-maps.test.js +0 -175
- package/dist/core/source-maps.test.js.map +0 -1
- package/dist/core/speed-benchmark.test.d.ts +0 -2
- package/dist/core/speed-benchmark.test.d.ts.map +0 -1
- package/dist/core/speed-benchmark.test.js +0 -102
- package/dist/core/speed-benchmark.test.js.map +0 -1
- package/dist/core/subagent-manager.test.d.ts +0 -2
- package/dist/core/subagent-manager.test.d.ts.map +0 -1
- package/dist/core/subagent-manager.test.js +0 -536
- package/dist/core/subagent-manager.test.js.map +0 -1
- package/dist/core/subagent-store.test.d.ts +0 -2
- package/dist/core/subagent-store.test.d.ts.map +0 -1
- package/dist/core/subagent-store.test.js +0 -106
- package/dist/core/subagent-store.test.js.map +0 -1
- package/dist/core/subagent-turn-record.test.d.ts +0 -2
- package/dist/core/subagent-turn-record.test.d.ts.map +0 -1
- package/dist/core/subagent-turn-record.test.js +0 -70
- package/dist/core/subagent-turn-record.test.js.map +0 -1
- package/dist/core/verification-evidence.test.d.ts +0 -2
- package/dist/core/verification-evidence.test.d.ts.map +0 -1
- package/dist/core/verification-evidence.test.js +0 -103
- package/dist/core/verification-evidence.test.js.map +0 -1
- package/dist/core/verification-gate.test.d.ts +0 -2
- package/dist/core/verification-gate.test.d.ts.map +0 -1
- package/dist/core/verification-gate.test.js +0 -138
- package/dist/core/verification-gate.test.js.map +0 -1
- package/dist/core/verify-commands.test.d.ts +0 -2
- package/dist/core/verify-commands.test.d.ts.map +0 -1
- package/dist/core/verify-commands.test.js +0 -81
- package/dist/core/verify-commands.test.js.map +0 -1
- package/dist/core/workspace-guard.test.d.ts +0 -2
- package/dist/core/workspace-guard.test.d.ts.map +0 -1
- package/dist/core/workspace-guard.test.js +0 -107
- package/dist/core/workspace-guard.test.js.map +0 -1
- package/dist/hf-pull.test.d.ts +0 -2
- package/dist/hf-pull.test.d.ts.map +0 -1
- package/dist/hf-pull.test.js +0 -112
- package/dist/hf-pull.test.js.map +0 -1
- package/dist/modes/acp-mode.test.d.ts +0 -2
- package/dist/modes/acp-mode.test.d.ts.map +0 -1
- package/dist/modes/acp-mode.test.js +0 -1067
- package/dist/modes/acp-mode.test.js.map +0 -1
- package/dist/modes/json-mode.test.d.ts +0 -2
- package/dist/modes/json-mode.test.d.ts.map +0 -1
- package/dist/modes/json-mode.test.js +0 -84
- package/dist/modes/json-mode.test.js.map +0 -1
- package/dist/modes/subagent-worker-mode.test.d.ts +0 -2
- package/dist/modes/subagent-worker-mode.test.d.ts.map +0 -1
- package/dist/modes/subagent-worker-mode.test.js +0 -52
- package/dist/modes/subagent-worker-mode.test.js.map +0 -1
- package/dist/session.test.d.ts +0 -2
- package/dist/session.test.d.ts.map +0 -1
- package/dist/session.test.js +0 -35
- package/dist/session.test.js.map +0 -1
- package/dist/system-prompt.test.d.ts +0 -2
- package/dist/system-prompt.test.d.ts.map +0 -1
- package/dist/system-prompt.test.js +0 -684
- package/dist/system-prompt.test.js.map +0 -1
- package/dist/system-prompt.tiering.test.d.ts +0 -2
- package/dist/system-prompt.tiering.test.d.ts.map +0 -1
- package/dist/system-prompt.tiering.test.js +0 -112
- package/dist/system-prompt.tiering.test.js.map +0 -1
- package/dist/tools/bash.test.d.ts +0 -2
- package/dist/tools/bash.test.d.ts.map +0 -1
- package/dist/tools/bash.test.js +0 -248
- package/dist/tools/bash.test.js.map +0 -1
- package/dist/tools/checkpoint-hook.test.d.ts +0 -2
- package/dist/tools/checkpoint-hook.test.d.ts.map +0 -1
- package/dist/tools/checkpoint-hook.test.js +0 -65
- package/dist/tools/checkpoint-hook.test.js.map +0 -1
- package/dist/tools/code-nav.test.d.ts +0 -2
- package/dist/tools/code-nav.test.d.ts.map +0 -1
- package/dist/tools/code-nav.test.js +0 -136
- package/dist/tools/code-nav.test.js.map +0 -1
- package/dist/tools/code-skeleton.test.d.ts +0 -2
- package/dist/tools/code-skeleton.test.d.ts.map +0 -1
- package/dist/tools/code-skeleton.test.js +0 -115
- package/dist/tools/code-skeleton.test.js.map +0 -1
- package/dist/tools/compress-integration.test.d.ts +0 -2
- package/dist/tools/compress-integration.test.d.ts.map +0 -1
- package/dist/tools/compress-integration.test.js +0 -59
- package/dist/tools/compress-integration.test.js.map +0 -1
- package/dist/tools/compress.test.d.ts +0 -2
- package/dist/tools/compress.test.d.ts.map +0 -1
- package/dist/tools/compress.test.js +0 -60
- package/dist/tools/compress.test.js.map +0 -1
- package/dist/tools/edit-diff.test.d.ts +0 -2
- package/dist/tools/edit-diff.test.d.ts.map +0 -1
- package/dist/tools/edit-diff.test.js +0 -329
- package/dist/tools/edit-diff.test.js.map +0 -1
- package/dist/tools/edit-robustness.test.d.ts +0 -2
- package/dist/tools/edit-robustness.test.d.ts.map +0 -1
- package/dist/tools/edit-robustness.test.js +0 -417
- package/dist/tools/edit-robustness.test.js.map +0 -1
- package/dist/tools/edit.test.d.ts +0 -2
- package/dist/tools/edit.test.d.ts.map +0 -1
- package/dist/tools/edit.test.js +0 -984
- package/dist/tools/edit.test.js.map +0 -1
- package/dist/tools/exit-plan.test.d.ts +0 -2
- package/dist/tools/exit-plan.test.d.ts.map +0 -1
- package/dist/tools/exit-plan.test.js +0 -72
- package/dist/tools/exit-plan.test.js.map +0 -1
- package/dist/tools/generate-image.test.d.ts +0 -2
- package/dist/tools/generate-image.test.d.ts.map +0 -1
- package/dist/tools/generate-image.test.js +0 -240
- package/dist/tools/generate-image.test.js.map +0 -1
- package/dist/tools/grep-parity.test.d.ts +0 -2
- package/dist/tools/grep-parity.test.d.ts.map +0 -1
- package/dist/tools/grep-parity.test.js +0 -92
- package/dist/tools/grep-parity.test.js.map +0 -1
- package/dist/tools/grep-recall.test.d.ts +0 -2
- package/dist/tools/grep-recall.test.d.ts.map +0 -1
- package/dist/tools/grep-recall.test.js +0 -114
- package/dist/tools/grep-recall.test.js.map +0 -1
- package/dist/tools/grep-spawn.test.d.ts +0 -2
- package/dist/tools/grep-spawn.test.d.ts.map +0 -1
- package/dist/tools/grep-spawn.test.js +0 -66
- package/dist/tools/grep-spawn.test.js.map +0 -1
- package/dist/tools/grep.test.d.ts +0 -2
- package/dist/tools/grep.test.d.ts.map +0 -1
- package/dist/tools/grep.test.js +0 -82
- package/dist/tools/grep.test.js.map +0 -1
- package/dist/tools/html-extract.test.d.ts +0 -2
- package/dist/tools/html-extract.test.d.ts.map +0 -1
- package/dist/tools/html-extract.test.js +0 -60
- package/dist/tools/html-extract.test.js.map +0 -1
- package/dist/tools/index.test.d.ts +0 -2
- package/dist/tools/index.test.d.ts.map +0 -1
- package/dist/tools/index.test.js +0 -55
- package/dist/tools/index.test.js.map +0 -1
- package/dist/tools/overflow.test.d.ts +0 -2
- package/dist/tools/overflow.test.d.ts.map +0 -1
- package/dist/tools/overflow.test.js +0 -59
- package/dist/tools/overflow.test.js.map +0 -1
- package/dist/tools/path-utils.test.d.ts +0 -2
- package/dist/tools/path-utils.test.d.ts.map +0 -1
- package/dist/tools/path-utils.test.js +0 -110
- package/dist/tools/path-utils.test.js.map +0 -1
- package/dist/tools/pdf-extract.test.d.ts +0 -2
- package/dist/tools/pdf-extract.test.d.ts.map +0 -1
- package/dist/tools/pdf-extract.test.js +0 -15
- package/dist/tools/pdf-extract.test.js.map +0 -1
- package/dist/tools/plan-mode.test.d.ts +0 -2
- package/dist/tools/plan-mode.test.d.ts.map +0 -1
- package/dist/tools/plan-mode.test.js +0 -91
- package/dist/tools/plan-mode.test.js.map +0 -1
- package/dist/tools/read-only-bash.test.d.ts +0 -2
- package/dist/tools/read-only-bash.test.d.ts.map +0 -1
- package/dist/tools/read-only-bash.test.js +0 -96
- package/dist/tools/read-only-bash.test.js.map +0 -1
- package/dist/tools/read.test.d.ts +0 -2
- package/dist/tools/read.test.d.ts.map +0 -1
- package/dist/tools/read.test.js +0 -146
- package/dist/tools/read.test.js.map +0 -1
- package/dist/tools/screenshot.test.d.ts +0 -2
- package/dist/tools/screenshot.test.d.ts.map +0 -1
- package/dist/tools/screenshot.test.js +0 -145
- package/dist/tools/screenshot.test.js.map +0 -1
- package/dist/tools/search-code.test.d.ts +0 -2
- package/dist/tools/search-code.test.d.ts.map +0 -1
- package/dist/tools/search-code.test.js +0 -83
- package/dist/tools/search-code.test.js.map +0 -1
- package/dist/tools/source-path.test.d.ts +0 -2
- package/dist/tools/source-path.test.d.ts.map +0 -1
- package/dist/tools/source-path.test.js +0 -80
- package/dist/tools/source-path.test.js.map +0 -1
- package/dist/tools/subagent-control.test.d.ts +0 -2
- package/dist/tools/subagent-control.test.d.ts.map +0 -1
- package/dist/tools/subagent-control.test.js +0 -73
- package/dist/tools/subagent-control.test.js.map +0 -1
- package/dist/tools/subagent-shared.test.d.ts +0 -2
- package/dist/tools/subagent-shared.test.d.ts.map +0 -1
- package/dist/tools/subagent-shared.test.js +0 -83
- package/dist/tools/subagent-shared.test.js.map +0 -1
- package/dist/tools/subagent.test.d.ts +0 -2
- package/dist/tools/subagent.test.d.ts.map +0 -1
- package/dist/tools/subagent.test.js +0 -180
- package/dist/tools/subagent.test.js.map +0 -1
- package/dist/tools/task-send.test.d.ts +0 -2
- package/dist/tools/task-send.test.d.ts.map +0 -1
- package/dist/tools/task-send.test.js +0 -104
- package/dist/tools/task-send.test.js.map +0 -1
- package/dist/tools/tool-catalog.test.d.ts +0 -2
- package/dist/tools/tool-catalog.test.d.ts.map +0 -1
- package/dist/tools/tool-catalog.test.js +0 -124
- package/dist/tools/tool-catalog.test.js.map +0 -1
- package/dist/tools/tool-search.test.d.ts +0 -2
- package/dist/tools/tool-search.test.d.ts.map +0 -1
- package/dist/tools/tool-search.test.js +0 -127
- package/dist/tools/tool-search.test.js.map +0 -1
- package/dist/tools/tool-tiers.test.d.ts +0 -2
- package/dist/tools/tool-tiers.test.d.ts.map +0 -1
- package/dist/tools/tool-tiers.test.js +0 -48
- package/dist/tools/tool-tiers.test.js.map +0 -1
- package/dist/tools/truncate-utils.test.d.ts +0 -2
- package/dist/tools/truncate-utils.test.d.ts.map +0 -1
- package/dist/tools/truncate-utils.test.js +0 -93
- package/dist/tools/truncate-utils.test.js.map +0 -1
- package/dist/tools/truncate.test.d.ts +0 -2
- package/dist/tools/truncate.test.d.ts.map +0 -1
- package/dist/tools/truncate.test.js +0 -100
- package/dist/tools/truncate.test.js.map +0 -1
- package/dist/tools/web-fetch.test.d.ts +0 -2
- package/dist/tools/web-fetch.test.d.ts.map +0 -1
- package/dist/tools/web-fetch.test.js +0 -676
- package/dist/tools/web-fetch.test.js.map +0 -1
- package/dist/tools/web-search.test.d.ts +0 -2
- package/dist/tools/web-search.test.d.ts.map +0 -1
- package/dist/tools/web-search.test.js +0 -333
- package/dist/tools/web-search.test.js.map +0 -1
- package/dist/tools/write.test.d.ts +0 -2
- package/dist/tools/write.test.d.ts.map +0 -1
- package/dist/tools/write.test.js +0 -176
- package/dist/tools/write.test.js.map +0 -1
- package/dist/ui/anchor-pad-reclaim.test.d.ts +0 -2
- package/dist/ui/anchor-pad-reclaim.test.d.ts.map +0 -1
- package/dist/ui/anchor-pad-reclaim.test.js +0 -146
- package/dist/ui/anchor-pad-reclaim.test.js.map +0 -1
- package/dist/ui/app-items.test.d.ts +0 -2
- package/dist/ui/app-items.test.d.ts.map +0 -1
- package/dist/ui/app-items.test.js +0 -54
- package/dist/ui/app-items.test.js.map +0 -1
- package/dist/ui/app-state-persistence.test.d.ts +0 -2
- package/dist/ui/app-state-persistence.test.d.ts.map +0 -1
- package/dist/ui/app-state-persistence.test.js +0 -71
- package/dist/ui/app-state-persistence.test.js.map +0 -1
- package/dist/ui/assistant-stream-flush-parity.test.d.ts +0 -2
- package/dist/ui/assistant-stream-flush-parity.test.d.ts.map +0 -1
- package/dist/ui/assistant-stream-flush-parity.test.js +0 -85
- package/dist/ui/assistant-stream-flush-parity.test.js.map +0 -1
- package/dist/ui/atomic-flush-regression.test.d.ts +0 -2
- package/dist/ui/atomic-flush-regression.test.d.ts.map +0 -1
- package/dist/ui/atomic-flush-regression.test.js +0 -218
- package/dist/ui/atomic-flush-regression.test.js.map +0 -1
- package/dist/ui/chat-layout-pinning.test.d.ts +0 -2
- package/dist/ui/chat-layout-pinning.test.d.ts.map +0 -1
- package/dist/ui/chat-layout-pinning.test.js +0 -525
- package/dist/ui/chat-layout-pinning.test.js.map +0 -1
- package/dist/ui/components/ActivityIndicator.test.d.ts +0 -2
- package/dist/ui/components/ActivityIndicator.test.d.ts.map +0 -1
- package/dist/ui/components/ActivityIndicator.test.js +0 -40
- package/dist/ui/components/ActivityIndicator.test.js.map +0 -1
- package/dist/ui/components/AssistantMessage.test.d.ts +0 -2
- package/dist/ui/components/AssistantMessage.test.d.ts.map +0 -1
- package/dist/ui/components/AssistantMessage.test.js +0 -418
- package/dist/ui/components/AssistantMessage.test.js.map +0 -1
- package/dist/ui/components/Footer.test.d.ts +0 -2
- package/dist/ui/components/Footer.test.d.ts.map +0 -1
- package/dist/ui/components/Footer.test.js +0 -16
- package/dist/ui/components/Footer.test.js.map +0 -1
- package/dist/ui/components/InputArea.test.d.ts +0 -2
- package/dist/ui/components/InputArea.test.d.ts.map +0 -1
- package/dist/ui/components/InputArea.test.js +0 -95
- package/dist/ui/components/InputArea.test.js.map +0 -1
- package/dist/ui/components/PlanOverlay.test.d.ts +0 -2
- package/dist/ui/components/PlanOverlay.test.d.ts.map +0 -1
- package/dist/ui/components/PlanOverlay.test.js +0 -24
- package/dist/ui/components/PlanOverlay.test.js.map +0 -1
- package/dist/ui/components/StreamingArea.test.d.ts +0 -2
- package/dist/ui/components/StreamingArea.test.d.ts.map +0 -1
- package/dist/ui/components/StreamingArea.test.js +0 -18
- package/dist/ui/components/StreamingArea.test.js.map +0 -1
- package/dist/ui/components/UserMessage.test.d.ts +0 -2
- package/dist/ui/components/UserMessage.test.d.ts.map +0 -1
- package/dist/ui/components/UserMessage.test.js +0 -39
- package/dist/ui/components/UserMessage.test.js.map +0 -1
- package/dist/ui/components/themed-output.test.d.ts +0 -2
- package/dist/ui/components/themed-output.test.d.ts.map +0 -1
- package/dist/ui/components/themed-output.test.js +0 -111
- package/dist/ui/components/themed-output.test.js.map +0 -1
- package/dist/ui/footer-jump-regression.test.d.ts +0 -2
- package/dist/ui/footer-jump-regression.test.d.ts.map +0 -1
- package/dist/ui/footer-jump-regression.test.js +0 -224
- package/dist/ui/footer-jump-regression.test.js.map +0 -1
- package/dist/ui/footer-status-layout.test.d.ts +0 -2
- package/dist/ui/footer-status-layout.test.d.ts.map +0 -1
- package/dist/ui/footer-status-layout.test.js +0 -71
- package/dist/ui/footer-status-layout.test.js.map +0 -1
- package/dist/ui/frame-clip-regression.test.d.ts +0 -2
- package/dist/ui/frame-clip-regression.test.d.ts.map +0 -1
- package/dist/ui/frame-clip-regression.test.js +0 -215
- package/dist/ui/frame-clip-regression.test.js.map +0 -1
- package/dist/ui/hooks/stall-retry-duplicate.test.d.ts +0 -2
- package/dist/ui/hooks/stall-retry-duplicate.test.d.ts.map +0 -1
- package/dist/ui/hooks/stall-retry-duplicate.test.js +0 -94
- package/dist/ui/hooks/stall-retry-duplicate.test.js.map +0 -1
- package/dist/ui/hooks/useAgentLoop.test.d.ts +0 -2
- package/dist/ui/hooks/useAgentLoop.test.d.ts.map +0 -1
- package/dist/ui/hooks/useAgentLoop.test.js +0 -66
- package/dist/ui/hooks/useAgentLoop.test.js.map +0 -1
- package/dist/ui/hooks/useContextCompaction.test.d.ts +0 -2
- package/dist/ui/hooks/useContextCompaction.test.d.ts.map +0 -1
- package/dist/ui/hooks/useContextCompaction.test.js +0 -135
- package/dist/ui/hooks/useContextCompaction.test.js.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.d.ts +0 -2
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.d.ts.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.js +0 -81
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.js.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.test.d.ts +0 -2
- package/dist/ui/hooks/useTranscriptHistory.test.d.ts.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.test.js +0 -61
- package/dist/ui/hooks/useTranscriptHistory.test.js.map +0 -1
- package/dist/ui/hooks/useTranscriptScroll.test.d.ts +0 -2
- package/dist/ui/hooks/useTranscriptScroll.test.d.ts.map +0 -1
- package/dist/ui/hooks/useTranscriptScroll.test.js +0 -119
- package/dist/ui/hooks/useTranscriptScroll.test.js.map +0 -1
- package/dist/ui/live-area-clamp.test.d.ts +0 -2
- package/dist/ui/live-area-clamp.test.d.ts.map +0 -1
- package/dist/ui/live-area-clamp.test.js +0 -125
- package/dist/ui/live-area-clamp.test.js.map +0 -1
- package/dist/ui/live-area-height.test.d.ts +0 -2
- package/dist/ui/live-area-height.test.d.ts.map +0 -1
- package/dist/ui/live-area-height.test.js +0 -76
- package/dist/ui/live-area-height.test.js.map +0 -1
- package/dist/ui/live-frame-height.test.d.ts +0 -2
- package/dist/ui/live-frame-height.test.d.ts.map +0 -1
- package/dist/ui/live-frame-height.test.js +0 -116
- package/dist/ui/live-frame-height.test.js.map +0 -1
- package/dist/ui/live-item-flush.test.d.ts +0 -2
- package/dist/ui/live-item-flush.test.d.ts.map +0 -1
- package/dist/ui/live-item-flush.test.js +0 -437
- package/dist/ui/live-item-flush.test.js.map +0 -1
- package/dist/ui/long-prompt-regression-harness.test.d.ts +0 -2
- package/dist/ui/long-prompt-regression-harness.test.d.ts.map +0 -1
- package/dist/ui/long-prompt-regression-harness.test.js +0 -195
- package/dist/ui/long-prompt-regression-harness.test.js.map +0 -1
- package/dist/ui/plan-overlay.test.d.ts +0 -2
- package/dist/ui/plan-overlay.test.d.ts.map +0 -1
- package/dist/ui/plan-overlay.test.js +0 -305
- package/dist/ui/plan-overlay.test.js.map +0 -1
- package/dist/ui/queued-message.test.d.ts +0 -2
- package/dist/ui/queued-message.test.d.ts.map +0 -1
- package/dist/ui/queued-message.test.js +0 -172
- package/dist/ui/queued-message.test.js.map +0 -1
- package/dist/ui/render.test.d.ts +0 -2
- package/dist/ui/render.test.d.ts.map +0 -1
- package/dist/ui/render.test.js +0 -42
- package/dist/ui/render.test.js.map +0 -1
- package/dist/ui/scroll-stabilization.test.d.ts +0 -2
- package/dist/ui/scroll-stabilization.test.d.ts.map +0 -1
- package/dist/ui/scroll-stabilization.test.js +0 -64
- package/dist/ui/scroll-stabilization.test.js.map +0 -1
- package/dist/ui/slash-command-images.test.d.ts +0 -2
- package/dist/ui/slash-command-images.test.d.ts.map +0 -1
- package/dist/ui/slash-command-images.test.js +0 -110
- package/dist/ui/slash-command-images.test.js.map +0 -1
- package/dist/ui/startup-banner-order.test.d.ts +0 -2
- package/dist/ui/startup-banner-order.test.d.ts.map +0 -1
- package/dist/ui/startup-banner-order.test.js +0 -105
- package/dist/ui/startup-banner-order.test.js.map +0 -1
- package/dist/ui/stores/transcript-scroll-store.test.d.ts +0 -2
- package/dist/ui/stores/transcript-scroll-store.test.d.ts.map +0 -1
- package/dist/ui/stores/transcript-scroll-store.test.js +0 -73
- package/dist/ui/stores/transcript-scroll-store.test.js.map +0 -1
- package/dist/ui/streaming-flush-bounce.test.d.ts +0 -2
- package/dist/ui/streaming-flush-bounce.test.d.ts.map +0 -1
- package/dist/ui/streaming-flush-bounce.test.js +0 -177
- package/dist/ui/streaming-flush-bounce.test.js.map +0 -1
- package/dist/ui/submit-boundary-gap.test.d.ts +0 -2
- package/dist/ui/submit-boundary-gap.test.d.ts.map +0 -1
- package/dist/ui/submit-boundary-gap.test.js +0 -180
- package/dist/ui/submit-boundary-gap.test.js.map +0 -1
- package/dist/ui/terminal-history-repaint.test.d.ts +0 -2
- package/dist/ui/terminal-history-repaint.test.d.ts.map +0 -1
- package/dist/ui/terminal-history-repaint.test.js +0 -73
- package/dist/ui/terminal-history-repaint.test.js.map +0 -1
- package/dist/ui/terminal-history-retry-dedup.test.d.ts +0 -2
- package/dist/ui/terminal-history-retry-dedup.test.d.ts.map +0 -1
- package/dist/ui/terminal-history-retry-dedup.test.js +0 -61
- package/dist/ui/terminal-history-retry-dedup.test.js.map +0 -1
- package/dist/ui/terminal-history.test.d.ts +0 -2
- package/dist/ui/terminal-history.test.d.ts.map +0 -1
- package/dist/ui/terminal-history.test.js +0 -557
- package/dist/ui/terminal-history.test.js.map +0 -1
- package/dist/ui/thinking-level-cycle.test.d.ts +0 -2
- package/dist/ui/thinking-level-cycle.test.d.ts.map +0 -1
- package/dist/ui/thinking-level-cycle.test.js +0 -45
- package/dist/ui/thinking-level-cycle.test.js.map +0 -1
- package/dist/ui/tool-group-summary.test.d.ts +0 -2
- package/dist/ui/tool-group-summary.test.d.ts.map +0 -1
- package/dist/ui/tool-group-summary.test.js +0 -79
- package/dist/ui/tool-group-summary.test.js.map +0 -1
- package/dist/ui/transcript/spacing.test.d.ts +0 -2
- package/dist/ui/transcript/spacing.test.d.ts.map +0 -1
- package/dist/ui/transcript/spacing.test.js +0 -187
- package/dist/ui/transcript/spacing.test.js.map +0 -1
- package/dist/ui/transcript/transcript-lines.test.d.ts +0 -2
- package/dist/ui/transcript/transcript-lines.test.d.ts.map +0 -1
- package/dist/ui/transcript/transcript-lines.test.js +0 -76
- package/dist/ui/transcript/transcript-lines.test.js.map +0 -1
- package/dist/ui/transcript-viewport-pinning.test.d.ts +0 -2
- package/dist/ui/transcript-viewport-pinning.test.d.ts.map +0 -1
- package/dist/ui/transcript-viewport-pinning.test.js +0 -148
- package/dist/ui/transcript-viewport-pinning.test.js.map +0 -1
- package/dist/ui/tui-history-parity.test.d.ts +0 -2
- package/dist/ui/tui-history-parity.test.d.ts.map +0 -1
- package/dist/ui/tui-history-parity.test.js +0 -369
- package/dist/ui/tui-history-parity.test.js.map +0 -1
- package/dist/ui/tui-simulation.test.d.ts +0 -2
- package/dist/ui/tui-simulation.test.d.ts.map +0 -1
- package/dist/ui/tui-simulation.test.js +0 -145
- package/dist/ui/tui-simulation.test.js.map +0 -1
- package/dist/ui/tui-terminal-recorder.test.d.ts +0 -2
- package/dist/ui/tui-terminal-recorder.test.d.ts.map +0 -1
- package/dist/ui/tui-terminal-recorder.test.js +0 -134
- package/dist/ui/tui-terminal-recorder.test.js.map +0 -1
- package/dist/ui/utils/assistant-stream-split.test.d.ts +0 -2
- package/dist/ui/utils/assistant-stream-split.test.d.ts.map +0 -1
- package/dist/ui/utils/assistant-stream-split.test.js +0 -74
- package/dist/ui/utils/assistant-stream-split.test.js.map +0 -1
- package/dist/ui/utils/markdown-renderer.test.d.ts +0 -2
- package/dist/ui/utils/markdown-renderer.test.d.ts.map +0 -1
- package/dist/ui/utils/markdown-renderer.test.js +0 -63
- package/dist/ui/utils/markdown-renderer.test.js.map +0 -1
- package/dist/ui/utils/table-text.test.d.ts +0 -2
- package/dist/ui/utils/table-text.test.d.ts.map +0 -1
- package/dist/ui/utils/table-text.test.js +0 -202
- package/dist/ui/utils/table-text.test.js.map +0 -1
- package/dist/ui/utils/terminal-graphics.test.d.ts +0 -2
- package/dist/ui/utils/terminal-graphics.test.d.ts.map +0 -1
- package/dist/ui/utils/terminal-graphics.test.js +0 -100
- package/dist/ui/utils/terminal-graphics.test.js.map +0 -1
- package/dist/ui/utils/terminal-input.test.d.ts +0 -2
- package/dist/ui/utils/terminal-input.test.d.ts.map +0 -1
- package/dist/ui/utils/terminal-input.test.js +0 -15
- package/dist/ui/utils/terminal-input.test.js.map +0 -1
- package/dist/utils/git.test.d.ts +0 -2
- package/dist/utils/git.test.d.ts.map +0 -1
- package/dist/utils/git.test.js +0 -36
- package/dist/utils/git.test.js.map +0 -1
- package/dist/utils/github.test.d.ts +0 -2
- package/dist/utils/github.test.d.ts.map +0 -1
- package/dist/utils/github.test.js +0 -23
- package/dist/utils/github.test.js.map +0 -1
- package/dist/utils/http-body.test.d.ts +0 -2
- package/dist/utils/http-body.test.d.ts.map +0 -1
- package/dist/utils/http-body.test.js +0 -68
- package/dist/utils/http-body.test.js.map +0 -1
- package/dist/utils/image.test.d.ts +0 -2
- package/dist/utils/image.test.d.ts.map +0 -1
- package/dist/utils/image.test.js +0 -139
- package/dist/utils/image.test.js.map +0 -1
- package/dist/utils/plan-steps.test.d.ts +0 -2
- package/dist/utils/plan-steps.test.d.ts.map +0 -1
- package/dist/utils/plan-steps.test.js +0 -159
- package/dist/utils/plan-steps.test.js.map +0 -1
- package/dist/utils/process.test.d.ts +0 -2
- package/dist/utils/process.test.d.ts.map +0 -1
- package/dist/utils/process.test.js +0 -42
- package/dist/utils/process.test.js.map +0 -1
|
@@ -1,1067 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { spawn } from "node:child_process";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
7
|
-
import { ACP_PROTOCOL_VERSION } from "./acp-mode.js";
|
|
8
|
-
const FIXTURE = path.join(path.dirname(fileURLToPath(import.meta.url)), "__fixtures__", "acp-stdio-agent.mjs");
|
|
9
|
-
/**
|
|
10
|
-
* A HOME the fixture seeds sessions into, and the project directory they
|
|
11
|
-
* belong to.
|
|
12
|
-
*
|
|
13
|
-
* Real files rather than a stub: `session/list` and `session/load` exist to
|
|
14
|
-
* surface sessions the desktop wrote, so anything short of the real
|
|
15
|
-
* `~/.gg/sessions` layout would prove nothing about that.
|
|
16
|
-
*/
|
|
17
|
-
let tmpHome;
|
|
18
|
-
let tmpProject;
|
|
19
|
-
/** A second checkout, so "list everything" can be told apart from "list here". */
|
|
20
|
-
let tmpOtherProject;
|
|
21
|
-
/**
|
|
22
|
-
* A live ACP agent in a child process, driven exactly the way a client drives
|
|
23
|
-
* it: NDJSON in on stdin, NDJSON out on stdout.
|
|
24
|
-
*/
|
|
25
|
-
class AcpClient {
|
|
26
|
-
child;
|
|
27
|
-
buffer = "";
|
|
28
|
-
frames = [];
|
|
29
|
-
waiters = [];
|
|
30
|
-
stderr = "";
|
|
31
|
-
exit;
|
|
32
|
-
constructor() {
|
|
33
|
-
this.child = spawn(process.execPath, ["--import", "tsx", FIXTURE, tmpProject, tmpOtherProject], {
|
|
34
|
-
// Run from the package root so `tsx` resolves; the project directory is
|
|
35
|
-
// passed explicitly rather than inherited from the test runner.
|
|
36
|
-
cwd: process.cwd(),
|
|
37
|
-
env: {
|
|
38
|
-
...process.env,
|
|
39
|
-
HOME: tmpHome,
|
|
40
|
-
USERPROFILE: tmpHome,
|
|
41
|
-
GG_DISABLE_TELEMETRY: "1",
|
|
42
|
-
},
|
|
43
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
44
|
-
});
|
|
45
|
-
this.child.stdout.setEncoding("utf8");
|
|
46
|
-
this.child.stdout.on("data", (chunk) => {
|
|
47
|
-
this.buffer += chunk;
|
|
48
|
-
const lines = this.buffer.split("\n");
|
|
49
|
-
this.buffer = lines.pop() ?? "";
|
|
50
|
-
for (const line of lines) {
|
|
51
|
-
if (line.trim())
|
|
52
|
-
this.frames.push(JSON.parse(line));
|
|
53
|
-
}
|
|
54
|
-
for (const wake of this.waiters.splice(0))
|
|
55
|
-
wake();
|
|
56
|
-
});
|
|
57
|
-
this.child.stderr.setEncoding("utf8");
|
|
58
|
-
this.child.stderr.on("data", (chunk) => {
|
|
59
|
-
this.stderr += chunk;
|
|
60
|
-
});
|
|
61
|
-
this.exit = new Promise((resolve) => this.child.on("close", (code) => resolve(code)));
|
|
62
|
-
}
|
|
63
|
-
send(frame) {
|
|
64
|
-
this.child.stdin.write(`${JSON.stringify(frame)}\n`);
|
|
65
|
-
}
|
|
66
|
-
/** Write bytes verbatim, so malformed input can be tested. */
|
|
67
|
-
sendRaw(text) {
|
|
68
|
-
this.child.stdin.write(text);
|
|
69
|
-
}
|
|
70
|
-
/** Close stdin, which is how an ACP client disconnects. */
|
|
71
|
-
end() {
|
|
72
|
-
this.child.stdin.end();
|
|
73
|
-
}
|
|
74
|
-
kill() {
|
|
75
|
-
this.child.kill("SIGKILL");
|
|
76
|
-
}
|
|
77
|
-
/** Every frame received so far, in arrival order. */
|
|
78
|
-
received() {
|
|
79
|
-
return [...this.frames];
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Wait for the response to `id`, returning everything that arrived up to and
|
|
83
|
-
* including it. Ordering is the assertion that matters: notifications for a
|
|
84
|
-
* turn must precede that turn's response.
|
|
85
|
-
*/
|
|
86
|
-
async until(id, timeoutMs = 20_000) {
|
|
87
|
-
const deadline = Date.now() + timeoutMs;
|
|
88
|
-
for (;;) {
|
|
89
|
-
const index = this.frames.findIndex((frame) => frame.id === id);
|
|
90
|
-
if (index >= 0)
|
|
91
|
-
return this.frames.slice(0, index + 1);
|
|
92
|
-
const remaining = deadline - Date.now();
|
|
93
|
-
if (remaining <= 0) {
|
|
94
|
-
throw new Error(`timed out waiting for response ${String(id)}; got ${JSON.stringify(this.frames)} stderr=${this.stderr}`);
|
|
95
|
-
}
|
|
96
|
-
await new Promise((resolve) => {
|
|
97
|
-
const timer = setTimeout(resolve, Math.min(remaining, 50));
|
|
98
|
-
this.waiters.push(() => {
|
|
99
|
-
clearTimeout(timer);
|
|
100
|
-
resolve();
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/** Drive the handshake and return the created session id. */
|
|
106
|
-
async handshake() {
|
|
107
|
-
this.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
108
|
-
await this.until(1);
|
|
109
|
-
this.send({
|
|
110
|
-
jsonrpc: "2.0",
|
|
111
|
-
id: 2,
|
|
112
|
-
method: "session/new",
|
|
113
|
-
params: { cwd: tmpProject, mcpServers: [] },
|
|
114
|
-
});
|
|
115
|
-
const frames = await this.until(2);
|
|
116
|
-
return frames.at(-1).result.sessionId;
|
|
117
|
-
}
|
|
118
|
-
/** Wait for a `session/update` notification of one kind, ignoring the rest. */
|
|
119
|
-
async untilUpdate(kind, timeoutMs = 20_000) {
|
|
120
|
-
const deadline = Date.now() + timeoutMs;
|
|
121
|
-
for (;;) {
|
|
122
|
-
const found = updates(this.frames).find((update) => update.sessionUpdate === kind);
|
|
123
|
-
if (found)
|
|
124
|
-
return found;
|
|
125
|
-
if (Date.now() >= deadline) {
|
|
126
|
-
throw new Error(`timed out waiting for ${kind}; stderr=${this.stderr}`);
|
|
127
|
-
}
|
|
128
|
-
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* The stored sessions the fixture seeded, newest first.
|
|
133
|
-
*
|
|
134
|
-
* Omitting `cwd` asks for every project, which is what a phone wants; passing
|
|
135
|
-
* one scopes to that checkout.
|
|
136
|
-
*/
|
|
137
|
-
async list(id = 90, cwd) {
|
|
138
|
-
this.send({
|
|
139
|
-
jsonrpc: "2.0",
|
|
140
|
-
id,
|
|
141
|
-
method: "session/list",
|
|
142
|
-
params: cwd ? { cwd } : {},
|
|
143
|
-
});
|
|
144
|
-
const frames = await this.until(id);
|
|
145
|
-
return frames.at(-1).result.sessions;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
let client;
|
|
149
|
-
beforeEach(async () => {
|
|
150
|
-
tmpHome = await fs.mkdtemp(path.join(os.tmpdir(), "gg-acp-home-"));
|
|
151
|
-
tmpProject = await fs.mkdtemp(path.join(os.tmpdir(), "gg-acp-project-"));
|
|
152
|
-
tmpOtherProject = await fs.mkdtemp(path.join(os.tmpdir(), "gg-acp-other-"));
|
|
153
|
-
});
|
|
154
|
-
afterEach(async () => {
|
|
155
|
-
client?.kill();
|
|
156
|
-
client = undefined;
|
|
157
|
-
await fs.rm(tmpHome, { recursive: true, force: true });
|
|
158
|
-
await fs.rm(tmpProject, { recursive: true, force: true });
|
|
159
|
-
await fs.rm(tmpOtherProject, { recursive: true, force: true });
|
|
160
|
-
});
|
|
161
|
-
/** Session updates only, unwrapped to the `update` payload. */
|
|
162
|
-
function updates(frames) {
|
|
163
|
-
return frames
|
|
164
|
-
.filter((frame) => frame.method === "session/update")
|
|
165
|
-
.map((frame) => frame.params.update);
|
|
166
|
-
}
|
|
167
|
-
/** Updates a session announces on its own schedule, not as part of a turn. */
|
|
168
|
-
const OUT_OF_BAND_UPDATES = new Set([
|
|
169
|
-
"available_commands_update",
|
|
170
|
-
"usage_update",
|
|
171
|
-
"session_info_update",
|
|
172
|
-
]);
|
|
173
|
-
/**
|
|
174
|
-
* Conversation updates only.
|
|
175
|
-
*
|
|
176
|
-
* The command list and the context-usage report are announced on their own
|
|
177
|
-
* schedule after a session opens, so an exact-match transcript assertion would
|
|
178
|
-
* otherwise pass or fail on timing.
|
|
179
|
-
*/
|
|
180
|
-
function transcript(frames) {
|
|
181
|
-
return updates(frames).filter((update) => !OUT_OF_BAND_UPDATES.has(update.sessionUpdate));
|
|
182
|
-
}
|
|
183
|
-
/** Context-usage notifications only, in arrival order. */
|
|
184
|
-
function usageUpdates(frames) {
|
|
185
|
-
return updates(frames).filter((update) => update.sessionUpdate === "usage_update");
|
|
186
|
-
}
|
|
187
|
-
/** Every update of one kind, in arrival order. */
|
|
188
|
-
function updatesOfKind(frames, kind) {
|
|
189
|
-
return updates(frames).filter((update) => update.sessionUpdate === kind);
|
|
190
|
-
}
|
|
191
|
-
describe("ACP mode over stdio", () => {
|
|
192
|
-
it("negotiates initialize and creates a session", async () => {
|
|
193
|
-
client = new AcpClient();
|
|
194
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
195
|
-
const frames = await client.until(1);
|
|
196
|
-
const initialize = frames.at(-1);
|
|
197
|
-
expect(initialize.jsonrpc).toBe("2.0");
|
|
198
|
-
expect(initialize.result).toMatchObject({
|
|
199
|
-
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
200
|
-
authMethods: [],
|
|
201
|
-
agentInfo: { name: "ggcoder", title: "GG Coder", version: "0.0.0-test" },
|
|
202
|
-
});
|
|
203
|
-
// A client only offers resume and a session list when these are advertised,
|
|
204
|
-
// and `{}` — not `true` — is how ACP spells "supported" for these two.
|
|
205
|
-
expect(initialize.result.agentCapabilities).toMatchObject({
|
|
206
|
-
loadSession: true,
|
|
207
|
-
sessionCapabilities: { list: {}, resume: {}, close: {}, delete: {} },
|
|
208
|
-
});
|
|
209
|
-
client.send({ jsonrpc: "2.0", id: 2, method: "session/new", params: { cwd: tmpProject } });
|
|
210
|
-
const created = (await client.until(2)).at(-1);
|
|
211
|
-
expect(created.result.sessionId).toBe("acp-fixture-session");
|
|
212
|
-
});
|
|
213
|
-
it("lists sessions from every project, newest first, titled by their first user prompt", async () => {
|
|
214
|
-
client = new AcpClient();
|
|
215
|
-
await client.handshake();
|
|
216
|
-
const sessions = await client.list();
|
|
217
|
-
// No `cwd` means the whole machine, so the other checkout's session must be
|
|
218
|
-
// here too — a phone asks "what have I been working on", not "what is in
|
|
219
|
-
// this one directory". The empty seeded session must NOT appear: there is
|
|
220
|
-
// nothing to resume.
|
|
221
|
-
expect(sessions).toHaveLength(3);
|
|
222
|
-
expect(sessions.map((entry) => entry.title)).toEqual([
|
|
223
|
-
"other project: fix the parser",
|
|
224
|
-
"newer: add the config panel",
|
|
225
|
-
"older: rename the widget",
|
|
226
|
-
]);
|
|
227
|
-
// Each entry carries its own project, which is what lets a client group by
|
|
228
|
-
// checkout instead of showing one flat undifferentiated list.
|
|
229
|
-
expect(sessions.map((entry) => entry.cwd)).toEqual([tmpOtherProject, tmpProject, tmpProject]);
|
|
230
|
-
for (const entry of sessions)
|
|
231
|
-
expect(Date.parse(entry.updatedAt)).not.toBeNaN();
|
|
232
|
-
// Ids must be the ones the fixture actually wrote, or `session/load` is
|
|
233
|
-
// addressing something that does not exist.
|
|
234
|
-
expect(client.stderr).toContain(sessions[0].sessionId);
|
|
235
|
-
expect(client.stderr).toContain(sessions[1].sessionId);
|
|
236
|
-
});
|
|
237
|
-
it("scopes the list to one project when a cwd is given", async () => {
|
|
238
|
-
client = new AcpClient();
|
|
239
|
-
await client.handshake();
|
|
240
|
-
const scoped = await client.list(90, tmpProject);
|
|
241
|
-
expect(scoped.map((entry) => entry.title)).toEqual([
|
|
242
|
-
"newer: add the config panel",
|
|
243
|
-
"older: rename the widget",
|
|
244
|
-
]);
|
|
245
|
-
for (const entry of scoped)
|
|
246
|
-
expect(entry.cwd).toBe(tmpProject);
|
|
247
|
-
});
|
|
248
|
-
it("replays a loaded session's transcript before answering, then resumes it", async () => {
|
|
249
|
-
client = new AcpClient();
|
|
250
|
-
await client.handshake();
|
|
251
|
-
const [newest] = await client.list(90, tmpProject);
|
|
252
|
-
client.send({
|
|
253
|
-
jsonrpc: "2.0",
|
|
254
|
-
id: 91,
|
|
255
|
-
method: "session/load",
|
|
256
|
-
params: { sessionId: newest.sessionId, cwd: tmpProject, mcpServers: [] },
|
|
257
|
-
});
|
|
258
|
-
const frames = await client.until(91);
|
|
259
|
-
const replay = frames.filter((frame) => frame.method === "session/update" &&
|
|
260
|
-
!OUT_OF_BAND_UPDATES.has(frame.params.update.sessionUpdate));
|
|
261
|
-
// History must arrive BEFORE the response: a client draws a resumed session
|
|
262
|
-
// with its live-turn renderer, so anything after the reply lands nowhere.
|
|
263
|
-
expect(replay.length).toBeGreaterThan(0);
|
|
264
|
-
expect(frames.at(-1).id).toBe(91);
|
|
265
|
-
for (const frame of replay)
|
|
266
|
-
expect(frame.params.sessionId).toBe(newest.sessionId);
|
|
267
|
-
expect(transcript(frames)).toEqual([
|
|
268
|
-
{
|
|
269
|
-
sessionUpdate: "user_message_chunk",
|
|
270
|
-
// Chunks carry the message they belong to, so a client can group them
|
|
271
|
-
// into bubbles instead of guessing at boundaries.
|
|
272
|
-
messageId: "hist-1",
|
|
273
|
-
content: { type: "text", text: "newer: add the config panel" },
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
sessionUpdate: "agent_message_chunk",
|
|
277
|
-
messageId: "hist-2",
|
|
278
|
-
content: { type: "text", text: "Reading the panel first." },
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
sessionUpdate: "tool_call",
|
|
282
|
-
toolCallId: "call-1",
|
|
283
|
-
title: "read(/panel.tsx)",
|
|
284
|
-
name: "read",
|
|
285
|
-
kind: "read",
|
|
286
|
-
// A replayed call is settled; `in_progress` would spin forever.
|
|
287
|
-
status: "completed",
|
|
288
|
-
rawInput: { file_path: "/panel.tsx" },
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
sessionUpdate: "tool_call_update",
|
|
292
|
-
toolCallId: "call-1",
|
|
293
|
-
status: "completed",
|
|
294
|
-
content: [{ type: "content", content: { type: "text", text: "panel source" } }],
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
sessionUpdate: "agent_message_chunk",
|
|
298
|
-
messageId: "hist-3",
|
|
299
|
-
content: { type: "text", text: "Added the config panel." },
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
sessionUpdate: "user_message_chunk",
|
|
303
|
-
messageId: "hist-4",
|
|
304
|
-
content: { type: "text", text: "after first compaction" },
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
sessionUpdate: "agent_message_chunk",
|
|
308
|
-
messageId: "hist-5",
|
|
309
|
-
content: { type: "text", text: "First follow-up complete." },
|
|
310
|
-
},
|
|
311
|
-
{
|
|
312
|
-
sessionUpdate: "user_message_chunk",
|
|
313
|
-
messageId: "hist-6",
|
|
314
|
-
content: { type: "text", text: "after second compaction" },
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
sessionUpdate: "agent_message_chunk",
|
|
318
|
-
messageId: "hist-7",
|
|
319
|
-
content: { type: "text", text: "Second follow-up complete." },
|
|
320
|
-
},
|
|
321
|
-
]);
|
|
322
|
-
const replayText = transcript(frames)
|
|
323
|
-
.map((update) => update.content?.text ?? "")
|
|
324
|
-
.join("\n");
|
|
325
|
-
expect(replayText).not.toContain("replacement summary");
|
|
326
|
-
// Resuming is worthless if the session cannot then be prompted, and the
|
|
327
|
-
// client must keep addressing it by the id it asked to load.
|
|
328
|
-
client.send({
|
|
329
|
-
jsonrpc: "2.0",
|
|
330
|
-
id: 92,
|
|
331
|
-
method: "session/prompt",
|
|
332
|
-
params: { sessionId: newest.sessionId, prompt: [{ type: "text", text: "again" }] },
|
|
333
|
-
});
|
|
334
|
-
const turn = await client.until(92);
|
|
335
|
-
expect(turn.at(-1).result).toEqual({ stopReason: "end_turn" });
|
|
336
|
-
expect(turn
|
|
337
|
-
.filter((frame) => frame.method === "session/update" &&
|
|
338
|
-
!OUT_OF_BAND_UPDATES.has(frame.params.update.sessionUpdate))
|
|
339
|
-
.every((frame) => frame.params.sessionId === newest.sessionId)).toBe(true);
|
|
340
|
-
// Full replay is display-only: prompting still sees only generation 2.
|
|
341
|
-
const contextStart = client.received().length;
|
|
342
|
-
client.send({
|
|
343
|
-
jsonrpc: "2.0",
|
|
344
|
-
id: 93,
|
|
345
|
-
method: "session/prompt",
|
|
346
|
-
params: {
|
|
347
|
-
sessionId: newest.sessionId,
|
|
348
|
-
prompt: [{ type: "text", text: "report loaded context" }],
|
|
349
|
-
},
|
|
350
|
-
});
|
|
351
|
-
const contextFrames = (await client.until(93)).slice(contextStart);
|
|
352
|
-
const contextText = transcript(contextFrames)
|
|
353
|
-
.map((update) => update.content?.text ?? "")
|
|
354
|
-
.join("\n");
|
|
355
|
-
expect(contextText).toContain("second replacement summary");
|
|
356
|
-
expect(contextText).toContain("after second compaction");
|
|
357
|
-
expect(contextText).not.toContain("newer: add the config panel");
|
|
358
|
-
});
|
|
359
|
-
it("loads a session listed under a different cwd than the one it is opened with", async () => {
|
|
360
|
-
client = new AcpClient();
|
|
361
|
-
await client.handshake();
|
|
362
|
-
const [newest] = await client.list(90, tmpProject);
|
|
363
|
-
// Exactly what pew2 does: its capability probe lists from its own working
|
|
364
|
-
// directory, then resumes against the project the session belongs to. A
|
|
365
|
-
// cwd-scoped lookup fails here, so this is the regression that matters.
|
|
366
|
-
client.send({
|
|
367
|
-
jsonrpc: "2.0",
|
|
368
|
-
id: 91,
|
|
369
|
-
method: "session/load",
|
|
370
|
-
params: { sessionId: newest.sessionId, cwd: os.tmpdir(), mcpServers: [] },
|
|
371
|
-
});
|
|
372
|
-
const frames = await client.until(91);
|
|
373
|
-
expect(frames.at(-1).error).toBeUndefined();
|
|
374
|
-
expect(transcript(frames)[0]).toEqual({
|
|
375
|
-
sessionUpdate: "user_message_chunk",
|
|
376
|
-
messageId: "hist-1",
|
|
377
|
-
content: { type: "text", text: "newer: add the config panel" },
|
|
378
|
-
});
|
|
379
|
-
});
|
|
380
|
-
it("replays a compaction summary when the parent checkpoint is missing", async () => {
|
|
381
|
-
client = new AcpClient();
|
|
382
|
-
await client.handshake();
|
|
383
|
-
const stored = await client.list(90, tmpProject);
|
|
384
|
-
const older = stored.find((entry) => entry.title === "older: rename the widget");
|
|
385
|
-
client.send({
|
|
386
|
-
jsonrpc: "2.0",
|
|
387
|
-
id: 91,
|
|
388
|
-
method: "session/load",
|
|
389
|
-
params: { sessionId: older.sessionId, cwd: tmpProject, mcpServers: [] },
|
|
390
|
-
});
|
|
391
|
-
const frames = await client.until(91);
|
|
392
|
-
expect(transcript(frames)).toEqual([
|
|
393
|
-
{
|
|
394
|
-
sessionUpdate: "user_message_chunk",
|
|
395
|
-
messageId: "hist-1",
|
|
396
|
-
content: {
|
|
397
|
-
type: "text",
|
|
398
|
-
text: "[Previous conversation summary]\n\nolder fallback summary",
|
|
399
|
-
},
|
|
400
|
-
},
|
|
401
|
-
{
|
|
402
|
-
sessionUpdate: "agent_message_chunk",
|
|
403
|
-
messageId: "hist-2",
|
|
404
|
-
content: { type: "text", text: "Recovered from summary." },
|
|
405
|
-
},
|
|
406
|
-
]);
|
|
407
|
-
});
|
|
408
|
-
it("refuses to load a session that does not exist", async () => {
|
|
409
|
-
client = new AcpClient();
|
|
410
|
-
await client.handshake();
|
|
411
|
-
client.send({
|
|
412
|
-
jsonrpc: "2.0",
|
|
413
|
-
id: 91,
|
|
414
|
-
method: "session/load",
|
|
415
|
-
params: { sessionId: "no-such-session", cwd: tmpProject, mcpServers: [] },
|
|
416
|
-
});
|
|
417
|
-
expect((await client.until(91)).at(-1).error).toMatchObject({
|
|
418
|
-
code: -32602,
|
|
419
|
-
message: expect.stringContaining("no-such-session"),
|
|
420
|
-
});
|
|
421
|
-
});
|
|
422
|
-
it("advertises model and thinking selectors, and applies changes to both", async () => {
|
|
423
|
-
client = new AcpClient();
|
|
424
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
425
|
-
await client.until(1);
|
|
426
|
-
client.send({
|
|
427
|
-
jsonrpc: "2.0",
|
|
428
|
-
id: 2,
|
|
429
|
-
method: "session/new",
|
|
430
|
-
params: { cwd: tmpProject, mcpServers: [] },
|
|
431
|
-
});
|
|
432
|
-
const created = (await client.until(2)).at(-1);
|
|
433
|
-
const initial = created.result.configOptions;
|
|
434
|
-
const model = initial.find((option) => option.id === "model");
|
|
435
|
-
const thinking = initial.find((option) => option.id === "thinking");
|
|
436
|
-
// Categories are what let a client place these correctly without knowing
|
|
437
|
-
// anything about ggcoder.
|
|
438
|
-
expect(model).toMatchObject({ category: "model", type: "select" });
|
|
439
|
-
expect(thinking).toMatchObject({ category: "thought_level", type: "select" });
|
|
440
|
-
expect(model.currentValue).toBe("claude-opus-5");
|
|
441
|
-
expect(model.options.length).toBeGreaterThan(1);
|
|
442
|
-
expect(model.options.some((option) => option.value === "claude-opus-5")).toBe(true);
|
|
443
|
-
expect(thinking.currentValue).toBe("off");
|
|
444
|
-
expect(thinking.options[0]).toMatchObject({ value: "off" });
|
|
445
|
-
client.send({
|
|
446
|
-
jsonrpc: "2.0",
|
|
447
|
-
id: 3,
|
|
448
|
-
method: "session/set_config_option",
|
|
449
|
-
params: { sessionId: "acp-fixture-session", configId: "thinking", value: "high" },
|
|
450
|
-
});
|
|
451
|
-
const afterThinking = (await client.until(3)).at(-1).result.configOptions;
|
|
452
|
-
// The reply must carry the COMPLETE set, not just the field that changed.
|
|
453
|
-
expect(afterThinking.map((option) => option.id).sort()).toEqual(["mode", "model", "thinking"]);
|
|
454
|
-
expect(afterThinking.find((option) => option.id === "thinking").currentValue).toBe("high");
|
|
455
|
-
client.send({
|
|
456
|
-
jsonrpc: "2.0",
|
|
457
|
-
id: 4,
|
|
458
|
-
method: "session/set_config_option",
|
|
459
|
-
params: {
|
|
460
|
-
sessionId: "acp-fixture-session",
|
|
461
|
-
configId: "model",
|
|
462
|
-
value: "claude-haiku-4-5-20251001",
|
|
463
|
-
},
|
|
464
|
-
});
|
|
465
|
-
const afterModel = (await client.until(4)).at(-1).result.configOptions;
|
|
466
|
-
expect(afterModel.find((option) => option.id === "model").currentValue).toBe("claude-haiku-4-5-20251001");
|
|
467
|
-
// Haiku's ceiling is `high`, so the ladder must shrink with the model rather
|
|
468
|
-
// than keep offering a level it would silently ignore.
|
|
469
|
-
const haikuLevels = afterModel.find((option) => option.id === "thinking").options;
|
|
470
|
-
expect(haikuLevels.some((option) => option.value === "max")).toBe(false);
|
|
471
|
-
expect(haikuLevels.at(-1)).toMatchObject({ value: "high" });
|
|
472
|
-
// The level set before the switch is still legal here, so it must survive.
|
|
473
|
-
expect(afterModel.find((option) => option.id === "thinking").currentValue).toBe("high");
|
|
474
|
-
});
|
|
475
|
-
it("clamps a thinking level the newly selected model cannot reach", async () => {
|
|
476
|
-
client = new AcpClient();
|
|
477
|
-
await client.handshake();
|
|
478
|
-
client.send({
|
|
479
|
-
jsonrpc: "2.0",
|
|
480
|
-
id: 3,
|
|
481
|
-
method: "session/set_config_option",
|
|
482
|
-
params: { sessionId: "acp-fixture-session", configId: "thinking", value: "max" },
|
|
483
|
-
});
|
|
484
|
-
await client.until(3);
|
|
485
|
-
client.send({
|
|
486
|
-
jsonrpc: "2.0",
|
|
487
|
-
id: 4,
|
|
488
|
-
method: "session/set_config_option",
|
|
489
|
-
params: {
|
|
490
|
-
sessionId: "acp-fixture-session",
|
|
491
|
-
configId: "model",
|
|
492
|
-
value: "claude-haiku-4-5-20251001",
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
const options = (await client.until(4)).at(-1).result.configOptions;
|
|
496
|
-
// Reporting `max` here would be a control that lies: Haiku has no such tier,
|
|
497
|
-
// so the session's real effort is `high` and the client must be told that.
|
|
498
|
-
expect(options.find((option) => option.id === "thinking").currentValue).toBe("high");
|
|
499
|
-
});
|
|
500
|
-
it("advertises plan mode in both the config options and the modes block", async () => {
|
|
501
|
-
client = new AcpClient();
|
|
502
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
503
|
-
await client.until(1);
|
|
504
|
-
client.send({
|
|
505
|
-
jsonrpc: "2.0",
|
|
506
|
-
id: 2,
|
|
507
|
-
method: "session/new",
|
|
508
|
-
params: { cwd: tmpProject, mcpServers: [] },
|
|
509
|
-
});
|
|
510
|
-
const created = (await client.until(2)).at(-1).result;
|
|
511
|
-
// Two surfaces, one truth: spec clients (Zed) read `modes`; pew2 reads the
|
|
512
|
-
// config option. They must agree or the two pickers would disagree.
|
|
513
|
-
expect(created.modes).toEqual({
|
|
514
|
-
currentModeId: "default",
|
|
515
|
-
availableModes: [
|
|
516
|
-
{ id: "default", name: "Default", description: "Full tool access" },
|
|
517
|
-
{ id: "plan", name: "Plan", description: "Read-only research until a plan is approved" },
|
|
518
|
-
],
|
|
519
|
-
});
|
|
520
|
-
const mode = created.configOptions.find((option) => option.id === "mode");
|
|
521
|
-
expect(mode).toMatchObject({ category: "mode", type: "select", currentValue: "default" });
|
|
522
|
-
expect(mode.options.map((option) => option.value)).toEqual(["default", "plan"]);
|
|
523
|
-
});
|
|
524
|
-
it("announces available commands after session/new, merging built-ins with project files", async () => {
|
|
525
|
-
// A project command, and one whose name collides with a built-in template.
|
|
526
|
-
const commandsDir = path.join(tmpProject, ".gg", "commands");
|
|
527
|
-
await fs.mkdir(commandsDir, { recursive: true });
|
|
528
|
-
await fs.writeFile(path.join(commandsDir, "commit.md"), "---\nname: commit\ndescription: Check, review, commit and push\n---\n\nRun the checks.\n");
|
|
529
|
-
await fs.writeFile(path.join(commandsDir, "init.md"), "---\nname: init\ndescription: Shadowed by the built-in\n---\n\nNever runs.\n");
|
|
530
|
-
// A project file whose name collides with a REGISTRY command (the fixture
|
|
531
|
-
// registers `/new`). The session resolves a template body before consulting
|
|
532
|
-
// the registry, so this file really is what `/new` runs here.
|
|
533
|
-
await fs.writeFile(path.join(commandsDir, "new.md"), "---\nname: new\ndescription: Project override of the registry command\n---\n\nRuns.\n");
|
|
534
|
-
client = new AcpClient();
|
|
535
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
536
|
-
await client.until(1);
|
|
537
|
-
client.send({
|
|
538
|
-
jsonrpc: "2.0",
|
|
539
|
-
id: 2,
|
|
540
|
-
method: "session/new",
|
|
541
|
-
params: { cwd: tmpProject, mcpServers: [] },
|
|
542
|
-
});
|
|
543
|
-
const frames = await client.until(2);
|
|
544
|
-
// The announcement must not overtake the response that names the session.
|
|
545
|
-
expect(updates(frames).some((u) => u.sessionUpdate === "available_commands_update")).toBe(false);
|
|
546
|
-
const update = await client.untilUpdate("available_commands_update");
|
|
547
|
-
const commands = update.availableCommands;
|
|
548
|
-
const byName = new Map(commands.map((command) => [command.name, command]));
|
|
549
|
-
// A built-in the client could not have discovered by scanning the disk.
|
|
550
|
-
expect(byName.get("expand")).toMatchObject({
|
|
551
|
-
description: expect.any(String),
|
|
552
|
-
input: { hint: expect.any(String) },
|
|
553
|
-
});
|
|
554
|
-
// A project file, carried with its own frontmatter description.
|
|
555
|
-
expect(byName.get("commit").description).toBe("Check, review, commit and push");
|
|
556
|
-
// Collisions resolve the way the session itself resolves them: a built-in
|
|
557
|
-
// template beats a project file, and it is listed once.
|
|
558
|
-
expect(commands.filter((command) => command.name === "init")).toHaveLength(1);
|
|
559
|
-
expect(byName.get("init").description).toBe("Generate or update CLAUDE.md for this project");
|
|
560
|
-
// ...but a project file beats a REGISTRY command, because that is the order
|
|
561
|
-
// `resolveSlashInput` uses. Advertising the registry's `/new` here would
|
|
562
|
-
// describe something the agent would never run.
|
|
563
|
-
expect(commands.filter((command) => command.name === "new")).toHaveLength(1);
|
|
564
|
-
expect(byName.get("new").description).toBe("Project override of the registry command");
|
|
565
|
-
// A registry command with no collision is listed, with a hint parsed from
|
|
566
|
-
// its usage rather than the template hint.
|
|
567
|
-
expect(byName.get("quit")).toEqual({ name: "quit", description: "Exit the agent" });
|
|
568
|
-
// Aliases are not separate commands: /quit ships `q` and `exit`, and only
|
|
569
|
-
// the canonical name is advertised.
|
|
570
|
-
expect(byName.has("q")).toBe(false);
|
|
571
|
-
expect(byName.has("exit")).toBe(false);
|
|
572
|
-
});
|
|
573
|
-
it("switches mode via session/set_mode and tells the client with current_mode_update", async () => {
|
|
574
|
-
client = new AcpClient();
|
|
575
|
-
const sessionId = await client.handshake();
|
|
576
|
-
client.send({
|
|
577
|
-
jsonrpc: "2.0",
|
|
578
|
-
id: 3,
|
|
579
|
-
method: "session/set_mode",
|
|
580
|
-
params: { sessionId, modeId: "plan" },
|
|
581
|
-
});
|
|
582
|
-
const frames = await client.until(3);
|
|
583
|
-
expect(frames.at(-1).result).toEqual({});
|
|
584
|
-
const notes = transcript(frames);
|
|
585
|
-
expect(notes[0]).toEqual({ sessionUpdate: "current_mode_update", currentModeId: "plan" });
|
|
586
|
-
// The full option set rides along so a client tracking config sees the
|
|
587
|
-
// same truth the modes block would tell it.
|
|
588
|
-
const configNote = notes.find((u) => u.sessionUpdate === "config_option_update");
|
|
589
|
-
expect((configNote.configOptions ?? []).find((o) => o.id === "mode")
|
|
590
|
-
.currentValue).toBe("plan");
|
|
591
|
-
// And back — via the config-option route pew2 actually uses.
|
|
592
|
-
client.send({
|
|
593
|
-
jsonrpc: "2.0",
|
|
594
|
-
id: 4,
|
|
595
|
-
method: "session/set_config_option",
|
|
596
|
-
params: { sessionId, configId: "mode", value: "default" },
|
|
597
|
-
});
|
|
598
|
-
const back = (await client.until(4)).at(-1).result.configOptions;
|
|
599
|
-
expect(back.find((option) => option.id === "mode").currentValue).toBe("default");
|
|
600
|
-
});
|
|
601
|
-
it("rejects an unknown mode", async () => {
|
|
602
|
-
client = new AcpClient();
|
|
603
|
-
const sessionId = await client.handshake();
|
|
604
|
-
client.send({
|
|
605
|
-
jsonrpc: "2.0",
|
|
606
|
-
id: 3,
|
|
607
|
-
method: "session/set_mode",
|
|
608
|
-
params: { sessionId, modeId: "yolo" },
|
|
609
|
-
});
|
|
610
|
-
expect((await client.until(3)).at(-1).error).toMatchObject({
|
|
611
|
-
code: -32602,
|
|
612
|
-
message: expect.stringContaining("yolo"),
|
|
613
|
-
});
|
|
614
|
-
});
|
|
615
|
-
it("rejects config values the active model cannot honour", async () => {
|
|
616
|
-
client = new AcpClient();
|
|
617
|
-
await client.handshake();
|
|
618
|
-
client.send({
|
|
619
|
-
jsonrpc: "2.0",
|
|
620
|
-
id: 3,
|
|
621
|
-
method: "session/set_config_option",
|
|
622
|
-
params: { sessionId: "acp-fixture-session", configId: "model", value: "not-a-model" },
|
|
623
|
-
});
|
|
624
|
-
expect((await client.until(3)).at(-1).error).toMatchObject({
|
|
625
|
-
code: -32602,
|
|
626
|
-
message: expect.stringContaining("not-a-model"),
|
|
627
|
-
});
|
|
628
|
-
client.send({
|
|
629
|
-
jsonrpc: "2.0",
|
|
630
|
-
id: 4,
|
|
631
|
-
method: "session/set_config_option",
|
|
632
|
-
params: { sessionId: "acp-fixture-session", configId: "nonsense", value: "x" },
|
|
633
|
-
});
|
|
634
|
-
expect((await client.until(4)).at(-1).error).toMatchObject({ code: -32602 });
|
|
635
|
-
});
|
|
636
|
-
it("maps the event bus onto session/update notifications, then answers with a stopReason", async () => {
|
|
637
|
-
client = new AcpClient();
|
|
638
|
-
const sessionId = await client.handshake();
|
|
639
|
-
client.send({
|
|
640
|
-
jsonrpc: "2.0",
|
|
641
|
-
id: 3,
|
|
642
|
-
method: "session/prompt",
|
|
643
|
-
params: { sessionId, prompt: [{ type: "text", text: "world" }] },
|
|
644
|
-
});
|
|
645
|
-
const frames = await client.until(3);
|
|
646
|
-
const turn = frames.filter((frame) => frame.method === "session/update" || frame.id === 3);
|
|
647
|
-
// Every notification for the turn must arrive BEFORE its response, or a
|
|
648
|
-
// client renders the finished turn with no content in it.
|
|
649
|
-
expect(turn.at(-1).result).toEqual({ stopReason: "end_turn" });
|
|
650
|
-
expect(turn.slice(0, -1).every((frame) => frame.method === "session/update")).toBe(true);
|
|
651
|
-
for (const frame of frames.filter((f) => f.method === "session/update")) {
|
|
652
|
-
expect(frame.params.sessionId).toBe(sessionId);
|
|
653
|
-
}
|
|
654
|
-
expect(transcript(frames)).toEqual([
|
|
655
|
-
{ sessionUpdate: "agent_thought_chunk", content: { type: "text", text: "planning" } },
|
|
656
|
-
// Both deltas belong to the same message, so they share an id; the tool
|
|
657
|
-
// call below ends it, and anything after starts a new one.
|
|
658
|
-
{
|
|
659
|
-
sessionUpdate: "agent_message_chunk",
|
|
660
|
-
messageId: "msg-1",
|
|
661
|
-
content: { type: "text", text: "Hello " },
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
sessionUpdate: "agent_message_chunk",
|
|
665
|
-
messageId: "msg-1",
|
|
666
|
-
content: { type: "text", text: "world" },
|
|
667
|
-
},
|
|
668
|
-
{
|
|
669
|
-
sessionUpdate: "tool_call",
|
|
670
|
-
toolCallId: "t1",
|
|
671
|
-
title: "read(/tmp/example.ts)",
|
|
672
|
-
name: "read",
|
|
673
|
-
kind: "read",
|
|
674
|
-
status: "in_progress",
|
|
675
|
-
rawInput: { file_path: "/tmp/example.ts" },
|
|
676
|
-
// Drives "follow the agent": the client opens the file being read.
|
|
677
|
-
locations: [{ path: "/tmp/example.ts" }],
|
|
678
|
-
},
|
|
679
|
-
{
|
|
680
|
-
sessionUpdate: "tool_call_update",
|
|
681
|
-
toolCallId: "t1",
|
|
682
|
-
status: "in_progress",
|
|
683
|
-
rawOutput: { progress: 0.5 },
|
|
684
|
-
},
|
|
685
|
-
{
|
|
686
|
-
sessionUpdate: "tool_call_update",
|
|
687
|
-
toolCallId: "t1",
|
|
688
|
-
status: "completed",
|
|
689
|
-
content: [{ type: "content", content: { type: "text", text: "file contents" } }],
|
|
690
|
-
},
|
|
691
|
-
{
|
|
692
|
-
sessionUpdate: "tool_call",
|
|
693
|
-
toolCallId: "t2",
|
|
694
|
-
title: "bash(exit 1)",
|
|
695
|
-
name: "bash",
|
|
696
|
-
kind: "execute",
|
|
697
|
-
status: "in_progress",
|
|
698
|
-
rawInput: { command: "exit 1" },
|
|
699
|
-
},
|
|
700
|
-
{
|
|
701
|
-
sessionUpdate: "tool_call_update",
|
|
702
|
-
toolCallId: "t2",
|
|
703
|
-
status: "failed",
|
|
704
|
-
content: [{ type: "content", content: { type: "text", text: "boom" } }],
|
|
705
|
-
},
|
|
706
|
-
]);
|
|
707
|
-
});
|
|
708
|
-
it("reports context usage after session/new, before any prompt runs", async () => {
|
|
709
|
-
client = new AcpClient();
|
|
710
|
-
const sessionId = await client.handshake();
|
|
711
|
-
const usage = await client.untilUpdate("usage_update");
|
|
712
|
-
// A fresh session must show its window immediately: a client that only
|
|
713
|
-
// learns the size after the first reply cannot draw a context meter.
|
|
714
|
-
expect(usage).toEqual({ sessionUpdate: "usage_update", used: 4200, size: 200_000 });
|
|
715
|
-
const frame = client
|
|
716
|
-
.received()
|
|
717
|
-
.find((f) => f.params?.update?.sessionUpdate === "usage_update");
|
|
718
|
-
expect(frame.params.sessionId).toBe(sessionId);
|
|
719
|
-
});
|
|
720
|
-
it("reports context usage on session/load so a resumed conversation shows it", async () => {
|
|
721
|
-
client = new AcpClient();
|
|
722
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
723
|
-
await client.until(1);
|
|
724
|
-
const [newest] = await client.list(90, tmpProject);
|
|
725
|
-
client.send({
|
|
726
|
-
jsonrpc: "2.0",
|
|
727
|
-
id: 91,
|
|
728
|
-
method: "session/load",
|
|
729
|
-
params: { sessionId: newest.sessionId, cwd: tmpProject, mcpServers: [] },
|
|
730
|
-
});
|
|
731
|
-
await client.until(91);
|
|
732
|
-
const usage = await client.untilUpdate("usage_update");
|
|
733
|
-
expect(usage).toEqual({ sessionUpdate: "usage_update", used: 4200, size: 200_000 });
|
|
734
|
-
// Addressed to the id the client asked to load, not the session's internal
|
|
735
|
-
// one, or the update lands on a session the client never heard of.
|
|
736
|
-
const frame = client
|
|
737
|
-
.received()
|
|
738
|
-
.find((f) => f.params?.update?.sessionUpdate === "usage_update");
|
|
739
|
-
expect(frame.params.sessionId).toBe(newest.sessionId);
|
|
740
|
-
});
|
|
741
|
-
it("reports context usage after each model response", async () => {
|
|
742
|
-
client = new AcpClient();
|
|
743
|
-
const sessionId = await client.handshake();
|
|
744
|
-
await client.untilUpdate("usage_update");
|
|
745
|
-
const beforeTurn = client.received().length;
|
|
746
|
-
client.send({
|
|
747
|
-
jsonrpc: "2.0",
|
|
748
|
-
id: 3,
|
|
749
|
-
method: "session/prompt",
|
|
750
|
-
params: { sessionId, prompt: [{ type: "text", text: "world" }] },
|
|
751
|
-
});
|
|
752
|
-
const frames = await client.until(3);
|
|
753
|
-
const turnUsage = usageUpdates(frames.slice(beforeTurn));
|
|
754
|
-
expect(turnUsage).toEqual([{ sessionUpdate: "usage_update", used: 9200, size: 200_000 }]);
|
|
755
|
-
// Like every other turn notification, it must precede the response.
|
|
756
|
-
expect(frames.at(-1).id).toBe(3);
|
|
757
|
-
});
|
|
758
|
-
it("reports the post-compaction count, so a client can see the drop", async () => {
|
|
759
|
-
client = new AcpClient();
|
|
760
|
-
const sessionId = await client.handshake();
|
|
761
|
-
await client.untilUpdate("usage_update");
|
|
762
|
-
const beforeTurn = client.received().length;
|
|
763
|
-
client.send({
|
|
764
|
-
jsonrpc: "2.0",
|
|
765
|
-
id: 3,
|
|
766
|
-
method: "session/prompt",
|
|
767
|
-
params: { sessionId, prompt: [{ type: "text", text: "compact me" }] },
|
|
768
|
-
});
|
|
769
|
-
const frames = await client.until(3);
|
|
770
|
-
// Compaction is invisible on the wire except as a fall in `used` at an
|
|
771
|
-
// unchanged `size`, so the emit right after it is the whole signal.
|
|
772
|
-
expect(usageUpdates(frames.slice(beforeTurn))).toEqual([
|
|
773
|
-
{ sessionUpdate: "usage_update", used: 900, size: 200_000 },
|
|
774
|
-
{
|
|
775
|
-
sessionUpdate: "usage_update",
|
|
776
|
-
used: 2400,
|
|
777
|
-
size: 200_000,
|
|
778
|
-
cost: { amount: 0.25, currency: "USD" },
|
|
779
|
-
},
|
|
780
|
-
]);
|
|
781
|
-
});
|
|
782
|
-
it("sends file edits as a real diff instead of the tool's prose", async () => {
|
|
783
|
-
client = new AcpClient();
|
|
784
|
-
const sessionId = await client.handshake();
|
|
785
|
-
client.send({
|
|
786
|
-
jsonrpc: "2.0",
|
|
787
|
-
id: 3,
|
|
788
|
-
method: "session/prompt",
|
|
789
|
-
params: { sessionId, prompt: [{ type: "text", text: "edit a file" }] },
|
|
790
|
-
});
|
|
791
|
-
const frames = await client.until(3);
|
|
792
|
-
const completed = updatesOfKind(frames, "tool_call_update");
|
|
793
|
-
// The BEFORE contents, captured while the tool was still running. Reading
|
|
794
|
-
// the file twice after the fact would report "after" as both sides.
|
|
795
|
-
expect(completed[0]).toMatchObject({
|
|
796
|
-
toolCallId: "d1",
|
|
797
|
-
status: "completed",
|
|
798
|
-
content: [
|
|
799
|
-
{
|
|
800
|
-
type: "diff",
|
|
801
|
-
path: path.join(tmpProject, "diffed.txt"),
|
|
802
|
-
oldText: "before\n",
|
|
803
|
-
newText: "after\n",
|
|
804
|
-
},
|
|
805
|
-
],
|
|
806
|
-
});
|
|
807
|
-
// A new file has no old side; ACP spells that as null, which clients render
|
|
808
|
-
// as an all-additions diff.
|
|
809
|
-
expect(completed[1]).toMatchObject({
|
|
810
|
-
toolCallId: "d2",
|
|
811
|
-
content: [
|
|
812
|
-
{
|
|
813
|
-
type: "diff",
|
|
814
|
-
path: path.join(tmpProject, "created.txt"),
|
|
815
|
-
oldText: null,
|
|
816
|
-
newText: "brand new\n",
|
|
817
|
-
},
|
|
818
|
-
],
|
|
819
|
-
});
|
|
820
|
-
// Relative tool arguments are resolved against the session cwd, since the
|
|
821
|
-
// client is running somewhere else and cannot resolve them itself.
|
|
822
|
-
const starts = updatesOfKind(frames, "tool_call");
|
|
823
|
-
expect(starts[1].locations).toEqual([{ path: path.join(tmpProject, "created.txt") }]);
|
|
824
|
-
});
|
|
825
|
-
it("publishes an approved plan and advances it from [DONE:n] markers", async () => {
|
|
826
|
-
client = new AcpClient();
|
|
827
|
-
const sessionId = await client.handshake();
|
|
828
|
-
client.send({
|
|
829
|
-
jsonrpc: "2.0",
|
|
830
|
-
id: 3,
|
|
831
|
-
method: "session/prompt",
|
|
832
|
-
params: { sessionId, prompt: [{ type: "text", text: "approve a plan" }] },
|
|
833
|
-
});
|
|
834
|
-
const frames = await client.until(3);
|
|
835
|
-
const plans = updatesOfKind(frames, "plan");
|
|
836
|
-
expect(plans).toHaveLength(2);
|
|
837
|
-
// On approval the whole plan appears, with the first step already active:
|
|
838
|
-
// steps run in order, so that is what the agent is doing right now.
|
|
839
|
-
expect(plans[0]).toEqual({
|
|
840
|
-
sessionUpdate: "plan",
|
|
841
|
-
entries: [
|
|
842
|
-
{ content: "Wire the transport layer", priority: "medium", status: "in_progress" },
|
|
843
|
-
{ content: "Render the results", priority: "medium", status: "pending" },
|
|
844
|
-
{ content: "Ship the thing", priority: "medium", status: "pending" },
|
|
845
|
-
],
|
|
846
|
-
});
|
|
847
|
-
// The marker was split across two text deltas and still registered.
|
|
848
|
-
expect(plans[1]).toEqual({
|
|
849
|
-
sessionUpdate: "plan",
|
|
850
|
-
entries: [
|
|
851
|
-
{ content: "Wire the transport layer", priority: "medium", status: "completed" },
|
|
852
|
-
{ content: "Render the results", priority: "medium", status: "in_progress" },
|
|
853
|
-
{ content: "Ship the thing", priority: "medium", status: "pending" },
|
|
854
|
-
],
|
|
855
|
-
});
|
|
856
|
-
});
|
|
857
|
-
it("names the session from its first prompt, once", async () => {
|
|
858
|
-
client = new AcpClient();
|
|
859
|
-
const sessionId = await client.handshake();
|
|
860
|
-
for (const id of [3, 4]) {
|
|
861
|
-
client.send({
|
|
862
|
-
jsonrpc: "2.0",
|
|
863
|
-
id,
|
|
864
|
-
method: "session/prompt",
|
|
865
|
-
params: { sessionId, prompt: [{ type: "text", text: `turn ${id}` }] },
|
|
866
|
-
});
|
|
867
|
-
await client.until(id);
|
|
868
|
-
}
|
|
869
|
-
const infos = updatesOfKind(client.received(), "session_info_update");
|
|
870
|
-
// Titled after the FIRST exchange and never renamed underneath the user.
|
|
871
|
-
expect(infos).toHaveLength(1);
|
|
872
|
-
expect(infos[0].title).toBe("turn 3");
|
|
873
|
-
expect(Date.parse(infos[0].updatedAt)).not.toBeNaN();
|
|
874
|
-
});
|
|
875
|
-
it("resumes a stored session without replaying its transcript", async () => {
|
|
876
|
-
client = new AcpClient();
|
|
877
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
878
|
-
await client.until(1);
|
|
879
|
-
const [newest] = await client.list(90, tmpProject);
|
|
880
|
-
client.send({
|
|
881
|
-
jsonrpc: "2.0",
|
|
882
|
-
id: 91,
|
|
883
|
-
method: "session/resume",
|
|
884
|
-
params: { sessionId: newest.sessionId, cwd: tmpProject, mcpServers: [] },
|
|
885
|
-
});
|
|
886
|
-
const frames = await client.until(91);
|
|
887
|
-
expect(frames.at(-1).error).toBeUndefined();
|
|
888
|
-
// The whole point of resume over load: the client already has the
|
|
889
|
-
// transcript, so pushing it a second copy is what it asked to avoid.
|
|
890
|
-
expect(transcript(frames)).toEqual([]);
|
|
891
|
-
// The context is genuinely restored, not merely reported as restored.
|
|
892
|
-
client.send({
|
|
893
|
-
jsonrpc: "2.0",
|
|
894
|
-
id: 92,
|
|
895
|
-
method: "session/prompt",
|
|
896
|
-
params: {
|
|
897
|
-
sessionId: newest.sessionId,
|
|
898
|
-
prompt: [{ type: "text", text: "report loaded context" }],
|
|
899
|
-
},
|
|
900
|
-
});
|
|
901
|
-
const answered = await client.until(92);
|
|
902
|
-
const replied = updatesOfKind(answered, "agent_message_chunk")
|
|
903
|
-
.map((update) => update.content.text)
|
|
904
|
-
.join("");
|
|
905
|
-
// Generation 2, exactly as `session/load` restores it: the live context is
|
|
906
|
-
// the newest checkpoint, not the pre-compaction transcript.
|
|
907
|
-
expect(replied).toContain("after second compaction");
|
|
908
|
-
expect(replied).not.toContain("newer: add the config panel");
|
|
909
|
-
});
|
|
910
|
-
it("closes an active session and refuses to close an unknown one", async () => {
|
|
911
|
-
client = new AcpClient();
|
|
912
|
-
const sessionId = await client.handshake();
|
|
913
|
-
client.send({
|
|
914
|
-
jsonrpc: "2.0",
|
|
915
|
-
id: 3,
|
|
916
|
-
method: "session/close",
|
|
917
|
-
params: { sessionId: "not-a-session" },
|
|
918
|
-
});
|
|
919
|
-
const rejected = (await client.until(3)).at(-1);
|
|
920
|
-
expect(rejected.error.code).toBe(-32602);
|
|
921
|
-
client.send({ jsonrpc: "2.0", id: 4, method: "session/close", params: { sessionId } });
|
|
922
|
-
const closed = (await client.until(4)).at(-1);
|
|
923
|
-
expect(closed.result).toEqual({});
|
|
924
|
-
// Closing frees the session, so prompting the closed id is now a client
|
|
925
|
-
// sequencing error rather than a silently ignored no-op.
|
|
926
|
-
client.send({
|
|
927
|
-
jsonrpc: "2.0",
|
|
928
|
-
id: 5,
|
|
929
|
-
method: "session/prompt",
|
|
930
|
-
params: { sessionId, prompt: [{ type: "text", text: "still there?" }] },
|
|
931
|
-
});
|
|
932
|
-
expect((await client.until(5)).at(-1).error.code).toBe(-32602);
|
|
933
|
-
});
|
|
934
|
-
it("waits for a cancelled turn to unwind before closing the session", async () => {
|
|
935
|
-
client = new AcpClient();
|
|
936
|
-
const sessionId = await client.handshake();
|
|
937
|
-
client.send({
|
|
938
|
-
jsonrpc: "2.0",
|
|
939
|
-
id: 3,
|
|
940
|
-
method: "session/prompt",
|
|
941
|
-
params: { sessionId, prompt: [{ type: "text", text: "hang" }] },
|
|
942
|
-
});
|
|
943
|
-
// Let the turn actually start, or close would tear down an idle session and
|
|
944
|
-
// the race this guards against could never happen.
|
|
945
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
946
|
-
client.send({ jsonrpc: "2.0", id: 4, method: "session/close", params: { sessionId } });
|
|
947
|
-
expect((await client.until(4)).at(-1).result).toEqual({});
|
|
948
|
-
// The cancelled turn resolves as cancelled, not as an error.
|
|
949
|
-
expect((await client.until(3)).at(-1).result).toEqual({ stopReason: "cancelled" });
|
|
950
|
-
// Close only SIGNALS the abort; the turn keeps unwinding and persists its
|
|
951
|
-
// tail on a later tick. Disposing without waiting drops that write, and a
|
|
952
|
-
// resumed session comes back missing its last exchange.
|
|
953
|
-
const witness = JSON.parse(await fs.readFile(path.join(tmpProject, "dispose-witness.json"), "utf8"));
|
|
954
|
-
expect(witness.disposedMidTurn).toBe(false);
|
|
955
|
-
});
|
|
956
|
-
it("deletes a stored session, and succeeds when it is already gone", async () => {
|
|
957
|
-
client = new AcpClient();
|
|
958
|
-
await client.handshake();
|
|
959
|
-
const before = await client.list(90, tmpProject);
|
|
960
|
-
const target = before.find((entry) => entry.title === "older: rename the widget");
|
|
961
|
-
client.send({
|
|
962
|
-
jsonrpc: "2.0",
|
|
963
|
-
id: 92,
|
|
964
|
-
method: "session/delete",
|
|
965
|
-
params: { sessionId: target.sessionId },
|
|
966
|
-
});
|
|
967
|
-
expect((await client.until(92)).at(-1).result).toEqual({});
|
|
968
|
-
const after = await client.list(93, tmpProject);
|
|
969
|
-
expect(after.map((entry) => entry.title)).not.toContain("older: rename the widget");
|
|
970
|
-
// Idempotent by spec: the user's intent is already satisfied, so deleting
|
|
971
|
-
// it again is a success, not an error.
|
|
972
|
-
client.send({
|
|
973
|
-
jsonrpc: "2.0",
|
|
974
|
-
id: 94,
|
|
975
|
-
method: "session/delete",
|
|
976
|
-
params: { sessionId: target.sessionId },
|
|
977
|
-
});
|
|
978
|
-
expect((await client.until(94)).at(-1).result).toEqual({});
|
|
979
|
-
});
|
|
980
|
-
it("reports a refusal as its own stop reason", async () => {
|
|
981
|
-
client = new AcpClient();
|
|
982
|
-
const sessionId = await client.handshake();
|
|
983
|
-
client.send({
|
|
984
|
-
jsonrpc: "2.0",
|
|
985
|
-
id: 3,
|
|
986
|
-
method: "session/prompt",
|
|
987
|
-
params: { sessionId, prompt: [{ type: "text", text: "refuse" }] },
|
|
988
|
-
});
|
|
989
|
-
expect((await client.until(3)).at(-1).result).toEqual({ stopReason: "refusal" });
|
|
990
|
-
});
|
|
991
|
-
it("resolves a cancelled turn with stopReason cancelled rather than an error", async () => {
|
|
992
|
-
client = new AcpClient();
|
|
993
|
-
const sessionId = await client.handshake();
|
|
994
|
-
client.send({
|
|
995
|
-
jsonrpc: "2.0",
|
|
996
|
-
id: 3,
|
|
997
|
-
method: "session/prompt",
|
|
998
|
-
params: { sessionId, prompt: [{ type: "text", text: "hang" }] },
|
|
999
|
-
});
|
|
1000
|
-
// Let the prompt actually start; cancelling before it does is a different
|
|
1001
|
-
// path and would make this test pass for the wrong reason.
|
|
1002
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
1003
|
-
client.send({ jsonrpc: "2.0", method: "session/cancel", params: { sessionId } });
|
|
1004
|
-
const frames = await client.until(3);
|
|
1005
|
-
expect(frames.at(-1).result).toEqual({ stopReason: "cancelled" });
|
|
1006
|
-
// A notification must never be answered — an id here is a protocol violation.
|
|
1007
|
-
expect(frames.some((frame) => frame.id === null && frame.error)).toBe(false);
|
|
1008
|
-
// Cancel ends ONE turn, not the session. This catches a stale aborted
|
|
1009
|
-
// signal: AgentSession swallows that abort, so without re-arming this next
|
|
1010
|
-
// request deceptively returns end_turn but streams no answer.
|
|
1011
|
-
client.send({
|
|
1012
|
-
jsonrpc: "2.0",
|
|
1013
|
-
id: 4,
|
|
1014
|
-
method: "session/prompt",
|
|
1015
|
-
params: { sessionId, prompt: [{ type: "text", text: "after cancel" }] },
|
|
1016
|
-
});
|
|
1017
|
-
const resumed = await client.until(4);
|
|
1018
|
-
expect(resumed.at(-1).result).toEqual({ stopReason: "end_turn" });
|
|
1019
|
-
expect(updates(resumed).some((update) => update.sessionUpdate === "agent_message_chunk" &&
|
|
1020
|
-
update.content?.text === "after cancel")).toBe(true);
|
|
1021
|
-
});
|
|
1022
|
-
it("rejects unknown methods and prompts sent before a session exists", async () => {
|
|
1023
|
-
client = new AcpClient();
|
|
1024
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: 1 } });
|
|
1025
|
-
await client.until(1);
|
|
1026
|
-
client.send({
|
|
1027
|
-
jsonrpc: "2.0",
|
|
1028
|
-
id: 2,
|
|
1029
|
-
method: "session/prompt",
|
|
1030
|
-
params: { prompt: [{ type: "text", text: "hi" }] },
|
|
1031
|
-
});
|
|
1032
|
-
expect((await client.until(2)).at(-1).error).toMatchObject({
|
|
1033
|
-
code: -32602,
|
|
1034
|
-
message: expect.stringContaining("session/new"),
|
|
1035
|
-
});
|
|
1036
|
-
// Unimplemented methods must be refused, not silently accepted, so a client
|
|
1037
|
-
// can fall back instead of hanging.
|
|
1038
|
-
client.send({ jsonrpc: "2.0", id: 3, method: "session/fork", params: {} });
|
|
1039
|
-
expect((await client.until(3)).at(-1).error).toMatchObject({ code: -32601 });
|
|
1040
|
-
});
|
|
1041
|
-
it("answers malformed input with a parse error and keeps serving", async () => {
|
|
1042
|
-
client = new AcpClient();
|
|
1043
|
-
client.send({ jsonrpc: "2.0", id: 1, method: "initialize", params: {} });
|
|
1044
|
-
await client.until(1);
|
|
1045
|
-
client.sendRaw("{ not json\n");
|
|
1046
|
-
client.send({ jsonrpc: "2.0", id: 2, method: "initialize", params: {} });
|
|
1047
|
-
const frames = await client.until(2);
|
|
1048
|
-
expect(frames.some((f) => f.id === null && f.error?.code === -32700)).toBe(true);
|
|
1049
|
-
expect(frames.at(-1).result.protocolVersion).toBe(ACP_PROTOCOL_VERSION);
|
|
1050
|
-
});
|
|
1051
|
-
it("disposes the session and exits cleanly when the client disconnects", async () => {
|
|
1052
|
-
client = new AcpClient();
|
|
1053
|
-
await client.handshake();
|
|
1054
|
-
client.end();
|
|
1055
|
-
expect(await client.exit).toBe(0);
|
|
1056
|
-
expect(client.stderr).toContain("disposed=true");
|
|
1057
|
-
});
|
|
1058
|
-
// Every test in this suite spawns a real agent child process and seeds its
|
|
1059
|
-
// session files, which costs seconds on a loaded CI runner. The headroom sits
|
|
1060
|
-
// on the suite rather than on whichever tests happened to time out last, so a
|
|
1061
|
-
// slow machine is never reported as a bug.
|
|
1062
|
-
//
|
|
1063
|
-
// Kept above the 20s harness budget in `until`/`untilUpdate` so a genuine hang
|
|
1064
|
-
// surfaces their diagnostic (pending frames + child stderr) instead of
|
|
1065
|
-
// vitest's bare "Test timed out".
|
|
1066
|
-
}, 30_000);
|
|
1067
|
-
//# sourceMappingURL=acp-mode.test.js.map
|