@getpaseo/server 0.1.35 → 0.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/dev-runner.js +1 -1
- package/dist/scripts/dev-runner.js.map +1 -1
- package/dist/scripts/{daemon-runner.js → supervisor-entrypoint.js} +38 -10
- package/dist/scripts/supervisor-entrypoint.js.map +1 -0
- package/dist/scripts/supervisor.js +33 -7
- package/dist/scripts/supervisor.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +175 -0
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +235 -0
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +13 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +53 -0
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-storage.d.ts +10 -10
- package/dist/server/server/agent/agent-storage.js +9 -4
- package/dist/server/server/agent/agent-storage.js.map +1 -1
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -1
- package/dist/server/server/agent/provider-launch-config.js +38 -1
- package/dist/server/server/agent/provider-launch-config.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +24 -5
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent-attention-policy.d.ts +1 -1
- package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
- package/dist/server/server/bootstrap.d.ts +0 -4
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +65 -40
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/chat/chat-mentions.d.ts +31 -0
- package/dist/server/server/chat/chat-mentions.d.ts.map +1 -0
- package/dist/server/server/chat/chat-mentions.js +71 -0
- package/dist/server/server/chat/chat-mentions.js.map +1 -0
- package/dist/server/server/chat/chat-rpc-schemas.d.ts +728 -0
- package/dist/server/server/chat/chat-rpc-schemas.d.ts.map +1 -0
- package/dist/server/server/chat/chat-rpc-schemas.js +103 -0
- package/dist/server/server/chat/chat-rpc-schemas.js.map +1 -0
- package/dist/server/server/chat/chat-service.d.ts +74 -0
- package/dist/server/server/chat/chat-service.d.ts.map +1 -0
- package/dist/server/server/chat/chat-service.js +330 -0
- package/dist/server/server/chat/chat-service.js.map +1 -0
- package/dist/server/server/chat/chat-types.d.ts +75 -0
- package/dist/server/server/chat/chat-types.d.ts.map +1 -0
- package/dist/server/server/chat/chat-types.js +22 -0
- package/dist/server/server/chat/chat-types.js.map +1 -0
- package/dist/server/server/checkout-diff-manager.d.ts +41 -0
- package/dist/server/server/checkout-diff-manager.d.ts.map +1 -0
- package/dist/server/server/checkout-diff-manager.js +272 -0
- package/dist/server/server/checkout-diff-manager.js.map +1 -0
- package/dist/server/server/checkout-git-utils.d.ts +9 -0
- package/dist/server/server/checkout-git-utils.d.ts.map +1 -0
- package/dist/server/server/checkout-git-utils.js +37 -0
- package/dist/server/server/checkout-git-utils.js.map +1 -0
- package/dist/server/server/index.js +0 -4
- package/dist/server/server/index.js.map +1 -1
- package/dist/server/server/loop/rpc-schemas.d.ts +2937 -0
- package/dist/server/server/loop/rpc-schemas.d.ts.map +1 -0
- package/dist/server/server/loop/rpc-schemas.js +159 -0
- package/dist/server/server/loop/rpc-schemas.js.map +1 -0
- package/dist/server/server/loop-service.d.ts +520 -0
- package/dist/server/server/loop-service.d.ts.map +1 -0
- package/dist/server/server/loop-service.js +741 -0
- package/dist/server/server/loop-service.js.map +1 -0
- package/dist/server/server/persisted-config.d.ts +10 -10
- package/dist/server/server/pid-lock.d.ts +7 -2
- package/dist/server/server/pid-lock.d.ts.map +1 -1
- package/dist/server/server/pid-lock.js +21 -0
- package/dist/server/server/pid-lock.js.map +1 -1
- package/dist/server/server/schedule/cron.d.ts +4 -0
- package/dist/server/server/schedule/cron.d.ts.map +1 -0
- package/dist/server/server/schedule/cron.js +103 -0
- package/dist/server/server/schedule/cron.js.map +1 -0
- package/dist/server/server/schedule/rpc-schemas.d.ts +2773 -0
- package/dist/server/server/schedule/rpc-schemas.d.ts.map +1 -0
- package/dist/server/server/schedule/rpc-schemas.js +112 -0
- package/dist/server/server/schedule/rpc-schemas.js.map +1 -0
- package/dist/server/server/schedule/service.d.ts +39 -0
- package/dist/server/server/schedule/service.d.ts.map +1 -0
- package/dist/server/server/schedule/service.js +397 -0
- package/dist/server/server/schedule/service.js.map +1 -0
- package/dist/server/server/schedule/store.d.ts +13 -0
- package/dist/server/server/schedule/store.d.ts.map +1 -0
- package/dist/server/server/schedule/store.js +56 -0
- package/dist/server/server/schedule/store.js.map +1 -0
- package/dist/server/server/schedule/types.d.ts +710 -0
- package/dist/server/server/schedule/types.d.ts.map +1 -0
- package/dist/server/server/schedule/types.js +73 -0
- package/dist/server/server/schedule/types.js.map +1 -0
- package/dist/server/server/session.d.ts +40 -19
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +779 -568
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js +19 -3
- package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts +12 -1
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +71 -14
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/shared/messages.d.ts +37933 -16895
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +41 -0
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/terminal/terminal-manager.js +2 -2
- package/dist/server/terminal/terminal-manager.js.map +1 -1
- package/dist/server/utils/checkout-git.d.ts +12 -0
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +73 -3
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/dist/server/utils/directory-suggestions.js +20 -4
- package/dist/server/utils/directory-suggestions.js.map +1 -1
- package/dist/src/server/pid-lock.js +21 -0
- package/dist/src/server/pid-lock.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js +19 -3
- package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js.map +1 -1
- package/package.json +4 -3
- package/dist/scripts/daemon-runner.js.map +0 -1
- package/dist/src/server/agent/activity-curator.js +0 -243
- package/dist/src/server/agent/activity-curator.js.map +0 -1
- package/dist/src/server/agent/agent-manager.js +0 -1802
- package/dist/src/server/agent/agent-manager.js.map +0 -1
- package/dist/src/server/agent/agent-metadata-generator.js +0 -161
- package/dist/src/server/agent/agent-metadata-generator.js.map +0 -1
- package/dist/src/server/agent/agent-projections.js +0 -254
- package/dist/src/server/agent/agent-projections.js.map +0 -1
- package/dist/src/server/agent/agent-response-loop.js +0 -304
- package/dist/src/server/agent/agent-response-loop.js.map +0 -1
- package/dist/src/server/agent/agent-sdk-types.js +0 -12
- package/dist/src/server/agent/agent-sdk-types.js.map +0 -1
- package/dist/src/server/agent/agent-storage.js +0 -297
- package/dist/src/server/agent/agent-storage.js.map +0 -1
- package/dist/src/server/agent/agent-title-limits.js +0 -3
- package/dist/src/server/agent/agent-title-limits.js.map +0 -1
- package/dist/src/server/agent/audio-utils.js +0 -19
- package/dist/src/server/agent/audio-utils.js.map +0 -1
- package/dist/src/server/agent/dictation-debug.js +0 -50
- package/dist/src/server/agent/dictation-debug.js.map +0 -1
- package/dist/src/server/agent/mcp-server.js +0 -754
- package/dist/src/server/agent/mcp-server.js.map +0 -1
- package/dist/src/server/agent/orchestrator-instructions.js +0 -51
- package/dist/src/server/agent/orchestrator-instructions.js.map +0 -1
- package/dist/src/server/agent/pcm16-resampler.js +0 -63
- package/dist/src/server/agent/pcm16-resampler.js.map +0 -1
- package/dist/src/server/agent/provider-launch-config.js +0 -176
- package/dist/src/server/agent/provider-launch-config.js.map +0 -1
- package/dist/src/server/agent/provider-manifest.js +0 -127
- package/dist/src/server/agent/provider-manifest.js.map +0 -1
- package/dist/src/server/agent/provider-registry.js +0 -45
- package/dist/src/server/agent/provider-registry.js.map +0 -1
- package/dist/src/server/agent/providers/claude/partial-json.js +0 -306
- package/dist/src/server/agent/providers/claude/partial-json.js.map +0 -1
- package/dist/src/server/agent/providers/claude/sdk-model-resolver.js +0 -104
- package/dist/src/server/agent/providers/claude/sdk-model-resolver.js.map +0 -1
- package/dist/src/server/agent/providers/claude/sidechain-tracker.js +0 -230
- package/dist/src/server/agent/providers/claude/sidechain-tracker.js.map +0 -1
- package/dist/src/server/agent/providers/claude/task-notification-tool-call.js +0 -267
- package/dist/src/server/agent/providers/claude/task-notification-tool-call.js.map +0 -1
- package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js +0 -121
- package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js.map +0 -1
- package/dist/src/server/agent/providers/claude/tool-call-mapper.js +0 -252
- package/dist/src/server/agent/providers/claude/tool-call-mapper.js.map +0 -1
- package/dist/src/server/agent/providers/claude-agent.js +0 -3147
- package/dist/src/server/agent/providers/claude-agent.js.map +0 -1
- package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js +0 -104
- package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js.map +0 -1
- package/dist/src/server/agent/providers/codex/tool-call-mapper.js +0 -758
- package/dist/src/server/agent/providers/codex/tool-call-mapper.js.map +0 -1
- package/dist/src/server/agent/providers/codex-app-server-agent.js +0 -2949
- package/dist/src/server/agent/providers/codex-app-server-agent.js.map +0 -1
- package/dist/src/server/agent/providers/codex-rollout-timeline.js +0 -544
- package/dist/src/server/agent/providers/codex-rollout-timeline.js.map +0 -1
- package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js +0 -39
- package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js.map +0 -1
- package/dist/src/server/agent/providers/opencode/tool-call-mapper.js +0 -144
- package/dist/src/server/agent/providers/opencode/tool-call-mapper.js.map +0 -1
- package/dist/src/server/agent/providers/opencode-agent.js +0 -1193
- package/dist/src/server/agent/providers/opencode-agent.js.map +0 -1
- package/dist/src/server/agent/providers/tool-call-detail-primitives.js +0 -686
- package/dist/src/server/agent/providers/tool-call-detail-primitives.js.map +0 -1
- package/dist/src/server/agent/providers/tool-call-mapper-utils.js +0 -115
- package/dist/src/server/agent/providers/tool-call-mapper-utils.js.map +0 -1
- package/dist/src/server/agent/recordings-debug.js +0 -19
- package/dist/src/server/agent/recordings-debug.js.map +0 -1
- package/dist/src/server/agent/stt-debug.js +0 -33
- package/dist/src/server/agent/stt-debug.js.map +0 -1
- package/dist/src/server/agent/stt-manager.js +0 -232
- package/dist/src/server/agent/stt-manager.js.map +0 -1
- package/dist/src/server/agent/timeline-append.js +0 -27
- package/dist/src/server/agent/timeline-append.js.map +0 -1
- package/dist/src/server/agent/timeline-projection.js +0 -215
- package/dist/src/server/agent/timeline-projection.js.map +0 -1
- package/dist/src/server/agent/tool-name-normalization.js +0 -45
- package/dist/src/server/agent/tool-name-normalization.js.map +0 -1
- package/dist/src/server/agent/tts-debug.js +0 -24
- package/dist/src/server/agent/tts-debug.js.map +0 -1
- package/dist/src/server/agent/tts-manager.js +0 -374
- package/dist/src/server/agent/tts-manager.js.map +0 -1
- package/dist/src/server/agent/wait-for-agent-tracker.js +0 -53
- package/dist/src/server/agent/wait-for-agent-tracker.js.map +0 -1
- package/dist/src/server/agent-attention-policy.js +0 -40
- package/dist/src/server/agent-attention-policy.js.map +0 -1
- package/dist/src/server/allowed-hosts.js +0 -94
- package/dist/src/server/allowed-hosts.js.map +0 -1
- package/dist/src/server/bootstrap.js +0 -581
- package/dist/src/server/bootstrap.js.map +0 -1
- package/dist/src/server/client-message-id.js +0 -12
- package/dist/src/server/client-message-id.js.map +0 -1
- package/dist/src/server/config.js +0 -73
- package/dist/src/server/config.js.map +0 -1
- package/dist/src/server/connection-offer.js +0 -59
- package/dist/src/server/connection-offer.js.map +0 -1
- package/dist/src/server/daemon-keypair.js +0 -40
- package/dist/src/server/daemon-keypair.js.map +0 -1
- package/dist/src/server/daemon-version.js +0 -22
- package/dist/src/server/daemon-version.js.map +0 -1
- package/dist/src/server/dictation/dictation-stream-manager.js +0 -571
- package/dist/src/server/dictation/dictation-stream-manager.js.map +0 -1
- package/dist/src/server/file-download/token-store.js +0 -40
- package/dist/src/server/file-download/token-store.js.map +0 -1
- package/dist/src/server/file-explorer/service.js +0 -180
- package/dist/src/server/file-explorer/service.js.map +0 -1
- package/dist/src/server/json-utils.js +0 -45
- package/dist/src/server/json-utils.js.map +0 -1
- package/dist/src/server/messages.js +0 -29
- package/dist/src/server/messages.js.map +0 -1
- package/dist/src/server/package-version.js +0 -46
- package/dist/src/server/package-version.js.map +0 -1
- package/dist/src/server/pairing-offer.js +0 -45
- package/dist/src/server/pairing-offer.js.map +0 -1
- package/dist/src/server/pairing-qr.js +0 -45
- package/dist/src/server/pairing-qr.js.map +0 -1
- package/dist/src/server/path-utils.js +0 -20
- package/dist/src/server/path-utils.js.map +0 -1
- package/dist/src/server/persisted-config.js +0 -265
- package/dist/src/server/persisted-config.js.map +0 -1
- package/dist/src/server/persistence-hooks.js +0 -60
- package/dist/src/server/persistence-hooks.js.map +0 -1
- package/dist/src/server/push/push-service.js +0 -68
- package/dist/src/server/push/push-service.js.map +0 -1
- package/dist/src/server/push/token-store.js +0 -70
- package/dist/src/server/push/token-store.js.map +0 -1
- package/dist/src/server/relay-transport.js +0 -461
- package/dist/src/server/relay-transport.js.map +0 -1
- package/dist/src/server/server-id.js +0 -63
- package/dist/src/server/server-id.js.map +0 -1
- package/dist/src/server/session.js +0 -6170
- package/dist/src/server/session.js.map +0 -1
- package/dist/src/server/speech/audio.js +0 -101
- package/dist/src/server/speech/audio.js.map +0 -1
- package/dist/src/server/speech/provider-resolver.js +0 -7
- package/dist/src/server/speech/provider-resolver.js.map +0 -1
- package/dist/src/server/speech/providers/local/config.js +0 -74
- package/dist/src/server/speech/providers/local/config.js.map +0 -1
- package/dist/src/server/speech/providers/local/models.js +0 -17
- package/dist/src/server/speech/providers/local/models.js.map +0 -1
- package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js +0 -436
- package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +0 -1
- package/dist/src/server/speech/providers/local/runtime.js +0 -238
- package/dist/src/server/speech/providers/local/runtime.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/model-catalog.js +0 -166
- package/dist/src/server/speech/providers/local/sherpa/model-catalog.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/model-downloader.js +0 -165
- package/dist/src/server/speech/providers/local/sherpa/model-downloader.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +0 -73
- package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +0 -84
- package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-loader.js +0 -11
- package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-loader.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +0 -102
- package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +0 -135
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +0 -130
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js +0 -110
- package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js +0 -138
- package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js +0 -98
- package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/silero-vad-provider.js +0 -23
- package/dist/src/server/speech/providers/local/sherpa/silero-vad-provider.js.map +0 -1
- package/dist/src/server/speech/providers/local/sherpa/silero-vad-session.js +0 -107
- package/dist/src/server/speech/providers/local/sherpa/silero-vad-session.js.map +0 -1
- package/dist/src/server/speech/providers/openai/config.js +0 -80
- package/dist/src/server/speech/providers/openai/config.js.map +0 -1
- package/dist/src/server/speech/providers/openai/realtime-transcription-session.js +0 -168
- package/dist/src/server/speech/providers/openai/realtime-transcription-session.js.map +0 -1
- package/dist/src/server/speech/providers/openai/runtime.js +0 -112
- package/dist/src/server/speech/providers/openai/runtime.js.map +0 -1
- package/dist/src/server/speech/providers/openai/stt.js +0 -206
- package/dist/src/server/speech/providers/openai/stt.js.map +0 -1
- package/dist/src/server/speech/providers/openai/tts.js +0 -46
- package/dist/src/server/speech/providers/openai/tts.js.map +0 -1
- package/dist/src/server/speech/speech-config-resolver.js +0 -102
- package/dist/src/server/speech/speech-config-resolver.js.map +0 -1
- package/dist/src/server/speech/speech-provider.js +0 -2
- package/dist/src/server/speech/speech-provider.js.map +0 -1
- package/dist/src/server/speech/speech-runtime.js +0 -530
- package/dist/src/server/speech/speech-runtime.js.map +0 -1
- package/dist/src/server/speech/speech-types.js +0 -8
- package/dist/src/server/speech/speech-types.js.map +0 -1
- package/dist/src/server/speech/turn-detection-provider.js +0 -2
- package/dist/src/server/speech/turn-detection-provider.js.map +0 -1
- package/dist/src/server/utils/diff-highlighter.js +0 -257
- package/dist/src/server/utils/diff-highlighter.js.map +0 -1
- package/dist/src/server/voice/fixed-duration-pcm-ring-buffer.js +0 -35
- package/dist/src/server/voice/fixed-duration-pcm-ring-buffer.js.map +0 -1
- package/dist/src/server/voice/voice-turn-controller.js +0 -159
- package/dist/src/server/voice/voice-turn-controller.js.map +0 -1
- package/dist/src/server/voice-config.js +0 -51
- package/dist/src/server/voice-config.js.map +0 -1
- package/dist/src/server/voice-mcp-bridge-command.js +0 -31
- package/dist/src/server/voice-mcp-bridge-command.js.map +0 -1
- package/dist/src/server/voice-mcp-bridge.js +0 -109
- package/dist/src/server/voice-mcp-bridge.js.map +0 -1
- package/dist/src/server/voice-permission-policy.js +0 -13
- package/dist/src/server/voice-permission-policy.js.map +0 -1
- package/dist/src/server/voice-types.js +0 -2
- package/dist/src/server/voice-types.js.map +0 -1
- package/dist/src/server/websocket-server.js +0 -991
- package/dist/src/server/websocket-server.js.map +0 -1
- package/dist/src/server/workspace-registry-bootstrap.js +0 -98
- package/dist/src/server/workspace-registry-bootstrap.js.map +0 -1
- package/dist/src/server/workspace-registry-model.js +0 -175
- package/dist/src/server/workspace-registry-model.js.map +0 -1
- package/dist/src/server/workspace-registry.js +0 -151
- package/dist/src/server/workspace-registry.js.map +0 -1
- package/dist/src/server/worktree-bootstrap.js +0 -508
- package/dist/src/server/worktree-bootstrap.js.map +0 -1
- package/dist/src/shared/agent-attention-notification.js +0 -130
- package/dist/src/shared/agent-attention-notification.js.map +0 -1
- package/dist/src/shared/agent-lifecycle.js +0 -8
- package/dist/src/shared/agent-lifecycle.js.map +0 -1
- package/dist/src/shared/connection-offer.js +0 -17
- package/dist/src/shared/connection-offer.js.map +0 -1
- package/dist/src/shared/daemon-endpoints.js +0 -122
- package/dist/src/shared/daemon-endpoints.js.map +0 -1
- package/dist/src/shared/messages.js +0 -2066
- package/dist/src/shared/messages.js.map +0 -1
- package/dist/src/shared/path-utils.js +0 -16
- package/dist/src/shared/path-utils.js.map +0 -1
- package/dist/src/shared/terminal-stream-protocol.js +0 -99
- package/dist/src/shared/terminal-stream-protocol.js.map +0 -1
- package/dist/src/shared/tool-call-display.js +0 -122
- package/dist/src/shared/tool-call-display.js.map +0 -1
- package/dist/src/terminal/terminal-manager.js +0 -136
- package/dist/src/terminal/terminal-manager.js.map +0 -1
- package/dist/src/terminal/terminal.js +0 -333
- package/dist/src/terminal/terminal.js.map +0 -1
- package/dist/src/utils/checkout-git.js +0 -1448
- package/dist/src/utils/checkout-git.js.map +0 -1
- package/dist/src/utils/directory-suggestions.js +0 -655
- package/dist/src/utils/directory-suggestions.js.map +0 -1
- package/dist/src/utils/path.js +0 -15
- package/dist/src/utils/path.js.map +0 -1
- package/dist/src/utils/project-icon.js +0 -389
- package/dist/src/utils/project-icon.js.map +0 -1
- package/dist/src/utils/worktree-metadata.js +0 -116
- package/dist/src/utils/worktree-metadata.js.map +0 -1
- package/dist/src/utils/worktree.js +0 -744
- package/dist/src/utils/worktree.js.map +0 -1
|
@@ -1,1193 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { createOpencodeClient } from "@opencode-ai/sdk/v2/client";
|
|
4
|
-
import net from "node:net";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { applyProviderEnv, findExecutable, resolveProviderCommandPrefix, } from "../provider-launch-config.js";
|
|
7
|
-
import { mapOpencodeToolCall } from "./opencode/tool-call-mapper.js";
|
|
8
|
-
const OPENCODE_CAPABILITIES = {
|
|
9
|
-
supportsStreaming: true,
|
|
10
|
-
supportsSessionPersistence: true,
|
|
11
|
-
supportsDynamicModes: true,
|
|
12
|
-
supportsMcpServers: true,
|
|
13
|
-
supportsReasoningStream: true,
|
|
14
|
-
supportsToolInvocations: true,
|
|
15
|
-
};
|
|
16
|
-
const DEFAULT_MODES = [
|
|
17
|
-
{
|
|
18
|
-
id: "build",
|
|
19
|
-
label: "Build",
|
|
20
|
-
description: "Allows edits and tool execution for implementation work",
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
id: "plan",
|
|
24
|
-
label: "Plan",
|
|
25
|
-
description: "Read-only planning mode that avoids file edits",
|
|
26
|
-
},
|
|
27
|
-
];
|
|
28
|
-
const OPENCODE_MODE_IDS = new Set(DEFAULT_MODES.map((mode) => mode.id));
|
|
29
|
-
const MCP_ALREADY_PRESENT_ERROR_TOKENS = ["already", "exists", "connected"];
|
|
30
|
-
const OpencodeToolStateSchema = z
|
|
31
|
-
.object({
|
|
32
|
-
status: z.string().optional(),
|
|
33
|
-
input: z.unknown().optional(),
|
|
34
|
-
output: z.unknown().optional(),
|
|
35
|
-
error: z.unknown().optional(),
|
|
36
|
-
})
|
|
37
|
-
.passthrough();
|
|
38
|
-
const OpencodeToolPartBaseSchema = z
|
|
39
|
-
.object({
|
|
40
|
-
tool: z.string().trim().min(1),
|
|
41
|
-
state: OpencodeToolStateSchema.optional(),
|
|
42
|
-
})
|
|
43
|
-
.passthrough();
|
|
44
|
-
const OpencodeToolPartWithCallIdSchema = OpencodeToolPartBaseSchema.extend({
|
|
45
|
-
callID: z.string().trim().min(1),
|
|
46
|
-
id: z.string().optional(),
|
|
47
|
-
}).transform((part) => ({
|
|
48
|
-
toolName: part.tool,
|
|
49
|
-
callId: part.callID,
|
|
50
|
-
status: part.state?.status,
|
|
51
|
-
input: part.state?.input,
|
|
52
|
-
output: part.state?.output,
|
|
53
|
-
error: part.state?.error,
|
|
54
|
-
}));
|
|
55
|
-
const OpencodeToolPartWithIdSchema = OpencodeToolPartBaseSchema.extend({
|
|
56
|
-
id: z.string().trim().min(1),
|
|
57
|
-
callID: z.string().optional(),
|
|
58
|
-
}).transform((part) => ({
|
|
59
|
-
toolName: part.tool,
|
|
60
|
-
callId: part.id,
|
|
61
|
-
status: part.state?.status,
|
|
62
|
-
input: part.state?.input,
|
|
63
|
-
output: part.state?.output,
|
|
64
|
-
error: part.state?.error,
|
|
65
|
-
}));
|
|
66
|
-
const OpencodeToolPartWithoutIdSchema = OpencodeToolPartBaseSchema.extend({
|
|
67
|
-
id: z.string().optional(),
|
|
68
|
-
callID: z.string().optional(),
|
|
69
|
-
}).transform((part) => ({
|
|
70
|
-
toolName: part.tool,
|
|
71
|
-
callId: undefined,
|
|
72
|
-
status: part.state?.status,
|
|
73
|
-
input: part.state?.input,
|
|
74
|
-
output: part.state?.output,
|
|
75
|
-
error: part.state?.error,
|
|
76
|
-
}));
|
|
77
|
-
const OpencodeToolPartSchema = z.union([
|
|
78
|
-
OpencodeToolPartWithCallIdSchema,
|
|
79
|
-
OpencodeToolPartWithIdSchema,
|
|
80
|
-
OpencodeToolPartWithoutIdSchema,
|
|
81
|
-
]);
|
|
82
|
-
const OpencodeToolPartTimelineEnvelopeSchema = OpencodeToolPartSchema.transform((part) => ({
|
|
83
|
-
toolName: part.toolName,
|
|
84
|
-
callId: part.callId,
|
|
85
|
-
status: part.status,
|
|
86
|
-
input: part.input,
|
|
87
|
-
output: part.output,
|
|
88
|
-
error: part.error,
|
|
89
|
-
}));
|
|
90
|
-
const OpencodeToolPartToTimelineItemSchema = OpencodeToolPartTimelineEnvelopeSchema.transform((part) => mapOpencodeToolCall({
|
|
91
|
-
toolName: part.toolName,
|
|
92
|
-
callId: part.callId,
|
|
93
|
-
status: part.status,
|
|
94
|
-
input: part.input,
|
|
95
|
-
output: part.output,
|
|
96
|
-
error: part.error,
|
|
97
|
-
}));
|
|
98
|
-
function resolveOpenCodeBinary() {
|
|
99
|
-
const found = findExecutable("opencode");
|
|
100
|
-
if (found) {
|
|
101
|
-
return found;
|
|
102
|
-
}
|
|
103
|
-
throw new Error("OpenCode binary not found. Install OpenCode (https://github.com/opencode-ai/opencode) and ensure it is available in your shell PATH.");
|
|
104
|
-
}
|
|
105
|
-
function toOpenCodeMcpConfig(config) {
|
|
106
|
-
if (config.type === "stdio") {
|
|
107
|
-
return {
|
|
108
|
-
type: "local",
|
|
109
|
-
command: [config.command, ...(config.args ?? [])],
|
|
110
|
-
...(config.env ? { environment: config.env } : {}),
|
|
111
|
-
enabled: true,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
type: "remote",
|
|
116
|
-
url: config.url,
|
|
117
|
-
...(config.headers ? { headers: config.headers } : {}),
|
|
118
|
-
enabled: true,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
function stringifyUnknownError(error) {
|
|
122
|
-
if (typeof error === "string") {
|
|
123
|
-
return error;
|
|
124
|
-
}
|
|
125
|
-
try {
|
|
126
|
-
return JSON.stringify(error);
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
return String(error);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function isAlreadyPresentMcpError(error) {
|
|
133
|
-
const normalized = stringifyUnknownError(error).toLowerCase();
|
|
134
|
-
return MCP_ALREADY_PRESENT_ERROR_TOKENS.some((token) => normalized.includes(token));
|
|
135
|
-
}
|
|
136
|
-
async function findAvailablePort() {
|
|
137
|
-
return new Promise((resolve, reject) => {
|
|
138
|
-
const server = net.createServer();
|
|
139
|
-
server.listen(0, () => {
|
|
140
|
-
const address = server.address();
|
|
141
|
-
if (address && typeof address === "object") {
|
|
142
|
-
const port = address.port;
|
|
143
|
-
server.close(() => resolve(port));
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
server.close(() => reject(new Error("Failed to get port")));
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
server.on("error", reject);
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
function resolvePartDedupeKey(part, partType) {
|
|
153
|
-
const partId = part.id;
|
|
154
|
-
if (typeof partId === "string" && partId.trim().length > 0) {
|
|
155
|
-
return `${partType}:${partId}`;
|
|
156
|
-
}
|
|
157
|
-
const messageId = part.messageID;
|
|
158
|
-
if (typeof messageId === "string" && messageId.trim().length > 0) {
|
|
159
|
-
return `${partType}:message:${messageId}`;
|
|
160
|
-
}
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
function normalizeOpenCodeModeId(modeId) {
|
|
164
|
-
const trimmed = typeof modeId === "string" ? modeId.trim() : "";
|
|
165
|
-
if (!trimmed || trimmed === "default") {
|
|
166
|
-
return "build";
|
|
167
|
-
}
|
|
168
|
-
return trimmed;
|
|
169
|
-
}
|
|
170
|
-
function sortOpenCodeModes(modes) {
|
|
171
|
-
const order = new Map(DEFAULT_MODES.map((mode, index) => [mode.id, index]));
|
|
172
|
-
return [...modes].sort((left, right) => {
|
|
173
|
-
const leftOrder = order.get(left.id) ?? Number.MAX_SAFE_INTEGER;
|
|
174
|
-
const rightOrder = order.get(right.id) ?? Number.MAX_SAFE_INTEGER;
|
|
175
|
-
if (leftOrder !== rightOrder) {
|
|
176
|
-
return leftOrder - rightOrder;
|
|
177
|
-
}
|
|
178
|
-
return left.label.localeCompare(right.label);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
export class OpenCodeServerManager {
|
|
182
|
-
constructor(logger, runtimeSettings) {
|
|
183
|
-
this.server = null;
|
|
184
|
-
this.port = null;
|
|
185
|
-
this.startPromise = null;
|
|
186
|
-
this.logger = logger;
|
|
187
|
-
this.runtimeSettings = runtimeSettings;
|
|
188
|
-
this.runtimeSettingsKey = JSON.stringify(runtimeSettings ?? {});
|
|
189
|
-
}
|
|
190
|
-
static getInstance(logger, runtimeSettings) {
|
|
191
|
-
const nextSettingsKey = JSON.stringify(runtimeSettings ?? {});
|
|
192
|
-
if (!OpenCodeServerManager.instance) {
|
|
193
|
-
OpenCodeServerManager.instance = new OpenCodeServerManager(logger, runtimeSettings);
|
|
194
|
-
OpenCodeServerManager.registerExitHandler();
|
|
195
|
-
}
|
|
196
|
-
else if (OpenCodeServerManager.instance.runtimeSettingsKey !== nextSettingsKey) {
|
|
197
|
-
logger.warn({
|
|
198
|
-
existingRuntimeSettings: OpenCodeServerManager.instance.runtimeSettingsKey,
|
|
199
|
-
requestedRuntimeSettings: nextSettingsKey,
|
|
200
|
-
}, "OpenCode server manager already initialized with different runtime settings");
|
|
201
|
-
}
|
|
202
|
-
return OpenCodeServerManager.instance;
|
|
203
|
-
}
|
|
204
|
-
static registerExitHandler() {
|
|
205
|
-
if (OpenCodeServerManager.exitHandlerRegistered) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
OpenCodeServerManager.exitHandlerRegistered = true;
|
|
209
|
-
const cleanup = () => {
|
|
210
|
-
const instance = OpenCodeServerManager.instance;
|
|
211
|
-
if (instance?.server && !instance.server.killed) {
|
|
212
|
-
instance.server.kill("SIGTERM");
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
process.on("exit", cleanup);
|
|
216
|
-
process.on("SIGTERM", cleanup);
|
|
217
|
-
process.on("SIGINT", cleanup);
|
|
218
|
-
}
|
|
219
|
-
async ensureRunning() {
|
|
220
|
-
if (this.startPromise) {
|
|
221
|
-
return this.startPromise;
|
|
222
|
-
}
|
|
223
|
-
if (this.server && this.port && !this.server.killed) {
|
|
224
|
-
return { port: this.port, url: `http://127.0.0.1:${this.port}` };
|
|
225
|
-
}
|
|
226
|
-
this.startPromise = this.startServer();
|
|
227
|
-
try {
|
|
228
|
-
const result = await this.startPromise;
|
|
229
|
-
return result;
|
|
230
|
-
}
|
|
231
|
-
finally {
|
|
232
|
-
this.startPromise = null;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
async startServer() {
|
|
236
|
-
this.port = await findAvailablePort();
|
|
237
|
-
const url = `http://127.0.0.1:${this.port}`;
|
|
238
|
-
const launchPrefix = resolveProviderCommandPrefix(this.runtimeSettings?.command, resolveOpenCodeBinary);
|
|
239
|
-
return new Promise((resolve, reject) => {
|
|
240
|
-
this.server = spawn(launchPrefix.command, [...launchPrefix.args, "serve", "--port", String(this.port)], {
|
|
241
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
242
|
-
env: applyProviderEnv(process.env, this.runtimeSettings),
|
|
243
|
-
});
|
|
244
|
-
let started = false;
|
|
245
|
-
const timeout = setTimeout(() => {
|
|
246
|
-
if (!started) {
|
|
247
|
-
reject(new Error("OpenCode server startup timeout"));
|
|
248
|
-
}
|
|
249
|
-
}, 30000);
|
|
250
|
-
this.server.stdout?.on("data", (data) => {
|
|
251
|
-
const output = data.toString();
|
|
252
|
-
if (output.includes("listening on") && !started) {
|
|
253
|
-
started = true;
|
|
254
|
-
clearTimeout(timeout);
|
|
255
|
-
resolve({ port: this.port, url });
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
this.server.stderr?.on("data", (data) => {
|
|
259
|
-
this.logger.error({ stderr: data.toString().trim() }, "OpenCode server stderr");
|
|
260
|
-
});
|
|
261
|
-
this.server.on("error", (error) => {
|
|
262
|
-
clearTimeout(timeout);
|
|
263
|
-
reject(error);
|
|
264
|
-
});
|
|
265
|
-
this.server.on("exit", (code) => {
|
|
266
|
-
if (!started) {
|
|
267
|
-
clearTimeout(timeout);
|
|
268
|
-
reject(new Error(`OpenCode server exited with code ${code}`));
|
|
269
|
-
}
|
|
270
|
-
this.server = null;
|
|
271
|
-
this.port = null;
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
async shutdown() {
|
|
276
|
-
if (this.server && !this.server.killed) {
|
|
277
|
-
this.server.kill("SIGTERM");
|
|
278
|
-
await new Promise((resolve) => {
|
|
279
|
-
const timeout = setTimeout(() => {
|
|
280
|
-
this.server?.kill("SIGKILL");
|
|
281
|
-
resolve();
|
|
282
|
-
}, 5000);
|
|
283
|
-
this.server?.on("exit", () => {
|
|
284
|
-
clearTimeout(timeout);
|
|
285
|
-
resolve();
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
this.server = null;
|
|
290
|
-
this.port = null;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
OpenCodeServerManager.instance = null;
|
|
294
|
-
OpenCodeServerManager.exitHandlerRegistered = false;
|
|
295
|
-
export class OpenCodeAgentClient {
|
|
296
|
-
constructor(logger, runtimeSettings) {
|
|
297
|
-
this.provider = "opencode";
|
|
298
|
-
this.capabilities = OPENCODE_CAPABILITIES;
|
|
299
|
-
this.logger = logger.child({ module: "agent", provider: "opencode" });
|
|
300
|
-
this.runtimeSettings = runtimeSettings;
|
|
301
|
-
this.serverManager = OpenCodeServerManager.getInstance(this.logger, runtimeSettings);
|
|
302
|
-
}
|
|
303
|
-
async createSession(config, _launchContext) {
|
|
304
|
-
const openCodeConfig = this.assertConfig(config);
|
|
305
|
-
const { url } = await this.serverManager.ensureRunning();
|
|
306
|
-
const client = createOpencodeClient({
|
|
307
|
-
baseUrl: url,
|
|
308
|
-
directory: openCodeConfig.cwd,
|
|
309
|
-
});
|
|
310
|
-
// Set a timeout for session creation to fail fast
|
|
311
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
312
|
-
setTimeout(() => reject(new Error("OpenCode session.create timed out after 10s")), 10000);
|
|
313
|
-
});
|
|
314
|
-
const response = await Promise.race([
|
|
315
|
-
client.session.create({ directory: openCodeConfig.cwd }),
|
|
316
|
-
timeoutPromise,
|
|
317
|
-
]);
|
|
318
|
-
if (response.error) {
|
|
319
|
-
throw new Error(`Failed to create OpenCode session: ${JSON.stringify(response.error)}`);
|
|
320
|
-
}
|
|
321
|
-
const session = response.data;
|
|
322
|
-
if (!session) {
|
|
323
|
-
throw new Error("OpenCode session creation returned no data");
|
|
324
|
-
}
|
|
325
|
-
return new OpenCodeAgentSession(openCodeConfig, client, session.id);
|
|
326
|
-
}
|
|
327
|
-
async resumeSession(handle, overrides, _launchContext) {
|
|
328
|
-
const cwd = overrides?.cwd ?? handle.metadata?.cwd;
|
|
329
|
-
if (!cwd) {
|
|
330
|
-
throw new Error("OpenCode resume requires the original working directory");
|
|
331
|
-
}
|
|
332
|
-
const config = {
|
|
333
|
-
provider: "opencode",
|
|
334
|
-
cwd,
|
|
335
|
-
...overrides,
|
|
336
|
-
};
|
|
337
|
-
const openCodeConfig = this.assertConfig(config);
|
|
338
|
-
const { url } = await this.serverManager.ensureRunning();
|
|
339
|
-
const client = createOpencodeClient({
|
|
340
|
-
baseUrl: url,
|
|
341
|
-
directory: openCodeConfig.cwd,
|
|
342
|
-
});
|
|
343
|
-
return new OpenCodeAgentSession(openCodeConfig, client, handle.sessionId);
|
|
344
|
-
}
|
|
345
|
-
async listModels(options) {
|
|
346
|
-
const { url } = await this.serverManager.ensureRunning();
|
|
347
|
-
const client = createOpencodeClient({
|
|
348
|
-
baseUrl: url,
|
|
349
|
-
directory: options?.cwd ?? process.cwd(),
|
|
350
|
-
});
|
|
351
|
-
// Set a timeout for the API call to fail fast if OpenCode isn't responding
|
|
352
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
353
|
-
setTimeout(() => reject(new Error("OpenCode provider.list timed out after 10s - server may not be authenticated or connected to any providers")), 10000);
|
|
354
|
-
});
|
|
355
|
-
const response = await Promise.race([
|
|
356
|
-
client.provider.list({ directory: options?.cwd ?? process.cwd() }),
|
|
357
|
-
timeoutPromise,
|
|
358
|
-
]);
|
|
359
|
-
if (response.error) {
|
|
360
|
-
throw new Error(`Failed to fetch OpenCode providers: ${JSON.stringify(response.error)}`);
|
|
361
|
-
}
|
|
362
|
-
const providers = response.data;
|
|
363
|
-
if (!providers) {
|
|
364
|
-
return [];
|
|
365
|
-
}
|
|
366
|
-
// Only include models from connected providers (ones that are actually available)
|
|
367
|
-
const connectedProviderIds = new Set(providers.connected);
|
|
368
|
-
// Fail fast if no providers are connected
|
|
369
|
-
if (connectedProviderIds.size === 0) {
|
|
370
|
-
throw new Error("OpenCode has no connected providers. Please authenticate with at least one provider (e.g., openai, anthropic) or set appropriate environment variables (e.g., OPENAI_API_KEY).");
|
|
371
|
-
}
|
|
372
|
-
const models = [];
|
|
373
|
-
for (const provider of providers.all) {
|
|
374
|
-
// Skip providers that aren't connected/configured
|
|
375
|
-
if (!connectedProviderIds.has(provider.id)) {
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
for (const [modelId, model] of Object.entries(provider.models)) {
|
|
379
|
-
const rawVariants = model.variants ? Object.keys(model.variants) : [];
|
|
380
|
-
const thinkingOptions = [
|
|
381
|
-
{ id: "default", label: "Model default", isDefault: true },
|
|
382
|
-
...rawVariants.map((id) => ({ id, label: id })),
|
|
383
|
-
];
|
|
384
|
-
models.push({
|
|
385
|
-
provider: "opencode",
|
|
386
|
-
id: `${provider.id}/${modelId}`,
|
|
387
|
-
label: model.name,
|
|
388
|
-
description: `${provider.name} - ${model.family ?? ""}`.trim(),
|
|
389
|
-
thinkingOptions: thinkingOptions.length > 1 ? thinkingOptions : undefined,
|
|
390
|
-
defaultThinkingOptionId: "default",
|
|
391
|
-
metadata: {
|
|
392
|
-
providerId: provider.id,
|
|
393
|
-
providerName: provider.name,
|
|
394
|
-
modelId,
|
|
395
|
-
family: model.family,
|
|
396
|
-
releaseDate: model.release_date,
|
|
397
|
-
supportsAttachments: model.attachment,
|
|
398
|
-
supportsReasoning: model.reasoning,
|
|
399
|
-
supportsToolCall: model.tool_call,
|
|
400
|
-
cost: model.cost,
|
|
401
|
-
},
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return models;
|
|
406
|
-
}
|
|
407
|
-
async listPersistedAgents(_options) {
|
|
408
|
-
// TODO: Implement by listing sessions from OpenCode
|
|
409
|
-
return [];
|
|
410
|
-
}
|
|
411
|
-
async isAvailable() {
|
|
412
|
-
const command = this.runtimeSettings?.command;
|
|
413
|
-
if (command?.mode === "replace") {
|
|
414
|
-
return existsSync(command.argv[0]);
|
|
415
|
-
}
|
|
416
|
-
return true;
|
|
417
|
-
}
|
|
418
|
-
assertConfig(config) {
|
|
419
|
-
if (config.provider !== "opencode") {
|
|
420
|
-
throw new Error(`OpenCodeAgentClient received config for provider '${config.provider}'`);
|
|
421
|
-
}
|
|
422
|
-
return { ...config, provider: "opencode" };
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
function stringifyStructuredAssistantMessage(value) {
|
|
426
|
-
if (value === undefined) {
|
|
427
|
-
return null;
|
|
428
|
-
}
|
|
429
|
-
if (typeof value === "string") {
|
|
430
|
-
const trimmed = value.trim();
|
|
431
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
432
|
-
}
|
|
433
|
-
try {
|
|
434
|
-
return JSON.stringify(value);
|
|
435
|
-
}
|
|
436
|
-
catch {
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
function readOpenCodeRecord(value) {
|
|
441
|
-
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
442
|
-
? value
|
|
443
|
-
: null;
|
|
444
|
-
}
|
|
445
|
-
function readNonEmptyString(value) {
|
|
446
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
447
|
-
}
|
|
448
|
-
function normalizeQuestionOptions(value) {
|
|
449
|
-
if (!Array.isArray(value)) {
|
|
450
|
-
return null;
|
|
451
|
-
}
|
|
452
|
-
const options = [];
|
|
453
|
-
for (const item of value) {
|
|
454
|
-
if (typeof item === "string" && item.trim().length > 0) {
|
|
455
|
-
options.push({ label: item.trim() });
|
|
456
|
-
continue;
|
|
457
|
-
}
|
|
458
|
-
const record = readOpenCodeRecord(item);
|
|
459
|
-
const label = readNonEmptyString(record?.label);
|
|
460
|
-
if (!label) {
|
|
461
|
-
continue;
|
|
462
|
-
}
|
|
463
|
-
const description = readNonEmptyString(record?.description);
|
|
464
|
-
options.push(description ? { label, description } : { label });
|
|
465
|
-
}
|
|
466
|
-
return options;
|
|
467
|
-
}
|
|
468
|
-
export function translateOpenCodeEvent(event, state) {
|
|
469
|
-
const events = [];
|
|
470
|
-
if (!event || typeof event !== "object") {
|
|
471
|
-
return events;
|
|
472
|
-
}
|
|
473
|
-
const e = event;
|
|
474
|
-
const type = e.type;
|
|
475
|
-
const props = e.properties ?? {};
|
|
476
|
-
switch (type) {
|
|
477
|
-
case "session.created":
|
|
478
|
-
case "session.updated": {
|
|
479
|
-
const sessionId = props.id;
|
|
480
|
-
if (sessionId === state.sessionId) {
|
|
481
|
-
events.push({
|
|
482
|
-
type: "thread_started",
|
|
483
|
-
sessionId: state.sessionId,
|
|
484
|
-
provider: "opencode",
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
break;
|
|
488
|
-
}
|
|
489
|
-
case "message.updated": {
|
|
490
|
-
const info = props.info;
|
|
491
|
-
if (!info) {
|
|
492
|
-
break;
|
|
493
|
-
}
|
|
494
|
-
const messageId = info.id;
|
|
495
|
-
const messageSessionId = info.sessionID;
|
|
496
|
-
const role = info.role;
|
|
497
|
-
if (messageId && messageSessionId === state.sessionId && role) {
|
|
498
|
-
state.messageRoles.set(messageId, role);
|
|
499
|
-
if (role === "assistant" &&
|
|
500
|
-
!state.emittedStructuredMessageIds.has(messageId) &&
|
|
501
|
-
typeof info.time === "object" &&
|
|
502
|
-
info.time !== null &&
|
|
503
|
-
"completed" in info.time) {
|
|
504
|
-
const text = stringifyStructuredAssistantMessage(info.structured);
|
|
505
|
-
if (text) {
|
|
506
|
-
state.emittedStructuredMessageIds.add(messageId);
|
|
507
|
-
events.push({
|
|
508
|
-
type: "timeline",
|
|
509
|
-
provider: "opencode",
|
|
510
|
-
item: { type: "assistant_message", text },
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
break;
|
|
516
|
-
}
|
|
517
|
-
case "message.part.updated": {
|
|
518
|
-
const part = props.part;
|
|
519
|
-
const delta = props.delta;
|
|
520
|
-
if (!part) {
|
|
521
|
-
break;
|
|
522
|
-
}
|
|
523
|
-
const partSessionId = part.sessionID;
|
|
524
|
-
if (partSessionId !== state.sessionId) {
|
|
525
|
-
break;
|
|
526
|
-
}
|
|
527
|
-
const messageId = part.messageID;
|
|
528
|
-
const messageRole = messageId ? state.messageRoles.get(messageId) : undefined;
|
|
529
|
-
const partType = part.type;
|
|
530
|
-
const partTime = part.time;
|
|
531
|
-
if (partType === "text") {
|
|
532
|
-
const partKey = resolvePartDedupeKey(part, "text");
|
|
533
|
-
if (messageRole === "user") {
|
|
534
|
-
break;
|
|
535
|
-
}
|
|
536
|
-
if (!messageRole && !delta) {
|
|
537
|
-
break;
|
|
538
|
-
}
|
|
539
|
-
if (delta) {
|
|
540
|
-
if (partKey) {
|
|
541
|
-
state.streamedPartKeys.add(partKey);
|
|
542
|
-
}
|
|
543
|
-
events.push({
|
|
544
|
-
type: "timeline",
|
|
545
|
-
provider: "opencode",
|
|
546
|
-
item: { type: "assistant_message", text: delta },
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
else if (partTime?.end) {
|
|
550
|
-
if (partKey && state.streamedPartKeys.delete(partKey)) {
|
|
551
|
-
break;
|
|
552
|
-
}
|
|
553
|
-
const text = part.text;
|
|
554
|
-
if (text) {
|
|
555
|
-
events.push({
|
|
556
|
-
type: "timeline",
|
|
557
|
-
provider: "opencode",
|
|
558
|
-
item: { type: "assistant_message", text },
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
else if (partType === "reasoning") {
|
|
564
|
-
const partKey = resolvePartDedupeKey(part, "reasoning");
|
|
565
|
-
if (delta) {
|
|
566
|
-
if (partKey) {
|
|
567
|
-
state.streamedPartKeys.add(partKey);
|
|
568
|
-
}
|
|
569
|
-
events.push({
|
|
570
|
-
type: "timeline",
|
|
571
|
-
provider: "opencode",
|
|
572
|
-
item: { type: "reasoning", text: delta },
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
else if (partTime?.end) {
|
|
576
|
-
if (partKey && state.streamedPartKeys.delete(partKey)) {
|
|
577
|
-
break;
|
|
578
|
-
}
|
|
579
|
-
const text = part.text;
|
|
580
|
-
if (text) {
|
|
581
|
-
events.push({
|
|
582
|
-
type: "timeline",
|
|
583
|
-
provider: "opencode",
|
|
584
|
-
item: { type: "reasoning", text },
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
else if (partType === "tool") {
|
|
590
|
-
const parsedToolPart = OpencodeToolPartToTimelineItemSchema.safeParse(part);
|
|
591
|
-
if (parsedToolPart.success && parsedToolPart.data) {
|
|
592
|
-
events.push({
|
|
593
|
-
type: "timeline",
|
|
594
|
-
provider: "opencode",
|
|
595
|
-
item: parsedToolPart.data,
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
else if (partType === "step-finish") {
|
|
600
|
-
const tokens = part.tokens;
|
|
601
|
-
const cost = part.cost;
|
|
602
|
-
if (tokens) {
|
|
603
|
-
state.accumulatedUsage.inputTokens =
|
|
604
|
-
(state.accumulatedUsage.inputTokens ?? 0) + (tokens.input ?? 0);
|
|
605
|
-
state.accumulatedUsage.outputTokens =
|
|
606
|
-
(state.accumulatedUsage.outputTokens ?? 0) + (tokens.output ?? 0);
|
|
607
|
-
}
|
|
608
|
-
if (cost !== undefined) {
|
|
609
|
-
state.accumulatedUsage.totalCostUsd = (state.accumulatedUsage.totalCostUsd ?? 0) + cost;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
break;
|
|
613
|
-
}
|
|
614
|
-
case "permission.asked": {
|
|
615
|
-
const sessionId = props.sessionID;
|
|
616
|
-
if (sessionId !== state.sessionId) {
|
|
617
|
-
break;
|
|
618
|
-
}
|
|
619
|
-
const requestId = props.id;
|
|
620
|
-
const permission = props.permission;
|
|
621
|
-
const metadata = props.metadata;
|
|
622
|
-
const patterns = props.patterns;
|
|
623
|
-
const permRequest = {
|
|
624
|
-
id: requestId,
|
|
625
|
-
provider: "opencode",
|
|
626
|
-
name: permission,
|
|
627
|
-
kind: "tool",
|
|
628
|
-
title: permission,
|
|
629
|
-
description: patterns?.join(", "),
|
|
630
|
-
input: metadata,
|
|
631
|
-
};
|
|
632
|
-
events.push({
|
|
633
|
-
type: "permission_requested",
|
|
634
|
-
provider: "opencode",
|
|
635
|
-
request: permRequest,
|
|
636
|
-
});
|
|
637
|
-
break;
|
|
638
|
-
}
|
|
639
|
-
case "question.asked": {
|
|
640
|
-
const sessionId = props.sessionID;
|
|
641
|
-
if (sessionId !== state.sessionId) {
|
|
642
|
-
break;
|
|
643
|
-
}
|
|
644
|
-
const requestId = props.id;
|
|
645
|
-
const rawQuestions = Array.isArray(props.questions) ? props.questions : [];
|
|
646
|
-
if (!requestId || rawQuestions.length === 0) {
|
|
647
|
-
break;
|
|
648
|
-
}
|
|
649
|
-
const questions = rawQuestions.flatMap((item) => {
|
|
650
|
-
const questionRecord = readOpenCodeRecord(item);
|
|
651
|
-
const question = readNonEmptyString(questionRecord?.question);
|
|
652
|
-
const header = readNonEmptyString(questionRecord?.header);
|
|
653
|
-
if (!question || !header) {
|
|
654
|
-
return [];
|
|
655
|
-
}
|
|
656
|
-
const options = normalizeQuestionOptions(questionRecord?.options) ?? [];
|
|
657
|
-
return [
|
|
658
|
-
{
|
|
659
|
-
question,
|
|
660
|
-
header,
|
|
661
|
-
options,
|
|
662
|
-
...(questionRecord?.multiple === true ? { multiSelect: true } : {}),
|
|
663
|
-
},
|
|
664
|
-
];
|
|
665
|
-
});
|
|
666
|
-
if (questions.length === 0) {
|
|
667
|
-
break;
|
|
668
|
-
}
|
|
669
|
-
events.push({
|
|
670
|
-
type: "permission_requested",
|
|
671
|
-
provider: "opencode",
|
|
672
|
-
request: {
|
|
673
|
-
id: requestId,
|
|
674
|
-
provider: "opencode",
|
|
675
|
-
name: "question",
|
|
676
|
-
kind: "question",
|
|
677
|
-
title: "Question",
|
|
678
|
-
input: { questions },
|
|
679
|
-
metadata: {
|
|
680
|
-
source: "opencode_question",
|
|
681
|
-
...(readOpenCodeRecord(props.tool) ?? {}),
|
|
682
|
-
},
|
|
683
|
-
},
|
|
684
|
-
});
|
|
685
|
-
break;
|
|
686
|
-
}
|
|
687
|
-
case "session.idle": {
|
|
688
|
-
const sessionId = props.sessionID;
|
|
689
|
-
if (sessionId === state.sessionId) {
|
|
690
|
-
state.streamedPartKeys.clear();
|
|
691
|
-
events.push({
|
|
692
|
-
type: "turn_completed",
|
|
693
|
-
provider: "opencode",
|
|
694
|
-
usage: undefined,
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
break;
|
|
698
|
-
}
|
|
699
|
-
case "session.error": {
|
|
700
|
-
const sessionId = props.sessionID;
|
|
701
|
-
if (sessionId === state.sessionId) {
|
|
702
|
-
state.streamedPartKeys.clear();
|
|
703
|
-
const error = props.error;
|
|
704
|
-
events.push({
|
|
705
|
-
type: "turn_failed",
|
|
706
|
-
provider: "opencode",
|
|
707
|
-
error: error ?? "Unknown error",
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
break;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
return events;
|
|
714
|
-
}
|
|
715
|
-
class OpenCodeAgentSession {
|
|
716
|
-
constructor(config, client, sessionId) {
|
|
717
|
-
this.provider = "opencode";
|
|
718
|
-
this.capabilities = OPENCODE_CAPABILITIES;
|
|
719
|
-
this.currentMode = "default";
|
|
720
|
-
this.pendingPermissions = new Map();
|
|
721
|
-
this.abortController = null;
|
|
722
|
-
this.accumulatedUsage = {};
|
|
723
|
-
this.mcpConfigured = false;
|
|
724
|
-
this.mcpSetupPromise = null;
|
|
725
|
-
/** Tracks the role of each message by ID to distinguish user from assistant messages */
|
|
726
|
-
this.messageRoles = new Map();
|
|
727
|
-
/** Tracks streamed textual part IDs to suppress final full-text echoes from OpenCode. */
|
|
728
|
-
this.streamedPartKeys = new Set();
|
|
729
|
-
/** Tracks assistant messages already emitted from structured payloads. */
|
|
730
|
-
this.emittedStructuredMessageIds = new Set();
|
|
731
|
-
this.availableModesCache = null;
|
|
732
|
-
this.subscribers = new Set();
|
|
733
|
-
this.nextTurnOrdinal = 0;
|
|
734
|
-
this.activeForegroundTurnId = null;
|
|
735
|
-
this.config = config;
|
|
736
|
-
this.client = client;
|
|
737
|
-
this.sessionId = sessionId;
|
|
738
|
-
this.currentMode = normalizeOpenCodeModeId(config.modeId);
|
|
739
|
-
}
|
|
740
|
-
get id() {
|
|
741
|
-
return this.sessionId;
|
|
742
|
-
}
|
|
743
|
-
async getRuntimeInfo() {
|
|
744
|
-
return {
|
|
745
|
-
provider: "opencode",
|
|
746
|
-
sessionId: this.sessionId,
|
|
747
|
-
model: this.config.model ?? null,
|
|
748
|
-
modeId: this.currentMode,
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
async setModel(modelId) {
|
|
752
|
-
const normalizedModelId = typeof modelId === "string" && modelId.trim().length > 0 ? modelId : null;
|
|
753
|
-
this.config.model = normalizedModelId ?? undefined;
|
|
754
|
-
}
|
|
755
|
-
async setThinkingOption(thinkingOptionId) {
|
|
756
|
-
const normalizedThinkingOptionId = typeof thinkingOptionId === "string" && thinkingOptionId.trim().length > 0
|
|
757
|
-
? thinkingOptionId
|
|
758
|
-
: null;
|
|
759
|
-
this.config.thinkingOptionId = normalizedThinkingOptionId ?? undefined;
|
|
760
|
-
}
|
|
761
|
-
async run(prompt, options) {
|
|
762
|
-
const timeline = [];
|
|
763
|
-
let finalText = "";
|
|
764
|
-
let usage;
|
|
765
|
-
let turnId = null;
|
|
766
|
-
const bufferedEvents = [];
|
|
767
|
-
let settled = false;
|
|
768
|
-
let resolveCompletion;
|
|
769
|
-
let rejectCompletion;
|
|
770
|
-
const processEvent = (event) => {
|
|
771
|
-
if (settled) {
|
|
772
|
-
return;
|
|
773
|
-
}
|
|
774
|
-
const eventTurnId = event.turnId;
|
|
775
|
-
if (turnId && eventTurnId && eventTurnId !== turnId) {
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
if (event.type === "timeline") {
|
|
779
|
-
timeline.push(event.item);
|
|
780
|
-
if (event.item.type === "assistant_message") {
|
|
781
|
-
finalText = event.item.text;
|
|
782
|
-
}
|
|
783
|
-
return;
|
|
784
|
-
}
|
|
785
|
-
if (event.type === "turn_completed") {
|
|
786
|
-
usage = event.usage;
|
|
787
|
-
settled = true;
|
|
788
|
-
resolveCompletion();
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
if (event.type === "turn_failed") {
|
|
792
|
-
settled = true;
|
|
793
|
-
rejectCompletion(new Error(event.error));
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
if (event.type === "turn_canceled") {
|
|
797
|
-
settled = true;
|
|
798
|
-
resolveCompletion();
|
|
799
|
-
}
|
|
800
|
-
};
|
|
801
|
-
const completion = new Promise((resolve, reject) => {
|
|
802
|
-
resolveCompletion = resolve;
|
|
803
|
-
rejectCompletion = reject;
|
|
804
|
-
});
|
|
805
|
-
const unsubscribe = this.subscribe((event) => {
|
|
806
|
-
if (!turnId) {
|
|
807
|
-
bufferedEvents.push(event);
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
810
|
-
processEvent(event);
|
|
811
|
-
});
|
|
812
|
-
try {
|
|
813
|
-
const result = await this.startTurn(prompt, options);
|
|
814
|
-
turnId = result.turnId;
|
|
815
|
-
for (const event of bufferedEvents) {
|
|
816
|
-
processEvent(event);
|
|
817
|
-
}
|
|
818
|
-
if (!settled) {
|
|
819
|
-
await completion;
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
finally {
|
|
823
|
-
unsubscribe();
|
|
824
|
-
}
|
|
825
|
-
return {
|
|
826
|
-
sessionId: this.sessionId,
|
|
827
|
-
finalText,
|
|
828
|
-
usage,
|
|
829
|
-
timeline,
|
|
830
|
-
};
|
|
831
|
-
}
|
|
832
|
-
async interrupt() {
|
|
833
|
-
this.abortController?.abort();
|
|
834
|
-
await this.client.session.abort({
|
|
835
|
-
sessionID: this.sessionId,
|
|
836
|
-
directory: this.config.cwd,
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
async startTurn(prompt, options) {
|
|
840
|
-
if (this.activeForegroundTurnId) {
|
|
841
|
-
throw new Error("A foreground turn is already active");
|
|
842
|
-
}
|
|
843
|
-
this.abortController = new AbortController();
|
|
844
|
-
await this.ensureMcpServersConfigured();
|
|
845
|
-
const parts = this.buildPromptParts(prompt);
|
|
846
|
-
const model = this.parseModel(this.config.model);
|
|
847
|
-
const thinkingOptionId = this.config.thinkingOptionId;
|
|
848
|
-
const effectiveVariant = thinkingOptionId && thinkingOptionId !== "default" ? thinkingOptionId : undefined;
|
|
849
|
-
const effectiveMode = normalizeOpenCodeModeId(this.currentMode);
|
|
850
|
-
const promptResponse = await this.client.session.promptAsync({
|
|
851
|
-
sessionID: this.sessionId,
|
|
852
|
-
directory: this.config.cwd,
|
|
853
|
-
parts,
|
|
854
|
-
...(options?.outputSchema
|
|
855
|
-
? {
|
|
856
|
-
format: {
|
|
857
|
-
type: "json_schema",
|
|
858
|
-
schema: options.outputSchema,
|
|
859
|
-
},
|
|
860
|
-
}
|
|
861
|
-
: {}),
|
|
862
|
-
...(this.config.systemPrompt ? { system: this.config.systemPrompt } : {}),
|
|
863
|
-
...(model ? { model } : {}),
|
|
864
|
-
...(effectiveMode ? { agent: effectiveMode } : {}),
|
|
865
|
-
...(effectiveVariant ? { variant: effectiveVariant } : {}),
|
|
866
|
-
});
|
|
867
|
-
if (promptResponse.error) {
|
|
868
|
-
const errorMsg = JSON.stringify(promptResponse.error);
|
|
869
|
-
this.notifySubscribers({
|
|
870
|
-
type: "turn_failed",
|
|
871
|
-
provider: "opencode",
|
|
872
|
-
error: errorMsg,
|
|
873
|
-
});
|
|
874
|
-
throw new Error(errorMsg);
|
|
875
|
-
}
|
|
876
|
-
const turnId = this.createTurnId();
|
|
877
|
-
this.activeForegroundTurnId = turnId;
|
|
878
|
-
void this.consumeEventStream();
|
|
879
|
-
return { turnId };
|
|
880
|
-
}
|
|
881
|
-
subscribe(callback) {
|
|
882
|
-
this.subscribers.add(callback);
|
|
883
|
-
return () => {
|
|
884
|
-
this.subscribers.delete(callback);
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
async consumeEventStream() {
|
|
888
|
-
const eventsResult = await this.client.event.subscribe({
|
|
889
|
-
directory: this.config.cwd,
|
|
890
|
-
});
|
|
891
|
-
try {
|
|
892
|
-
for await (const event of eventsResult.stream) {
|
|
893
|
-
if (this.abortController?.signal.aborted) {
|
|
894
|
-
break;
|
|
895
|
-
}
|
|
896
|
-
const translated = this.translateEvent(event);
|
|
897
|
-
for (const e of translated) {
|
|
898
|
-
this.notifySubscribers(e);
|
|
899
|
-
if (e.type === "turn_completed" || e.type === "turn_failed") {
|
|
900
|
-
this.activeForegroundTurnId = null;
|
|
901
|
-
return;
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
catch (error) {
|
|
907
|
-
if (!this.abortController?.signal.aborted) {
|
|
908
|
-
this.notifySubscribers({
|
|
909
|
-
type: "turn_failed",
|
|
910
|
-
provider: "opencode",
|
|
911
|
-
error: error instanceof Error ? error.message : "Stream error",
|
|
912
|
-
});
|
|
913
|
-
this.activeForegroundTurnId = null;
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
notifySubscribers(event) {
|
|
918
|
-
const turnId = this.activeForegroundTurnId;
|
|
919
|
-
const tagged = turnId ? { ...event, turnId } : event;
|
|
920
|
-
for (const callback of this.subscribers) {
|
|
921
|
-
try {
|
|
922
|
-
callback(tagged);
|
|
923
|
-
}
|
|
924
|
-
catch {
|
|
925
|
-
// Subscriber callback error isolation
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
createTurnId() {
|
|
930
|
-
return `opencode-turn-${this.nextTurnOrdinal++}`;
|
|
931
|
-
}
|
|
932
|
-
async *streamHistory() {
|
|
933
|
-
const response = await this.client.session.messages({
|
|
934
|
-
sessionID: this.sessionId,
|
|
935
|
-
directory: this.config.cwd,
|
|
936
|
-
});
|
|
937
|
-
if (response.error || !response.data) {
|
|
938
|
-
return;
|
|
939
|
-
}
|
|
940
|
-
const messages = response.data;
|
|
941
|
-
for (const message of messages) {
|
|
942
|
-
const { info, parts } = message;
|
|
943
|
-
const role = info.role;
|
|
944
|
-
if (role === "user") {
|
|
945
|
-
// Extract user message text from parts
|
|
946
|
-
const textParts = parts.filter((p) => p.type === "text");
|
|
947
|
-
const text = textParts.map((p) => p.text ?? "").join("");
|
|
948
|
-
if (text) {
|
|
949
|
-
yield {
|
|
950
|
-
type: "timeline",
|
|
951
|
-
provider: "opencode",
|
|
952
|
-
item: { type: "user_message", text },
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
else if (role === "assistant") {
|
|
957
|
-
let emittedAssistantText = false;
|
|
958
|
-
// Process each part
|
|
959
|
-
for (const part of parts) {
|
|
960
|
-
const partType = part.type;
|
|
961
|
-
if (partType === "text") {
|
|
962
|
-
const text = part.text;
|
|
963
|
-
if (text) {
|
|
964
|
-
emittedAssistantText = true;
|
|
965
|
-
yield {
|
|
966
|
-
type: "timeline",
|
|
967
|
-
provider: "opencode",
|
|
968
|
-
item: { type: "assistant_message", text },
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
else if (partType === "reasoning") {
|
|
973
|
-
const text = part.text;
|
|
974
|
-
if (text) {
|
|
975
|
-
yield {
|
|
976
|
-
type: "timeline",
|
|
977
|
-
provider: "opencode",
|
|
978
|
-
item: { type: "reasoning", text },
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
else if (partType === "tool") {
|
|
983
|
-
const parsedToolPart = OpencodeToolPartToTimelineItemSchema.safeParse(part);
|
|
984
|
-
if (parsedToolPart.success) {
|
|
985
|
-
if (parsedToolPart.data) {
|
|
986
|
-
yield {
|
|
987
|
-
type: "timeline",
|
|
988
|
-
provider: "opencode",
|
|
989
|
-
item: parsedToolPart.data,
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
if (!emittedAssistantText) {
|
|
996
|
-
const text = stringifyStructuredAssistantMessage(info.structured);
|
|
997
|
-
if (text) {
|
|
998
|
-
yield {
|
|
999
|
-
type: "timeline",
|
|
1000
|
-
provider: "opencode",
|
|
1001
|
-
item: { type: "assistant_message", text },
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
async getAvailableModes() {
|
|
1009
|
-
if (this.availableModesCache) {
|
|
1010
|
-
return this.availableModesCache;
|
|
1011
|
-
}
|
|
1012
|
-
const response = await this.client.app.agents({
|
|
1013
|
-
directory: this.config.cwd,
|
|
1014
|
-
});
|
|
1015
|
-
const discoveredModes = response.error || !response.data
|
|
1016
|
-
? []
|
|
1017
|
-
: response.data
|
|
1018
|
-
.filter((agent) => agent.mode === "primary" && agent.hidden !== true)
|
|
1019
|
-
.filter((agent) => OPENCODE_MODE_IDS.has(agent.name))
|
|
1020
|
-
.map((agent) => ({
|
|
1021
|
-
id: agent.name,
|
|
1022
|
-
label: agent.name.charAt(0).toUpperCase() + agent.name.slice(1),
|
|
1023
|
-
description: typeof agent.description === "string" && agent.description.trim().length > 0
|
|
1024
|
-
? agent.description.trim()
|
|
1025
|
-
: DEFAULT_MODES.find((mode) => mode.id === agent.name)?.description,
|
|
1026
|
-
}));
|
|
1027
|
-
this.availableModesCache =
|
|
1028
|
-
discoveredModes.length > 0 ? sortOpenCodeModes(discoveredModes) : DEFAULT_MODES;
|
|
1029
|
-
return this.availableModesCache;
|
|
1030
|
-
}
|
|
1031
|
-
async getCurrentMode() {
|
|
1032
|
-
return this.currentMode;
|
|
1033
|
-
}
|
|
1034
|
-
async setMode(modeId) {
|
|
1035
|
-
this.currentMode = normalizeOpenCodeModeId(modeId);
|
|
1036
|
-
}
|
|
1037
|
-
getPendingPermissions() {
|
|
1038
|
-
return Array.from(this.pendingPermissions.values());
|
|
1039
|
-
}
|
|
1040
|
-
async respondToPermission(requestId, response) {
|
|
1041
|
-
const pending = this.pendingPermissions.get(requestId);
|
|
1042
|
-
if (!pending) {
|
|
1043
|
-
throw new Error(`No pending permission request with id '${requestId}'`);
|
|
1044
|
-
}
|
|
1045
|
-
if (pending.kind === "question") {
|
|
1046
|
-
if (response.behavior === "deny") {
|
|
1047
|
-
await this.client.question.reject({
|
|
1048
|
-
requestID: requestId,
|
|
1049
|
-
directory: this.config.cwd,
|
|
1050
|
-
});
|
|
1051
|
-
}
|
|
1052
|
-
else {
|
|
1053
|
-
const answersRecord = readOpenCodeRecord(response.updatedInput?.answers);
|
|
1054
|
-
const questions = Array.isArray(pending.input?.questions) ? pending.input.questions : [];
|
|
1055
|
-
const answers = questions.map((item) => {
|
|
1056
|
-
const header = readNonEmptyString(readOpenCodeRecord(item)?.header);
|
|
1057
|
-
const rawAnswer = header ? readNonEmptyString(answersRecord?.[header]) : null;
|
|
1058
|
-
if (!rawAnswer) {
|
|
1059
|
-
return [];
|
|
1060
|
-
}
|
|
1061
|
-
return rawAnswer
|
|
1062
|
-
.split(",")
|
|
1063
|
-
.map((entry) => entry.trim())
|
|
1064
|
-
.filter((entry) => entry.length > 0);
|
|
1065
|
-
});
|
|
1066
|
-
await this.client.question.reply({
|
|
1067
|
-
requestID: requestId,
|
|
1068
|
-
directory: this.config.cwd,
|
|
1069
|
-
answers,
|
|
1070
|
-
});
|
|
1071
|
-
}
|
|
1072
|
-
this.pendingPermissions.delete(requestId);
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
const reply = response.behavior === "allow" ? "once" : "reject";
|
|
1076
|
-
await this.client.permission.reply({
|
|
1077
|
-
requestID: requestId,
|
|
1078
|
-
directory: this.config.cwd,
|
|
1079
|
-
reply,
|
|
1080
|
-
message: response.behavior === "deny" ? response.message : undefined,
|
|
1081
|
-
});
|
|
1082
|
-
this.pendingPermissions.delete(requestId);
|
|
1083
|
-
}
|
|
1084
|
-
describePersistence() {
|
|
1085
|
-
return {
|
|
1086
|
-
provider: "opencode",
|
|
1087
|
-
sessionId: this.sessionId,
|
|
1088
|
-
nativeHandle: this.sessionId,
|
|
1089
|
-
metadata: {
|
|
1090
|
-
cwd: this.config.cwd,
|
|
1091
|
-
},
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
async close() {
|
|
1095
|
-
this.abortController?.abort();
|
|
1096
|
-
this.subscribers.clear();
|
|
1097
|
-
this.activeForegroundTurnId = null;
|
|
1098
|
-
}
|
|
1099
|
-
buildPromptParts(prompt) {
|
|
1100
|
-
if (typeof prompt === "string") {
|
|
1101
|
-
return [{ type: "text", text: prompt }];
|
|
1102
|
-
}
|
|
1103
|
-
return prompt
|
|
1104
|
-
.filter((p) => p.type === "text")
|
|
1105
|
-
.map((p) => ({ type: "text", text: p.text }));
|
|
1106
|
-
}
|
|
1107
|
-
parseModel(model) {
|
|
1108
|
-
if (!model) {
|
|
1109
|
-
return undefined;
|
|
1110
|
-
}
|
|
1111
|
-
const parts = model.split("/");
|
|
1112
|
-
if (parts.length >= 2) {
|
|
1113
|
-
return { providerID: parts[0], modelID: parts.slice(1).join("/") };
|
|
1114
|
-
}
|
|
1115
|
-
return { providerID: "opencode", modelID: model };
|
|
1116
|
-
}
|
|
1117
|
-
async ensureMcpServersConfigured() {
|
|
1118
|
-
if (this.mcpConfigured) {
|
|
1119
|
-
return;
|
|
1120
|
-
}
|
|
1121
|
-
const mcpServers = this.config.mcpServers;
|
|
1122
|
-
if (!mcpServers || Object.keys(mcpServers).length === 0) {
|
|
1123
|
-
this.mcpConfigured = true;
|
|
1124
|
-
return;
|
|
1125
|
-
}
|
|
1126
|
-
if (!this.mcpSetupPromise) {
|
|
1127
|
-
this.mcpSetupPromise = this.configureMcpServers(mcpServers);
|
|
1128
|
-
}
|
|
1129
|
-
try {
|
|
1130
|
-
await this.mcpSetupPromise;
|
|
1131
|
-
this.mcpConfigured = true;
|
|
1132
|
-
}
|
|
1133
|
-
catch (error) {
|
|
1134
|
-
this.mcpSetupPromise = null;
|
|
1135
|
-
throw error;
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
async configureMcpServers(mcpServers) {
|
|
1139
|
-
for (const [name, serverConfig] of Object.entries(mcpServers)) {
|
|
1140
|
-
const mappedConfig = toOpenCodeMcpConfig(serverConfig);
|
|
1141
|
-
await this.registerMcpServer(name, mappedConfig);
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
async registerMcpServer(name, config) {
|
|
1145
|
-
await this.runMcpOperation("add", name, () => this.client.mcp.add({
|
|
1146
|
-
directory: this.config.cwd,
|
|
1147
|
-
name,
|
|
1148
|
-
config,
|
|
1149
|
-
}));
|
|
1150
|
-
await this.runMcpOperation("connect", name, () => this.client.mcp.connect({
|
|
1151
|
-
directory: this.config.cwd,
|
|
1152
|
-
name,
|
|
1153
|
-
}));
|
|
1154
|
-
}
|
|
1155
|
-
async runMcpOperation(operation, name, run) {
|
|
1156
|
-
const response = await run();
|
|
1157
|
-
const error = response.error;
|
|
1158
|
-
if (!error) {
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
if (isAlreadyPresentMcpError(error)) {
|
|
1162
|
-
return;
|
|
1163
|
-
}
|
|
1164
|
-
throw new Error(`Failed to ${operation} OpenCode MCP server '${name}': ${stringifyUnknownError(error)}`);
|
|
1165
|
-
}
|
|
1166
|
-
translateEvent(event) {
|
|
1167
|
-
const translated = translateOpenCodeEvent(event, {
|
|
1168
|
-
sessionId: this.sessionId,
|
|
1169
|
-
messageRoles: this.messageRoles,
|
|
1170
|
-
accumulatedUsage: this.accumulatedUsage,
|
|
1171
|
-
streamedPartKeys: this.streamedPartKeys,
|
|
1172
|
-
emittedStructuredMessageIds: this.emittedStructuredMessageIds,
|
|
1173
|
-
});
|
|
1174
|
-
for (const translatedEvent of translated) {
|
|
1175
|
-
if (translatedEvent.type === "permission_requested") {
|
|
1176
|
-
this.pendingPermissions.set(translatedEvent.request.id, translatedEvent.request);
|
|
1177
|
-
}
|
|
1178
|
-
if (translatedEvent.type === "turn_completed") {
|
|
1179
|
-
translatedEvent.usage = this.extractAndResetUsage();
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
return translated;
|
|
1183
|
-
}
|
|
1184
|
-
extractAndResetUsage() {
|
|
1185
|
-
const usage = this.accumulatedUsage;
|
|
1186
|
-
this.accumulatedUsage = {};
|
|
1187
|
-
if (!usage.inputTokens && !usage.outputTokens && !usage.totalCostUsd) {
|
|
1188
|
-
return undefined;
|
|
1189
|
-
}
|
|
1190
|
-
return usage;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
//# sourceMappingURL=opencode-agent.js.map
|