@getpaseo/server 0.1.2
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/.env.example +20 -0
- package/README.md +107 -0
- package/agent-prompt.md +339 -0
- package/dist/scripts/daemon-runner.js +32 -0
- package/dist/scripts/daemon-runner.js.map +1 -0
- package/dist/scripts/dev-runner.js +19 -0
- package/dist/scripts/dev-runner.js.map +1 -0
- package/dist/scripts/mcp-stdio-socket-bridge-cli.mjs +62 -0
- package/dist/scripts/supervisor.js +95 -0
- package/dist/scripts/supervisor.js.map +1 -0
- package/dist/server/client/daemon-client.d.ts +383 -0
- package/dist/server/client/daemon-client.d.ts.map +1 -0
- package/dist/server/client/daemon-client.js +2443 -0
- package/dist/server/client/daemon-client.js.map +1 -0
- package/dist/server/server/agent/activity-curator.d.ts +8 -0
- package/dist/server/server/agent/activity-curator.d.ts.map +1 -0
- package/dist/server/server/agent/activity-curator.js +228 -0
- package/dist/server/server/agent/activity-curator.js.map +1 -0
- package/dist/server/server/agent/agent-management-mcp.d.ts +34 -0
- package/dist/server/server/agent/agent-management-mcp.d.ts.map +1 -0
- package/dist/server/server/agent/agent-management-mcp.js +619 -0
- package/dist/server/server/agent/agent-management-mcp.js.map +1 -0
- package/dist/server/server/agent/agent-manager.d.ts +182 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -0
- package/dist/server/server/agent/agent-manager.js +1066 -0
- package/dist/server/server/agent/agent-manager.js.map +1 -0
- package/dist/server/server/agent/agent-metadata-generator.d.ts +29 -0
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -0
- package/dist/server/server/agent/agent-metadata-generator.js +157 -0
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -0
- package/dist/server/server/agent/agent-projections.d.ts +12 -0
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -0
- package/dist/server/server/agent/agent-projections.js +238 -0
- package/dist/server/server/agent/agent-projections.js.map +1 -0
- package/dist/server/server/agent/agent-response-loop.d.ts +32 -0
- package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -0
- package/dist/server/server/agent/agent-response-loop.js +224 -0
- package/dist/server/server/agent/agent-response-loop.js.map +1 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts +360 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -0
- package/dist/server/server/agent/agent-sdk-types.js +2 -0
- package/dist/server/server/agent/agent-sdk-types.js.map +1 -0
- package/dist/server/server/agent/agent-storage.d.ts +187 -0
- package/dist/server/server/agent/agent-storage.d.ts.map +1 -0
- package/dist/server/server/agent/agent-storage.js +328 -0
- package/dist/server/server/agent/agent-storage.js.map +1 -0
- package/dist/server/server/agent/audio-utils.d.ts +3 -0
- package/dist/server/server/agent/audio-utils.d.ts.map +1 -0
- package/dist/server/server/agent/audio-utils.js +19 -0
- package/dist/server/server/agent/audio-utils.js.map +1 -0
- package/dist/server/server/agent/dictation-debug.d.ts +13 -0
- package/dist/server/server/agent/dictation-debug.d.ts.map +1 -0
- package/dist/server/server/agent/dictation-debug.js +50 -0
- package/dist/server/server/agent/dictation-debug.js.map +1 -0
- package/dist/server/server/agent/llm-openai.d.ts +7 -0
- package/dist/server/server/agent/llm-openai.d.ts.map +1 -0
- package/dist/server/server/agent/llm-openai.js +8 -0
- package/dist/server/server/agent/llm-openai.js.map +1 -0
- package/dist/server/server/agent/mcp-server.d.ts +26 -0
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -0
- package/dist/server/server/agent/mcp-server.js +762 -0
- package/dist/server/server/agent/mcp-server.js.map +1 -0
- package/dist/server/server/agent/model-resolver.d.ts +11 -0
- package/dist/server/server/agent/model-resolver.d.ts.map +1 -0
- package/dist/server/server/agent/model-resolver.js +21 -0
- package/dist/server/server/agent/model-resolver.js.map +1 -0
- package/dist/server/server/agent/orchestrator-instructions.d.ts +7 -0
- package/dist/server/server/agent/orchestrator-instructions.d.ts.map +1 -0
- package/dist/server/server/agent/orchestrator-instructions.js +51 -0
- package/dist/server/server/agent/orchestrator-instructions.js.map +1 -0
- package/dist/server/server/agent/orchestrator.d.ts +12 -0
- package/dist/server/server/agent/orchestrator.d.ts.map +1 -0
- package/dist/server/server/agent/orchestrator.js +12 -0
- package/dist/server/server/agent/orchestrator.js.map +1 -0
- package/dist/server/server/agent/pcm16-resampler.d.ts +14 -0
- package/dist/server/server/agent/pcm16-resampler.d.ts.map +1 -0
- package/dist/server/server/agent/pcm16-resampler.js +63 -0
- package/dist/server/server/agent/pcm16-resampler.js.map +1 -0
- package/dist/server/server/agent/provider-launch-config.d.ts +139 -0
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -0
- package/dist/server/server/agent/provider-launch-config.js +83 -0
- package/dist/server/server/agent/provider-launch-config.js.map +1 -0
- package/dist/server/server/agent/provider-manifest.d.ts +20 -0
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -0
- package/dist/server/server/agent/provider-manifest.js +97 -0
- package/dist/server/server/agent/provider-manifest.js.map +1 -0
- package/dist/server/server/agent/provider-registry.d.ts +18 -0
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -0
- package/dist/server/server/agent/provider-registry.js +45 -0
- package/dist/server/server/agent/provider-registry.js.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts +3 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +42 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +16 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +73 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts +35 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude-agent.js +2056 -0
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +13 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +67 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +15 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +640 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +34 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.js +2476 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts +9 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +486 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +3 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +33 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +13 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +75 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts +37 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode-agent.js +822 -0
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +1363 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +534 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +18 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js +119 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -0
- package/dist/server/server/agent/recordings-debug.d.ts +3 -0
- package/dist/server/server/agent/recordings-debug.d.ts.map +1 -0
- package/dist/server/server/agent/recordings-debug.js +19 -0
- package/dist/server/server/agent/recordings-debug.js.map +1 -0
- package/dist/server/server/agent/stt-debug.d.ts +10 -0
- package/dist/server/server/agent/stt-debug.d.ts.map +1 -0
- package/dist/server/server/agent/stt-debug.js +33 -0
- package/dist/server/server/agent/stt-debug.js.map +1 -0
- package/dist/server/server/agent/stt-manager.d.ts +32 -0
- package/dist/server/server/agent/stt-manager.d.ts.map +1 -0
- package/dist/server/server/agent/stt-manager.js +231 -0
- package/dist/server/server/agent/stt-manager.js.map +1 -0
- package/dist/server/server/agent/system-prompt.d.ts +3 -0
- package/dist/server/server/agent/system-prompt.d.ts.map +1 -0
- package/dist/server/server/agent/system-prompt.js +19 -0
- package/dist/server/server/agent/system-prompt.js.map +1 -0
- package/dist/server/server/agent/tool-name-normalization.d.ts +7 -0
- package/dist/server/server/agent/tool-name-normalization.d.ts.map +1 -0
- package/dist/server/server/agent/tool-name-normalization.js +45 -0
- package/dist/server/server/agent/tool-name-normalization.js.map +1 -0
- package/dist/server/server/agent/tts-debug.d.ts +8 -0
- package/dist/server/server/agent/tts-debug.d.ts.map +1 -0
- package/dist/server/server/agent/tts-debug.js +24 -0
- package/dist/server/server/agent/tts-debug.js.map +1 -0
- package/dist/server/server/agent/tts-manager.d.ts +33 -0
- package/dist/server/server/agent/tts-manager.d.ts.map +1 -0
- package/dist/server/server/agent/tts-manager.js +261 -0
- package/dist/server/server/agent/tts-manager.js.map +1 -0
- package/dist/server/server/agent/wait-for-agent-tracker.d.ts +15 -0
- package/dist/server/server/agent/wait-for-agent-tracker.d.ts.map +1 -0
- package/dist/server/server/agent/wait-for-agent-tracker.js +53 -0
- package/dist/server/server/agent/wait-for-agent-tracker.js.map +1 -0
- package/dist/server/server/allowed-hosts.d.ts +13 -0
- package/dist/server/server/allowed-hosts.d.ts.map +1 -0
- package/dist/server/server/allowed-hosts.js +94 -0
- package/dist/server/server/allowed-hosts.js.map +1 -0
- package/dist/server/server/bootstrap.d.ts +49 -0
- package/dist/server/server/bootstrap.d.ts.map +1 -0
- package/dist/server/server/bootstrap.js +483 -0
- package/dist/server/server/bootstrap.js.map +1 -0
- package/dist/server/server/config.d.ts +13 -0
- package/dist/server/server/config.d.ts.map +1 -0
- package/dist/server/server/config.js +84 -0
- package/dist/server/server/config.js.map +1 -0
- package/dist/server/server/connection-offer.d.ts +19 -0
- package/dist/server/server/connection-offer.d.ts.map +1 -0
- package/dist/server/server/connection-offer.js +60 -0
- package/dist/server/server/connection-offer.js.map +1 -0
- package/dist/server/server/daemon-keypair.d.ts +8 -0
- package/dist/server/server/daemon-keypair.d.ts.map +1 -0
- package/dist/server/server/daemon-keypair.js +40 -0
- package/dist/server/server/daemon-keypair.js.map +1 -0
- package/dist/server/server/dictation/dictation-stream-manager.d.ts +76 -0
- package/dist/server/server/dictation/dictation-stream-manager.d.ts.map +1 -0
- package/dist/server/server/dictation/dictation-stream-manager.js +481 -0
- package/dist/server/server/dictation/dictation-stream-manager.js.map +1 -0
- package/dist/server/server/exports.d.ts +11 -0
- package/dist/server/server/exports.d.ts.map +1 -0
- package/dist/server/server/exports.js +11 -0
- package/dist/server/server/exports.js.map +1 -0
- package/dist/server/server/file-download/token-store.d.ts +25 -0
- package/dist/server/server/file-download/token-store.d.ts.map +1 -0
- package/dist/server/server/file-download/token-store.js +40 -0
- package/dist/server/server/file-download/token-store.js.map +1 -0
- package/dist/server/server/file-explorer/service.d.ts +41 -0
- package/dist/server/server/file-explorer/service.d.ts.map +1 -0
- package/dist/server/server/file-explorer/service.js +163 -0
- package/dist/server/server/file-explorer/service.js.map +1 -0
- package/dist/server/server/index.d.ts +2 -0
- package/dist/server/server/index.d.ts.map +1 -0
- package/dist/server/server/index.js +90 -0
- package/dist/server/server/index.js.map +1 -0
- package/dist/server/server/json-utils.d.ts +11 -0
- package/dist/server/server/json-utils.d.ts.map +1 -0
- package/dist/server/server/json-utils.js +45 -0
- package/dist/server/server/json-utils.js.map +1 -0
- package/dist/server/server/logger.d.ts +12 -0
- package/dist/server/server/logger.d.ts.map +1 -0
- package/dist/server/server/logger.js +29 -0
- package/dist/server/server/logger.js.map +1 -0
- package/dist/server/server/messages.d.ts +9 -0
- package/dist/server/server/messages.d.ts.map +1 -0
- package/dist/server/server/messages.js +29 -0
- package/dist/server/server/messages.js.map +1 -0
- package/dist/server/server/pairing-offer.d.ts +16 -0
- package/dist/server/server/pairing-offer.d.ts.map +1 -0
- package/dist/server/server/pairing-offer.js +45 -0
- package/dist/server/server/pairing-offer.js.map +1 -0
- package/dist/server/server/pairing-qr.d.ts +7 -0
- package/dist/server/server/pairing-qr.d.ts.map +1 -0
- package/dist/server/server/pairing-qr.js +45 -0
- package/dist/server/server/pairing-qr.js.map +1 -0
- package/dist/server/server/paseo-home.d.ts +2 -0
- package/dist/server/server/paseo-home.d.ts.map +1 -0
- package/dist/server/server/paseo-home.js +19 -0
- package/dist/server/server/paseo-home.js.map +1 -0
- package/dist/server/server/path-utils.d.ts +3 -0
- package/dist/server/server/path-utils.d.ts.map +1 -0
- package/dist/server/server/path-utils.js +20 -0
- package/dist/server/server/path-utils.js.map +1 -0
- package/dist/server/server/persisted-config.d.ts +500 -0
- package/dist/server/server/persisted-config.d.ts.map +1 -0
- package/dist/server/server/persisted-config.js +212 -0
- package/dist/server/server/persisted-config.js.map +1 -0
- package/dist/server/server/persistence-hooks.d.ts +24 -0
- package/dist/server/server/persistence-hooks.d.ts.map +1 -0
- package/dist/server/server/persistence-hooks.js +60 -0
- package/dist/server/server/persistence-hooks.js.map +1 -0
- package/dist/server/server/pid-lock.d.ts +19 -0
- package/dist/server/server/pid-lock.d.ts.map +1 -0
- package/dist/server/server/pid-lock.js +115 -0
- package/dist/server/server/pid-lock.js.map +1 -0
- package/dist/server/server/push/push-service.d.ts +21 -0
- package/dist/server/server/push/push-service.d.ts.map +1 -0
- package/dist/server/server/push/push-service.js +68 -0
- package/dist/server/server/push/push-service.js.map +1 -0
- package/dist/server/server/push/token-store.d.ts +18 -0
- package/dist/server/server/push/token-store.d.ts.map +1 -0
- package/dist/server/server/push/token-store.js +70 -0
- package/dist/server/server/push/token-store.js.map +1 -0
- package/dist/server/server/relay-transport.d.ts +22 -0
- package/dist/server/server/relay-transport.d.ts.map +1 -0
- package/dist/server/server/relay-transport.js +374 -0
- package/dist/server/server/relay-transport.js.map +1 -0
- package/dist/server/server/server-id.d.ts +17 -0
- package/dist/server/server/server-id.d.ts.map +1 -0
- package/dist/server/server/server-id.js +63 -0
- package/dist/server/server/server-id.js.map +1 -0
- package/dist/server/server/session.d.ts +360 -0
- package/dist/server/server/session.d.ts.map +1 -0
- package/dist/server/server/session.js +4615 -0
- package/dist/server/server/session.js.map +1 -0
- package/dist/server/server/speech/audio.d.ts +10 -0
- package/dist/server/server/speech/audio.d.ts.map +1 -0
- package/dist/server/server/speech/audio.js +101 -0
- package/dist/server/server/speech/audio.js.map +1 -0
- package/dist/server/server/speech/providers/local/config.d.ts +26 -0
- package/dist/server/server/speech/providers/local/config.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/config.js +93 -0
- package/dist/server/server/speech/providers/local/config.js.map +1 -0
- package/dist/server/server/speech/providers/local/models.d.ts +12 -0
- package/dist/server/server/speech/providers/local/models.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/models.js +18 -0
- package/dist/server/server/speech/providers/local/models.js.map +1 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts +24 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js +422 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -0
- package/dist/server/server/speech/providers/local/runtime.d.ts +30 -0
- package/dist/server/server/speech/providers/local/runtime.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/runtime.js +254 -0
- package/dist/server/server/speech/providers/local/runtime.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +117 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +166 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +17 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +151 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +28 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +68 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts +37 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +79 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts +7 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.js +11 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +7 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +44 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts +28 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +131 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +21 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +132 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts +23 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js +112 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts +23 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js +140 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +21 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +95 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -0
- package/dist/server/server/speech/providers/openai/config.d.ts +22 -0
- package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/config.js +94 -0
- package/dist/server/server/speech/providers/openai/config.js.map +1 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts +42 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js +165 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js.map +1 -0
- package/dist/server/server/speech/providers/openai/runtime.d.ts +27 -0
- package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/runtime.js +103 -0
- package/dist/server/server/speech/providers/openai/runtime.js.map +1 -0
- package/dist/server/server/speech/providers/openai/stt.d.ts +22 -0
- package/dist/server/server/speech/providers/openai/stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/stt.js +208 -0
- package/dist/server/server/speech/providers/openai/stt.js.map +1 -0
- package/dist/server/server/speech/providers/openai/tts.d.ts +18 -0
- package/dist/server/server/speech/providers/openai/tts.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/tts.js +46 -0
- package/dist/server/server/speech/providers/openai/tts.js.map +1 -0
- package/dist/server/server/speech/speech-config-resolver.d.ts +11 -0
- package/dist/server/server/speech/speech-config-resolver.d.ts.map +1 -0
- package/dist/server/server/speech/speech-config-resolver.js +64 -0
- package/dist/server/server/speech/speech-config-resolver.js.map +1 -0
- package/dist/server/server/speech/speech-provider.d.ts +59 -0
- package/dist/server/server/speech/speech-provider.d.ts.map +1 -0
- package/dist/server/server/speech/speech-provider.js +2 -0
- package/dist/server/server/speech/speech-provider.js.map +1 -0
- package/dist/server/server/speech/speech-runtime.d.ts +20 -0
- package/dist/server/server/speech/speech-runtime.d.ts.map +1 -0
- package/dist/server/server/speech/speech-runtime.js +119 -0
- package/dist/server/server/speech/speech-runtime.js.map +1 -0
- package/dist/server/server/speech/speech-types.d.ts +20 -0
- package/dist/server/server/speech/speech-types.d.ts.map +1 -0
- package/dist/server/server/speech/speech-types.js +7 -0
- package/dist/server/server/speech/speech-types.js.map +1 -0
- package/dist/server/server/terminal-mcp/index.d.ts +4 -0
- package/dist/server/server/terminal-mcp/index.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/index.js +3 -0
- package/dist/server/server/terminal-mcp/index.js.map +1 -0
- package/dist/server/server/terminal-mcp/server.d.ts +10 -0
- package/dist/server/server/terminal-mcp/server.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/server.js +217 -0
- package/dist/server/server/terminal-mcp/server.js.map +1 -0
- package/dist/server/server/terminal-mcp/terminal-manager.d.ts +123 -0
- package/dist/server/server/terminal-mcp/terminal-manager.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/terminal-manager.js +351 -0
- package/dist/server/server/terminal-mcp/terminal-manager.js.map +1 -0
- package/dist/server/server/terminal-mcp/tmux.d.ts +207 -0
- package/dist/server/server/terminal-mcp/tmux.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/tmux.js +924 -0
- package/dist/server/server/terminal-mcp/tmux.js.map +1 -0
- package/dist/server/server/types.d.ts +5 -0
- package/dist/server/server/types.d.ts.map +1 -0
- package/dist/server/server/types.js +3 -0
- package/dist/server/server/types.js.map +1 -0
- package/dist/server/server/utils/diff-highlighter.d.ts +52 -0
- package/dist/server/server/utils/diff-highlighter.d.ts.map +1 -0
- package/dist/server/server/utils/diff-highlighter.js +244 -0
- package/dist/server/server/utils/diff-highlighter.js.map +1 -0
- package/dist/server/server/utils/syntax-highlighter.d.ts +10 -0
- package/dist/server/server/utils/syntax-highlighter.d.ts.map +1 -0
- package/dist/server/server/utils/syntax-highlighter.js +141 -0
- package/dist/server/server/utils/syntax-highlighter.js.map +1 -0
- package/dist/server/server/voice-config.d.ts +14 -0
- package/dist/server/server/voice-config.d.ts.map +1 -0
- package/dist/server/server/voice-config.js +51 -0
- package/dist/server/server/voice-config.js.map +1 -0
- package/dist/server/server/voice-mcp-bridge-command.d.ts +17 -0
- package/dist/server/server/voice-mcp-bridge-command.d.ts.map +1 -0
- package/dist/server/server/voice-mcp-bridge-command.js +31 -0
- package/dist/server/server/voice-mcp-bridge-command.js.map +1 -0
- package/dist/server/server/voice-mcp-bridge.d.ts +18 -0
- package/dist/server/server/voice-mcp-bridge.d.ts.map +1 -0
- package/dist/server/server/voice-mcp-bridge.js +109 -0
- package/dist/server/server/voice-mcp-bridge.js.map +1 -0
- package/dist/server/server/voice-permission-policy.d.ts +4 -0
- package/dist/server/server/voice-permission-policy.d.ts.map +1 -0
- package/dist/server/server/voice-permission-policy.js +13 -0
- package/dist/server/server/voice-permission-policy.js.map +1 -0
- package/dist/server/server/voice-types.d.ts +17 -0
- package/dist/server/server/voice-types.d.ts.map +1 -0
- package/dist/server/server/voice-types.js +2 -0
- package/dist/server/server/voice-types.js.map +1 -0
- package/dist/server/server/websocket-server.d.ts +80 -0
- package/dist/server/server/websocket-server.d.ts.map +1 -0
- package/dist/server/server/websocket-server.js +447 -0
- package/dist/server/server/websocket-server.js.map +1 -0
- package/dist/server/shared/agent-lifecycle.d.ts +3 -0
- package/dist/server/shared/agent-lifecycle.d.ts.map +1 -0
- package/dist/server/shared/agent-lifecycle.js +8 -0
- package/dist/server/shared/agent-lifecycle.js.map +1 -0
- package/dist/server/shared/connection-offer.d.ts +62 -0
- package/dist/server/shared/connection-offer.d.ts.map +1 -0
- package/dist/server/shared/connection-offer.js +17 -0
- package/dist/server/shared/connection-offer.js.map +1 -0
- package/dist/server/shared/daemon-endpoints.d.ts +19 -0
- package/dist/server/shared/daemon-endpoints.d.ts.map +1 -0
- package/dist/server/shared/daemon-endpoints.js +98 -0
- package/dist/server/shared/daemon-endpoints.js.map +1 -0
- package/dist/server/shared/messages.d.ts +36729 -0
- package/dist/server/shared/messages.d.ts.map +1 -0
- package/dist/server/shared/messages.js +1666 -0
- package/dist/server/shared/messages.js.map +1 -0
- package/dist/server/shared/path-utils.d.ts +2 -0
- package/dist/server/shared/path-utils.d.ts.map +1 -0
- package/dist/server/shared/path-utils.js +16 -0
- package/dist/server/shared/path-utils.js.map +1 -0
- package/dist/server/shared/tool-call-display.d.ts +11 -0
- package/dist/server/shared/tool-call-display.d.ts.map +1 -0
- package/dist/server/shared/tool-call-display.js +82 -0
- package/dist/server/shared/tool-call-display.js.map +1 -0
- package/dist/server/terminal/terminal-manager.d.ts +14 -0
- package/dist/server/terminal/terminal-manager.d.ts.map +1 -0
- package/dist/server/terminal/terminal-manager.js +67 -0
- package/dist/server/terminal/terminal-manager.js.map +1 -0
- package/dist/server/terminal/terminal.d.ts +67 -0
- package/dist/server/terminal/terminal.d.ts.map +1 -0
- package/dist/server/terminal/terminal.js +190 -0
- package/dist/server/terminal/terminal.js.map +1 -0
- package/dist/server/utils/checkout-git.d.ts +138 -0
- package/dist/server/utils/checkout-git.d.ts.map +1 -0
- package/dist/server/utils/checkout-git.js +1079 -0
- package/dist/server/utils/checkout-git.js.map +1 -0
- package/dist/server/utils/path.d.ts +5 -0
- package/dist/server/utils/path.d.ts.map +1 -0
- package/dist/server/utils/path.js +15 -0
- package/dist/server/utils/path.js.map +1 -0
- package/dist/server/utils/project-icon.d.ts +39 -0
- package/dist/server/utils/project-icon.d.ts.map +1 -0
- package/dist/server/utils/project-icon.js +391 -0
- package/dist/server/utils/project-icon.js.map +1 -0
- package/dist/server/utils/worktree-metadata.d.ts +21 -0
- package/dist/server/utils/worktree-metadata.d.ts.map +1 -0
- package/dist/server/utils/worktree-metadata.js +74 -0
- package/dist/server/utils/worktree-metadata.js.map +1 -0
- package/dist/server/utils/worktree.d.ts +95 -0
- package/dist/server/utils/worktree.d.ts.map +1 -0
- package/dist/server/utils/worktree.js +568 -0
- package/dist/server/utils/worktree.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,2443 @@
|
|
|
1
|
+
import { AgentCreateFailedStatusPayloadSchema, AgentCreatedStatusPayloadSchema, AgentRefreshedStatusPayloadSchema, AgentResumedStatusPayloadSchema, RestartRequestedStatusPayloadSchema, SessionInboundMessageSchema, WSOutboundMessageSchema, } from "../shared/messages.js";
|
|
2
|
+
import { getAgentProviderDefinition } from "../server/agent/provider-manifest.js";
|
|
3
|
+
import { createClientChannel, } from "@getpaseo/relay/e2ee";
|
|
4
|
+
import { isRelayClientWebSocketUrl } from "../shared/daemon-endpoints.js";
|
|
5
|
+
const consoleLogger = {
|
|
6
|
+
debug: (obj, msg) => console.debug(msg, obj),
|
|
7
|
+
info: (obj, msg) => console.info(msg, obj),
|
|
8
|
+
warn: (obj, msg) => console.warn(msg, obj),
|
|
9
|
+
error: (obj, msg) => console.error(msg, obj),
|
|
10
|
+
};
|
|
11
|
+
class DaemonRpcError extends Error {
|
|
12
|
+
constructor(params) {
|
|
13
|
+
super(params.error);
|
|
14
|
+
this.name = "DaemonRpcError";
|
|
15
|
+
this.requestId = params.requestId;
|
|
16
|
+
this.requestType = params.requestType;
|
|
17
|
+
this.code = params.code;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const DEFAULT_RECONNECT_BASE_DELAY_MS = 1500;
|
|
21
|
+
const DEFAULT_RECONNECT_MAX_DELAY_MS = 30000;
|
|
22
|
+
/** Default timeout for waiting for connection before sending queued messages */
|
|
23
|
+
const DEFAULT_SEND_QUEUE_TIMEOUT_MS = 10000;
|
|
24
|
+
export class DaemonClient {
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.transport = null;
|
|
28
|
+
this.transportCleanup = [];
|
|
29
|
+
this.rawMessageListeners = new Set();
|
|
30
|
+
this.messageHandlers = new Map();
|
|
31
|
+
this.eventListeners = new Set();
|
|
32
|
+
this.waiters = new Set();
|
|
33
|
+
this.checkoutStatusInFlight = new Map();
|
|
34
|
+
this.connectionListeners = new Set();
|
|
35
|
+
this.reconnectTimeout = null;
|
|
36
|
+
this.pendingGenericTransportErrorTimeout = null;
|
|
37
|
+
this.reconnectAttempt = 0;
|
|
38
|
+
this.shouldReconnect = true;
|
|
39
|
+
this.connectPromise = null;
|
|
40
|
+
this.connectResolve = null;
|
|
41
|
+
this.connectReject = null;
|
|
42
|
+
this.lastErrorValue = null;
|
|
43
|
+
this.connectionState = { status: "idle" };
|
|
44
|
+
this.agentUpdateSubscriptions = new Map();
|
|
45
|
+
this.checkoutDiffSubscriptions = new Map();
|
|
46
|
+
this.pendingSendQueue = [];
|
|
47
|
+
this.relayClientId = null;
|
|
48
|
+
this.logger = config.logger ?? consoleLogger;
|
|
49
|
+
// Relay requires a clientId so the daemon can create an independent
|
|
50
|
+
// socket + E2EE channel per connected client. Generate one per DaemonClient
|
|
51
|
+
// instance (stable across reconnects in this tab/app session).
|
|
52
|
+
if (isRelayClientWebSocketUrl(this.config.url)) {
|
|
53
|
+
try {
|
|
54
|
+
const parsed = new URL(this.config.url);
|
|
55
|
+
if (!parsed.searchParams.get("clientId")) {
|
|
56
|
+
this.relayClientId = `clt_${safeRandomId()}`;
|
|
57
|
+
parsed.searchParams.set("clientId", this.relayClientId);
|
|
58
|
+
this.config.url = parsed.toString();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// ignore - invalid URL will be handled on connect
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Connection
|
|
68
|
+
// ============================================================================
|
|
69
|
+
async connect() {
|
|
70
|
+
if (this.connectionState.status === "connected") {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (this.connectPromise) {
|
|
74
|
+
return this.connectPromise;
|
|
75
|
+
}
|
|
76
|
+
this.shouldReconnect = true;
|
|
77
|
+
this.connectPromise = new Promise((resolve, reject) => {
|
|
78
|
+
this.connectResolve = resolve;
|
|
79
|
+
this.connectReject = reject;
|
|
80
|
+
this.attemptConnect();
|
|
81
|
+
});
|
|
82
|
+
return this.connectPromise;
|
|
83
|
+
}
|
|
84
|
+
attemptConnect() {
|
|
85
|
+
if (!this.shouldReconnect) {
|
|
86
|
+
this.rejectConnect(new Error("Daemon client is closed"));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (this.connectionState.status === "connecting") {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const headers = {};
|
|
93
|
+
if (this.config.authHeader) {
|
|
94
|
+
headers["Authorization"] = this.config.authHeader;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
// If we reconnect while the previous socket is still open (common in browsers
|
|
98
|
+
// where `onerror` may fire before `onclose`), we can end up with multiple
|
|
99
|
+
// concurrent relay sockets. Cloudflare then closes the old one with
|
|
100
|
+
// "Replaced by new connection", causing a disconnect loop.
|
|
101
|
+
this.disposeTransport();
|
|
102
|
+
const baseTransportFactory = this.config.transportFactory ??
|
|
103
|
+
createWebSocketTransportFactory(this.config.webSocketFactory ?? defaultWebSocketFactory);
|
|
104
|
+
const shouldUseRelayE2ee = this.config.e2ee?.enabled === true &&
|
|
105
|
+
isRelayClientWebSocketUrl(this.config.url);
|
|
106
|
+
let transportFactory = baseTransportFactory;
|
|
107
|
+
if (shouldUseRelayE2ee) {
|
|
108
|
+
const daemonPublicKeyB64 = this.config.e2ee?.daemonPublicKeyB64;
|
|
109
|
+
if (!daemonPublicKeyB64) {
|
|
110
|
+
throw new Error("daemonPublicKeyB64 is required for relay E2EE");
|
|
111
|
+
}
|
|
112
|
+
transportFactory = createRelayE2eeTransportFactory({
|
|
113
|
+
baseFactory: baseTransportFactory,
|
|
114
|
+
daemonPublicKeyB64,
|
|
115
|
+
logger: this.logger,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const transport = transportFactory({ url: this.config.url, headers });
|
|
119
|
+
this.transport = transport;
|
|
120
|
+
this.updateConnectionState({
|
|
121
|
+
status: "connecting",
|
|
122
|
+
attempt: this.reconnectAttempt,
|
|
123
|
+
});
|
|
124
|
+
this.transportCleanup = [
|
|
125
|
+
transport.onOpen(() => {
|
|
126
|
+
if (this.pendingGenericTransportErrorTimeout) {
|
|
127
|
+
clearTimeout(this.pendingGenericTransportErrorTimeout);
|
|
128
|
+
this.pendingGenericTransportErrorTimeout = null;
|
|
129
|
+
}
|
|
130
|
+
this.lastErrorValue = null;
|
|
131
|
+
this.reconnectAttempt = 0;
|
|
132
|
+
this.updateConnectionState({ status: "connected" });
|
|
133
|
+
this.resubscribeAgentUpdates();
|
|
134
|
+
this.resubscribeCheckoutDiffSubscriptions();
|
|
135
|
+
this.flushPendingSendQueue();
|
|
136
|
+
this.resolveConnect();
|
|
137
|
+
}),
|
|
138
|
+
transport.onClose((event) => {
|
|
139
|
+
if (this.pendingGenericTransportErrorTimeout) {
|
|
140
|
+
clearTimeout(this.pendingGenericTransportErrorTimeout);
|
|
141
|
+
this.pendingGenericTransportErrorTimeout = null;
|
|
142
|
+
}
|
|
143
|
+
const closeRecord = event;
|
|
144
|
+
const closeCode = closeRecord && typeof closeRecord === "object" && typeof closeRecord.code === "number"
|
|
145
|
+
? closeRecord.code
|
|
146
|
+
: null;
|
|
147
|
+
const closeReason = closeRecord && typeof closeRecord === "object" && typeof closeRecord.reason === "string"
|
|
148
|
+
? closeRecord.reason
|
|
149
|
+
: null;
|
|
150
|
+
const reason = describeTransportClose(event);
|
|
151
|
+
if (reason) {
|
|
152
|
+
this.lastErrorValue = reason;
|
|
153
|
+
}
|
|
154
|
+
this.updateConnectionState({
|
|
155
|
+
status: "disconnected",
|
|
156
|
+
...(reason ? { reason } : {}),
|
|
157
|
+
});
|
|
158
|
+
// When connecting over the relay, only one client connection is allowed at a time.
|
|
159
|
+
// If another device/tab takes over, we should not auto-reconnect and "fight" the new
|
|
160
|
+
// connection (which causes flapping where both sides repeatedly replace each other).
|
|
161
|
+
if (isRelayClientWebSocketUrl(this.config.url) &&
|
|
162
|
+
closeCode === 1008 &&
|
|
163
|
+
(closeReason ?? reason) === "Replaced by new connection") {
|
|
164
|
+
this.shouldReconnect = false;
|
|
165
|
+
this.clearWaiters(new Error(reason ?? "Replaced by new connection"));
|
|
166
|
+
this.rejectPendingSendQueue(new Error(reason ?? "Replaced by new connection"));
|
|
167
|
+
this.rejectConnect(new Error(reason ?? "Replaced by new connection"));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.scheduleReconnect(reason);
|
|
171
|
+
}),
|
|
172
|
+
transport.onError((event) => {
|
|
173
|
+
const reason = describeTransportError(event);
|
|
174
|
+
const isGeneric = reason === "Transport error";
|
|
175
|
+
// Browser WebSocket.onerror often provides no useful details and is followed
|
|
176
|
+
// by a close event (often with code 1006). Prefer surfacing the close details
|
|
177
|
+
// instead of immediately disconnecting with a generic "Transport error".
|
|
178
|
+
if (isGeneric) {
|
|
179
|
+
this.lastErrorValue ?? (this.lastErrorValue = reason);
|
|
180
|
+
if (!this.pendingGenericTransportErrorTimeout) {
|
|
181
|
+
this.pendingGenericTransportErrorTimeout = setTimeout(() => {
|
|
182
|
+
this.pendingGenericTransportErrorTimeout = null;
|
|
183
|
+
if (this.connectionState.status === "connected" ||
|
|
184
|
+
this.connectionState.status === "connecting") {
|
|
185
|
+
this.lastErrorValue = reason;
|
|
186
|
+
this.updateConnectionState({ status: "disconnected", reason });
|
|
187
|
+
this.scheduleReconnect(reason);
|
|
188
|
+
}
|
|
189
|
+
}, 250);
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (this.pendingGenericTransportErrorTimeout) {
|
|
194
|
+
clearTimeout(this.pendingGenericTransportErrorTimeout);
|
|
195
|
+
this.pendingGenericTransportErrorTimeout = null;
|
|
196
|
+
}
|
|
197
|
+
this.lastErrorValue = reason;
|
|
198
|
+
this.updateConnectionState({ status: "disconnected", reason });
|
|
199
|
+
this.scheduleReconnect(reason);
|
|
200
|
+
}),
|
|
201
|
+
transport.onMessage((data) => this.handleTransportMessage(data)),
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
const message = error instanceof Error ? error.message : "Failed to connect";
|
|
206
|
+
this.lastErrorValue = message;
|
|
207
|
+
this.scheduleReconnect(message);
|
|
208
|
+
this.rejectConnect(error instanceof Error ? error : new Error(message));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
resolveConnect() {
|
|
212
|
+
if (this.connectResolve) {
|
|
213
|
+
this.connectResolve();
|
|
214
|
+
}
|
|
215
|
+
this.connectPromise = null;
|
|
216
|
+
this.connectResolve = null;
|
|
217
|
+
this.connectReject = null;
|
|
218
|
+
}
|
|
219
|
+
rejectConnect(error) {
|
|
220
|
+
if (this.connectReject) {
|
|
221
|
+
this.connectReject(error);
|
|
222
|
+
}
|
|
223
|
+
this.connectPromise = null;
|
|
224
|
+
this.connectResolve = null;
|
|
225
|
+
this.connectReject = null;
|
|
226
|
+
}
|
|
227
|
+
async close() {
|
|
228
|
+
this.shouldReconnect = false;
|
|
229
|
+
this.connectPromise = null;
|
|
230
|
+
this.connectResolve = null;
|
|
231
|
+
this.connectReject = null;
|
|
232
|
+
if (this.reconnectTimeout) {
|
|
233
|
+
clearTimeout(this.reconnectTimeout);
|
|
234
|
+
this.reconnectTimeout = null;
|
|
235
|
+
}
|
|
236
|
+
this.disposeTransport(1000, "Client closed");
|
|
237
|
+
this.clearWaiters(new Error("Daemon client closed"));
|
|
238
|
+
this.updateConnectionState({
|
|
239
|
+
status: "disconnected",
|
|
240
|
+
reason: "client_closed",
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
ensureConnected() {
|
|
244
|
+
if (!this.shouldReconnect) {
|
|
245
|
+
this.shouldReconnect = true;
|
|
246
|
+
}
|
|
247
|
+
if (this.connectionState.status === "connected" ||
|
|
248
|
+
this.connectionState.status === "connecting") {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
void this.connect();
|
|
252
|
+
}
|
|
253
|
+
getConnectionState() {
|
|
254
|
+
return this.connectionState;
|
|
255
|
+
}
|
|
256
|
+
subscribeConnectionStatus(listener) {
|
|
257
|
+
this.connectionListeners.add(listener);
|
|
258
|
+
listener(this.connectionState);
|
|
259
|
+
return () => {
|
|
260
|
+
this.connectionListeners.delete(listener);
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
get isConnected() {
|
|
264
|
+
return this.connectionState.status === "connected";
|
|
265
|
+
}
|
|
266
|
+
get isConnecting() {
|
|
267
|
+
return this.connectionState.status === "connecting";
|
|
268
|
+
}
|
|
269
|
+
get lastError() {
|
|
270
|
+
return this.lastErrorValue;
|
|
271
|
+
}
|
|
272
|
+
// ============================================================================
|
|
273
|
+
// Message Subscription
|
|
274
|
+
// ============================================================================
|
|
275
|
+
subscribe(handler) {
|
|
276
|
+
this.eventListeners.add(handler);
|
|
277
|
+
return () => this.eventListeners.delete(handler);
|
|
278
|
+
}
|
|
279
|
+
subscribeRawMessages(handler) {
|
|
280
|
+
this.rawMessageListeners.add(handler);
|
|
281
|
+
return () => {
|
|
282
|
+
this.rawMessageListeners.delete(handler);
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
on(arg1, arg2) {
|
|
286
|
+
if (typeof arg1 === "function") {
|
|
287
|
+
return this.subscribe(arg1);
|
|
288
|
+
}
|
|
289
|
+
const type = arg1;
|
|
290
|
+
const handler = arg2;
|
|
291
|
+
if (!this.messageHandlers.has(type)) {
|
|
292
|
+
this.messageHandlers.set(type, new Set());
|
|
293
|
+
}
|
|
294
|
+
this.messageHandlers.get(type).add(handler);
|
|
295
|
+
return () => {
|
|
296
|
+
const handlers = this.messageHandlers.get(type);
|
|
297
|
+
if (!handlers) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
handlers.delete(handler);
|
|
301
|
+
if (handlers.size === 0) {
|
|
302
|
+
this.messageHandlers.delete(type);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
// ============================================================================
|
|
307
|
+
// Core Send Helpers
|
|
308
|
+
// ============================================================================
|
|
309
|
+
/**
|
|
310
|
+
* Send a session message. For fire-and-forget messages (heartbeats, etc.),
|
|
311
|
+
* failures are suppressed if `suppressSendErrors` is configured.
|
|
312
|
+
* For RPC methods that wait for responses, use `sendSessionMessageOrThrow` instead.
|
|
313
|
+
*/
|
|
314
|
+
sendSessionMessage(message) {
|
|
315
|
+
if (!this.transport || this.connectionState.status !== "connected") {
|
|
316
|
+
if (this.config.suppressSendErrors) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
throw new Error(`Transport not connected (status: ${this.connectionState.status})`);
|
|
320
|
+
}
|
|
321
|
+
const payload = SessionInboundMessageSchema.parse(message);
|
|
322
|
+
try {
|
|
323
|
+
this.transport.send(JSON.stringify({ type: "session", message: payload }));
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
if (this.config.suppressSendErrors) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Send a session message for RPC methods that create waiters.
|
|
334
|
+
* If the connection is still being established ("connecting"), the message
|
|
335
|
+
* is queued and will be sent once connected (or rejected after timeout).
|
|
336
|
+
* This prevents waiters from hanging forever when called during connection.
|
|
337
|
+
*/
|
|
338
|
+
sendSessionMessageOrThrow(message) {
|
|
339
|
+
const status = this.connectionState.status;
|
|
340
|
+
// If connected, send immediately
|
|
341
|
+
if (this.transport && status === "connected") {
|
|
342
|
+
const payload = SessionInboundMessageSchema.parse(message);
|
|
343
|
+
this.transport.send(JSON.stringify({ type: "session", message: payload }));
|
|
344
|
+
return Promise.resolve();
|
|
345
|
+
}
|
|
346
|
+
// If connecting, queue the message to be sent once connected
|
|
347
|
+
if (status === "connecting") {
|
|
348
|
+
return new Promise((resolve, reject) => {
|
|
349
|
+
const timeoutHandle = setTimeout(() => {
|
|
350
|
+
// Remove from queue
|
|
351
|
+
const idx = this.pendingSendQueue.findIndex((p) => p.resolve === resolve);
|
|
352
|
+
if (idx !== -1) {
|
|
353
|
+
this.pendingSendQueue.splice(idx, 1);
|
|
354
|
+
}
|
|
355
|
+
reject(new Error(`Timed out waiting for connection to send message`));
|
|
356
|
+
}, DEFAULT_SEND_QUEUE_TIMEOUT_MS);
|
|
357
|
+
this.pendingSendQueue.push({ message, resolve, reject, timeoutHandle });
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
// Not connected and not connecting - fail immediately
|
|
361
|
+
return Promise.reject(new Error(`Transport not connected (status: ${status})`));
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Flush pending send queue - called when connection is established.
|
|
365
|
+
*/
|
|
366
|
+
flushPendingSendQueue() {
|
|
367
|
+
const queue = this.pendingSendQueue;
|
|
368
|
+
this.pendingSendQueue = [];
|
|
369
|
+
for (const pending of queue) {
|
|
370
|
+
clearTimeout(pending.timeoutHandle);
|
|
371
|
+
try {
|
|
372
|
+
if (this.transport && this.connectionState.status === "connected") {
|
|
373
|
+
const payload = SessionInboundMessageSchema.parse(pending.message);
|
|
374
|
+
this.transport.send(JSON.stringify({ type: "session", message: payload }));
|
|
375
|
+
pending.resolve();
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
pending.reject(new Error("Connection lost before message could be sent"));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
pending.reject(error instanceof Error ? error : new Error(String(error)));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Reject all pending sends - called when connection fails or is closed.
|
|
388
|
+
*/
|
|
389
|
+
rejectPendingSendQueue(error) {
|
|
390
|
+
const queue = this.pendingSendQueue;
|
|
391
|
+
this.pendingSendQueue = [];
|
|
392
|
+
for (const pending of queue) {
|
|
393
|
+
clearTimeout(pending.timeoutHandle);
|
|
394
|
+
pending.reject(error);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
async sendRequest(params) {
|
|
398
|
+
const { promise, cancel } = this.waitForWithCancel((msg) => {
|
|
399
|
+
if (msg.type === "rpc_error" && msg.payload.requestId === params.requestId) {
|
|
400
|
+
return {
|
|
401
|
+
kind: "error",
|
|
402
|
+
error: new DaemonRpcError({
|
|
403
|
+
requestId: msg.payload.requestId,
|
|
404
|
+
error: msg.payload.error,
|
|
405
|
+
requestType: msg.payload.requestType,
|
|
406
|
+
code: msg.payload.code,
|
|
407
|
+
}),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const value = params.select(msg);
|
|
411
|
+
if (value === null) {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
return { kind: "ok", value };
|
|
415
|
+
}, params.timeout, params.options);
|
|
416
|
+
try {
|
|
417
|
+
await this.sendSessionMessageOrThrow(params.message);
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
421
|
+
cancel(err);
|
|
422
|
+
void promise.catch(() => undefined);
|
|
423
|
+
throw err;
|
|
424
|
+
}
|
|
425
|
+
const result = await promise;
|
|
426
|
+
if (result.kind === "error") {
|
|
427
|
+
throw result.error;
|
|
428
|
+
}
|
|
429
|
+
return result.value;
|
|
430
|
+
}
|
|
431
|
+
sendSessionMessageStrict(message) {
|
|
432
|
+
if (!this.transport || this.connectionState.status !== "connected") {
|
|
433
|
+
throw new Error("Transport not connected");
|
|
434
|
+
}
|
|
435
|
+
const payload = SessionInboundMessageSchema.parse(message);
|
|
436
|
+
try {
|
|
437
|
+
this.transport.send(JSON.stringify({ type: "session", message: payload }));
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
clearAgentAttention(agentId) {
|
|
444
|
+
this.sendSessionMessage({ type: "clear_agent_attention", agentId });
|
|
445
|
+
}
|
|
446
|
+
sendHeartbeat(params) {
|
|
447
|
+
this.sendSessionMessage({
|
|
448
|
+
type: "client_heartbeat",
|
|
449
|
+
deviceType: params.deviceType,
|
|
450
|
+
focusedAgentId: params.focusedAgentId,
|
|
451
|
+
lastActivityAt: params.lastActivityAt,
|
|
452
|
+
appVisible: params.appVisible,
|
|
453
|
+
appVisibilityChangedAt: params.appVisibilityChangedAt,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
registerPushToken(token) {
|
|
457
|
+
this.sendSessionMessage({
|
|
458
|
+
type: "register_push_token",
|
|
459
|
+
token,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
async ping(params) {
|
|
463
|
+
const requestId = params?.requestId ??
|
|
464
|
+
`ping-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
465
|
+
const clientSentAt = Date.now();
|
|
466
|
+
const payload = await this.sendRequest({
|
|
467
|
+
requestId,
|
|
468
|
+
message: { type: "ping", requestId, clientSentAt },
|
|
469
|
+
timeout: params?.timeoutMs ?? 5000,
|
|
470
|
+
select: (msg) => {
|
|
471
|
+
if (msg.type !== "pong")
|
|
472
|
+
return null;
|
|
473
|
+
if (msg.payload.requestId !== requestId)
|
|
474
|
+
return null;
|
|
475
|
+
if (typeof msg.payload.serverReceivedAt !== "number")
|
|
476
|
+
return null;
|
|
477
|
+
if (typeof msg.payload.serverSentAt !== "number")
|
|
478
|
+
return null;
|
|
479
|
+
return msg.payload;
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
return {
|
|
483
|
+
requestId,
|
|
484
|
+
clientSentAt,
|
|
485
|
+
serverReceivedAt: payload.serverReceivedAt,
|
|
486
|
+
serverSentAt: payload.serverSentAt,
|
|
487
|
+
rttMs: Date.now() - clientSentAt,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
// ============================================================================
|
|
491
|
+
// Agent RPCs (requestId-correlated)
|
|
492
|
+
// ============================================================================
|
|
493
|
+
async fetchAgents(options) {
|
|
494
|
+
const resolvedRequestId = this.createRequestId(options?.requestId);
|
|
495
|
+
const message = SessionInboundMessageSchema.parse({
|
|
496
|
+
type: "fetch_agents_request",
|
|
497
|
+
requestId: resolvedRequestId,
|
|
498
|
+
...(options?.filter ? { filter: options.filter } : {}),
|
|
499
|
+
});
|
|
500
|
+
return this.sendRequest({
|
|
501
|
+
requestId: resolvedRequestId,
|
|
502
|
+
message,
|
|
503
|
+
timeout: 10000,
|
|
504
|
+
options: { skipQueue: true },
|
|
505
|
+
select: (msg) => {
|
|
506
|
+
if (msg.type !== "fetch_agents_response") {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
return msg.payload.agents;
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
async fetchAgentsGroupedByProject(options) {
|
|
517
|
+
const resolvedRequestId = this.createRequestId(options?.requestId);
|
|
518
|
+
const message = SessionInboundMessageSchema.parse({
|
|
519
|
+
type: "fetch_agents_grouped_by_project_request",
|
|
520
|
+
requestId: resolvedRequestId,
|
|
521
|
+
...(options?.filter ? { filter: options.filter } : {}),
|
|
522
|
+
});
|
|
523
|
+
return this.sendRequest({
|
|
524
|
+
requestId: resolvedRequestId,
|
|
525
|
+
message,
|
|
526
|
+
timeout: 15000,
|
|
527
|
+
options: { skipQueue: true },
|
|
528
|
+
select: (msg) => {
|
|
529
|
+
if (msg.type !== "fetch_agents_grouped_by_project_response") {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
return msg.payload;
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
async fetchAgent(agentId, requestId) {
|
|
540
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
541
|
+
const message = SessionInboundMessageSchema.parse({
|
|
542
|
+
type: "fetch_agent_request",
|
|
543
|
+
requestId: resolvedRequestId,
|
|
544
|
+
agentId,
|
|
545
|
+
});
|
|
546
|
+
const payload = await this.sendRequest({
|
|
547
|
+
requestId: resolvedRequestId,
|
|
548
|
+
message,
|
|
549
|
+
timeout: 10000,
|
|
550
|
+
options: { skipQueue: true },
|
|
551
|
+
select: (msg) => {
|
|
552
|
+
if (msg.type !== "fetch_agent_response") {
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
return msg.payload;
|
|
559
|
+
},
|
|
560
|
+
});
|
|
561
|
+
if (payload.error) {
|
|
562
|
+
throw new Error(payload.error);
|
|
563
|
+
}
|
|
564
|
+
return payload.agent;
|
|
565
|
+
}
|
|
566
|
+
subscribeAgentUpdates(options) {
|
|
567
|
+
const subscriptionId = options?.subscriptionId ?? crypto.randomUUID();
|
|
568
|
+
this.agentUpdateSubscriptions.set(subscriptionId, options?.filter);
|
|
569
|
+
const message = SessionInboundMessageSchema.parse({
|
|
570
|
+
type: "subscribe_agent_updates",
|
|
571
|
+
subscriptionId,
|
|
572
|
+
...(options?.filter ? { filter: options.filter } : {}),
|
|
573
|
+
});
|
|
574
|
+
this.sendSessionMessage(message);
|
|
575
|
+
return subscriptionId;
|
|
576
|
+
}
|
|
577
|
+
unsubscribeAgentUpdates(subscriptionId) {
|
|
578
|
+
this.agentUpdateSubscriptions.delete(subscriptionId);
|
|
579
|
+
const message = SessionInboundMessageSchema.parse({
|
|
580
|
+
type: "unsubscribe_agent_updates",
|
|
581
|
+
subscriptionId,
|
|
582
|
+
});
|
|
583
|
+
this.sendSessionMessage(message);
|
|
584
|
+
}
|
|
585
|
+
resubscribeAgentUpdates() {
|
|
586
|
+
if (this.agentUpdateSubscriptions.size === 0) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
for (const [subscriptionId, filter] of this.agentUpdateSubscriptions) {
|
|
590
|
+
const message = SessionInboundMessageSchema.parse({
|
|
591
|
+
type: "subscribe_agent_updates",
|
|
592
|
+
subscriptionId,
|
|
593
|
+
...(filter ? { filter } : {}),
|
|
594
|
+
});
|
|
595
|
+
this.sendSessionMessage(message);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
resubscribeCheckoutDiffSubscriptions() {
|
|
599
|
+
if (this.checkoutDiffSubscriptions.size === 0) {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
for (const [subscriptionId, subscription] of this.checkoutDiffSubscriptions) {
|
|
603
|
+
const message = SessionInboundMessageSchema.parse({
|
|
604
|
+
type: "subscribe_checkout_diff_request",
|
|
605
|
+
subscriptionId,
|
|
606
|
+
cwd: subscription.cwd,
|
|
607
|
+
compare: subscription.compare,
|
|
608
|
+
requestId: this.createRequestId(),
|
|
609
|
+
});
|
|
610
|
+
this.sendSessionMessage(message);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
// ============================================================================
|
|
614
|
+
// Agent Lifecycle
|
|
615
|
+
// ============================================================================
|
|
616
|
+
async createAgent(options) {
|
|
617
|
+
const requestId = this.createRequestId(options.requestId);
|
|
618
|
+
const config = resolveAgentConfig(options);
|
|
619
|
+
const message = SessionInboundMessageSchema.parse({
|
|
620
|
+
type: "create_agent_request",
|
|
621
|
+
requestId,
|
|
622
|
+
config,
|
|
623
|
+
...(options.initialPrompt ? { initialPrompt: options.initialPrompt } : {}),
|
|
624
|
+
...(options.images && options.images.length > 0
|
|
625
|
+
? { images: options.images }
|
|
626
|
+
: {}),
|
|
627
|
+
...(options.git ? { git: options.git } : {}),
|
|
628
|
+
...(options.worktreeName ? { worktreeName: options.worktreeName } : {}),
|
|
629
|
+
...(options.labels && Object.keys(options.labels).length > 0
|
|
630
|
+
? { labels: options.labels }
|
|
631
|
+
: {}),
|
|
632
|
+
});
|
|
633
|
+
const status = await this.sendRequest({
|
|
634
|
+
requestId,
|
|
635
|
+
message,
|
|
636
|
+
timeout: 15000,
|
|
637
|
+
options: { skipQueue: true },
|
|
638
|
+
select: (msg) => {
|
|
639
|
+
if (msg.type !== "status") {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
const created = AgentCreatedStatusPayloadSchema.safeParse(msg.payload);
|
|
643
|
+
if (created.success && created.data.requestId === requestId) {
|
|
644
|
+
return created.data;
|
|
645
|
+
}
|
|
646
|
+
const failed = AgentCreateFailedStatusPayloadSchema.safeParse(msg.payload);
|
|
647
|
+
if (failed.success && failed.data.requestId === requestId) {
|
|
648
|
+
return failed.data;
|
|
649
|
+
}
|
|
650
|
+
return null;
|
|
651
|
+
},
|
|
652
|
+
});
|
|
653
|
+
if (status.status === "agent_create_failed") {
|
|
654
|
+
throw new Error(status.error);
|
|
655
|
+
}
|
|
656
|
+
return status.agent;
|
|
657
|
+
}
|
|
658
|
+
async deleteAgent(agentId) {
|
|
659
|
+
const requestId = this.createRequestId();
|
|
660
|
+
const message = SessionInboundMessageSchema.parse({
|
|
661
|
+
type: "delete_agent_request",
|
|
662
|
+
agentId,
|
|
663
|
+
requestId,
|
|
664
|
+
});
|
|
665
|
+
await this.sendRequest({
|
|
666
|
+
requestId,
|
|
667
|
+
message,
|
|
668
|
+
timeout: 10000,
|
|
669
|
+
options: { skipQueue: true },
|
|
670
|
+
select: (msg) => {
|
|
671
|
+
if (msg.type !== "agent_deleted") {
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
if (msg.payload.requestId !== requestId) {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
return msg.payload;
|
|
678
|
+
},
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
async archiveAgent(agentId) {
|
|
682
|
+
const requestId = this.createRequestId();
|
|
683
|
+
const message = SessionInboundMessageSchema.parse({
|
|
684
|
+
type: "archive_agent_request",
|
|
685
|
+
agentId,
|
|
686
|
+
requestId,
|
|
687
|
+
});
|
|
688
|
+
const result = await this.sendRequest({
|
|
689
|
+
requestId,
|
|
690
|
+
message,
|
|
691
|
+
timeout: 10000,
|
|
692
|
+
options: { skipQueue: true },
|
|
693
|
+
select: (msg) => {
|
|
694
|
+
if (msg.type !== "agent_archived") {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
if (msg.payload.requestId !== requestId) {
|
|
698
|
+
return null;
|
|
699
|
+
}
|
|
700
|
+
return msg.payload;
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
return { archivedAt: result.archivedAt };
|
|
704
|
+
}
|
|
705
|
+
async resumeAgent(handle, overrides) {
|
|
706
|
+
const requestId = this.createRequestId();
|
|
707
|
+
const message = SessionInboundMessageSchema.parse({
|
|
708
|
+
type: "resume_agent_request",
|
|
709
|
+
requestId,
|
|
710
|
+
handle,
|
|
711
|
+
...(overrides ? { overrides } : {}),
|
|
712
|
+
});
|
|
713
|
+
const status = await this.sendRequest({
|
|
714
|
+
requestId,
|
|
715
|
+
message,
|
|
716
|
+
timeout: 15000,
|
|
717
|
+
options: { skipQueue: true },
|
|
718
|
+
select: (msg) => {
|
|
719
|
+
if (msg.type !== "status") {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
const resumed = AgentResumedStatusPayloadSchema.safeParse(msg.payload);
|
|
723
|
+
if (resumed.success && resumed.data.requestId === requestId) {
|
|
724
|
+
return resumed.data;
|
|
725
|
+
}
|
|
726
|
+
return null;
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
return status.agent;
|
|
730
|
+
}
|
|
731
|
+
async refreshAgent(agentId, requestId) {
|
|
732
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
733
|
+
const message = SessionInboundMessageSchema.parse({
|
|
734
|
+
type: "refresh_agent_request",
|
|
735
|
+
agentId,
|
|
736
|
+
requestId: resolvedRequestId,
|
|
737
|
+
});
|
|
738
|
+
return this.sendRequest({
|
|
739
|
+
requestId: resolvedRequestId,
|
|
740
|
+
message,
|
|
741
|
+
timeout: 15000,
|
|
742
|
+
options: { skipQueue: true },
|
|
743
|
+
select: (msg) => {
|
|
744
|
+
if (msg.type !== "status") {
|
|
745
|
+
return null;
|
|
746
|
+
}
|
|
747
|
+
const refreshed = AgentRefreshedStatusPayloadSchema.safeParse(msg.payload);
|
|
748
|
+
if (refreshed.success && refreshed.data.requestId === resolvedRequestId) {
|
|
749
|
+
return refreshed.data;
|
|
750
|
+
}
|
|
751
|
+
return null;
|
|
752
|
+
},
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
async initializeAgent(agentId, requestId) {
|
|
756
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
757
|
+
const message = SessionInboundMessageSchema.parse({
|
|
758
|
+
type: "initialize_agent_request",
|
|
759
|
+
agentId,
|
|
760
|
+
requestId: resolvedRequestId,
|
|
761
|
+
});
|
|
762
|
+
const payload = await this.sendRequest({
|
|
763
|
+
requestId: resolvedRequestId,
|
|
764
|
+
message,
|
|
765
|
+
timeout: 10000,
|
|
766
|
+
options: { skipQueue: true },
|
|
767
|
+
select: (msg) => {
|
|
768
|
+
if (msg.type !== "initialize_agent_request") {
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
return msg.payload;
|
|
775
|
+
},
|
|
776
|
+
});
|
|
777
|
+
if (payload.error) {
|
|
778
|
+
throw new Error(payload.error);
|
|
779
|
+
}
|
|
780
|
+
const agent = await this.fetchAgent(agentId);
|
|
781
|
+
if (!agent) {
|
|
782
|
+
throw new Error(`Agent not found after initialize: ${agentId}`);
|
|
783
|
+
}
|
|
784
|
+
return agent;
|
|
785
|
+
}
|
|
786
|
+
// ============================================================================
|
|
787
|
+
// Agent Interaction
|
|
788
|
+
// ============================================================================
|
|
789
|
+
async sendAgentMessage(agentId, text, options) {
|
|
790
|
+
const requestId = this.createRequestId();
|
|
791
|
+
const messageId = options?.messageId ?? crypto.randomUUID();
|
|
792
|
+
const message = SessionInboundMessageSchema.parse({
|
|
793
|
+
type: "send_agent_message_request",
|
|
794
|
+
requestId,
|
|
795
|
+
agentId,
|
|
796
|
+
text,
|
|
797
|
+
...(messageId ? { messageId } : {}),
|
|
798
|
+
...(options?.images ? { images: options.images } : {}),
|
|
799
|
+
});
|
|
800
|
+
const payload = await this.sendRequest({
|
|
801
|
+
requestId,
|
|
802
|
+
message,
|
|
803
|
+
timeout: 15000,
|
|
804
|
+
options: { skipQueue: true },
|
|
805
|
+
select: (msg) => {
|
|
806
|
+
if (msg.type !== "send_agent_message_response") {
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
if (msg.payload.requestId !== requestId) {
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
return msg.payload;
|
|
813
|
+
},
|
|
814
|
+
});
|
|
815
|
+
if (!payload.accepted) {
|
|
816
|
+
throw new Error(payload.error ?? "sendAgentMessage rejected");
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
async sendMessage(agentId, text, options) {
|
|
820
|
+
await this.sendAgentMessage(agentId, text, options);
|
|
821
|
+
}
|
|
822
|
+
async cancelAgent(agentId) {
|
|
823
|
+
this.sendSessionMessage({ type: "cancel_agent_request", agentId });
|
|
824
|
+
}
|
|
825
|
+
async setAgentMode(agentId, modeId) {
|
|
826
|
+
const requestId = this.createRequestId();
|
|
827
|
+
const message = SessionInboundMessageSchema.parse({
|
|
828
|
+
type: "set_agent_mode_request",
|
|
829
|
+
agentId,
|
|
830
|
+
modeId,
|
|
831
|
+
requestId,
|
|
832
|
+
});
|
|
833
|
+
const payload = await this.sendRequest({
|
|
834
|
+
requestId,
|
|
835
|
+
message,
|
|
836
|
+
timeout: 15000,
|
|
837
|
+
options: { skipQueue: true },
|
|
838
|
+
select: (msg) => {
|
|
839
|
+
if (msg.type !== "set_agent_mode_response") {
|
|
840
|
+
return null;
|
|
841
|
+
}
|
|
842
|
+
if (msg.payload.requestId !== requestId) {
|
|
843
|
+
return null;
|
|
844
|
+
}
|
|
845
|
+
return msg.payload;
|
|
846
|
+
},
|
|
847
|
+
});
|
|
848
|
+
if (!payload.accepted) {
|
|
849
|
+
throw new Error(payload.error ?? "setAgentMode rejected");
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
async setAgentModel(agentId, modelId) {
|
|
853
|
+
const requestId = this.createRequestId();
|
|
854
|
+
const message = SessionInboundMessageSchema.parse({
|
|
855
|
+
type: "set_agent_model_request",
|
|
856
|
+
agentId,
|
|
857
|
+
modelId,
|
|
858
|
+
requestId,
|
|
859
|
+
});
|
|
860
|
+
const payload = await this.sendRequest({
|
|
861
|
+
requestId,
|
|
862
|
+
message,
|
|
863
|
+
timeout: 15000,
|
|
864
|
+
options: { skipQueue: true },
|
|
865
|
+
select: (msg) => {
|
|
866
|
+
if (msg.type !== "set_agent_model_response") {
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
869
|
+
if (msg.payload.requestId !== requestId) {
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
return msg.payload;
|
|
873
|
+
},
|
|
874
|
+
});
|
|
875
|
+
if (!payload.accepted) {
|
|
876
|
+
throw new Error(payload.error ?? "setAgentModel rejected");
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
async setAgentThinkingOption(agentId, thinkingOptionId) {
|
|
880
|
+
const requestId = this.createRequestId();
|
|
881
|
+
const message = SessionInboundMessageSchema.parse({
|
|
882
|
+
type: "set_agent_thinking_request",
|
|
883
|
+
agentId,
|
|
884
|
+
thinkingOptionId,
|
|
885
|
+
requestId,
|
|
886
|
+
});
|
|
887
|
+
const payload = await this.sendRequest({
|
|
888
|
+
requestId,
|
|
889
|
+
message,
|
|
890
|
+
timeout: 15000,
|
|
891
|
+
options: { skipQueue: true },
|
|
892
|
+
select: (msg) => {
|
|
893
|
+
if (msg.type !== "set_agent_thinking_response") {
|
|
894
|
+
return null;
|
|
895
|
+
}
|
|
896
|
+
if (msg.payload.requestId !== requestId) {
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
899
|
+
return msg.payload;
|
|
900
|
+
},
|
|
901
|
+
});
|
|
902
|
+
if (!payload.accepted) {
|
|
903
|
+
throw new Error(payload.error ?? "setAgentThinkingOption rejected");
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
async restartServer(reason, requestId) {
|
|
907
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
908
|
+
const message = SessionInboundMessageSchema.parse({
|
|
909
|
+
type: "restart_server_request",
|
|
910
|
+
...(reason && reason.trim().length > 0 ? { reason } : {}),
|
|
911
|
+
requestId: resolvedRequestId,
|
|
912
|
+
});
|
|
913
|
+
return this.sendRequest({
|
|
914
|
+
requestId: resolvedRequestId,
|
|
915
|
+
message,
|
|
916
|
+
timeout: 10000,
|
|
917
|
+
options: { skipQueue: true },
|
|
918
|
+
select: (msg) => {
|
|
919
|
+
if (msg.type !== "status") {
|
|
920
|
+
return null;
|
|
921
|
+
}
|
|
922
|
+
const restarted = RestartRequestedStatusPayloadSchema.safeParse(msg.payload);
|
|
923
|
+
if (!restarted.success) {
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
926
|
+
if (restarted.data.requestId !== resolvedRequestId) {
|
|
927
|
+
return null;
|
|
928
|
+
}
|
|
929
|
+
return restarted.data;
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
// ============================================================================
|
|
934
|
+
// Audio / Voice
|
|
935
|
+
// ============================================================================
|
|
936
|
+
async setVoiceMode(enabled, agentId) {
|
|
937
|
+
const requestId = this.createRequestId();
|
|
938
|
+
const message = SessionInboundMessageSchema.parse({
|
|
939
|
+
type: "set_voice_mode",
|
|
940
|
+
enabled,
|
|
941
|
+
...(agentId ? { agentId } : {}),
|
|
942
|
+
requestId,
|
|
943
|
+
});
|
|
944
|
+
return this.sendRequest({
|
|
945
|
+
requestId,
|
|
946
|
+
message,
|
|
947
|
+
timeout: 10000,
|
|
948
|
+
select: (msg) => {
|
|
949
|
+
if (msg.type !== "set_voice_mode_response") {
|
|
950
|
+
return null;
|
|
951
|
+
}
|
|
952
|
+
if (msg.payload.requestId !== requestId) {
|
|
953
|
+
return null;
|
|
954
|
+
}
|
|
955
|
+
return msg.payload;
|
|
956
|
+
},
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
async sendVoiceAudioChunk(audio, format, isLast) {
|
|
960
|
+
this.sendSessionMessage({ type: "voice_audio_chunk", audio, format, isLast });
|
|
961
|
+
}
|
|
962
|
+
startDictationStream(dictationId, format) {
|
|
963
|
+
const ack = this.waitForWithCancel((msg) => {
|
|
964
|
+
if (msg.type !== "dictation_stream_ack") {
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
if (msg.payload.dictationId !== dictationId) {
|
|
968
|
+
return null;
|
|
969
|
+
}
|
|
970
|
+
if (msg.payload.ackSeq !== -1) {
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
return msg.payload;
|
|
974
|
+
}, 30000, { skipQueue: true });
|
|
975
|
+
const ackPromise = ack.promise.then(() => undefined);
|
|
976
|
+
const streamError = this.waitForWithCancel((msg) => {
|
|
977
|
+
if (msg.type !== "dictation_stream_error") {
|
|
978
|
+
return null;
|
|
979
|
+
}
|
|
980
|
+
if (msg.payload.dictationId !== dictationId) {
|
|
981
|
+
return null;
|
|
982
|
+
}
|
|
983
|
+
return msg.payload;
|
|
984
|
+
}, 30000, { skipQueue: true });
|
|
985
|
+
const errorPromise = streamError.promise.then((payload) => {
|
|
986
|
+
throw new Error(payload.error);
|
|
987
|
+
});
|
|
988
|
+
try {
|
|
989
|
+
this.sendSessionMessageStrict({ type: "dictation_stream_start", dictationId, format });
|
|
990
|
+
}
|
|
991
|
+
catch (error) {
|
|
992
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
993
|
+
ack.cancel(err);
|
|
994
|
+
streamError.cancel(err);
|
|
995
|
+
void ackPromise.catch(() => undefined);
|
|
996
|
+
void errorPromise.catch(() => undefined);
|
|
997
|
+
throw err;
|
|
998
|
+
}
|
|
999
|
+
return Promise.race([ackPromise, errorPromise]);
|
|
1000
|
+
}
|
|
1001
|
+
sendDictationStreamChunk(dictationId, seq, audio, format) {
|
|
1002
|
+
this.sendSessionMessageStrict({ type: "dictation_stream_chunk", dictationId, seq, audio, format });
|
|
1003
|
+
}
|
|
1004
|
+
finishDictationStream(dictationId, finalSeq) {
|
|
1005
|
+
const final = this.waitForWithCancel((msg) => {
|
|
1006
|
+
if (msg.type !== "dictation_stream_final") {
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
if (msg.payload.dictationId !== dictationId) {
|
|
1010
|
+
return null;
|
|
1011
|
+
}
|
|
1012
|
+
return msg.payload;
|
|
1013
|
+
}, 30000, { skipQueue: true });
|
|
1014
|
+
const streamError = this.waitForWithCancel((msg) => {
|
|
1015
|
+
if (msg.type !== "dictation_stream_error") {
|
|
1016
|
+
return null;
|
|
1017
|
+
}
|
|
1018
|
+
if (msg.payload.dictationId !== dictationId) {
|
|
1019
|
+
return null;
|
|
1020
|
+
}
|
|
1021
|
+
return msg.payload;
|
|
1022
|
+
}, 30000, { skipQueue: true });
|
|
1023
|
+
const finalPromise = final.promise;
|
|
1024
|
+
const errorPromise = streamError.promise.then((payload) => {
|
|
1025
|
+
throw new Error(payload.error);
|
|
1026
|
+
});
|
|
1027
|
+
try {
|
|
1028
|
+
this.sendSessionMessageStrict({ type: "dictation_stream_finish", dictationId, finalSeq });
|
|
1029
|
+
}
|
|
1030
|
+
catch (error) {
|
|
1031
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1032
|
+
final.cancel(err);
|
|
1033
|
+
streamError.cancel(err);
|
|
1034
|
+
void finalPromise.catch(() => undefined);
|
|
1035
|
+
void errorPromise.catch(() => undefined);
|
|
1036
|
+
throw err;
|
|
1037
|
+
}
|
|
1038
|
+
return Promise.race([finalPromise, errorPromise]);
|
|
1039
|
+
}
|
|
1040
|
+
cancelDictationStream(dictationId) {
|
|
1041
|
+
this.sendSessionMessageStrict({ type: "dictation_stream_cancel", dictationId });
|
|
1042
|
+
}
|
|
1043
|
+
async abortRequest() {
|
|
1044
|
+
this.sendSessionMessage({ type: "abort_request" });
|
|
1045
|
+
}
|
|
1046
|
+
async audioPlayed(id) {
|
|
1047
|
+
this.sendSessionMessage({ type: "audio_played", id });
|
|
1048
|
+
}
|
|
1049
|
+
// ============================================================================
|
|
1050
|
+
// Git Operations
|
|
1051
|
+
// ============================================================================
|
|
1052
|
+
async getCheckoutStatus(cwd, options) {
|
|
1053
|
+
const requestId = options?.requestId;
|
|
1054
|
+
if (!requestId) {
|
|
1055
|
+
const existing = this.checkoutStatusInFlight.get(cwd);
|
|
1056
|
+
if (existing) {
|
|
1057
|
+
return existing;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1061
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1062
|
+
type: "checkout_status_request",
|
|
1063
|
+
cwd,
|
|
1064
|
+
requestId: resolvedRequestId,
|
|
1065
|
+
});
|
|
1066
|
+
const responsePromise = this.sendRequest({
|
|
1067
|
+
requestId: resolvedRequestId,
|
|
1068
|
+
message,
|
|
1069
|
+
timeout: 60000,
|
|
1070
|
+
options: { skipQueue: true },
|
|
1071
|
+
select: (msg) => {
|
|
1072
|
+
if (msg.type !== "checkout_status_response") {
|
|
1073
|
+
return null;
|
|
1074
|
+
}
|
|
1075
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
return msg.payload;
|
|
1079
|
+
},
|
|
1080
|
+
});
|
|
1081
|
+
if (!requestId) {
|
|
1082
|
+
this.checkoutStatusInFlight.set(cwd, responsePromise);
|
|
1083
|
+
void responsePromise
|
|
1084
|
+
.finally(() => {
|
|
1085
|
+
if (this.checkoutStatusInFlight.get(cwd) === responsePromise) {
|
|
1086
|
+
this.checkoutStatusInFlight.delete(cwd);
|
|
1087
|
+
}
|
|
1088
|
+
})
|
|
1089
|
+
.catch(() => undefined);
|
|
1090
|
+
}
|
|
1091
|
+
return responsePromise;
|
|
1092
|
+
}
|
|
1093
|
+
normalizeCheckoutDiffCompare(compare) {
|
|
1094
|
+
if (compare.mode === "uncommitted") {
|
|
1095
|
+
return { mode: "uncommitted" };
|
|
1096
|
+
}
|
|
1097
|
+
const trimmedBaseRef = compare.baseRef?.trim();
|
|
1098
|
+
if (!trimmedBaseRef) {
|
|
1099
|
+
return { mode: "base" };
|
|
1100
|
+
}
|
|
1101
|
+
return { mode: "base", baseRef: trimmedBaseRef };
|
|
1102
|
+
}
|
|
1103
|
+
async getCheckoutDiff(cwd, compare, requestId) {
|
|
1104
|
+
const oneShotSubscriptionId = `oneshot-checkout-diff:${crypto.randomUUID()}`;
|
|
1105
|
+
try {
|
|
1106
|
+
const payload = await this.subscribeCheckoutDiff(cwd, compare, {
|
|
1107
|
+
subscriptionId: oneShotSubscriptionId,
|
|
1108
|
+
requestId,
|
|
1109
|
+
});
|
|
1110
|
+
return {
|
|
1111
|
+
cwd: payload.cwd,
|
|
1112
|
+
files: payload.files,
|
|
1113
|
+
error: payload.error,
|
|
1114
|
+
requestId: payload.requestId,
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
finally {
|
|
1118
|
+
try {
|
|
1119
|
+
this.unsubscribeCheckoutDiff(oneShotSubscriptionId);
|
|
1120
|
+
}
|
|
1121
|
+
catch {
|
|
1122
|
+
// Ignore disconnect races during one-shot cleanup.
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
async subscribeCheckoutDiff(cwd, compare, options) {
|
|
1127
|
+
const subscriptionId = options?.subscriptionId ?? crypto.randomUUID();
|
|
1128
|
+
const normalizedCompare = this.normalizeCheckoutDiffCompare(compare);
|
|
1129
|
+
const previousSubscription = this.checkoutDiffSubscriptions.get(subscriptionId) ?? null;
|
|
1130
|
+
this.checkoutDiffSubscriptions.set(subscriptionId, {
|
|
1131
|
+
cwd,
|
|
1132
|
+
compare: normalizedCompare,
|
|
1133
|
+
});
|
|
1134
|
+
const resolvedRequestId = this.createRequestId(options?.requestId);
|
|
1135
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1136
|
+
type: "subscribe_checkout_diff_request",
|
|
1137
|
+
subscriptionId,
|
|
1138
|
+
cwd,
|
|
1139
|
+
compare: normalizedCompare,
|
|
1140
|
+
requestId: resolvedRequestId,
|
|
1141
|
+
});
|
|
1142
|
+
try {
|
|
1143
|
+
return await this.sendRequest({
|
|
1144
|
+
requestId: resolvedRequestId,
|
|
1145
|
+
message,
|
|
1146
|
+
timeout: 60000,
|
|
1147
|
+
options: { skipQueue: true },
|
|
1148
|
+
select: (msg) => {
|
|
1149
|
+
if (msg.type !== "subscribe_checkout_diff_response") {
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1153
|
+
return null;
|
|
1154
|
+
}
|
|
1155
|
+
if (msg.payload.subscriptionId !== subscriptionId) {
|
|
1156
|
+
return null;
|
|
1157
|
+
}
|
|
1158
|
+
return msg.payload;
|
|
1159
|
+
},
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
catch (error) {
|
|
1163
|
+
if (previousSubscription) {
|
|
1164
|
+
this.checkoutDiffSubscriptions.set(subscriptionId, previousSubscription);
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
this.checkoutDiffSubscriptions.delete(subscriptionId);
|
|
1168
|
+
}
|
|
1169
|
+
throw error;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
unsubscribeCheckoutDiff(subscriptionId) {
|
|
1173
|
+
this.checkoutDiffSubscriptions.delete(subscriptionId);
|
|
1174
|
+
this.sendSessionMessage({
|
|
1175
|
+
type: "unsubscribe_checkout_diff_request",
|
|
1176
|
+
subscriptionId,
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
async checkoutCommit(cwd, input, requestId) {
|
|
1180
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1181
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1182
|
+
type: "checkout_commit_request",
|
|
1183
|
+
cwd,
|
|
1184
|
+
message: input.message,
|
|
1185
|
+
addAll: input.addAll,
|
|
1186
|
+
requestId: resolvedRequestId,
|
|
1187
|
+
});
|
|
1188
|
+
return this.sendRequest({
|
|
1189
|
+
requestId: resolvedRequestId,
|
|
1190
|
+
message,
|
|
1191
|
+
timeout: 60000,
|
|
1192
|
+
options: { skipQueue: true },
|
|
1193
|
+
select: (msg) => {
|
|
1194
|
+
if (msg.type !== "checkout_commit_response") {
|
|
1195
|
+
return null;
|
|
1196
|
+
}
|
|
1197
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1198
|
+
return null;
|
|
1199
|
+
}
|
|
1200
|
+
return msg.payload;
|
|
1201
|
+
},
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
async checkoutMerge(cwd, input, requestId) {
|
|
1205
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1206
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1207
|
+
type: "checkout_merge_request",
|
|
1208
|
+
cwd,
|
|
1209
|
+
baseRef: input.baseRef,
|
|
1210
|
+
strategy: input.strategy,
|
|
1211
|
+
requireCleanTarget: input.requireCleanTarget,
|
|
1212
|
+
requestId: resolvedRequestId,
|
|
1213
|
+
});
|
|
1214
|
+
return this.sendRequest({
|
|
1215
|
+
requestId: resolvedRequestId,
|
|
1216
|
+
message,
|
|
1217
|
+
timeout: 60000,
|
|
1218
|
+
options: { skipQueue: true },
|
|
1219
|
+
select: (msg) => {
|
|
1220
|
+
if (msg.type !== "checkout_merge_response") {
|
|
1221
|
+
return null;
|
|
1222
|
+
}
|
|
1223
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1224
|
+
return null;
|
|
1225
|
+
}
|
|
1226
|
+
return msg.payload;
|
|
1227
|
+
},
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
async checkoutMergeFromBase(cwd, input, requestId) {
|
|
1231
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1232
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1233
|
+
type: "checkout_merge_from_base_request",
|
|
1234
|
+
cwd,
|
|
1235
|
+
baseRef: input.baseRef,
|
|
1236
|
+
requireCleanTarget: input.requireCleanTarget,
|
|
1237
|
+
requestId: resolvedRequestId,
|
|
1238
|
+
});
|
|
1239
|
+
return this.sendRequest({
|
|
1240
|
+
requestId: resolvedRequestId,
|
|
1241
|
+
message,
|
|
1242
|
+
timeout: 60000,
|
|
1243
|
+
options: { skipQueue: true },
|
|
1244
|
+
select: (msg) => {
|
|
1245
|
+
if (msg.type !== "checkout_merge_from_base_response") {
|
|
1246
|
+
return null;
|
|
1247
|
+
}
|
|
1248
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
return msg.payload;
|
|
1252
|
+
},
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
async checkoutPush(cwd, requestId) {
|
|
1256
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1257
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1258
|
+
type: "checkout_push_request",
|
|
1259
|
+
cwd,
|
|
1260
|
+
requestId: resolvedRequestId,
|
|
1261
|
+
});
|
|
1262
|
+
return this.sendRequest({
|
|
1263
|
+
requestId: resolvedRequestId,
|
|
1264
|
+
message,
|
|
1265
|
+
timeout: 60000,
|
|
1266
|
+
options: { skipQueue: true },
|
|
1267
|
+
select: (msg) => {
|
|
1268
|
+
if (msg.type !== "checkout_push_response") {
|
|
1269
|
+
return null;
|
|
1270
|
+
}
|
|
1271
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1272
|
+
return null;
|
|
1273
|
+
}
|
|
1274
|
+
return msg.payload;
|
|
1275
|
+
},
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
async checkoutPrCreate(cwd, input, requestId) {
|
|
1279
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1280
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1281
|
+
type: "checkout_pr_create_request",
|
|
1282
|
+
cwd,
|
|
1283
|
+
title: input.title,
|
|
1284
|
+
body: input.body,
|
|
1285
|
+
baseRef: input.baseRef,
|
|
1286
|
+
requestId: resolvedRequestId,
|
|
1287
|
+
});
|
|
1288
|
+
return this.sendRequest({
|
|
1289
|
+
requestId: resolvedRequestId,
|
|
1290
|
+
message,
|
|
1291
|
+
timeout: 60000,
|
|
1292
|
+
options: { skipQueue: true },
|
|
1293
|
+
select: (msg) => {
|
|
1294
|
+
if (msg.type !== "checkout_pr_create_response") {
|
|
1295
|
+
return null;
|
|
1296
|
+
}
|
|
1297
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1298
|
+
return null;
|
|
1299
|
+
}
|
|
1300
|
+
return msg.payload;
|
|
1301
|
+
},
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
async checkoutPrStatus(cwd, requestId) {
|
|
1305
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1306
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1307
|
+
type: "checkout_pr_status_request",
|
|
1308
|
+
cwd,
|
|
1309
|
+
requestId: resolvedRequestId,
|
|
1310
|
+
});
|
|
1311
|
+
return this.sendRequest({
|
|
1312
|
+
requestId: resolvedRequestId,
|
|
1313
|
+
message,
|
|
1314
|
+
timeout: 60000,
|
|
1315
|
+
options: { skipQueue: true },
|
|
1316
|
+
select: (msg) => {
|
|
1317
|
+
if (msg.type !== "checkout_pr_status_response") {
|
|
1318
|
+
return null;
|
|
1319
|
+
}
|
|
1320
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1321
|
+
return null;
|
|
1322
|
+
}
|
|
1323
|
+
return msg.payload;
|
|
1324
|
+
},
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
async getPaseoWorktreeList(input, requestId) {
|
|
1328
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1329
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1330
|
+
type: "paseo_worktree_list_request",
|
|
1331
|
+
cwd: input.cwd,
|
|
1332
|
+
repoRoot: input.repoRoot,
|
|
1333
|
+
requestId: resolvedRequestId,
|
|
1334
|
+
});
|
|
1335
|
+
return this.sendRequest({
|
|
1336
|
+
requestId: resolvedRequestId,
|
|
1337
|
+
message,
|
|
1338
|
+
timeout: 60000,
|
|
1339
|
+
options: { skipQueue: true },
|
|
1340
|
+
select: (msg) => {
|
|
1341
|
+
if (msg.type !== "paseo_worktree_list_response") {
|
|
1342
|
+
return null;
|
|
1343
|
+
}
|
|
1344
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1345
|
+
return null;
|
|
1346
|
+
}
|
|
1347
|
+
return msg.payload;
|
|
1348
|
+
},
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
async archivePaseoWorktree(input, requestId) {
|
|
1352
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1353
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1354
|
+
type: "paseo_worktree_archive_request",
|
|
1355
|
+
worktreePath: input.worktreePath,
|
|
1356
|
+
repoRoot: input.repoRoot,
|
|
1357
|
+
branchName: input.branchName,
|
|
1358
|
+
requestId: resolvedRequestId,
|
|
1359
|
+
});
|
|
1360
|
+
return this.sendRequest({
|
|
1361
|
+
requestId: resolvedRequestId,
|
|
1362
|
+
message,
|
|
1363
|
+
timeout: 20000,
|
|
1364
|
+
options: { skipQueue: true },
|
|
1365
|
+
select: (msg) => {
|
|
1366
|
+
if (msg.type !== "paseo_worktree_archive_response") {
|
|
1367
|
+
return null;
|
|
1368
|
+
}
|
|
1369
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1372
|
+
return msg.payload;
|
|
1373
|
+
},
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
async getGitDiff(agentId, requestId) {
|
|
1377
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1378
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1379
|
+
type: "git_diff_request",
|
|
1380
|
+
agentId,
|
|
1381
|
+
requestId: resolvedRequestId,
|
|
1382
|
+
});
|
|
1383
|
+
return this.sendRequest({
|
|
1384
|
+
requestId: resolvedRequestId,
|
|
1385
|
+
message,
|
|
1386
|
+
timeout: 10000,
|
|
1387
|
+
options: { skipQueue: true },
|
|
1388
|
+
select: (msg) => {
|
|
1389
|
+
if (msg.type !== "git_diff_response") {
|
|
1390
|
+
return null;
|
|
1391
|
+
}
|
|
1392
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1393
|
+
return null;
|
|
1394
|
+
}
|
|
1395
|
+
return msg.payload;
|
|
1396
|
+
},
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
async getHighlightedDiff(agentId, requestId) {
|
|
1400
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1401
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1402
|
+
type: "highlighted_diff_request",
|
|
1403
|
+
agentId,
|
|
1404
|
+
requestId: resolvedRequestId,
|
|
1405
|
+
});
|
|
1406
|
+
return this.sendRequest({
|
|
1407
|
+
requestId: resolvedRequestId,
|
|
1408
|
+
message,
|
|
1409
|
+
timeout: 10000,
|
|
1410
|
+
options: { skipQueue: true },
|
|
1411
|
+
select: (msg) => {
|
|
1412
|
+
if (msg.type !== "highlighted_diff_response") {
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1416
|
+
return null;
|
|
1417
|
+
}
|
|
1418
|
+
return msg.payload;
|
|
1419
|
+
},
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
async validateBranch(options, requestId) {
|
|
1423
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1424
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1425
|
+
type: "validate_branch_request",
|
|
1426
|
+
cwd: options.cwd,
|
|
1427
|
+
branchName: options.branchName,
|
|
1428
|
+
requestId: resolvedRequestId,
|
|
1429
|
+
});
|
|
1430
|
+
return this.sendRequest({
|
|
1431
|
+
requestId: resolvedRequestId,
|
|
1432
|
+
message,
|
|
1433
|
+
timeout: 10000,
|
|
1434
|
+
options: { skipQueue: true },
|
|
1435
|
+
select: (msg) => {
|
|
1436
|
+
if (msg.type !== "validate_branch_response") {
|
|
1437
|
+
return null;
|
|
1438
|
+
}
|
|
1439
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1440
|
+
return null;
|
|
1441
|
+
}
|
|
1442
|
+
return msg.payload;
|
|
1443
|
+
},
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
// ============================================================================
|
|
1447
|
+
// File Explorer
|
|
1448
|
+
// ============================================================================
|
|
1449
|
+
async exploreFileSystem(agentId, path, mode = "list", requestId) {
|
|
1450
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1451
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1452
|
+
type: "file_explorer_request",
|
|
1453
|
+
agentId,
|
|
1454
|
+
path,
|
|
1455
|
+
mode,
|
|
1456
|
+
requestId: resolvedRequestId,
|
|
1457
|
+
});
|
|
1458
|
+
return this.sendRequest({
|
|
1459
|
+
requestId: resolvedRequestId,
|
|
1460
|
+
message,
|
|
1461
|
+
timeout: 10000,
|
|
1462
|
+
options: { skipQueue: true },
|
|
1463
|
+
select: (msg) => {
|
|
1464
|
+
if (msg.type !== "file_explorer_response") {
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1468
|
+
return null;
|
|
1469
|
+
}
|
|
1470
|
+
return msg.payload;
|
|
1471
|
+
},
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
async requestDownloadToken(agentId, path, requestId) {
|
|
1475
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1476
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1477
|
+
type: "file_download_token_request",
|
|
1478
|
+
agentId,
|
|
1479
|
+
path,
|
|
1480
|
+
requestId: resolvedRequestId,
|
|
1481
|
+
});
|
|
1482
|
+
return this.sendRequest({
|
|
1483
|
+
requestId: resolvedRequestId,
|
|
1484
|
+
message,
|
|
1485
|
+
timeout: 10000,
|
|
1486
|
+
options: { skipQueue: true },
|
|
1487
|
+
select: (msg) => {
|
|
1488
|
+
if (msg.type !== "file_download_token_response") {
|
|
1489
|
+
return null;
|
|
1490
|
+
}
|
|
1491
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1492
|
+
return null;
|
|
1493
|
+
}
|
|
1494
|
+
return msg.payload;
|
|
1495
|
+
},
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
async requestProjectIcon(cwd, requestId) {
|
|
1499
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1500
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1501
|
+
type: "project_icon_request",
|
|
1502
|
+
cwd,
|
|
1503
|
+
requestId: resolvedRequestId,
|
|
1504
|
+
});
|
|
1505
|
+
return this.sendRequest({
|
|
1506
|
+
requestId: resolvedRequestId,
|
|
1507
|
+
message,
|
|
1508
|
+
timeout: 10000,
|
|
1509
|
+
options: { skipQueue: true },
|
|
1510
|
+
select: (msg) => {
|
|
1511
|
+
if (msg.type !== "project_icon_response") {
|
|
1512
|
+
return null;
|
|
1513
|
+
}
|
|
1514
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1515
|
+
return null;
|
|
1516
|
+
}
|
|
1517
|
+
return msg.payload;
|
|
1518
|
+
},
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
// ============================================================================
|
|
1522
|
+
// Provider Models / Commands
|
|
1523
|
+
// ============================================================================
|
|
1524
|
+
async listProviderModels(provider, options) {
|
|
1525
|
+
const resolvedRequestId = this.createRequestId(options?.requestId);
|
|
1526
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1527
|
+
type: "list_provider_models_request",
|
|
1528
|
+
provider,
|
|
1529
|
+
cwd: options?.cwd,
|
|
1530
|
+
requestId: resolvedRequestId,
|
|
1531
|
+
});
|
|
1532
|
+
return this.sendRequest({
|
|
1533
|
+
requestId: resolvedRequestId,
|
|
1534
|
+
message,
|
|
1535
|
+
timeout: 30000,
|
|
1536
|
+
options: { skipQueue: true },
|
|
1537
|
+
select: (msg) => {
|
|
1538
|
+
if (msg.type !== "list_provider_models_response") {
|
|
1539
|
+
return null;
|
|
1540
|
+
}
|
|
1541
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1542
|
+
return null;
|
|
1543
|
+
}
|
|
1544
|
+
return msg.payload;
|
|
1545
|
+
},
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
async listSpeechModels(requestId) {
|
|
1549
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1550
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1551
|
+
type: "speech_models_list_request",
|
|
1552
|
+
requestId: resolvedRequestId,
|
|
1553
|
+
});
|
|
1554
|
+
return this.sendRequest({
|
|
1555
|
+
requestId: resolvedRequestId,
|
|
1556
|
+
message,
|
|
1557
|
+
timeout: 30000,
|
|
1558
|
+
options: { skipQueue: true },
|
|
1559
|
+
select: (msg) => {
|
|
1560
|
+
if (msg.type !== "speech_models_list_response") {
|
|
1561
|
+
return null;
|
|
1562
|
+
}
|
|
1563
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1564
|
+
return null;
|
|
1565
|
+
}
|
|
1566
|
+
return msg.payload;
|
|
1567
|
+
},
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
async downloadSpeechModels(options) {
|
|
1571
|
+
const resolvedRequestId = this.createRequestId(options?.requestId);
|
|
1572
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1573
|
+
type: "speech_models_download_request",
|
|
1574
|
+
modelIds: options?.modelIds,
|
|
1575
|
+
requestId: resolvedRequestId,
|
|
1576
|
+
});
|
|
1577
|
+
return this.sendRequest({
|
|
1578
|
+
requestId: resolvedRequestId,
|
|
1579
|
+
message,
|
|
1580
|
+
timeout: 30 * 60 * 1000,
|
|
1581
|
+
options: { skipQueue: true },
|
|
1582
|
+
select: (msg) => {
|
|
1583
|
+
if (msg.type !== "speech_models_download_response") {
|
|
1584
|
+
return null;
|
|
1585
|
+
}
|
|
1586
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1587
|
+
return null;
|
|
1588
|
+
}
|
|
1589
|
+
return msg.payload;
|
|
1590
|
+
},
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
async listCommands(agentId, requestId) {
|
|
1594
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1595
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1596
|
+
type: "list_commands_request",
|
|
1597
|
+
agentId,
|
|
1598
|
+
requestId: resolvedRequestId,
|
|
1599
|
+
});
|
|
1600
|
+
return this.sendRequest({
|
|
1601
|
+
requestId: resolvedRequestId,
|
|
1602
|
+
message,
|
|
1603
|
+
timeout: 30000,
|
|
1604
|
+
options: { skipQueue: true },
|
|
1605
|
+
select: (msg) => {
|
|
1606
|
+
if (msg.type !== "list_commands_response") {
|
|
1607
|
+
return null;
|
|
1608
|
+
}
|
|
1609
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1610
|
+
return null;
|
|
1611
|
+
}
|
|
1612
|
+
return msg.payload;
|
|
1613
|
+
},
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
async executeCommand(agentId, commandName, args, requestId) {
|
|
1617
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1618
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1619
|
+
type: "execute_command_request",
|
|
1620
|
+
agentId,
|
|
1621
|
+
commandName,
|
|
1622
|
+
args,
|
|
1623
|
+
requestId: resolvedRequestId,
|
|
1624
|
+
});
|
|
1625
|
+
return this.sendRequest({
|
|
1626
|
+
requestId: resolvedRequestId,
|
|
1627
|
+
message,
|
|
1628
|
+
timeout: 30000,
|
|
1629
|
+
options: { skipQueue: true },
|
|
1630
|
+
select: (msg) => {
|
|
1631
|
+
if (msg.type !== "execute_command_response") {
|
|
1632
|
+
return null;
|
|
1633
|
+
}
|
|
1634
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
return msg.payload;
|
|
1638
|
+
},
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
// ============================================================================
|
|
1642
|
+
// Permissions
|
|
1643
|
+
// ============================================================================
|
|
1644
|
+
async respondToPermission(agentId, requestId, response) {
|
|
1645
|
+
this.sendSessionMessage({
|
|
1646
|
+
type: "agent_permission_response",
|
|
1647
|
+
agentId,
|
|
1648
|
+
requestId,
|
|
1649
|
+
response,
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1652
|
+
async respondToPermissionAndWait(agentId, requestId, response, timeout = 15000) {
|
|
1653
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1654
|
+
type: "agent_permission_response",
|
|
1655
|
+
agentId,
|
|
1656
|
+
requestId,
|
|
1657
|
+
response,
|
|
1658
|
+
});
|
|
1659
|
+
return this.sendRequest({
|
|
1660
|
+
requestId,
|
|
1661
|
+
message,
|
|
1662
|
+
timeout,
|
|
1663
|
+
options: { skipQueue: true },
|
|
1664
|
+
select: (msg) => {
|
|
1665
|
+
if (msg.type !== "agent_permission_resolved") {
|
|
1666
|
+
return null;
|
|
1667
|
+
}
|
|
1668
|
+
if (msg.payload.requestId !== requestId) {
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
if (msg.payload.agentId !== agentId) {
|
|
1672
|
+
return null;
|
|
1673
|
+
}
|
|
1674
|
+
return msg.payload;
|
|
1675
|
+
},
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
// ============================================================================
|
|
1679
|
+
// Waiting / Streaming Helpers
|
|
1680
|
+
// ============================================================================
|
|
1681
|
+
async waitForAgentUpsert(agentId, predicate, timeout = 60000) {
|
|
1682
|
+
const startedAt = Date.now();
|
|
1683
|
+
while (Date.now() - startedAt < timeout) {
|
|
1684
|
+
const snapshot = await this.fetchAgent(agentId).catch(() => null);
|
|
1685
|
+
if (snapshot && predicate(snapshot)) {
|
|
1686
|
+
return snapshot;
|
|
1687
|
+
}
|
|
1688
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
1689
|
+
}
|
|
1690
|
+
throw new Error(`Timed out waiting for agent ${agentId}`);
|
|
1691
|
+
}
|
|
1692
|
+
async waitForFinish(agentId, timeout = 60000) {
|
|
1693
|
+
const requestId = this.createRequestId();
|
|
1694
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1695
|
+
type: "wait_for_finish_request",
|
|
1696
|
+
requestId,
|
|
1697
|
+
agentId,
|
|
1698
|
+
timeoutMs: timeout,
|
|
1699
|
+
});
|
|
1700
|
+
const payload = await this.sendRequest({
|
|
1701
|
+
requestId,
|
|
1702
|
+
message,
|
|
1703
|
+
timeout: timeout + 5000,
|
|
1704
|
+
options: { skipQueue: true },
|
|
1705
|
+
select: (msg) => {
|
|
1706
|
+
if (msg.type !== "wait_for_finish_response") {
|
|
1707
|
+
return null;
|
|
1708
|
+
}
|
|
1709
|
+
if (msg.payload.requestId !== requestId) {
|
|
1710
|
+
return null;
|
|
1711
|
+
}
|
|
1712
|
+
return msg.payload;
|
|
1713
|
+
},
|
|
1714
|
+
});
|
|
1715
|
+
return {
|
|
1716
|
+
status: payload.status,
|
|
1717
|
+
final: payload.final,
|
|
1718
|
+
error: payload.error,
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
// ============================================================================
|
|
1722
|
+
// Terminals
|
|
1723
|
+
// ============================================================================
|
|
1724
|
+
async listTerminals(cwd, requestId) {
|
|
1725
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1726
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1727
|
+
type: "list_terminals_request",
|
|
1728
|
+
cwd,
|
|
1729
|
+
requestId: resolvedRequestId,
|
|
1730
|
+
});
|
|
1731
|
+
return this.sendRequest({
|
|
1732
|
+
requestId: resolvedRequestId,
|
|
1733
|
+
message,
|
|
1734
|
+
timeout: 10000,
|
|
1735
|
+
options: { skipQueue: true },
|
|
1736
|
+
select: (msg) => {
|
|
1737
|
+
if (msg.type !== "list_terminals_response") {
|
|
1738
|
+
return null;
|
|
1739
|
+
}
|
|
1740
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1741
|
+
return null;
|
|
1742
|
+
}
|
|
1743
|
+
return msg.payload;
|
|
1744
|
+
},
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
async createTerminal(cwd, name, requestId) {
|
|
1748
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1749
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1750
|
+
type: "create_terminal_request",
|
|
1751
|
+
cwd,
|
|
1752
|
+
name,
|
|
1753
|
+
requestId: resolvedRequestId,
|
|
1754
|
+
});
|
|
1755
|
+
return this.sendRequest({
|
|
1756
|
+
requestId: resolvedRequestId,
|
|
1757
|
+
message,
|
|
1758
|
+
timeout: 10000,
|
|
1759
|
+
options: { skipQueue: true },
|
|
1760
|
+
select: (msg) => {
|
|
1761
|
+
if (msg.type !== "create_terminal_response") {
|
|
1762
|
+
return null;
|
|
1763
|
+
}
|
|
1764
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1765
|
+
return null;
|
|
1766
|
+
}
|
|
1767
|
+
return msg.payload;
|
|
1768
|
+
},
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
async subscribeTerminal(terminalId, requestId) {
|
|
1772
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1773
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1774
|
+
type: "subscribe_terminal_request",
|
|
1775
|
+
terminalId,
|
|
1776
|
+
requestId: resolvedRequestId,
|
|
1777
|
+
});
|
|
1778
|
+
return this.sendRequest({
|
|
1779
|
+
requestId: resolvedRequestId,
|
|
1780
|
+
message,
|
|
1781
|
+
timeout: 10000,
|
|
1782
|
+
options: { skipQueue: true },
|
|
1783
|
+
select: (msg) => {
|
|
1784
|
+
if (msg.type !== "subscribe_terminal_response") {
|
|
1785
|
+
return null;
|
|
1786
|
+
}
|
|
1787
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1788
|
+
return null;
|
|
1789
|
+
}
|
|
1790
|
+
return msg.payload;
|
|
1791
|
+
},
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
unsubscribeTerminal(terminalId) {
|
|
1795
|
+
this.sendSessionMessage({
|
|
1796
|
+
type: "unsubscribe_terminal_request",
|
|
1797
|
+
terminalId,
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
sendTerminalInput(terminalId, message) {
|
|
1801
|
+
this.sendSessionMessage({
|
|
1802
|
+
type: "terminal_input",
|
|
1803
|
+
terminalId,
|
|
1804
|
+
message,
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
async killTerminal(terminalId, requestId) {
|
|
1808
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1809
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1810
|
+
type: "kill_terminal_request",
|
|
1811
|
+
terminalId,
|
|
1812
|
+
requestId: resolvedRequestId,
|
|
1813
|
+
});
|
|
1814
|
+
return this.sendRequest({
|
|
1815
|
+
requestId: resolvedRequestId,
|
|
1816
|
+
message,
|
|
1817
|
+
timeout: 10000,
|
|
1818
|
+
options: { skipQueue: true },
|
|
1819
|
+
select: (msg) => {
|
|
1820
|
+
if (msg.type !== "kill_terminal_response") {
|
|
1821
|
+
return null;
|
|
1822
|
+
}
|
|
1823
|
+
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1824
|
+
return null;
|
|
1825
|
+
}
|
|
1826
|
+
return msg.payload;
|
|
1827
|
+
},
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
async waitForTerminalOutput(terminalId, timeout = 5000) {
|
|
1831
|
+
return this.waitFor((msg) => {
|
|
1832
|
+
if (msg.type !== "terminal_output") {
|
|
1833
|
+
return null;
|
|
1834
|
+
}
|
|
1835
|
+
if (msg.payload.terminalId !== terminalId) {
|
|
1836
|
+
return null;
|
|
1837
|
+
}
|
|
1838
|
+
return msg.payload;
|
|
1839
|
+
}, timeout, { skipQueue: true });
|
|
1840
|
+
}
|
|
1841
|
+
// ============================================================================
|
|
1842
|
+
// Internals
|
|
1843
|
+
// ============================================================================
|
|
1844
|
+
createRequestId(requestId) {
|
|
1845
|
+
return requestId ?? crypto.randomUUID();
|
|
1846
|
+
}
|
|
1847
|
+
disposeTransport(code = 1001, reason = "Reconnecting") {
|
|
1848
|
+
this.cleanupTransport();
|
|
1849
|
+
if (this.transport) {
|
|
1850
|
+
try {
|
|
1851
|
+
this.transport.close(code, reason);
|
|
1852
|
+
}
|
|
1853
|
+
catch {
|
|
1854
|
+
// no-op
|
|
1855
|
+
}
|
|
1856
|
+
this.transport = null;
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
cleanupTransport() {
|
|
1860
|
+
if (this.pendingGenericTransportErrorTimeout) {
|
|
1861
|
+
clearTimeout(this.pendingGenericTransportErrorTimeout);
|
|
1862
|
+
this.pendingGenericTransportErrorTimeout = null;
|
|
1863
|
+
}
|
|
1864
|
+
for (const cleanup of this.transportCleanup) {
|
|
1865
|
+
try {
|
|
1866
|
+
cleanup();
|
|
1867
|
+
}
|
|
1868
|
+
catch {
|
|
1869
|
+
// no-op
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
this.transportCleanup = [];
|
|
1873
|
+
}
|
|
1874
|
+
handleTransportMessage(data) {
|
|
1875
|
+
const rawData = data && typeof data === "object" && "data" in data
|
|
1876
|
+
? data.data
|
|
1877
|
+
: data;
|
|
1878
|
+
const payload = decodeMessageData(rawData);
|
|
1879
|
+
if (!payload) {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
let parsedJson;
|
|
1883
|
+
try {
|
|
1884
|
+
parsedJson = JSON.parse(payload);
|
|
1885
|
+
}
|
|
1886
|
+
catch {
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
const parsed = WSOutboundMessageSchema.safeParse(parsedJson);
|
|
1890
|
+
if (!parsed.success) {
|
|
1891
|
+
const msgType = parsedJson?.message?.type ?? "unknown";
|
|
1892
|
+
this.logger.warn({ msgType, error: parsed.error.message }, "Message validation failed");
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
if (parsed.data.type === "pong") {
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
this.handleSessionMessage(parsed.data.message);
|
|
1899
|
+
}
|
|
1900
|
+
updateConnectionState(next) {
|
|
1901
|
+
this.connectionState = next;
|
|
1902
|
+
for (const listener of this.connectionListeners) {
|
|
1903
|
+
try {
|
|
1904
|
+
listener(next);
|
|
1905
|
+
}
|
|
1906
|
+
catch {
|
|
1907
|
+
// no-op
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
scheduleReconnect(reason) {
|
|
1912
|
+
if (this.reconnectTimeout) {
|
|
1913
|
+
clearTimeout(this.reconnectTimeout);
|
|
1914
|
+
this.reconnectTimeout = null;
|
|
1915
|
+
}
|
|
1916
|
+
if (!this.shouldReconnect || this.config.reconnect?.enabled === false) {
|
|
1917
|
+
this.rejectConnect(new Error(reason ?? "Transport disconnected before connect"));
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
const attempt = this.reconnectAttempt;
|
|
1921
|
+
const baseDelay = this.config.reconnect?.baseDelayMs ?? DEFAULT_RECONNECT_BASE_DELAY_MS;
|
|
1922
|
+
const maxDelay = this.config.reconnect?.maxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS;
|
|
1923
|
+
const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
|
|
1924
|
+
this.reconnectAttempt = attempt + 1;
|
|
1925
|
+
if (typeof reason === "string" && reason.trim().length > 0) {
|
|
1926
|
+
this.lastErrorValue = reason.trim();
|
|
1927
|
+
}
|
|
1928
|
+
// Clear all pending waiters and queued sends since the connection was lost
|
|
1929
|
+
// and responses from the previous connection will never arrive.
|
|
1930
|
+
this.clearWaiters(new Error(reason ?? "Connection lost"));
|
|
1931
|
+
this.rejectPendingSendQueue(new Error(reason ?? "Connection lost"));
|
|
1932
|
+
this.updateConnectionState({
|
|
1933
|
+
status: "disconnected",
|
|
1934
|
+
...(reason ? { reason } : {}),
|
|
1935
|
+
});
|
|
1936
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
1937
|
+
this.reconnectTimeout = null;
|
|
1938
|
+
if (!this.shouldReconnect) {
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
this.attemptConnect();
|
|
1942
|
+
}, delay);
|
|
1943
|
+
}
|
|
1944
|
+
handleSessionMessage(msg) {
|
|
1945
|
+
if (this.rawMessageListeners.size > 0) {
|
|
1946
|
+
for (const handler of this.rawMessageListeners) {
|
|
1947
|
+
try {
|
|
1948
|
+
handler(msg);
|
|
1949
|
+
}
|
|
1950
|
+
catch {
|
|
1951
|
+
// no-op
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
const handlers = this.messageHandlers.get(msg.type);
|
|
1956
|
+
if (handlers) {
|
|
1957
|
+
for (const handler of handlers) {
|
|
1958
|
+
try {
|
|
1959
|
+
handler(msg);
|
|
1960
|
+
}
|
|
1961
|
+
catch {
|
|
1962
|
+
// no-op
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
const event = this.toEvent(msg);
|
|
1967
|
+
if (event) {
|
|
1968
|
+
for (const handler of this.eventListeners) {
|
|
1969
|
+
handler(event);
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
this.resolveWaiters(msg);
|
|
1973
|
+
}
|
|
1974
|
+
resolveWaiters(msg) {
|
|
1975
|
+
for (const waiter of Array.from(this.waiters)) {
|
|
1976
|
+
const result = waiter.predicate(msg);
|
|
1977
|
+
if (result !== null) {
|
|
1978
|
+
this.waiters.delete(waiter);
|
|
1979
|
+
if (waiter.timeoutHandle) {
|
|
1980
|
+
clearTimeout(waiter.timeoutHandle);
|
|
1981
|
+
}
|
|
1982
|
+
waiter.resolve(result);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
clearWaiters(error) {
|
|
1987
|
+
for (const waiter of Array.from(this.waiters)) {
|
|
1988
|
+
if (waiter.timeoutHandle) {
|
|
1989
|
+
clearTimeout(waiter.timeoutHandle);
|
|
1990
|
+
}
|
|
1991
|
+
waiter.reject(error);
|
|
1992
|
+
}
|
|
1993
|
+
this.waiters.clear();
|
|
1994
|
+
}
|
|
1995
|
+
toEvent(msg) {
|
|
1996
|
+
switch (msg.type) {
|
|
1997
|
+
case "agent_update":
|
|
1998
|
+
return {
|
|
1999
|
+
type: "agent_update",
|
|
2000
|
+
agentId: msg.payload.kind === "upsert"
|
|
2001
|
+
? msg.payload.agent.id
|
|
2002
|
+
: msg.payload.agentId,
|
|
2003
|
+
payload: msg.payload,
|
|
2004
|
+
};
|
|
2005
|
+
case "agent_stream":
|
|
2006
|
+
return {
|
|
2007
|
+
type: "agent_stream",
|
|
2008
|
+
agentId: msg.payload.agentId,
|
|
2009
|
+
event: msg.payload.event,
|
|
2010
|
+
timestamp: msg.payload.timestamp,
|
|
2011
|
+
};
|
|
2012
|
+
case "status":
|
|
2013
|
+
return { type: "status", payload: msg.payload };
|
|
2014
|
+
case "agent_deleted":
|
|
2015
|
+
return { type: "agent_deleted", agentId: msg.payload.agentId };
|
|
2016
|
+
case "agent_permission_request":
|
|
2017
|
+
return {
|
|
2018
|
+
type: "agent_permission_request",
|
|
2019
|
+
agentId: msg.payload.agentId,
|
|
2020
|
+
request: msg.payload.request,
|
|
2021
|
+
};
|
|
2022
|
+
case "agent_permission_resolved":
|
|
2023
|
+
return {
|
|
2024
|
+
type: "agent_permission_resolved",
|
|
2025
|
+
agentId: msg.payload.agentId,
|
|
2026
|
+
requestId: msg.payload.requestId,
|
|
2027
|
+
resolution: msg.payload.resolution,
|
|
2028
|
+
};
|
|
2029
|
+
default:
|
|
2030
|
+
return null;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
async waitFor(predicate, timeout = 30000, _options) {
|
|
2034
|
+
return this.waitForWithCancel(predicate, timeout, _options).promise;
|
|
2035
|
+
}
|
|
2036
|
+
waitForWithCancel(predicate, timeout = 30000, _options) {
|
|
2037
|
+
// Capture stack trace at call site, not inside setTimeout
|
|
2038
|
+
const timeoutError = new Error(`Timeout waiting for message (${timeout}ms)`);
|
|
2039
|
+
let waiter = null;
|
|
2040
|
+
let settled = false;
|
|
2041
|
+
let rejectFn = null;
|
|
2042
|
+
const promise = new Promise((resolve, reject) => {
|
|
2043
|
+
const wrappedResolve = (value) => {
|
|
2044
|
+
if (settled)
|
|
2045
|
+
return;
|
|
2046
|
+
settled = true;
|
|
2047
|
+
resolve(value);
|
|
2048
|
+
};
|
|
2049
|
+
const wrappedReject = (error) => {
|
|
2050
|
+
if (settled)
|
|
2051
|
+
return;
|
|
2052
|
+
settled = true;
|
|
2053
|
+
reject(error);
|
|
2054
|
+
};
|
|
2055
|
+
rejectFn = wrappedReject;
|
|
2056
|
+
const timeoutHandle = timeout > 0
|
|
2057
|
+
? setTimeout(() => {
|
|
2058
|
+
if (waiter) {
|
|
2059
|
+
this.waiters.delete(waiter);
|
|
2060
|
+
}
|
|
2061
|
+
wrappedReject(timeoutError);
|
|
2062
|
+
}, timeout)
|
|
2063
|
+
: null;
|
|
2064
|
+
waiter = {
|
|
2065
|
+
predicate,
|
|
2066
|
+
resolve: wrappedResolve,
|
|
2067
|
+
reject: wrappedReject,
|
|
2068
|
+
timeoutHandle,
|
|
2069
|
+
};
|
|
2070
|
+
this.waiters.add(waiter);
|
|
2071
|
+
});
|
|
2072
|
+
const cancel = (error) => {
|
|
2073
|
+
if (settled) {
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
if (waiter) {
|
|
2077
|
+
this.waiters.delete(waiter);
|
|
2078
|
+
if (waiter.timeoutHandle) {
|
|
2079
|
+
clearTimeout(waiter.timeoutHandle);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
if (rejectFn) {
|
|
2083
|
+
rejectFn(error);
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
// Extremely unlikely: cancel called before the Promise executor ran.
|
|
2087
|
+
queueMicrotask(() => {
|
|
2088
|
+
if (!settled && rejectFn) {
|
|
2089
|
+
rejectFn(error);
|
|
2090
|
+
}
|
|
2091
|
+
});
|
|
2092
|
+
};
|
|
2093
|
+
return { promise, cancel };
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
// ============================================================================
|
|
2097
|
+
// Helpers
|
|
2098
|
+
// ============================================================================
|
|
2099
|
+
function defaultWebSocketFactory(url, _options) {
|
|
2100
|
+
const globalWs = globalThis.WebSocket;
|
|
2101
|
+
if (!globalWs) {
|
|
2102
|
+
throw new Error("WebSocket is not available in this runtime");
|
|
2103
|
+
}
|
|
2104
|
+
return new globalWs(url);
|
|
2105
|
+
}
|
|
2106
|
+
function createWebSocketTransportFactory(factory) {
|
|
2107
|
+
return ({ url, headers }) => {
|
|
2108
|
+
const ws = factory(url, { headers });
|
|
2109
|
+
return {
|
|
2110
|
+
send: (data) => {
|
|
2111
|
+
if (typeof ws.readyState === "number" && ws.readyState !== 1) {
|
|
2112
|
+
throw new Error(`WebSocket not open (readyState=${ws.readyState})`);
|
|
2113
|
+
}
|
|
2114
|
+
ws.send(data);
|
|
2115
|
+
},
|
|
2116
|
+
close: (code, reason) => ws.close(code, reason),
|
|
2117
|
+
onOpen: (handler) => bindWsHandler(ws, "open", handler),
|
|
2118
|
+
onClose: (handler) => bindWsHandler(ws, "close", handler),
|
|
2119
|
+
onError: (handler) => bindWsHandler(ws, "error", handler),
|
|
2120
|
+
onMessage: (handler) => bindWsHandler(ws, "message", handler),
|
|
2121
|
+
};
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
function createRelayE2eeTransportFactory(args) {
|
|
2125
|
+
return ({ url, headers }) => {
|
|
2126
|
+
const base = args.baseFactory({ url, headers });
|
|
2127
|
+
return createEncryptedTransport(base, args.daemonPublicKeyB64, args.logger);
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
2131
|
+
let channel = null;
|
|
2132
|
+
let opened = false;
|
|
2133
|
+
let closed = false;
|
|
2134
|
+
const openHandlers = new Set();
|
|
2135
|
+
const closeHandlers = new Set();
|
|
2136
|
+
const errorHandlers = new Set();
|
|
2137
|
+
const messageHandlers = new Set();
|
|
2138
|
+
const emitOpen = () => {
|
|
2139
|
+
if (opened || closed)
|
|
2140
|
+
return;
|
|
2141
|
+
opened = true;
|
|
2142
|
+
for (const handler of openHandlers) {
|
|
2143
|
+
try {
|
|
2144
|
+
handler();
|
|
2145
|
+
}
|
|
2146
|
+
catch {
|
|
2147
|
+
// no-op
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
const emitClose = (event) => {
|
|
2152
|
+
if (closed)
|
|
2153
|
+
return;
|
|
2154
|
+
closed = true;
|
|
2155
|
+
for (const handler of closeHandlers) {
|
|
2156
|
+
try {
|
|
2157
|
+
handler(event);
|
|
2158
|
+
}
|
|
2159
|
+
catch {
|
|
2160
|
+
// no-op
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
const emitError = (event) => {
|
|
2165
|
+
if (closed)
|
|
2166
|
+
return;
|
|
2167
|
+
for (const handler of errorHandlers) {
|
|
2168
|
+
try {
|
|
2169
|
+
handler(event);
|
|
2170
|
+
}
|
|
2171
|
+
catch {
|
|
2172
|
+
// no-op
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
};
|
|
2176
|
+
const emitMessage = (data) => {
|
|
2177
|
+
if (closed)
|
|
2178
|
+
return;
|
|
2179
|
+
for (const handler of messageHandlers) {
|
|
2180
|
+
try {
|
|
2181
|
+
handler(data);
|
|
2182
|
+
}
|
|
2183
|
+
catch {
|
|
2184
|
+
// no-op
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
};
|
|
2188
|
+
const relayTransport = {
|
|
2189
|
+
send: (data) => {
|
|
2190
|
+
if (typeof data === "string") {
|
|
2191
|
+
base.send(data);
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
if (data instanceof ArrayBuffer) {
|
|
2195
|
+
if (typeof TextDecoder !== "undefined") {
|
|
2196
|
+
base.send(new TextDecoder().decode(data));
|
|
2197
|
+
return;
|
|
2198
|
+
}
|
|
2199
|
+
if (typeof Buffer !== "undefined") {
|
|
2200
|
+
base.send(Buffer.from(data).toString("utf8"));
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
base.send(String(data));
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
base.send(String(data));
|
|
2207
|
+
},
|
|
2208
|
+
close: (code, reason) => base.close(code, reason),
|
|
2209
|
+
onmessage: null,
|
|
2210
|
+
onclose: null,
|
|
2211
|
+
onerror: null,
|
|
2212
|
+
};
|
|
2213
|
+
const startHandshake = async () => {
|
|
2214
|
+
try {
|
|
2215
|
+
channel = await createClientChannel(relayTransport, daemonPublicKeyB64, {
|
|
2216
|
+
onopen: emitOpen,
|
|
2217
|
+
onmessage: (data) => emitMessage(data),
|
|
2218
|
+
onclose: (code, reason) => emitClose({ code, reason }),
|
|
2219
|
+
onerror: (error) => emitError(error),
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
catch (error) {
|
|
2223
|
+
logger.warn({ err: error }, "relay_e2ee_handshake_failed");
|
|
2224
|
+
emitError(error);
|
|
2225
|
+
base.close(1011, "E2EE handshake failed");
|
|
2226
|
+
}
|
|
2227
|
+
};
|
|
2228
|
+
base.onOpen(() => {
|
|
2229
|
+
void startHandshake();
|
|
2230
|
+
});
|
|
2231
|
+
base.onMessage((event) => {
|
|
2232
|
+
relayTransport.onmessage?.(extractRelayMessageData(event));
|
|
2233
|
+
});
|
|
2234
|
+
base.onClose((event) => {
|
|
2235
|
+
const record = event;
|
|
2236
|
+
relayTransport.onclose?.(record?.code ?? 0, record?.reason ?? "");
|
|
2237
|
+
emitClose(event);
|
|
2238
|
+
});
|
|
2239
|
+
base.onError((event) => {
|
|
2240
|
+
relayTransport.onerror?.(event instanceof Error ? event : new Error(String(event)));
|
|
2241
|
+
emitError(event);
|
|
2242
|
+
});
|
|
2243
|
+
return {
|
|
2244
|
+
send: (data) => {
|
|
2245
|
+
if (!channel) {
|
|
2246
|
+
throw new Error("Encrypted channel not ready");
|
|
2247
|
+
}
|
|
2248
|
+
void channel.send(data).catch((error) => {
|
|
2249
|
+
emitError(error);
|
|
2250
|
+
});
|
|
2251
|
+
},
|
|
2252
|
+
close: (code, reason) => {
|
|
2253
|
+
if (channel) {
|
|
2254
|
+
channel.close(code, reason);
|
|
2255
|
+
}
|
|
2256
|
+
else {
|
|
2257
|
+
base.close(code, reason);
|
|
2258
|
+
}
|
|
2259
|
+
emitClose({ code, reason });
|
|
2260
|
+
},
|
|
2261
|
+
onMessage: (handler) => {
|
|
2262
|
+
messageHandlers.add(handler);
|
|
2263
|
+
return () => messageHandlers.delete(handler);
|
|
2264
|
+
},
|
|
2265
|
+
onOpen: (handler) => {
|
|
2266
|
+
openHandlers.add(handler);
|
|
2267
|
+
if (opened) {
|
|
2268
|
+
try {
|
|
2269
|
+
handler();
|
|
2270
|
+
}
|
|
2271
|
+
catch {
|
|
2272
|
+
// no-op
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
return () => openHandlers.delete(handler);
|
|
2276
|
+
},
|
|
2277
|
+
onClose: (handler) => {
|
|
2278
|
+
closeHandlers.add(handler);
|
|
2279
|
+
if (closed) {
|
|
2280
|
+
try {
|
|
2281
|
+
handler();
|
|
2282
|
+
}
|
|
2283
|
+
catch {
|
|
2284
|
+
// no-op
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
return () => closeHandlers.delete(handler);
|
|
2288
|
+
},
|
|
2289
|
+
onError: (handler) => {
|
|
2290
|
+
errorHandlers.add(handler);
|
|
2291
|
+
return () => errorHandlers.delete(handler);
|
|
2292
|
+
},
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
function extractRelayMessageData(event) {
|
|
2296
|
+
const raw = event && typeof event === "object" && "data" in event
|
|
2297
|
+
? event.data
|
|
2298
|
+
: event;
|
|
2299
|
+
if (typeof raw === "string")
|
|
2300
|
+
return raw;
|
|
2301
|
+
if (raw instanceof ArrayBuffer)
|
|
2302
|
+
return raw;
|
|
2303
|
+
if (ArrayBuffer.isView(raw)) {
|
|
2304
|
+
const view = new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
|
|
2305
|
+
const out = new Uint8Array(view.byteLength);
|
|
2306
|
+
out.set(view);
|
|
2307
|
+
return out.buffer;
|
|
2308
|
+
}
|
|
2309
|
+
return String(raw ?? "");
|
|
2310
|
+
}
|
|
2311
|
+
function bindWsHandler(ws, event, handler) {
|
|
2312
|
+
if (typeof ws.addEventListener === "function") {
|
|
2313
|
+
ws.addEventListener(event, handler);
|
|
2314
|
+
return () => {
|
|
2315
|
+
if (typeof ws.removeEventListener === "function") {
|
|
2316
|
+
ws.removeEventListener(event, handler);
|
|
2317
|
+
}
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
if (typeof ws.on === "function") {
|
|
2321
|
+
ws.on(event, handler);
|
|
2322
|
+
return () => {
|
|
2323
|
+
if (typeof ws.off === "function") {
|
|
2324
|
+
ws.off(event, handler);
|
|
2325
|
+
return;
|
|
2326
|
+
}
|
|
2327
|
+
if (typeof ws.removeListener === "function") {
|
|
2328
|
+
ws.removeListener(event, handler);
|
|
2329
|
+
}
|
|
2330
|
+
};
|
|
2331
|
+
}
|
|
2332
|
+
const prop = `on${event}`;
|
|
2333
|
+
const previous = ws[prop];
|
|
2334
|
+
ws[prop] = handler;
|
|
2335
|
+
return () => {
|
|
2336
|
+
if (ws[prop] === handler) {
|
|
2337
|
+
ws[prop] = previous ?? null;
|
|
2338
|
+
}
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
function describeTransportClose(event) {
|
|
2342
|
+
if (!event) {
|
|
2343
|
+
return "Transport closed";
|
|
2344
|
+
}
|
|
2345
|
+
if (event instanceof Error) {
|
|
2346
|
+
return event.message;
|
|
2347
|
+
}
|
|
2348
|
+
if (typeof event === "string") {
|
|
2349
|
+
return event;
|
|
2350
|
+
}
|
|
2351
|
+
if (typeof event === "object") {
|
|
2352
|
+
const record = event;
|
|
2353
|
+
if (typeof record.reason === "string" && record.reason.trim().length > 0) {
|
|
2354
|
+
return record.reason.trim();
|
|
2355
|
+
}
|
|
2356
|
+
if (typeof record.message === "string" && record.message.trim().length > 0) {
|
|
2357
|
+
return record.message.trim();
|
|
2358
|
+
}
|
|
2359
|
+
if (typeof record.code === "number") {
|
|
2360
|
+
return `Transport closed (code ${record.code})`;
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
return "Transport closed";
|
|
2364
|
+
}
|
|
2365
|
+
function describeTransportError(event) {
|
|
2366
|
+
if (!event) {
|
|
2367
|
+
return "Transport error";
|
|
2368
|
+
}
|
|
2369
|
+
if (event instanceof Error) {
|
|
2370
|
+
return event.message;
|
|
2371
|
+
}
|
|
2372
|
+
if (typeof event === "string") {
|
|
2373
|
+
return event;
|
|
2374
|
+
}
|
|
2375
|
+
if (typeof event === "object") {
|
|
2376
|
+
const record = event;
|
|
2377
|
+
if (typeof record.message === "string" && record.message.trim().length > 0) {
|
|
2378
|
+
return record.message.trim();
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
return "Transport error";
|
|
2382
|
+
}
|
|
2383
|
+
function safeRandomId() {
|
|
2384
|
+
try {
|
|
2385
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
2386
|
+
return crypto.randomUUID();
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
catch {
|
|
2390
|
+
// ignore
|
|
2391
|
+
}
|
|
2392
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
2393
|
+
}
|
|
2394
|
+
function decodeMessageData(data) {
|
|
2395
|
+
if (data === null || data === undefined) {
|
|
2396
|
+
return null;
|
|
2397
|
+
}
|
|
2398
|
+
if (typeof data === "string") {
|
|
2399
|
+
return data;
|
|
2400
|
+
}
|
|
2401
|
+
if (typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) {
|
|
2402
|
+
if (typeof Buffer !== "undefined") {
|
|
2403
|
+
return Buffer.from(data).toString("utf8");
|
|
2404
|
+
}
|
|
2405
|
+
if (typeof TextDecoder !== "undefined") {
|
|
2406
|
+
return new TextDecoder().decode(data);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
if (ArrayBuffer.isView(data)) {
|
|
2410
|
+
const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
2411
|
+
if (typeof Buffer !== "undefined") {
|
|
2412
|
+
return Buffer.from(view).toString("utf8");
|
|
2413
|
+
}
|
|
2414
|
+
if (typeof TextDecoder !== "undefined") {
|
|
2415
|
+
return new TextDecoder().decode(view);
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
if (typeof data.toString === "function") {
|
|
2419
|
+
return data.toString();
|
|
2420
|
+
}
|
|
2421
|
+
return null;
|
|
2422
|
+
}
|
|
2423
|
+
function resolveAgentConfig(options) {
|
|
2424
|
+
const { config, provider, cwd, initialPrompt: _initialPrompt, images: _images, git: _git, worktreeName: _worktreeName, requestId: _requestId, labels: _labels, ...overrides } = options;
|
|
2425
|
+
const baseConfig = {
|
|
2426
|
+
...(provider ? { provider } : {}),
|
|
2427
|
+
...(cwd ? { cwd } : {}),
|
|
2428
|
+
...overrides,
|
|
2429
|
+
};
|
|
2430
|
+
const merged = config ? { ...baseConfig, ...config } : baseConfig;
|
|
2431
|
+
if (!merged.provider || !merged.cwd) {
|
|
2432
|
+
throw new Error("createAgent requires provider and cwd");
|
|
2433
|
+
}
|
|
2434
|
+
if (!merged.modeId) {
|
|
2435
|
+
merged.modeId = getAgentProviderDefinition(merged.provider).defaultModeId ?? undefined;
|
|
2436
|
+
}
|
|
2437
|
+
return {
|
|
2438
|
+
...merged,
|
|
2439
|
+
provider: merged.provider,
|
|
2440
|
+
cwd: merged.cwd,
|
|
2441
|
+
};
|
|
2442
|
+
}
|
|
2443
|
+
//# sourceMappingURL=daemon-client.js.map
|