chisel-studio 0.1.1 → 0.1.3
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 +16 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -2
- package/dist/index.mjs.map +1 -1
- package/dist/ui/assets/index-fqnUS6Ov.css +1 -0
- package/dist/ui/assets/index-m_6_IyQf.js +2704 -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,9 +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();
|
|
180
|
+
app.onError((err, c) => {
|
|
181
|
+
console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);
|
|
182
|
+
return c.json({ error: err.message }, 500);
|
|
183
|
+
});
|
|
179
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
|
+
}
|
|
180
194
|
app.route("/api", createApiRoutes(engine));
|
|
181
195
|
app.route("/api", createSseRoute(engine));
|
|
182
196
|
app.get("*", createStaticHandler(resolveUiDir()));
|
|
@@ -188,7 +202,7 @@ function createStudio(engine, options = {}) {
|
|
|
188
202
|
const port = options.port ?? 4040;
|
|
189
203
|
const host = options.host ?? "localhost";
|
|
190
204
|
const url = `http://${host}:${port}`;
|
|
191
|
-
const app = createStudioApp(engine);
|
|
205
|
+
const app = createStudioApp(engine, { readOnly: options.readOnly });
|
|
192
206
|
let server = null;
|
|
193
207
|
return {
|
|
194
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 // 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,9 +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();
|
|
178
|
+
app.onError((err, c) => {
|
|
179
|
+
console.error(`[studio] ${c.req.method} ${c.req.path} error:`, err);
|
|
180
|
+
return c.json({ error: err.message }, 500);
|
|
181
|
+
});
|
|
177
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
|
+
}
|
|
178
192
|
app.route("/api", createApiRoutes(engine));
|
|
179
193
|
app.route("/api", createSseRoute(engine));
|
|
180
194
|
app.get("*", createStaticHandler(resolveUiDir()));
|
|
@@ -186,7 +200,7 @@ function createStudio(engine, options = {}) {
|
|
|
186
200
|
const port = options.port ?? 4040;
|
|
187
201
|
const host = options.host ?? "localhost";
|
|
188
202
|
const url = `http://${host}:${port}`;
|
|
189
|
-
const app = createStudioApp(engine);
|
|
203
|
+
const app = createStudioApp(engine, { readOnly: options.readOnly });
|
|
190
204
|
let server = null;
|
|
191
205
|
return {
|
|
192
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 // 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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 220 14% 10%;--card: 0 0% 100%;--card-foreground: 220 14% 10%;--popover: 0 0% 100%;--popover-foreground: 220 14% 10%;--primary: 245 58% 51%;--primary-foreground: 0 0% 100%;--secondary: 220 14% 96%;--secondary-foreground: 220 14% 10%;--muted: 220 14% 96%;--muted-foreground: 220 9% 46%;--accent: 220 14% 96%;--accent-foreground: 220 14% 10%;--destructive: 0 72% 51%;--destructive-foreground: 0 0% 100%;--border: 220 13% 91%;--input: 220 13% 91%;--ring: 245 58% 51%;--radius: .375rem;--sidebar-bg: 220 20% 98%;--sidebar-border: 220 13% 91%;--sidebar-hover: 220 14% 94%;--sidebar-active: 245 58% 51%}.dark{--background: 228 12% 10%;--foreground: 220 14% 96%;--card: 228 12% 12%;--card-foreground: 220 14% 96%;--popover: 228 12% 14%;--popover-foreground: 220 14% 96%;--primary: 245 58% 61%;--primary-foreground: 0 0% 100%;--secondary: 228 10% 16%;--secondary-foreground: 220 14% 96%;--muted: 228 10% 16%;--muted-foreground: 220 9% 55%;--accent: 228 10% 18%;--accent-foreground: 220 14% 96%;--destructive: 0 72% 55%;--destructive-foreground: 0 0% 100%;--border: 228 10% 18%;--input: 228 10% 20%;--ring: 245 58% 61%;--sidebar-bg: 228 12% 9%;--sidebar-border: 228 10% 16%;--sidebar-hover: 228 10% 14%;--sidebar-active: 245 58% 61%}*{border-color:hsl(var(--border))}body{min-height:100vh;background-color:hsl(var(--background));color:hsl(var(--foreground));font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*{scrollbar-width:thin;scrollbar-color:hsl(var(--border)) transparent}*::-webkit-scrollbar{width:6px;height:6px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background-color:hsl(var(--muted-foreground) / .25);border-radius:3px}*::-webkit-scrollbar-thumb:hover{background-color:hsl(var(--muted-foreground) / .4)}.trace-bar{border-radius:4px;transition:all .15s ease}.trace-bar:hover{filter:brightness(1.1)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.collapse{visibility:collapse}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{left:0;right:0}.left-2\.5{left:.625rem}.left-\[50\%\]{left:50%}.right-4{right:1rem}.top-0{top:0}.top-1\/2{top:50%}.top-4{top:1rem}.top-\[50\%\]{top:50%}.z-10{z-index:10}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.ml-8{margin-left:2rem}.ml-auto{margin-left:auto}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[1px\]{height:1px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.min-h-0{min-height:0px}.min-h-\[140px\]{min-height:140px}.min-h-\[24px\]{min-height:24px}.min-h-\[80px\]{min-height:80px}.w-14{width:3.5rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-52{width:13rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-\[1px\]{width:1px}.w-\[320px\]{width:320px}.w-\[80px\]{width:80px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[80px\]{min-width:80px}.max-w-lg{max-width:32rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}0%,to{opacity:1}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.animate-shimmer{animation:shimmer 2s linear infinite}@keyframes slide-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}.animate-slide-in{animation:slide-in .15s ease-out}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(0px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px * var(--tw-space-y-reverse))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-px>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1px * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-amber-200{--tw-border-opacity: 1;border-color:rgb(253 230 138 / var(--tw-border-opacity, 1))}.border-border{border-color:hsl(var(--border))}.border-input{border-color:hsl(var(--input))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.border-sidebar-border{border-color:hsl(var(--sidebar-border))}.border-transparent{border-color:transparent}.border-l-transparent{border-left-color:transparent}.border-t-transparent{border-top-color:transparent}.bg-accent{background-color:hsl(var(--accent))}.bg-amber-50{--tw-bg-opacity: 1;background-color:rgb(255 251 235 / var(--tw-bg-opacity, 1))}.bg-background{background-color:hsl(var(--background))}.bg-black\/50{background-color:#00000080}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/30{background-color:#3b82f64d}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/10{background-color:hsl(var(--destructive) / .1)}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-emerald-500\/30{background-color:#10b9814d}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-300{--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.bg-gray-400{--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-orange-500\/30{background-color:#f973164d}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-purple-500{--tw-bg-opacity: 1;background-color:rgb(168 85 247 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/30{background-color:#ef44444d}.bg-red-500\/5{background-color:#ef44440d}.bg-secondary{background-color:hsl(var(--secondary))}.bg-sidebar-bg{background-color:hsl(var(--sidebar-bg))}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-blue-500\/20{--tw-gradient-from: rgb(59 130 246 / .2) var(--tw-gradient-from-position);--tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-blue-400\/40{--tw-gradient-to: rgb(96 165 250 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), rgb(96 165 250 / .4) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-blue-500\/20{--tw-gradient-to: rgb(59 130 246 / .2) var(--tw-gradient-to-position)}.bg-\[length\:200\%_100\%\]{background-size:200% 100%}.p-1\.5{padding:.375rem}.p-2\.5{padding:.625rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-\[1px\]{padding:1px}.px-0{padding-left:0;padding-right:0}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-0{padding-bottom:0}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pl-3{padding-left:.75rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-5{padding-right:1.25rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-emerald-500{--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity, 1))}.text-emerald-600{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/70{color:hsl(var(--foreground) / .7)}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-orange-500{--tw-text-opacity: 1;color:rgb(249 115 22 / var(--tw-text-opacity, 1))}.text-orange-600{--tw-text-opacity: 1;color:rgb(234 88 12 / var(--tw-text-opacity, 1))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-purple-600{--tw-text-opacity: 1;color:rgb(147 51 234 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.underline-offset-4{text-underline-offset:4px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.font-mono{font-family:JetBrains Mono,Fira Code,SF Mono,Cascadia Code,ui-monospace,monospace}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-sidebar-hover:hover{background-color:hsl(var(--sidebar-hover))}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.data-\[state\=active\]\:bg-accent[data-state=active],.data-\[state\=open\]\:bg-accent[data-state=open],.data-\[state\=selected\]\:bg-accent[data-state=selected]{background-color:hsl(var(--accent))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:hsl(var(--muted-foreground))}.dark\:border-amber-500\/20:is(.dark *){border-color:#f59e0b33}.dark\:border-red-500\/20:is(.dark *){border-color:#ef444433}.dark\:bg-amber-500\/10:is(.dark *){background-color:#f59e0b1a}.dark\:bg-blue-500\/40:is(.dark *){background-color:#3b82f666}.dark\:bg-emerald-500\/40:is(.dark *){background-color:#10b98166}.dark\:bg-gray-600:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.dark\:bg-orange-500\/40:is(.dark *){background-color:#f9731666}.dark\:bg-red-500\/40:is(.dark *){background-color:#ef444466}.dark\:bg-red-500\/5:is(.dark *){background-color:#ef44440d}.dark\:text-amber-400:is(.dark *){--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.dark\:text-blue-400:is(.dark *){--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.dark\:text-emerald-400:is(.dark *){--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.dark\:text-orange-400:is(.dark *){--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.dark\:text-purple-400:is(.dark *){--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.dark\:text-yellow-400:is(.dark *){--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}@media (min-width: 640px){.sm\:text-left{text-align:left}}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}
|