quadwork 1.15.0 → 1.16.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 (75) hide show
  1. package/README.md +1 -0
  2. package/bin/quadwork.js +22 -0
  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/0-w6bd-n2t2n~.css +2 -0
  10. package/out/_next/static/chunks/{0crp2e6jp_uau.js → 0a-o_h2xhfjpa.js} +19 -15
  11. package/out/_next/static/chunks/{136v4hoh5wgyv.js → 0b0p-uvdx~p32.js} +1 -1
  12. package/out/_next/static/chunks/0ocyu-i-3tr3t.js +1 -0
  13. package/out/_not-found/__next._full.txt +2 -2
  14. package/out/_not-found/__next._head.txt +1 -1
  15. package/out/_not-found/__next._index.txt +2 -2
  16. package/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
  17. package/out/_not-found/__next._not-found.txt +1 -1
  18. package/out/_not-found/__next._tree.txt +2 -2
  19. package/out/_not-found.html +1 -1
  20. package/out/_not-found.txt +2 -2
  21. package/out/app-shell/__next._full.txt +2 -2
  22. package/out/app-shell/__next._head.txt +1 -1
  23. package/out/app-shell/__next._index.txt +2 -2
  24. package/out/app-shell/__next._tree.txt +2 -2
  25. package/out/app-shell/__next.app-shell.__PAGE__.txt +1 -1
  26. package/out/app-shell/__next.app-shell.txt +1 -1
  27. package/out/app-shell.html +1 -1
  28. package/out/app-shell.txt +2 -2
  29. package/out/index.html +1 -1
  30. package/out/index.txt +2 -2
  31. package/out/project/_/__next._full.txt +3 -3
  32. package/out/project/_/__next._head.txt +1 -1
  33. package/out/project/_/__next._index.txt +2 -2
  34. package/out/project/_/__next._tree.txt +2 -2
  35. package/out/project/_/__next.project.$d$id.__PAGE__.txt +2 -2
  36. package/out/project/_/__next.project.$d$id.txt +1 -1
  37. package/out/project/_/__next.project.txt +1 -1
  38. package/out/project/_/queue/__next._full.txt +2 -2
  39. package/out/project/_/queue/__next._head.txt +1 -1
  40. package/out/project/_/queue/__next._index.txt +2 -2
  41. package/out/project/_/queue/__next._tree.txt +2 -2
  42. package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +1 -1
  43. package/out/project/_/queue/__next.project.$d$id.queue.txt +1 -1
  44. package/out/project/_/queue/__next.project.$d$id.txt +1 -1
  45. package/out/project/_/queue/__next.project.txt +1 -1
  46. package/out/project/_/queue.html +1 -1
  47. package/out/project/_/queue.txt +2 -2
  48. package/out/project/_.html +1 -1
  49. package/out/project/_.txt +3 -3
  50. package/out/settings/__next._full.txt +3 -3
  51. package/out/settings/__next._head.txt +1 -1
  52. package/out/settings/__next._index.txt +2 -2
  53. package/out/settings/__next._tree.txt +2 -2
  54. package/out/settings/__next.settings.__PAGE__.txt +2 -2
  55. package/out/settings/__next.settings.txt +1 -1
  56. package/out/settings.html +1 -1
  57. package/out/settings.txt +3 -3
  58. package/out/setup/__next._full.txt +2 -2
  59. package/out/setup/__next._head.txt +1 -1
  60. package/out/setup/__next._index.txt +2 -2
  61. package/out/setup/__next._tree.txt +2 -2
  62. package/out/setup/__next.setup.__PAGE__.txt +1 -1
  63. package/out/setup/__next.setup.txt +1 -1
  64. package/out/setup.html +1 -1
  65. package/out/setup.txt +2 -2
  66. package/package.json +1 -1
  67. package/server/index.js +251 -27
  68. package/server/install-agentchattr.js +28 -0
  69. package/server/install-agentchattr.patchCrashTimeout.test.js +71 -0
  70. package/templates/seeds/butler.AGENTS.md +425 -0
  71. package/out/_next/static/chunks/0khv6othabbrd.js +0 -1
  72. package/out/_next/static/chunks/0yjmb1lbyzaa1.css +0 -2
  73. /package/out/_next/static/{yi31oGNueSNboTtRFQmfN → TYz7xYDKn1qut8gR2RrXw}/_buildManifest.js +0 -0
  74. /package/out/_next/static/{yi31oGNueSNboTtRFQmfN → TYz7xYDKn1qut8gR2RrXw}/_clientMiddlewareManifest.js +0 -0
  75. /package/out/_next/static/{yi31oGNueSNboTtRFQmfN → TYz7xYDKn1qut8gR2RrXw}/_ssgManifest.js +0 -0
