quadwork 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/bin/quadwork.js +9 -1
  2. package/out/404.html +1 -1
  3. package/out/__next.__PAGE__.txt +1 -1
  4. package/out/__next._full.txt +2 -2
  5. package/out/__next._head.txt +1 -1
  6. package/out/__next._index.txt +2 -2
  7. package/out/__next._tree.txt +2 -2
  8. package/out/_next/static/chunks/0caq73v0knw_w.js +1 -0
  9. package/out/_next/static/chunks/10b3c4k.q.yw..css +2 -0
  10. package/out/_not-found/__next._full.txt +2 -2
  11. package/out/_not-found/__next._head.txt +1 -1
  12. package/out/_not-found/__next._index.txt +2 -2
  13. package/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
  14. package/out/_not-found/__next._not-found.txt +1 -1
  15. package/out/_not-found/__next._tree.txt +2 -2
  16. package/out/_not-found.html +1 -1
  17. package/out/_not-found.txt +2 -2
  18. package/out/app-shell/__next._full.txt +2 -2
  19. package/out/app-shell/__next._head.txt +1 -1
  20. package/out/app-shell/__next._index.txt +2 -2
  21. package/out/app-shell/__next._tree.txt +2 -2
  22. package/out/app-shell/__next.app-shell.__PAGE__.txt +1 -1
  23. package/out/app-shell/__next.app-shell.txt +1 -1
  24. package/out/app-shell.html +1 -1
  25. package/out/app-shell.txt +2 -2
  26. package/out/index.html +1 -1
  27. package/out/index.txt +2 -2
  28. package/out/project/_/__next._full.txt +2 -2
  29. package/out/project/_/__next._head.txt +1 -1
  30. package/out/project/_/__next._index.txt +2 -2
  31. package/out/project/_/__next._tree.txt +2 -2
  32. package/out/project/_/__next.project.$d$id.__PAGE__.txt +1 -1
  33. package/out/project/_/__next.project.$d$id.txt +1 -1
  34. package/out/project/_/__next.project.txt +1 -1
  35. package/out/project/_/memory/__next._full.txt +2 -2
  36. package/out/project/_/memory/__next._head.txt +1 -1
  37. package/out/project/_/memory/__next._index.txt +2 -2
  38. package/out/project/_/memory/__next._tree.txt +2 -2
  39. package/out/project/_/memory/__next.project.$d$id.memory.__PAGE__.txt +1 -1
  40. package/out/project/_/memory/__next.project.$d$id.memory.txt +1 -1
  41. package/out/project/_/memory/__next.project.$d$id.txt +1 -1
  42. package/out/project/_/memory/__next.project.txt +1 -1
  43. package/out/project/_/memory.html +1 -1
  44. package/out/project/_/memory.txt +2 -2
  45. package/out/project/_/queue/__next._full.txt +2 -2
  46. package/out/project/_/queue/__next._head.txt +1 -1
  47. package/out/project/_/queue/__next._index.txt +2 -2
  48. package/out/project/_/queue/__next._tree.txt +2 -2
  49. package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +1 -1
  50. package/out/project/_/queue/__next.project.$d$id.queue.txt +1 -1
  51. package/out/project/_/queue/__next.project.$d$id.txt +1 -1
  52. package/out/project/_/queue/__next.project.txt +1 -1
  53. package/out/project/_/queue.html +1 -1
  54. package/out/project/_/queue.txt +2 -2
  55. package/out/project/_.html +1 -1
  56. package/out/project/_.txt +2 -2
  57. package/out/settings/__next._full.txt +2 -2
  58. package/out/settings/__next._head.txt +1 -1
  59. package/out/settings/__next._index.txt +2 -2
  60. package/out/settings/__next._tree.txt +2 -2
  61. package/out/settings/__next.settings.__PAGE__.txt +1 -1
  62. package/out/settings/__next.settings.txt +1 -1
  63. package/out/settings.html +1 -1
  64. package/out/settings.txt +2 -2
  65. package/out/setup/__next._full.txt +3 -3
  66. package/out/setup/__next._head.txt +1 -1
  67. package/out/setup/__next._index.txt +2 -2
  68. package/out/setup/__next._tree.txt +2 -2
  69. package/out/setup/__next.setup.__PAGE__.txt +2 -2
  70. package/out/setup/__next.setup.txt +1 -1
  71. package/out/setup.html +1 -1
  72. package/out/setup.txt +3 -3
  73. package/package.json +1 -1
  74. package/server/index.js +188 -10
  75. package/server/routes.js +27 -16
  76. package/out/_next/static/chunks/0ahp74n0wkel0.js +0 -1
  77. package/out/_next/static/chunks/0s8jbc4nxw6y6.css +0 -2
  78. /package/out/_next/static/{GOOT2ox5oH-rTFhgq8-MK → TKQFu1hHpaRuo62RWWrUJ}/_buildManifest.js +0 -0
  79. /package/out/_next/static/{GOOT2ox5oH-rTFhgq8-MK → TKQFu1hHpaRuo62RWWrUJ}/_clientMiddlewareManifest.js +0 -0
  80. /package/out/_next/static/{GOOT2ox5oH-rTFhgq8-MK → TKQFu1hHpaRuo62RWWrUJ}/_ssgManifest.js +0 -0
package/server/index.js CHANGED
@@ -131,22 +131,197 @@ const agentSessions = new Map();
131
131
  // AgentChattr server processes — per-project (key = projectId)
132
132
  const chattrProcesses = new Map();
133
133
 
