@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.
Files changed (109) 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 +22 -5
  18. package/dist/bridge/claude-md-generator.d.ts.map +1 -1
  19. package/dist/bridge/claude-md-generator.js +81 -213
  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/stream-json-parser.js +12 -5
  52. package/dist/bridge/stream-json-parser.js.map +1 -1
  53. package/dist/bridge/types.d.ts +4 -10
  54. package/dist/bridge/types.d.ts.map +1 -1
  55. package/dist/client/assets/index-BfvQSMwH.css +1 -0
  56. package/dist/client/assets/index-CiwD5LkP.js +235 -0
  57. package/dist/client/index.html +2 -2
  58. package/dist/index.d.ts +4 -3
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +3 -3
  61. package/dist/index.js.map +1 -1
  62. package/dist/invite-code.d.ts +5 -0
  63. package/dist/invite-code.d.ts.map +1 -0
  64. package/dist/invite-code.js +14 -0
  65. package/dist/invite-code.js.map +1 -0
  66. package/dist/project-utils.d.ts.map +1 -1
  67. package/dist/project-utils.js.map +1 -1
  68. package/dist/registry.d.ts +11 -4
  69. package/dist/registry.d.ts.map +1 -1
  70. package/dist/registry.js +1 -1
  71. package/dist/registry.js.map +1 -1
  72. package/dist/room-router.d.ts +73 -0
  73. package/dist/room-router.d.ts.map +1 -0
  74. package/dist/room-router.js +345 -0
  75. package/dist/room-router.js.map +1 -0
  76. package/dist/sandbox/docker.d.ts.map +1 -1
  77. package/dist/sandbox/docker.js +5 -6
  78. package/dist/sandbox/docker.js.map +1 -1
  79. package/dist/sandbox/index.d.ts +0 -1
  80. package/dist/sandbox/index.d.ts.map +1 -1
  81. package/dist/sandbox/index.js +0 -1
  82. package/dist/sandbox/index.js.map +1 -1
  83. package/dist/sandbox/sprites.d.ts.map +1 -1
  84. package/dist/sandbox/sprites.js +40 -10
  85. package/dist/sandbox/sprites.js.map +1 -1
  86. package/dist/sandbox/types.d.ts +4 -2
  87. package/dist/sandbox/types.d.ts.map +1 -1
  88. package/dist/server.d.ts +12 -0
  89. package/dist/server.d.ts.map +1 -1
  90. package/dist/server.js +824 -309
  91. package/dist/server.js.map +1 -1
  92. package/dist/session-auth.d.ts +9 -0
  93. package/dist/session-auth.d.ts.map +1 -1
  94. package/dist/session-auth.js +30 -0
  95. package/dist/session-auth.js.map +1 -1
  96. package/dist/sessions.d.ts +7 -1
  97. package/dist/sessions.d.ts.map +1 -1
  98. package/dist/sessions.js.map +1 -1
  99. package/dist/streams.d.ts +2 -6
  100. package/dist/streams.d.ts.map +1 -1
  101. package/dist/streams.js +6 -17
  102. package/dist/streams.js.map +1 -1
  103. package/dist/validate.d.ts +10 -0
  104. package/dist/validate.d.ts.map +1 -0
  105. package/dist/validate.js +24 -0
  106. package/dist/validate.js.map +1 -0
  107. package/package.json +6 -9
  108. package/dist/client/assets/index-DDzmxYub.js +0 -234
  109. package/dist/client/assets/index-DcP7prsZ.css +0 -1
@@ -8,235 +8,227 @@
8
8
  * Codex runs in one-shot mode (`codex exec --json`) and exits after completing.
9
9
  * On iterate (follow-up message), the bridge respawns Codex with the new prompt.
10
10
  */
