@electric-agent/studio 1.0.0 → 1.1.1

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 (68) hide show
  1. package/dist/active-sessions.d.ts +28 -0
  2. package/dist/active-sessions.d.ts.map +1 -0
  3. package/dist/active-sessions.js +50 -0
  4. package/dist/active-sessions.js.map +1 -0
  5. package/dist/bridge/claude-code-docker.d.ts +74 -0
  6. package/dist/bridge/claude-code-docker.d.ts.map +1 -0
  7. package/dist/bridge/claude-code-docker.js +305 -0
  8. package/dist/bridge/claude-code-docker.js.map +1 -0
  9. package/dist/bridge/claude-code-sprites.d.ts +64 -0
  10. package/dist/bridge/claude-code-sprites.d.ts.map +1 -0
  11. package/dist/bridge/claude-code-sprites.js +293 -0
  12. package/dist/bridge/claude-code-sprites.js.map +1 -0
  13. package/dist/bridge/claude-md-generator.d.ts +24 -0
  14. package/dist/bridge/claude-md-generator.d.ts.map +1 -0
  15. package/dist/bridge/claude-md-generator.js +303 -0
  16. package/dist/bridge/claude-md-generator.js.map +1 -0
  17. package/dist/bridge/index.d.ts +3 -0
  18. package/dist/bridge/index.d.ts.map +1 -1
  19. package/dist/bridge/index.js +3 -0
  20. package/dist/bridge/index.js.map +1 -1
  21. package/dist/bridge/stream-json-parser.d.ts +30 -0
  22. package/dist/bridge/stream-json-parser.d.ts.map +1 -0
  23. package/dist/bridge/stream-json-parser.js +207 -0
  24. package/dist/bridge/stream-json-parser.js.map +1 -0
  25. package/dist/client/assets/index-BeZ6CTGd.css +1 -0
  26. package/dist/client/assets/index-DRLXdDNp.js +241 -0
  27. package/dist/client/index.html +2 -2
  28. package/dist/index.d.ts +5 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +4 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/project-utils.d.ts +2 -1
  33. package/dist/project-utils.d.ts.map +1 -1
  34. package/dist/project-utils.js +2 -6
  35. package/dist/project-utils.js.map +1 -1
  36. package/dist/registry.d.ts +52 -0
  37. package/dist/registry.d.ts.map +1 -0
  38. package/dist/registry.js +204 -0
  39. package/dist/registry.js.map +1 -0
  40. package/dist/room-registry.d.ts +40 -0
  41. package/dist/room-registry.d.ts.map +1 -0
  42. package/dist/room-registry.js +112 -0
  43. package/dist/room-registry.js.map +1 -0
  44. package/dist/sandbox/sprites-bootstrap.d.ts.map +1 -1
  45. package/dist/sandbox/sprites-bootstrap.js +7 -1
  46. package/dist/sandbox/sprites-bootstrap.js.map +1 -1
  47. package/dist/sandbox/sprites.d.ts +5 -0
  48. package/dist/sandbox/sprites.d.ts.map +1 -1
  49. package/dist/sandbox/sprites.js +22 -2
  50. package/dist/sandbox/sprites.js.map +1 -1
  51. package/dist/server.d.ts +9 -2
  52. package/dist/server.d.ts.map +1 -1
  53. package/dist/server.js +625 -58
  54. package/dist/server.js.map +1 -1
  55. package/dist/sessions.d.ts +2 -0
  56. package/dist/sessions.d.ts.map +1 -1
  57. package/dist/sessions.js.map +1 -1
  58. package/dist/shared-sessions.d.ts +16 -0
  59. package/dist/shared-sessions.d.ts.map +1 -0
  60. package/dist/shared-sessions.js +52 -0
  61. package/dist/shared-sessions.js.map +1 -0
  62. package/dist/streams.d.ts +8 -0
  63. package/dist/streams.d.ts.map +1 -1
  64. package/dist/streams.js +22 -0
  65. package/dist/streams.js.map +1 -1
  66. package/package.json +15 -2
  67. package/dist/client/assets/index-CK__1-6e.css +0 -1
  68. package/dist/client/assets/index-DKL-jl7t.js +0 -241
