quadwork 2.0.0 → 2.1.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 (73) hide show
  1. package/out/404.html +1 -1
  2. package/out/__next.__PAGE__.txt +2 -2
  3. package/out/__next._full.txt +3 -3
  4. package/out/__next._head.txt +1 -1
  5. package/out/__next._index.txt +2 -2
  6. package/out/__next._tree.txt +2 -2
  7. package/out/_next/static/chunks/{13xk0vgfbrcld.css → 0pfyuhd8ccue..css} +1 -1
  8. package/out/_next/static/chunks/{0_lyyn..t63bc.js → 0ud0uv.699had.js} +1 -1
  9. package/out/_next/static/chunks/{11khe5i7gu158.js → 0z.9wnba-t6z8.js} +1 -1
  10. package/out/_next/static/chunks/0zk4tzycn0w4g.js +25 -0
  11. package/out/_not-found/__next._full.txt +2 -2
  12. package/out/_not-found/__next._head.txt +1 -1
  13. package/out/_not-found/__next._index.txt +2 -2
  14. package/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
  15. package/out/_not-found/__next._not-found.txt +1 -1
  16. package/out/_not-found/__next._tree.txt +2 -2
  17. package/out/_not-found.html +1 -1
  18. package/out/_not-found.txt +2 -2
  19. package/out/app-shell/__next._full.txt +2 -2
  20. package/out/app-shell/__next._head.txt +1 -1
  21. package/out/app-shell/__next._index.txt +2 -2
  22. package/out/app-shell/__next._tree.txt +2 -2
  23. package/out/app-shell/__next.app-shell.__PAGE__.txt +1 -1
  24. package/out/app-shell/__next.app-shell.txt +1 -1
  25. package/out/app-shell.html +1 -1
  26. package/out/app-shell.txt +2 -2
  27. package/out/index.html +1 -1
  28. package/out/index.txt +3 -3
  29. package/out/project/_/__next._full.txt +3 -3
  30. package/out/project/_/__next._head.txt +1 -1
  31. package/out/project/_/__next._index.txt +2 -2
  32. package/out/project/_/__next._tree.txt +2 -2
  33. package/out/project/_/__next.project.$d$id.__PAGE__.txt +2 -2
  34. package/out/project/_/__next.project.$d$id.txt +1 -1
  35. package/out/project/_/__next.project.txt +1 -1
  36. package/out/project/_/queue/__next._full.txt +2 -2
  37. package/out/project/_/queue/__next._head.txt +1 -1
  38. package/out/project/_/queue/__next._index.txt +2 -2
  39. package/out/project/_/queue/__next._tree.txt +2 -2
  40. package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +1 -1
  41. package/out/project/_/queue/__next.project.$d$id.queue.txt +1 -1
  42. package/out/project/_/queue/__next.project.$d$id.txt +1 -1
  43. package/out/project/_/queue/__next.project.txt +1 -1
  44. package/out/project/_/queue.html +1 -1
  45. package/out/project/_/queue.txt +2 -2
  46. package/out/project/_.html +1 -1
  47. package/out/project/_.txt +3 -3
  48. package/out/settings/__next._full.txt +2 -2
  49. package/out/settings/__next._head.txt +1 -1
  50. package/out/settings/__next._index.txt +2 -2
  51. package/out/settings/__next._tree.txt +2 -2
  52. package/out/settings/__next.settings.__PAGE__.txt +1 -1
  53. package/out/settings/__next.settings.txt +1 -1
  54. package/out/settings.html +1 -1
  55. package/out/settings.txt +2 -2
  56. package/out/setup/__next._full.txt +2 -2
  57. package/out/setup/__next._head.txt +1 -1
  58. package/out/setup/__next._index.txt +2 -2
  59. package/out/setup/__next._tree.txt +2 -2
  60. package/out/setup/__next.setup.__PAGE__.txt +1 -1
  61. package/out/setup/__next.setup.txt +1 -1
  62. package/out/setup.html +1 -1
  63. package/out/setup.txt +2 -2
  64. package/package.json +1 -1
  65. package/server/bridges/discord.js +63 -2
  66. package/server/bridges/telegram.js +51 -3
  67. package/server/index.js +22 -1
  68. package/server/routes.js +73 -12
  69. package/templates/seeds/head.AGENTS.md +9 -5
  70. package/out/_next/static/chunks/14k3bfe537f9_.js +0 -25
  71. /package/out/_next/static/{479UD5Kit4YvCmtgO25VT → vvtpLPTwziTD3klXH46MU}/_buildManifest.js +0 -0
  72. /package/out/_next/static/{479UD5Kit4YvCmtgO25VT → vvtpLPTwziTD3klXH46MU}/_clientMiddlewareManifest.js +0 -0
  73. /package/out/_next/static/{479UD5Kit4YvCmtgO25VT → vvtpLPTwziTD3klXH46MU}/_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.09zddjkbdep5a.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/13xk0vgfbrcld.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/07lhk_q6pmm3r.js" async=""></script><script src="/_next/static/chunks/0oxv9vrvc17to.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0y2u-q0l2m67w.js" async=""></script><script src="/_next/static/chunks/0q4bm04c1jl_3.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/0py7102i226n5.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/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"LocaleProvider\"]\n3:I[43688,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[26704,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[22140,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[39756,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[37457,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n8:I[94810,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/0py7102i226n5.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\na:\"$Sreact.suspense\"\nd:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n11:I[68027,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/13xk0vgfbrcld.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.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/13xk0vgfbrcld.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0q4bm04c1jl_3.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/0py7102i226n5.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/13xk0vgfbrcld.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"479UD5Kit4YvCmtgO25VT\"}\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/0q4bm04c1jl_3.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.09zddjkbdep5a.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/0pfyuhd8ccue..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/07lhk_q6pmm3r.js" async=""></script><script src="/_next/static/chunks/0oxv9vrvc17to.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0y2u-q0l2m67w.js" async=""></script><script src="/_next/static/chunks/0q4bm04c1jl_3.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/0py7102i226n5.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/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"LocaleProvider\"]\n3:I[43688,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[26704,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[22140,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[39756,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[37457,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n8:I[94810,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/0py7102i226n5.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\na:\"$Sreact.suspense\"\nd:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n11:I[68027,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0pfyuhd8ccue..css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.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/0pfyuhd8ccue..css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0q4bm04c1jl_3.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/0py7102i226n5.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/0pfyuhd8ccue..css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"vvtpLPTwziTD3klXH46MU\"}\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/0q4bm04c1jl_3.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/0q4bm04c1jl_3.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"ViewportBoundary"]