11
- import { spawn } from "node:child_process";
12
- import * as readline from "node:readline";
13
- import { DurableStream } from "@durable-streams/client";
14
- import { ts } from "@electric-agent/protocol";
15
- import { createCodexJsonParser } from "./codex-json-parser.js";
11
+ import { spawn } from "node:child_process"
12
+ import * as readline from "node:readline"
13
+ import { DurableStream } from "@durable-streams/client"
14
+ import { ts } from "@electric-agent/protocol"
15
+ import { createCodexJsonParser } from "./codex-json-parser.js"
16
16
  export class CodexDockerBridge {
17
- sessionId;
18
- streamUrl;
19
- streamHeaders;
20
- containerId;
21
- config;
22
- writer;
23
- parser = createCodexJsonParser();
24
- agentEventCallbacks = [];
25
- completeCallbacks = [];
26
- closed = false;
27
- proc = null;
28
- /** Codex thread ID captured from thread.started — used for resume */
29
- codexThreadId = null;
30
- /** Whether a Codex process is currently running */
31
- running = false;
32
- /** Whether the parser already emitted a session_end */
33
- resultReceived = false;
34
- constructor(sessionId, connection, containerId, config) {
35
- this.sessionId = sessionId;
36
- this.streamUrl = connection.url;
37
- this.streamHeaders = connection.headers;
38
- this.containerId = containerId;
39
- this.config = config;
40
- this.writer = new DurableStream({
41
- url: connection.url,
42
- headers: connection.headers,
43
- contentType: "application/json",
44
- });
45
- }
46
- async emit(event) {
47
- if (this.closed)
48
- return;
49
- const msg = { source: "server", ...event };
50
- await this.writer.append(JSON.stringify(msg));
51
- }
52
- /**
53
- * Send a follow-up user message to Codex by respawning with a new prompt.
54
- */
55
- async sendCommand(cmd) {
56
- if (this.closed)
57
- return;
58
- if (cmd.command === "iterate" && typeof cmd.request === "string") {
59
- this.spawnCodex(cmd.request);
60
- return;
61
- }
62
- console.log(`[codex-docker] Ignoring unsupported command: ${cmd.command}`);
63
- }
64
- /**
65
- * Send a gate response. Codex exec mode doesn't support stdin interaction,
66
- * so gate responses are limited.
67
- */
68
- async sendGateResponse(_gate, _value) {
69
- // Codex exec --json doesn't support stdin user messages mid-run
70
- }
71
- onAgentEvent(cb) {
72
- this.agentEventCallbacks.push(cb);
73
- }
74
- onComplete(cb) {
75
- this.completeCallbacks.push(cb);
76
- }
77
- async start() {
78
- if (this.closed)
79
- return;
80
- this.spawnCodex(this.config.prompt);
81
- }
82
- close() {
83
- this.closed = true;
84
- if (this.proc) {
85
- try {
86
- this.proc.stdin?.end();
87
- this.proc.kill("SIGTERM");
88
- }
89
- catch {
90
- // Process may already be dead
91
- }
92
- this.proc = null;
93
- }
94
- }
95
- // -----------------------------------------------------------------------
96
- // Private helpers
97
- // -----------------------------------------------------------------------
98
- /**
99
- * Spawn a new Codex process. Called for both the initial prompt
100
- * and follow-up iterate messages.
101
- */
102
- spawnCodex(prompt) {
103
- // Kill any existing process
104
- if (this.proc) {
105
- try {
106
- this.proc.stdin?.end();
107
- this.proc.kill("SIGTERM");
108
- }
109
- catch {
110
- // Already dead
111
- }
112
- this.proc = null;
113
- }
114
- // Reset parser state for the new process
115
- this.parser = createCodexJsonParser();
116
- this.resultReceived = false;
117
- this.running = true;
118
- const model = this.config.model ?? "o4-mini";
119
- // Build the codex CLI command
120
- const codexArgs = [
121
- "exec",
122
- "--json",
123
- "--full-auto",
124
- "--model",
125
- model,
126
- ...(this.config.extraFlags ?? []),
127
- "-q",
128
- prompt,
129
- ];
130
- // Escape for bash
131
- const escapedArgs = codexArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
132
- const cmd = `cd '${this.config.cwd}' && codex ${escapedArgs}`;
133
- this.proc = spawn("docker", ["exec", this.containerId, "bash", "-c", cmd], {
134
- stdio: ["pipe", "pipe", "pipe"],
135
- });
136
- console.log(`[codex-docker] Started: session=${this.sessionId} container=${this.containerId} pid=${this.proc.pid}`);
137
- console.log(`[codex-docker] cmd: ${cmd}`);
138
- const currentProc = this.proc;
139
- // Read stdout line by line (exec --json NDJSON)
140
- if (currentProc.stdout) {
141
- const rl = readline.createInterface({
142
- input: currentProc.stdout,
143
- terminal: false,
144
- });
145
- rl.on("line", (line) => {
146
- if (this.closed)
147
- return;
148
- console.log(`[codex-docker:stdout] ${line.slice(0, 120)}...`);
149
- this.handleLine(line);
150
- });
151
- }
152
- // Log stderr
153
- if (currentProc.stderr) {
154
- const stderrRl = readline.createInterface({
155
- input: currentProc.stderr,
156
- terminal: false,
157
- });
158
- stderrRl.on("line", (line) => {
159
- if (!this.closed) {
160
- console.error(`[codex-docker:stderr] ${line}`);
161
- }
162
- });
163
- }
164
- // Handle process exit defer to let pending readline events flush first
165
- currentProc.on("exit", (code) => {
166
- console.log(`[codex-docker] Process exited: code=${code} session=${this.sessionId}`);
167
- setTimeout(() => {
168
- // Capture thread ID from parser state before marking not running
169
- if (this.parser.state.threadId) {
170
- this.codexThreadId = this.parser.state.threadId;
171
- }
172
- this.running = false;
173
- // Emit session_end if the parser didn't already
174
- if (!this.closed && !this.resultReceived) {
175
- const endEvent = {
176
- type: "session_end",
177
- success: code === 0,
178
- ts: ts(),
179
- };
180
- this.dispatchEvent(endEvent);
181
- }
182
- }, 100);
183
- });
184
- }
185
- handleLine(line) {
186
- const trimmed = line.trim();
187
- if (!trimmed)
188
- return;
189
- const events = this.parser.parse(trimmed);
190
- for (const event of events) {
191
- this.dispatchEvent(event);
192
- }
193
- }
194
- dispatchEvent(event) {
195
- // Write to Durable Stream for UI
196
- const msg = { source: "agent", ...event };
197
- this.writer.append(JSON.stringify(msg)).catch(() => { });
198
- // Track session_end to prevent duplicates
199
- if (event.type === "session_end") {
200
- this.resultReceived = true;
201
- }
202
- // Detect dev:start in Bash tool_use emit app_ready for the UI preview
203
- if (event.type === "pre_tool_use" && event.tool_name === "Bash") {
204
- const cmd = event.tool_input?.command;
205
- if (typeof cmd === "string" && /\bdev:start\b/.test(cmd)) {
206
- const appReady = { type: "app_ready", ts: ts() };
207
- const appReadyMsg = { source: "agent", ...appReady };
208
- this.writer.append(JSON.stringify(appReadyMsg)).catch(() => { });
209
- for (const cb of this.agentEventCallbacks) {
210
- try {
211
- cb(appReady);
212
- }
213
- catch {
214
- // Swallow
215
- }
216
- }
217
- }
218
- }
219
- // Dispatch to callbacks
220
- for (const cb of this.agentEventCallbacks) {
221
- try {
222
- cb(event);
223
- }
224
- catch {
225
- // Swallow callback errors
226
- }
227
- }
228
- // Detect session_end
229
- if (event.type === "session_end" && "success" in event) {
230
- const success = event.success;
231
- for (const cb of this.completeCallbacks) {
232
- try {
233
- cb(success);
234
- }
235
- catch {
236
- // Swallow callback errors
237
- }
238
- }
239
- }
240
- }
17
+ sessionId
18
+ streamUrl
19
+ streamHeaders
20
+ containerId
21
+ config
22
+ writer
23
+ parser = createCodexJsonParser()
24
+ agentEventCallbacks = []
25
+ completeCallbacks = []
26
+ closed = false
27
+ proc = null
28
+ /** Codex thread ID captured from thread.started — used for resume */
29
+ codexThreadId = null
30
+ /** Whether a Codex process is currently running */
31
+ running = false
32
+ /** Whether the parser already emitted a session_end */
33
+ resultReceived = false
34
+ constructor(sessionId, connection, containerId, config) {
35
+ this.sessionId = sessionId
36
+ this.streamUrl = connection.url
37
+ this.streamHeaders = connection.headers
38
+ this.containerId = containerId
39
+ this.config = config
40
+ this.writer = new DurableStream({
41
+ url: connection.url,
42
+ headers: connection.headers,
43
+ contentType: "application/json",
44
+ })
45
+ }
46
+ async emit(event) {
47
+ if (this.closed) return
48
+ const msg = { source: "server", ...event }
49
+ await this.writer.append(JSON.stringify(msg))
50
+ }
51
+ /**
52
+ * Send a follow-up user message to Codex by respawning with a new prompt.
53
+ */
54
+ async sendCommand(cmd) {
55
+ if (this.closed) return
56
+ if (cmd.command === "iterate" && typeof cmd.request === "string") {
57
+ this.spawnCodex(cmd.request)
58
+ return
59
+ }
60
+ console.log(`[codex-docker] Ignoring unsupported command: ${cmd.command}`)
61
+ }
62
+ /**
63
+ * Send a gate response. Codex exec mode doesn't support stdin interaction,
64
+ * so gate responses are limited.
65
+ */
66
+ async sendGateResponse(_gate, _value) {
67
+ // Codex exec --json doesn't support stdin user messages mid-run
68
+ }
69
+ onAgentEvent(cb) {
70
+ this.agentEventCallbacks.push(cb)
71
+ }
72
+ onComplete(cb) {
73
+ this.completeCallbacks.push(cb)
74
+ }
75
+ async start() {
76
+ if (this.closed) return
77
+ this.spawnCodex(this.config.prompt)
78
+ }
79
+ close() {
80
+ this.closed = true
81
+ if (this.proc) {
82
+ try {
83
+ this.proc.stdin?.end()
84
+ this.proc.kill("SIGTERM")
85
+ } catch {
86
+ // Process may already be dead
87
+ }
88
+ this.proc = null
89
+ }
90
+ }
91
+ // -----------------------------------------------------------------------
92
+ // Private helpers
93
+ // -----------------------------------------------------------------------
94
+ /**
95
+ * Spawn a new Codex process. Called for both the initial prompt
96
+ * and follow-up iterate messages.
97
+ */
98
+ spawnCodex(prompt) {
99
+ // Kill any existing process
100
+ if (this.proc) {
101
+ try {
102
+ this.proc.stdin?.end()
103
+ this.proc.kill("SIGTERM")
104
+ } catch {
105
+ // Already dead
106
+ }
107
+ this.proc = null
108
+ }
109
+ // Reset parser state for the new process
110
+ this.parser = createCodexJsonParser()
111
+ this.resultReceived = false
112
+ this.running = true
113
+ const model = this.config.model ?? "o4-mini"
114
+ // Build the codex CLI command
115
+ const codexArgs = [
116
+ "exec",
117
+ "--json",
118
+ "--full-auto",
119
+ "--model",
120
+ model,
121
+ ...(this.config.extraFlags ?? []),
122
+ "-q",
123
+ prompt,
124
+ ]
125
+ // Escape for bash
126
+ const escapedArgs = codexArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ")
127
+ const cmd = `cd '${this.config.cwd}' && codex ${escapedArgs}`
128
+ this.proc = spawn("docker", ["exec", this.containerId, "bash", "-c", cmd], {
129
+ stdio: ["pipe", "pipe", "pipe"],
130
+ })
131
+ console.log(
132
+ `[codex-docker] Started: session=${this.sessionId} container=${this.containerId} pid=${this.proc.pid}`,
133
+ )
134
+ console.log(`[codex-docker] cmd: ${cmd}`)
135
+ const currentProc = this.proc
136
+ // Read stdout line by line (exec --json NDJSON)
137
+ if (currentProc.stdout) {
138
+ const rl = readline.createInterface({
139
+ input: currentProc.stdout,
140
+ terminal: false,
141
+ })
142
+ rl.on("line", (line) => {
143
+ if (this.closed) return
144
+ console.log(`[codex-docker:stdout] ${line.slice(0, 120)}...`)
145
+ this.handleLine(line)
146
+ })
147
+ }
148
+ // Log stderr
149
+ if (currentProc.stderr) {
150
+ const stderrRl = readline.createInterface({
151
+ input: currentProc.stderr,
152
+ terminal: false,
153
+ })
154
+ stderrRl.on("line", (line) => {
155
+ if (!this.closed) {
156
+ console.error(`[codex-docker:stderr] ${line}`)
157
+ }
158
+ })
159
+ }
160
+ // Handle process exit — defer to let pending readline events flush first
161
+ currentProc.on("exit", (code) => {
162
+ console.log(`[codex-docker] Process exited: code=${code} session=${this.sessionId}`)
163
+ setTimeout(() => {
164
+ // Capture thread ID from parser state before marking not running
165
+ if (this.parser.state.threadId) {
166
+ this.codexThreadId = this.parser.state.threadId
167
+ }
168
+ this.running = false
169
+ // Emit session_end if the parser didn't already
170
+ if (!this.closed && !this.resultReceived) {
171
+ const endEvent = {
172
+ type: "session_end",
173
+ success: code === 0,
174
+ ts: ts(),
175
+ }
176
+ this.dispatchEvent(endEvent)
177
+ }
178
+ }, 100)
179
+ })
180
+ }
181
+ handleLine(line) {
182
+ const trimmed = line.trim()
183
+ if (!trimmed) return
184
+ const events = this.parser.parse(trimmed)
185
+ for (const event of events) {
186
+ this.dispatchEvent(event)
187
+ }
188
+ }
189
+ dispatchEvent(event) {
190
+ // Write to Durable Stream for UI
191
+ const msg = { source: "agent", ...event }
192
+ this.writer.append(JSON.stringify(msg)).catch(() => {})
193
+ // Track session_end to prevent duplicates
194
+ if (event.type === "session_end") {
195
+ this.resultReceived = true
196
+ }
197
+ // Detect dev:start in Bash tool_use → emit app_ready for the UI preview
198
+ if (event.type === "pre_tool_use" && event.tool_name === "Bash") {
199
+ const cmd = event.tool_input?.command
200
+ if (typeof cmd === "string" && /\bdev:start\b/.test(cmd)) {
201
+ const appReady = { type: "app_ready", ts: ts() }
202
+ const appReadyMsg = { source: "agent", ...appReady }
203
+ this.writer.append(JSON.stringify(appReadyMsg)).catch(() => {})
204
+ for (const cb of this.agentEventCallbacks) {
205
+ try {
206
+ cb(appReady)
207
+ } catch {
208
+ // Swallow
209
+ }
210
+ }
211
+ }
212
+ }
213
+ // Dispatch to callbacks
214
+ for (const cb of this.agentEventCallbacks) {
215
+ try {
216
+ cb(event)
217
+ } catch {
218
+ // Swallow callback errors
219
+ }
220
+ }
221
+ // Detect session_end
222
+ if (event.type === "session_end" && "success" in event) {
223
+ const success = event.success
224
+ for (const cb of this.completeCallbacks) {
225
+ try {
226
+ cb(success)
227
+ } catch {
228
+ // Swallow callback errors
229
+ }
230
+ }
231
+ }
232
+ }
241
233
  }
