quadwork 0.1.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +58 -83
  2. package/bin/quadwork.js +372 -58
  3. package/out/404.html +1 -1
  4. package/out/__next.__PAGE__.txt +1 -1
  5. package/out/__next._full.txt +2 -2
  6. package/out/__next._head.txt +1 -1
  7. package/out/__next._index.txt +2 -2
  8. package/out/__next._tree.txt +2 -2
  9. package/out/_next/static/chunks/0ahp74n0wkel0.js +1 -0
  10. package/out/_next/static/chunks/{038g944ax83al.js → 0dmi9pk2bd712.js} +3 -3
  11. package/out/_next/static/chunks/0ezniz80psxr6.js +1 -0
  12. package/out/_next/static/chunks/0g-nq4.uckan-.js +1 -0
  13. package/out/_next/static/chunks/0io_y3d0p5v~b.js +2 -0
  14. package/out/_next/static/chunks/0jt42fqe6jaw6.js +1 -0
  15. package/out/_next/static/chunks/{0wda-2lcle8c4.js → 0q5hwcek8vu2q.js} +12 -12
  16. package/out/_next/static/chunks/0r_tb4lmfa_yb.js +1 -0
  17. package/out/_next/static/chunks/0s8jbc4nxw6y6.css +2 -0
  18. package/out/_next/static/chunks/0z~0.4hivi.f2.js +31 -0
  19. package/out/_next/static/chunks/135rms05ismy4.js +13 -0
  20. package/out/_next/static/chunks/14kr4rvjq-2md.js +1 -0
  21. package/out/_next/static/chunks/turbopack-0sammtvunroor.js +1 -0
  22. package/out/_not-found/__next._full.txt +2 -2
  23. package/out/_not-found/__next._head.txt +1 -1
  24. package/out/_not-found/__next._index.txt +2 -2
  25. package/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
  26. package/out/_not-found/__next._not-found.txt +1 -1
  27. package/out/_not-found/__next._tree.txt +2 -2
  28. package/out/_not-found.html +1 -1
  29. package/out/_not-found.txt +2 -2
  30. package/out/app-shell/__next._full.txt +18 -0
  31. package/out/app-shell/__next._head.txt +6 -0
  32. package/out/app-shell/__next._index.txt +6 -0
  33. package/out/app-shell/__next._tree.txt +3 -0
  34. package/out/app-shell/__next.app-shell.__PAGE__.txt +5 -0
  35. package/out/app-shell/__next.app-shell.txt +5 -0
  36. package/out/app-shell.html +1 -0
  37. package/out/app-shell.txt +18 -0
  38. package/out/index.html +1 -1
  39. package/out/index.txt +2 -2
  40. package/out/project/_/__next._full.txt +3 -4
  41. package/out/project/_/__next._head.txt +1 -1
  42. package/out/project/_/__next._index.txt +2 -2
  43. package/out/project/_/__next._tree.txt +2 -3
  44. package/out/project/_/__next.project.$d$id.__PAGE__.txt +2 -3
  45. package/out/project/_/__next.project.$d$id.txt +1 -1
  46. package/out/project/_/__next.project.txt +1 -1
  47. package/out/project/_/memory/__next._full.txt +3 -3
  48. package/out/project/_/memory/__next._head.txt +1 -1
  49. package/out/project/_/memory/__next._index.txt +2 -2
  50. package/out/project/_/memory/__next._tree.txt +2 -2
  51. package/out/project/_/memory/__next.project.$d$id.memory.__PAGE__.txt +2 -2
  52. package/out/project/_/memory/__next.project.$d$id.memory.txt +1 -1
  53. package/out/project/_/memory/__next.project.$d$id.txt +1 -1
  54. package/out/project/_/memory/__next.project.txt +1 -1
  55. package/out/project/_/memory.html +1 -1
  56. package/out/project/_/memory.txt +3 -3
  57. package/out/project/_/queue/__next._full.txt +3 -3
  58. package/out/project/_/queue/__next._head.txt +1 -1
  59. package/out/project/_/queue/__next._index.txt +2 -2
  60. package/out/project/_/queue/__next._tree.txt +2 -2
  61. package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +2 -2
  62. package/out/project/_/queue/__next.project.$d$id.queue.txt +1 -1
  63. package/out/project/_/queue/__next.project.$d$id.txt +1 -1
  64. package/out/project/_/queue/__next.project.txt +1 -1
  65. package/out/project/_/queue.html +1 -1
  66. package/out/project/_/queue.txt +3 -3
  67. package/out/project/_.html +1 -1
  68. package/out/project/_.txt +3 -4
  69. package/out/settings/__next._full.txt +3 -3
  70. package/out/settings/__next._head.txt +1 -1
  71. package/out/settings/__next._index.txt +2 -2
  72. package/out/settings/__next._tree.txt +2 -2
  73. package/out/settings/__next.settings.__PAGE__.txt +2 -2
  74. package/out/settings/__next.settings.txt +1 -1
  75. package/out/settings.html +1 -1
  76. package/out/settings.txt +3 -3
  77. package/out/setup/__next._full.txt +3 -3
  78. package/out/setup/__next._head.txt +1 -1
  79. package/out/setup/__next._index.txt +2 -2
  80. package/out/setup/__next._tree.txt +2 -2
  81. package/out/setup/__next.setup.__PAGE__.txt +2 -2
  82. package/out/setup/__next.setup.txt +1 -1
  83. package/out/setup.html +1 -1
  84. package/out/setup.txt +3 -3
  85. package/package.json +1 -1
  86. package/server/config.js +25 -1
  87. package/server/index.js +248 -15
  88. package/server/routes.js +91 -2
  89. package/out/_next/static/chunks/0.dzh0qf9zq1l.js +0 -2
  90. package/out/_next/static/chunks/02ul7y114vj2f.js +0 -13
  91. package/out/_next/static/chunks/0gy_9ugdx7ueh.js +0 -1
  92. package/out/_next/static/chunks/0idtc5k0469of.js +0 -1
  93. package/out/_next/static/chunks/0yxmvmvm1dx_d.css +0 -2
  94. package/out/_next/static/chunks/13uu.sohs74zg.js +0 -31
  95. package/out/_next/static/chunks/turbopack-06pqx~0d8czn_.js +0 -1
  96. /package/out/_next/static/{91YUiFoMbLQ9sZW4uk45J → 4vrILyy2mh_Ox4JMTaqx8}/_buildManifest.js +0 -0
  97. /package/out/_next/static/{91YUiFoMbLQ9sZW4uk45J → 4vrILyy2mh_Ox4JMTaqx8}/_clientMiddlewareManifest.js +0 -0
  98. /package/out/_next/static/{91YUiFoMbLQ9sZW4uk45J → 4vrILyy2mh_Ox4JMTaqx8}/_ssgManifest.js +0 -0