package/out/setup.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="preload" href="/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/0yjmb1lbyzaa1.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0ze4gu236oq96.js"/><script src="/_next/static/chunks/0.bbxho1vnxin.js" async=""></script><script src="/_next/static/chunks/0n~dq4kpx9xxx.js" async=""></script><script src="/_next/static/chunks/0zfotsowwll1x.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0qm-e3ifrz~2u.js" async=""></script><script src="/_next/static/chunks/0m48m-8no_mew.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/0uz5svjlo9dwl.js" async=""></script><meta name="next-size-adjust" content=""/><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.05o2q2p4kvnq_.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex flex-col"><div hidden=""><!--$--><!--/$--></div><header class="sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur" aria-hidden="true"></header><div class="flex flex-1 min-h-0"><button type="button" class="fixed top-14 left-2 z-30 lg:hidden w-10 h-10 flex items-center justify-center bg-bg-surface border border-border text-text-muted hover:text-accent"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M3 5h14M3 10h14M3 15h14"></path></svg></button><aside class="fixed inset-y-0 left-0 z-50 w-52 bg-bg-surface border-r border-border flex flex-col py-3 px-2 items-stretch overflow-y-auto transition-transform duration-200 ease-in-out lg:hidden -translate-x-full"><button type="button" class="self-end shrink-0 w-10 h-10 flex items-center justify-center text-text-muted hover:text-accent mb-1"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M5 5l10 10M15 5L5 15"></path></svg></button><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 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><span class="text-xs">Home</span></a><div class="h-px bg-border my-2 "></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 "><a class="flex items-center gap-2 rounded-full transition-colors px-2 py-2 border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] rounded-sm" 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><span class="text-xs text-text-muted">New Project</span></a></div><div class="h-px bg-border my-2 "></div><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 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><span class="text-xs">Settings</span></a></aside><aside class="hidden lg:flex shrink-0 h-full border-r border-border bg-bg-surface flex-col py-3 transition-[width] duration-200 ease-in-out overflow-hidden w-16 items-center"><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center 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="h-px bg-border my-2 w-6 self-center"></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 items-center"><a class="flex items-center gap-2 rounded-full transition-colors w-10 h-10 justify-center border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a]" 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="h-px bg-border my-2 w-6 self-center"></div><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center 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><div class="h-1"></div><button class="flex shrink-0 items-center justify-center w-10 h-10 rounded-sm border border-border text-text-muted hover:text-accent hover:border-accent/50 transition-colors self-center" title="Expand sidebar"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"></path></svg></button></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto"></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/0ze4gu236oq96.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[52368,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"LocaleProvider\"]\n3:I[43688,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[26704,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[22140,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[39756,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[37457,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n8:I[94810,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/0uz5svjlo9dwl.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\na:\"$Sreact.suspense\"\nd:I[97367,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n11:I[68027,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0yjmb1lbyzaa1.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"setup\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"setup\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0yjmb1lbyzaa1.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0m48m-8no_mew.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0d3shmwh5_nmn.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 flex-col\",\"children\":[\"$\",\"$L2\",null,{\"children\":[[\"$\",\"$L3\",null,{}],[\"$\",\"$L4\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",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,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L8\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0uz5svjlo9dwl.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@b\"}]}]]}],{},null,false,null]},null,false,\"$@c\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L10\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$11\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0yjmb1lbyzaa1.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"yi31oGNueSNboTtRFQmfN\"}\n"])</script><script>self.__next_f.push([1,"12:[]\nc:\"$W12\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\nb:null\n10:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.05o2q2p4kvnq_.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"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="preload" href="/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/0-w6bd-n2t2n~.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0ze4gu236oq96.js"/><script src="/_next/static/chunks/0.bbxho1vnxin.js" async=""></script><script src="/_next/static/chunks/0n~dq4kpx9xxx.js" async=""></script><script src="/_next/static/chunks/0zfotsowwll1x.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0qm-e3ifrz~2u.js" async=""></script><script src="/_next/static/chunks/0m48m-8no_mew.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/0uz5svjlo9dwl.js" async=""></script><meta name="next-size-adjust" content=""/><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.05o2q2p4kvnq_.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex flex-col"><div hidden=""><!--$--><!--/$--></div><header class="sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur" aria-hidden="true"></header><div class="flex flex-1 min-h-0"><button type="button" class="fixed top-14 left-2 z-30 lg:hidden w-10 h-10 flex items-center justify-center bg-bg-surface border border-border text-text-muted hover:text-accent"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M3 5h14M3 10h14M3 15h14"></path></svg></button><aside class="fixed inset-y-0 left-0 z-50 w-52 bg-bg-surface border-r border-border flex flex-col py-3 px-2 items-stretch overflow-y-auto transition-transform duration-200 ease-in-out lg:hidden -translate-x-full"><button type="button" class="self-end shrink-0 w-10 h-10 flex items-center justify-center text-text-muted hover:text-accent mb-1"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M5 5l10 10M15 5L5 15"></path></svg></button><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 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><span class="text-xs">Home</span></a><div class="h-px bg-border my-2 "></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 "><a class="flex items-center gap-2 rounded-full transition-colors px-2 py-2 border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] rounded-sm" 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><span class="text-xs text-text-muted">New Project</span></a></div><div class="h-px bg-border my-2 "></div><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 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><span class="text-xs">Settings</span></a></aside><aside class="hidden lg:flex shrink-0 h-full border-r border-border bg-bg-surface flex-col py-3 transition-[width] duration-200 ease-in-out overflow-hidden w-16 items-center"><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center 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="h-px bg-border my-2 w-6 self-center"></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 items-center"><a class="flex items-center gap-2 rounded-full transition-colors w-10 h-10 justify-center border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a]" 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="h-px bg-border my-2 w-6 self-center"></div><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center 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><div class="h-1"></div><button class="flex shrink-0 items-center justify-center w-10 h-10 rounded-sm border border-border text-text-muted hover:text-accent hover:border-accent/50 transition-colors self-center" title="Expand sidebar"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"></path></svg></button></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto"></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/0ze4gu236oq96.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[52368,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"LocaleProvider\"]\n3:I[43688,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[26704,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[22140,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[39756,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[37457,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n8:I[94810,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/0uz5svjlo9dwl.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\na:\"$Sreact.suspense\"\nd:I[97367,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n11:I[68027,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0-w6bd-n2t2n~.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"setup\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"setup\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0-w6bd-n2t2n~.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0m48m-8no_mew.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0d3shmwh5_nmn.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 flex-col\",\"children\":[\"$\",\"$L2\",null,{\"children\":[[\"$\",\"$L3\",null,{}],[\"$\",\"$L4\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",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,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L8\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0uz5svjlo9dwl.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@b\"}]}]]}],{},null,false,null]},null,false,\"$@c\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L10\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$11\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0-w6bd-n2t2n~.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"TYz7xYDKn1qut8gR2RrXw\"}\n"])</script><script>self.__next_f.push([1,"12:[]\nc:\"$W12\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/0m48m-8no_mew.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\nb:null\n10:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.05o2q2p4kvnq_.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"3\",{}]]\n"])</script></body></html>
package/out/setup.txt CHANGED
@@ -11,9 +11,9 @@ a:"$Sreact.suspense"
11
11
  d:I[97367,["/_next/static/chunks/0m48m-8no_mew.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"ViewportBoundary"]
12
12
  f:I[97367,["/_next/static/chunks/0m48m-8no_mew.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"MetadataBoundary"]
13
13
  11:I[68027,["/_next/static/chunks/0m48m-8no_mew.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default",1]
14
- :HL["/_next/static/chunks/0yjmb1lbyzaa1.css","style"]
14
+ :HL["/_next/static/chunks/0-w6bd-n2t2n~.css","style"]
15
15
  :HL["/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
16
- 0:{"P":null,"c":["","setup"],"q":"","i":false,"f":[[["",{"children":["setup",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0yjmb1lbyzaa1.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0m48m-8no_mew.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.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 flex-col","children":["$","$L2",null,{"children":[["$","$L3",null,{}],["$","$L4",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L5",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",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,["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","$L8",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0uz5svjlo9dwl.js","async":true,"nonce":"$undefined"}]],["$","$L9",null,{"children":["$","$a",null,{"name":"Next.MetadataOutlet","children":"$@b"}]}]]}],{},null,false,null]},null,false,"$@c"]},null,false,null],["$","$1","h",{"children":[null,["$","$Ld",null,{"children":"$Le"}],["$","div",null,{"hidden":true,"children":["$","$Lf",null,{"children":["$","$a",null,{"name":"Next.Metadata","children":"$L10"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$11",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0yjmb1lbyzaa1.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"yi31oGNueSNboTtRFQmfN"}
16
+ 0:{"P":null,"c":["","setup"],"q":"","i":false,"f":[[["",{"children":["setup",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0-w6bd-n2t2n~.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0m48m-8no_mew.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.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 flex-col","children":["$","$L2",null,{"children":[["$","$L3",null,{}],["$","$L4",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L5",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",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,["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","$L8",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0uz5svjlo9dwl.js","async":true,"nonce":"$undefined"}]],["$","$L9",null,{"children":["$","$a",null,{"name":"Next.MetadataOutlet","children":"$@b"}]}]]}],{},null,false,null]},null,false,"$@c"]},null,false,null],["$","$1","h",{"children":[null,["$","$Ld",null,{"children":"$Le"}],["$","div",null,{"hidden":true,"children":["$","$Lf",null,{"children":["$","$a",null,{"name":"Next.Metadata","children":"$L10"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$11",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0-w6bd-n2t2n~.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"TYz7xYDKn1qut8gR2RrXw"}
17
17
  12:[]
18
18
  c:"$W12"
19
19
  e:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quadwork",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "Unified dashboard for multi-agent coding teams — 4 AI agents, one terminal",
5
5
  "bin": {
6
6
  "quadwork": "./bin/quadwork.js"
package/server/index.js CHANGED
@@ -14,7 +14,7 @@ const {
14
14
  projectAgentchattrConfigPath,
15
15
  } = routes;
16
16
  const { waitForAgentChattrReady, registerAgent, registerAgentWithRetry, deregisterAgent, startHeartbeat, stopHeartbeat } = require("./agentchattr-registry");
17
- const { patchAgentchattrCss } = require("./install-agentchattr");
17
+ const { patchAgentchattrCss, patchCrashTimeout } = require("./install-agentchattr");
18
18
  const { startQueueWatcher, stopQueueWatcher } = require("./queue-watcher");
19
19
 
20
20
  const net = require("net");
@@ -154,6 +154,9 @@ const agentSessions = new Map();
154
154
  // AgentChattr server processes — per-project (key = projectId)
155
155
  const chattrProcesses = new Map();
156
156
 
157
+ // #631: Butler session — single global PTY (not per-project, no AC integration)
158
+ let butlerSession = { term: null, ws: null, state: "stopped", error: null, scrollback: Buffer.alloc(0) };
159
+
157
160
  // --- MCP auth proxy for Codex (can't pass headers via -c flag) ---
158
161
  // Maps "project/agent" → { server, port }
159
162
  const mcpProxies = new Map();
@@ -1169,6 +1172,8 @@ async function handleAgentChattr(req, res) {
1169
1172
  const pullResult = execFileSync("git", ["pull"], { cwd: acDir, encoding: "utf-8", timeout: 30000, stdio: "pipe" }).trim();
1170
1173
  // #388: re-apply sender-overflow CSS patch after git pull
1171
1174
  patchAgentchattrCss(acDir);
1175
+ // #629: re-apply crash timeout patch after git pull (pull may revert app.py)
1176
+ patchCrashTimeout(acDir);
1172
1177
  const venvPython = path.join(acDir, ".venv", "bin", "python");
1173
1178
  let pipResult = "";
1174
1179
  const reqFile = path.join(acDir, "requirements.txt");
@@ -1384,6 +1389,127 @@ app.post("/api/agents/:project/:agent/write", (req, res) => {
1384
1389
  }
1385
1390
  });
1386
1391
 
1392
+ // --- Butler agent (#631) ---
1393
+
1394
+ function spawnButlerPty() {
1395
+ if (butlerSession.term) return { ok: true, pid: butlerSession.term.pid };
1396
+
1397
+ try {
1398
+ const cfg = readConfig();
1399
+ const butlerCfg = cfg.butler || {};
1400
+ const cwdRaw = butlerCfg.cwd || "~/docs/";
1401
+ const docsDir = cwdRaw.startsWith("~/") ? path.join(os.homedir(), cwdRaw.slice(2)) : cwdRaw;
1402
+ if (!fs.existsSync(docsDir)) {
1403
+ fs.mkdirSync(docsDir, { recursive: true, mode: 0o700 });
1404
+ }
1405
+
1406
+ const command = butlerCfg.command || "claude";
1407
+ const args = [];
1408
+ if (butlerCfg.model) args.push("--model", butlerCfg.model);
1409
+ if (butlerCfg.auto_approve) args.push("--dangerously-skip-permissions");
1410
+
1411
+ const seedPath = path.join(__dirname, "..", "templates", "seeds", "butler.AGENTS.md");
1412
+ if (fs.existsSync(seedPath)) {
1413
+ const agentsPath = path.join(docsDir, "AGENTS.md");
1414
+ if (!fs.existsSync(agentsPath)) {
1415
+ fs.copyFileSync(seedPath, agentsPath);
1416
+ }
1417
+ }
1418
+
1419
+ // #635: seed README.md explaining ~/docs/ folder purpose
1420
+ const readmePath = path.join(docsDir, "README.md");
1421
+ if (!fs.existsSync(readmePath)) {
1422
+ fs.writeFileSync(readmePath, [
1423
+ "# ~/docs/",
1424
+ "",
1425
+ "Butler's working directory — cross-project operator notes and artifacts.",
1426
+ "Not git-tracked; operator-local.",
1427
+ "",
1428
+ "## File types",
1429
+ "",
1430
+ "| Prefix | Purpose |",
1431
+ "|--------|---------|",
1432
+ "| `PROPOSAL-<name>.md` | Feature proposals with phases and operator gates |",
1433
+ "| `REVIEW-<batch>.md` | PR review summaries |",
1434
+ "| `INFO-<topic>.md` | Research notes |",
1435
+ "| `PROGRESS-<project>.md` | Per-project progress (one file per project) |",
1436
+ "",
1437
+ ].join("\n"));
1438
+ }
1439
+
1440
+ const term = pty.spawn(command, args, {
1441
+ name: "xterm-256color",
1442
+ cols: 120,
1443
+ rows: 30,
1444
+ cwd: docsDir,
1445
+ env: { ...process.env },
1446
+ });
1447
+
1448
+ butlerSession = {
1449
+ term,
1450
+ ws: null,
1451
+ state: "running",
1452
+ error: null,
1453
+ scrollback: Buffer.alloc(0),
1454
+ };
1455
+
1456
+ const SCROLLBACK_SIZE = 64 * 1024;
1457
+ term.onData((data) => {
1458
+ const chunk = Buffer.from(data);
1459
+ butlerSession.scrollback = Buffer.concat([butlerSession.scrollback, chunk]);
1460
+ if (butlerSession.scrollback.length > SCROLLBACK_SIZE) {
1461
+ butlerSession.scrollback = butlerSession.scrollback.slice(-SCROLLBACK_SIZE);
1462
+ }
1463
+ });
1464
+
1465
+ term.onExit(({ exitCode }) => {
1466
+ if (butlerSession.term === term) {
1467
+ butlerSession.state = "stopped";
1468
+ butlerSession.error = exitCode ? `exit:${exitCode}` : null;
1469
+ butlerSession.term = null;
1470
+ if (butlerSession.ws && butlerSession.ws.readyState <= 1) {
1471
+ butlerSession.ws.close(1000, `exited:${exitCode}`);
1472
+ }
1473
+ butlerSession.ws = null;
1474
+ }
1475
+ });
1476
+
1477
+ console.log(`[butler] spawned (PID: ${term.pid}, cwd: ${docsDir})`);
1478
+ return { ok: true, pid: term.pid };
1479
+ } catch (err) {
1480
+ butlerSession = { term: null, ws: null, state: "error", error: err.message, scrollback: Buffer.alloc(0) };
1481
+ return { ok: false, error: err.message };
1482
+ }
1483
+ }
1484
+
1485
+ function stopButlerPty() {
1486
+ if (butlerSession.term) {
1487
+ try { butlerSession.term.kill(); } catch {}
1488
+ butlerSession.term = null;
1489
+ }
1490
+ if (butlerSession.ws && butlerSession.ws.readyState <= 1) {
1491
+ butlerSession.ws.close(1000, "stopped");
1492
+ }
1493
+ butlerSession = { term: null, ws: null, state: "stopped", error: null, scrollback: Buffer.alloc(0) };
1494
+ }
1495
+
1496
+ app.post("/api/butler/start", (_req, res) => {
1497
+ const result = spawnButlerPty();
1498
+ res.json(result);
1499
+ });
1500
+
1501
+ app.post("/api/butler/stop", (_req, res) => {
1502
+ stopButlerPty();
1503
+ res.json({ ok: true });
1504
+ });
1505
+
1506
+ app.get("/api/butler/status", (_req, res) => {
1507
+ res.json({
1508
+ running: butlerSession.state === "running" && !!butlerSession.term,
1509
+ pid: butlerSession.term ? butlerSession.term.pid : null,
1510
+ });
1511
+ });
1512
+
1387
1513
  // --- Scheduled Triggers ---
1388
1514
 
1389
1515
  const triggers = new Map();
@@ -1917,6 +2043,64 @@ wss.on("connection", async (ws, req) => {
1917
2043
  });
1918
2044
  });
1919
2045
 
2046
+ // --- Butler WebSocket (#631) ---
2047
+ const wssButler = new WebSocketServer({ server, path: "/ws/butler" });
2048
+
2049
+ wssButler.on("connection", async (ws) => {
2050
+ if (!butlerSession.term) {
2051
+ const result = spawnButlerPty();
2052
+ if (!result.ok) {
2053
+ ws.close(1011, "pty-spawn-failed");
2054
+ return;
2055
+ }
2056
+ }
2057
+
2058
+ if (butlerSession.ws && butlerSession.ws !== ws && butlerSession.ws.readyState <= 1) {
2059
+ butlerSession.ws.close(1000, "replaced");
2060
+ }
2061
+
2062
+ butlerSession.ws = ws;
2063
+
2064
+ const dataHandler = butlerSession.term.onData((data) => {
2065
+ if (ws.readyState === ws.OPEN) {
2066
+ ws.send(scrubSecrets(data));
2067
+ }
2068
+ });
2069
+
2070
+ ws.on("message", (msg) => {
2071
+ if (!butlerSession.term) return;
2072
+ const str = msg.toString();
2073
+ try {
2074
+ const parsed = JSON.parse(str);
2075
+ if (parsed.type === "resize") {
2076
+ if (typeof parsed.cols === "number" && typeof parsed.rows === "number" &&
2077
+ Number.isFinite(parsed.cols) && Number.isFinite(parsed.rows) &&
2078
+ parsed.cols >= 1 && parsed.cols <= 500 &&
2079
+ parsed.rows >= 1 && parsed.rows <= 500) {
2080
+ butlerSession.term.resize(parsed.cols, parsed.rows);
2081
+ }
2082
+ return;
2083
+ }
2084
+ if (parsed.type === "replay") {
2085
+ if (butlerSession.scrollback && butlerSession.scrollback.length > 0) {
2086
+ ws.send(scrubScrollback(butlerSession.scrollback));
2087
+ } else {
2088
+ ws.send(`\x1b[2m[butler online — waiting for input]\x1b[0m\r\n`);
2089
+ }
2090
+ return;
2091
+ }
2092
+ } catch {}
2093
+ butlerSession.term.write(str);
2094
+ });
2095
+
2096
+ ws.on("close", () => {
2097
+ dataHandler.dispose();
2098
+ if (butlerSession.ws === ws) {
2099
+ butlerSession.ws = null;
2100
+ }
2101
+ });
2102
+ });
2103
+
1920
2104
  // --- Trigger auto-start from config ---
1921
2105
 
1922
2106
  function syncTriggersFromConfig() {
@@ -2330,29 +2514,39 @@ server.listen(PORT, "127.0.0.1", async () => {
2330
2514
  // #457: migrate bridge slugs in AC configs on startup.
2331
2515
  // Renames [agents.discord-bridge] → [agents.dc] and
2332
2516
  // [agents.telegram-bridge] → [agents.tg] so bridges register
2333
- // under the short slug. Restarts AC for projects whose config changed.
2517
+ // under the short slug. Restarts AC ONLY for slug renames (not
2518
+ // fresh block appends) — #616: script-only patches should not
2519
+ // trigger AC restarts which kill bridge registration.
2334
2520
  for (const p of (startupCfg.projects || [])) {
2335
2521
  const acPath = projectAgentchattrConfigPath(p.id);
2336
2522
  if (!fs.existsSync(acPath)) continue;
2337
2523
  try {
2338
2524
  const before = fs.readFileSync(acPath, "utf-8");
2525
+ // Track whether an actual slug RENAME happened (old → new).
2526
+ // Fresh block appends don't need an AC restart — AC picks them
2527
+ // up on its next natural start.
2528
+ const hadOldDc = /^\[agents\.discord-bridge\]\s*$/m.test(before);
2529
+ const hadOldTg = /^\[agents\.telegram-bridge\]\s*$/m.test(before);
2339
2530
  const dc = patchAgentchattrConfigForDiscordBridge(before);
2340
2531
  const tg = patchAgentchattrConfigForTelegramBridge(dc.text);
2341
2532
  if (dc.changed || tg.changed) {
2342
2533
  fs.writeFileSync(acPath, tg.text);
2343
2534
  console.log(`[bridge-migrate] ${p.id}: migrated AC config slugs`);
2344
- // Restart AC so it loads the new agent slugs
2345
- setTimeout(async () => {
2346
- try {
2347
- const r = await fetch(`http://127.0.0.1:${PORT}/api/agentchattr/${encodeURIComponent(p.id)}/restart`, {
2348
- method: "POST",
2349
- });
2350
- if (r.ok) console.log(`[bridge-migrate] ${p.id}: restarted AC`);
2351
- else console.warn(`[bridge-migrate] ${p.id}: AC restart returned ${r.status}`);
2352
- } catch (err) {
2353
- console.warn(`[bridge-migrate] ${p.id}: AC restart failed: ${err.message || err}`);
2354
- }
2355
- }, 3000);
2535
+ // Only restart AC when a slug was actually RENAMED — not when
2536
+ // a fresh block was appended (#616).
2537
+ if (hadOldDc || hadOldTg) {
2538
+ setTimeout(async () => {
2539
+ try {
2540
+ const r = await fetch(`http://127.0.0.1:${PORT}/api/agentchattr/${encodeURIComponent(p.id)}/restart`, {
2541
+ method: "POST",
2542
+ });
2543
+ if (r.ok) console.log(`[bridge-migrate] ${p.id}: restarted AC`);
2544
+ else console.warn(`[bridge-migrate] ${p.id}: AC restart returned ${r.status}`);
2545
+ } catch (err) {
2546
+ console.warn(`[bridge-migrate] ${p.id}: AC restart failed: ${err.message || err}`);
2547
+ }
2548
+ }, 3000);
2549
+ }
2356
2550
  }
2357
2551
  } catch {}
2358
2552
  }
@@ -2496,22 +2690,19 @@ server.listen(PORT, "127.0.0.1", async () => {
2496
2690
  console.warn(`[ghost-fix] ${p.id}: failed to patch app.py: ${err.message}`);
2497
2691
  }
2498
2692
  }
2499
- // #502: increase crash timeout from 15s to 120s for idle agent tolerance
2693
+ // #502 + #629: increase crash timeout from 15s to 120s.
2694
+ // Uses the shared patchCrashTimeout() from install-agentchattr.js.
2695
+ // For existing installs where AC is already running, the on-disk
2696
+ // patch alone is useless (Python caches module-level values at import).
2697
+ // Flag the project for AC restart so the running process picks it up.
2500
2698
  if (fs.existsSync(appPath)) {
2501
2699
  try {
2502
- let app = fs.readFileSync(appPath, "utf-8");
2700
+ const app = fs.readFileSync(appPath, "utf-8");
2503
2701
  if (app.includes("_CRASH_TIMEOUT = 15")) {
2504
- app = app.replace(
2505
- "_CRASH_TIMEOUT = 15",
2506
- "_CRASH_TIMEOUT = 120",
2507
- );
2508
- // Fix the misleading comment too
2509
- app = app.replace(
2510
- "# Crash timeout: if a wrapper hasn't heartbeated for 60s,\n",
2511
- "# Crash timeout: if a wrapper hasn't heartbeated for 120s,\n",
2512
- );
2513
- fs.writeFileSync(appPath, app);
2514
- console.log(`[idle-fix] ${p.id}: increased crash timeout to 120s (#502)`);
2702
+ patchCrashTimeout(acDir);
2703
+ console.log(`[idle-fix] ${p.id}: crash timeout patched on disk — AC restart required for running process to observe it (#629)`);
2704
+ if (!startupCfg._acRestartNeeded) startupCfg._acRestartNeeded = [];
2705
+ startupCfg._acRestartNeeded.push(p.id);
2515
2706
  }
2516
2707
  } catch (err) {
2517
2708
  console.warn(`[idle-fix] ${p.id}: failed to patch app.py crash timeout: ${err.message}`);
@@ -2552,6 +2743,37 @@ server.listen(PORT, "127.0.0.1", async () => {
2552
2743
  console.warn(`[#596] ${p.id}: config.toml migration failed: ${err.message}`);
2553
2744
  }
2554
2745
  }
2746
+ // #629: restart AC for projects where idle-fix patched the on-disk file
2747
+ // so the running Python process picks up _CRASH_TIMEOUT = 120.
2748
+ // Use port-alive check instead of chattrProcesses — AC may be running
2749
+ // from a previous QuadWork instance (tracked with process: null).
2750
+ if (startupCfg._acRestartNeeded) {
2751
+ for (const projectId of startupCfg._acRestartNeeded) {
2752
+ const { url } = resolveProjectChattr(projectId);
2753
+ const portMatch = url.match(/:(\d+)/);
2754
+ const port = portMatch ? parseInt(portMatch[1], 10) : 8300;
2755
+ isPortAlive(port).then((alive) => {
2756
+ if (!alive) return;
2757
+ console.log(`[idle-fix] ${projectId}: restarting AC (port ${port}) so running process observes _CRASH_TIMEOUT = 120 (#629)`);
2758
+ return fetch(`http://127.0.0.1:${PORT}/api/agentchattr/${encodeURIComponent(projectId)}/restart`, {
2759
+ method: "POST",
2760
+ headers: { "Content-Type": "application/json" },
2761
+ body: JSON.stringify({ action: "restart" }),
2762
+ });
2763
+ }).then((r) => {
2764
+ if (r && r.ok) console.log(`[idle-fix] ${projectId}: AC restarted successfully`);
2765
+ else if (r) console.warn(`[idle-fix] ${projectId}: AC restart returned ${r.status}`);
2766
+ }).catch((err) => {
2767
+ console.warn(`[idle-fix] ${projectId}: AC restart failed: ${err.message}`);
2768
+ });
2769
+ }
2770
+ }
2771
+ // #631 + #632: auto-start Butler if enabled + auto_start
2772
+ if (startupCfg.butler && startupCfg.butler.enabled && startupCfg.butler.auto_start) {
2773
+ const result = spawnButlerPty();
2774
+ if (result.ok) console.log(`[butler] auto-started (PID: ${result.pid})`);
2775
+ else console.warn(`[butler] auto-start failed: ${result.error}`);
2776
+ }
2555
2777
  // #416: start the AC health monitor
2556
2778
  startAcHealthMonitor();
2557
2779
  });
@@ -2573,6 +2795,8 @@ function shutdownChattrProcesses() {
2573
2795
  }
2574
2796
  }
2575
2797
  chattrProcesses.clear();
2798
+ // #631: stop Butler PTY on shutdown
2799
+ stopButlerPty();
2576
2800
  }
2577
2801
 
2578
2802
  module.exports = { shutdownChattrProcesses };
@@ -195,6 +195,8 @@ function _installAgentChattrLocked(dir, setError) {
195
195
  }
196
196
  // #388: patch sender-column overflow CSS after clone/install
197
197
  patchAgentchattrCss(dir);
198
+ // #629: patch crash timeout before AC's first import
199
+ patchCrashTimeout(dir);
198
200
  return dir;
199
201
  }
200
202
 
@@ -260,10 +262,36 @@ function patchAgentchattrCss(dir) {
260
262
  }
261
263
  }
262
264
 
265
+ /**
266
+ * #629: Patch AC's crash timeout from 15s to 120s.
267
+ * Must run at clone time (before any `python run.py`) so the first
268
+ * AC process imports the patched value. Idempotent.
269
+ */
270
+ function patchCrashTimeout(dir) {
271
+ if (!dir) return;
272
+ const appPath = path.join(dir, "app.py");
273
+ if (!fs.existsSync(appPath)) return;
274
+ try {
275
+ let app = fs.readFileSync(appPath, "utf-8");
276
+ if (app.includes("_CRASH_TIMEOUT = 15")) {
277
+ app = app.replace("_CRASH_TIMEOUT = 15", "_CRASH_TIMEOUT = 120");
278
+ app = app.replace(
279
+ "# Crash timeout: if a wrapper hasn't heartbeated for 60s,\n",
280
+ "# Crash timeout: if a wrapper hasn't heartbeated for 120s,\n",
281
+ );
282
+ fs.writeFileSync(appPath, app);
283
+ console.log(`[idle-fix] patched crash timeout to 120s at clone time (#629): ${dir}`);
284
+ }
285
+ } catch (err) {
286
+ console.warn(`[idle-fix] failed to patch crash timeout in ${appPath}: ${err.message}`);
287
+ }
288
+ }
289
+
263
290
  module.exports = {
264
291
  AGENTCHATTR_REPO,
265
292
  findAgentChattr,
266
293
  installAgentChattr,
267
294
  chattrSpawnArgs,
268
295
  patchAgentchattrCss,
296
+ patchCrashTimeout,
269
297
  };
@@ -0,0 +1,71 @@
1
+ // #629: patchCrashTimeout tests. Plain node:assert — run with
2
+ // `node server/install-agentchattr.patchCrashTimeout.test.js`.
3
+
4
+ const assert = require("node:assert/strict");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ const os = require("os");
8
+ const { patchCrashTimeout } = require("./install-agentchattr");
9
+
10
+ const UNPATCHED_APP_PY = [
11
+ "import time",
12
+ "",
13
+ "# Crash timeout: if a wrapper hasn't heartbeated for 60s,",
14
+ "# consider it dead and deregister.",
15
+ "_CRASH_TIMEOUT = 15",
16
+ "",
17
+ "def check_heartbeats():",
18
+ " now = time.time()",
19
+ " for name, last_seen in list(_heartbeats.items()):",
20
+ " if last_seen > 0 and now - last_seen > _CRASH_TIMEOUT:",
21
+ ' log.info(f"Crash timeout: deregistering {name} (no heartbeat for {_CRASH_TIMEOUT}s)")',
22
+ ].join("\n");
23
+
24
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "qw-test-629-"));
25
+
26
+ function setup(content) {
27
+ const dir = fs.mkdtempSync(path.join(tmpDir, "ac-"));
28
+ if (content !== undefined) {
29
+ fs.writeFileSync(path.join(dir, "app.py"), content);
30
+ }
31
+ return dir;
32
+ }
33
+
34
+ // 1) Patches _CRASH_TIMEOUT from 15 to 120
35
+ {
36
+ const dir = setup(UNPATCHED_APP_PY);
37
+ patchCrashTimeout(dir);
38
+ const result = fs.readFileSync(path.join(dir, "app.py"), "utf-8");
39
+ assert.ok(result.includes("_CRASH_TIMEOUT = 120"), "timeout patched to 120");
40
+ assert.ok(!result.includes("_CRASH_TIMEOUT = 15"), "old value removed");
41
+ assert.ok(result.includes("heartbeated for 120s"), "comment updated");
42
+ assert.ok(!result.includes("heartbeated for 60s"), "old comment removed");
43
+ }
44
+
45
+ // 2) Idempotent — already-patched file is untouched
46
+ {
47
+ const dir = setup(UNPATCHED_APP_PY.replace("_CRASH_TIMEOUT = 15", "_CRASH_TIMEOUT = 120")
48
+ .replace("heartbeated for 60s", "heartbeated for 120s"));
49
+ const before = fs.readFileSync(path.join(dir, "app.py"), "utf-8");
50
+ patchCrashTimeout(dir);
51
+ const after = fs.readFileSync(path.join(dir, "app.py"), "utf-8");
52
+ assert.equal(before, after, "already-patched file unchanged");
53
+ }
54
+
55
+ // 3) No app.py — no crash
56
+ {
57
+ const dir = setup();
58
+ patchCrashTimeout(dir);
59
+ assert.ok(!fs.existsSync(path.join(dir, "app.py")), "no file created");
60
+ }
61
+
62
+ // 4) Null/undefined dir — no crash
63
+ {
64
+ patchCrashTimeout(null);
65
+ patchCrashTimeout(undefined);
66
+ }
67
+
68
+ // Cleanup
69
+ fs.rmSync(tmpDir, { recursive: true, force: true });
70
+
71
+ console.log("patchCrashTimeout: all tests passed");