@@ -0,0 +1,28 @@
1
+ import type { SessionInfo } from "./sessions.js";
2
+ /**
3
+ * Lightweight in-memory session store for the current server lifetime.
4
+ *
5
+ * Sessions are private to each user (stored in their browser's localStorage).
6
+ * The server only tracks active sessions for sandbox/bridge management.
7
+ * This store is NOT persisted — it resets on server restart.
8
+ */
9
+ export declare class ActiveSessions {
10
+ private sessions;
11
+ private transcriptToSession;
12
+ add(session: SessionInfo): void;
13
+ get(id: string): SessionInfo | undefined;
14
+ update(id: string, update: Partial<SessionInfo>): void;
15
+ delete(id: string): boolean;
16
+ /** Check if a session exists in the active store. */
17
+ has(id: string): boolean;
18
+ /**
19
+ * Look up the EA session ID for a Claude Code transcript path.
20
+ * Returns undefined if no mapping exists or the session has been deleted.
21
+ */
22
+ getByTranscript(transcriptPath: string): string | undefined;
23
+ /**
24
+ * Map a transcript path to an EA session ID.
25
+ */
26
+ mapTranscript(transcriptPath: string, sessionId: string): void;
27
+ }
28
+ //# sourceMappingURL=active-sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-sessions.d.ts","sourceRoot":"","sources":["../src/active-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD;;;;;;GAMG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,mBAAmB,CAA4B;IAEvD,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAI/B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIxC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;IAStD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI3B,qDAAqD;IACrD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAMxB;;;OAGG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAM3D;;OAEG;IACH,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;CAG9D"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Lightweight in-memory session store for the current server lifetime.
3
+ *
4
+ * Sessions are private to each user (stored in their browser's localStorage).
5
+ * The server only tracks active sessions for sandbox/bridge management.
6
+ * This store is NOT persisted — it resets on server restart.
7
+ */
8
+ export class ActiveSessions {
9
+ sessions = new Map();
10
+ transcriptToSession = new Map();
11
+ add(session) {
12
+ this.sessions.set(session.id, session);
13
+ }
14
+ get(id) {
15
+ return this.sessions.get(id);
16
+ }
17
+ update(id, update) {
18
+ const session = this.sessions.get(id);
19
+ if (session) {
20
+ Object.assign(session, update, {
21
+ lastActiveAt: new Date().toISOString(),
22
+ });
23
+ }
24
+ }
25
+ delete(id) {
26
+ return this.sessions.delete(id);
27
+ }
28
+ /** Check if a session exists in the active store. */
29
+ has(id) {
30
+ return this.sessions.has(id);
31
+ }
32
+ // --- Transcript → Session Mapping (for Claude Code hook integration) ---
33
+ /**
34
+ * Look up the EA session ID for a Claude Code transcript path.
35
+ * Returns undefined if no mapping exists or the session has been deleted.
36
+ */
37
+ getByTranscript(transcriptPath) {
38
+ const sessionId = this.transcriptToSession.get(transcriptPath);
39
+ if (!sessionId)
40
+ return undefined;
41
+ return this.sessions.has(sessionId) ? sessionId : undefined;
42
+ }
43
+ /**
44
+ * Map a transcript path to an EA session ID.
45
+ */
46
+ mapTranscript(transcriptPath, sessionId) {
47
+ this.transcriptToSession.set(transcriptPath, sessionId);
48
+ }
49
+ }
50
+ //# sourceMappingURL=active-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-sessions.js","sourceRoot":"","sources":["../src/active-sessions.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IAClB,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAA;IACzC,mBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAA;IAEvD,GAAG,CAAC,OAAoB;QACvB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IACvC,CAAC;IAED,GAAG,CAAC,EAAU;QACb,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,MAAM,CAAC,EAAU,EAAE,MAA4B;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACrC,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE;gBAC9B,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACtC,CAAC,CAAA;QACH,CAAC;IACF,CAAC;IAED,MAAM,CAAC,EAAU;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAChC,CAAC;IAED,qDAAqD;IACrD,GAAG,CAAC,EAAU;QACb,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,0EAA0E;IAE1E;;;OAGG;IACH,eAAe,CAAC,cAAsB;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QAC9D,IAAI,CAAC,SAAS;YAAE,OAAO,SAAS,CAAA;QAChC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;IAC5D,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,cAAsB,EAAE,SAAiB;QACtD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;IACxD,CAAC;CACD"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * SessionBridge implementation that runs Claude Code CLI inside a Docker
3
+ * container via `docker exec -i`, communicating via stream-json NDJSON.
4
+ *
5
+ * The bridge translates Claude Code's stream-json output into EngineEvents
6
+ * and writes them to the Durable Stream for the UI. User messages and
7
+ * gate responses are sent to Claude Code's stdin.
8
+ *
9
+ * Claude Code runs in one-shot mode (`-p`) and exits after completing.
10
+ * On iterate (follow-up message), the bridge respawns Claude Code with
11
+ * `--resume <sessionId>` so it picks up the previous conversation context.
12
+ */
13
+ import type { EngineEvent } from "@electric-agent/protocol";
14
+ import type { StreamConnectionInfo } from "../streams.js";
15
+ import type { SessionBridge } from "./types.js";
16
+ export interface ClaudeCodeDockerConfig {
17
+ /** Initial prompt (the user's app description or task) */
18
+ prompt: string;
19
+ /** Working directory inside the container */
20
+ cwd: string;
21
+ /** Model to use (default: claude-sonnet-4-6) */
22
+ model?: string;
23
+ /** Allowed tools (default: all standard tools) */
24
+ allowedTools?: string[];
25
+ /** Additional CLI flags */
26
+ extraFlags?: string[];
27
+ }
28
+ export declare class ClaudeCodeDockerBridge implements SessionBridge {
29
+ readonly sessionId: string;
30
+ readonly streamUrl: string;
31
+ readonly streamHeaders: Record<string, string>;
32
+ private containerId;
33
+ private config;
34
+ private writer;
35
+ private parser;
36
+ private agentEventCallbacks;
37
+ private completeCallbacks;
38
+ private closed;
39
+ private proc;
40
+ /** Claude Code session ID captured from stream-json system.init — used for --resume */
41
+ private claudeSessionId;
42
+ /** Whether a Claude Code process is currently running */
43
+ private running;
44
+ /** Whether the parser already emitted a session_end (from a "result" message) */
45
+ private resultReceived;
46
+ constructor(sessionId: string, connection: StreamConnectionInfo, containerId: string, config: ClaudeCodeDockerConfig);
47
+ emit(event: EngineEvent): Promise<void>;
48
+ /**
49
+ * Send a follow-up user message to Claude Code by respawning with --resume.
50
+ * Used for iteration requests (the user types a new message in the UI).
51
+ */
52
+ sendCommand(cmd: Record<string, unknown>): Promise<void>;
53
+ /**
54
+ * Send a gate response back to Claude Code as a user message.
55
+ * For ask_user_question gates, the user's answer becomes a follow-up message.
56
+ */
57
+ sendGateResponse(gate: string, value: Record<string, unknown>): Promise<void>;
58
+ onAgentEvent(cb: (event: EngineEvent) => void): void;
59
+ onComplete(cb: (success: boolean) => void): void;
60
+ start(): Promise<void>;
61
+ close(): void;
62
+ /**
63
+ * Spawn a new Claude Code process. Called for both the initial prompt
64
+ * and follow-up iterate messages (with --resume).
65
+ */
66
+ private spawnClaude;
67
+ private handleLine;
68
+ private dispatchEvent;
69
+ /**
70
+ * Write a user message to Claude Code's stdin in stream-json format.
71
+ */
72
+ private writeUserMessage;
73
+ }
74
+ //# sourceMappingURL=claude-code-docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code-docker.d.ts","sourceRoot":"","sources":["../../src/bridge/claude-code-docker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAE9D,MAAM,WAAW,sBAAsB;IACtC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAA;IACX,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAcD,qBAAa,sBAAuB,YAAW,aAAa;IAC3D,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,WAAW,CAAQ;IAC3B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,mBAAmB,CAA0C;IACrE,OAAO,CAAC,iBAAiB,CAAwC;IACjE,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,IAAI,CAA4B;IAExC,uFAAuF;IACvF,OAAO,CAAC,eAAe,CAAsB;IAC7C,yDAAyD;IACzD,OAAO,CAAC,OAAO,CAAQ;IACvB,iFAAiF;IACjF,OAAO,CAAC,cAAc,CAAQ;gBAG7B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,sBAAsB;IAezB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7C;;;OAGG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAc9D;;;OAGG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAiCnF,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;IAK5B,KAAK,IAAI,IAAI;IAiBb;;;OAGG;IACH,OAAO,CAAC,WAAW;IA2GnB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,aAAa;IAiDrB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAQxB"}
@@ -0,0 +1,305 @@
1
+ /**
2
+ * SessionBridge implementation that runs Claude Code CLI inside a Docker
3
+ * container via `docker exec -i`, communicating via stream-json NDJSON.
4
+ *
5
+ * The bridge translates Claude Code's stream-json output into EngineEvents
6
+ * and writes them to the Durable Stream for the UI. User messages and
7
+ * gate responses are sent to Claude Code's stdin.
8
+ *
9
+ * Claude Code runs in one-shot mode (`-p`) and exits after completing.
10
+ * On iterate (follow-up message), the bridge respawns Claude Code with
11
+ * `--resume <sessionId>` so it picks up the previous conversation context.
12
+ */
13
+ import { spawn } from "node:child_process";
14
+ import * as readline from "node:readline";
15
+ import { DurableStream } from "@durable-streams/client";
16
+ import { ts } from "@electric-agent/protocol";
17
+ import { createStreamJsonParser } from "./stream-json-parser.js";
18
+ const DEFAULT_ALLOWED_TOOLS = [
19
+ "Read",
20
+ "Write",
21
+ "Edit",
22
+ "Bash",
23
+ "Glob",
24
+ "Grep",
25
+ "WebSearch",
26
+ "TodoWrite",
27
+ "AskUserQuestion",
28
+ ];
29
+ export class ClaudeCodeDockerBridge {
30
+ sessionId;
31
+ streamUrl;
32
+ streamHeaders;
33
+ containerId;
34
+ config;
35
+ writer;
36
+ parser = createStreamJsonParser();
37
+ agentEventCallbacks = [];
38
+ completeCallbacks = [];
39
+ closed = false;
40
+ proc = null;
41
+ /** Claude Code session ID captured from stream-json system.init — used for --resume */
42
+ claudeSessionId = null;
43
+ /** Whether a Claude Code process is currently running */
44
+ running = false;
45
+ /** Whether the parser already emitted a session_end (from a "result" message) */
46
+ resultReceived = false;
47
+ constructor(sessionId, connection, containerId, config) {
48
+ this.sessionId = sessionId;
49
+ this.streamUrl = connection.url;
50
+ this.streamHeaders = connection.headers;
51
+ this.containerId = containerId;
52
+ this.config = config;
53
+ this.writer = new DurableStream({
54
+ url: connection.url,
55
+ headers: connection.headers,
56
+ contentType: "application/json",
57
+ });
58
+ }
59
+ async emit(event) {
60
+ if (this.closed)
61
+ return;
62
+ const msg = { source: "server", ...event };
63
+ await this.writer.append(JSON.stringify(msg));
64
+ }
65
+ /**
66
+ * Send a follow-up user message to Claude Code by respawning with --resume.
67
+ * Used for iteration requests (the user types a new message in the UI).
68
+ */
69
+ async sendCommand(cmd) {
70
+ if (this.closed)
71
+ return;
72
+ // For iteration: respawn Claude Code with --resume
73
+ if (cmd.command === "iterate" && typeof cmd.request === "string") {
74
+ this.spawnClaude(cmd.request, this.claudeSessionId ?? undefined);
75
+ return;
76
+ }
77
+ // For initial "new" command: this is handled in start() via the prompt
78
+ // Other commands are ignored — Claude Code doesn't understand them
79
+ console.log(`[claude-code-docker] Ignoring unsupported command: ${cmd.command}`);
80
+ }
81
+ /**
82
+ * Send a gate response back to Claude Code as a user message.
83
+ * For ask_user_question gates, the user's answer becomes a follow-up message.
84
+ */
85
+ async sendGateResponse(gate, value) {
86
+ if (this.closed || !this.proc?.stdin?.writable)
87
+ return;
88
+ if (gate === "ask_user_question" || gate.startsWith("ask_user_question:")) {
89
+ const answer = value.answer || "";
90
+ this.writeUserMessage(answer);
91
+ return;
92
+ }
93
+ if (gate === "clarification") {
94
+ const answers = value.answers;
95
+ if (answers?.length) {
96
+ this.writeUserMessage(answers.join("\n"));
97
+ }
98
+ return;
99
+ }
100
+ if (gate === "approval") {
101
+ const decision = value.decision || "approve";
102
+ this.writeUserMessage(decision);
103
+ return;
104
+ }
105
+ if (gate === "continue") {
106
+ const proceed = value.proceed;
107
+ this.writeUserMessage(proceed ? "continue" : "stop");
108
+ return;
109
+ }
110
+ // Generic: send the value as JSON
111
+ this.writeUserMessage(JSON.stringify(value));
112
+ }
113
+ onAgentEvent(cb) {
114
+ this.agentEventCallbacks.push(cb);
115
+ }
116
+ onComplete(cb) {
117
+ this.completeCallbacks.push(cb);
118
+ }
119
+ async start() {
120
+ if (this.closed)
121
+ return;
122
+ this.spawnClaude(this.config.prompt);
123
+ }
124
+ close() {
125
+ this.closed = true;
126
+ if (this.proc) {
127
+ try {
128
+ this.proc.stdin?.end();
129
+ this.proc.kill("SIGTERM");
130
+ }
131
+ catch {
132
+ // Process may already be dead
133
+ }
134
+ this.proc = null;
135
+ }
136
+ }
137
+ // -----------------------------------------------------------------------
138
+ // Private helpers
139
+ // -----------------------------------------------------------------------
140
+ /**
141
+ * Spawn a new Claude Code process. Called for both the initial prompt
142
+ * and follow-up iterate messages (with --resume).
143
+ */
144
+ spawnClaude(prompt, resumeSessionId) {
145
+ // Kill any existing process
146
+ if (this.proc) {
147
+ try {
148
+ this.proc.stdin?.end();
149
+ this.proc.kill("SIGTERM");
150
+ }
151
+ catch {
152
+ // Already dead
153
+ }
154
+ this.proc = null;
155
+ }
156
+ // Reset parser state for the new process
157
+ this.parser = createStreamJsonParser();
158
+ this.resultReceived = false;
159
+ this.running = true;
160
+ const allowedTools = this.config.allowedTools ?? DEFAULT_ALLOWED_TOOLS;
161
+ const model = this.config.model ?? "claude-sonnet-4-6";
162
+ // Build the claude CLI command
163
+ const claudeArgs = [
164
+ "-p",
165
+ prompt,
166
+ "--output-format",
167
+ "stream-json",
168
+ "--verbose",
169
+ "--model",
170
+ model,
171
+ "--dangerously-skip-permissions",
172
+ "--allowedTools",
173
+ allowedTools.join(","),
174
+ ...(this.config.extraFlags ?? []),
175
+ ];
176
+ // Add --resume if we have a previous session ID
177
+ if (resumeSessionId) {
178
+ claudeArgs.push("--resume", resumeSessionId);
179
+ }
180
+ // Escape for bash
181
+ const escapedArgs = claudeArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
182
+ const cmd = `cd '${this.config.cwd}' && claude ${escapedArgs}`;
183
+ // Note: do NOT use -i flag — Claude Code detects interactive stdin and blocks
184
+ // waiting for input even when -p is provided. Without -i, stdout flows normally.
185
+ this.proc = spawn("docker", ["exec", this.containerId, "bash", "-c", cmd], {
186
+ stdio: ["pipe", "pipe", "pipe"],
187
+ });
188
+ console.log(`[claude-code-docker] Started: session=${this.sessionId} container=${this.containerId} pid=${this.proc.pid} resume=${resumeSessionId ?? "none"}`);
189
+ console.log(`[claude-code-docker] cmd: ${cmd}`);
190
+ const currentProc = this.proc;
191
+ // Read stdout line by line (stream-json NDJSON)
192
+ if (currentProc.stdout) {
193
+ const rl = readline.createInterface({
194
+ input: currentProc.stdout,
195
+ terminal: false,
196
+ });
197
+ rl.on("line", (line) => {
198
+ if (this.closed)
199
+ return;
200
+ console.log(`[claude-code-docker:stdout] ${line.slice(0, 120)}...`);
201
+ this.handleLine(line);
202
+ });
203
+ }
204
+ // Log stderr
205
+ if (currentProc.stderr) {
206
+ const stderrRl = readline.createInterface({
207
+ input: currentProc.stderr,
208
+ terminal: false,
209
+ });
210
+ stderrRl.on("line", (line) => {
211
+ if (!this.closed) {
212
+ console.error(`[claude-code-docker:stderr] ${line}`);
213
+ }
214
+ });
215
+ }
216
+ // Handle process exit
217
+ currentProc.on("exit", (code) => {
218
+ console.log(`[claude-code-docker] Process exited: code=${code} session=${this.sessionId}`);
219
+ // Capture session ID from parser state before marking not running
220
+ if (this.parser.state.sessionId) {
221
+ this.claudeSessionId = this.parser.state.sessionId;
222
+ }
223
+ this.running = false;
224
+ // Only emit session_end from exit handler if the parser didn't already
225
+ // emit one (via a "result" message). This prevents double session_end.
226
+ if (!this.closed && !this.resultReceived) {
227
+ const endEvent = {
228
+ type: "session_end",
229
+ success: code === 0,
230
+ ts: ts(),
231
+ };
232
+ this.dispatchEvent(endEvent);
233
+ }
234
+ });
235
+ }
236
+ handleLine(line) {
237
+ const trimmed = line.trim();
238
+ if (!trimmed)
239
+ return;
240
+ const events = this.parser.parse(trimmed);
241
+ for (const event of events) {
242
+ this.dispatchEvent(event);
243
+ }
244
+ }
245
+ dispatchEvent(event) {
246
+ // Write to Durable Stream for UI
247
+ const msg = { source: "agent", ...event };
248
+ this.writer.append(JSON.stringify(msg)).catch(() => { });
249
+ // Track session_end from result messages to prevent duplicates
250
+ if (event.type === "session_end") {
251
+ this.resultReceived = true;
252
+ }
253
+ // Detect dev:start in Bash tool_use → emit app_ready for the UI preview
254
+ if (event.type === "pre_tool_use" && event.tool_name === "Bash") {
255
+ const cmd = event.tool_input?.command;
256
+ if (typeof cmd === "string" && /\bdev:start\b/.test(cmd)) {
257
+ const appReady = { type: "app_ready", ts: ts() };
258
+ const appReadyMsg = { source: "agent", ...appReady };
259
+ this.writer.append(JSON.stringify(appReadyMsg)).catch(() => { });
260
+ for (const cb of this.agentEventCallbacks) {
261
+ try {
262
+ cb(appReady);
263
+ }
264
+ catch {
265
+ // Swallow
266
+ }
267
+ }
268
+ }
269
+ }
270
+ // Dispatch to callbacks
271
+ for (const cb of this.agentEventCallbacks) {
272
+ try {
273
+ cb(event);
274
+ }
275
+ catch {
276
+ // Swallow callback errors
277
+ }
278
+ }
279
+ // Detect session_end
280
+ if (event.type === "session_end" && "success" in event) {
281
+ const success = event.success;
282
+ for (const cb of this.completeCallbacks) {
283
+ try {
284
+ cb(success);
285
+ }
286
+ catch {
287
+ // Swallow callback errors
288
+ }
289
+ }
290
+ }
291
+ }
292
+ /**
293
+ * Write a user message to Claude Code's stdin in stream-json format.
294
+ */
295
+ writeUserMessage(content) {
296
+ if (!this.proc?.stdin?.writable)
297
+ return;
298
+ const msg = JSON.stringify({
299
+ type: "user",
300
+ message: { role: "user", content },
301
+ });
302
+ this.proc.stdin.write(`${msg}\n`);
303
+ }
304
+ }
305
+ //# sourceMappingURL=claude-code-docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code-docker.js","sourceRoot":"","sources":["../../src/bridge/claude-code-docker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * SessionBridge implementation that runs Claude Code CLI inside a Sprites
3
+ * sandbox via the Sprites SDK session API, communicating via stream-json NDJSON.
4
+ *
5
+ * The bridge translates Claude Code's stream-json output into EngineEvents
6
+ * and writes them to the Durable Stream for the UI. User messages and
7
+ * gate responses are sent to Claude Code's stdin.
8
+ *
9
+ * Claude Code runs in one-shot mode (`-p`) and exits after completing.
10
+ * On iterate (follow-up message), the bridge respawns Claude Code with
11
+ * `--resume <sessionId>` so it picks up the previous conversation context.
12
+ */
13
+ import type { EngineEvent } from "@electric-agent/protocol";
14
+ import type { Sprite } from "@fly/sprites";
15
+ import type { StreamConnectionInfo } from "../streams.js";
16
+ import type { SessionBridge } from "./types.js";
17
+ export interface ClaudeCodeSpritesConfig {
18
+ /** Initial prompt (the user's app description or task) */
19
+ prompt: string;
20
+ /** Working directory inside the sprite */
21
+ cwd: string;
22
+ /** Model to use (default: claude-sonnet-4-6) */
23
+ model?: string;
24
+ /** Allowed tools (default: all standard tools) */
25
+ allowedTools?: string[];
26
+ /** Additional CLI flags */
27
+ extraFlags?: string[];
28
+ }
29
+ export declare class ClaudeCodeSpritesBridge implements SessionBridge {
30
+ readonly sessionId: string;
31
+ readonly streamUrl: string;
32
+ readonly streamHeaders: Record<string, string>;
33
+ private sprite;
34
+ private config;
35
+ private writer;
36
+ private parser;
37
+ private agentEventCallbacks;
38
+ private completeCallbacks;
39
+ private closed;
40
+ private cmd;
41
+ /** Claude Code session ID captured from stream-json system.init — used for --resume */
42
+ private claudeSessionId;
43
+ /** Whether a Claude Code process is currently running */
44
+ private running;
45
+ /** Whether the parser already emitted a session_end (from a "result" message) */
46
+ private resultReceived;
47
+ constructor(sessionId: string, connection: StreamConnectionInfo, sprite: Sprite, config: ClaudeCodeSpritesConfig);
48
+ emit(event: EngineEvent): Promise<void>;
49
+ sendCommand(cmd: Record<string, unknown>): Promise<void>;
50
+ sendGateResponse(gate: string, value: Record<string, unknown>): Promise<void>;
51
+ onAgentEvent(cb: (event: EngineEvent) => void): void;
52
+ onComplete(cb: (success: boolean) => void): void;
53
+ start(): Promise<void>;
54
+ close(): void;
55
+ /**
56
+ * Spawn a new Claude Code process. Called for both the initial prompt
57
+ * and follow-up iterate messages (with --resume).
58
+ */
59
+ private spawnClaude;
60
+ private handleLine;
61
+ private dispatchEvent;
62
+ private writeUserMessage;
63
+ }
64
+ //# sourceMappingURL=claude-code-sprites.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code-sprites.d.ts","sourceRoot":"","sources":["../../src/bridge/claude-code-sprites.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAI9D,MAAM,WAAW,uBAAuB;IACvC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;IACd,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAA;IACX,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAcD,qBAAa,uBAAwB,YAAW,aAAa;IAC5D,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,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,mBAAmB,CAA0C;IACrE,OAAO,CAAC,iBAAiB,CAAwC;IACjE,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,GAAG,CAA6B;IAExC,uFAAuF;IACvF,OAAO,CAAC,eAAe,CAAsB;IAC7C,yDAAyD;IACzD,OAAO,CAAC,OAAO,CAAQ;IACvB,iFAAiF;IACjF,OAAO,CAAC,cAAc,CAAQ;gBAG7B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,uBAAuB;IAe1B,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;IAYxD,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCnF,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;IAK5B,KAAK,IAAI,IAAI;IAgBb;;;OAGG;IACH,OAAO,CAAC,WAAW;IAqGnB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,aAAa;IA8CrB,OAAO,CAAC,gBAAgB;CAQxB"}