package/bin/quadwork.js CHANGED
@@ -164,46 +164,295 @@ function writeConfig(config) {
164
164
 
165
165
  let agentChattrFound = false;
166
166
 
167
- function checkPrereqs() {
167
+ function detectPlatform() {
168
+ const p = os.platform();
169
+ if (p === "darwin") return "macos";
170
+ if (p === "linux") {
171
+ // Check for apt vs dnf vs yum
172
+ if (which("apt")) return "linux-apt";
173
+ if (which("dnf")) return "linux-dnf";
174
+ if (which("yum")) return "linux-yum";
175
+ return "linux";
176
+ }
177
+ return "other";
178
+ }
179
+
180
+ async function tryInstall(rl, name, description, commands, { platform } = {}) {
181
+ const cmd = typeof commands === "function" ? commands(platform) : commands;
182
+ if (!cmd) {
183
+ warn(`${name} cannot be auto-installed on your system.`);
184
+ return false;
185
+ }
186
+ console.log("");
187
+ log(`${description}`);
188
+ const doInstall = await askYN(rl, `Install ${name} now?`, true);
189
+ if (!doInstall) {
190
+ log("Skipped.");
191
+ return false;
192
+ }
193
+ const sp = spinner(`Installing ${name}...`);
194
+ const result = run(`${cmd} 2>&1`, { timeout: 120000 });
195
+ if (result !== null) {
196
+ sp.stop(true);
197
+ return true;
198
+ } else {
199
+ sp.stop(false);
200
+ warn(`Auto-install failed. You can install manually and try again.`);
201
+ return false;
202
+ }
203
+ }
204
+
205
+ async function checkPrereqs(rl) {
168
206
  header("Step 1: Prerequisites");
207
+ const platform = detectPlatform();
169
208
  let allOk = true;
209
+ let hasPython = false;
210
+ let hasPipx = false;
170
211
 
171
- // Node.js 20+
212
+ // ── 1. Node.js 20+ (must already exist — user ran npx) ──
172
213
  const nodeVer = run("node --version");
173
214
  if (nodeVer) {
174
215
  const major = parseInt(nodeVer.replace("v", "").split(".")[0], 10);
175
- if (major >= 20) ok(`Node.js ${nodeVer}`);
176
- else { fail(`Node.js ${nodeVer} — need 20+`); allOk = false; }
177
- } else { fail("Node.js not found"); allOk = false; }
216
+ if (major >= 20) {
217
+ ok(`Node.js ${nodeVer}`);
218
+ } else {
219
+ fail(`Node.js ${nodeVer} — version 20 or newer is required`);
220
+ log("Update from: https://nodejs.org");
221
+ allOk = false;
222
+ }
223
+ } else {
224
+ fail("Node.js not found (this shouldn't happen since you ran npx)");
225
+ allOk = false;
226
+ }
178
227
 
179
- // Python 3.10+
228
+ // ── 2. Python 3.10+ (manual install — guide only) ──
180
229
  const pyVer = run("python3 --version");
181
230
  if (pyVer) {
182
231
  const parts = pyVer.replace("Python ", "").split(".");
183
232
  const minor = parseInt(parts[1], 10);
184
- if (parseInt(parts[0], 10) >= 3 && minor >= 10) ok(`${pyVer}`);
185
- else { fail(`${pyVer} — need 3.10+`); allOk = false; }
186
- } else { fail("Python 3 not found"); allOk = false; }
233
+ if (parseInt(parts[0], 10) >= 3 && minor >= 10) {
234
+ ok(`${pyVer}`);
235
+ hasPython = true;
236
+ } else {
237
+ console.log("");
238
+ warn(`${pyVer} found, but version 3.10 or newer is required.`);
239
+ log("Python powers the agent communication layer.");
240
+ log("Download the latest version from:");
241
+ log(` → https://python.org/downloads`);
242
+ log("");
243
+ log("After installing, close and reopen your terminal, then run:");
244
+ log(" → npx quadwork init");
245
+ allOk = false;
246
+ }
247
+ } else {
248
+ console.log("");
249
+ warn("Python 3 is required but not installed on your system.");
250
+ log("");
251
+ log("Python powers the agent communication layer. Install it from:");
252
+ log(" → https://python.org/downloads (download and run the installer)");
253
+ log("");
254
+ log("After installing, close and reopen your terminal, then run:");
255
+ log(" → npx quadwork init");
256
+ allOk = false;
257
+ }
187
258
 
188
- // AgentChattr
259
+ if (!hasPython) {
260
+ // Can't continue with pipx/AgentChattr without Python
261
+ console.log("");
262
+ fail("Python is required before we can set up the remaining tools.");
263
+ log("Install Python first, then re-run: npx quadwork init");
264
+ return false;
265
+ }
266
+
267
+ // ── 3. pipx (needs Python) ──
268
+ if (which("pipx")) {
269
+ ok("pipx");
270
+ hasPipx = true;
271
+ } else {
272
+ console.log("");
273
+ warn("pipx is needed to install AgentChattr safely.");
274
+ log("(pipx keeps Python tools isolated so they don't conflict with your system)");
275
+ const installed = await tryInstall(rl, "pipx", "We can install it automatically.",
276
+ "python3 -m pip install --user pipx && python3 -m pipx ensurepath");
277
+ if (installed && which("pipx")) {
278
+ ok("pipx installed");
279
+ hasPipx = true;
280
+ } else if (installed) {
281
+ // pipx installed but not in PATH yet
282
+ warn("pipx was installed but isn't in your PATH yet.");
283
+ log("Close and reopen your terminal, then run: npx quadwork init");
284
+ return false;
285
+ } else {
286
+ warn("pipx skipped — you can install it later:");
287
+ log(" → python3 -m pip install --user pipx && pipx ensurepath");
288
+ }
289
+ }
290
+
291
+ // ── 4. AgentChattr (needs pipx) ──
189
292
  const acVer = run("agentchattr --version") || run("python3 -m agentchattr --version");
190
- if (acVer) { ok(`AgentChattr ${acVer}`); agentChattrFound = true; }
191
- else { warn("AgentChattr not found — install: pip install agentchattr"); allOk = false; }
293
+ if (acVer) {
294
+ ok(`AgentChattr ${acVer}`);
295
+ agentChattrFound = true;
296
+ } else if (hasPipx) {
297
+ console.log("");
298
+ warn("AgentChattr lets your AI agents communicate with each other.");
299
+ const installed = await tryInstall(rl, "AgentChattr",
300
+ "We can install it now using pipx.", "pipx install agentchattr");
301
+ const acVerAfter = run("agentchattr --version") || run("python3 -m agentchattr --version");
302
+ if (acVerAfter) {
303
+ ok(`AgentChattr ${acVerAfter} installed`);
304
+ agentChattrFound = true;
305
+ } else {
306
+ warn("AgentChattr not available — agents won't be able to chat until it's installed.");
307
+ log(" → Install later: pipx install agentchattr");
308
+ allOk = false;
309
+ }
310
+ } else {
311
+ warn("AgentChattr not found — install pipx first, then: pipx install agentchattr");
312
+ allOk = false;
313
+ }
192
314
 
193
- // gh CLI
194
- if (which("gh")) ok("GitHub CLI (gh)");
195
- else { fail("GitHub CLI not found — install: https://cli.github.com"); allOk = false; }
315
+ // ── 5. GitHub CLI (independent) ──
316
+ if (which("gh")) {
317
+ ok("GitHub CLI (gh)");
318
+ } else {
319
+ console.log("");
320
+ warn("GitHub CLI is required for agents to create branches, PRs, and reviews.");
321
+ const ghCmd = (p) => {
322
+ if (p === "macos") return "brew install gh";
323
+ if (p === "linux-apt") return "sudo apt install gh -y";
324
+ if (p === "linux-dnf") return "sudo dnf install gh -y";
325
+ return null;
326
+ };
327
+ const cmd = ghCmd(platform);
328
+ if (cmd) {
329
+ const installed = await tryInstall(rl, "GitHub CLI",
330
+ "We can install it now.", ghCmd, { platform });
331
+ if (installed && which("gh")) {
332
+ ok("GitHub CLI installed");
333
+ } else {
334
+ fail("GitHub CLI is required. Install from: https://cli.github.com");
335
+ allOk = false;
336
+ }
337
+ } else {
338
+ fail("GitHub CLI is required. Install from: https://cli.github.com");
339
+ allOk = false;
340
+ }
341
+ }
342
+
343
+ // ── 6. AI CLIs — at least one required (independent) ──
344
+ let hasClaude = which("claude");
345
+ let hasCodex = which("codex");
196
346
 
197
- // Claude Code or Codex
198
- const hasClaude = which("claude");
199
- const hasCodex = which("codex");
200
347
  if (hasClaude) ok("Claude Code");
201
348
  if (hasCodex) ok("Codex CLI");
349
+
202
350
  if (!hasClaude && !hasCodex) {
203
- fail("No AI CLI found — install Claude Code or Codex CLI");
351
+ console.log("");
352
+ warn("You need at least one AI CLI to power your agents.");
353
+ log("Choose one (or both) to install:");
354
+ console.log("");
355
+ }
356
+
357
+ // Offer to install Claude Code if missing
358
+ if (!hasClaude) {
359
+ const isRequired = !hasCodex;
360
+ log("Claude Code — Anthropic's AI coding assistant");
361
+ const installClaude = await askYN(rl, "Install Claude Code?", isRequired);
362
+ if (installClaude) {
363
+ const sp = spinner("Installing Claude Code...");
364
+ const result = run("npm install -g @anthropic-ai/claude-code 2>&1", { timeout: 120000 });
365
+ sp.stop(result !== null);
366
+ hasClaude = which("claude");
367
+ if (hasClaude) ok("Claude Code installed");
368
+ else warn("Install failed — try manually: npm install -g @anthropic-ai/claude-code");
369
+ }
370
+ }
371
+
372
+ // Offer to install Codex CLI if missing
373
+ if (!hasCodex) {
374
+ const isRequired = !hasClaude;
375
+ if (hasClaude) {
376
+ console.log("");
377
+ log("Tip: Installing Codex CLI too gives your team different AI perspectives.");
378
+ }
379
+ log("Codex CLI — OpenAI's AI coding assistant");
380
+ const installCodex = await askYN(rl, "Install Codex CLI?", isRequired);
381
+ if (installCodex) {
382
+ const sp = spinner("Installing Codex CLI...");
383
+ const result = run("npm install -g codex 2>&1", { timeout: 120000 });
384
+ sp.stop(result !== null);
385
+ hasCodex = which("codex");
386
+ if (hasCodex) ok("Codex CLI installed");
387
+ else warn("Install failed — try manually: npm install -g codex");
388
+ }
389
+ }
390
+
391
+ if (!hasClaude && !hasCodex) {
392
+ fail("At least one AI CLI is required (Claude Code or Codex CLI).");
393
+ log("Install one and re-run: npx quadwork init");
204
394
  allOk = false;
205
395
  }
206
396
 
397
+ // ── CLI Authentication Checks ──
398
+ if (allOk) {
399
+ console.log("");
400
+ log("Checking CLI authentication...");
401
+ console.log("");
402
+
403
+ // GitHub CLI auth
404
+ const ghAuth = run("gh auth status 2>&1");
405
+ if (ghAuth && ghAuth.includes("Logged in")) {
406
+ ok("GitHub CLI — authenticated");
407
+ } else {
408
+ warn("GitHub CLI is installed but not logged in.");
409
+ log(" Run this command to log in:");
410
+ log(" → gh auth login");
411
+ log("");
412
+ const recheck = await askYN(rl, "Done? Press Y to re-check, or N to continue anyway", false);
413
+ if (recheck) {
414
+ const ghAuth2 = run("gh auth status 2>&1");
415
+ if (ghAuth2 && ghAuth2.includes("Logged in")) {
416
+ ok("GitHub CLI — authenticated");
417
+ } else {
418
+ warn("Still not authenticated — you can set this up later.");
419
+ }
420
+ }
421
+ }
422
+
423
+ // Claude Code auth
424
+ if (hasClaude) {
425
+ const claudeAuth = run("claude auth status 2>&1") || run("claude --version 2>&1");
426
+ if (claudeAuth && (claudeAuth.includes("authenticated") || claudeAuth.includes("Logged in") || claudeAuth.includes("@"))) {
427
+ ok("Claude Code — authenticated");
428
+ } else {
429
+ warn("Claude Code may need authentication.");
430
+ log(" If prompted when agents start, run: claude auth login");
431
+ }
432
+ }
433
+
434
+ // Codex CLI auth
435
+ if (hasCodex) {
436
+ const codexAuth = run("codex auth status 2>&1") || run("codex --version 2>&1");
437
+ if (codexAuth && (codexAuth.includes("authenticated") || codexAuth.includes("Logged in") || codexAuth.includes("@"))) {
438
+ ok("Codex CLI — authenticated");
439
+ } else {
440
+ warn("Codex CLI may need authentication.");
441
+ log(" If prompted when agents start, run: codex auth");
442
+ }
443
+ }
444
+ }
445
+
446
+ // ── Summary ──
447
+ console.log("");
448
+ if (allOk) {
449
+ ok("All prerequisites ready!");
450
+ } else {
451
+ console.log("");
452
+ log("Some prerequisites are missing. Fix the issues above and re-run:");
453
+ log(" → npx quadwork init");
454
+ }
455
+
207
456
  return allOk;
208
457
  }
