@voxagent/bridge 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/dist/audio/source.d.ts +23 -0
- package/dist/audio/source.d.ts.map +1 -0
- package/dist/audio/source.js +69 -0
- package/dist/audio/source.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +171 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +62 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +102 -0
- package/dist/config.js.map +1 -0
- package/dist/drivers/claude.d.ts +36 -0
- package/dist/drivers/claude.d.ts.map +1 -0
- package/dist/drivers/claude.js +445 -0
- package/dist/drivers/claude.js.map +1 -0
- package/dist/drivers/codex.d.ts +56 -0
- package/dist/drivers/codex.d.ts.map +1 -0
- package/dist/drivers/codex.js +652 -0
- package/dist/drivers/codex.js.map +1 -0
- package/dist/drivers/index.d.ts +34 -0
- package/dist/drivers/index.d.ts.map +1 -0
- package/dist/drivers/index.js +18 -0
- package/dist/drivers/index.js.map +1 -0
- package/dist/drivers/types.d.ts +81 -0
- package/dist/drivers/types.d.ts.map +1 -0
- package/dist/drivers/types.js +11 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/logging.d.ts +15 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +36 -0
- package/dist/logging.js.map +1 -0
- package/dist/pair.d.ts +25 -0
- package/dist/pair.d.ts.map +1 -0
- package/dist/pair.js +41 -0
- package/dist/pair.js.map +1 -0
- package/dist/permissions.d.ts +67 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +221 -0
- package/dist/permissions.js.map +1 -0
- package/dist/protocol.d.ts +181 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +63 -0
- package/dist/protocol.js.map +1 -0
- package/dist/room.d.ts +52 -0
- package/dist/room.d.ts.map +1 -0
- package/dist/room.js +401 -0
- package/dist/room.js.map +1 -0
- package/dist/tts/elevenlabs.d.ts +43 -0
- package/dist/tts/elevenlabs.d.ts.map +1 -0
- package/dist/tts/elevenlabs.js +268 -0
- package/dist/tts/elevenlabs.js.map +1 -0
- package/dist/tts/index.d.ts +22 -0
- package/dist/tts/index.d.ts.map +1 -0
- package/dist/tts/index.js +23 -0
- package/dist/tts/index.js.map +1 -0
- package/dist/tts/openai.d.ts +35 -0
- package/dist/tts/openai.d.ts.map +1 -0
- package/dist/tts/openai.js +270 -0
- package/dist/tts/openai.js.map +1 -0
- package/dist/tts/types.d.ts +28 -0
- package/dist/tts/types.d.ts.map +1 -0
- package/dist/tts/types.js +5 -0
- package/dist/tts/types.js.map +1 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# @voxagent/bridge
|
|
2
|
+
|
|
3
|
+
Local bridge process that pairs the host's Claude Code or Codex agent with a VoxAgent meeting room.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
When a host pairs from the VoxAgent web app, this process:
|
|
8
|
+
|
|
9
|
+
1. Joins the LiveKit room as a real participant (identity `agent:<roomId>`).
|
|
10
|
+
2. Publishes a synthesized voice track via ElevenLabs (or stays silent in `--text-only`).
|
|
11
|
+
3. Listens on a LiveKit data channel for `prompt.user_turn` events from any participant.
|
|
12
|
+
4. Drives the host's local Claude Code (`@anthropic-ai/claude-agent-sdk`) or Codex CLI (`codex exec --json`) agent with the prompt.
|
|
13
|
+
5. Streams text deltas, tool calls, and run lifecycle events back to the room — UI gets subtitles + activity timeline, audio track gets the spoken response.
|
|
14
|
+
|
|
15
|
+
Trust mode by default: the agent runs under the host's existing CLI permission settings, no in-room approval gate.
|
|
16
|
+
|
|
17
|
+
## Quickstart
|
|
18
|
+
|
|
19
|
+
From the monorepo root:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# 1. Make sure your local agent is installed and logged in
|
|
23
|
+
# Claude: npm i -g @anthropic-ai/claude-code && claude
|
|
24
|
+
# Codex: npm i -g @openai/codex && codex login
|
|
25
|
+
|
|
26
|
+
# 2. In one terminal, run the web app
|
|
27
|
+
pnpm --dir apps/web dev
|
|
28
|
+
|
|
29
|
+
# 3. In a browser, open the room and click "Pair local agent" — copy the 6-digit code
|
|
30
|
+
|
|
31
|
+
# 4. In another terminal, run the bridge
|
|
32
|
+
export VOXAGENT_ELEVENLABS_API_KEY=... # required for voice; --text-only to skip
|
|
33
|
+
pnpm --filter @voxagent/bridge dev -- --code 123456 --agent claude
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or after a `pnpm --filter @voxagent/bridge build`:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node packages/bridge/dist/cli.js --code 123456 --agent claude
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Flags
|
|
43
|
+
|
|
44
|
+
| Flag | Env | Default | Notes |
|
|
45
|
+
|------|-----|---------|-------|
|
|
46
|
+
| `--code <CODE>` | `VOXAGENT_PAIR_CODE` | (interactive prompt) | 6-digit code from the room UI |
|
|
47
|
+
| `--api-url <URL>` | `VOXAGENT_API_URL` | `http://localhost:3000` | VoxAgent web app base URL |
|
|
48
|
+
| `--agent <BACKEND>` | `VOXAGENT_AGENT` | `claude` | `claude` or `codex` |
|
|
49
|
+
| `--cwd <PATH>` | `VOXAGENT_CWD` | `process.cwd()` | Working directory the agent runs inside |
|
|
50
|
+
| `--voice <VOICE_ID>` | `VOXAGENT_VOICE_ID` | `21m00Tcm4TlvDq8ikWAM` | ElevenLabs voice ID |
|
|
51
|
+
| `--model <MODEL_ID>` | `VOXAGENT_MODEL_ID` | `eleven_turbo_v2_5` | ElevenLabs model ID |
|
|
52
|
+
| `--text-only` | `VOXAGENT_TEXT_ONLY=1` | `false` | Skip TTS — text-only mode (subtitles in UI, no voice) |
|
|
53
|
+
| `--verbose` | — | `false` | Debug logs |
|
|
54
|
+
|
|
55
|
+
`VOXAGENT_ELEVENLABS_API_KEY` (or `ELEVENLABS_API_KEY`) is required unless `--text-only` is set.
|
|
56
|
+
|
|
57
|
+
## Architecture
|
|
58
|
+
|
|
59
|
+
See [`/docs/learning-reviews/`](../../docs/learning-reviews) and the refactor plan at `/Users/tanmay/.claude/plans/ok-i-want-you-refactored-wadler.md` for full background.
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Browser ──LiveKit data channel──▶ Bridge ──@anthropic-ai/claude-agent-sdk──▶ Claude Code
|
|
63
|
+
▲ │ (or `codex exec --json`)
|
|
64
|
+
│ ▼
|
|
65
|
+
└────agent voice track──── AudioSource ◀── ElevenLabs PCM ◀── text deltas
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Testing
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pnpm --filter @voxagent/bridge test
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Unit tests mock the SDK and subprocess so they run offline.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Wraps a LiveKit AudioSource so we can push TTS frames + flush on interrupt.
|
|
3
|
+
*/
|
|
4
|
+
import type { Room } from '@livekit/rtc-node';
|
|
5
|
+
import type { TtsFrame } from '../tts/types.js';
|
|
6
|
+
export declare class AgentAudioPublisher {
|
|
7
|
+
private source;
|
|
8
|
+
private track;
|
|
9
|
+
private published;
|
|
10
|
+
constructor(sampleRate: number, numChannels: number);
|
|
11
|
+
publish(room: Room): Promise<void>;
|
|
12
|
+
pushFrame(frame: TtsFrame): Promise<void>;
|
|
13
|
+
waitForPlayout(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Best-effort flush — clears anything in-flight inside the source's queue.
|
|
16
|
+
*
|
|
17
|
+
* @livekit/rtc-node's AudioSource exposes `clearQueue()` in newer versions.
|
|
18
|
+
* We optionally call it; falls back to a noop when unavailable.
|
|
19
|
+
*/
|
|
20
|
+
flush(): Promise<void>;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/audio/source.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAKhD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,SAAS,CAAS;gBAEd,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAK7C,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAalC,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAWzC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrC;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAatB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Wraps a LiveKit AudioSource so we can push TTS frames + flush on interrupt.
|
|
3
|
+
*/
|
|
4
|
+
import { AudioFrame, AudioSource, LocalAudioTrack, TrackPublishOptions, TrackSource } from '@livekit/rtc-node';
|
|
5
|
+
import { log } from '../logging.js';
|
|
6
|
+
const TRACK_NAME = 'voxagent-agent-voice';
|
|
7
|
+
export class AgentAudioPublisher {
|
|
8
|
+
source;
|
|
9
|
+
track;
|
|
10
|
+
published = false;
|
|
11
|
+
constructor(sampleRate, numChannels) {
|
|
12
|
+
this.source = new AudioSource(sampleRate, numChannels);
|
|
13
|
+
this.track = LocalAudioTrack.createAudioTrack(TRACK_NAME, this.source);
|
|
14
|
+
}
|
|
15
|
+
async publish(room) {
|
|
16
|
+
if (this.published)
|
|
17
|
+
return;
|
|
18
|
+
const local = room.localParticipant;
|
|
19
|
+
if (!local) {
|
|
20
|
+
throw new Error('Cannot publish agent audio: room has no local participant.');
|
|
21
|
+
}
|
|
22
|
+
const opts = new TrackPublishOptions();
|
|
23
|
+
opts.source = TrackSource.SOURCE_MICROPHONE;
|
|
24
|
+
await local.publishTrack(this.track, opts);
|
|
25
|
+
this.published = true;
|
|
26
|
+
log.info('agent_audio_track_published', { name: TRACK_NAME });
|
|
27
|
+
}
|
|
28
|
+
async pushFrame(frame) {
|
|
29
|
+
const samplesPerChannel = frame.samples.length / frame.numChannels;
|
|
30
|
+
const audioFrame = new AudioFrame(frame.samples, frame.sampleRate, frame.numChannels, samplesPerChannel);
|
|
31
|
+
await this.source.captureFrame(audioFrame);
|
|
32
|
+
}
|
|
33
|
+
async waitForPlayout() {
|
|
34
|
+
try {
|
|
35
|
+
await this.source.waitForPlayout();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// ignore — happens during interrupt
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Best-effort flush — clears anything in-flight inside the source's queue.
|
|
43
|
+
*
|
|
44
|
+
* @livekit/rtc-node's AudioSource exposes `clearQueue()` in newer versions.
|
|
45
|
+
* We optionally call it; falls back to a noop when unavailable.
|
|
46
|
+
*/
|
|
47
|
+
async flush() {
|
|
48
|
+
const maybeClear = this.source.clearQueue;
|
|
49
|
+
if (typeof maybeClear === 'function') {
|
|
50
|
+
try {
|
|
51
|
+
await Promise.resolve(maybeClear.call(this.source));
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
log.debug('agent_audio_flush_failed', {
|
|
55
|
+
message: error instanceof Error ? error.message : String(error),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async close() {
|
|
61
|
+
try {
|
|
62
|
+
await this.source.close();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// ignore
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/audio/source.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG/G,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,MAAM,UAAU,GAAG,sBAAsB,CAAC;AAE1C,MAAM,OAAO,mBAAmB;IACtB,MAAM,CAAc;IACpB,KAAK,CAAkB;IACvB,SAAS,GAAG,KAAK,CAAC;IAE1B,YAAY,UAAkB,EAAE,WAAmB;QACjD,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAU;QACtB,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,mBAAmB,EAAE,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,iBAAiB,CAAC;QAC5C,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,KAAe;QAC7B,MAAM,iBAAiB,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;QACnE,MAAM,UAAU,GAAG,IAAI,UAAU,CAC/B,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,WAAW,EACjB,iBAAiB,CAClB,CAAC;QACF,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,oCAAoC;QACtC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,UAAU,GAAI,IAAI,CAAC,MAAiE,CAAC,UAAU,CAAC;QACtG,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACtD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,KAAK,CAAC,0BAA0B,EAAE;oBACpC,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;iBAChE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;CACF"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file Bridge CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Pair flow:
|
|
6
|
+
* 1. Read pair code (CLI arg / env / interactive prompt).
|
|
7
|
+
* 2. Discover capabilities for the selected backend.
|
|
8
|
+
* 3. POST capabilities + code → /api/bridge/pair to get LiveKit credentials.
|
|
9
|
+
* 4. Start the room runtime.
|
|
10
|
+
* 5. Handle SIGINT cleanly.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file Bridge CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Pair flow:
|
|
6
|
+
* 1. Read pair code (CLI arg / env / interactive prompt).
|
|
7
|
+
* 2. Discover capabilities for the selected backend.
|
|
8
|
+
* 3. POST capabilities + code → /api/bridge/pair to get LiveKit credentials.
|
|
9
|
+
* 4. Start the room runtime.
|
|
10
|
+
* 5. Handle SIGINT cleanly.
|
|
11
|
+
*/
|
|
12
|
+
import { Command } from 'commander';
|
|
13
|
+
import { dispose } from '@livekit/rtc-node';
|
|
14
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
15
|
+
import { dirname, join } from 'node:path';
|
|
16
|
+
import { stdin as input, stdout as output } from 'node:process';
|
|
17
|
+
import { createInterface } from 'node:readline/promises';
|
|
18
|
+
import { buildBridgeConfig } from './config.js';
|
|
19
|
+
import { createDriver } from './drivers/index.js';
|
|
20
|
+
import { exchangePairCode } from './pair.js';
|
|
21
|
+
import { PermissionBroker } from './permissions.js';
|
|
22
|
+
import { BridgeRoomRuntime } from './room.js';
|
|
23
|
+
import { log, setLogLevel } from './logging.js';
|
|
24
|
+
/**
|
|
25
|
+
* Loads `.env.local` (or `.env`) from the bridge's cwd, walking up one
|
|
26
|
+
* directory at a time until it finds one or hits the filesystem root.
|
|
27
|
+
*
|
|
28
|
+
* Designed so a host who keeps secrets in the VoxAgent repo's
|
|
29
|
+
* `.env.local` (Next.js convention) gets the same env in the bridge
|
|
30
|
+
* process without having to `source` the file by hand. Existing
|
|
31
|
+
* environment values win — sourced files don't override what the user
|
|
32
|
+
* already exported.
|
|
33
|
+
*/
|
|
34
|
+
function loadDotenv() {
|
|
35
|
+
const filenames = ['.env.local', '.env'];
|
|
36
|
+
let dir = process.cwd();
|
|
37
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
38
|
+
for (const name of filenames) {
|
|
39
|
+
const path = join(dir, name);
|
|
40
|
+
if (existsSync(path)) {
|
|
41
|
+
try {
|
|
42
|
+
const text = readFileSync(path, 'utf-8');
|
|
43
|
+
for (const line of text.split('\n')) {
|
|
44
|
+
const trimmed = line.trim();
|
|
45
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
46
|
+
continue;
|
|
47
|
+
const eq = trimmed.indexOf('=');
|
|
48
|
+
if (eq < 0)
|
|
49
|
+
continue;
|
|
50
|
+
const key = trimmed.slice(0, eq).trim();
|
|
51
|
+
if (!key || key in process.env)
|
|
52
|
+
continue;
|
|
53
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
54
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
55
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
56
|
+
value = value.slice(1, -1);
|
|
57
|
+
}
|
|
58
|
+
process.env[key] = value;
|
|
59
|
+
}
|
|
60
|
+
return { loaded: path };
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// ignore — fall through to next candidate
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const parent = dirname(dir);
|
|
68
|
+
if (parent === dir)
|
|
69
|
+
break;
|
|
70
|
+
dir = parent;
|
|
71
|
+
}
|
|
72
|
+
return { loaded: null };
|
|
73
|
+
}
|
|
74
|
+
async function main() {
|
|
75
|
+
const dotenv = loadDotenv();
|
|
76
|
+
if (dotenv.loaded) {
|
|
77
|
+
log.info('bridge_dotenv_loaded', { path: dotenv.loaded });
|
|
78
|
+
}
|
|
79
|
+
const program = new Command();
|
|
80
|
+
// pnpm and some script runners forward a literal `--` separator into argv.
|
|
81
|
+
// Commander treats `--` as end-of-options, so stripping it lets users invoke
|
|
82
|
+
// either `pnpm ... dev -- --code 123` or `pnpm ... dev --code 123` reliably.
|
|
83
|
+
const cleanedArgv = process.argv.filter((arg, index) => !(index >= 2 && arg === '--'));
|
|
84
|
+
program
|
|
85
|
+
.name('voxagent-bridge')
|
|
86
|
+
.description('Pair the host\'s local Claude Code or Codex agent with a VoxAgent meeting.')
|
|
87
|
+
.option('-c, --code <CODE>', '6-digit pair code shown in the meeting room')
|
|
88
|
+
.option('-u, --api-url <URL>', 'VoxAgent web app base URL (default: http://localhost:3000)')
|
|
89
|
+
.option('-a, --agent <BACKEND>', 'Agent backend: claude | codex')
|
|
90
|
+
.option('--cwd <PATH>', 'Working directory the agent should run in (default: cwd)')
|
|
91
|
+
.option('--tts <PROVIDER>', 'TTS provider: elevenlabs (default) | openai (uses OPENAI_API_KEY)')
|
|
92
|
+
.option('--voice <VOICE_ID>', 'Voice ID — ElevenLabs voice ID, or OpenAI voice name (alloy, nova, shimmer, ...)')
|
|
93
|
+
.option('--model <MODEL_ID>', 'TTS model — ElevenLabs model ID, or OpenAI tts-1 / tts-1-hd / gpt-4o-mini-tts')
|
|
94
|
+
.option('--audio-format <FORMAT>', 'ElevenLabs PCM format: pcm_16000 (default, Starter+) | pcm_22050 (Creator+) | pcm_24000 (Pro+) | pcm_44100 (Pro+)')
|
|
95
|
+
.option('--text-only', 'Skip TTS — for environments without ElevenLabs credentials')
|
|
96
|
+
.option('--llm-model <ID>', 'Agent LLM model (e.g. claude-opus-4-7, claude-sonnet-4-6, gpt-5-codex)')
|
|
97
|
+
.option('--full-access', 'Disable the workspace sandbox so the agent can read/write anywhere on this machine')
|
|
98
|
+
.option('-v, --verbose', 'Enable debug logging')
|
|
99
|
+
.parse(cleanedArgv);
|
|
100
|
+
const flags = program.opts();
|
|
101
|
+
if (flags.verbose)
|
|
102
|
+
setLogLevel('debug');
|
|
103
|
+
if (!flags.code) {
|
|
104
|
+
const envCode = process.env.VOXAGENT_PAIR_CODE;
|
|
105
|
+
if (!envCode) {
|
|
106
|
+
const rl = createInterface({ input, output });
|
|
107
|
+
const entered = (await rl.question('Pair code: ')).trim();
|
|
108
|
+
rl.close();
|
|
109
|
+
flags.code = entered;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const config = buildBridgeConfig(flags);
|
|
113
|
+
log.info('bridge_config_resolved', {
|
|
114
|
+
backend: config.backend,
|
|
115
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
116
|
+
cwd: config.cwd,
|
|
117
|
+
llmModel: config.llmModel,
|
|
118
|
+
fullAccess: config.fullAccess,
|
|
119
|
+
textOnly: config.textOnly,
|
|
120
|
+
});
|
|
121
|
+
const permissionBroker = new PermissionBroker({
|
|
122
|
+
workspaceCwd: config.cwd,
|
|
123
|
+
fullAccess: config.fullAccess,
|
|
124
|
+
});
|
|
125
|
+
const driver = createDriver(config.backend, {
|
|
126
|
+
...(config.llmModel ? { model: config.llmModel } : {}),
|
|
127
|
+
fullAccess: config.fullAccess,
|
|
128
|
+
permissionResolver: permissionBroker,
|
|
129
|
+
});
|
|
130
|
+
const capabilities = await driver.capabilities(config.cwd);
|
|
131
|
+
log.info('bridge_capabilities', {
|
|
132
|
+
backend: capabilities.backend,
|
|
133
|
+
skills: capabilities.skills.length,
|
|
134
|
+
plugins: capabilities.plugins.length,
|
|
135
|
+
mcpServers: capabilities.mcpServers.length,
|
|
136
|
+
});
|
|
137
|
+
log.info('bridge_pairing', { apiBaseUrl: config.apiBaseUrl });
|
|
138
|
+
const pair = await exchangePairCode({
|
|
139
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
140
|
+
pairCode: config.pairCode,
|
|
141
|
+
capabilities,
|
|
142
|
+
});
|
|
143
|
+
log.info('bridge_paired', { roomId: pair.roomId, roomName: pair.roomName, hostName: pair.hostName });
|
|
144
|
+
const runtime = new BridgeRoomRuntime({ config, pair, driver, capabilities, permissionBroker });
|
|
145
|
+
await runtime.start();
|
|
146
|
+
log.info('bridge_ready');
|
|
147
|
+
const shutdown = async (signal) => {
|
|
148
|
+
log.info('bridge_shutdown_signal', { signal });
|
|
149
|
+
try {
|
|
150
|
+
await runtime.shutdown('shutdown');
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
try {
|
|
154
|
+
await dispose();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// ignore
|
|
158
|
+
}
|
|
159
|
+
process.exit(0);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
process.once('SIGINT', () => void shutdown('SIGINT'));
|
|
163
|
+
process.once('SIGTERM', () => void shutdown('SIGTERM'));
|
|
164
|
+
}
|
|
165
|
+
main().catch((error) => {
|
|
166
|
+
log.error('bridge_fatal', {
|
|
167
|
+
message: error instanceof Error ? error.message : String(error),
|
|
168
|
+
});
|
|
169
|
+
process.exitCode = 1;
|
|
170
|
+
});
|
|
171
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Bridge runtime configuration resolved from CLI args + environment.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentBackend } from './protocol.js';
|
|
5
|
+
import type { ElevenLabsAudioFormat, TtsProvider } from './tts/index.js';
|
|
6
|
+
export interface BridgeConfig {
|
|
7
|
+
/** VoxAgent web app base URL — where the pair endpoint lives. */
|
|
8
|
+
apiBaseUrl: string;
|
|
9
|
+
/** 6-digit pair code obtained from the host's browser. */
|
|
10
|
+
pairCode: string;
|
|
11
|
+
/** Agent backend driver selection. */
|
|
12
|
+
backend: AgentBackend;
|
|
13
|
+
/** Working directory the agent will operate inside. */
|
|
14
|
+
cwd: string;
|
|
15
|
+
/** TTS provider selection. */
|
|
16
|
+
ttsProvider: TtsProvider;
|
|
17
|
+
/** ElevenLabs API key (required for ElevenLabs provider). */
|
|
18
|
+
elevenLabsApiKey: string | null;
|
|
19
|
+
/** OpenAI API key (required for OpenAI provider). */
|
|
20
|
+
openAiApiKey: string | null;
|
|
21
|
+
/** Voice ID — ElevenLabs voice ID or OpenAI voice name (alloy, nova, etc.). */
|
|
22
|
+
ttsVoiceId: string;
|
|
23
|
+
/** Model ID — ElevenLabs model ID or OpenAI TTS model (tts-1, tts-1-hd, gpt-4o-mini-tts). */
|
|
24
|
+
ttsModelId: string;
|
|
25
|
+
/**
|
|
26
|
+
* ElevenLabs output format. Defaults to `pcm_16000` (Starter+ tier);
|
|
27
|
+
* upgrade to `pcm_22050` (Creator+) or `pcm_44100` (Pro+) if your
|
|
28
|
+
* subscription tier allows. Ignored for the OpenAI provider.
|
|
29
|
+
*/
|
|
30
|
+
elevenLabsAudioFormat: ElevenLabsAudioFormat;
|
|
31
|
+
/** When set, skip TTS entirely (text-only mode). */
|
|
32
|
+
textOnly: boolean;
|
|
33
|
+
/** LLM model override for the agent backend. */
|
|
34
|
+
llmModel: string | null;
|
|
35
|
+
/**
|
|
36
|
+
* When true, the agent runs without its native workspace sandbox
|
|
37
|
+
* (Codex `--dangerously-bypass-approvals-and-sandbox`, Claude
|
|
38
|
+
* `permissionMode: bypassPermissions`). Default is false — agents stay
|
|
39
|
+
* within their workspace.
|
|
40
|
+
*/
|
|
41
|
+
fullAccess: boolean;
|
|
42
|
+
}
|
|
43
|
+
interface CliFlags {
|
|
44
|
+
code?: string;
|
|
45
|
+
apiUrl?: string;
|
|
46
|
+
agent?: string;
|
|
47
|
+
cwd?: string;
|
|
48
|
+
voice?: string;
|
|
49
|
+
model?: string;
|
|
50
|
+
llmModel?: string;
|
|
51
|
+
audioFormat?: string;
|
|
52
|
+
textOnly?: boolean;
|
|
53
|
+
fullAccess?: boolean;
|
|
54
|
+
tts?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Detects which CLI agent is available on PATH so `--agent` can default sensibly.
|
|
58
|
+
*/
|
|
59
|
+
export declare function autoDetectBackend(): AgentBackend;
|
|
60
|
+
export declare function buildBridgeConfig(flags: CliFlags): BridgeConfig;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEzE,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,OAAO,EAAE,YAAY,CAAC;IACtB,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,8BAA8B;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,6DAA6D;IAC7D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,qDAAqD;IACrD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;IAClB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAiBD,UAAU,QAAQ;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,YAAY,CAMhD;AAoCD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,GAAG,YAAY,CAsD/D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Bridge runtime configuration resolved from CLI args + environment.
|
|
3
|
+
*/
|
|
4
|
+
const DEFAULT_API_BASE_URL = 'http://localhost:3000';
|
|
5
|
+
const DEFAULT_ELEVENLABS_VOICE_ID = '21m00Tcm4TlvDq8ikWAM'; // Rachel
|
|
6
|
+
const DEFAULT_ELEVENLABS_MODEL_ID = 'eleven_turbo_v2_5';
|
|
7
|
+
const DEFAULT_OPENAI_VOICE = 'alloy';
|
|
8
|
+
const DEFAULT_OPENAI_MODEL = 'tts-1';
|
|
9
|
+
const DEFAULT_TTS_PROVIDER = 'elevenlabs';
|
|
10
|
+
const VALID_TTS_PROVIDERS = new Set(['elevenlabs', 'openai']);
|
|
11
|
+
const DEFAULT_AUDIO_FORMAT = 'pcm_16000';
|
|
12
|
+
const VALID_AUDIO_FORMATS = new Set([
|
|
13
|
+
'pcm_16000',
|
|
14
|
+
'pcm_22050',
|
|
15
|
+
'pcm_24000',
|
|
16
|
+
'pcm_44100',
|
|
17
|
+
]);
|
|
18
|
+
/**
|
|
19
|
+
* Detects which CLI agent is available on PATH so `--agent` can default sensibly.
|
|
20
|
+
*/
|
|
21
|
+
export function autoDetectBackend() {
|
|
22
|
+
// Defer to env if user prefers one but didn't pass --agent
|
|
23
|
+
const envBackend = process.env.VOXAGENT_AGENT?.toLowerCase();
|
|
24
|
+
if (envBackend === 'claude' || envBackend === 'codex')
|
|
25
|
+
return envBackend;
|
|
26
|
+
// Default to claude — Anthropic SDK is bundled.
|
|
27
|
+
return 'claude';
|
|
28
|
+
}
|
|
29
|
+
function resolveTtsProvider(raw) {
|
|
30
|
+
if (!raw)
|
|
31
|
+
return DEFAULT_TTS_PROVIDER;
|
|
32
|
+
const normalized = raw.trim().toLowerCase();
|
|
33
|
+
if (VALID_TTS_PROVIDERS.has(normalized))
|
|
34
|
+
return normalized;
|
|
35
|
+
throw new Error(`Unknown --tts "${raw}". Use "elevenlabs" or "openai".`);
|
|
36
|
+
}
|
|
37
|
+
function resolveAudioFormat(raw) {
|
|
38
|
+
if (!raw)
|
|
39
|
+
return DEFAULT_AUDIO_FORMAT;
|
|
40
|
+
const normalized = raw.trim().toLowerCase();
|
|
41
|
+
if (VALID_AUDIO_FORMATS.has(normalized)) {
|
|
42
|
+
return normalized;
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`Unknown --audio-format "${raw}". Use one of: pcm_16000, pcm_22050, pcm_24000, pcm_44100.`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Strips a single matching pair of surrounding quotes from a path. Useful when
|
|
48
|
+
* shell-quoting leaks through (e.g. macOS "Copy as Pathname" wraps paths with
|
|
49
|
+
* spaces in single quotes) or when a user pastes `'$HOME/proj'` literally.
|
|
50
|
+
*/
|
|
51
|
+
function unquotePath(value) {
|
|
52
|
+
const trimmed = value.trim();
|
|
53
|
+
if (trimmed.length < 2)
|
|
54
|
+
return trimmed;
|
|
55
|
+
const first = trimmed[0];
|
|
56
|
+
const last = trimmed[trimmed.length - 1];
|
|
57
|
+
if ((first === "'" && last === "'") || (first === '"' && last === '"')) {
|
|
58
|
+
return trimmed.slice(1, -1);
|
|
59
|
+
}
|
|
60
|
+
return trimmed;
|
|
61
|
+
}
|
|
62
|
+
export function buildBridgeConfig(flags) {
|
|
63
|
+
const pairCode = (flags.code ?? process.env.VOXAGENT_PAIR_CODE ?? '').trim();
|
|
64
|
+
if (!pairCode) {
|
|
65
|
+
throw new Error('A pair code is required. Pass --code <CODE> or set VOXAGENT_PAIR_CODE.');
|
|
66
|
+
}
|
|
67
|
+
const requestedBackend = (flags.agent ?? process.env.VOXAGENT_AGENT ?? '').toLowerCase();
|
|
68
|
+
let backend;
|
|
69
|
+
if (requestedBackend === 'claude' || requestedBackend === 'codex') {
|
|
70
|
+
backend = requestedBackend;
|
|
71
|
+
}
|
|
72
|
+
else if (requestedBackend === '') {
|
|
73
|
+
backend = autoDetectBackend();
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
throw new Error(`Unknown --agent "${requestedBackend}". Use "claude" or "codex".`);
|
|
77
|
+
}
|
|
78
|
+
const apiBaseUrl = (flags.apiUrl ??
|
|
79
|
+
process.env.VOXAGENT_API_URL ??
|
|
80
|
+
DEFAULT_API_BASE_URL).replace(/\/+$/, '');
|
|
81
|
+
const rawCwd = flags.cwd ?? process.env.VOXAGENT_CWD;
|
|
82
|
+
const cwd = rawCwd ? unquotePath(rawCwd) : process.cwd();
|
|
83
|
+
const ttsProvider = resolveTtsProvider(flags.tts ?? process.env.VOXAGENT_TTS);
|
|
84
|
+
const providerVoiceDefault = ttsProvider === 'openai' ? DEFAULT_OPENAI_VOICE : DEFAULT_ELEVENLABS_VOICE_ID;
|
|
85
|
+
const providerModelDefault = ttsProvider === 'openai' ? DEFAULT_OPENAI_MODEL : DEFAULT_ELEVENLABS_MODEL_ID;
|
|
86
|
+
return {
|
|
87
|
+
apiBaseUrl,
|
|
88
|
+
pairCode,
|
|
89
|
+
backend,
|
|
90
|
+
cwd,
|
|
91
|
+
ttsProvider,
|
|
92
|
+
elevenLabsApiKey: process.env.VOXAGENT_ELEVENLABS_API_KEY ?? process.env.ELEVENLABS_API_KEY ?? null,
|
|
93
|
+
openAiApiKey: process.env.VOXAGENT_OPENAI_API_KEY ?? process.env.OPENAI_API_KEY ?? null,
|
|
94
|
+
ttsVoiceId: flags.voice ?? process.env.VOXAGENT_VOICE_ID ?? providerVoiceDefault,
|
|
95
|
+
ttsModelId: flags.model ?? process.env.VOXAGENT_MODEL_ID ?? providerModelDefault,
|
|
96
|
+
elevenLabsAudioFormat: resolveAudioFormat(flags.audioFormat ?? process.env.VOXAGENT_AUDIO_FORMAT),
|
|
97
|
+
textOnly: flags.textOnly === true || process.env.VOXAGENT_TEXT_ONLY === '1',
|
|
98
|
+
llmModel: (flags.llmModel ?? process.env.VOXAGENT_LLM_MODEL ?? '').trim() || null,
|
|
99
|
+
fullAccess: flags.fullAccess === true || process.env.VOXAGENT_FULL_ACCESS === '1',
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Claude Code driver — drives `@anthropic-ai/claude-agent-sdk`.
|
|
3
|
+
*
|
|
4
|
+
* Translates the SDK's `SDKMessage` and `SDKStreamEvent` outputs into our
|
|
5
|
+
* normalized `DriverEvent` stream.
|
|
6
|
+
*
|
|
7
|
+
* Streaming details (per SDK reference):
|
|
8
|
+
* - With `includePartialMessages: true`, every Anthropic API event is
|
|
9
|
+
* emitted as a `stream_event` SDKMessage.
|
|
10
|
+
* - Text deltas: `content_block_delta` with `delta.type === 'text_delta'`.
|
|
11
|
+
* - Tool start: `content_block_start` where `content_block.type === 'tool_use'`.
|
|
12
|
+
* - Tool input streaming: `content_block_delta` with `input_json_delta`.
|
|
13
|
+
* - Tool end: `content_block_stop`.
|
|
14
|
+
* - Tool results / progress: surface via `user` messages with tool_result
|
|
15
|
+
* blocks (post-execution); we use these to flag success/error + payload.
|
|
16
|
+
* - Run end: `result` SDKMessage; subtype `success` / `error_*` / `interrupted`.
|
|
17
|
+
*/
|
|
18
|
+
import type { CapabilitiesInfo } from '../protocol.js';
|
|
19
|
+
import type { DriverOptions } from './index.js';
|
|
20
|
+
import type { AgentDriver, DriverEvent, DriverRunInput } from './types.js';
|
|
21
|
+
export declare class ClaudeDriver implements AgentDriver {
|
|
22
|
+
private readonly options;
|
|
23
|
+
readonly backend: "claude";
|
|
24
|
+
/** Most recent Claude Code session ID, used to keep room context across turns. */
|
|
25
|
+
private sessionId;
|
|
26
|
+
/** Currently active query handle, used for `interrupt()`. */
|
|
27
|
+
private activeQuery;
|
|
28
|
+
constructor(options?: DriverOptions);
|
|
29
|
+
capabilities(cwd: string): Promise<CapabilitiesInfo>;
|
|
30
|
+
run(input: DriverRunInput, signal: AbortSignal): AsyncIterable<DriverEvent>;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
private discoverSkills;
|
|
33
|
+
private discoverPlugins;
|
|
34
|
+
private discoverMcpServers;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/drivers/claude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAiB3E,qBAAa,YAAa,YAAW,WAAW;IASlC,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,QAAQ,CAAC,OAAO,EAAG,QAAQ,CAAU;IAErC,kFAAkF;IAClF,OAAO,CAAC,SAAS,CAAuB;IAExC,6DAA6D;IAC7D,OAAO,CAAC,WAAW,CAAsB;gBAEZ,OAAO,GAAE,aAAkB;IAElD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiBnD,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC;IAwM5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAWd,cAAc;YA4Bd,eAAe;YAiBf,kBAAkB;CAajC"}
|