242
- //# sourceMappingURL=codex-docker.js.map
234
+ //# sourceMappingURL=codex-docker.js.map
@@ -11,21 +11,21 @@
11
11
  *
12
12
  * This parser converts each line into zero or more EngineEvent objects.
13
13
  */
14
- import type { EngineEvent } from "@electric-agent/protocol";
14
+ import type { EngineEvent } from "@electric-agent/protocol"
15
15
  export interface CodexJsonParserState {
16
- /** Map item ID → tool name for correlating started/completed events */
17
- toolNames: Map<string, string>;
18
- /** Accumulated cost from turn.completed messages */
19
- totalCost: number;
20
- /** Codex thread ID from thread.started */
21
- threadId: string | null;
16
+ /** Map item ID → tool name for correlating started/completed events */
17
+ toolNames: Map<string, string>
18
+ /** Accumulated cost from turn.completed messages */
19
+ totalCost: number
20
+ /** Codex thread ID from thread.started */
21
+ threadId: string | null
22
22
  }
23
23
  /**
24
24
  * Create a new stateful parser. The returned `parse` function converts
25
25
  * a single raw JSON line from Codex into zero or more EngineEvents.
26
26
  */
27
27
  export declare function createCodexJsonParser(): {
28
- state: CodexJsonParserState;
29
- parse(line: string): EngineEvent[];
30
- };
31
- //# sourceMappingURL=codex-json-parser.d.ts.map
28
+ state: CodexJsonParserState
29
+ parse(line: string): EngineEvent[]
30
+ }
31
+ //# sourceMappingURL=codex-json-parser.d.ts.map