chisel-studio 0.1.2 → 0.1.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/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -2
- package/dist/index.mjs.map +1 -1
- package/dist/ui/assets/index-CPVLBgk7.js +246 -0
- package/dist/ui/assets/index-fqnUS6Ov.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +2 -1
- package/dist/ui/assets/index-DI8TefNH.js +0 -2699
- package/dist/ui/assets/index-UB4FWL5j.css +0 -1
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -174,13 +174,23 @@ function resolveUiDir() {
|
|
|
174
174
|
if (fs.existsSync(path.join(fromSrc, "index.html"))) return fromSrc;
|
|
175
175
|
return fromDist;
|
|
176
176
|
}
|
|
177
|
-
function createStudioApp(engine) {
|
|
177
|
+
function createStudioApp(engine, options) {
|
|
178
|
+
const readOnly = options?.readOnly ?? false;
|
|
178
179
|
const app = new hono.Hono();
|
|
179
180
|
app.onError((err, c) => {
|
|
180
181
|
console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);
|
|
181
182
|
return c.json({ error: err.message }, 500);
|
|
182
183
|
});
|
|
183
184
|
app.use("*", cors.cors());
|
|
185
|
+
app.get("/api/config", (c) => c.json({ readOnly }));
|
|
186
|
+
if (readOnly) {
|
|
187
|
+
app.use("/api/*", async (c, next) => {
|
|
188
|
+
if (c.req.method === "POST") {
|
|
189
|
+
return c.json({ error: "Studio is in read-only mode" }, 403);
|
|
190
|
+
}
|
|
191
|
+
await next();
|
|
192
|
+
});
|
|
193
|
+
}
|
|
184
194
|
app.route("/api", createApiRoutes(engine));
|
|
185
195
|
app.route("/api", createSseRoute(engine));
|
|
186
196
|
app.get("*", createStaticHandler(resolveUiDir()));
|
|
@@ -192,7 +202,7 @@ function createStudio(engine, options = {}) {
|
|
|
192
202
|
const port = options.port ?? 4040;
|
|
193
203
|
const host = options.host ?? "localhost";
|
|
194
204
|
const url = `http://${host}:${port}`;
|
|
195
|
-
const app = createStudioApp(engine);
|
|
205
|
+
const app = createStudioApp(engine, { readOnly: options.readOnly });
|
|
196
206
|
let server = null;
|
|
197
207
|
return {
|
|
198
208
|
get url() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routes/api.ts","../src/routes/sse.ts","../src/static.ts","../src/server.ts","../src/index.ts"],"names":["Hono","streamSSE","join","existsSync","readFileSync","extname","cors","serve"],"mappings":"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","file":"index.js","sourcesContent":["import { Hono } from \"hono\";\nimport type { Engine } from \"chisel-engine\";\nimport type { RunStatus } from \"chisel-engine\";\n\nexport function createApiRoutes(engine: Engine): Hono {\n const app = new Hono();\n\n // Health check\n app.get(\"/health\", async (c) => {\n const health = await engine.health();\n return c.json(health, health.connected ? 200 : 503);\n });\n\n // List registered workflows\n app.get(\"/workflows\", (c) => {\n return c.json(engine.listWorkflows());\n });\n\n // List runs for a workflow\n app.get(\"/workflows/:id/runs\", async (c) => {\n const id = c.req.param(\"id\");\n const query = c.req.query();\n\n const result = await engine.listRuns(id, {\n limit: query.limit ? Number(query.limit) : undefined,\n cursor: query.cursor ? Number(query.cursor) : undefined,\n order: query.order as \"asc\" | \"desc\" | undefined,\n status: query.status as RunStatus | undefined,\n });\n\n return c.json(result);\n });\n\n // Get run detail\n app.get(\"/runs/:runId\", async (c) => {\n const runId = c.req.param(\"runId\");\n const run = await engine.getRun(runId);\n\n if (!run) {\n return c.json({ error: \"Run not found\" }, 404);\n }\n\n return c.json(run);\n });\n\n // Cancel a run\n app.post(\"/runs/:runId/cancel\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.cancelRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Retry a failed run\n app.post(\"/runs/:runId/retry\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.retryRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Trigger a workflow\n app.post(\"/workflows/:id/trigger\", async (c) => {\n const id = c.req.param(\"id\");\n\n try {\n const body = await c.req.json();\n const { runId } = await engine.trigger(id, body);\n return c.json({ runId }, 202);\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n return app;\n}\n","import { Hono } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { Engine, EngineEventName } from \"chisel-engine\";\n\nconst ENGINE_EVENTS: EngineEventName[] = [\n \"workflow:start\",\n \"workflow:complete\",\n \"workflow:fail\",\n \"step:start\",\n \"step:complete\",\n \"step:fail\",\n \"step:retry\",\n];\n\nexport function createSseRoute(engine: Engine): Hono {\n const app = new Hono();\n\n app.get(\"/events\", (c) => {\n return streamSSE(c, async (stream) => {\n const handlers = new Map<string, (payload: unknown) => void>();\n\n for (const event of ENGINE_EVENTS) {\n const handler = (payload: unknown) => {\n stream\n .writeSSE({\n event,\n data: JSON.stringify(payload, (_key, value) =>\n value instanceof Error\n ? { message: value.message, name: value.name }\n : value\n ),\n })\n .catch(() => {});\n };\n handlers.set(event, handler);\n engine.on(event, handler as any);\n }\n\n // Heartbeat every 15 seconds\n const heartbeat = setInterval(() => {\n stream\n .writeSSE({\n event: \"heartbeat\",\n data: JSON.stringify({ time: Date.now() }),\n })\n .catch(() => {});\n }, 15_000);\n\n // Keep the stream alive until client disconnects\n try {\n while (true) {\n await stream.sleep(1000);\n }\n } finally {\n clearInterval(heartbeat);\n for (const [event, handler] of handlers) {\n engine.off(event as EngineEventName, handler as any);\n }\n }\n });\n });\n\n return app;\n}\n","import { readFileSync, existsSync } from \"fs\";\nimport { join, extname } from \"path\";\nimport type { Context } from \"hono\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".mjs\": \"application/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport function createStaticHandler(uiDir: string) {\n // Pre-load index.html into memory (small file, hot path)\n const indexPath = join(uiDir, \"index.html\");\n let indexHtml = \"\";\n if (existsSync(indexPath)) {\n indexHtml = readFileSync(indexPath, \"utf-8\");\n }\n\n return async (c: Context) => {\n const reqPath = new URL(c.req.url).pathname;\n\n // Try serving static asset\n const filePath = join(uiDir, reqPath);\n if (existsSync(filePath) && reqPath !== \"/\") {\n try {\n const content = readFileSync(filePath);\n const ext = extname(filePath);\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n return new Response(content, {\n headers: {\n \"Content-Type\": contentType,\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n },\n });\n } catch {\n // Fall through to index.html\n }\n }\n\n // SPA fallback: serve index.html for all non-file routes\n if (!indexHtml) {\n return c.text(\"Studio UI not built. Run: bun run build:ui\", 500);\n }\n return c.html(indexHtml);\n };\n}\n","import { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { join } from \"path\";\nimport { existsSync } from \"fs\";\nimport type { Engine } from \"chisel-engine\";\nimport { createApiRoutes } from \"./routes/api\";\nimport { createSseRoute } from \"./routes/sse\";\nimport { createStaticHandler } from \"./static\";\n\nfunction resolveUiDir(): string {\n // When running from built output: __dirname is dist/, ui is dist/ui/\n const fromDist = join(__dirname, \"ui\");\n if (existsSync(join(fromDist, \"index.html\"))) return fromDist;\n\n // When running from source via bun/tsx: __dirname is src/, ui is ../dist/ui/\n const fromSrc = join(__dirname, \"..\", \"dist\", \"ui\");\n if (existsSync(join(fromSrc, \"index.html\"))) return fromSrc;\n\n // Fallback\n return fromDist;\n}\n\nexport function createStudioApp(engine: Engine): Hono {\n const app = new Hono();\n\n app.onError((err, c) => {\n console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);\n return c.json({ error: err.message }, 500);\n });\n\n // Enable CORS for development\n app.use(\"*\", cors());\n\n // API routes\n app.route(\"/api\", createApiRoutes(engine));\n\n // SSE events\n app.route(\"/api\", createSseRoute(engine));\n\n // Static SPA assets\n app.get(\"*\", createStaticHandler(resolveUiDir()));\n\n return app;\n}\n","import { serve } from \"@hono/node-server\";\nimport type { Engine } from \"chisel-engine\";\nimport { createStudioApp } from \"./server\";\nimport type { StudioOptions, StudioServer } from \"./types\";\n\nexport type { StudioOptions, StudioServer } from \"./types\";\n\nexport function createStudio(\n engine: Engine,\n options: StudioOptions = {}\n): StudioServer {\n const port = options.port ?? 4040;\n const host = options.host ?? \"localhost\";\n const url = `http://${host}:${port}`;\n\n const app = createStudioApp(engine);\n let server: ReturnType<typeof serve> | null = null;\n\n return {\n get url() {\n return url;\n },\n\n async start() {\n server = serve({ fetch: app.fetch, port, hostname: host });\n\n console.log(`Chisel Studio running at ${url}`);\n\n if (options.open) {\n const { exec } = await import(\"child_process\");\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n exec(`${cmd} ${url}`);\n }\n },\n\n async stop() {\n if (server) {\n server.close();\n server = null;\n }\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/routes/api.ts","../src/routes/sse.ts","../src/static.ts","../src/server.ts","../src/index.ts"],"names":["Hono","streamSSE","join","existsSync","readFileSync","extname","cors","serve"],"mappings":"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","file":"index.js","sourcesContent":["import { Hono } from \"hono\";\nimport type { Engine } from \"chisel-engine\";\nimport type { RunStatus } from \"chisel-engine\";\n\nexport function createApiRoutes(engine: Engine): Hono {\n const app = new Hono();\n\n // Health check\n app.get(\"/health\", async (c) => {\n const health = await engine.health();\n return c.json(health, health.connected ? 200 : 503);\n });\n\n // List registered workflows\n app.get(\"/workflows\", (c) => {\n return c.json(engine.listWorkflows());\n });\n\n // List runs for a workflow\n app.get(\"/workflows/:id/runs\", async (c) => {\n const id = c.req.param(\"id\");\n const query = c.req.query();\n\n const result = await engine.listRuns(id, {\n limit: query.limit ? Number(query.limit) : undefined,\n cursor: query.cursor ? Number(query.cursor) : undefined,\n order: query.order as \"asc\" | \"desc\" | undefined,\n status: query.status as RunStatus | undefined,\n });\n\n return c.json(result);\n });\n\n // Get run detail\n app.get(\"/runs/:runId\", async (c) => {\n const runId = c.req.param(\"runId\");\n const run = await engine.getRun(runId);\n\n if (!run) {\n return c.json({ error: \"Run not found\" }, 404);\n }\n\n return c.json(run);\n });\n\n // Cancel a run\n app.post(\"/runs/:runId/cancel\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.cancelRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Retry a failed run\n app.post(\"/runs/:runId/retry\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.retryRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Trigger a workflow\n app.post(\"/workflows/:id/trigger\", async (c) => {\n const id = c.req.param(\"id\");\n\n try {\n const body = await c.req.json();\n const { runId } = await engine.trigger(id, body);\n return c.json({ runId }, 202);\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n return app;\n}\n","import { Hono } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { Engine, EngineEventName } from \"chisel-engine\";\n\nconst ENGINE_EVENTS: EngineEventName[] = [\n \"workflow:start\",\n \"workflow:complete\",\n \"workflow:fail\",\n \"step:start\",\n \"step:complete\",\n \"step:fail\",\n \"step:retry\",\n];\n\nexport function createSseRoute(engine: Engine): Hono {\n const app = new Hono();\n\n app.get(\"/events\", (c) => {\n return streamSSE(c, async (stream) => {\n const handlers = new Map<string, (payload: unknown) => void>();\n\n for (const event of ENGINE_EVENTS) {\n const handler = (payload: unknown) => {\n stream\n .writeSSE({\n event,\n data: JSON.stringify(payload, (_key, value) =>\n value instanceof Error\n ? { message: value.message, name: value.name }\n : value\n ),\n })\n .catch(() => {});\n };\n handlers.set(event, handler);\n engine.on(event, handler as any);\n }\n\n // Heartbeat every 15 seconds\n const heartbeat = setInterval(() => {\n stream\n .writeSSE({\n event: \"heartbeat\",\n data: JSON.stringify({ time: Date.now() }),\n })\n .catch(() => {});\n }, 15_000);\n\n // Keep the stream alive until client disconnects\n try {\n while (true) {\n await stream.sleep(1000);\n }\n } finally {\n clearInterval(heartbeat);\n for (const [event, handler] of handlers) {\n engine.off(event as EngineEventName, handler as any);\n }\n }\n });\n });\n\n return app;\n}\n","import { readFileSync, existsSync } from \"fs\";\nimport { join, extname } from \"path\";\nimport type { Context } from \"hono\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".mjs\": \"application/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport function createStaticHandler(uiDir: string) {\n // Pre-load index.html into memory (small file, hot path)\n const indexPath = join(uiDir, \"index.html\");\n let indexHtml = \"\";\n if (existsSync(indexPath)) {\n indexHtml = readFileSync(indexPath, \"utf-8\");\n }\n\n return async (c: Context) => {\n const reqPath = new URL(c.req.url).pathname;\n\n // Try serving static asset\n const filePath = join(uiDir, reqPath);\n if (existsSync(filePath) && reqPath !== \"/\") {\n try {\n const content = readFileSync(filePath);\n const ext = extname(filePath);\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n return new Response(content, {\n headers: {\n \"Content-Type\": contentType,\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n },\n });\n } catch {\n // Fall through to index.html\n }\n }\n\n // SPA fallback: serve index.html for all non-file routes\n if (!indexHtml) {\n return c.text(\"Studio UI not built. Run: bun run build:ui\", 500);\n }\n return c.html(indexHtml);\n };\n}\n","import { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { join } from \"path\";\nimport { existsSync } from \"fs\";\nimport type { Engine } from \"chisel-engine\";\nimport { createApiRoutes } from \"./routes/api\";\nimport { createSseRoute } from \"./routes/sse\";\nimport { createStaticHandler } from \"./static\";\n\nfunction resolveUiDir(): string {\n // When running from built output: __dirname is dist/, ui is dist/ui/\n const fromDist = join(__dirname, \"ui\");\n if (existsSync(join(fromDist, \"index.html\"))) return fromDist;\n\n // When running from source via bun/tsx: __dirname is src/, ui is ../dist/ui/\n const fromSrc = join(__dirname, \"..\", \"dist\", \"ui\");\n if (existsSync(join(fromSrc, \"index.html\"))) return fromSrc;\n\n // Fallback\n return fromDist;\n}\n\nexport function createStudioApp(\n engine: Engine,\n options?: { readOnly?: boolean }\n): Hono {\n const readOnly = options?.readOnly ?? false;\n const app = new Hono();\n\n app.onError((err, c) => {\n console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);\n return c.json({ error: err.message }, 500);\n });\n\n // Enable CORS for development\n app.use(\"*\", cors());\n\n // Config endpoint\n app.get(\"/api/config\", (c) => c.json({ readOnly }));\n\n // Block mutations in read-only mode\n if (readOnly) {\n app.use(\"/api/*\", async (c, next) => {\n if (c.req.method === \"POST\") {\n return c.json({ error: \"Studio is in read-only mode\" }, 403);\n }\n await next();\n });\n }\n\n // API routes\n app.route(\"/api\", createApiRoutes(engine));\n\n // SSE events\n app.route(\"/api\", createSseRoute(engine));\n\n // Static SPA assets\n app.get(\"*\", createStaticHandler(resolveUiDir()));\n\n return app;\n}\n","import { serve } from \"@hono/node-server\";\nimport type { Engine } from \"chisel-engine\";\nimport { createStudioApp } from \"./server\";\nimport type { StudioOptions, StudioServer } from \"./types\";\n\nexport type { StudioOptions, StudioServer } from \"./types\";\n\nexport function createStudio(\n engine: Engine,\n options: StudioOptions = {}\n): StudioServer {\n const port = options.port ?? 4040;\n const host = options.host ?? \"localhost\";\n const url = `http://${host}:${port}`;\n\n const app = createStudioApp(engine, { readOnly: options.readOnly });\n let server: ReturnType<typeof serve> | null = null;\n\n return {\n get url() {\n return url;\n },\n\n async start() {\n server = serve({ fetch: app.fetch, port, hostname: host });\n\n console.log(`Chisel Studio running at ${url}`);\n\n if (options.open) {\n const { exec } = await import(\"child_process\");\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n exec(`${cmd} ${url}`);\n }\n },\n\n async stop() {\n if (server) {\n server.close();\n server = null;\n }\n },\n };\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -172,13 +172,23 @@ function resolveUiDir() {
|
|
|
172
172
|
if (existsSync(join(fromSrc, "index.html"))) return fromSrc;
|
|
173
173
|
return fromDist;
|
|
174
174
|
}
|
|
175
|
-
function createStudioApp(engine) {
|
|
175
|
+
function createStudioApp(engine, options) {
|
|
176
|
+
const readOnly = options?.readOnly ?? false;
|
|
176
177
|
const app = new Hono();
|
|
177
178
|
app.onError((err, c) => {
|
|
178
179
|
console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);
|
|
179
180
|
return c.json({ error: err.message }, 500);
|
|
180
181
|
});
|
|
181
182
|
app.use("*", cors());
|
|
183
|
+
app.get("/api/config", (c) => c.json({ readOnly }));
|
|
184
|
+
if (readOnly) {
|
|
185
|
+
app.use("/api/*", async (c, next) => {
|
|
186
|
+
if (c.req.method === "POST") {
|
|
187
|
+
return c.json({ error: "Studio is in read-only mode" }, 403);
|
|
188
|
+
}
|
|
189
|
+
await next();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
182
192
|
app.route("/api", createApiRoutes(engine));
|
|
183
193
|
app.route("/api", createSseRoute(engine));
|
|
184
194
|
app.get("*", createStaticHandler(resolveUiDir()));
|
|
@@ -190,7 +200,7 @@ function createStudio(engine, options = {}) {
|
|
|
190
200
|
const port = options.port ?? 4040;
|
|
191
201
|
const host = options.host ?? "localhost";
|
|
192
202
|
const url = `http://${host}:${port}`;
|
|
193
|
-
const app = createStudioApp(engine);
|
|
203
|
+
const app = createStudioApp(engine, { readOnly: options.readOnly });
|
|
194
204
|
let server = null;
|
|
195
205
|
return {
|
|
196
206
|
get url() {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routes/api.ts","../src/routes/sse.ts","../src/static.ts","../src/server.ts","../src/index.ts"],"names":["Hono","join","existsSync"],"mappings":"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","file":"index.mjs","sourcesContent":["import { Hono } from \"hono\";\nimport type { Engine } from \"chisel-engine\";\nimport type { RunStatus } from \"chisel-engine\";\n\nexport function createApiRoutes(engine: Engine): Hono {\n const app = new Hono();\n\n // Health check\n app.get(\"/health\", async (c) => {\n const health = await engine.health();\n return c.json(health, health.connected ? 200 : 503);\n });\n\n // List registered workflows\n app.get(\"/workflows\", (c) => {\n return c.json(engine.listWorkflows());\n });\n\n // List runs for a workflow\n app.get(\"/workflows/:id/runs\", async (c) => {\n const id = c.req.param(\"id\");\n const query = c.req.query();\n\n const result = await engine.listRuns(id, {\n limit: query.limit ? Number(query.limit) : undefined,\n cursor: query.cursor ? Number(query.cursor) : undefined,\n order: query.order as \"asc\" | \"desc\" | undefined,\n status: query.status as RunStatus | undefined,\n });\n\n return c.json(result);\n });\n\n // Get run detail\n app.get(\"/runs/:runId\", async (c) => {\n const runId = c.req.param(\"runId\");\n const run = await engine.getRun(runId);\n\n if (!run) {\n return c.json({ error: \"Run not found\" }, 404);\n }\n\n return c.json(run);\n });\n\n // Cancel a run\n app.post(\"/runs/:runId/cancel\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.cancelRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Retry a failed run\n app.post(\"/runs/:runId/retry\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.retryRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Trigger a workflow\n app.post(\"/workflows/:id/trigger\", async (c) => {\n const id = c.req.param(\"id\");\n\n try {\n const body = await c.req.json();\n const { runId } = await engine.trigger(id, body);\n return c.json({ runId }, 202);\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n return app;\n}\n","import { Hono } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { Engine, EngineEventName } from \"chisel-engine\";\n\nconst ENGINE_EVENTS: EngineEventName[] = [\n \"workflow:start\",\n \"workflow:complete\",\n \"workflow:fail\",\n \"step:start\",\n \"step:complete\",\n \"step:fail\",\n \"step:retry\",\n];\n\nexport function createSseRoute(engine: Engine): Hono {\n const app = new Hono();\n\n app.get(\"/events\", (c) => {\n return streamSSE(c, async (stream) => {\n const handlers = new Map<string, (payload: unknown) => void>();\n\n for (const event of ENGINE_EVENTS) {\n const handler = (payload: unknown) => {\n stream\n .writeSSE({\n event,\n data: JSON.stringify(payload, (_key, value) =>\n value instanceof Error\n ? { message: value.message, name: value.name }\n : value\n ),\n })\n .catch(() => {});\n };\n handlers.set(event, handler);\n engine.on(event, handler as any);\n }\n\n // Heartbeat every 15 seconds\n const heartbeat = setInterval(() => {\n stream\n .writeSSE({\n event: \"heartbeat\",\n data: JSON.stringify({ time: Date.now() }),\n })\n .catch(() => {});\n }, 15_000);\n\n // Keep the stream alive until client disconnects\n try {\n while (true) {\n await stream.sleep(1000);\n }\n } finally {\n clearInterval(heartbeat);\n for (const [event, handler] of handlers) {\n engine.off(event as EngineEventName, handler as any);\n }\n }\n });\n });\n\n return app;\n}\n","import { readFileSync, existsSync } from \"fs\";\nimport { join, extname } from \"path\";\nimport type { Context } from \"hono\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".mjs\": \"application/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport function createStaticHandler(uiDir: string) {\n // Pre-load index.html into memory (small file, hot path)\n const indexPath = join(uiDir, \"index.html\");\n let indexHtml = \"\";\n if (existsSync(indexPath)) {\n indexHtml = readFileSync(indexPath, \"utf-8\");\n }\n\n return async (c: Context) => {\n const reqPath = new URL(c.req.url).pathname;\n\n // Try serving static asset\n const filePath = join(uiDir, reqPath);\n if (existsSync(filePath) && reqPath !== \"/\") {\n try {\n const content = readFileSync(filePath);\n const ext = extname(filePath);\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n return new Response(content, {\n headers: {\n \"Content-Type\": contentType,\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n },\n });\n } catch {\n // Fall through to index.html\n }\n }\n\n // SPA fallback: serve index.html for all non-file routes\n if (!indexHtml) {\n return c.text(\"Studio UI not built. Run: bun run build:ui\", 500);\n }\n return c.html(indexHtml);\n };\n}\n","import { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { join } from \"path\";\nimport { existsSync } from \"fs\";\nimport type { Engine } from \"chisel-engine\";\nimport { createApiRoutes } from \"./routes/api\";\nimport { createSseRoute } from \"./routes/sse\";\nimport { createStaticHandler } from \"./static\";\n\nfunction resolveUiDir(): string {\n // When running from built output: __dirname is dist/, ui is dist/ui/\n const fromDist = join(__dirname, \"ui\");\n if (existsSync(join(fromDist, \"index.html\"))) return fromDist;\n\n // When running from source via bun/tsx: __dirname is src/, ui is ../dist/ui/\n const fromSrc = join(__dirname, \"..\", \"dist\", \"ui\");\n if (existsSync(join(fromSrc, \"index.html\"))) return fromSrc;\n\n // Fallback\n return fromDist;\n}\n\nexport function createStudioApp(engine: Engine): Hono {\n const app = new Hono();\n\n app.onError((err, c) => {\n console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);\n return c.json({ error: err.message }, 500);\n });\n\n // Enable CORS for development\n app.use(\"*\", cors());\n\n // API routes\n app.route(\"/api\", createApiRoutes(engine));\n\n // SSE events\n app.route(\"/api\", createSseRoute(engine));\n\n // Static SPA assets\n app.get(\"*\", createStaticHandler(resolveUiDir()));\n\n return app;\n}\n","import { serve } from \"@hono/node-server\";\nimport type { Engine } from \"chisel-engine\";\nimport { createStudioApp } from \"./server\";\nimport type { StudioOptions, StudioServer } from \"./types\";\n\nexport type { StudioOptions, StudioServer } from \"./types\";\n\nexport function createStudio(\n engine: Engine,\n options: StudioOptions = {}\n): StudioServer {\n const port = options.port ?? 4040;\n const host = options.host ?? \"localhost\";\n const url = `http://${host}:${port}`;\n\n const app = createStudioApp(engine);\n let server: ReturnType<typeof serve> | null = null;\n\n return {\n get url() {\n return url;\n },\n\n async start() {\n server = serve({ fetch: app.fetch, port, hostname: host });\n\n console.log(`Chisel Studio running at ${url}`);\n\n if (options.open) {\n const { exec } = await import(\"child_process\");\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n exec(`${cmd} ${url}`);\n }\n },\n\n async stop() {\n if (server) {\n server.close();\n server = null;\n }\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/routes/api.ts","../src/routes/sse.ts","../src/static.ts","../src/server.ts","../src/index.ts"],"names":["Hono","join","existsSync"],"mappings":"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","file":"index.mjs","sourcesContent":["import { Hono } from \"hono\";\nimport type { Engine } from \"chisel-engine\";\nimport type { RunStatus } from \"chisel-engine\";\n\nexport function createApiRoutes(engine: Engine): Hono {\n const app = new Hono();\n\n // Health check\n app.get(\"/health\", async (c) => {\n const health = await engine.health();\n return c.json(health, health.connected ? 200 : 503);\n });\n\n // List registered workflows\n app.get(\"/workflows\", (c) => {\n return c.json(engine.listWorkflows());\n });\n\n // List runs for a workflow\n app.get(\"/workflows/:id/runs\", async (c) => {\n const id = c.req.param(\"id\");\n const query = c.req.query();\n\n const result = await engine.listRuns(id, {\n limit: query.limit ? Number(query.limit) : undefined,\n cursor: query.cursor ? Number(query.cursor) : undefined,\n order: query.order as \"asc\" | \"desc\" | undefined,\n status: query.status as RunStatus | undefined,\n });\n\n return c.json(result);\n });\n\n // Get run detail\n app.get(\"/runs/:runId\", async (c) => {\n const runId = c.req.param(\"runId\");\n const run = await engine.getRun(runId);\n\n if (!run) {\n return c.json({ error: \"Run not found\" }, 404);\n }\n\n return c.json(run);\n });\n\n // Cancel a run\n app.post(\"/runs/:runId/cancel\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.cancelRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Retry a failed run\n app.post(\"/runs/:runId/retry\", async (c) => {\n const runId = c.req.param(\"runId\");\n\n try {\n await engine.retryRun(runId);\n return c.json({ success: true });\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n // Trigger a workflow\n app.post(\"/workflows/:id/trigger\", async (c) => {\n const id = c.req.param(\"id\");\n\n try {\n const body = await c.req.json();\n const { runId } = await engine.trigger(id, body);\n return c.json({ runId }, 202);\n } catch (error) {\n return c.json(\n { error: error instanceof Error ? error.message : String(error) },\n 400\n );\n }\n });\n\n return app;\n}\n","import { Hono } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { Engine, EngineEventName } from \"chisel-engine\";\n\nconst ENGINE_EVENTS: EngineEventName[] = [\n \"workflow:start\",\n \"workflow:complete\",\n \"workflow:fail\",\n \"step:start\",\n \"step:complete\",\n \"step:fail\",\n \"step:retry\",\n];\n\nexport function createSseRoute(engine: Engine): Hono {\n const app = new Hono();\n\n app.get(\"/events\", (c) => {\n return streamSSE(c, async (stream) => {\n const handlers = new Map<string, (payload: unknown) => void>();\n\n for (const event of ENGINE_EVENTS) {\n const handler = (payload: unknown) => {\n stream\n .writeSSE({\n event,\n data: JSON.stringify(payload, (_key, value) =>\n value instanceof Error\n ? { message: value.message, name: value.name }\n : value\n ),\n })\n .catch(() => {});\n };\n handlers.set(event, handler);\n engine.on(event, handler as any);\n }\n\n // Heartbeat every 15 seconds\n const heartbeat = setInterval(() => {\n stream\n .writeSSE({\n event: \"heartbeat\",\n data: JSON.stringify({ time: Date.now() }),\n })\n .catch(() => {});\n }, 15_000);\n\n // Keep the stream alive until client disconnects\n try {\n while (true) {\n await stream.sleep(1000);\n }\n } finally {\n clearInterval(heartbeat);\n for (const [event, handler] of handlers) {\n engine.off(event as EngineEventName, handler as any);\n }\n }\n });\n });\n\n return app;\n}\n","import { readFileSync, existsSync } from \"fs\";\nimport { join, extname } from \"path\";\nimport type { Context } from \"hono\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".mjs\": \"application/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport function createStaticHandler(uiDir: string) {\n // Pre-load index.html into memory (small file, hot path)\n const indexPath = join(uiDir, \"index.html\");\n let indexHtml = \"\";\n if (existsSync(indexPath)) {\n indexHtml = readFileSync(indexPath, \"utf-8\");\n }\n\n return async (c: Context) => {\n const reqPath = new URL(c.req.url).pathname;\n\n // Try serving static asset\n const filePath = join(uiDir, reqPath);\n if (existsSync(filePath) && reqPath !== \"/\") {\n try {\n const content = readFileSync(filePath);\n const ext = extname(filePath);\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n return new Response(content, {\n headers: {\n \"Content-Type\": contentType,\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n },\n });\n } catch {\n // Fall through to index.html\n }\n }\n\n // SPA fallback: serve index.html for all non-file routes\n if (!indexHtml) {\n return c.text(\"Studio UI not built. Run: bun run build:ui\", 500);\n }\n return c.html(indexHtml);\n };\n}\n","import { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { join } from \"path\";\nimport { existsSync } from \"fs\";\nimport type { Engine } from \"chisel-engine\";\nimport { createApiRoutes } from \"./routes/api\";\nimport { createSseRoute } from \"./routes/sse\";\nimport { createStaticHandler } from \"./static\";\n\nfunction resolveUiDir(): string {\n // When running from built output: __dirname is dist/, ui is dist/ui/\n const fromDist = join(__dirname, \"ui\");\n if (existsSync(join(fromDist, \"index.html\"))) return fromDist;\n\n // When running from source via bun/tsx: __dirname is src/, ui is ../dist/ui/\n const fromSrc = join(__dirname, \"..\", \"dist\", \"ui\");\n if (existsSync(join(fromSrc, \"index.html\"))) return fromSrc;\n\n // Fallback\n return fromDist;\n}\n\nexport function createStudioApp(\n engine: Engine,\n options?: { readOnly?: boolean }\n): Hono {\n const readOnly = options?.readOnly ?? false;\n const app = new Hono();\n\n app.onError((err, c) => {\n console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);\n return c.json({ error: err.message }, 500);\n });\n\n // Enable CORS for development\n app.use(\"*\", cors());\n\n // Config endpoint\n app.get(\"/api/config\", (c) => c.json({ readOnly }));\n\n // Block mutations in read-only mode\n if (readOnly) {\n app.use(\"/api/*\", async (c, next) => {\n if (c.req.method === \"POST\") {\n return c.json({ error: \"Studio is in read-only mode\" }, 403);\n }\n await next();\n });\n }\n\n // API routes\n app.route(\"/api\", createApiRoutes(engine));\n\n // SSE events\n app.route(\"/api\", createSseRoute(engine));\n\n // Static SPA assets\n app.get(\"*\", createStaticHandler(resolveUiDir()));\n\n return app;\n}\n","import { serve } from \"@hono/node-server\";\nimport type { Engine } from \"chisel-engine\";\nimport { createStudioApp } from \"./server\";\nimport type { StudioOptions, StudioServer } from \"./types\";\n\nexport type { StudioOptions, StudioServer } from \"./types\";\n\nexport function createStudio(\n engine: Engine,\n options: StudioOptions = {}\n): StudioServer {\n const port = options.port ?? 4040;\n const host = options.host ?? \"localhost\";\n const url = `http://${host}:${port}`;\n\n const app = createStudioApp(engine, { readOnly: options.readOnly });\n let server: ReturnType<typeof serve> | null = null;\n\n return {\n get url() {\n return url;\n },\n\n async start() {\n server = serve({ fetch: app.fetch, port, hostname: host });\n\n console.log(`Chisel Studio running at ${url}`);\n\n if (options.open) {\n const { exec } = await import(\"child_process\");\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n exec(`${cmd} ${url}`);\n }\n },\n\n async stop() {\n if (server) {\n server.close();\n server = null;\n }\n },\n };\n}\n"]}
|