@electric-agent/studio 1.1.1 → 1.3.4
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/bridge/claude-code-docker.d.ts +14 -0
- package/dist/bridge/claude-code-docker.d.ts.map +1 -1
- package/dist/bridge/claude-code-docker.js +121 -22
- package/dist/bridge/claude-code-docker.js.map +1 -1
- package/dist/bridge/claude-code-sprites.d.ts +13 -1
- package/dist/bridge/claude-code-sprites.d.ts.map +1 -1
- package/dist/bridge/claude-code-sprites.js +122 -26
- package/dist/bridge/claude-code-sprites.js.map +1 -1
- package/dist/bridge/claude-md-generator.d.ts +1 -0
- package/dist/bridge/claude-md-generator.d.ts.map +1 -1
- package/dist/bridge/claude-md-generator.js +67 -12
- package/dist/bridge/claude-md-generator.js.map +1 -1
- package/dist/bridge/codex-docker.d.ts +65 -0
- package/dist/bridge/codex-docker.d.ts.map +1 -0
- package/dist/bridge/codex-docker.js +242 -0
- package/dist/bridge/codex-docker.js.map +1 -0
- package/dist/bridge/codex-json-parser.d.ts +31 -0
- package/dist/bridge/codex-json-parser.d.ts.map +1 -0
- package/dist/bridge/codex-json-parser.js +274 -0
- package/dist/bridge/codex-json-parser.js.map +1 -0
- package/dist/bridge/codex-md-generator.d.ts +14 -0
- package/dist/bridge/codex-md-generator.d.ts.map +1 -0
- package/dist/bridge/codex-md-generator.js +45 -0
- package/dist/bridge/codex-md-generator.js.map +1 -0
- package/dist/bridge/codex-sprites.d.ts +59 -0
- package/dist/bridge/codex-sprites.d.ts.map +1 -0
- package/dist/bridge/codex-sprites.js +237 -0
- package/dist/bridge/codex-sprites.js.map +1 -0
- package/dist/bridge/create-app-skill.d.ts +11 -0
- package/dist/bridge/create-app-skill.d.ts.map +1 -0
- package/dist/bridge/create-app-skill.js +39 -0
- package/dist/bridge/create-app-skill.js.map +1 -0
- package/dist/bridge/hosted.d.ts +1 -0
- 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/index.d.ts +0 -3
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +0 -3
- package/dist/bridge/index.js.map +1 -1
- package/dist/bridge/stream-json-parser.d.ts +0 -2
- package/dist/bridge/stream-json-parser.d.ts.map +1 -1
- package/dist/bridge/stream-json-parser.js +0 -18
- package/dist/bridge/stream-json-parser.js.map +1 -1
- package/dist/bridge/types.d.ts +6 -0
- package/dist/bridge/types.d.ts.map +1 -1
- package/dist/client/assets/index-B6arNdVE.css +1 -0
- package/dist/client/assets/index-CxBu-PUg.js +234 -0
- package/dist/client/index.html +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/sandbox/daytona.js +4 -4
- package/dist/sandbox/daytona.js.map +1 -1
- package/dist/sandbox/docker.d.ts +0 -1
- package/dist/sandbox/docker.d.ts.map +1 -1
- package/dist/sandbox/docker.js +10 -42
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/sprites.d.ts +0 -6
- package/dist/sandbox/sprites.d.ts.map +1 -1
- package/dist/sandbox/sprites.js +4 -36
- package/dist/sandbox/sprites.js.map +1 -1
- package/dist/sandbox/types.d.ts +0 -8
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/server.d.ts +2 -5
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +212 -161
- package/dist/server.js.map +1 -1
- package/dist/session-auth.d.ts +3 -0
- package/dist/session-auth.d.ts.map +1 -0
- package/dist/session-auth.js +11 -0
- package/dist/session-auth.js.map +1 -0
- package/dist/sessions.d.ts +0 -2
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js.map +1 -1
- package/package.json +2 -2
- package/dist/client/assets/index-BeZ6CTGd.css +0 -1
- package/dist/client/assets/index-DRLXdDNp.js +0 -241
|
@@ -14,10 +14,17 @@ export function generateClaudeMd(opts) {
|
|
|
14
14
|
sections.push("");
|
|
15
15
|
sections.push(PROJECT_CONTEXT);
|
|
16
16
|
sections.push("");
|
|
17
|
+
const sandbox = sandboxEnvironment(opts.runtime);
|
|
18
|
+
if (sandbox) {
|
|
19
|
+
sections.push(sandbox);
|
|
20
|
+
sections.push("");
|
|
21
|
+
}
|
|
17
22
|
if (!opts.isIteration) {
|
|
18
23
|
sections.push("## Current Task");
|
|
19
24
|
sections.push(opts.description);
|
|
20
25
|
sections.push("");
|
|
26
|
+
sections.push(SKILL_AUTO_TRIGGER);
|
|
27
|
+
sections.push("");
|
|
21
28
|
}
|
|
22
29
|
sections.push(SCAFFOLD_STRUCTURE);
|
|
23
30
|
sections.push("");
|
|
@@ -44,6 +51,11 @@ export function generateElectricAgentClaudeMd(opts) {
|
|
|
44
51
|
sections.push("");
|
|
45
52
|
sections.push(PROJECT_CONTEXT);
|
|
46
53
|
sections.push("");
|
|
54
|
+
const sandbox = sandboxEnvironment(opts.runtime);
|
|
55
|
+
if (sandbox) {
|
|
56
|
+
sections.push(sandbox);
|
|
57
|
+
sections.push("");
|
|
58
|
+
}
|
|
47
59
|
if (!opts.isIteration) {
|
|
48
60
|
sections.push("## Current Task");
|
|
49
61
|
sections.push(opts.description);
|
|
@@ -98,6 +110,7 @@ const GUARDRAILS = `## Guardrails (MUST FOLLOW)
|
|
|
98
110
|
|
|
99
111
|
### Protected Files — DO NOT MODIFY
|
|
100
112
|
- docker-compose.yml
|
|
113
|
+
- vite.config.ts (pre-configured with port, host, allowedHosts, and proxy — modifying it WILL break the preview)
|
|
101
114
|
- tsconfig.json
|
|
102
115
|
- biome.json
|
|
103
116
|
- pnpm-lock.yaml
|
|
@@ -111,9 +124,6 @@ const GUARDRAILS = `## Guardrails (MUST FOLLOW)
|
|
|
111
124
|
- Use "@radix-ui/themes" for Radix components (NOT @radix-ui/react-*)
|
|
112
125
|
- Use "react-router" for routing (NOT react-router-dom)
|
|
113
126
|
|
|
114
|
-
### Vite Config Rules
|
|
115
|
-
- When modifying vite.config.ts, ALWAYS preserve \`server: { allowedHosts: true }\` — without it, Vite rejects connections from the proxy URL
|
|
116
|
-
|
|
117
127
|
### Dependency Rules
|
|
118
128
|
- NEVER remove existing dependencies from package.json
|
|
119
129
|
- Only add new dependencies
|
|
@@ -126,15 +136,46 @@ const GUARDRAILS = `## Guardrails (MUST FOLLOW)
|
|
|
126
136
|
- timestamp({ withTimezone: true }) for all dates
|
|
127
137
|
- snake_case for SQL table/column names
|
|
128
138
|
- Foreign keys with onDelete: "cascade" where appropriate`;
|
|
139
|
+
function sandboxEnvironment(runtime) {
|
|
140
|
+
if (runtime === "sprites" || runtime === "daytona") {
|
|
141
|
+
return `## Sandbox Environment (IMPORTANT — READ FIRST)
|
|
142
|
+
You are running inside a cloud micro-VM (Fly.io Sprite). This is NOT a local machine.
|
|
143
|
+
|
|
144
|
+
### Networking & Port Exposure
|
|
145
|
+
- The Sprite HTTP proxy routes all external traffic to **port 8080** inside the VM
|
|
146
|
+
- Your app MUST listen on port 8080 to be accessible via the preview URL — this is pre-configured via the \`VITE_PORT\` environment variable
|
|
147
|
+
- The app MUST bind to \`0.0.0.0\` (not localhost) — pre-configured via \`host: true\` in vite.config.ts
|
|
148
|
+
- The preview URL follows the pattern: \`https://<sprite-name>.sprites.app\`
|
|
149
|
+
- There is NO way to expose other ports — only port 8080 is proxied
|
|
150
|
+
|
|
151
|
+
### What's Available
|
|
152
|
+
- Node.js (via nvm at \`/.sprite/languages/node/nvm/\`)
|
|
153
|
+
- pnpm, git, gh CLI
|
|
154
|
+
- Outbound internet access (npm install, API calls, etc.)
|
|
155
|
+
- \`DATABASE_URL\` — remote Postgres (Neon), no local database
|
|
156
|
+
|
|
157
|
+
### What's NOT Available
|
|
158
|
+
- Docker, docker-compose, or any container runtime
|
|
159
|
+
- Local Postgres or any local database
|
|
160
|
+
- Ports other than 8080 for external HTTP access
|
|
161
|
+
|
|
162
|
+
### PATH
|
|
163
|
+
- npm global binaries are NOT in PATH by default
|
|
164
|
+
- If you need a globally installed tool, source the profile first: \`source /etc/profile.d/npm-global.sh\``;
|
|
165
|
+
}
|
|
166
|
+
return "";
|
|
167
|
+
}
|
|
129
168
|
function devServerInstructions(runtime) {
|
|
130
169
|
if (runtime === "sprites" || runtime === "daytona") {
|
|
131
170
|
return `## Dev Server & Migrations
|
|
132
|
-
### Dev Server
|
|
171
|
+
### Dev Server (CRITICAL — use pnpm scripts ONLY)
|
|
133
172
|
- \`pnpm dev:start\` — start the Vite dev server in the background
|
|
134
173
|
- \`pnpm dev:stop\` — stop the dev server
|
|
135
174
|
- \`pnpm dev:restart\` — stop then start
|
|
136
175
|
|
|
137
|
-
|
|
176
|
+
**IMPORTANT**: Always use \`pnpm dev:start\` from the project directory. Do NOT use \`sprite-env services create\` or launch Vite manually — the project's vite.config.ts contains required settings (allowedHosts, port, proxy) that will not be applied if Vite is started from a different directory or with different arguments.
|
|
177
|
+
|
|
178
|
+
The app listens on port 8080 (set via VITE_PORT) — this is the only port the Sprite proxy exposes.
|
|
138
179
|
The database and Electric sync service are remote (cloud-hosted) — there is no local Postgres or Docker.
|
|
139
180
|
|
|
140
181
|
### Migrations (CRITICAL)
|
|
@@ -144,13 +185,6 @@ pnpm drizzle-kit generate # generate SQL from schema changes
|
|
|
144
185
|
pnpm drizzle-kit migrate # apply migration to the database
|
|
145
186
|
\`\`\`
|
|
146
187
|
|
|
147
|
-
### Sprites Environment Gotchas
|
|
148
|
-
- npm global binaries are NOT in PATH by default. If you need to run a globally installed tool, source the profile first: \`source /etc/profile.d/npm-global.sh\`
|
|
149
|
-
- Node.js is managed via nvm at \`/.sprite/languages/node/nvm/\`
|
|
150
|
-
- The sandbox is a cloud micro-VM — there is no Docker, no docker-compose, no local Postgres
|
|
151
|
-
- The database connection string is in DATABASE_URL (remote Neon Postgres)
|
|
152
|
-
- **CRITICAL**: vite.config.ts MUST have \`server: { allowedHosts: true }\` — without it, Vite rejects connections from the proxy URL and the preview will not work
|
|
153
|
-
|
|
154
188
|
### Workflow
|
|
155
189
|
After finishing ALL code generation: run migrations, then \`pnpm dev:start\` so the user can preview the app.`;
|
|
156
190
|
}
|
|
@@ -180,6 +214,22 @@ This is needed because useLiveQuery uses useSyncExternalStore without getServerS
|
|
|
180
214
|
// ---------------------------------------------------------------------------
|
|
181
215
|
// Claude Code–only sections
|
|
182
216
|
// ---------------------------------------------------------------------------
|
|
217
|
+
const SKILL_AUTO_TRIGGER = `## App Generation Pipeline (CRITICAL)
|
|
218
|
+
When building a new app, you MUST use the /create-app skill. This skill is available at .claude/skills/create-app/SKILL.md and provides the structured phased pipeline for generating Electric SQL apps.
|
|
219
|
+
|
|
220
|
+
Invoke it with: /create-app <description>
|
|
221
|
+
|
|
222
|
+
The skill enforces the correct phase order:
|
|
223
|
+
1. Clarification (if description is vague)
|
|
224
|
+
2. Plan generation (PLAN.md with data model + tasks)
|
|
225
|
+
3. Data model validation (schema + zod-schemas + tests — STOP if tests fail)
|
|
226
|
+
4. Collections & API routes
|
|
227
|
+
5. UI components
|
|
228
|
+
6. Build & lint
|
|
229
|
+
7. Final tests
|
|
230
|
+
8. Architecture reference (ARCHITECTURE.md)
|
|
231
|
+
|
|
232
|
+
Do NOT skip phases or code ad-hoc. Always follow the skill's structured pipeline.`;
|
|
183
233
|
const PLAYBOOK_INSTRUCTIONS = `## Playbooks (Domain Knowledge — MUST READ)
|
|
184
234
|
Playbook SKILL.md files contain critical API usage patterns. Read them BEFORE writing code for each phase.
|
|
185
235
|
|
|
@@ -296,6 +346,11 @@ You have git and gh CLI available via Bash. Use them when needed:
|
|
|
296
346
|
- \`gh repo create "org/name" --private --source . --remote origin --push\` — create repo
|
|
297
347
|
- \`gh pr create --title "..." --body "..."\` — create PR
|
|
298
348
|
Commit types: feat, fix, refactor, style, chore, docs, test`;
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
// Create-app skill content — exported so the server can write it to sandboxes
|
|
351
|
+
// where the npm-installed electric-agent may not include it yet.
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
export { createAppSkillContent } from "./create-app-skill.js";
|
|
299
354
|
const ERROR_HANDLING = `## Error Handling
|
|
300
355
|
Before fixing any error, check _agent/errors.md for previous attempts at the same fix.
|
|
301
356
|
If you see the same error has failed before, try a different approach.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-md-generator.js","sourceRoot":"","sources":["../../src/bridge/claude-md-generator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"claude-md-generator.js","sourceRoot":"","sources":["../../src/bridge/claude-md-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionBridge implementation that runs Codex CLI inside a Docker
|
|
3
|
+
* container via `docker exec -i`, communicating via exec --json NDJSON.
|
|
4
|
+
*
|
|
5
|
+
* The bridge translates Codex's exec --json output into EngineEvents
|
|
6
|
+
* and writes them to the Durable Stream for the UI.
|
|
7
|
+
*
|
|
8
|
+
* Codex runs in one-shot mode (`codex exec --json`) and exits after completing.
|
|
9
|
+
* On iterate (follow-up message), the bridge respawns Codex with the new prompt.
|
|
10
|
+
*/
|
|
11
|
+
import type { EngineEvent } from "@electric-agent/protocol";
|
|
12
|
+
import type { StreamConnectionInfo } from "../streams.js";
|
|
13
|
+
import type { SessionBridge } from "./types.js";
|
|
14
|
+
export interface CodexDockerConfig {
|
|
15
|
+
/** Initial prompt (the user's app description or task) */
|
|
16
|
+
prompt: string;
|
|
17
|
+
/** Working directory inside the container */
|
|
18
|
+
cwd: string;
|
|
19
|
+
/** Model to use (default: o4-mini) */
|
|
20
|
+
model?: string;
|
|
21
|
+
/** Additional CLI flags */
|
|
22
|
+
extraFlags?: string[];
|
|
23
|
+
}
|
|
24
|
+
export declare class CodexDockerBridge implements SessionBridge {
|
|
25
|
+
readonly sessionId: string;
|
|
26
|
+
readonly streamUrl: string;
|
|
27
|
+
readonly streamHeaders: Record<string, string>;
|
|
28
|
+
private containerId;
|
|
29
|
+
private config;
|
|
30
|
+
private writer;
|
|
31
|
+
private parser;
|
|
32
|
+
private agentEventCallbacks;
|
|
33
|
+
private completeCallbacks;
|
|
34
|
+
private closed;
|
|
35
|
+
private proc;
|
|
36
|
+
/** Codex thread ID captured from thread.started — used for resume */
|
|
37
|
+
private codexThreadId;
|
|
38
|
+
/** Whether a Codex process is currently running */
|
|
39
|
+
private running;
|
|
40
|
+
/** Whether the parser already emitted a session_end */
|
|
41
|
+
private resultReceived;
|
|
42
|
+
constructor(sessionId: string, connection: StreamConnectionInfo, containerId: string, config: CodexDockerConfig);
|
|
43
|
+
emit(event: EngineEvent): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Send a follow-up user message to Codex by respawning with a new prompt.
|
|
46
|
+
*/
|
|
47
|
+
sendCommand(cmd: Record<string, unknown>): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Send a gate response. Codex exec mode doesn't support stdin interaction,
|
|
50
|
+
* so gate responses are limited.
|
|
51
|
+
*/
|
|
52
|
+
sendGateResponse(_gate: string, _value: Record<string, unknown>): Promise<void>;
|
|
53
|
+
onAgentEvent(cb: (event: EngineEvent) => void): void;
|
|
54
|
+
onComplete(cb: (success: boolean) => void): void;
|
|
55
|
+
start(): Promise<void>;
|
|
56
|
+
close(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Spawn a new Codex process. Called for both the initial prompt
|
|
59
|
+
* and follow-up iterate messages.
|
|
60
|
+
*/
|
|
61
|
+
private spawnCodex;
|
|
62
|
+
private handleLine;
|
|
63
|
+
private dispatchEvent;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=codex-docker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-docker.d.ts","sourceRoot":"","sources":["../../src/bridge/codex-docker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;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,iBAAiB;IACjC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAA;IACX,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,qBAAa,iBAAkB,YAAW,aAAa;IACtD,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,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,mBAAmB,CAA0C;IACrE,OAAO,CAAC,iBAAiB,CAAwC;IACjE,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,IAAI,CAA4B;IAExC,qEAAqE;IACrE,OAAO,CAAC,aAAa,CAAsB;IAC3C,mDAAmD;IACnD,OAAO,CAAC,OAAO,CAAQ;IACvB,uDAAuD;IACvD,OAAO,CAAC,cAAc,CAAQ;gBAG7B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB;IAepB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7C;;OAEG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9D;;;OAGG;IACG,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrF,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,UAAU;IAgGlB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,aAAa;CAgDrB"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionBridge implementation that runs Codex CLI inside a Docker
|
|
3
|
+
* container via `docker exec -i`, communicating via exec --json NDJSON.
|
|
4
|
+
*
|
|
5
|
+
* The bridge translates Codex's exec --json output into EngineEvents
|
|
6
|
+
* and writes them to the Durable Stream for the UI.
|
|
7
|
+
*
|
|
8
|
+
* Codex runs in one-shot mode (`codex exec --json`) and exits after completing.
|
|
9
|
+
* On iterate (follow-up message), the bridge respawns Codex with the new prompt.
|
|
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";
|
|
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
|
+
}
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=codex-docker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-docker.js","sourceRoot":"","sources":["../../src/bridge/codex-docker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translates Codex CLI `codex exec --json` NDJSON messages
|
|
3
|
+
* into EngineEvent arrays compatible with the existing bridge/UI pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Codex exec --json emits lines like:
|
|
6
|
+
* {"type":"thread.started","thread_id":"..."}
|
|
7
|
+
* {"type":"item.started","item":{"type":"command_execution","id":"...","command":"..."}}
|
|
8
|
+
* {"type":"item.completed","item":{"type":"agent_message","id":"...","content":"..."}}
|
|
9
|
+
* {"type":"turn.completed","usage":{"input_tokens":100,"output_tokens":50}}
|
|
10
|
+
* {"type":"turn.failed","error":"..."}
|
|
11
|
+
*
|
|
12
|
+
* This parser converts each line into zero or more EngineEvent objects.
|
|
13
|
+
*/
|
|
14
|
+
import type { EngineEvent } from "@electric-agent/protocol";
|
|
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;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create a new stateful parser. The returned `parse` function converts
|
|
25
|
+
* a single raw JSON line from Codex into zero or more EngineEvents.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createCodexJsonParser(): {
|
|
28
|
+
state: CodexJsonParserState;
|
|
29
|
+
parse(line: string): EngineEvent[];
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=codex-json-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-json-parser.d.ts","sourceRoot":"","sources":["../../src/bridge/codex-json-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AA+F3D,MAAM,WAAW,oBAAoB;IACpC,uEAAuE;IACvE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB;;gBASvB,MAAM,GAAG,WAAW,EAAE;EAInC"}
|