@electric-agent/studio 1.7.0 → 1.12.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.
Files changed (105) hide show
  1. package/dist/api-schemas.d.ts +225 -0
  2. package/dist/api-schemas.d.ts.map +1 -0
  3. package/dist/api-schemas.js +95 -0
  4. package/dist/api-schemas.js.map +1 -0
  5. package/dist/bridge/claude-code-base.d.ts +121 -0
  6. package/dist/bridge/claude-code-base.d.ts.map +1 -0
  7. package/dist/bridge/claude-code-base.js +263 -0
  8. package/dist/bridge/claude-code-base.js.map +1 -0
  9. package/dist/bridge/claude-code-docker.d.ts +13 -73
  10. package/dist/bridge/claude-code-docker.d.ts.map +1 -1
  11. package/dist/bridge/claude-code-docker.js +91 -302
  12. package/dist/bridge/claude-code-docker.js.map +1 -1
  13. package/dist/bridge/claude-code-sprites.d.ts +12 -59
  14. package/dist/bridge/claude-code-sprites.d.ts.map +1 -1
  15. package/dist/bridge/claude-code-sprites.js +88 -281
  16. package/dist/bridge/claude-code-sprites.js.map +1 -1
  17. package/dist/bridge/claude-md-generator.d.ts +10 -1
  18. package/dist/bridge/claude-md-generator.d.ts.map +1 -1
  19. package/dist/bridge/claude-md-generator.js +47 -98
  20. package/dist/bridge/claude-md-generator.js.map +1 -1
  21. package/dist/bridge/codex-docker.d.ts +56 -51
  22. package/dist/bridge/codex-docker.js +222 -230
  23. package/dist/bridge/codex-json-parser.d.ts +11 -11
  24. package/dist/bridge/codex-json-parser.js +231 -238
  25. package/dist/bridge/codex-md-generator.d.ts +3 -3
  26. package/dist/bridge/codex-md-generator.js +42 -32
  27. package/dist/bridge/codex-sprites.d.ts +50 -45
  28. package/dist/bridge/codex-sprites.js +212 -222
  29. package/dist/bridge/daytona.d.ts +25 -25
  30. package/dist/bridge/daytona.js +131 -136
  31. package/dist/bridge/docker-stdio.d.ts +21 -21
  32. package/dist/bridge/docker-stdio.js +126 -132
  33. package/dist/bridge/hosted.d.ts +3 -2
  34. package/dist/bridge/hosted.d.ts.map +1 -1
  35. package/dist/bridge/hosted.js +4 -0
  36. package/dist/bridge/hosted.js.map +1 -1
  37. package/dist/bridge/message-parser.d.ts +24 -0
  38. package/dist/bridge/message-parser.d.ts.map +1 -0
  39. package/dist/bridge/message-parser.js +39 -0
  40. package/dist/bridge/message-parser.js.map +1 -0
  41. package/dist/bridge/role-skills.d.ts +25 -0
  42. package/dist/bridge/role-skills.d.ts.map +1 -0
  43. package/dist/bridge/role-skills.js +120 -0
  44. package/dist/bridge/role-skills.js.map +1 -0
  45. package/dist/bridge/room-messaging-skill.d.ts +11 -0
  46. package/dist/bridge/room-messaging-skill.d.ts.map +1 -0
  47. package/dist/bridge/room-messaging-skill.js +41 -0
  48. package/dist/bridge/room-messaging-skill.js.map +1 -0
  49. package/dist/bridge/sprites.d.ts +22 -22
  50. package/dist/bridge/sprites.js +123 -128
  51. package/dist/bridge/types.d.ts +4 -10
  52. package/dist/bridge/types.d.ts.map +1 -1
  53. package/dist/client/assets/index-BfvQSMwH.css +1 -0
  54. package/dist/client/assets/index-CiwD5LkP.js +235 -0
  55. package/dist/client/index.html +2 -2
  56. package/dist/index.d.ts +4 -3
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +3 -3
  59. package/dist/index.js.map +1 -1
  60. package/dist/invite-code.d.ts +5 -0
  61. package/dist/invite-code.d.ts.map +1 -0
  62. package/dist/invite-code.js +14 -0
  63. package/dist/invite-code.js.map +1 -0
  64. package/dist/project-utils.d.ts.map +1 -1
  65. package/dist/project-utils.js.map +1 -1
  66. package/dist/registry.d.ts +11 -4
  67. package/dist/registry.d.ts.map +1 -1
  68. package/dist/registry.js +1 -1
  69. package/dist/registry.js.map +1 -1
  70. package/dist/room-router.d.ts +73 -0
  71. package/dist/room-router.d.ts.map +1 -0
  72. package/dist/room-router.js +345 -0
  73. package/dist/room-router.js.map +1 -0
  74. package/dist/sandbox/docker.d.ts.map +1 -1
  75. package/dist/sandbox/docker.js +5 -6
  76. package/dist/sandbox/docker.js.map +1 -1
  77. package/dist/sandbox/index.d.ts +0 -1
  78. package/dist/sandbox/index.d.ts.map +1 -1
  79. package/dist/sandbox/index.js +0 -1
  80. package/dist/sandbox/index.js.map +1 -1
  81. package/dist/sandbox/sprites.d.ts.map +1 -1
  82. package/dist/sandbox/sprites.js +40 -10
  83. package/dist/sandbox/sprites.js.map +1 -1
  84. package/dist/sandbox/types.d.ts +4 -2
  85. package/dist/sandbox/types.d.ts.map +1 -1
  86. package/dist/server.d.ts +12 -0
  87. package/dist/server.d.ts.map +1 -1
  88. package/dist/server.js +761 -346
  89. package/dist/server.js.map +1 -1
  90. package/dist/session-auth.d.ts +9 -0
  91. package/dist/session-auth.d.ts.map +1 -1
  92. package/dist/session-auth.js +30 -0
  93. package/dist/session-auth.js.map +1 -1
  94. package/dist/sessions.d.ts +1 -1
  95. package/dist/streams.d.ts +2 -6
  96. package/dist/streams.d.ts.map +1 -1
  97. package/dist/streams.js +6 -17
  98. package/dist/streams.js.map +1 -1
  99. package/dist/validate.d.ts +10 -0
  100. package/dist/validate.d.ts.map +1 -0
  101. package/dist/validate.js +24 -0
  102. package/dist/validate.js.map +1 -0
  103. package/package.json +6 -9
  104. package/dist/client/assets/index-D5-jqAV-.js +0 -234
  105. package/dist/client/assets/index-YyyiO26y.css +0 -1