134
+ // --- MCP auth proxy for Codex (can't pass headers via -c flag) ---
135
+ // Maps "project/agent" → { server, port }
136
+ const mcpProxies = new Map();
137
+
138
+ /**
139
+ * Start a local HTTP proxy that forwards MCP requests with Bearer token.
140
+ * Returns a Promise that resolves to the proxy URL once listening.
141
+ */
142
+ function startMcpProxy(projectId, agentId, upstreamUrl, token) {
143
+ const key = `${projectId}/${agentId}`;
144
+ const existing = mcpProxies.get(key);
145
+ if (existing) return Promise.resolve(`http://127.0.0.1:${existing.port}/mcp`);
146
+
147
+ return new Promise((resolve, reject) => {
148
+ const proxyServer = http.createServer((req, res) => {
149
+ const parsedUrl = new URL(req.url, `http://127.0.0.1`);
150
+ const targetUrl = `${upstreamUrl}${parsedUrl.pathname}${parsedUrl.search}`;
151
+ const headers = { ...req.headers, host: new URL(upstreamUrl).host };
152
+ if (token) {
153
+ headers["authorization"] = `Bearer ${token}`;
154
+ headers["x-agent-token"] = token;
155
+ }
156
+ delete headers["content-length"];
157
+
158
+ const chunks = [];
159
+ req.on("data", (chunk) => chunks.push(chunk));
160
+ req.on("end", () => {
161
+ const body = Buffer.concat(chunks);
162
+ const proxyReq = (upstreamUrl.startsWith("https") ? require("https") : http).request(
163
+ targetUrl,
164
+ { method: req.method, headers: { ...headers, "content-length": body.length } },
165
+ (proxyRes) => {
166
+ res.writeHead(proxyRes.statusCode, proxyRes.headers);
167
+ proxyRes.pipe(res);
168
+ }
169
+ );
170
+ proxyReq.on("error", (err) => {
171
+ res.writeHead(502);
172
+ res.end(`Proxy error: ${err.message}`);
173
+ });
174
+ proxyReq.end(body);
175
+ });
176
+ });
177
+
178
+ proxyServer.on("error", (err) => reject(err));
179
+ proxyServer.listen(0, "127.0.0.1", () => {
180
+ const port = proxyServer.address().port;
181
+ mcpProxies.set(key, { server: proxyServer, port });
182
+ resolve(`http://127.0.0.1:${port}/mcp`);
183
+ });
184
+ });
185
+ }
186
+
187
+ function stopMcpProxy(projectId, agentId) {
188
+ const key = `${projectId}/${agentId}`;
189
+ const proxy = mcpProxies.get(key);
190
+ if (proxy) {
191
+ try { proxy.server.close(); } catch {}
192
+ mcpProxies.delete(key);
193
+ }
194
+ }
195
+
196
+ // --- Permission bypass flags per CLI ---
197
+ const PERMISSION_FLAGS = {
198
+ claude: ["--dangerously-skip-permissions"],
199
+ codex: ["--dangerously-bypass-approvals-and-sandbox"],
200
+ gemini: ["--yolo"],
201
+ };
202
+
203
+ // --- MCP config generation & agent launch args ---
204
+
205
+ /**
206
+ * Generate a per-agent MCP config file for Claude (--mcp-config).
207
+ * Returns the absolute path to the written JSON file.
208
+ */
209
+ function writeMcpConfigFile(projectId, agentId, mcpHttpPort, token) {
210
+ const os = require("os");
211
+ const configDir = path.join(os.homedir(), ".quadwork", projectId);
212
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
213
+ const filePath = path.join(configDir, `mcp-${agentId}.json`);
214
+ const url = `http://127.0.0.1:${mcpHttpPort}/mcp`;
215
+ const config = {
216
+ mcpServers: {
217
+ agentchattr: {
218
+ type: "http",
219
+ url,
220
+ ...(token ? { headers: { Authorization: `Bearer ${token}` } } : {}),
221
+ },
222
+ },
223
+ };
224
+ fs.writeFileSync(filePath, JSON.stringify(config, null, 2));
225
+ return filePath;
226
+ }
227
+
228
+ /**
229
+ * Build extra launch args for an agent (permission flags + MCP injection).
230
+ * Async because Codex proxy_flag mode needs to await proxy startup.
231
+ */
232
+ async function buildAgentArgs(projectId, agentId) {
233
+ const cfg = readConfig();
234
+ const project = cfg.projects?.find((p) => p.id === projectId);
235
+ if (!project) return [];
236
+
237
+ const agentCfg = project.agents?.[agentId] || {};
238
+ const command = agentCfg.command || "claude";
239
+ const cliBase = command.split("/").pop().split(" ")[0]; // extract base CLI name
240
+ const args = [];
241
+
242
+ // Permission bypass flags
243
+ if (agentCfg.auto_approve !== false) {
244
+ const flags = PERMISSION_FLAGS[cliBase];
245
+ if (flags) args.push(...flags);
246
+ }
247
+
248
+ // MCP config injection
249
+ const mcpHttpPort = project.mcp_http_port;
250
+ const token = project.agentchattr_token;
251
+ if (mcpHttpPort) {
252
+ const injectMode = agentCfg.mcp_inject || (cliBase === "codex" ? "proxy_flag" : cliBase === "gemini" ? "env" : "flag");
253
+ if (injectMode === "flag") {
254
+ // Claude/Kimi: write config file, pass --mcp-config
255
+ const mcpConfigPath = writeMcpConfigFile(projectId, agentId, mcpHttpPort, token);
256
+ const flag = agentCfg.mcp_flag || "--mcp-config";
257
+ args.push(flag, mcpConfigPath);
258
+ } else if (injectMode === "proxy_flag") {
259
+ // Codex: start local auth proxy, pass proxy URL via -c flag
260
+ const upstreamUrl = `http://127.0.0.1:${mcpHttpPort}`;
261
+ const proxyUrl = await startMcpProxy(projectId, agentId, upstreamUrl, token);
262
+ if (proxyUrl) {
263
+ args.push("-c", `mcp_servers.agentchattr.url="${proxyUrl}"`);
264
+ }
265
+ }
266
+ }
267
+
268
+ return args;
269
+ }
270
+
271
+ /**
272
+ * Build extra env vars for an agent (MCP injection via env for Gemini).
273
+ */
274
+ function buildAgentEnv(projectId, agentId) {
275
+ const cfg = readConfig();
276
+ const project = cfg.projects?.find((p) => p.id === projectId);
277
+ if (!project) return {};
278
+
279
+ const agentCfg = project.agents?.[agentId] || {};
280
+ const command = agentCfg.command || "claude";
281
+ const cliBase = command.split("/").pop().split(" ")[0];
282
+ const env = {};
283
+
284
+ // Gemini: inject MCP via env var
285
+ if (cliBase === "gemini" && project.mcp_http_port) {
286
+ const os = require("os");
287
+ const configDir = path.join(os.homedir(), ".quadwork", projectId);
288
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
289
+ const settingsPath = path.join(configDir, `mcp-${agentId}-settings.json`);
290
+ const url = `http://127.0.0.1:${project.mcp_http_port}/mcp`;
291
+ const settings = {
292
+ mcpServers: {
293
+ agentchattr: {
294
+ type: "http",
295
+ url,
296
+ ...(project.agentchattr_token ? { headers: { Authorization: `Bearer ${project.agentchattr_token}` } } : {}),
297
+ },
298
+ },
299
+ };
300
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
301
+ env.GEMINI_CLI_SYSTEM_SETTINGS_PATH = settingsPath;
302
+ }
303
+
304
+ return env;
305
+ }
306
+
134
307
  // Helper: spawn a PTY for a project/agent and register in agentSessions
