@electric-agent/studio 1.5.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.
- package/dist/api-schemas.d.ts +225 -0
- package/dist/api-schemas.d.ts.map +1 -0
- package/dist/api-schemas.js +95 -0
- package/dist/api-schemas.js.map +1 -0
- package/dist/bridge/claude-code-base.d.ts +121 -0
- package/dist/bridge/claude-code-base.d.ts.map +1 -0
- package/dist/bridge/claude-code-base.js +263 -0
- package/dist/bridge/claude-code-base.js.map +1 -0
- package/dist/bridge/claude-code-docker.d.ts +13 -73
- package/dist/bridge/claude-code-docker.d.ts.map +1 -1
- package/dist/bridge/claude-code-docker.js +91 -302
- package/dist/bridge/claude-code-docker.js.map +1 -1
- package/dist/bridge/claude-code-sprites.d.ts +12 -59
- package/dist/bridge/claude-code-sprites.d.ts.map +1 -1
- package/dist/bridge/claude-code-sprites.js +88 -281
- package/dist/bridge/claude-code-sprites.js.map +1 -1
- package/dist/bridge/claude-md-generator.d.ts +22 -5
- package/dist/bridge/claude-md-generator.d.ts.map +1 -1
- package/dist/bridge/claude-md-generator.js +81 -213
- package/dist/bridge/claude-md-generator.js.map +1 -1
- package/dist/bridge/codex-docker.d.ts +56 -51
- package/dist/bridge/codex-docker.js +222 -230
- package/dist/bridge/codex-json-parser.d.ts +11 -11
- package/dist/bridge/codex-json-parser.js +231 -238
- package/dist/bridge/codex-md-generator.d.ts +3 -3
- package/dist/bridge/codex-md-generator.js +42 -32
- package/dist/bridge/codex-sprites.d.ts +50 -45
- package/dist/bridge/codex-sprites.js +212 -222
- package/dist/bridge/daytona.d.ts +25 -25
- package/dist/bridge/daytona.js +131 -136
- package/dist/bridge/docker-stdio.d.ts +21 -21
- package/dist/bridge/docker-stdio.js +126 -132
- package/dist/bridge/hosted.d.ts +3 -2
- package/dist/bridge/hosted.d.ts.map +1 -1
- package/dist/bridge/hosted.js +4 -0
- package/dist/bridge/hosted.js.map +1 -1
- package/dist/bridge/message-parser.d.ts +24 -0
- package/dist/bridge/message-parser.d.ts.map +1 -0
- package/dist/bridge/message-parser.js +39 -0
- package/dist/bridge/message-parser.js.map +1 -0
- package/dist/bridge/role-skills.d.ts +25 -0
- package/dist/bridge/role-skills.d.ts.map +1 -0
- package/dist/bridge/role-skills.js +120 -0
- package/dist/bridge/role-skills.js.map +1 -0
- package/dist/bridge/room-messaging-skill.d.ts +11 -0
- package/dist/bridge/room-messaging-skill.d.ts.map +1 -0
- package/dist/bridge/room-messaging-skill.js +41 -0
- package/dist/bridge/room-messaging-skill.js.map +1 -0
- package/dist/bridge/sprites.d.ts +22 -22
- package/dist/bridge/sprites.js +123 -128
- package/dist/bridge/stream-json-parser.js +12 -5
- package/dist/bridge/stream-json-parser.js.map +1 -1
- package/dist/bridge/types.d.ts +4 -10
- package/dist/bridge/types.d.ts.map +1 -1
- package/dist/client/assets/index-BfvQSMwH.css +1 -0
- package/dist/client/assets/index-CiwD5LkP.js +235 -0
- package/dist/client/index.html +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/invite-code.d.ts +5 -0
- package/dist/invite-code.d.ts.map +1 -0
- package/dist/invite-code.js +14 -0
- package/dist/invite-code.js.map +1 -0
- package/dist/project-utils.d.ts.map +1 -1
- package/dist/project-utils.js.map +1 -1
- package/dist/registry.d.ts +11 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/registry.js.map +1 -1
- package/dist/room-router.d.ts +73 -0
- package/dist/room-router.d.ts.map +1 -0
- package/dist/room-router.js +345 -0
- package/dist/room-router.js.map +1 -0
- package/dist/sandbox/docker.d.ts.map +1 -1
- package/dist/sandbox/docker.js +5 -6
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/index.d.ts +0 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +0 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/sprites.d.ts.map +1 -1
- package/dist/sandbox/sprites.js +40 -10
- package/dist/sandbox/sprites.js.map +1 -1
- package/dist/sandbox/types.d.ts +4 -2
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +824 -309
- package/dist/server.js.map +1 -1
- package/dist/session-auth.d.ts +9 -0
- package/dist/session-auth.d.ts.map +1 -1
- package/dist/session-auth.js +30 -0
- package/dist/session-auth.js.map +1 -1
- package/dist/sessions.d.ts +7 -1
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js.map +1 -1
- package/dist/streams.d.ts +2 -6
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +6 -17
- package/dist/streams.js.map +1 -1
- package/dist/validate.d.ts +10 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +24 -0
- package/dist/validate.js.map +1 -0
- package/package.json +6 -9
- package/dist/client/assets/index-DDzmxYub.js +0 -234
- package/dist/client/assets/index-DcP7prsZ.css +0 -1
package/dist/bridge/daytona.js
CHANGED
|
@@ -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
|
-
|
|
9
|
+
import { DurableStream } from "@durable-streams/client"
|
|
10
|
+
|
|
11
|
+
const DAYTONA_SESSION_ID = "agent-session"
|
|
11
12
|
export class DaytonaSessionBridge {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
package/dist/bridge/hosted.d.ts
CHANGED
|
@@ -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
|
|
13
|
-
readonly streamHeaders
|
|
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,
|
|
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"}
|
package/dist/bridge/hosted.js
CHANGED
|
@@ -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":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAEvD,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAA;AAI7C,MAAM,OAAO,kBAAkB;IACrB,SAAS,CAAQ;
|
|
1
|
+
{"version":3,"file":"hosted.js","sourceRoot":"","sources":["../../src/bridge/hosted.ts"],"names":[],"mappings":"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"}
|