209
458
 
@@ -247,28 +496,52 @@ async function setupGitHub(rl) {
247
496
  async function setupAgents(rl, repo) {
248
497
  header("Step 3: Agent Configuration");
249
498
 
250
- // Prompt for CLI backend
499
+ // Detect available CLIs
251
500
  const hasClaude = which("claude");
252
501
  const hasCodex = which("codex");
502
+ const bothAvailable = hasClaude && hasCodex;
503
+ const onlyOneCli = (hasClaude && !hasCodex) || (!hasClaude && hasCodex);
253
504
  let defaultBackend = hasClaude ? "claude" : "codex";
254
- log("Choose which AI CLI to run in agent terminals. Claude Code (`claude`) or OpenAI Codex (`codex`).");
255
- const backend = await ask(rl, "Default CLI backend (claude/codex)", defaultBackend);
256
- if (backend !== "claude" && backend !== "codex") {
257
- fail("Backend must be 'claude' or 'codex'");
258
- return null;
259
- }
260
505
 
261
- // Per-agent backend selection
262
506
  const backends = {};
263
- const customPerAgent = await askYN(rl, "Use same backend for all agents?", true);
264
- if (customPerAgent) {
265
- for (const agent of AGENTS) backends[agent] = backend;
266
- } else {
267
- for (const agent of AGENTS) {
268
- const agentBackend = await ask(rl, `${agent.toUpperCase()} backend (claude/codex)`, backend);
269
- backends[agent] = (agentBackend === "claude" || agentBackend === "codex") ? agentBackend : backend;
507
+
508
+ if (onlyOneCli) {
509
+ // Single-CLI mode: default all agents, no prompt needed
510
+ const cliName = hasClaude ? "Claude Code" : "Codex CLI";
511
+ const otherName = hasClaude ? "Codex CLI" : "Claude Code";
512
+ const installCmd = hasClaude ? "npm install -g codex" : "npm install -g @anthropic-ai/claude-code";
513
+ ok(`${cliName} detected all 4 agents will use ${cliName}.`);
514
+ console.log("");
515
+ log(`Tip: Installing ${otherName} too gives your team different AI perspectives,`);
516
+ log(`which can improve code review quality. You can add it anytime:`);
517
+ log(` → ${installCmd}`);
518
+ console.log("");
519
+ for (const agent of AGENTS) backends[agent] = defaultBackend;
520
+ } else if (bothAvailable) {
521
+ log("Both Claude Code and Codex CLI are available.");
522
+ log("Choose which AI CLI to run in agent terminals.");
523
+ const backend = await ask(rl, "Default CLI backend (claude/codex)", defaultBackend);
524
+ if (backend !== "claude" && backend !== "codex") {
525
+ fail("Backend must be 'claude' or 'codex'");
526
+ return null;
527
+ }
528
+ defaultBackend = backend;
529
+
530
+ // Per-agent backend selection
531
+ const customPerAgent = await askYN(rl, "Use same backend for all agents?", true);
532
+ if (customPerAgent) {
533
+ for (const agent of AGENTS) backends[agent] = backend;
534
+ } else {
535
+ for (const agent of AGENTS) {
536
+ const agentBackend = await ask(rl, `${agent.toUpperCase()} backend (claude/codex)`, backend);
537
+ backends[agent] = (agentBackend === "claude" || agentBackend === "codex") ? agentBackend : backend;
538
+ }
270
539
  }
540
+ } else {
541
+ fail("No AI CLI found — install Claude Code or Codex CLI first.");
542
+ return null;
271
543
  }
544
+ const backend = defaultBackend;
272
545
 
273
546
  log("Path to your local clone of the repo. Four worktrees will be created next to it");
274
547
  log("(e.g., project-head/, project-reviewer1/, project-reviewer2/, project-dev/).");
@@ -411,14 +684,14 @@ function writeAgentChattrConfig(setup, configTomlPath, { skipInstall = false } =
411
684
  let acAvailable = which("agentchattr");
412
685
  if (!acAvailable && !skipInstall) {
413
686
  const acSpinner = spinner("Installing AgentChattr...");
414
- const installResult = run("pip install agentchattr 2>&1");
687
+ const installResult = run("pipx install agentchattr 2>&1");
415
688
  if (installResult !== null) {
416
689
  acSpinner.stop(true);
417
690
  acAvailable = which("agentchattr");
418
691
  if (!acAvailable) warn("agentchattr binary not found in PATH after install");
419
692
  } else {
420
693
  acSpinner.stop(false);
421
- warn("Install manually: pip install agentchattr");
694
+ warn("Install manually: pipx install agentchattr");
422
695
  }
423
696
  }
424
697
 
@@ -670,29 +943,25 @@ async function cmdInit() {
670
943
  console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.white}${c.bold}QuadWork Init${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
671
944
  console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.dim}Global setup — projects via web UI${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
672
945
  console.log(` ${c.cyan}${c.bold}╚══════════════════════════════════════════╝${c.reset}`);
673
- console.log(`\n ${c.dim}Tip: Press Enter to accept defaults shown in [brackets].${c.reset}\n`);
946
+ console.log(`\n ${c.dim}Press Enter to accept defaults. Takes under 30 seconds.${c.reset}\n`);
674
947
 
675
948
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
676
949
 
677
950
  try {
678
- // Step 1: Prerequisites
679
- header("Step 1: Prerequisites");
680
- const prereqsOk = checkPrereqs();
951
+ // Step 1: Prerequisites (header printed by checkPrereqs)
952
+ const prereqsOk = await checkPrereqs(rl);
681
953
  if (!prereqsOk) {
682
954
  const proceed = await askYN(rl, "Some prerequisites missing. Continue anyway?", false);
683
955
  if (!proceed) { rl.close(); process.exit(1); }
684
956
  }
685
957
 
686
- // Step 2: Global config
687
- header("Step 2: Global Configuration");
688
- const port = await ask(rl, "Dashboard port", "8400");
689
- const defaultBackend = which("claude") ? "claude" : which("codex") ? "codex" : "claude";
690
- const backend = await ask(rl, "Default CLI backend (claude/codex)", defaultBackend);
958
+ // Step 2: Dashboard port
959
+ header("Step 2: Dashboard Port");
960
+ const port = await ask(rl, "Port for the QuadWork dashboard (Enter for default)", "8400");
691
961
 
692
962
  // Write global config
693
963
  const config = readConfig();
694
964
  config.port = parseInt(port, 10) || 8400;
695
- config.default_backend = backend;
696
965
  writeConfig(config);
697
966
  ok(`Wrote ${CONFIG_PATH}`);
698
967
 
@@ -700,6 +969,7 @@ async function cmdInit() {
700
969
  header("Step 3: Starting Dashboard");
701
970
  const quadworkDir = path.join(__dirname, "..");
702
971
  const serverDir = path.join(quadworkDir, "server");
972
+ let serverPid = null;
703
973
  if (fs.existsSync(path.join(serverDir, "index.js"))) {
704
974
  const server = spawn("node", [serverDir], {
705
975
  stdio: "ignore",
@@ -708,28 +978,59 @@ async function cmdInit() {
708
978
  });
709
979
  server.unref();
710
980
  if (server.pid) {
711
- ok(`Server started (PID: ${server.pid})`);
981
+ serverPid = server.pid;
982
+ ok(`Server started (PID: ${serverPid})`);
712
983
  const pidFile = path.join(CONFIG_DIR, "server.pid");
713
984
  if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
714
- fs.writeFileSync(pidFile, String(server.pid));
985
+ fs.writeFileSync(pidFile, String(serverPid));
715
986
  }
716
987
  } else {
717
988
  warn("Server not found — run from the quadwork directory");
718
989
  }
719
990
 
720
- // Done
991
+ // Done — celebratory welcome
721
992
  const dashPort = parseInt(port, 10) || 8400;
722
993
  const dashboardUrl = `http://127.0.0.1:${dashPort}`;
723
994
 
724
- header("Setup Complete");
725
- log(`Config: ${CONFIG_PATH}`);
726
- log(`Dashboard: ${dashboardUrl}`);
727
- log(`Backend: ${backend}`);
728
- log("");
729
- log("Next steps:");
730
- log(` Open ${c.cyan}${dashboardUrl}/setup${c.reset} to create your first project`);
731
- log(" npx quadwork stop stop all processes");
732
- log("");
995
+ console.log("");
996
+ console.log(` ${c.cyan}${c.bold}╔══════════════════════════════════════════════════════════╗${c.reset}`);
997
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
998
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.green}${c.bold}Welcome to QuadWork!${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
999
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1000
+ console.log(` ${c.cyan}${c.bold}║${c.reset} Your AI-powered dev team is ready to ship. ${c.cyan}${c.bold}║${c.reset}`);
1001
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1002
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.green}*${c.reset} ${c.bold}Head${c.reset} ${c.dim}coordinates & merges${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1003
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.green}*${c.reset} ${c.bold}Dev${c.reset} ${c.dim}— writes all the code${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1004
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.green}*${c.reset} ${c.bold}Reviewer1${c.reset} ${c.dim}— independent code review${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1005
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.green}*${c.reset} ${c.bold}Reviewer2${c.reset} ${c.dim}— independent code review${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1006
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1007
+ console.log(` ${c.cyan}${c.bold}║${c.reset} 4 agents. Full GitHub workflow. Runs while you sleep. ${c.cyan}${c.bold}║${c.reset}`);
1008
+ console.log(` ${c.cyan}${c.bold}║${c.reset} ${c.cyan}${c.bold}║${c.reset}`);
1009
+ console.log(` ${c.cyan}${c.bold}╚══════════════════════════════════════════════════════════╝${c.reset}`);
1010
+ console.log("");
1011
+ if (serverPid) {
1012
+ console.log(` ${c.green}*${c.reset} Server running at ${c.cyan}${dashboardUrl}${c.reset} ${c.dim}(PID: ${serverPid})${c.reset}`);
1013
+ } else {
1014
+ console.log(` ${c.yellow}*${c.reset} Server not started — run ${c.dim}npx quadwork start${c.reset} to launch`);
1015
+ }
1016
+ console.log(` ${c.green}*${c.reset} Config saved to ${c.dim}${CONFIG_PATH}${c.reset}`);
1017
+ console.log("");
1018
+ console.log(` ${c.cyan}${c.bold}--- Create Your First Project ---${c.reset}`);
1019
+ console.log("");
1020
+ console.log(` Your browser is opening now. If not, visit:`);
1021
+ console.log("");
1022
+ console.log(` ${c.cyan}${c.bold}${dashboardUrl}/setup${c.reset}`);
1023
+ console.log("");
1024
+ console.log(` ${c.dim}1.${c.reset} Connect a GitHub repo`);
1025
+ console.log(` ${c.dim}2.${c.reset} Pick models for each agent`);
1026
+ console.log(` ${c.dim}3.${c.reset} Hit Start — your team takes it from there`);
1027
+ console.log("");
1028
+ console.log(` ${c.dim}Commands:${c.reset}`);
1029
+ console.log(` ${c.dim}npx quadwork start${c.reset} — restart everything`);
1030
+ console.log(` ${c.dim}npx quadwork stop${c.reset} — shut it all down`);
1031
+ console.log("");
1032
+ console.log(` ${c.green}${c.bold}Happy shipping!${c.reset}`);
1033
+ console.log("");
733
1034
 
734
1035
  // Open browser
735
1036
  const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -850,6 +1151,19 @@ function cmdStop() {
850
1151
 
851
1152
  if (stopPid("Server", "server.pid")) stopped++;
852
1153
 
1154
+ // Stop caffeinate via the running server's API (targets only QuadWork's instance)
1155
+ if (process.platform === "darwin") {
1156
+ const cfg = readConfig();
1157
+ const qwPort = cfg.port || 8400;
1158
+ try {
1159
+ const result = run(`curl -s -X POST http://127.0.0.1:${qwPort}/api/caffeinate/stop 2>/dev/null`);
1160
+ if (result && result.includes('"ok":true')) {
1161
+ ok("Stopped caffeinate (sleep prevention)");
1162
+ stopped++;
1163
+ }
1164
+ } catch {}
1165
+ }
1166
+
853
1167
  if (stopped === 0) warn("No running processes found");
854
1168
  else ok(`Stopped ${stopped} process(es)`);
855
1169
  log("");
package/out/404.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="en" class="geist_mono_8d43a2aa-module__8Li5zG__variable h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/0yxmvmvm1dx_d.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/13uu.sohs74zg.js"/><script src="/_next/static/chunks/0excsn2a_5qsb.js" async=""></script><script src="/_next/static/chunks/0r7t_sj_sejq9.js" async=""></script><script src="/_next/static/chunks/0.dzh0qf9zq1l.js" async=""></script><script src="/_next/static/chunks/turbopack-06pqx~0d8czn_.js" async=""></script><script src="/_next/static/chunks/08fgie1bcjynm.js" async=""></script><script src="/_next/static/chunks/0ox7p_szjhn69.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.0x3dzn~oxb6tn.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex"><div hidden=""><!--$--><!--/$--></div><aside class="w-16 shrink-0 h-full border-r border-border bg-bg-surface flex flex-col items-center py-3"><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="w-6 h-px bg-border my-2"></div><div class="flex-1 flex flex-col items-center gap-2 overflow-y-auto min-h-0"><a class="w-10 h-10 flex items-center justify-center rounded-full border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="w-6 h-px bg-border my-2"></div><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a></aside><main class="flex-1 min-w-0 overflow-auto"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--></main><script src="/_next/static/chunks/13uu.sohs74zg.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[86081,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n3:I[12527,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n4:I[59763,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n5:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"OutletBoundary\"]\n6:\"$Sreact.suspense\"\n9:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"ViewportBoundary\"]\nb:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"MetadataBoundary\"]\nd:I[92243,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0yxmvmvm1dx_d.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_not-found\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0yxmvmvm1dx_d.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/08fgie1bcjynm.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0ox7p_szjhn69.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L5\",null,{\"children\":[\"$\",\"$6\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@7\"}]}]]}],{},null,false,null]},null,false,\"$@8\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$L9\",null,{\"children\":\"$La\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lb\",null,{\"children\":[\"$\",\"$6\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lc\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0yxmvmvm1dx_d.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"91YUiFoMbLQ9sZW4uk45J\"}\n"])</script><script>self.__next_f.push([1,"e:[]\n8:\"$We\"\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"f:I[80070,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"IconMark\"]\n7:null\nc:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0x3dzn~oxb6tn.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$Lf\",\"3\",{}]]\n"])</script></body></html>
1
+ <!DOCTYPE html><html lang="en" class="geist_mono_8d43a2aa-module__8Li5zG__variable h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/0s8jbc4nxw6y6.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0z~0.4hivi.f2.js"/><script src="/_next/static/chunks/0ezniz80psxr6.js" async=""></script><script src="/_next/static/chunks/0r7t_sj_sejq9.js" async=""></script><script src="/_next/static/chunks/0io_y3d0p5v~b.js" async=""></script><script src="/_next/static/chunks/0excsn2a_5qsb.js" async=""></script><script src="/_next/static/chunks/turbopack-0sammtvunroor.js" async=""></script><script src="/_next/static/chunks/08fgie1bcjynm.js" async=""></script><script src="/_next/static/chunks/0ox7p_szjhn69.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.0x3dzn~oxb6tn.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex"><div hidden=""><!--$--><!--/$--></div><aside class="w-16 shrink-0 h-full border-r border-border bg-bg-surface flex flex-col items-center py-3"><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="w-6 h-px bg-border my-2"></div><div class="flex-1 flex flex-col items-center gap-2 overflow-y-auto min-h-0"><a class="w-10 h-10 flex items-center justify-center rounded-full border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="w-6 h-px bg-border my-2"></div><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a></aside><main class="flex-1 min-w-0 overflow-auto"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--></main><script src="/_next/static/chunks/0z~0.4hivi.f2.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[86081,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n3:I[12527,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n4:I[59763,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n5:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"OutletBoundary\"]\n6:\"$Sreact.suspense\"\n9:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"ViewportBoundary\"]\nb:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"MetadataBoundary\"]\nd:I[92243,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0s8jbc4nxw6y6.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_not-found\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0s8jbc4nxw6y6.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/08fgie1bcjynm.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0ox7p_szjhn69.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L5\",null,{\"children\":[\"$\",\"$6\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@7\"}]}]]}],{},null,false,null]},null,false,\"$@8\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$L9\",null,{\"children\":\"$La\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lb\",null,{\"children\":[\"$\",\"$6\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lc\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0s8jbc4nxw6y6.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"4vrILyy2mh_Ox4JMTaqx8\"}\n"])</script><script>self.__next_f.push([1,"e:[]\n8:\"$We\"\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"f:I[80070,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"IconMark\"]\n7:null\nc:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0x3dzn~oxb6tn.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$Lf\",\"3\",{}]]\n"])</script></body></html>
@@ -2,5 +2,5 @@
2
2
  2:I[16348,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js","/_next/static/chunks/03v5eoc-wic6o.js"],"default"]
3
3
  3:I[11717,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"OutletBoundary"]
4
4
  4:"$Sreact.suspense"
5
- 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/03v5eoc-wic6o.js","async":true}]],["$","$L3",null,{"children":["$","$4",null,{"name":"Next.MetadataOutlet","children":"$@5"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"91YUiFoMbLQ9sZW4uk45J"}
5
+ 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/03v5eoc-wic6o.js","async":true}]],["$","$L3",null,{"children":["$","$4",null,{"name":"Next.MetadataOutlet","children":"$@5"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"4vrILyy2mh_Ox4JMTaqx8"}
6
6
  5:null