@@ -6,141 +6,136 @@
6
6
  * the Daytona session (for agent communication). The agent inside the
7
7
  * sandbox uses the stdio adapter — no outbound internet required.
8
8
  */
9
- import { DurableStream } from "@durable-streams/client";
10
- const DAYTONA_SESSION_ID = "agent-session";
9
+ import { DurableStream } from "@durable-streams/client"
10
+
11
+ const DAYTONA_SESSION_ID = "agent-session"
11
12
  export class DaytonaSessionBridge {
12
- sessionId;
13
- streamUrl;
14
- streamHeaders;
15
- sandbox;
16
- writer;
17
- agentEventCallbacks = [];
18
- completeCallbacks = [];
19
- closed = false;
20
- cmdId = null;
21
- stdoutBuffer = "";
22
- constructor(sessionId, connection, sandbox) {
23
- this.sessionId = sessionId;
24
- this.streamUrl = connection.url;
25
- this.streamHeaders = connection.headers;
26
- this.sandbox = sandbox;
27
- this.writer = new DurableStream({
28
- url: connection.url,
29
- headers: connection.headers,
30
- contentType: "application/json",
31
- });
32
- }
33
- async emit(event) {
34
- if (this.closed)
35
- return;
36
- const msg = { source: "server", ...event };
37
- await this.writer.append(JSON.stringify(msg));
38
- }
39
- async sendCommand(cmd) {
40
- if (this.closed || !this.cmdId)
41
- return;
42
- const line = JSON.stringify({ type: "command", ...cmd });
43
- await this.sandbox.process.sendSessionCommandInput(DAYTONA_SESSION_ID, this.cmdId, `${line}\n`);
44
- }
45
- async sendGateResponse(gate, value) {
46
- if (this.closed || !this.cmdId)
47
- return;
48
- const line = JSON.stringify({ type: "gate_response", gate, ...value });
49
- await this.sandbox.process.sendSessionCommandInput(DAYTONA_SESSION_ID, this.cmdId, `${line}\n`);
50
- }
51
- onAgentEvent(cb) {
52
- this.agentEventCallbacks.push(cb);
53
- }
54
- onComplete(cb) {
55
- this.completeCallbacks.push(cb);
56
- }
57
- async start() {
58
- if (this.closed)
59
- return;
60
- // Create a persistent session in the sandbox
61
- await this.sandbox.process.createSession(DAYTONA_SESSION_ID);
62
- // Start the headless agent asynchronously
63
- const response = await this.sandbox.process.executeSessionCommand(DAYTONA_SESSION_ID, {
64
- command: "electric-agent headless",
65
- runAsync: true,
66
- });
67
- this.cmdId = response.cmdId ?? null;
68
- if (!this.cmdId) {
69
- throw new Error("Failed to get command ID from Daytona session");
70
- }
71
- console.log(`[daytona-bridge] Agent started: session=${this.sessionId} cmdId=${this.cmdId}`);
72
- // Stream stdout output via log polling
73
- this.pollLogs().catch((err) => {
74
- if (!this.closed) {
75
- console.error(`[daytona-bridge] Log streaming error:`, err);
76
- }
77
- });
78
- }
79
- async pollLogs() {
80
- if (!this.cmdId)
81
- return;
82
- try {
83
- await this.sandbox.process.getSessionCommandLogs(DAYTONA_SESSION_ID, this.cmdId, (chunk) => this.handleStdout(chunk), (chunk) => {
84
- if (!this.closed) {
85
- process.stderr.write(`[daytona-bridge:stderr] ${chunk}`);
86
- }
87
- });
88
- }
89
- catch (err) {
90
- if (!this.closed) {
91
- console.error(`[daytona-bridge] getSessionCommandLogs error:`, err);
92
- }
93
- }
94
- }
95
- handleStdout(chunk) {
96
- if (this.closed)
97
- return;
98
- // Buffer partial lines
99
- this.stdoutBuffer += chunk;
100
- const lines = this.stdoutBuffer.split("\n");
101
- // Keep the last (possibly incomplete) line in the buffer
102
- this.stdoutBuffer = lines.pop() ?? "";
103
- for (const line of lines) {
104
- const trimmed = line.trim();
105
- if (!trimmed)
106
- continue;
107
- let event;
108
- try {
109
- event = JSON.parse(trimmed);
110
- }
111
- catch {
112
- // Not valid JSON log as diagnostic
113
- console.log(`[daytona-bridge] Non-JSON stdout: ${trimmed}`);
114
- continue;
115
- }
116
- // Write to Durable Stream for UI
117
- const msg = { source: "agent", ...event };
118
- this.writer.append(JSON.stringify(msg)).catch(() => { });
119
- // Dispatch to callbacks
120
- for (const cb of this.agentEventCallbacks) {
121
- try {
122
- cb(event);
123
- }
124
- catch {
125
- // Swallow callback errors
126
- }
127
- }
128
- // Detect session_end
129
- if (event.type === "session_end" && "success" in event) {
130
- const success = event.success;
131
- for (const cb of this.completeCallbacks) {
132
- try {
133
- cb(success);
134
- }
135
- catch {
136
- // Swallow callback errors
137
- }
138
- }
139
- }
140
- }
141
- }
142
- close() {
143
- this.closed = true;
144
- }
13
+ sessionId
14
+ streamUrl
15
+ streamHeaders
16
+ sandbox
17
+ writer
18
+ agentEventCallbacks = []
19
+ completeCallbacks = []
20
+ closed = false
21
+ cmdId = null
22
+ stdoutBuffer = ""
23
+ constructor(sessionId, connection, sandbox) {
24
+ this.sessionId = sessionId
25
+ this.streamUrl = connection.url
26
+ this.streamHeaders = connection.headers
27
+ this.sandbox = sandbox
28
+ this.writer = new DurableStream({
29
+ url: connection.url,
30
+ headers: connection.headers,
31
+ contentType: "application/json",
32
+ })
33
+ }
34
+ async emit(event) {
35
+ if (this.closed) return
36
+ const msg = { source: "server", ...event }
37
+ await this.writer.append(JSON.stringify(msg))
38
+ }
39
+ async sendCommand(cmd) {
40
+ if (this.closed || !this.cmdId) return
41
+ const line = JSON.stringify({ type: "command", ...cmd })
42
+ await this.sandbox.process.sendSessionCommandInput(DAYTONA_SESSION_ID, this.cmdId, `${line}\n`)
43
+ }
44
+ async sendGateResponse(gate, value) {
45
+ if (this.closed || !this.cmdId) return
46
+ const line = JSON.stringify({ type: "gate_response", gate, ...value })
47
+ await this.sandbox.process.sendSessionCommandInput(DAYTONA_SESSION_ID, this.cmdId, `${line}\n`)
48
+ }
49
+ onAgentEvent(cb) {
50
+ this.agentEventCallbacks.push(cb)
51
+ }
52
+ onComplete(cb) {
53
+ this.completeCallbacks.push(cb)
54
+ }
55
+ async start() {
56
+ if (this.closed) return
57
+ // Create a persistent session in the sandbox
58
+ await this.sandbox.process.createSession(DAYTONA_SESSION_ID)
59
+ // Start the headless agent asynchronously
60
+ const response = await this.sandbox.process.executeSessionCommand(DAYTONA_SESSION_ID, {
61
+ command: "electric-agent headless",
62
+ runAsync: true,
63
+ })
64
+ this.cmdId = response.cmdId ?? null
65
+ if (!this.cmdId) {
66
+ throw new Error("Failed to get command ID from Daytona session")
67
+ }
68
+ console.log(`[daytona-bridge] Agent started: session=${this.sessionId} cmdId=${this.cmdId}`)
69
+ // Stream stdout output via log polling
70
+ this.pollLogs().catch((err) => {
71
+ if (!this.closed) {
72
+ console.error(`[daytona-bridge] Log streaming error:`, err)
73
+ }
74
+ })
75
+ }
76
+ async pollLogs() {
77
+ if (!this.cmdId) return
78
+ try {
79
+ await this.sandbox.process.getSessionCommandLogs(
80
+ DAYTONA_SESSION_ID,
81
+ this.cmdId,
82
+ (chunk) => this.handleStdout(chunk),
83
+ (chunk) => {
84
+ if (!this.closed) {
85
+ process.stderr.write(`[daytona-bridge:stderr] ${chunk}`)
86
+ }
87
+ },
88
+ )
89
+ } catch (err) {
90
+ if (!this.closed) {
91
+ console.error(`[daytona-bridge] getSessionCommandLogs error:`, err)
92
+ }
93
+ }
94
+ }
95
+ handleStdout(chunk) {
96
+ if (this.closed) return
97
+ // Buffer partial lines
98
+ this.stdoutBuffer += chunk
99
+ const lines = this.stdoutBuffer.split("\n")
100
+ // Keep the last (possibly incomplete) line in the buffer
101
+ this.stdoutBuffer = lines.pop() ?? ""
102
+ for (const line of lines) {
103
+ const trimmed = line.trim()
104
+ if (!trimmed) continue
105
+ let event
106
+ try {
107
+ event = JSON.parse(trimmed)
108
+ } catch {
109
+ // Not valid JSON — log as diagnostic
110
+ console.log(`[daytona-bridge] Non-JSON stdout: ${trimmed}`)
111
+ continue
112
+ }
113
+ // Write to Durable Stream for UI
114
+ const msg = { source: "agent", ...event }
115
+ this.writer.append(JSON.stringify(msg)).catch(() => {})
116
+ // Dispatch to callbacks
117
+ for (const cb of this.agentEventCallbacks) {
118
+ try {
119
+ cb(event)
120
+ } catch {
121
+ // Swallow callback errors
122
+ }
123
+ }
124
+ // Detect session_end
125
+ if (event.type === "session_end" && "success" in event) {
126
+ const success = event.success
127
+ for (const cb of this.completeCallbacks) {
128
+ try {
129
+ cb(success)
130
+ } catch {
131
+ // Swallow callback errors
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ close() {
138
+ this.closed = true
139
+ }
145
140
  }
146
- //# sourceMappingURL=daytona.js.map
141
+ //# sourceMappingURL=daytona.js.map
@@ -5,26 +5,26 @@
5
5
  * The server bridges between the Durable Stream (for UI events) and
6
6
  * the container's stdin/stdout (for agent communication).
7
7
  */
8
- import type { EngineEvent } from "@electric-agent/protocol";
9
- import type { StreamConnectionInfo } from "../streams.js";
10
- import type { SessionBridge } from "./types.js";
8
+ import type { EngineEvent } from "@electric-agent/protocol"
9
+ import type { StreamConnectionInfo } from "../streams.js"
10
+ import type { SessionBridge } from "./types.js"
11
11
  export declare class DockerStdioBridge implements SessionBridge {
12
- readonly sessionId: string;
13
- readonly streamUrl: string;
14
- readonly streamHeaders: Record<string, string>;
15
- private containerId;
16
- private writer;
17
- private agentEventCallbacks;
18
- private completeCallbacks;
19
- private closed;
20
- private proc;
21
- constructor(sessionId: string, connection: StreamConnectionInfo, containerId: string);
22
- emit(event: EngineEvent): Promise<void>;
23
- sendCommand(cmd: Record<string, unknown>): Promise<void>;
24
- sendGateResponse(gate: string, value: Record<string, unknown>): Promise<void>;
25
- onAgentEvent(cb: (event: EngineEvent) => void): void;
26
- onComplete(cb: (success: boolean) => void): void;
27
- start(): Promise<void>;
28
- close(): void;
12
+ readonly sessionId: string
13
+ readonly streamUrl: string
14
+ readonly streamHeaders: Record<string, string>
15
+ private containerId
16
+ private writer
17
+ private agentEventCallbacks
18
+ private completeCallbacks
19
+ private closed
20
+ private proc
21
+ constructor(sessionId: string, connection: StreamConnectionInfo, containerId: string)
22
+ emit(event: EngineEvent): Promise<void>
23
+ sendCommand(cmd: Record<string, unknown>): Promise<void>
24
+ sendGateResponse(gate: string, value: Record<string, unknown>): Promise<void>
25
+ onAgentEvent(cb: (event: EngineEvent) => void): void
26
+ onComplete(cb: (success: boolean) => void): void
27
+ start(): Promise<void>
28
+ close(): void
29
29
  }
30
- //# sourceMappingURL=docker-stdio.d.ts.map
30
+ //# sourceMappingURL=docker-stdio.d.ts.map
@@ -5,137 +5,131 @@
5
5
  * The server bridges between the Durable Stream (for UI events) and
6
6
  * the container's stdin/stdout (for agent communication).
7
7
  */
8
- import { spawn } from "node:child_process";
9
- import * as readline from "node:readline";
10
- import { DurableStream } from "@durable-streams/client";
8
+ import { spawn } from "node:child_process"
9
+ import * as readline from "node:readline"
10
+ import { DurableStream } from "@durable-streams/client"
11
11
  export class DockerStdioBridge {
12
- sessionId;
13
- streamUrl;
14
- streamHeaders;
15
- containerId;
16
- writer;
17
- agentEventCallbacks = [];
18
- completeCallbacks = [];
19
- closed = false;
20
- proc = null;
21
- constructor(sessionId, connection, containerId) {
22
- this.sessionId = sessionId;
23
- this.streamUrl = connection.url;
24
- this.streamHeaders = connection.headers;
25
- this.containerId = containerId;
26
- this.writer = new DurableStream({
27
- url: connection.url,
28
- headers: connection.headers,
29
- contentType: "application/json",
30
- });
31
- }
32
- async emit(event) {
33
- if (this.closed)
34
- return;
35
- const msg = { source: "server", ...event };
36
- await this.writer.append(JSON.stringify(msg));
37
- }
38
- async sendCommand(cmd) {
39
- if (this.closed || !this.proc?.stdin?.writable)
40
- return;
41
- const line = JSON.stringify({ type: "command", ...cmd });
42
- this.proc.stdin.write(`${line}\n`);
43
- }
44
- async sendGateResponse(gate, value) {
45
- if (this.closed || !this.proc?.stdin?.writable)
46
- return;
47
- const line = JSON.stringify({ type: "gate_response", gate, ...value });
48
- this.proc.stdin.write(`${line}\n`);
49
- }
50
- onAgentEvent(cb) {
51
- this.agentEventCallbacks.push(cb);
52
- }
53
- onComplete(cb) {
54
- this.completeCallbacks.push(cb);
55
- }
56
- async start() {
57
- if (this.closed)
58
- return;
59
- // Spawn docker exec with stdin piped
60
- this.proc = spawn("docker", ["exec", "-i", this.containerId, "electric-agent", "headless"], {
61
- stdio: ["pipe", "pipe", "pipe"],
62
- });
63
- console.log(`[docker-stdio-bridge] Agent started: session=${this.sessionId} container=${this.containerId} pid=${this.proc.pid}`);
64
- // Read stdout line by line (NDJSON)
65
- if (this.proc.stdout) {
66
- const rl = readline.createInterface({
67
- input: this.proc.stdout,
68
- terminal: false,
69
- });
70
- rl.on("line", (line) => {
71
- if (this.closed)
72
- return;
73
- const trimmed = line.trim();
74
- if (!trimmed)
75
- return;
76
- let event;
77
- try {
78
- event = JSON.parse(trimmed);
79
- }
80
- catch {
81
- console.log(`[docker-stdio-bridge] Non-JSON stdout: ${trimmed}`);
82
- return;
83
- }
84
- // Write to Durable Stream for UI
85
- const msg = { source: "agent", ...event };
86
- this.writer.append(JSON.stringify(msg)).catch(() => { });
87
- // Dispatch to callbacks
88
- for (const cb of this.agentEventCallbacks) {
89
- try {
90
- cb(event);
91
- }
92
- catch {
93
- // Swallow callback errors
94
- }
95
- }
96
- // Detect session_end
97
- if (event.type === "session_end" && "success" in event) {
98
- const success = event.success;
99
- for (const cb of this.completeCallbacks) {
100
- try {
101
- cb(success);
102
- }
103
- catch {
104
- // Swallow callback errors
105
- }
106
- }
107
- }
108
- });
109
- }
110
- // Log stderr
111
- if (this.proc.stderr) {
112
- const stderrRl = readline.createInterface({
113
- input: this.proc.stderr,
114
- terminal: false,
115
- });
116
- stderrRl.on("line", (line) => {
117
- if (!this.closed) {
118
- console.error(`[docker-stdio-bridge:stderr] ${line}`);
119
- }
120
- });
121
- }
122
- // Handle process exit
123
- this.proc.on("exit", (code) => {
124
- console.log(`[docker-stdio-bridge] Agent process exited: code=${code} session=${this.sessionId}`);
125
- });
126
- }
127
- close() {
128
- this.closed = true;
129
- if (this.proc) {
130
- try {
131
- this.proc.stdin?.end();
132
- this.proc.kill("SIGTERM");
133
- }
134
- catch {
135
- // Process may already be dead
136
- }
137
- this.proc = null;
138
- }
139
- }
12
+ sessionId
13
+ streamUrl
14
+ streamHeaders
15
+ containerId
16
+ writer
17
+ agentEventCallbacks = []
18
+ completeCallbacks = []
19
+ closed = false
20
+ proc = null
21
+ constructor(sessionId, connection, containerId) {
22
+ this.sessionId = sessionId
23
+ this.streamUrl = connection.url
24
+ this.streamHeaders = connection.headers
25
+ this.containerId = containerId
26
+ this.writer = new DurableStream({
27
+ url: connection.url,
28
+ headers: connection.headers,
29
+ contentType: "application/json",
30
+ })
31
+ }
32
+ async emit(event) {
33
+ if (this.closed) return
34
+ const msg = { source: "server", ...event }
35
+ await this.writer.append(JSON.stringify(msg))
36
+ }
37
+ async sendCommand(cmd) {
38
+ if (this.closed || !this.proc?.stdin?.writable) return
39
+ const line = JSON.stringify({ type: "command", ...cmd })
40
+ this.proc.stdin.write(`${line}\n`)
41
+ }
42
+ async sendGateResponse(gate, value) {
43
+ if (this.closed || !this.proc?.stdin?.writable) return
44
+ const line = JSON.stringify({ type: "gate_response", gate, ...value })
45
+ this.proc.stdin.write(`${line}\n`)
46
+ }
47
+ onAgentEvent(cb) {
48
+ this.agentEventCallbacks.push(cb)
49
+ }
50
+ onComplete(cb) {
51
+ this.completeCallbacks.push(cb)
52
+ }
53
+ async start() {
54
+ if (this.closed) return
55
+ // Spawn docker exec with stdin piped
56
+ this.proc = spawn("docker", ["exec", "-i", this.containerId, "electric-agent", "headless"], {
57
+ stdio: ["pipe", "pipe", "pipe"],
58
+ })
59
+ console.log(
60
+ `[docker-stdio-bridge] Agent started: session=${this.sessionId} container=${this.containerId} pid=${this.proc.pid}`,
61
+ )
62
+ // Read stdout line by line (NDJSON)
63
+ if (this.proc.stdout) {
64
+ const rl = readline.createInterface({
65
+ input: this.proc.stdout,
66
+ terminal: false,
67
+ })
68
+ rl.on("line", (line) => {
69
+ if (this.closed) return
70
+ const trimmed = line.trim()
71
+ if (!trimmed) return
72
+ let event
73
+ try {
74
+ event = JSON.parse(trimmed)
75
+ } catch {
76
+ console.log(`[docker-stdio-bridge] Non-JSON stdout: ${trimmed}`)
77
+ return
78
+ }
79
+ // Write to Durable Stream for UI
80
+ const msg = { source: "agent", ...event }
81
+ this.writer.append(JSON.stringify(msg)).catch(() => {})
82
+ // Dispatch to callbacks
83
+ for (const cb of this.agentEventCallbacks) {
84
+ try {
85
+ cb(event)
86
+ } catch {
87
+ // Swallow callback errors
88
+ }
89
+ }
90
+ // Detect session_end
91
+ if (event.type === "session_end" && "success" in event) {
92
+ const success = event.success
93
+ for (const cb of this.completeCallbacks) {
94
+ try {
95
+ cb(success)
96
+ } catch {
97
+ // Swallow callback errors
98
+ }
99
+ }
100
+ }
101
+ })
102
+ }
103
+ // Log stderr
104
+ if (this.proc.stderr) {
105
+ const stderrRl = readline.createInterface({
106
+ input: this.proc.stderr,
107
+ terminal: false,
108
+ })
109
+ stderrRl.on("line", (line) => {
110
+ if (!this.closed) {
111
+ console.error(`[docker-stdio-bridge:stderr] ${line}`)
112
+ }
113
+ })
114
+ }
115
+ // Handle process exit
116
+ this.proc.on("exit", (code) => {
117
+ console.log(
118
+ `[docker-stdio-bridge] Agent process exited: code=${code} session=${this.sessionId}`,
119
+ )
120
+ })
121
+ }
122
+ close() {
123
+ this.closed = true
124
+ if (this.proc) {
125
+ try {
126
+ this.proc.stdin?.end()
127
+ this.proc.kill("SIGTERM")
128
+ } catch {
129
+ // Process may already be dead
130
+ }
131
+ this.proc = null
132
+ }
133
+ }
140
134
  }
141
- //# sourceMappingURL=docker-stdio.js.map
135
+ //# sourceMappingURL=docker-stdio.js.map
@@ -9,8 +9,8 @@ import type { StreamConnectionInfo } from "../streams.js";
9
9
  import type { SessionBridge } from "./types.js";
10
10
  export declare class HostedStreamBridge implements SessionBridge {
11
11
  readonly sessionId: string;
12
- readonly streamUrl: string;
13
- readonly streamHeaders: Record<string, string>;
12
+ private readonly streamUrl;
13
+ private readonly streamHeaders;
14
14
  private writer;
15
15
  private agentEventCallbacks;
16
16
  private completeCallbacks;
@@ -25,5 +25,6 @@ export declare class HostedStreamBridge implements SessionBridge {
25
25
  start(): Promise<void>;
26
26
  interrupt(): void;
27
27
  close(): void;
28
+ isRunning(): boolean;
28
29
  }
29
30
  //# sourceMappingURL=hosted.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hosted.d.ts","sourceRoot":"","sources":["../../src/bridge/hosted.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,KAAK,EAAc,aAAa,EAAiB,MAAM,YAAY,CAAA;AAE1E,qBAAa,kBAAmB,YAAW,aAAa;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE9C,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,mBAAmB,CAA0C;IACrE,OAAO,CAAC,iBAAiB,CAAwC;IACjE,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,MAAM,CAAQ;gBAEV,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB;IAYzD,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnF,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAIpD,UAAU,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAI1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6C5B,SAAS,IAAI,IAAI;IAKjB,KAAK,IAAI,IAAI;CAOb"}
1
+ {"version":3,"file":"hosted.d.ts","sourceRoot":"","sources":["../../src/bridge/hosted.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,KAAK,EAAc,aAAa,EAAiB,MAAM,YAAY,CAAA;AAE1E,qBAAa,kBAAmB,YAAW,aAAa;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwB;IAEtD,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,mBAAmB,CAA0C;IACrE,OAAO,CAAC,iBAAiB,CAAwC;IACjE,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,MAAM,CAAQ;gBAEV,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB;IAYzD,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnF,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAIpD,UAAU,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAI1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6C5B,SAAS,IAAI,IAAI;IAKjB,KAAK,IAAI,IAAI;IAQb,SAAS,IAAI,OAAO;CAIpB"}
@@ -113,5 +113,9 @@ export class HostedStreamBridge {
113
113
  this.cancelSubscription = null;
114
114
  }
115
115
  }
116
+ isRunning() {
117
+ // Hosted bridges don't track process state — assume running if not closed
118
+ return !this.closed;
119
+ }
116
120
  }
117
121
  //# sourceMappingURL=hosted.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hosted.js","sourceRoot":"","sources":["../../src/bridge/hosted.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hosted.js","sourceRoot":"","sources":["../../src/bridge/hosted.ts"],"names":[],"mappings":"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"}