12
12
  f:I[97367,["/_next/static/chunks/0q4bm04c1jl_3.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"MetadataBoundary"]
13
13
  11:I[68027,["/_next/static/chunks/0q4bm04c1jl_3.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default",1]
14
- :HL["/_next/static/chunks/13xk0vgfbrcld.css","style"]
14
+ :HL["/_next/static/chunks/0pfyuhd8ccue..css","style"]
15
15
  :HL["/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.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/13xk0vgfbrcld.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0q4bm04c1jl_3.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/0py7102i226n5.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/13xk0vgfbrcld.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"479UD5Kit4YvCmtgO25VT"}
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/0pfyuhd8ccue..css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0q4bm04c1jl_3.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/0py7102i226n5.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/0pfyuhd8ccue..css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"vvtpLPTwziTD3klXH46MU"}
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": "2.0.0",
3
+ "version": "2.1.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"
@@ -6,6 +6,16 @@ const CONFIG_DIR = path.join(os.homedir(), ".quadwork");
6
6
 
7
7
  const instances = new Map();
8
8
 
9
+ // #782: cursor-lag threshold beyond which a valid cursor is treated as
10
+ // stale (bridge stopped mid-backlog) and reseeded to latest on start.
11
+ // Small lags within this window keep continuity for graceful restarts.
12
+ //
13
+ // #786: intentional trade-off — if the bridge was down while 11+ messages
14
+ // arrived, those messages are skipped (not replayed to Discord). This
15
+ // prevents the "old message flood" bug. If continuity is needed for long
16
+ // downtimes, increase this threshold or remove the stale-cursor check.
17
+ const STALE_CURSOR_THRESHOLD = 10;
18
+
9
19
  function cursorPath(projectId) {
10
20
  return path.join(CONFIG_DIR, `dc-bridge-cursor-${projectId}.json`);
11
21
  }
@@ -134,7 +144,11 @@ async function start(projectId, botToken, channelId, qwPort) {
134
144
  if (message.channel.id !== channelId) return;
135
145
 
136
146
  const from = message.author.username || "unknown";
137
- await fetch(`http://127.0.0.1:${qwPort}/api/chat?project=${encodeURIComponent(projectId)}`, {
147
+ console.log(`[bridge] discord ${projectId}: received message from ${from}`);
148
+ if (!message.content) {
149
+ console.warn(`[bridge] discord ${projectId}: empty message content — check MESSAGE_CONTENT intent`);
150
+ }
151
+ const res = await fetch(`http://127.0.0.1:${qwPort}/api/chat?project=${encodeURIComponent(projectId)}`, {
138
152
  method: "POST",
139
153
  headers: {
140
154
  "Content-Type": "application/json",
@@ -147,11 +161,58 @@ async function start(projectId, botToken, channelId, qwPort) {
147
161
  }),
148
162
  signal: AbortSignal.timeout(5000),
149
163
  });
164
+ if (!res.ok) {
165
+ console.error(`[bridge] discord ${projectId} inbound POST failed: ${res.status}`);
166
+ }
150
167
  } catch (err) {
151
- if (!inst.stopping) inst.lastError = err.message;
168
+ if (!inst.stopping) {
169
+ console.error(`[bridge] discord ${projectId} inbound error: ${err.message}`);
170
+ inst.lastError = err.message;
171
+ }
152
172
  }
153
173
  });
154
174
 
175
+ client.on("error", (err) => {
176
+ console.error(`[bridge] discord ${projectId} client error: ${err?.message || err}`);
177
+ });
178
+ client.on("warn", (msg) => {
179
+ console.warn(`[bridge] discord ${projectId} client warn: ${msg}`);
180
+ });
181
+
182
+ // #782: seed cursor to latest on first enable (no cursor file, or
183
+ // cursor=0) AND on stale-cursor restarts where the cursor lags the
184
+ // latest chat message by more than STALE_CURSOR_THRESHOLD. The stale
185
+ // case covers bridges stopped mid-backlog (e.g. the plottoon scenario:
186
+ // cursor=83 with 127 messages — without this guard the next start
187
+ // replays 44 old messages to Discord). Small lags (graceful restart
188
+ // mid-conversation) keep continuity.
189
+ const cursorFileExists = fs.existsSync(cursorPath(projectId));
190
+ try {
191
+ const r = await fetch(
192
+ `http://127.0.0.1:${qwPort}/api/chat?project=${encodeURIComponent(projectId)}&limit=1`,
193
+ { signal: AbortSignal.timeout(5000) }
194
+ );
195
+ if (r.ok) {
196
+ const msgs = await r.json();
197
+ if (msgs.length > 0) {
198
+ const latestId = msgs[msgs.length - 1].id;
199
+ const stale = !cursorFileExists
200
+ || inst.cursor === 0
201
+ || (latestId - inst.cursor) > STALE_CURSOR_THRESHOLD;
202
+ if (stale) {
203
+ inst.cursor = latestId;
204
+ writeCursor(projectId, inst.cursor);
205
+ }
206
+ }
207
+ } else {
208
+ // #786: surface HTTP failures so non-OK responses don't fall
209
+ // through silently (the catch only fires on thrown errors).
210
+ console.warn(`[bridge] discord ${projectId}: cursor seed fetch returned ${r.status}`);
211
+ }
212
+ } catch (err) {
213
+ console.warn(`[bridge] discord ${projectId}: cursor seed failed (${err.message})`);
214
+ }
215
+
155
216
  pollLoop(projectId, channel, qwPort).catch((err) => {
156
217
  console.error(`[bridge] discord ${projectId} poll crashed: ${err.message}`);
157
218
  inst.lastError = err.message;
@@ -6,6 +6,16 @@ const CONFIG_DIR = path.join(os.homedir(), ".quadwork");
6
6
 
7
7
  const instances = new Map();
8
8
 
9
+ // #782: cursor-lag threshold beyond which a valid cursor is treated as
10
+ // stale (bridge stopped mid-backlog) and reseeded to latest on start.
11
+ // Small lags within this window keep continuity for graceful restarts.
12
+ //
13
+ // #786: intentional trade-off — if the bridge was down while 11+ messages
14
+ // arrived, those messages are skipped (not replayed to Telegram). This
15
+ // prevents the "old message flood" bug. If continuity is needed for long
16
+ // downtimes, increase this threshold or remove the stale-cursor check.
17
+ const STALE_CURSOR_THRESHOLD = 10;
18
+
9
19
  function cursorPath(projectId) {
10
20
  return path.join(CONFIG_DIR, `tg-bridge-cursor-${projectId}.json`);
11
21
  }
@@ -123,7 +133,7 @@ async function startTelegramUpdates(projectId, botToken, chatId, qwPort) {
123
133
  if (!text || msgChatId !== String(chatId)) continue;
124
134
 
125
135
  try {
126
- await fetch(`http://127.0.0.1:${qwPort}/api/chat?project=${encodeURIComponent(projectId)}`, {
136
+ const r = await fetch(`http://127.0.0.1:${qwPort}/api/chat?project=${encodeURIComponent(projectId)}`, {
127
137
  method: "POST",
128
138
  headers: {
129
139
  "Content-Type": "application/json",
@@ -136,7 +146,12 @@ async function startTelegramUpdates(projectId, botToken, chatId, qwPort) {
136
146
  }),
137
147
  signal: AbortSignal.timeout(5000),
138
148
  });
139
- } catch {}
149
+ if (!r.ok) {
150
+ console.error(`[bridge] telegram ${projectId} inbound POST failed: ${r.status}`);
151
+ }
152
+ } catch (err) {
153
+ console.error(`[bridge] telegram ${projectId} inbound error: ${err.message}`);
154
+ }
140
155
  }
141
156
  }
142
157
  } catch (err) {
@@ -154,7 +169,7 @@ async function startTelegramUpdates(projectId, botToken, chatId, qwPort) {
154
169
  tick();
155
170
  }
156
171
 
157
- function start(projectId, botToken, chatId, qwPort) {
172
+ async function start(projectId, botToken, chatId, qwPort) {
158
173
  if (instances.has(projectId)) return;
159
174
 
160
175
  const oldCursor = path.join(CONFIG_DIR, `telegram-bridge-cursor-${projectId}.json`);
@@ -174,6 +189,39 @@ function start(projectId, botToken, chatId, qwPort) {
174
189
  };
175
190
  instances.set(projectId, inst);
176
191
 
192
+ // #782: seed cursor to latest on first enable (no cursor file, or
193
+ // cursor=0) AND on stale-cursor restarts where the cursor lags the
194
+ // latest chat message by more than STALE_CURSOR_THRESHOLD. The stale
195
+ // case covers bridges stopped mid-backlog so the next start does not
196
+ // replay old conversations to Telegram. Small lags (graceful restart
197
+ // mid-conversation) keep continuity.
198
+ const cursorFileExists = fs.existsSync(cursorPath(projectId));
199
+ try {
200
+ const r = await fetch(
201
+ `http://127.0.0.1:${qwPort}/api/chat?project=${encodeURIComponent(projectId)}&limit=1`,
202
+ { signal: AbortSignal.timeout(5000) }
203
+ );
204
+ if (r.ok) {
205
+ const msgs = await r.json();
206
+ if (msgs.length > 0) {
207
+ const latestId = msgs[msgs.length - 1].id;
208
+ const stale = !cursorFileExists
209
+ || inst.cursor === 0
210
+ || (latestId - inst.cursor) > STALE_CURSOR_THRESHOLD;
211
+ if (stale) {
212
+ inst.cursor = latestId;
213
+ writeCursor(projectId, inst.cursor);
214
+ }
215
+ }
216
+ } else {
217
+ // #786: surface HTTP failures so non-OK responses don't fall
218
+ // through silently (the catch only fires on thrown errors).
219
+ console.warn(`[bridge] telegram ${projectId}: cursor seed fetch returned ${r.status}`);
220
+ }
221
+ } catch (err) {
222
+ console.warn(`[bridge] telegram ${projectId}: cursor seed failed (${err.message})`);
223
+ }
224
+
177
225
  pollLoop(projectId, botToken, chatId, qwPort).catch((err) => {
178
226
  console.error(`[bridge] telegram ${projectId} poll crashed: ${err.message}`);
179
227
  inst.lastError = err.message;
package/server/index.js CHANGED
@@ -1183,6 +1183,13 @@ app.get("/api/triggers", (_req, res) => {
1183
1183
  res.json(result);
1184
1184
  });
1185
1185
 
1186
+ // #812: a parked (idle) project gets no trigger starts/pulses. Read
1187
+ // the live config so a config-write that sets idle takes effect at once.
1188
+ function isProjectIdleId(projectId) {
1189
+ try { return !!readConfig().projects?.find((p) => p.id === projectId)?.idle; }
1190
+ catch { return false; }
1191
+ }
1192
+
1186
1193
  function stopTrigger(project) {
1187
1194
  const existing = triggers.get(project);
1188
1195
  if (existing) {
@@ -1194,6 +1201,11 @@ function stopTrigger(project) {
1194
1201
 
1195
1202
  app.post("/api/triggers/:project/start", (req, res) => {
1196
1203
  const { project } = req.params;
1204
+ // #812: refuse to start a trigger for a parked (idle) project — no
1205
+ // timer created, no agents pulsed. Toggle the project off idle first.
1206
+ if (isProjectIdleId(project)) {
1207
+ return res.json({ ok: false, idle: true, enabled: false });
1208
+ }
1197
1209
  // #418 / quadwork#306: sendImmediately was an always-true
1198
1210
  // send-and-start flag from the original #210 button; operators
1199
1211
  // asked for a pure scheduler (the button is now just "Start
@@ -1265,6 +1277,10 @@ app.post("/api/triggers/:project/stop", (req, res) => {
1265
1277
 
1266
1278
  app.post("/api/triggers/:project/send-now", (req, res) => {
1267
1279
  const { project } = req.params;
1280
+ // #812: parked (idle) project — do not pulse agents.
1281
+ if (isProjectIdleId(project)) {
1282
+ return res.json({ ok: false, idle: true, sent: false });
1283
+ }
1268
1284
  sendTriggerMessage(project);
1269
1285
  res.json({ ok: true, sent: true });
1270
1286
  });
@@ -1593,7 +1609,11 @@ function syncTriggersFromConfig() {
1593
1609
 
1594
1610
  if (cfg.projects) {
1595
1611
  for (const project of cfg.projects) {
1596
- if (project.trigger_enabled) {
1612
+ // #812: idle (parked) projects get no trigger. Excluding them from
1613
+ // activeIds also makes the cleanup loop below clear any timer they
1614
+ // had — so writing idle:true via PUT /api/config (which calls this)
1615
+ // stops a running trigger with no separate stop call.
1616
+ if (project.trigger_enabled && !project.idle) {
1597
1617
  activeIds.add(project.id);
1598
1618
  const ms = (project.trigger_interval || 30) * 60 * 1000;
1599
1619
  const existing = triggers.get(project.id);
@@ -1631,6 +1651,7 @@ async function autoStopPollingTick() {
1631
1651
  if (!cfg.projects) return;
1632
1652
 
1633
1653
  for (const project of cfg.projects) {
1654
+ if (project.idle) continue; // #812: parked project — no batch-progress polling
1634
1655
  const hasTriggerAuto = project.trigger_auto && triggers.has(project.id);
1635
1656
  const hasBridgeAuto = project.telegram_auto || project.discord_auto;
1636
1657
  if (!hasTriggerAuto && !hasBridgeAuto) continue;
package/server/routes.js CHANGED
@@ -120,9 +120,17 @@ function _ghEnqueueRefresh(cacheKey, ghArgs, transform) {
120
120
  _ghDrainQueue();
121
121
  }
122
122
 
123
- function cachedGhEndpoint(cacheKey, ghArgs, res, { transform } = {}) {
124
- const ttl = adaptiveTTL(GH_ENDPOINT_CACHE_TTL);
123
+ function cachedGhEndpoint(cacheKey, ghArgs, res, { transform, idle } = {}) {
125
124
  const cached = _ghEndpointCache.get(cacheKey);
125
+ // #812: a parked (idle) project must never initiate a gh fetch. Serve
126
+ // whatever we last cached, or an empty list — never call gh. The list
127
+ // endpoints return a bare array (client contract), so signal idle via a
128
+ // response header rather than mutating the JSON shape.
129
+ if (idle) {
130
+ res.set("X-QuadWork-Idle", "1");
131
+ return res.json(cached ? cached.data : []);
132
+ }
133
+ const ttl = adaptiveTTL(GH_ENDPOINT_CACHE_TTL);
126
134
  if (cached && Date.now() - cached.ts < ttl) {
127
135
  return res.json(cached.stale ? { ...cached.data, _stale: true } : cached.data);
128
136
  }
@@ -268,11 +276,10 @@ router.get("/api/chat", (req, res) => {
268
276
  since_id: sinceId,
269
277
  limit: Number(req.query.limit) || 50,
270
278
  });
271
- const normalized = messages.map((m) => ({
272
- ...m,
273
- time: m.time || (m.ts ? new Date(m.ts).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false }) : ""),
274
- }));
275
- return res.json(normalized);
279
+ // #783: return raw ISO `ts` only. The previous server-side `time`
280
+ // field used the server's local time, which on UTC VPS hosts gave
281
+ // wrong-timezone display. The frontend formats `ts` in the browser.
282
+ return res.json(messages);
276
283
  });
277
284
 
278
285
  // #693: Auto-normalize bare agent names to @mentions in outbound messages.
@@ -851,6 +858,20 @@ router.get("/api/projects", async (req, res) => {
851
858
  async function fetchProjectGhData(p) {
852
859
  let openPrs = 0;
853
860
  let lastActivity = null;
861
+ // #812: parked (idle) project — no gh calls; return zero/last-known metadata.
862
+ if (p.idle) {
863
+ const hasAgentsIdle = p.agents && Object.keys(p.agents).length > 0;
864
+ return {
865
+ id: p.id,
866
+ name: p.name,
867
+ repo: p.repo,
868
+ agentCount: hasAgentsIdle ? Object.keys(p.agents).length : 0,
869
+ openPrs: 0,
870
+ state: "idle",
871
+ lastActivity: null,
872
+ _idle: true,
873
+ };
874
+ }
854
875
  if (REPO_RE.test(p.repo)) {
855
876
  try {
856
877
  const [prs, recentPrs] = await Promise.allSettled([
@@ -891,7 +912,7 @@ router.get("/api/projects", async (req, res) => {
891
912
  }
892
913
  if (projectName) {
893
914
  recentEvents.push({
894
- time: m.time,
915
+ ts: m.ts,
895
916
  text: m.text.length > 120 ? m.text.slice(0, 120) + "…" : m.text,
896
917
  actor: m.sender,
897
918
  projectName,
@@ -938,6 +959,20 @@ function getRepo(projectId) {
938
959
  }
939
960
  }
940
961
 
962
+ // #812: per-project Idle toggle. When a project is idle, QuadWork must
963
+ // initiate ZERO project-specific GitHub/API activity for it. Callers
964
+ // (board fetch, per-endpoint handlers, batch-progress, /api/projects)
965
+ // check this before issuing any gh call.
966
+ function isProjectIdle(projectId) {
967
+ if (!projectId) return false;
968
+ try {
969
+ const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
970
+ return !!cfg.projects?.find((p) => p.id === projectId)?.idle;
971
+ } catch {
972
+ return false;
973
+ }
974
+ }
975
+
941
976
  // ─── #703: Batched GraphQL layer ──────────────────────────────────────────
942
977
  // Instead of spawning individual `gh issue list` / `gh pr list` subprocesses
943
978
  // per project per endpoint, we fetch ALL configured projects' GitHub data in
@@ -960,7 +995,7 @@ async function fetchAllProjectsGraphQL() {
960
995
  } catch {
961
996
  return null;
962
997
  }
963
- const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo));
998
+ const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo) && !p.idle); // #812: skip idle (parked) projects
964
999
  if (projects.length === 0) return null;
965
1000
 
966
1001
  // Build aliased repository fields — one per project.
@@ -1239,7 +1274,7 @@ router.get("/api/github/all", async (req, res) => {
1239
1274
  const anyStale = (() => {
1240
1275
  let cfg;
1241
1276
  try { cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); } catch { return true; }
1242
- const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo));
1277
+ const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo) && !p.idle); // #812: skip idle (parked) projects
1243
1278
  for (const p of projects) {
1244
1279
  const cached = _graphqlCache.get(p.repo);
1245
1280
  if (!cached || Date.now() - cached.ts > adaptiveTTL(GRAPHQL_CACHE_TTL)) return true;
@@ -1251,13 +1286,21 @@ router.get("/api/github/all", async (req, res) => {
1251
1286
  // Build response.
1252
1287
  let cfg;
1253
1288
  try { cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); } catch { return res.status(500).json({ error: "Config unreadable" }); }
1254
- const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo));
1289
+ const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo)); // #812: include idle projects — served stale below, never fetched
1255
1290
 
1256
1291
  const result = {};
1257
1292
  const fallbackNeeded = [];
1258
1293
  for (const p of projects) {
1259
1294
  if (projectFilter && p.id !== projectFilter) continue;
1260
1295
  const cached = _graphqlCache.get(p.repo);
1296
+ // #812: idle (parked) project — serve last-known data flagged _idle,
1297
+ // never trigger a fetch or fall back to gh.
1298
+ if (p.idle) {
1299
+ result[p.id] = cached
1300
+ ? { issues: cached.issues, prs: cached.prs, closedIssues: cached.closedIssues, mergedPrs: cached.mergedPrs, _idle: true }
1301
+ : { issues: [], prs: [], closedIssues: [], mergedPrs: [], _idle: true };
1302
+ continue;
1303
+ }
1261
1304
  if (cached) {
1262
1305
  result[p.id] = {
1263
1306
  issues: cached.issues,
@@ -1321,6 +1364,7 @@ router.get("/api/github/issues", (req, res) => {
1321
1364
  `issues:${repo}`,
1322
1365
  ["issue", "list", "-R", repo, "--json", "number,title,state,assignees,labels,createdAt,url", "--limit", "50"],
1323
1366
  res,
1367
+ { idle: isProjectIdle(req.query.project || "") },
1324
1368
  );
1325
1369
  });
1326
1370
 
@@ -1331,6 +1375,7 @@ router.get("/api/github/prs", (req, res) => {
1331
1375
  `prs:${repo}`,
1332
1376
  ["pr", "list", "-R", repo, "--json", "number,title,state,author,assignees,reviewDecision,reviews,statusCheckRollup,url,createdAt", "--limit", "50"],
1333
1377
  res,
1378
+ { idle: isProjectIdle(req.query.project || "") },
1334
1379
  );
1335
1380
  });
1336
1381
 
@@ -1352,6 +1397,7 @@ router.get("/api/github/closed-issues", (req, res) => {
1352
1397
  ["issue", "list", "-R", repo, "--state", "closed", "--json", "number,title,state,url,closedAt", "--limit", String(RECENT_FETCH_LIMIT)],
1353
1398
  res,
1354
1399
  {
1400
+ idle: isProjectIdle(req.query.project || ""),
1355
1401
  transform: (items) =>
1356
1402
  Array.isArray(items)
1357
1403
  ? items
@@ -1379,6 +1425,7 @@ router.get("/api/github/merged-prs", (req, res) => {
1379
1425
  ["pr", "list", "-R", repo, "--state", "merged", "--json", "number,title,state,url,mergedAt,author", "--limit", String(RECENT_FETCH_LIMIT)],
1380
1426
  res,
1381
1427
  {
1428
+ idle: isProjectIdle(req.query.project || ""),
1382
1429
  transform: (items) =>
1383
1430
  Array.isArray(items)
1384
1431
  ? items
@@ -1804,6 +1851,14 @@ router.get("/api/batch-progress", async (req, res) => {
1804
1851
  if (!projectId) return res.status(400).json({ error: "Missing project" });
1805
1852
 
1806
1853
  const cached = _batchProgressCache.get(projectId);
1854
+ // #812: parked (idle) project — never run batch-progress gh/GraphQL calls,
1855
+ // and ALWAYS flag the payload _idle (even on a fresh cache hit), so the
1856
+ // endpoint contract is consistent regardless of cache freshness. This must
1857
+ // precede the fresh-cache and rate-limit returns below.
1858
+ if (isProjectIdle(projectId)) {
1859
+ if (cached) return res.json({ ...cached.data, _idle: true });
1860
+ return res.json({ batch_number: null, items: [], summary: "", complete: false, _idle: true });
1861
+ }
1807
1862
  const batchTTL = adaptiveTTL(BATCH_PROGRESS_TTL_MS);
1808
1863
  if (cached && Date.now() - cached.ts < batchTTL) {
1809
1864
  return res.json(cached.data);
@@ -2202,6 +2257,12 @@ router.post("/api/setup", (req, res) => {
2202
2257
  ensureSecureDir(dir);
2203
2258
  writeConfig(cfg);
2204
2259
 
2260
+ // #775: initialize file-chat for the new project so the first
2261
+ // chat send doesn't error with "Project not initialized" before
2262
+ // the next server restart. Boot init only runs for projects
2263
+ // already in config.json at startup.
2264
+ fileChat.initProject(id);
2265
+
2205
2266
  // Batch 25 / #204: seed the per-project OVERNIGHT-QUEUE.md at
2206
2267
  // ~/.quadwork/{id}/OVERNIGHT-QUEUE.md.
2207
2268
  writeOvernightQueueFileSafe(id, name || id, repo);
@@ -2436,7 +2497,7 @@ router.post("/api/telegram", async (req, res) => {
2436
2497
  try {
2437
2498
  const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
2438
2499
  const qwPort = cfg.port || 8400;
2439
- telegramBridge.start(projectId, tg.bot_token, tg.chat_id, qwPort);
2500
+ await telegramBridge.start(projectId, tg.bot_token, tg.chat_id, qwPort);
2440
2501
  emitSystemMessage(projectId, "Telegram bridge connected");
2441
2502
  return res.json({ ok: true, running: true });
2442
2503
  } catch (err) {
@@ -96,13 +96,17 @@ When the operator asks you in chat to start a task or batch:
96
96
 
97
97
  When you move a batch to Done, **preserve its `Batch: N` line** so the next batch's number computation stays correct.
98
98
  3. Reply in chat to confirm what you wrote to the queue file (issue numbers + which section).
99
- 4. **Tell the operator the queue is ready and how to kick it off.** Send a chat message like:
99
+ 4. **Tell the operator the queue is ready.** Send a chat message like:
100
100
 
101
- > Queue is ready. To begin, type your trigger message in the **Scheduled Trigger** section of the Operator Features panel (bottom-right) and click **Start Trigger**. I will start assigning Dev as soon as the trigger fires.
101
+ > Batch N is ready with tickets #X, #Y, #Z. Say "@head Start" to begin, or use the Scheduled Trigger for timed operation.
102
102
 
103
- Without this prompt the operator has no idea what to do next and the batch sits idle indefinitely. Always send it after step 3, even if the operator only asked for a single ticket.
104
- 5. **Wait for the operator to trigger the batch via the Scheduled Trigger widget** before assigning the first item to `@dev`. Do NOT start assignments the moment the queue file is written — the operator controls kickoff. The trigger fires the queue-check pulse to all agents and is your signal that the operator wants the batch to start.
105
- 6. Once triggered, assign the first item to `@dev` following the normal workflow below.
103
+ Always send this after step 3, even if the operator only asked for a single ticket.
104
+ 5. **Start assigning when EITHER:**
105
+ - The operator says "Start", "Go", "Begin", or similar in chat addressed to `@head`
106
+ - The Scheduled Trigger fires
107
+
108
+ Do NOT require the Scheduled Trigger — the operator's direct chat command is sufficient. Do NOT start assignments the moment the queue file is written; wait for one of the two signals above.
109
+ 6. Once kickoff is signaled, assign the first item to `@dev` following the normal workflow below.
106
110
 
107
111
  ### After each merge
108
112
  1. Move the merged item from **Active Batch** to **Done** in `OVERNIGHT-QUEUE.md`.