@electric-agent/studio 1.0.0 → 1.1.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/active-sessions.d.ts +28 -0
- package/dist/active-sessions.d.ts.map +1 -0
- package/dist/active-sessions.js +50 -0
- package/dist/active-sessions.js.map +1 -0
- package/dist/bridge/claude-code-docker.d.ts +59 -0
- package/dist/bridge/claude-code-docker.d.ts.map +1 -0
- package/dist/bridge/claude-code-docker.js +258 -0
- package/dist/bridge/claude-code-docker.js.map +1 -0
- package/dist/bridge/claude-code-sprites.d.ts +49 -0
- package/dist/bridge/claude-code-sprites.d.ts.map +1 -0
- package/dist/bridge/claude-code-sprites.js +231 -0
- package/dist/bridge/claude-code-sprites.js.map +1 -0
- package/dist/bridge/claude-md-generator.d.ts +24 -0
- package/dist/bridge/claude-md-generator.d.ts.map +1 -0
- package/dist/bridge/claude-md-generator.js +299 -0
- package/dist/bridge/claude-md-generator.js.map +1 -0
- package/dist/bridge/index.d.ts +3 -0
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +3 -0
- package/dist/bridge/index.js.map +1 -1
- package/dist/bridge/stream-json-parser.d.ts +30 -0
- package/dist/bridge/stream-json-parser.d.ts.map +1 -0
- package/dist/bridge/stream-json-parser.js +207 -0
- package/dist/bridge/stream-json-parser.js.map +1 -0
- package/dist/client/assets/index-BeZ6CTGd.css +1 -0
- package/dist/client/assets/index-DRLXdDNp.js +241 -0
- package/dist/client/index.html +2 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/project-utils.d.ts +2 -1
- package/dist/project-utils.d.ts.map +1 -1
- package/dist/project-utils.js +2 -6
- package/dist/project-utils.js.map +1 -1
- package/dist/registry.d.ts +52 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +204 -0
- package/dist/registry.js.map +1 -0
- package/dist/room-registry.d.ts +40 -0
- package/dist/room-registry.d.ts.map +1 -0
- package/dist/room-registry.js +112 -0
- package/dist/room-registry.js.map +1 -0
- package/dist/sandbox/sprites-bootstrap.d.ts.map +1 -1
- package/dist/sandbox/sprites-bootstrap.js +7 -1
- package/dist/sandbox/sprites-bootstrap.js.map +1 -1
- package/dist/sandbox/sprites.d.ts +5 -0
- package/dist/sandbox/sprites.d.ts.map +1 -1
- package/dist/sandbox/sprites.js +22 -2
- package/dist/sandbox/sprites.js.map +1 -1
- package/dist/server.d.ts +9 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +616 -58
- package/dist/server.js.map +1 -1
- package/dist/sessions.d.ts +2 -0
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js.map +1 -1
- package/dist/shared-sessions.d.ts +16 -0
- package/dist/shared-sessions.d.ts.map +1 -0
- package/dist/shared-sessions.js +52 -0
- package/dist/shared-sessions.js.map +1 -0
- package/dist/streams.d.ts +8 -0
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +22 -0
- package/dist/streams.js.map +1 -1
- package/package.json +15 -2
- package/dist/client/assets/index-CK__1-6e.css +0 -1
- package/dist/client/assets/index-DKL-jl7t.js +0 -241
|
@@ -0,0 +1,231 @@
|
|
|
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
|
+
import * as readline from "node:readline";
|
|
10
|
+
import { DurableStream } from "@durable-streams/client";
|
|
11
|
+
import { ts } from "@electric-agent/protocol";
|
|
12
|
+
import { createStreamJsonParser } from "./stream-json-parser.js";
|
|
13
|
+
const SPRITES_SESSION_ID = "claude-code-session";
|
|
14
|
+
const DEFAULT_ALLOWED_TOOLS = [
|
|
15
|
+
"Read",
|
|
16
|
+
"Write",
|
|
17
|
+
"Edit",
|
|
18
|
+
"Bash",
|
|
19
|
+
"Glob",
|
|
20
|
+
"Grep",
|
|
21
|
+
"WebSearch",
|
|
22
|
+
"TodoWrite",
|
|
23
|
+
"AskUserQuestion",
|
|
24
|
+
];
|
|
25
|
+
export class ClaudeCodeSpritesBridge {
|
|
26
|
+
sessionId;
|
|
27
|
+
streamUrl;
|
|
28
|
+
streamHeaders;
|
|
29
|
+
sprite;
|
|
30
|
+
config;
|
|
31
|
+
writer;
|
|
32
|
+
parser = createStreamJsonParser();
|
|
33
|
+
agentEventCallbacks = [];
|
|
34
|
+
completeCallbacks = [];
|
|
35
|
+
closed = false;
|
|
36
|
+
cmd = null;
|
|
37
|
+
constructor(sessionId, connection, sprite, config) {
|
|
38
|
+
this.sessionId = sessionId;
|
|
39
|
+
this.streamUrl = connection.url;
|
|
40
|
+
this.streamHeaders = connection.headers;
|
|
41
|
+
this.sprite = sprite;
|
|
42
|
+
this.config = config;
|
|
43
|
+
this.writer = new DurableStream({
|
|
44
|
+
url: connection.url,
|
|
45
|
+
headers: connection.headers,
|
|
46
|
+
contentType: "application/json",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async emit(event) {
|
|
50
|
+
if (this.closed)
|
|
51
|
+
return;
|
|
52
|
+
const msg = { source: "server", ...event };
|
|
53
|
+
await this.writer.append(JSON.stringify(msg));
|
|
54
|
+
}
|
|
55
|
+
async sendCommand(cmd) {
|
|
56
|
+
if (this.closed || !this.cmd)
|
|
57
|
+
return;
|
|
58
|
+
if (cmd.command === "iterate" && typeof cmd.request === "string") {
|
|
59
|
+
this.writeUserMessage(cmd.request);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log(`[claude-code-sprites] Ignoring unsupported command: ${cmd.command}`);
|
|
63
|
+
}
|
|
64
|
+
async sendGateResponse(gate, value) {
|
|
65
|
+
if (this.closed || !this.cmd)
|
|
66
|
+
return;
|
|
67
|
+
if (gate === "ask_user_question" || gate.startsWith("ask_user_question:")) {
|
|
68
|
+
const answer = value.answer || "";
|
|
69
|
+
this.writeUserMessage(answer);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (gate === "clarification") {
|
|
73
|
+
const answers = value.answers;
|
|
74
|
+
if (answers?.length) {
|
|
75
|
+
this.writeUserMessage(answers.join("\n"));
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (gate === "approval") {
|
|
80
|
+
const decision = value.decision || "approve";
|
|
81
|
+
this.writeUserMessage(decision);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (gate === "continue") {
|
|
85
|
+
const proceed = value.proceed;
|
|
86
|
+
this.writeUserMessage(proceed ? "continue" : "stop");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.writeUserMessage(JSON.stringify(value));
|
|
90
|
+
}
|
|
91
|
+
onAgentEvent(cb) {
|
|
92
|
+
this.agentEventCallbacks.push(cb);
|
|
93
|
+
}
|
|
94
|
+
onComplete(cb) {
|
|
95
|
+
this.completeCallbacks.push(cb);
|
|
96
|
+
}
|
|
97
|
+
async start() {
|
|
98
|
+
if (this.closed)
|
|
99
|
+
return;
|
|
100
|
+
const allowedTools = this.config.allowedTools ?? DEFAULT_ALLOWED_TOOLS;
|
|
101
|
+
const model = this.config.model ?? "claude-sonnet-4-6";
|
|
102
|
+
// Build the claude CLI command
|
|
103
|
+
const claudeArgs = [
|
|
104
|
+
"-p",
|
|
105
|
+
this.config.prompt,
|
|
106
|
+
"--output-format",
|
|
107
|
+
"stream-json",
|
|
108
|
+
"--verbose",
|
|
109
|
+
"--model",
|
|
110
|
+
model,
|
|
111
|
+
"--dangerously-skip-permissions",
|
|
112
|
+
"--allowedTools",
|
|
113
|
+
allowedTools.join(","),
|
|
114
|
+
...(this.config.extraFlags ?? []),
|
|
115
|
+
];
|
|
116
|
+
// Escape for bash — use bash -c with properly escaped args
|
|
117
|
+
const escapedArgs = claudeArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
|
|
118
|
+
const fullCmd = `source /etc/profile.d/npm-global.sh 2>/dev/null; source /etc/profile.d/electric-agent.sh 2>/dev/null; cd '${this.config.cwd}' && claude ${escapedArgs}`;
|
|
119
|
+
this.cmd = this.sprite.createSession("bash", ["-c", fullCmd], {
|
|
120
|
+
detachable: true,
|
|
121
|
+
sessionId: SPRITES_SESSION_ID,
|
|
122
|
+
});
|
|
123
|
+
console.log(`[claude-code-sprites] Started: session=${this.sessionId}`);
|
|
124
|
+
// Read stdout line by line (stream-json NDJSON)
|
|
125
|
+
const rl = readline.createInterface({
|
|
126
|
+
input: this.cmd.stdout,
|
|
127
|
+
terminal: false,
|
|
128
|
+
});
|
|
129
|
+
rl.on("line", (line) => {
|
|
130
|
+
if (this.closed)
|
|
131
|
+
return;
|
|
132
|
+
this.handleLine(line);
|
|
133
|
+
});
|
|
134
|
+
// Log stderr
|
|
135
|
+
const stderrRl = readline.createInterface({
|
|
136
|
+
input: this.cmd.stderr,
|
|
137
|
+
terminal: false,
|
|
138
|
+
});
|
|
139
|
+
stderrRl.on("line", (line) => {
|
|
140
|
+
if (!this.closed) {
|
|
141
|
+
console.error(`[claude-code-sprites:stderr] ${line}`);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
// Handle process exit
|
|
145
|
+
this.cmd.on("exit", (code) => {
|
|
146
|
+
console.log(`[claude-code-sprites] Process exited: code=${code} session=${this.sessionId}`);
|
|
147
|
+
if (!this.closed) {
|
|
148
|
+
const endEvent = {
|
|
149
|
+
type: "session_end",
|
|
150
|
+
success: code === 0,
|
|
151
|
+
ts: ts(),
|
|
152
|
+
};
|
|
153
|
+
this.dispatchEvent(endEvent);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
close() {
|
|
158
|
+
this.closed = true;
|
|
159
|
+
if (this.cmd) {
|
|
160
|
+
try {
|
|
161
|
+
this.cmd.kill();
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Process may already be dead
|
|
165
|
+
}
|
|
166
|
+
this.cmd = null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// -----------------------------------------------------------------------
|
|
170
|
+
// Private helpers
|
|
171
|
+
// -----------------------------------------------------------------------
|
|
172
|
+
handleLine(line) {
|
|
173
|
+
const trimmed = line.trim();
|
|
174
|
+
if (!trimmed)
|
|
175
|
+
return;
|
|
176
|
+
const events = this.parser.parse(trimmed);
|
|
177
|
+
for (const event of events) {
|
|
178
|
+
this.dispatchEvent(event);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
dispatchEvent(event) {
|
|
182
|
+
const msg = { source: "agent", ...event };
|
|
183
|
+
this.writer.append(JSON.stringify(msg)).catch(() => { });
|
|
184
|
+
// Detect dev:start in Bash tool_use → emit app_ready for the UI preview
|
|
185
|
+
if (event.type === "pre_tool_use" && event.tool_name === "Bash") {
|
|
186
|
+
const cmd = event.tool_input?.command;
|
|
187
|
+
if (typeof cmd === "string" && /\bdev:start\b/.test(cmd)) {
|
|
188
|
+
const appReady = { type: "app_ready", ts: ts() };
|
|
189
|
+
const appReadyMsg = { source: "agent", ...appReady };
|
|
190
|
+
this.writer.append(JSON.stringify(appReadyMsg)).catch(() => { });
|
|
191
|
+
for (const cb of this.agentEventCallbacks) {
|
|
192
|
+
try {
|
|
193
|
+
cb(appReady);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Swallow
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
for (const cb of this.agentEventCallbacks) {
|
|
202
|
+
try {
|
|
203
|
+
cb(event);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Swallow callback errors
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (event.type === "session_end" && "success" in event) {
|
|
210
|
+
const success = event.success;
|
|
211
|
+
for (const cb of this.completeCallbacks) {
|
|
212
|
+
try {
|
|
213
|
+
cb(success);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Swallow callback errors
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
writeUserMessage(content) {
|
|
222
|
+
if (!this.cmd)
|
|
223
|
+
return;
|
|
224
|
+
const msg = JSON.stringify({
|
|
225
|
+
type: "user",
|
|
226
|
+
message: { role: "user", content },
|
|
227
|
+
});
|
|
228
|
+
this.cmd.stdin.write(`${msg}\n`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=claude-code-sprites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-sprites.js","sourceRoot":"","sources":["../../src/bridge/claude-code-sprites.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates CLAUDE.md files for project workspaces.
|
|
3
|
+
*
|
|
4
|
+
* Two variants:
|
|
5
|
+
* - `generateClaudeMd()` — for Claude Code mode (streamlined, no redundant instructions)
|
|
6
|
+
* - `generateElectricAgentClaudeMd()` — for electric-agent mode (full instructions for the SDK agent)
|
|
7
|
+
*/
|
|
8
|
+
export interface ClaudeMdOptions {
|
|
9
|
+
/** The user's app description */
|
|
10
|
+
description: string;
|
|
11
|
+
/** Project name (kebab-case) */
|
|
12
|
+
projectName: string;
|
|
13
|
+
/** Absolute path to the project inside the sandbox */
|
|
14
|
+
projectDir: string;
|
|
15
|
+
/** Whether this is an iteration (vs initial generation) */
|
|
16
|
+
isIteration?: boolean;
|
|
17
|
+
/** Iteration request text (if isIteration) */
|
|
18
|
+
iterationRequest?: string;
|
|
19
|
+
/** Sandbox runtime — affects environment-specific instructions */
|
|
20
|
+
runtime?: "docker" | "sprites" | "daytona";
|
|
21
|
+
}
|
|
22
|
+
export declare function generateClaudeMd(opts: ClaudeMdOptions): string;
|
|
23
|
+
export declare function generateElectricAgentClaudeMd(opts: ClaudeMdOptions): string;
|
|
24
|
+
//# sourceMappingURL=claude-md-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-md-generator.d.ts","sourceRoot":"","sources":["../../src/bridge/claude-md-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,eAAe;IAC/B,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAA;IAClB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,kEAAkE;IAClE,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAA;CAC1C;AAMD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CA8B9D;AAMD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAoC3E"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates CLAUDE.md files for project workspaces.
|
|
3
|
+
*
|
|
4
|
+
* Two variants:
|
|
5
|
+
* - `generateClaudeMd()` — for Claude Code mode (streamlined, no redundant instructions)
|
|
6
|
+
* - `generateElectricAgentClaudeMd()` — for electric-agent mode (full instructions for the SDK agent)
|
|
7
|
+
*/
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Claude Code variant
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export function generateClaudeMd(opts) {
|
|
12
|
+
const sections = [];
|
|
13
|
+
sections.push(`# ${opts.projectName}`);
|
|
14
|
+
sections.push("");
|
|
15
|
+
sections.push(PROJECT_CONTEXT);
|
|
16
|
+
sections.push("");
|
|
17
|
+
if (!opts.isIteration) {
|
|
18
|
+
sections.push("## Current Task");
|
|
19
|
+
sections.push(opts.description);
|
|
20
|
+
sections.push("");
|
|
21
|
+
}
|
|
22
|
+
sections.push(SCAFFOLD_STRUCTURE);
|
|
23
|
+
sections.push("");
|
|
24
|
+
sections.push(DRIZZLE_WORKFLOW);
|
|
25
|
+
sections.push("");
|
|
26
|
+
sections.push(GUARDRAILS);
|
|
27
|
+
sections.push("");
|
|
28
|
+
sections.push(PLAYBOOK_INSTRUCTIONS);
|
|
29
|
+
sections.push("");
|
|
30
|
+
sections.push(INFRASTRUCTURE);
|
|
31
|
+
sections.push("");
|
|
32
|
+
sections.push(devServerInstructions(opts.runtime));
|
|
33
|
+
sections.push("");
|
|
34
|
+
sections.push(SSR_RULES);
|
|
35
|
+
sections.push("");
|
|
36
|
+
return sections.join("\n");
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Electric Agent variant
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
export function generateElectricAgentClaudeMd(opts) {
|
|
42
|
+
const sections = [];
|
|
43
|
+
sections.push(`# ${opts.projectName}`);
|
|
44
|
+
sections.push("");
|
|
45
|
+
sections.push(PROJECT_CONTEXT);
|
|
46
|
+
sections.push("");
|
|
47
|
+
if (!opts.isIteration) {
|
|
48
|
+
sections.push("## Current Task");
|
|
49
|
+
sections.push(opts.description);
|
|
50
|
+
sections.push("");
|
|
51
|
+
}
|
|
52
|
+
sections.push(SCAFFOLD_STRUCTURE);
|
|
53
|
+
sections.push("");
|
|
54
|
+
sections.push(DRIZZLE_WORKFLOW);
|
|
55
|
+
sections.push("");
|
|
56
|
+
sections.push(GUARDRAILS);
|
|
57
|
+
sections.push("");
|
|
58
|
+
sections.push(PLAYBOOK_INSTRUCTIONS_AGENT);
|
|
59
|
+
sections.push("");
|
|
60
|
+
sections.push(BUILD_INSTRUCTIONS);
|
|
61
|
+
sections.push("");
|
|
62
|
+
sections.push(devServerInstructions(opts.runtime));
|
|
63
|
+
sections.push("");
|
|
64
|
+
sections.push(ARCHITECTURE_REFERENCE);
|
|
65
|
+
sections.push("");
|
|
66
|
+
sections.push(GIT_INSTRUCTIONS);
|
|
67
|
+
sections.push("");
|
|
68
|
+
sections.push(SSR_RULES);
|
|
69
|
+
sections.push("");
|
|
70
|
+
sections.push(ERROR_HANDLING);
|
|
71
|
+
sections.push("");
|
|
72
|
+
return sections.join("\n");
|
|
73
|
+
}
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Shared sections (used by both variants)
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
const PROJECT_CONTEXT = "## Project Context\nThis is a reactive, real-time application built with Electric SQL + TanStack DB + Drizzle ORM + TanStack Start.";
|
|
78
|
+
const SCAFFOLD_STRUCTURE = `## Scaffold Structure (DO NOT EXPLORE)
|
|
79
|
+
The project is scaffolded from a known template. DO NOT read or explore scaffold files before coding. You already know the structure:
|
|
80
|
+
- src/db/schema.ts — placeholder Drizzle schema (you will overwrite)
|
|
81
|
+
- src/db/zod-schemas.ts — placeholder Zod derivation (you will overwrite)
|
|
82
|
+
- src/db/index.ts — Drizzle client setup (do not modify)
|
|
83
|
+
- src/db/utils.ts — parseDates + generateTxId helpers (do not modify)
|
|
84
|
+
- src/lib/electric-proxy.ts — Electric shape proxy helper (do not modify)
|
|
85
|
+
- src/components/ClientOnly.tsx — SSR wrapper (do not modify, just import when needed)
|
|
86
|
+
- src/routes/__root.tsx — root layout with SSR (do not add ssr:false here)
|
|
87
|
+
- tests/helpers/schema-test-utils.ts — generateValidRow/generateRowWithout (do not modify)
|
|
88
|
+
|
|
89
|
+
DO NOT use Bash/ls/find to explore the project. DO NOT read files you aren't about to modify. Start writing code.`;
|
|
90
|
+
const DRIZZLE_WORKFLOW = `## Drizzle Workflow (CRITICAL)
|
|
91
|
+
Always follow this order:
|
|
92
|
+
1. Edit src/db/schema.ts (Drizzle pgTable definitions)
|
|
93
|
+
2. Edit src/db/zod-schemas.ts (derive Zod schemas via createSelectSchema/createInsertSchema from drizzle-zod — NEVER hand-write Zod schemas — ALWAYS import z from "zod/v4" and override ALL timestamp columns with z.union([z.date(), z.string()]).default(() => new Date()) — the .default() is required so collection.insert() works without timestamps)
|
|
94
|
+
3. Create collection files in src/db/collections/ (import from ../zod-schemas)
|
|
95
|
+
4. Create API routes (proxy + mutation)
|
|
96
|
+
5. Create UI components`;
|
|
97
|
+
const GUARDRAILS = `## Guardrails (MUST FOLLOW)
|
|
98
|
+
|
|
99
|
+
### Protected Files — DO NOT MODIFY
|
|
100
|
+
- docker-compose.yml
|
|
101
|
+
- tsconfig.json
|
|
102
|
+
- biome.json
|
|
103
|
+
- pnpm-lock.yaml
|
|
104
|
+
- postgres.conf
|
|
105
|
+
- vitest.config.ts
|
|
106
|
+
- Caddyfile
|
|
107
|
+
|
|
108
|
+
### Import Rules
|
|
109
|
+
- Use "zod/v4" (NOT "zod") for all Zod imports
|
|
110
|
+
- Use "lucide-react" for icons (NOT @radix-ui/react-icons)
|
|
111
|
+
- Use "@radix-ui/themes" for Radix components (NOT @radix-ui/react-*)
|
|
112
|
+
- Use "react-router" for routing (NOT react-router-dom)
|
|
113
|
+
|
|
114
|
+
### Dependency Rules
|
|
115
|
+
- NEVER remove existing dependencies from package.json
|
|
116
|
+
- Only add new dependencies
|
|
117
|
+
|
|
118
|
+
### Schema Rules
|
|
119
|
+
- ALL timestamp columns MUST use: z.union([z.date(), z.string()]).default(() => new Date())
|
|
120
|
+
- NEVER use z.coerce.date() — it breaks TanStack DB
|
|
121
|
+
- ALL tables MUST have REPLICA IDENTITY FULL (auto-applied by migration hook)
|
|
122
|
+
- UUID primary keys with defaultRandom()
|
|
123
|
+
- timestamp({ withTimezone: true }) for all dates
|
|
124
|
+
- snake_case for SQL table/column names
|
|
125
|
+
- Foreign keys with onDelete: "cascade" where appropriate`;
|
|
126
|
+
function devServerInstructions(runtime) {
|
|
127
|
+
if (runtime === "sprites" || runtime === "daytona") {
|
|
128
|
+
return `## Dev Server & Migrations
|
|
129
|
+
### Dev Server
|
|
130
|
+
- \`pnpm dev:start\` — start the Vite dev server in the background
|
|
131
|
+
- \`pnpm dev:stop\` — stop the dev server
|
|
132
|
+
- \`pnpm dev:restart\` — stop then start
|
|
133
|
+
|
|
134
|
+
The app is exposed on the VITE_PORT environment variable (default: 5173).
|
|
135
|
+
The database and Electric sync service are remote (cloud-hosted) — there is no local Postgres or Docker.
|
|
136
|
+
|
|
137
|
+
### Migrations (CRITICAL)
|
|
138
|
+
After modifying src/db/schema.ts, ALWAYS run migrations:
|
|
139
|
+
\`\`\`bash
|
|
140
|
+
pnpm drizzle-kit generate # generate SQL from schema changes
|
|
141
|
+
pnpm drizzle-kit migrate # apply migration to the database
|
|
142
|
+
\`\`\`
|
|
143
|
+
|
|
144
|
+
### Sprites Environment Gotchas
|
|
145
|
+
- 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\`
|
|
146
|
+
- Node.js is managed via nvm at \`/.sprite/languages/node/nvm/\`
|
|
147
|
+
- The sandbox is a cloud micro-VM — there is no Docker, no docker-compose, no local Postgres
|
|
148
|
+
- The database connection string is in DATABASE_URL (remote Neon Postgres)
|
|
149
|
+
|
|
150
|
+
### Workflow
|
|
151
|
+
After finishing ALL code generation: run migrations, then \`pnpm dev:start\` so the user can preview the app.`;
|
|
152
|
+
}
|
|
153
|
+
return `## Dev Server & Migrations
|
|
154
|
+
### Dev Server
|
|
155
|
+
- \`pnpm dev:start\` — start Vite + Postgres + Electric in the background
|
|
156
|
+
- \`pnpm dev:stop\` — stop all background services
|
|
157
|
+
- \`pnpm dev:restart\` — stop then start
|
|
158
|
+
|
|
159
|
+
The app is exposed on the VITE_PORT environment variable (default: 5173).
|
|
160
|
+
|
|
161
|
+
### Migrations (CRITICAL)
|
|
162
|
+
After modifying src/db/schema.ts, ALWAYS run migrations:
|
|
163
|
+
\`\`\`bash
|
|
164
|
+
pnpm dev:start # start Postgres (needed for migrate)
|
|
165
|
+
pnpm drizzle-kit generate # generate SQL from schema changes
|
|
166
|
+
pnpm drizzle-kit migrate # apply migration to the database
|
|
167
|
+
\`\`\`
|
|
168
|
+
|
|
169
|
+
### Workflow
|
|
170
|
+
After finishing ALL code generation: run migrations, then \`pnpm dev:start\` so the user can preview the app.`;
|
|
171
|
+
}
|
|
172
|
+
const SSR_RULES = `## SSR Configuration (CRITICAL)
|
|
173
|
+
NEVER add ssr: false to __root.tsx — it renders the HTML shell and must always SSR.
|
|
174
|
+
Instead, add ssr: false to each LEAF route that uses useLiveQuery or collections.
|
|
175
|
+
This is needed because useLiveQuery uses useSyncExternalStore without getServerSnapshot.`;
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// Claude Code–only sections
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
const PLAYBOOK_INSTRUCTIONS = `## Playbooks (Domain Knowledge — MUST READ)
|
|
180
|
+
Playbook SKILL.md files contain critical API usage patterns. Read them BEFORE writing code for each phase.
|
|
181
|
+
|
|
182
|
+
### Available Skills
|
|
183
|
+
Read with the Read tool at these exact paths:
|
|
184
|
+
|
|
185
|
+
**Electric SQL** (\`node_modules/@electric-sql/playbook/skills/\`):
|
|
186
|
+
- \`electric/SKILL.md\` — core Electric concepts and shape API
|
|
187
|
+
- \`electric-tanstack-integration/SKILL.md\` — how Electric + TanStack DB work together (READ FIRST)
|
|
188
|
+
- \`electric-quickstart/SKILL.md\` — quickstart patterns
|
|
189
|
+
- \`electric-security-check/SKILL.md\` — security best practices
|
|
190
|
+
- \`tanstack-start-quickstart/SKILL.md\` — TanStack Start framework patterns
|
|
191
|
+
- \`deploying-electric/SKILL.md\` — deployment configuration
|
|
192
|
+
- \`electric-go-live/SKILL.md\` — production checklist
|
|
193
|
+
|
|
194
|
+
**TanStack DB** (\`node_modules/@tanstack/db-playbook/skills/\`):
|
|
195
|
+
- \`tanstack-db/SKILL.md\` — collections, useLiveQuery, mutations (CRITICAL — read before writing any UI)
|
|
196
|
+
|
|
197
|
+
**Durable Streams** (\`node_modules/@durable-streams/playbook/skills/\`):
|
|
198
|
+
- \`durable-streams/SKILL.md\` — event streaming patterns
|
|
199
|
+
- \`durable-state/SKILL.md\` — state management
|
|
200
|
+
- \`durable-streams-dev-setup/SKILL.md\` — development setup
|
|
201
|
+
|
|
202
|
+
### Reading Order
|
|
203
|
+
1. \`electric-tanstack-integration/SKILL.md\` — integration rules and guardrails
|
|
204
|
+
2. \`tanstack-db/SKILL.md\` — collections, queries, mutations API
|
|
205
|
+
3. \`electric/SKILL.md\` — shape API for proxy routes
|
|
206
|
+
4. Other skills as needed for your current phase
|
|
207
|
+
|
|
208
|
+
### Important
|
|
209
|
+
- ONLY read playbooks relevant to your current phase
|
|
210
|
+
- Do NOT use include_references — the SKILL.md content is sufficient`;
|
|
211
|
+
const INFRASTRUCTURE = `## Infrastructure (Pre-configured — DO NOT MODIFY)
|
|
212
|
+
The database (Postgres) and Electric sync service are already provisioned and configured via environment variables:
|
|
213
|
+
- \`DATABASE_URL\` — Postgres connection string
|
|
214
|
+
- \`ELECTRIC_URL\` — Electric sync service URL
|
|
215
|
+
- \`ELECTRIC_SOURCE_ID\` / \`ELECTRIC_SECRET\` — Electric Cloud auth (if using cloud mode)
|
|
216
|
+
|
|
217
|
+
These are read by:
|
|
218
|
+
- \`src/db/index.ts\` — Drizzle client (DO NOT MODIFY)
|
|
219
|
+
- \`drizzle.config.ts\` — Drizzle Kit migrations (DO NOT MODIFY)
|
|
220
|
+
- \`src/lib/electric-proxy.ts\` — Electric shape proxy for API routes (DO NOT MODIFY)
|
|
221
|
+
|
|
222
|
+
You do NOT need to set up database connections or configure Electric. Just define your schema, run migrations, and write your app.`;
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
// Electric Agent–only sections
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
const PLAYBOOK_INSTRUCTIONS_AGENT = `## Playbooks (Domain Knowledge)
|
|
227
|
+
Playbook skill files are available in node_modules. Read them before implementing each phase:
|
|
228
|
+
|
|
229
|
+
### How to Read Playbooks
|
|
230
|
+
Use the Read tool to read playbook SKILL.md files:
|
|
231
|
+
- \`node_modules/@electric-sql/playbook/skills/<name>/SKILL.md\`
|
|
232
|
+
- \`node_modules/@tanstack/db-playbook/skills/<name>/SKILL.md\`
|
|
233
|
+
- \`node_modules/@durable-streams/playbook/skills/<name>/SKILL.md\`
|
|
234
|
+
|
|
235
|
+
### Required Reading Order
|
|
236
|
+
1. Read the electric-app-guardrails playbook FIRST (critical integration rules)
|
|
237
|
+
2. Read "schemas" before writing Drizzle schemas
|
|
238
|
+
3. Read "collections" before creating collection files
|
|
239
|
+
4. Read "mutations" before creating mutation routes
|
|
240
|
+
5. Read "live-queries" before creating UI with useLiveQuery
|
|
241
|
+
|
|
242
|
+
### Important
|
|
243
|
+
- ONLY read playbooks relevant to your current phase
|
|
244
|
+
- Do NOT use include_references — the SKILL.md content is sufficient`;
|
|
245
|
+
const BUILD_INSTRUCTIONS = `## Build & Test
|
|
246
|
+
Run these commands to verify your work:
|
|
247
|
+
- \`pnpm run build\` — TypeScript compilation
|
|
248
|
+
- \`pnpm run check\` — Biome lint + format check
|
|
249
|
+
- \`pnpm test\` — Run tests (if tests/ directory exists)
|
|
250
|
+
|
|
251
|
+
Build only twice during initial generation: once after finishing all code, once after tests.
|
|
252
|
+
During iterations, build after completing changes.`;
|
|
253
|
+
const ARCHITECTURE_REFERENCE = `## Architecture Reference
|
|
254
|
+
|
|
255
|
+
### Writing ARCHITECTURE.md (Initial Generation)
|
|
256
|
+
After ALL tasks are complete and the build passes, write ARCHITECTURE.md in the project root as your FINAL action. This is a concise navigation index — not documentation. Keep it under 1500 tokens.
|
|
257
|
+
|
|
258
|
+
Format:
|
|
259
|
+
\`\`\`
|
|
260
|
+
# [App Name] — Architecture Reference
|
|
261
|
+
_Last updated: [ISO date]_
|
|
262
|
+
|
|
263
|
+
## App Description
|
|
264
|
+
[1-2 sentences]
|
|
265
|
+
|
|
266
|
+
## Data Model
|
|
267
|
+
### [EntityName] (\`table_name\`)
|
|
268
|
+
- **Columns**: id (uuid PK), title (text), created_at (timestamptz)
|
|
269
|
+
- **Relations**: [none | field → table.id cascade]
|
|
270
|
+
- **Collection**: src/db/collections/[entity].ts
|
|
271
|
+
|
|
272
|
+
## API Routes
|
|
273
|
+
| Method | Path | File | Purpose |
|
|
274
|
+
|
|
275
|
+
## UI Routes & Components
|
|
276
|
+
| Route | File | Description |
|
|
277
|
+
|
|
278
|
+
### Key Components
|
|
279
|
+
- src/components/X.tsx — [one line: what it renders]
|
|
280
|
+
|
|
281
|
+
## Styling
|
|
282
|
+
- CSS files: [file: purpose]
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
### Using ARCHITECTURE.md (Iteration Mode)
|
|
286
|
+
On iterations, read ARCHITECTURE.md to understand the app structure. Use it to locate files — do NOT scan the filesystem.`;
|
|
287
|
+
const GIT_INSTRUCTIONS = `## Git & GitHub CLI
|
|
288
|
+
You have git and gh CLI available via Bash. Use them when needed:
|
|
289
|
+
- \`git status\` / \`git diff --stat\` — check current state
|
|
290
|
+
- \`git add -A && git commit -m "type(scope): description"\` — commit changes
|
|
291
|
+
- \`git push -u origin main\` — push to remote
|
|
292
|
+
- \`gh repo create "org/name" --private --source . --remote origin --push\` — create repo
|
|
293
|
+
- \`gh pr create --title "..." --body "..."\` — create PR
|
|
294
|
+
Commit types: feat, fix, refactor, style, chore, docs, test`;
|
|
295
|
+
const ERROR_HANDLING = `## Error Handling
|
|
296
|
+
Before fixing any error, check _agent/errors.md for previous attempts at the same fix.
|
|
297
|
+
If you see the same error has failed before, try a different approach.
|
|
298
|
+
After fixing an error, log the outcome.`;
|
|
299
|
+
//# sourceMappingURL=claude-md-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-md-generator.js","sourceRoot":"","sources":["../../src/bridge/claude-md-generator.ts"],"names":[],"mappings":"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"}
|
package/dist/bridge/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
export { ClaudeCodeDockerBridge, type ClaudeCodeDockerConfig } from "./claude-code-docker.js";
|
|
2
|
+
export { ClaudeCodeSpritesBridge, type ClaudeCodeSpritesConfig } from "./claude-code-sprites.js";
|
|
1
3
|
export { DaytonaSessionBridge } from "./daytona.js";
|
|
2
4
|
export { DockerStdioBridge } from "./docker-stdio.js";
|
|
3
5
|
export { HostedStreamBridge } from "./hosted.js";
|
|
4
6
|
export { SpritesStdioBridge } from "./sprites.js";
|
|
7
|
+
export { createStreamJsonParser } from "./stream-json-parser.js";
|
|
5
8
|
export type { AgentEvent, ServerCommand, ServerGateResponse, SessionBridge, StreamMessage, } from "./types.js";
|
|
6
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,YAAY,EACX,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,aAAa,GACb,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAC7F,OAAO,EAAE,uBAAuB,EAAE,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAChG,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAChE,YAAY,EACX,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,aAAa,GACb,MAAM,YAAY,CAAA"}
|
package/dist/bridge/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
export { ClaudeCodeDockerBridge } from "./claude-code-docker.js";
|
|
2
|
+
export { ClaudeCodeSpritesBridge } from "./claude-code-sprites.js";
|
|
1
3
|
export { DaytonaSessionBridge } from "./daytona.js";
|
|
2
4
|
export { DockerStdioBridge } from "./docker-stdio.js";
|
|
3
5
|
export { HostedStreamBridge } from "./hosted.js";
|
|
4
6
|
export { SpritesStdioBridge } from "./sprites.js";
|
|
7
|
+
export { createStreamJsonParser } from "./stream-json-parser.js";
|
|
5
8
|
//# sourceMappingURL=index.js.map
|
package/dist/bridge/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAA+B,MAAM,yBAAyB,CAAA;AAC7F,OAAO,EAAE,uBAAuB,EAAgC,MAAM,0BAA0B,CAAA;AAChG,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translates Claude Code `--output-format stream-json` NDJSON messages
|
|
3
|
+
* into EngineEvent arrays compatible with the existing bridge/UI pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code emits lines like:
|
|
6
|
+
* {"type":"system","subtype":"init","session_id":"...","tools":[...]}
|
|
7
|
+
* {"type":"assistant","message":{"content":[{"type":"text","text":"..."}]}}
|
|
8
|
+
* {"type":"user","message":{"content":[{"type":"tool_result","tool_use_id":"...","content":"..."}]}}
|
|
9
|
+
* {"type":"result","subtype":"success","cost_usd":0.12,"num_turns":5}
|
|
10
|
+
*
|
|
11
|
+
* This parser converts each line into zero or more EngineEvent objects.
|
|
12
|
+
*/
|
|
13
|
+
import type { EngineEvent } from "@electric-agent/protocol";
|
|
14
|
+
export interface StreamJsonParserState {
|
|
15
|
+
/** Map tool_use_id → tool_name for correlating post_tool_use events */
|
|
16
|
+
toolNames: Map<string, string>;
|
|
17
|
+
/** Accumulated cost from result messages */
|
|
18
|
+
totalCost: number;
|
|
19
|
+
/** Claude Code session ID from init */
|
|
20
|
+
sessionId: string | null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a new stateful parser. The returned `parse` function converts
|
|
24
|
+
* a single raw JSON line from Claude Code into zero or more EngineEvents.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createStreamJsonParser(): {
|
|
27
|
+
state: StreamJsonParserState;
|
|
28
|
+
parse(line: string): EngineEvent[];
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=stream-json-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-json-parser.d.ts","sourceRoot":"","sources":["../../src/bridge/stream-json-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AA+D3D,MAAM,WAAW,qBAAqB;IACrC,uEAAuE;IACvE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAA;IACjB,uCAAuC;IACvC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB;;gBASxB,MAAM,GAAG,WAAW,EAAE;EAInC"}
|