135
- function spawnAgentPty(project, agent) {
308
+ async function spawnAgentPty(project, agent) {
136
309
  const key = `${project}/${agent}`;
137
310
 
138
311
  const cwd = resolveAgentCwd(project, agent);
139
312
  if (!cwd) return { ok: false, error: `Unknown agent: ${key}` };
140
313
 
141
314
  const command = resolveAgentCommand(project, agent) || (process.env.SHELL || "/bin/zsh");
315
+ const args = await buildAgentArgs(project, agent);
316
+ const extraEnv = buildAgentEnv(project, agent);
142
317
 
143
318
  try {
144
- const term = pty.spawn(command, [], {
319
+ const term = pty.spawn(command, args, {
145
320
  name: "xterm-256color",
146
321
  cols: 120,
147
322
  rows: 30,
148
323
  cwd,
149
- env: process.env,
324
+ env: { ...process.env, ...extraEnv },
150
325
  });
151
326
 
152
327
  const session = { projectId: project, agentId: agent, term, ws: null, state: "running", error: null };
@@ -190,6 +365,9 @@ function stopAgentSession(key) {
190
365
  session.ws = null;
191
366
  session.state = "stopped";
192
367
  session.error = null;
368
+ // Clean up MCP auth proxy if running
369
+ const [projectId, agentId] = key.split("/");
370
+ if (projectId && agentId) stopMcpProxy(projectId, agentId);
193
371
  }
194
372
 
195
373
  app.get("/api/agents", (_req, res) => {
@@ -423,7 +601,7 @@ app.post("/api/agents/:project/reset", async (req, res) => {
423
601
 
424
602
  // --- Lifecycle: start spawns PTY (visible in terminal panel) ---
425
603
 
426
- app.post("/api/agents/:project/:agent/start", (req, res) => {
604
+ app.post("/api/agents/:project/:agent/start", async (req, res) => {
427
605
  const { project, agent } = req.params;
428
606
  const key = `${project}/${agent}`;
429
607
 
@@ -432,7 +610,7 @@ app.post("/api/agents/:project/:agent/start", (req, res) => {
432
610
  return res.json({ ok: true, state: "running", message: "Already running" });
433
611
  }
434
612
 
435
- const result = spawnAgentPty(project, agent);
613
+ const result = await spawnAgentPty(project, agent);
436
614
  if (result.ok) {
437
615
  res.json({ ok: true, state: "running", pid: result.pid });
438
616
  } else {
@@ -451,14 +629,14 @@ app.post("/api/agents/:project/:agent/stop", (req, res) => {
451
629
 
452
630
  // --- Lifecycle: restart ---
453
631
 
454
- app.post("/api/agents/:project/:agent/restart", (req, res) => {
632
+ app.post("/api/agents/:project/:agent/restart", async (req, res) => {
455
633
  const { project, agent } = req.params;
456
634
  const key = `${project}/${agent}`;
457
635
 
458
636
  stopAgentSession(key);
459
637
 
460
- setTimeout(() => {
461
- const result = spawnAgentPty(project, agent);
638
+ setTimeout(async () => {
639
+ const result = await spawnAgentPty(project, agent);
462
640
  if (result.ok) {
463
641
  res.json({ ok: true, state: "running", pid: result.pid });
464
642
  } else {
@@ -708,7 +886,7 @@ app.use((req, res, next) => {
708
886
 
709
887
  const wss = new WebSocketServer({ server, path: "/ws/terminal" });
710
888
 
711
- wss.on("connection", (ws, req) => {
889
+ wss.on("connection", async (ws, req) => {
712
890
  const params = new URL(req.url, `http://localhost:${PORT}`).searchParams;
713
891
  const projectId = params.get("project");
714
892
  const agentId = params.get("agent");
@@ -723,7 +901,7 @@ wss.on("connection", (ws, req) => {
723
901
 
724
902
  // If no active PTY, spawn one
725
903
  if (!session || !session.term) {
726
- const result = spawnAgentPty(projectId, agentId);
904
+ const result = await spawnAgentPty(projectId, agentId);
727
905
  if (!result.ok) {
728
906
  ws.close(1011, "pty-spawn-failed");
729
907
  return;
package/server/routes.js CHANGED
@@ -590,21 +590,26 @@ router.post("/api/setup", (req, res) => {
590
590
  const wtDir = path.join(parentDir, `${dirName}-${agent}`);
591
591
  if (!fs.existsSync(wtDir)) continue;
592
592
 
593
- // AGENTS.md — use template with placeholder substitution (matches CLI)
593
+ // AGENTS.md — always (re)write from template so role definitions
594
+ // stay in sync with templates/seeds/ on every project (re)creation.
595
+ // Previously this was guarded by `!exists`, so if a worktree already
596
+ // had any AGENTS.md (stale, hand-edited, or empty) it was preserved
597
+ // forever and agents could launch with no/outdated role definition.
594
598
  const agentsMd = path.join(wtDir, "AGENTS.md");
595
- if (!fs.existsSync(agentsMd)) {
596
- const seedSrc = path.join(TEMPLATES_DIR, "seeds", `${agent}.AGENTS.md`);
597
- if (fs.existsSync(seedSrc)) {
598
- let content = fs.readFileSync(seedSrc, "utf-8");
599
- content = content.replace(/\{\{reviewer_github_user\}\}/g, reviewerUser);
600
- content = content.replace(/\{\{reviewer_token_path\}\}/g, reviewerTokenPath);
601
- fs.writeFileSync(agentsMd, content);
602
- } else {
603
- // Fallback stub if template missing
604
- fs.writeFileSync(agentsMd, `# ${dirName} — ${agent.charAt(0).toUpperCase() + agent.slice(1)} Agent\n\nRepo: ${body.repo}\nRole: ${agent === "head" ? "Owner" : agent.startsWith("reviewer") ? "Reviewer" : "Builder"}\n`);
605
- }
606
- seeded.push(`${agent}/AGENTS.md`);
599
+ const seedSrc = path.join(TEMPLATES_DIR, "seeds", `${agent}.AGENTS.md`);
600
+ if (!fs.existsSync(seedSrc)) {
601
+ // Hard fail: missing seed means role is undefined. Better to surface
602
+ // the error than silently write a generic stub.
603
+ return res.json({
604
+ ok: false,
605
+ error: `Missing seed template: templates/seeds/${agent}.AGENTS.md`,
606
+ });
607
607
  }
608
+ let agentsContent = fs.readFileSync(seedSrc, "utf-8");
609
+ agentsContent = agentsContent.replace(/\{\{reviewer_github_user\}\}/g, reviewerUser);
610
+ agentsContent = agentsContent.replace(/\{\{reviewer_token_path\}\}/g, reviewerTokenPath);
611
+ fs.writeFileSync(agentsMd, agentsContent);
612
+ seeded.push(`${agent}/AGENTS.md`);
608
613
 
609
614
  // CLAUDE.md — use template with placeholder substitution (matches CLI)
610
615
  const claudeMd = path.join(wtDir, "CLAUDE.md");
@@ -697,19 +702,25 @@ router.post("/api/setup", (req, res) => {
697
702
  }
698
703
  case "add-config": {
699
704
  const { id, name, repo, workingDir, backends } = body;
705
+ const autoApprove = body.auto_approve !== false; // default true
700
706
  // Use directory basename for sibling paths (matches CLI wizard)
701
707
  const dirName = path.basename(workingDir);
702
708
  const parentDir = path.dirname(workingDir);
703
709
  let cfg;
704
710
  try { cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); }
705
- catch { cfg = { port: 8400, agentchattr_url: "http://127.0.0.1:8300", projects: [] }; }
711
+ catch { cfg = { port: 8400, agentchattr_url: "http://127.0.0.1:8300", agentchattr_dir: path.join(os.homedir(), ".quadwork", "agentchattr"), projects: [] }; }
706
712
  if (cfg.projects.some((p) => p.id === id)) return res.json({ ok: true, message: "Project already in config" });
707
- // Match CLI wizard agent structure: { cwd, command }
713
+ // Match CLI wizard agent structure: { cwd, command, auto_approve, mcp_inject }
708
714
  const agents = {};
709
715
  for (const agentId of ["head", "reviewer1", "reviewer2", "dev"]) {
716
+ const cmd = (backends && backends[agentId]) || "claude";
717
+ const cliBase = cmd.split("/").pop().split(" ")[0];
718
+ const injectMode = cliBase === "codex" ? "proxy_flag" : cliBase === "gemini" ? "env" : "flag";
710
719
  agents[agentId] = {
711
720
  cwd: path.join(parentDir, `${dirName}-${agentId}`),
712
- command: (backends && backends[agentId]) || "claude",
721
+ command: cmd,
722
+ auto_approve: autoApprove,
723
+ mcp_inject: injectMode,
713
724
  };
714
725
  }
715
726
  // Use pre-assigned ports/token from agentchattr-config step if provided,
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,64618,e=>{"use strict";var t=e.i(24046),s=e.i(85899),a=e.i(4232),r=e.i(16353);let c=[{id:"name",label:"Project Name",subtitle:"Name your project",status:"active"},{id:"repo",label:"GitHub Repo",subtitle:"Connect a repository",status:"pending"},{id:"models",label:"Agent Models",subtitle:"Configure CLI backends",status:"pending"},{id:"workdir",label:"Working Directory",subtitle:"Set the local path",status:"pending"},{id:"workspaces",label:"Create Workspaces",subtitle:"Worktrees + seed files",status:"pending"},{id:"launch",label:"Ready to Launch",subtitle:"Review & start",status:"pending"}],n=[{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex"}],l=[{key:"head",label:"T1 — Head",role:"Owner / Final Guard",desc:"Merges PRs, makes final calls"},{key:"reviewer1",label:"T2a — Reviewer 1",role:"Design Reviewer",desc:"Reviews architecture & design"},{key:"reviewer2",label:"T2b — Reviewer 2",role:"Code Reviewer",desc:"Reviews implementation quality"},{key:"dev",label:"T3 — Developer",role:"Full-Stack Builder",desc:"Implements features & fixes"}];function o({repo:e,workingDir:t,setWorkingDir:r,error:c,onNext:n}){let[l,i]=(0,a.useState)(!0),[d,x]=(0,a.useState)(null),[p,m]=(0,a.useState)(!1),u=e?e.split("/")[1]:"project";return(0,a.useEffect)(()=>{e?fetch(`/api/setup/detect-clone?repo=${encodeURIComponent(e)}`).then(e=>e.ok?e.json():null).then(e=>{x(e),e?.found&&e.path?r(e.path):e?.suggested&&r(e.suggested),i(!1)}).catch(()=>i(!1)):i(!1)},[e,r]),(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Where is your project?"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-3",children:"Your project's git repository on your local machine. QuadWork will create 4 agent workspaces next to this directory."}),l&&(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-3",children:"Scanning for existing clone..."}),!l&&d?.found&&(0,s.jsxs)("div",{className:"border border-accent/30 bg-accent/5 p-3 mb-4 text-[11px]",children:[(0,s.jsx)("p",{className:"text-accent font-semibold mb-1",children:"Found existing clone"}),(0,s.jsx)("p",{className:"text-text font-mono",children:d.path}),(0,s.jsxs)("div",{className:"flex gap-2 mt-2",children:[(0,s.jsx)("button",{onClick:n,className:"px-3 py-1 bg-accent text-bg text-[11px] font-semibold hover:bg-accent-dim transition-colors",children:"Use this"}),(0,s.jsx)("button",{onClick:()=>{m(!0),r("")},className:"px-3 py-1 text-[11px] text-text-muted border border-border hover:text-text transition-colors",children:"Choose different path"})]})]}),!l&&!d?.found&&!p&&(0,s.jsxs)("div",{className:"border border-border bg-bg-surface p-3 mb-4 text-[11px]",children:[(0,s.jsxs)("p",{className:"text-text-muted mb-1",children:["No local clone found for ",(0,s.jsx)("span",{className:"text-accent",children:e})]}),(0,s.jsx)("p",{className:"text-text-muted mb-2",children:"Setup will clone it to:"}),(0,s.jsx)("p",{className:"text-text font-mono mb-2",children:d?.suggested||`~/Projects/${u}`}),(0,s.jsxs)("div",{className:"flex gap-2",children:[(0,s.jsx)("button",{onClick:n,disabled:!t.trim(),className:"px-3 py-1 bg-accent text-bg text-[11px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"Clone here & continue"}),(0,s.jsx)("button",{onClick:()=>m(!0),className:"px-3 py-1 text-[11px] text-text-muted border border-border hover:text-text transition-colors",children:"Choose different path"})]})]}),(p||!l&&!d)&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:t,onChange:e=>r(e.target.value),placeholder:`~/Projects/${u}`,className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-2"}),(0,s.jsx)("button",{onClick:n,disabled:!t.trim(),className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"Next"})]}),c&&(0,s.jsx)("p",{className:"text-[11px] text-error mt-2",children:c}),(0,s.jsxs)("div",{className:"border border-border bg-bg-surface p-3 mt-4 text-[11px] text-text-muted font-mono space-y-0.5",children:[(0,s.jsx)("p",{className:"text-[10px] uppercase tracking-wider text-text-muted mb-1 font-sans",children:"Workspace layout"}),(0,s.jsxs)("p",{className:"text-accent",children:[u,"/ ← your repo"]}),(0,s.jsxs)("p",{children:[u,"-head/ ← Head agent"]}),(0,s.jsxs)("p",{children:[u,"-dev/ ← Dev agent"]}),(0,s.jsxs)("p",{children:[u,"-reviewer1/ ← Reviewer1"]}),(0,s.jsxs)("p",{children:[u,"-reviewer2/ ← Reviewer2"]})]})]})}e.s(["default",0,function(){let e=(0,r.useRouter)(),[i,d]=(0,a.useState)(c),[x,p]=(0,a.useState)(0),[m,u]=(0,a.useState)(""),[h,b]=(0,a.useState)(""),[g,j]=(0,a.useState)(""),[f,v]=(0,a.useState)([]),[N,k]=(0,a.useState)(!1),[y,w]=(0,a.useState)(!1),[C,S]=(0,a.useState)(""),[_,R]=(0,a.useState)(!1),[T,P]=(0,a.useState)({head:"claude",reviewer1:"claude",reviewer2:"claude",dev:"claude"}),[$,q]=(0,a.useState)(!1),[H,I]=(0,a.useState)(""),[A,L]=(0,a.useState)("paste"),[E,F]=(0,a.useState)(""),[U,W]=(0,a.useState)("~/.quadwork/reviewer-token"),[D,G]=(0,a.useState)(""),[O,M]=(0,a.useState)({}),[Y,B]=(0,a.useState)(!1),[z,J]=(0,a.useState)([]),[K,V]=(0,a.useState)("idle"),[X,Q]=(0,a.useState)(!1),[Z,ee]=(0,a.useState)({chattr:0,mcpHttp:0,mcpSse:0}),[et,es]=(0,a.useState)({chattr:0,mcpHttp:0,mcpSse:0}),[ea,er]=(0,a.useState)(null);(0,a.useEffect)(()=>{fetch("/api/cli-status").then(e=>e.json()).then(e=>{er(e);let t=e.claude&&!e.codex?"claude":!e.claude&&e.codex?"codex":null;t?P({head:t,reviewer1:t,reviewer2:t,dev:t}):e.claude&&e.codex&&P({head:"codex",dev:"claude",reviewer1:"codex",reviewer2:"claude"})}).catch(()=>{})},[]),(0,a.useEffect)(()=>{fetch("/api/github/user").then(e=>e.json()).then(e=>{e.login&&S(e.login)}).catch(()=>{})},[]),(0,a.useEffect)(()=>{C&&(k(!0),fetch(`/api/github/repos?owner=${encodeURIComponent(C)}`).then(e=>e.json()).then(e=>{Array.isArray(e)&&v(e)}).catch(()=>{}).finally(()=>k(!1)))},[C]);let ec=(0,a.useCallback)((e,t)=>{d(s=>s.map((s,a)=>a===e?{...s,...t}:s))},[]),en=(0,a.useCallback)(()=>{d(e=>e.map((e,t)=>t===x?{...e,status:"done"}:t===x+1?{...e,status:"active"}:e)),p(e=>e+1)},[x]),el=async(e,t)=>{B(!0);try{let s=await fetch(`/api/setup?step=${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),a=await s.json();return B(!1),a}catch{return B(!1),{ok:!1,error:"Request failed"}}},eo=async()=>{let e=await el("verify-repo",{repo:h});e.ok?en():ec(x,{status:"error",error:e.error})},ei=async()=>{if(B(!0),J([]),$&&"paste"===A&&E){J(e=>[...e,"Saving reviewer token..."]);try{let e=await fetch("/api/setup/save-token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:E})}),t=await e.json();t.ok&&J(e=>[...e,`Token saved to ${t.path}`])}catch{}}J(e=>[...e,"Creating worktrees..."]);let e=await el("create-worktrees",{workingDir:D,repo:h});if(!e.ok){J(t=>[...t,`Error: ${e.errors?.join(", ")||e.error}`]),ec(x,{status:"error",error:e.errors?.join(", ")||e.error}),B(!1);return}J(e=>[...e,"Worktrees created."]),J(e=>[...e,"Writing seed files..."]);let t=$?"file"===A?U:"~/.quadwork/reviewer-token":"",s=await el("seed-files",{workingDir:D,projectName:m,repo:h,reviewerUser:$?H:"",reviewerTokenPath:t});if(!s.ok){J(e=>[...e,`Error: ${s.error}`]),ec(x,{status:"error",error:s.error}),B(!1);return}J(e=>[...e,"Seed files written."]),J(e=>[...e,"Done."]),B(!1),en()},ed=async()=>{let t,s,a;if(V("running"),X&&Z.chattr>0){t=Z.chattr,s=Z.mcpHttp||Z.chattr-100,a=Z.mcpSse||s+1;let e=[t,s,a];try{let t=(await Promise.all(e.map(e=>fetch(`/api/port-check?port=${e}`).then(e=>e.json())))).filter(e=>!e.free).map(e=>e.port);if(t.length>0){V("error"),ec(x,{status:"error",error:`Port${t.length>1?"s":""} ${t.join(", ")} already in use`});return}}catch{}}else if(et.chattr)t=et.chattr,s=et.mcpHttp,a=et.mcpSse;else try{let e=await fetch("/api/port-check/auto?start=8300&count=1"),r=await e.json(),c=await fetch("/api/port-check/auto?start=8200&count=2"),n=await c.json();t=r.ports?.[0]||8300,s=n.ports?.[0]||8200,a=n.ports?.[1]||8201}catch{t=8300,s=8200,a=8201}let r=await el("agentchattr-config",{workingDir:D,projectName:m,repo:h,backends:T,agentchattr_port:t,mcp_http_port:s,mcp_sse_port:a});r.ok&&M({agentchattr_token:r.agentchattr_token,agentchattr_port:r.agentchattr_port,mcp_http_port:r.mcp_http_port,mcp_sse_port:r.mcp_sse_port});let c=D.split("/").pop()||m.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""),n=await el("add-config",{id:c,name:m,repo:h,workingDir:D,backends:T,...r.ok?{agentchattr_token:r.agentchattr_token,agentchattr_port:r.agentchattr_port,mcp_http_port:r.mcp_http_port,mcp_sse_port:r.mcp_sse_port}:O});n.ok?(V("done"),ec(x,{status:"done"}),setTimeout(()=>e.push(`/project/${c}`),1200)):(V("error"),ec(x,{status:"error",error:n.error}))};(0,a.useEffect)(()=>{i[x]?.id==="launch"&&(async()=>{try{let e=await fetch("/api/port-check/auto?start=8300&count=1"),t=await e.json(),s=await fetch("/api/port-check/auto?start=8200&count=2"),a=await s.json(),r={chattr:t.ports?.[0]||8300,mcpHttp:a.ports?.[0]||8200,mcpSse:a.ports?.[1]||8201};es(r),Z.chattr||ee(r)}catch{}})()},[x,i]);let ex=f.filter(e=>e.name.toLowerCase().includes(g.toLowerCase())),ep=i[x];return(0,s.jsxs)("div",{className:"h-full overflow-y-auto",children:[(0,s.jsxs)("div",{className:"px-6 pt-6 pb-4 border-b border-border",children:[(0,s.jsx)("h1",{className:"text-lg font-semibold text-text tracking-tight",children:"Set Up Your AI Dev Team"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mt-1",children:"Configure agents, connect your repo, and launch a multi-agent development workflow in minutes."})]}),(0,s.jsxs)("div",{className:"flex h-[calc(100%-80px)]",children:[(0,s.jsxs)("div",{className:"flex-1 flex gap-6 p-6 overflow-y-auto",children:[(0,s.jsx)("div",{className:"w-44 shrink-0",children:i.map((e,t)=>(0,s.jsxs)("div",{className:"flex items-start gap-2 py-2",children:[(0,s.jsx)("span",{className:`w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 ${"done"===e.status?"border-accent text-accent":"error"===e.status?"border-error text-error":"active"===e.status?"border-accent text-accent bg-accent/10":"skipped"===e.status?"border-border text-text-muted line-through":"border-border text-text-muted"}`,children:"done"===e.status?"✓":"error"===e.status?"!":t+1}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:`text-[11px] block leading-tight ${"active"===e.status?"text-text font-semibold":"done"===e.status?"text-accent":"text-text-muted"}`,children:e.label}),(0,s.jsx)("span",{className:"text-[10px] text-text-muted block",children:e.subtitle})]})]},e.id))}),(0,s.jsxs)("div",{className:"flex-1 border border-border p-5 min-h-0",children:[ep?.id==="name"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Name your project"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"This name identifies your project in the dashboard and agent configs."}),(0,s.jsx)("input",{value:m,onChange:e=>u(e.target.value),placeholder:"e.g. My DeFi App",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-4",autoFocus:!0}),(0,s.jsx)("button",{onClick:en,disabled:!m.trim(),className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"Next"})]}),ep?.id==="repo"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Connect a GitHub repository"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"Select an existing repo or enter one manually. Agents will work within this repo."}),!y&&(0,s.jsxs)(s.Fragment,{children:[C&&(0,s.jsxs)("p",{className:"text-[11px] text-text-muted mb-2",children:["Showing repos for ",(0,s.jsx)("span",{className:"text-accent",children:C})]}),(0,s.jsx)("input",{value:g,onChange:e=>j(e.target.value),placeholder:"Search repos...",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-2"}),N&&(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-2",children:"Loading..."}),(0,s.jsxs)("div",{className:"max-h-40 overflow-y-auto border border-border mb-3",children:[ex.map(e=>(0,s.jsxs)("button",{onClick:()=>b(`${C}/${e.name}`),className:`w-full text-left px-3 py-1.5 text-[11px] border-b border-border/50 last:border-b-0 hover:bg-accent/5 transition-colors ${h===`${C}/${e.name}`?"bg-accent/10 text-accent":"text-text"}`,children:[(0,s.jsx)("span",{className:"font-semibold",children:e.name}),e.isPrivate&&(0,s.jsx)("span",{className:"text-[10px] text-text-muted ml-2",children:"private"}),e.description&&(0,s.jsx)("span",{className:"text-[10px] text-text-muted ml-2",children:e.description})]},e.name)),!N&&0===ex.length&&(0,s.jsx)("p",{className:"px-3 py-2 text-[11px] text-text-muted",children:"No repos found."})]}),(0,s.jsx)("button",{onClick:()=>w(!0),className:"text-[11px] text-text-muted hover:text-accent transition-colors mb-3 block",children:"Enter manually instead"})]}),y&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:h,onChange:e=>b(e.target.value),placeholder:"owner/repo",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-2"}),(0,s.jsx)("button",{onClick:()=>w(!1),className:"text-[11px] text-text-muted hover:text-accent transition-colors mb-3 block",children:"Back to repo list"})]}),(0,s.jsxs)("label",{className:"flex items-center gap-2 mb-4 cursor-pointer",children:[(0,s.jsx)("input",{type:"checkbox",checked:_,onChange:e=>R(e.target.checked),className:"accent-accent"}),(0,s.jsxs)("span",{className:"text-[11px] text-text-muted",children:["Enable branch protection on ",(0,s.jsx)("code",{className:"text-accent",children:"main"})]})]}),_&&(0,s.jsxs)("div",{className:"border border-border bg-bg-surface p-3 mb-4 text-[11px] space-y-2",children:[(0,s.jsx)("p",{className:"text-text-muted",children:"Run this after setup, or configure in GitHub UI:"}),(0,s.jsxs)("div",{className:"flex items-center gap-2",children:[(0,s.jsx)("code",{className:"text-accent flex-1 select-all text-[10px] break-all",children:`gh api repos/${h||"owner/repo"}/branches/main/protection -X PUT -f "required_pull_request_reviews[required_approving_review_count]=1" -f "enforce_admins=false" -f "required_status_checks=null" -f "restrictions=null"`}),(0,s.jsx)("button",{onClick:()=>navigator.clipboard.writeText(`gh api repos/${h}/branches/main/protection -X PUT -f "required_pull_request_reviews[required_approving_review_count]=1" -f "enforce_admins=false" -f "required_status_checks=null" -f "restrictions=null"`),className:"text-[10px] text-text-muted hover:text-accent shrink-0",children:"copy"})]})]}),ep.error&&(0,s.jsx)("p",{className:"text-[11px] text-error mb-2",children:ep.error}),(0,s.jsx)("button",{onClick:eo,disabled:!h||Y,className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:Y?"Verifying...":"Verify & Continue"})]}),ep?.id==="models"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Configure agent CLI backends"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"Each agent runs its own CLI instance. Pick the backend for each role."}),ea&&!ea.claude&&ea.codex&&(0,s.jsxs)("div",{className:"border border-accent/20 bg-accent/5 p-3 mb-4 text-[11px]",children:[(0,s.jsx)("p",{className:"text-text",children:"You have Codex CLI installed — great! All 4 agents will use Codex."}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"Tip: Installing Claude Code too gives your team different AI perspectives, which can improve code review quality. You can add it anytime:"}),(0,s.jsx)("p",{className:"text-accent mt-1 font-mono text-[10px]",children:"npm install -g @anthropic-ai/claude-code"}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"For now, Codex CLI handles everything perfectly. Let's continue!"})]}),ea&&ea.claude&&!ea.codex&&(0,s.jsxs)("div",{className:"border border-accent/20 bg-accent/5 p-3 mb-4 text-[11px]",children:[(0,s.jsx)("p",{className:"text-text",children:"You have Claude Code installed — great! All 4 agents will use Claude."}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"Tip: Installing Codex CLI too gives your team different AI perspectives, which can improve code review quality. You can add it anytime:"}),(0,s.jsx)("p",{className:"text-accent mt-1 font-mono text-[10px]",children:"npm install -g codex"}),(0,s.jsx)("p",{className:"text-text-muted mt-1.5",children:"For now, Claude Code handles everything perfectly. Let's continue!"})]}),(0,s.jsx)("div",{className:"border border-border mb-4",children:l.map(e=>(0,s.jsxs)("div",{className:"flex items-center justify-between px-3 py-2 border-b border-border/50 last:border-b-0",children:[(0,s.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,s.jsx)("span",{className:"text-[11px] text-text font-semibold block",children:e.label}),(0,s.jsx)("span",{className:"text-[10px] text-text-muted",children:e.desc})]}),(0,s.jsx)("select",{value:T[e.key],onChange:t=>P({...T,[e.key]:t.target.value}),className:"bg-transparent border border-border px-2 py-0.5 text-[11px] text-text outline-none focus:border-accent cursor-pointer ml-3",children:n.map(e=>(0,s.jsxs)("option",{value:e.value,className:"bg-bg-surface",disabled:!!ea&&!ea[e.value],children:[e.label,ea&&!ea[e.value]?" (not installed)":""]},e.value))})]},e.key))}),(0,s.jsxs)("label",{className:"flex items-center gap-2 mb-3 cursor-pointer",children:[(0,s.jsx)("input",{type:"checkbox",checked:$,onChange:e=>q(e.target.checked),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text-muted",children:"Configure reviewer credentials (for GitHub PR reviews)"})]}),$&&(0,s.jsxs)("div",{className:"border border-border p-3 mb-4 space-y-3",children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{className:"text-[11px] text-text-muted block mb-1",children:"Reviewer GitHub username"}),(0,s.jsx)("input",{value:H,onChange:e=>I(e.target.value),placeholder:"github-username",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{className:"text-[11px] text-text-muted block mb-2",children:"Token source"}),(0,s.jsxs)("div",{className:"flex gap-4 mb-2",children:[(0,s.jsxs)("label",{className:"flex items-center gap-1.5 cursor-pointer",children:[(0,s.jsx)("input",{type:"radio",name:"tokenMode",checked:"paste"===A,onChange:()=>L("paste"),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text",children:"Paste token"})]}),(0,s.jsxs)("label",{className:"flex items-center gap-1.5 cursor-pointer",children:[(0,s.jsx)("input",{type:"radio",name:"tokenMode",checked:"file"===A,onChange:()=>L("file"),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text",children:"Use existing file"})]})]}),"paste"===A?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:E,onChange:e=>F(e.target.value),placeholder:"ghp_xxxxxxxxxxxxxxxxxxxx",type:"password",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent"}),(0,s.jsxs)("div",{className:"mt-2 text-[10px] text-text-muted leading-relaxed",children:[(0,s.jsxs)("p",{children:["Paste a GitHub ",(0,s.jsx)("span",{className:"text-text",children:"Personal Access Token (classic)"}),"."]}),(0,s.jsxs)("p",{className:"mt-1",children:["Create one at"," ",(0,s.jsx)("a",{href:"https://github.com/settings/tokens",target:"_blank",rel:"noopener noreferrer",className:"text-accent hover:underline",children:"github.com/settings/tokens"})," ","→ Generate new token (classic)"]}),(0,s.jsxs)("p",{className:"mt-1",children:["Required permission: ",(0,s.jsx)("span",{className:"text-accent",children:"repo"})," (Full control of private repositories)",(0,s.jsx)("br",{}),(0,s.jsx)("span",{className:"text-text-muted",children:"Needed for reading PRs, posting reviews, and approving/requesting changes"})]})]})]}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("input",{value:U,onChange:e=>W(e.target.value),placeholder:"~/.quadwork/reviewer-token",className:"w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent"}),U&&!U.startsWith("~/.quadwork")&&!U.startsWith(String.raw`${t.default.env.HOME}/.quadwork`)&&(0,s.jsx)("p",{className:"text-[10px] text-[#ffcc00] mt-1",children:"This path may be inside a git repository. Consider using the default ~/.quadwork/ location to avoid accidentally committing tokens."})]})]})]}),(0,s.jsx)("button",{onClick:en,className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors",children:"Next"})]}),ep?.id==="workdir"&&(0,s.jsx)(o,{repo:h,workingDir:D,setWorkingDir:G,error:ep.error,onNext:en}),ep?.id==="workspaces"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Create workspaces"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"This creates git worktrees for each agent and writes seed configuration files (AGENTS.md, CLAUDE.md) into each workspace."}),ep.error&&(0,s.jsx)("p",{className:"text-[11px] text-error mb-2",children:ep.error}),z.length>0&&(0,s.jsx)("div",{className:"border border-border bg-bg-surface p-3 mb-4 text-[11px] text-text-muted space-y-0.5 font-mono",children:z.map((e,t)=>(0,s.jsx)("p",{children:e},t))}),(0,s.jsx)("button",{onClick:ei,disabled:Y,className:"px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:Y?"Creating...":"Create Worktrees & Seed Files"})]}),ep?.id==="launch"&&(0,s.jsxs)("div",{children:[(0,s.jsx)("h2",{className:"text-sm font-semibold text-text mb-1",children:"Ready to launch"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mb-4",children:"Everything is configured. Review the summary and launch your AI dev team."}),(0,s.jsxs)("div",{className:"border border-border mb-4",children:[(0,s.jsx)("div",{className:"px-3 py-1.5 border-b border-border bg-bg-surface",children:(0,s.jsx)("span",{className:"text-[11px] text-text font-semibold",children:"Team Roster"})}),l.map(e=>(0,s.jsxs)("div",{className:"flex items-center justify-between px-3 py-1.5 border-b border-border/50 last:border-b-0",children:[(0,s.jsx)("span",{className:"text-[11px] text-text font-semibold",children:e.label}),(0,s.jsx)("span",{className:"text-[10px] text-text-muted",children:e.role}),(0,s.jsx)("span",{className:"text-[11px] text-accent",children:"claude"===T[e.key]?"Claude Code":"Codex"})]},e.key))]}),(0,s.jsxs)("div",{className:"mb-4",children:[(0,s.jsxs)("label",{className:"flex items-center gap-2 cursor-pointer mb-2",children:[(0,s.jsx)("input",{type:"checkbox",checked:X,onChange:e=>Q(e.target.checked),className:"accent-accent"}),(0,s.jsx)("span",{className:"text-[11px] text-text-muted",children:"Custom ports"})]}),X&&(0,s.jsx)("div",{className:"border border-border p-3 space-y-2",children:(0,s.jsxs)("div",{className:"grid grid-cols-3 gap-3",children:[(0,s.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,s.jsx)("label",{className:"text-[10px] text-text-muted uppercase tracking-wider",children:"AgentChattr port"}),(0,s.jsx)("input",{type:"number",value:Z.chattr||"",onChange:e=>ee({...Z,chattr:parseInt(e.target.value,10)||0}),placeholder:String(et.chattr||8300),className:"bg-transparent border border-border px-2 py-1 text-[11px] text-text outline-none focus:border-accent"}),et.chattr>0&&(0,s.jsxs)("span",{className:"text-[10px] text-text-muted",children:["auto-detected: ",et.chattr]})]}),(0,s.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,s.jsx)("label",{className:"text-[10px] text-text-muted uppercase tracking-wider",children:"MCP HTTP port"}),(0,s.jsx)("input",{type:"number",value:Z.mcpHttp||"",onChange:e=>ee({...Z,mcpHttp:parseInt(e.target.value,10)||0}),placeholder:String(et.mcpHttp||8200),className:"bg-transparent border border-border px-2 py-1 text-[11px] text-text outline-none focus:border-accent"}),et.mcpHttp>0&&(0,s.jsxs)("span",{className:"text-[10px] text-text-muted",children:["auto-detected: ",et.mcpHttp]})]}),(0,s.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,s.jsx)("label",{className:"text-[10px] text-text-muted uppercase tracking-wider",children:"MCP SSE port"}),(0,s.jsx)("input",{type:"number",value:Z.mcpSse||"",onChange:e=>ee({...Z,mcpSse:parseInt(e.target.value,10)||0}),placeholder:String(et.mcpSse||8201),className:"bg-transparent border border-border px-2 py-1 text-[11px] text-text outline-none focus:border-accent"}),et.mcpSse>0&&(0,s.jsxs)("span",{className:"text-[10px] text-text-muted",children:["auto-detected: ",et.mcpSse]})]})]})})]}),ep.error&&(0,s.jsx)("p",{className:"text-[11px] text-error mb-2",children:ep.error}),"done"===K&&(0,s.jsx)("p",{className:"text-[11px] text-accent mb-2",children:"Project saved. Redirecting to dashboard..."}),(0,s.jsx)("button",{onClick:ed,disabled:"running"===K||"done"===K,className:"px-5 py-2 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50",children:"running"===K?"Launching...":"done"===K?"Launched!":"Launch Project"})]}),x>=i.length&&(0,s.jsxs)("div",{className:"text-center py-8",children:[(0,s.jsx)("p",{className:"text-accent text-sm font-semibold",children:"Setup complete!"}),(0,s.jsx)("p",{className:"text-[11px] text-text-muted mt-2",children:"Redirecting to project dashboard..."})]})]})]}),(0,s.jsxs)("div",{className:"w-64 shrink-0 border-l border-border p-4 overflow-y-auto bg-bg-surface/50",children:[(0,s.jsx)("h3",{className:"text-[11px] font-semibold text-text-muted uppercase tracking-wider mb-3",children:"Configuration Preview"}),(0,s.jsxs)("div",{className:"space-y-3 text-[11px]",children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Project"}),(0,s.jsx)("span",{className:"text-text",children:m||"—"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Repository"}),(0,s.jsx)("span",{className:"text-text",children:h||"—"}),_&&(0,s.jsx)("span",{className:"text-[10px] text-accent block",children:"+ branch protection"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Backends"}),Object.entries(T).map(([e,t])=>(0,s.jsxs)("div",{className:"flex justify-between",children:[(0,s.jsx)("span",{className:"text-text capitalize",children:e}),(0,s.jsx)("span",{className:"text-accent",children:t})]},e))]}),$&&H&&(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Reviewer"}),(0,s.jsxs)("span",{className:"text-text",children:["@",H]})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Directory"}),(0,s.jsx)("span",{className:"text-text font-mono text-[10px]",children:D||"—"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("span",{className:"text-text-muted block mb-0.5",children:"Status"}),(0,s.jsx)("div",{className:"space-y-0.5",children:i.map(e=>(0,s.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,s.jsx)("span",{className:`text-[10px] ${"done"===e.status?"text-accent":"error"===e.status?"text-error":"active"===e.status?"text-text":"text-text-muted"}`,children:"done"===e.status?"✓":"error"===e.status?"✗":"active"===e.status?"●":"○"}),(0,s.jsx)("span",{className:`text-[10px] ${"active"===e.status?"text-text":"text-text-muted"}`,children:e.label})]},e.id))})]})]})]})]})]})}])}]);
@@ -1,2 +0,0 @@
1
- @font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2)format("woff2");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Geist Mono Fallback;src:local(Arial);ascent-override:74.67%;descent-override:21.92%;line-gap-override:0.0%;size-adjust:134.59%}.geist_mono_8d43a2aa-module__8Li5zG__className{font-family:Geist Mono,Geist Mono Fallback;font-style:normal}.geist_mono_8d43a2aa-module__8Li5zG__variable{--font-geist-mono:"Geist Mono", "Geist Mono Fallback"}
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--color-red-400:#ff6568;--color-red-500:#fb2c36;--color-red-700:#bf000f;--color-red-900:#82181a;--color-green-500:#00c758;--spacing:.25rem;--container-3xl:48rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-sm:.25rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-geist-mono)}@supports (color:lab(0% 0 0)){:root,:host{--color-red-400:lab(63.7053% 60.745 31.3109);--color-red-500:lab(55.4814% 75.0732 48.8528);--color-red-700:lab(40.4273% 67.2623 53.7441);--color-red-900:lab(28.5139% 44.5539 29.0463);--color-green-500:lab(70.5521% -66.5147 45.8073)}}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0\.5{top:calc(var(--spacing) * .5)}.right-0{right:calc(var(--spacing) * 0)}.bottom-full{bottom:100%}.left-0{left:calc(var(--spacing) * 0)}.left-0\.5{left:calc(var(--spacing) * .5)}.left-4{left:calc(var(--spacing) * 4)}.left-16{left:calc(var(--spacing) * 16)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-0\.5{margin-inline:calc(var(--spacing) * .5)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-4{margin-block:calc(var(--spacing) * 4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-10{height:calc(var(--spacing) * 10)}.h-\[calc\(100\%-80px\)\]{height:calc(100% - 80px)}.h-full{height:100%}.h-px{height:1px}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-48{max-height:calc(var(--spacing) * 48)}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[88px\]{min-height:88px}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-3{width:calc(var(--spacing) * 3)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-44{width:calc(var(--spacing) * 44)}.w-64{width:calc(var(--spacing) * 64)}.w-full{width:100%}.w-px{width:1px}.max-w-3xl{max-width:var(--container-3xl)}.max-w-5xl{max-width:var(--container-5xl)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[140px\]{min-width:140px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-col-resize{cursor:col-resize}.cursor-move{cursor:move}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.resize{resize:both}.resize-none{resize:none}.resize-y{resize:vertical}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.self-stretch{align-self:stretch}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent,.border-accent\/20{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/20{border-color:color-mix(in oklab, var(--accent) 20%, transparent)}}.border-accent\/30{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/30{border-color:color-mix(in oklab, var(--accent) 30%, transparent)}}.border-accent\/40{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/40{border-color:color-mix(in oklab, var(--accent) 40%, transparent)}}.border-accent\/50{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/50{border-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.border-border,.border-border\/50{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/50{border-color:color-mix(in oklab, var(--border) 50%, transparent)}}.border-error,.border-error\/60{border-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.border-error\/60{border-color:color-mix(in oklab, var(--error) 60%, transparent)}}.border-red-700\/50{border-color:#bf000f80}@supports (color:color-mix(in lab, red, red)){.border-red-700\/50{border-color:color-mix(in oklab, var(--color-red-700) 50%, transparent)}}.bg-\[\#ffcc00\]{background-color:#fc0}.bg-accent,.bg-accent\/5{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/5{background-color:color-mix(in oklab, var(--accent) 5%, transparent)}}.bg-accent\/10{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/10{background-color:color-mix(in oklab, var(--accent) 10%, transparent)}}.bg-bg{background-color:var(--bg)}.bg-bg-surface,.bg-bg-surface\/50{background-color:var(--bg-surface)}@supports (color:color-mix(in lab, red, red)){.bg-bg-surface\/50{background-color:color-mix(in oklab, var(--bg-surface) 50%, transparent)}}.bg-border{background-color:var(--border)}.bg-error,.bg-error\/10{background-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.bg-error\/10{background-color:color-mix(in oklab, var(--error) 10%, transparent)}}.bg-green-500{background-color:var(--color-green-500)}.bg-red-500{background-color:var(--color-red-500)}.bg-red-900\/30{background-color:#82181a4d}@supports (color:color-mix(in lab, red, red)){.bg-red-900\/30{background-color:color-mix(in oklab, var(--color-red-900) 30%, transparent)}}.bg-text{background-color:var(--text)}.bg-text-muted{background-color:var(--text-muted)}.bg-transparent{background-color:#0000}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-geist-mono)}.font-sans{font-family:var(--font-sans)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#ffcc00\]{color:#fc0}.text-accent,.text-accent\/70{color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.text-accent\/70{color:color-mix(in oklab, var(--accent) 70%, transparent)}}.text-bg{color:var(--bg)}.text-error{color:var(--error)}.text-red-400{color:var(--color-red-400)}.text-text{color:var(--text)}.text-text-muted{color:var(--text-muted)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.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,)}.line-through{text-decoration-line:line-through}.accent-accent{accent-color:var(--accent)}.opacity-0{opacity:0}.opacity-60{opacity:.6}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}@media (hover:hover){.group-hover\:block:is(:where(.group):hover *){display:block}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-text-muted::placeholder{color:var(--text-muted)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:border-accent:hover,.hover\:border-accent\/40:hover{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:border-accent\/40:hover{border-color:color-mix(in oklab, var(--accent) 40%, transparent)}}.hover\:border-error:hover,.hover\:border-error\/40:hover{border-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.hover\:border-error\/40:hover{border-color:color-mix(in oklab, var(--error) 40%, transparent)}}.hover\:border-text-muted:hover{border-color:var(--text-muted)}.hover\:bg-\[\#1a1a1a\]:hover{background-color:#1a1a1a}.hover\:bg-accent-dim:hover{background-color:var(--accent-dim)}.hover\:bg-accent\/5:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/5:hover{background-color:color-mix(in oklab, var(--accent) 5%, transparent)}}.hover\:bg-accent\/10:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/10:hover{background-color:color-mix(in oklab, var(--accent) 10%, transparent)}}.hover\:bg-accent\/20:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/20:hover{background-color:color-mix(in oklab, var(--accent) 20%, transparent)}}.hover\:bg-error\/20:hover{background-color:var(--error)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-error\/20:hover{background-color:color-mix(in oklab, var(--error) 20%, transparent)}}.hover\:text-accent:hover{color:var(--accent)}.hover\:text-error:hover{color:var(--error)}.hover\:text-text:hover{color:var(--text)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:border-accent:focus{border-color:var(--accent)}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-accent:focus{--tw-ring-color:var(--accent)}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:root{--bg:#0a0a0a;--bg-surface:#111;--text:#e0e0e0;--text-muted:#737373;--accent:#0f8;--accent-dim:#00cc6a;--border:#2a2a2a;--error:#f44}::selection{background:var(--accent);color:var(--bg)}body{background:var(--bg);color:var(--text);font-family:var(--font-geist-mono), ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{font-family:var(--font-geist-mono), ui-monospace, monospace;letter-spacing:-.01em}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:var(--bg)}::-webkit-scrollbar-thumb{background:var(--border);border-radius:0}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}:focus-visible{outline:1px solid var(--accent);outline-offset:1px}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@keyframes pulse{50%{opacity:.5}}