quadwork 1.9.0 → 1.10.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.
- package/README.md +4 -0
- package/out/404.html +1 -1
- package/out/__next.__PAGE__.txt +2 -2
- package/out/__next._full.txt +3 -3
- package/out/__next._head.txt +1 -1
- package/out/__next._index.txt +2 -2
- package/out/__next._tree.txt +2 -2
- package/out/_next/static/chunks/{04jznxp9-kut_.js → 04ui63kyoqv4t.js} +1 -1
- package/out/_next/static/chunks/{0q71bcdksran1.js → 0aldkx8l9xukk.js} +1 -1
- package/out/_next/static/chunks/{0m439m2ljf2gz.js → 0uf3o~m9.vrpj.js} +14 -14
- package/out/_next/static/chunks/11r-w4ngz479i.css +2 -0
- package/out/_not-found/__next._full.txt +2 -2
- package/out/_not-found/__next._head.txt +1 -1
- package/out/_not-found/__next._index.txt +2 -2
- package/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/out/_not-found/__next._not-found.txt +1 -1
- package/out/_not-found/__next._tree.txt +2 -2
- package/out/_not-found.html +1 -1
- package/out/_not-found.txt +2 -2
- package/out/app-shell/__next._full.txt +2 -2
- package/out/app-shell/__next._head.txt +1 -1
- package/out/app-shell/__next._index.txt +2 -2
- package/out/app-shell/__next._tree.txt +2 -2
- package/out/app-shell/__next.app-shell.__PAGE__.txt +1 -1
- package/out/app-shell/__next.app-shell.txt +1 -1
- package/out/app-shell.html +1 -1
- package/out/app-shell.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +3 -3
- package/out/project/_/__next._full.txt +3 -3
- package/out/project/_/__next._head.txt +1 -1
- package/out/project/_/__next._index.txt +2 -2
- package/out/project/_/__next._tree.txt +2 -2
- package/out/project/_/__next.project.$d$id.__PAGE__.txt +2 -2
- package/out/project/_/__next.project.$d$id.txt +1 -1
- package/out/project/_/__next.project.txt +1 -1
- package/out/project/_/queue/__next._full.txt +2 -2
- package/out/project/_/queue/__next._head.txt +1 -1
- package/out/project/_/queue/__next._index.txt +2 -2
- package/out/project/_/queue/__next._tree.txt +2 -2
- package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +1 -1
- package/out/project/_/queue/__next.project.$d$id.queue.txt +1 -1
- package/out/project/_/queue/__next.project.$d$id.txt +1 -1
- package/out/project/_/queue/__next.project.txt +1 -1
- package/out/project/_/queue.html +1 -1
- package/out/project/_/queue.txt +2 -2
- package/out/project/_.html +1 -1
- package/out/project/_.txt +3 -3
- package/out/settings/__next._full.txt +2 -2
- package/out/settings/__next._head.txt +1 -1
- package/out/settings/__next._index.txt +2 -2
- package/out/settings/__next._tree.txt +2 -2
- package/out/settings/__next.settings.__PAGE__.txt +1 -1
- package/out/settings/__next.settings.txt +1 -1
- package/out/settings.html +1 -1
- package/out/settings.txt +2 -2
- package/out/setup/__next._full.txt +2 -2
- package/out/setup/__next._head.txt +1 -1
- package/out/setup/__next._index.txt +2 -2
- package/out/setup/__next._tree.txt +2 -2
- package/out/setup/__next.setup.__PAGE__.txt +1 -1
- package/out/setup/__next.setup.txt +1 -1
- package/out/setup.html +1 -1
- package/out/setup.txt +2 -2
- package/package.json +1 -1
- package/server/index.js +187 -0
- package/server/routes.js +60 -47
- package/out/_next/static/chunks/0d4fb920~o_t9.css +0 -2
- /package/out/_next/static/{8W6cFlsHLq6GQp5eCnKNU → mxlP6esPG86fhzv01dzCW}/_buildManifest.js +0 -0
- /package/out/_next/static/{8W6cFlsHLq6GQp5eCnKNU → mxlP6esPG86fhzv01dzCW}/_clientMiddlewareManifest.js +0 -0
- /package/out/_next/static/{8W6cFlsHLq6GQp5eCnKNU → mxlP6esPG86fhzv01dzCW}/_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/0d4fb920~o_t9.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/16g.ca89g7fib.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-0lcwh84lrj9gi.js" async=""></script><script src="/_next/static/chunks/0yt_bs94icoma.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/09h0i4gh79na..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"><aside class="shrink-0 h-full border-r border-border bg-bg-surface flex flex-col py-3 transition-[width] duration-200 ease-in-out overflow-hidden w-16 items-center"><button class="hidden md:flex shrink-0 items-center justify-center w-8 h-8 rounded-sm text-text-muted hover:text-text hover:bg-[#1a1a1a] 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><div class="h-1"></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="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></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto"><div class="px-6 pt-6 pb-4 border-b border-border"><h1 class="text-lg font-semibold text-text tracking-tight">Set Up Your AI Dev Team</h1><p class="text-[11px] text-text-muted mt-1">Configure agents, connect your repo, and launch a multi-agent development workflow in minutes.</p></div><div class="flex h-[calc(100%-80px)]"><div class="flex-1 flex gap-6 p-6 overflow-y-auto"><div class="w-44 shrink-0"><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-accent text-accent bg-accent/10">1</span><div><span class="text-[11px] block leading-tight text-text font-semibold">Project Name</span><span class="text-[10px] text-text-muted block">Name your project</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">2</span><div><span class="text-[11px] block leading-tight text-text-muted">GitHub Repo</span><span class="text-[10px] text-text-muted block">Connect a repository</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">3</span><div><span class="text-[11px] block leading-tight text-text-muted">Agent Models</span><span class="text-[10px] text-text-muted block">Configure CLI backends</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">4</span><div><span class="text-[11px] block leading-tight text-text-muted">Working Directory</span><span class="text-[10px] text-text-muted block">Set the local path</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">5</span><div><span class="text-[11px] block leading-tight text-text-muted">Create Workspaces</span><span class="text-[10px] text-text-muted block">Worktrees + seed files</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">6</span><div><span class="text-[11px] block leading-tight text-text-muted">Ready to Launch</span><span class="text-[10px] text-text-muted block">Review & start</span></div></div></div><div class="flex-1 border border-border p-5 min-h-0"><div><h2 class="text-sm font-semibold text-text mb-1">Name your project</h2><p class="text-[11px] text-text-muted mb-4">This name identifies your project in the dashboard and agent configs.</p><input placeholder="e.g. My DeFi App" class="w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-4" autofocus="" value=""/><button disabled="" class="px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50">Next</button></div></div></div><div class="w-64 shrink-0 border-l border-border p-4 overflow-y-auto bg-bg-surface/50"><h3 class="text-[11px] font-semibold text-text-muted uppercase tracking-wider mb-3">Configuration Preview</h3><div class="space-y-3 text-[11px]"><div><span class="text-text-muted block mb-0.5">Project</span><span class="text-text">—</span></div><div><span class="text-text-muted block mb-0.5">Repository</span><span class="text-text">—</span></div><div><span class="text-text-muted block mb-0.5">Backends</span><div class="flex justify-between"><span class="text-text capitalize">head</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">re1</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">re2</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">dev</span><span class="text-accent">claude</span></div></div><div><span class="text-text-muted block mb-0.5">Directory</span><span class="text-text font-mono text-[10px]">—</span></div><div><span class="text-text-muted block mb-0.5">Status</span><div class="space-y-0.5"><div class="flex items-center gap-1.5"><span class="text-[10px] text-text">●</span><span class="text-[10px] text-text">Project Name</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">GitHub Repo</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Agent Models</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Working Directory</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Create Workspaces</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Ready to Launch</span></div></div></div></div></div></div></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[43688,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n3:I[26704,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[22140,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[39756,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[37457,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[94810,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/09h0i4gh79na..js\"],\"default\"]\n8:I[97367,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\n9:\"$Sreact.suspense\"\nc:I[97367,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\ne:I[97367,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n10:I[68027,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0d4fb920~o_t9.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/0d4fb920~o_t9.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0yt_bs94icoma.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,{}],[\"$\",\"$L3\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L4\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",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,[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L7\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/09h0i4gh79na..js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L8\",null,{\"children\":[\"$\",\"$9\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@a\"}]}]]}],{},null,false,null]},null,false,\"$@b\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Lc\",null,{\"children\":\"$Ld\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Le\",null,{\"children\":[\"$\",\"$9\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lf\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$10\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0d4fb920~o_t9.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"8W6cFlsHLq6GQp5eCnKNU\"}\n"])</script><script>self.__next_f.push([1,"11:[]\nb:\"$W11\"\n"])</script><script>self.__next_f.push([1,"d:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"12:I[27201,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\na:null\nf:[[\"$\",\"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\"}],[\"$\",\"$L12\",\"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/11r-w4ngz479i.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/16g.ca89g7fib.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-0lcwh84lrj9gi.js" async=""></script><script src="/_next/static/chunks/0yt_bs94icoma.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/09h0i4gh79na..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"><aside class="shrink-0 h-full border-r border-border bg-bg-surface flex flex-col py-3 transition-[width] duration-200 ease-in-out overflow-hidden w-16 items-center"><button class="hidden md:flex shrink-0 items-center justify-center w-8 h-8 rounded-sm text-text-muted hover:text-text hover:bg-[#1a1a1a] 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><div class="h-1"></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="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></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto"><div class="px-6 pt-6 pb-4 border-b border-border"><h1 class="text-lg font-semibold text-text tracking-tight">Set Up Your AI Dev Team</h1><p class="text-[11px] text-text-muted mt-1">Configure agents, connect your repo, and launch a multi-agent development workflow in minutes.</p></div><div class="flex h-[calc(100%-80px)]"><div class="flex-1 flex gap-6 p-6 overflow-y-auto"><div class="w-44 shrink-0"><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-accent text-accent bg-accent/10">1</span><div><span class="text-[11px] block leading-tight text-text font-semibold">Project Name</span><span class="text-[10px] text-text-muted block">Name your project</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">2</span><div><span class="text-[11px] block leading-tight text-text-muted">GitHub Repo</span><span class="text-[10px] text-text-muted block">Connect a repository</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">3</span><div><span class="text-[11px] block leading-tight text-text-muted">Agent Models</span><span class="text-[10px] text-text-muted block">Configure CLI backends</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">4</span><div><span class="text-[11px] block leading-tight text-text-muted">Working Directory</span><span class="text-[10px] text-text-muted block">Set the local path</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">5</span><div><span class="text-[11px] block leading-tight text-text-muted">Create Workspaces</span><span class="text-[10px] text-text-muted block">Worktrees + seed files</span></div></div><div class="flex items-start gap-2 py-2 "><span class="w-5 h-5 flex items-center justify-center text-[10px] border shrink-0 mt-0.5 border-border text-text-muted">6</span><div><span class="text-[11px] block leading-tight text-text-muted">Ready to Launch</span><span class="text-[10px] text-text-muted block">Review & start</span></div></div></div><div class="flex-1 border border-border p-5 min-h-0"><div><h2 class="text-sm font-semibold text-text mb-1">Name your project</h2><p class="text-[11px] text-text-muted mb-4">This name identifies your project in the dashboard and agent configs.</p><input placeholder="e.g. My DeFi App" class="w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-4" autofocus="" value=""/><button disabled="" class="px-4 py-1.5 bg-accent text-bg text-[12px] font-semibold hover:bg-accent-dim transition-colors disabled:opacity-50">Next</button></div></div></div><div class="w-64 shrink-0 border-l border-border p-4 overflow-y-auto bg-bg-surface/50"><h3 class="text-[11px] font-semibold text-text-muted uppercase tracking-wider mb-3">Configuration Preview</h3><div class="space-y-3 text-[11px]"><div><span class="text-text-muted block mb-0.5">Project</span><span class="text-text">—</span></div><div><span class="text-text-muted block mb-0.5">Repository</span><span class="text-text">—</span></div><div><span class="text-text-muted block mb-0.5">Backends</span><div class="flex justify-between"><span class="text-text capitalize">head</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">re1</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">re2</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">dev</span><span class="text-accent">claude</span></div></div><div><span class="text-text-muted block mb-0.5">Directory</span><span class="text-text font-mono text-[10px]">—</span></div><div><span class="text-text-muted block mb-0.5">Status</span><div class="space-y-0.5"><div class="flex items-center gap-1.5"><span class="text-[10px] text-text">●</span><span class="text-[10px] text-text">Project Name</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">GitHub Repo</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Agent Models</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Working Directory</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Create Workspaces</span></div><div class="flex items-center gap-1.5"><span class="text-[10px] text-text-muted">○</span><span class="text-[10px] text-text-muted">Ready to Launch</span></div></div></div></div></div></div></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[43688,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n3:I[26704,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[22140,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[39756,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[37457,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[94810,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/09h0i4gh79na..js\"],\"default\"]\n8:I[97367,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\n9:\"$Sreact.suspense\"\nc:I[97367,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\ne:I[97367,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n10:I[68027,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/11r-w4ngz479i.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/11r-w4ngz479i.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0yt_bs94icoma.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,{}],[\"$\",\"$L3\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L4\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",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,[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L7\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/09h0i4gh79na..js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L8\",null,{\"children\":[\"$\",\"$9\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@a\"}]}]]}],{},null,false,null]},null,false,\"$@b\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Lc\",null,{\"children\":\"$Ld\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Le\",null,{\"children\":[\"$\",\"$9\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lf\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$10\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/11r-w4ngz479i.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"mxlP6esPG86fhzv01dzCW\"}\n"])</script><script>self.__next_f.push([1,"11:[]\nb:\"$W11\"\n"])</script><script>self.__next_f.push([1,"d:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"12:I[27201,[\"/_next/static/chunks/0yt_bs94icoma.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\na:null\nf:[[\"$\",\"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\"}],[\"$\",\"$L12\",\"3\",{}]]\n"])</script></body></html>
|
package/out/setup.txt
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
c:I[97367,["/_next/static/chunks/0yt_bs94icoma.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"ViewportBoundary"]
|
|
11
11
|
e:I[97367,["/_next/static/chunks/0yt_bs94icoma.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"MetadataBoundary"]
|
|
12
12
|
10:I[68027,["/_next/static/chunks/0yt_bs94icoma.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default",1]
|
|
13
|
-
:HL["/_next/static/chunks/
|
|
13
|
+
:HL["/_next/static/chunks/11r-w4ngz479i.css","style"]
|
|
14
14
|
:HL["/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
15
|
-
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/
|
|
15
|
+
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/11r-w4ngz479i.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0yt_bs94icoma.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,{}],["$","$L3",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L4",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",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,["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","$L7",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/09h0i4gh79na..js","async":true,"nonce":"$undefined"}]],["$","$L8",null,{"children":["$","$9",null,{"name":"Next.MetadataOutlet","children":"$@a"}]}]]}],{},null,false,null]},null,false,"$@b"]},null,false,null],["$","$1","h",{"children":[null,["$","$Lc",null,{"children":"$Ld"}],["$","div",null,{"hidden":true,"children":["$","$Le",null,{"children":["$","$9",null,{"name":"Next.Metadata","children":"$Lf"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$10",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/11r-w4ngz479i.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"mxlP6esPG86fhzv01dzCW"}
|
|
16
16
|
11:[]
|
|
17
17
|
b:"$W11"
|
|
18
18
|
d:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -1298,9 +1298,121 @@ Dev: Work on assigned ticket or address review feedback.
|
|
|
1298
1298
|
RE1/RE2: Review open PRs. If Dev pushed fixes, re-review. Post verdict on PR AND notify here.
|
|
1299
1299
|
ALL: Communicate via this chat by tagging agents. Your terminal is NOT visible.`;
|
|
1300
1300
|
|
|
1301
|
+
// #518: server-side bridge lifecycle helpers. Stop and start Telegram +
|
|
1302
|
+
// Discord bridges so they respond to batch transitions even when the
|
|
1303
|
+
// operator is on a different project page.
|
|
1304
|
+
|
|
1305
|
+
async function autoStopBridges(projectId, project, qwPort) {
|
|
1306
|
+
if (project?.telegram_auto) {
|
|
1307
|
+
try {
|
|
1308
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/telegram?action=stop`, {
|
|
1309
|
+
method: "POST",
|
|
1310
|
+
headers: { "Content-Type": "application/json" },
|
|
1311
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1312
|
+
signal: AbortSignal.timeout(5000),
|
|
1313
|
+
});
|
|
1314
|
+
console.log(`[auto-bridge] ${projectId}: telegram bridge auto-stopped`);
|
|
1315
|
+
} catch { /* non-fatal */ }
|
|
1316
|
+
}
|
|
1317
|
+
if (project?.discord_auto) {
|
|
1318
|
+
try {
|
|
1319
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/discord?action=stop`, {
|
|
1320
|
+
method: "POST",
|
|
1321
|
+
headers: { "Content-Type": "application/json" },
|
|
1322
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1323
|
+
signal: AbortSignal.timeout(5000),
|
|
1324
|
+
});
|
|
1325
|
+
console.log(`[auto-bridge] ${projectId}: discord bridge auto-stopped`);
|
|
1326
|
+
} catch { /* non-fatal */ }
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
async function autoStartBridges(projectId, project, qwPort) {
|
|
1331
|
+
if (project?.telegram_auto) {
|
|
1332
|
+
try {
|
|
1333
|
+
// Check if already running before starting
|
|
1334
|
+
const st = await fetch(
|
|
1335
|
+
`http://127.0.0.1:${qwPort}/api/telegram?project=${encodeURIComponent(projectId)}`,
|
|
1336
|
+
{ signal: AbortSignal.timeout(5000) }
|
|
1337
|
+
);
|
|
1338
|
+
if (st.ok) {
|
|
1339
|
+
const data = await st.json();
|
|
1340
|
+
if (data.running) return; // already running
|
|
1341
|
+
if (!data.configured) return; // not configured — can't start
|
|
1342
|
+
}
|
|
1343
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/telegram?action=start`, {
|
|
1344
|
+
method: "POST",
|
|
1345
|
+
headers: { "Content-Type": "application/json" },
|
|
1346
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1347
|
+
signal: AbortSignal.timeout(10000),
|
|
1348
|
+
});
|
|
1349
|
+
console.log(`[auto-bridge] ${projectId}: telegram bridge auto-started`);
|
|
1350
|
+
} catch { /* non-fatal */ }
|
|
1351
|
+
}
|
|
1352
|
+
if (project?.discord_auto) {
|
|
1353
|
+
try {
|
|
1354
|
+
const st = await fetch(
|
|
1355
|
+
`http://127.0.0.1:${qwPort}/api/discord?project=${encodeURIComponent(projectId)}`,
|
|
1356
|
+
{ signal: AbortSignal.timeout(5000) }
|
|
1357
|
+
);
|
|
1358
|
+
if (st.ok) {
|
|
1359
|
+
const data = await st.json();
|
|
1360
|
+
if (data.running) return;
|
|
1361
|
+
if (!data.configured) return;
|
|
1362
|
+
}
|
|
1363
|
+
await fetch(`http://127.0.0.1:${qwPort}/api/discord?action=start`, {
|
|
1364
|
+
method: "POST",
|
|
1365
|
+
headers: { "Content-Type": "application/json" },
|
|
1366
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1367
|
+
signal: AbortSignal.timeout(10000),
|
|
1368
|
+
});
|
|
1369
|
+
console.log(`[auto-bridge] ${projectId}: discord bridge auto-started`);
|
|
1370
|
+
} catch { /* non-fatal */ }
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// Track previous batch state per project for bridge auto-start detection
|
|
1375
|
+
const _bridgeBatchPrev = new Map();
|
|
1376
|
+
|
|
1301
1377
|
async function sendTriggerMessage(projectId) {
|
|
1302
1378
|
const cfg = readConfig();
|
|
1303
1379
|
const project = cfg.projects && cfg.projects.find((p) => p.id === projectId);
|
|
1380
|
+
|
|
1381
|
+
// #516: server-side auto-stop — check batch progress before sending.
|
|
1382
|
+
// When trigger_auto is enabled, skip the message and stop the trigger
|
|
1383
|
+
// (plus caffeinate) if the batch is already complete. This covers the
|
|
1384
|
+
// case where the operator is on a different page and the client-side
|
|
1385
|
+
// ScheduledTriggerWidget is not mounted to detect completion.
|
|
1386
|
+
if (project && project.trigger_auto) {
|
|
1387
|
+
const qwPort = cfg.port || 8400;
|
|
1388
|
+
try {
|
|
1389
|
+
const bpRes = await fetch(
|
|
1390
|
+
`http://127.0.0.1:${qwPort}/api/batch-progress?project=${encodeURIComponent(projectId)}`
|
|
1391
|
+
);
|
|
1392
|
+
if (bpRes.ok) {
|
|
1393
|
+
const bp = await bpRes.json();
|
|
1394
|
+
if (bp && bp.complete) {
|
|
1395
|
+
console.log(`[auto-trigger] ${projectId}: batch complete, auto-stopped`);
|
|
1396
|
+
stopTrigger(projectId);
|
|
1397
|
+
// Also stop caffeinate if no other triggers remain running
|
|
1398
|
+
// (#441 companion fix). caffeinateProcess is global (not
|
|
1399
|
+
// project-scoped), so only kill it when all work is done.
|
|
1400
|
+
if (caffeinateProcess.process && triggers.size === 0) {
|
|
1401
|
+
try { caffeinateProcess.process.kill("SIGTERM"); } catch {}
|
|
1402
|
+
caffeinateProcess = { process: null, pid: null, startedAt: null, duration: null };
|
|
1403
|
+
console.log(`[auto-trigger] ${projectId}: caffeinate auto-stopped (no active triggers remain)`);
|
|
1404
|
+
}
|
|
1405
|
+
// #518: also stop bridges when batch completes
|
|
1406
|
+
await autoStopBridges(projectId, project, qwPort);
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
} catch (err) {
|
|
1411
|
+
// Non-fatal — if batch-progress fails, proceed with the message
|
|
1412
|
+
console.error(`[auto-trigger] ${projectId}: batch-progress check failed:`, err.message);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1304
1416
|
const message = (project && project.trigger_message) || DEFAULT_MESSAGE;
|
|
1305
1417
|
|
|
1306
1418
|
// #401 / quadwork#277: route trigger sends through the local
|
|
@@ -1721,6 +1833,67 @@ function syncTriggersFromConfig() {
|
|
|
1721
1833
|
}
|
|
1722
1834
|
}
|
|
1723
1835
|
|
|
1836
|
+
// #516: server-side batch-completion poller. Checks every 30s whether
|
|
1837
|
+
// any trigger_auto project's batch is complete, and auto-stops the
|
|
1838
|
+
// trigger (plus caffeinate when no triggers remain). This runs
|
|
1839
|
+
// independently of the trigger tick interval, so completion is
|
|
1840
|
+
// detected within 30s even if the operator is on a different page.
|
|
1841
|
+
// #518: also handles telegram_auto / discord_auto bridge lifecycle
|
|
1842
|
+
// (both start and stop) so bridges respond to batch transitions
|
|
1843
|
+
// even when the operator is viewing a different project page.
|
|
1844
|
+
|
|
1845
|
+
const AUTO_STOP_POLL_INTERVAL_MS = 30_000;
|
|
1846
|
+
|
|
1847
|
+
async function autoStopPollingTick() {
|
|
1848
|
+
const cfg = readConfig();
|
|
1849
|
+
if (!cfg.projects) return;
|
|
1850
|
+
|
|
1851
|
+
for (const project of cfg.projects) {
|
|
1852
|
+
const hasTriggerAuto = project.trigger_auto && triggers.has(project.id);
|
|
1853
|
+
const hasBridgeAuto = project.telegram_auto || project.discord_auto;
|
|
1854
|
+
if (!hasTriggerAuto && !hasBridgeAuto) continue;
|
|
1855
|
+
const qwPort = cfg.port || 8400;
|
|
1856
|
+
try {
|
|
1857
|
+
const res = await fetch(
|
|
1858
|
+
`http://127.0.0.1:${qwPort}/api/batch-progress?project=${encodeURIComponent(project.id)}`
|
|
1859
|
+
);
|
|
1860
|
+
if (!res.ok) continue;
|
|
1861
|
+
const bp = await res.json();
|
|
1862
|
+
const hasItems = bp.items && bp.items.length > 0;
|
|
1863
|
+
const prev = _bridgeBatchPrev.get(project.id);
|
|
1864
|
+
_bridgeBatchPrev.set(project.id, { complete: bp.complete, hasItems });
|
|
1865
|
+
|
|
1866
|
+
if (bp && bp.complete) {
|
|
1867
|
+
if (hasTriggerAuto) {
|
|
1868
|
+
console.log(`[auto-trigger] ${project.id}: batch complete, auto-stopped (poller)`);
|
|
1869
|
+
stopTrigger(project.id);
|
|
1870
|
+
if (caffeinateProcess.process && triggers.size === 0) {
|
|
1871
|
+
try { caffeinateProcess.process.kill("SIGTERM"); } catch {}
|
|
1872
|
+
caffeinateProcess = { process: null, pid: null, startedAt: null, duration: null };
|
|
1873
|
+
console.log(`[auto-trigger] ${project.id}: caffeinate auto-stopped (no active triggers remain)`);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
// #518: also stop bridges when batch completes
|
|
1877
|
+
if (hasBridgeAuto) {
|
|
1878
|
+
await autoStopBridges(project.id, project, qwPort);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
// #518: detect batch-start transition → auto-start bridges
|
|
1883
|
+
if (hasBridgeAuto && hasItems && !bp.complete) {
|
|
1884
|
+
const isNewBatch = !prev || prev.complete || !prev.hasItems;
|
|
1885
|
+
if (isNewBatch) {
|
|
1886
|
+
await autoStartBridges(project.id, project, qwPort);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
} catch {
|
|
1890
|
+
// Non-fatal — retry on next tick
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
setInterval(autoStopPollingTick, AUTO_STOP_POLL_INTERVAL_MS);
|
|
1896
|
+
|
|
1724
1897
|
// #422 / quadwork#310: auto-continue after loop guard.
|
|
1725
1898
|
//
|
|
1726
1899
|
// Per opted-in project, poll AC's /api/status every 10s. When we see
|
|
@@ -1983,6 +2156,20 @@ server.listen(PORT, "127.0.0.1", () => {
|
|
|
1983
2156
|
}
|
|
1984
2157
|
} catch {}
|
|
1985
2158
|
}
|
|
2159
|
+
// #506: refresh Discord bridge script from the npm package on startup.
|
|
2160
|
+
// The Telegram bridge uses git-fetch + pin, but Discord uses a file-copy
|
|
2161
|
+
// pattern. Without this, upgrading QuadWork leaves a stale on-disk script
|
|
2162
|
+
// missing fixes shipped in newer versions.
|
|
2163
|
+
const DISCORD_BRIDGE_SRC = path.join(__dirname, "..", "bridges", "discord", "discord_bridge.py");
|
|
2164
|
+
const DISCORD_BRIDGE_DEST = path.join(os.homedir(), ".quadwork", "agentchattr-discord", "discord_bridge.py");
|
|
2165
|
+
if (fs.existsSync(DISCORD_BRIDGE_SRC) && fs.existsSync(path.dirname(DISCORD_BRIDGE_DEST))) {
|
|
2166
|
+
try {
|
|
2167
|
+
fs.copyFileSync(DISCORD_BRIDGE_SRC, DISCORD_BRIDGE_DEST);
|
|
2168
|
+
console.log("[bridge-refresh] refreshed Discord bridge script from package");
|
|
2169
|
+
} catch (err) {
|
|
2170
|
+
console.warn(`[bridge-refresh] failed to refresh Discord bridge script: ${err.message || err}`);
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
1986
2173
|
// #470: patch stale bridge_sender defaults in on-disk bridge scripts.
|
|
1987
2174
|
// The AC config migration (#457) renames the agent sections, but the
|
|
1988
2175
|
// bridge scripts themselves may still have old defaults if the operator
|
package/server/routes.js
CHANGED
|
@@ -1069,17 +1069,17 @@ router.get("/api/uploads/:project/:filename", (req, res) => {
|
|
|
1069
1069
|
|
|
1070
1070
|
// ─── Projects (dashboard aggregation) ──────────────────────────────────────
|
|
1071
1071
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
} catch {
|
|
1078
|
-
return [];
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1072
|
+
// #512: cache /api/projects results for 60s to eliminate repeated
|
|
1073
|
+
// slow gh CLI calls on every dashboard poll.
|
|
1074
|
+
let _projectsCache = null;
|
|
1075
|
+
let _projectsCacheTs = 0;
|
|
1076
|
+
const PROJECTS_CACHE_TTL = 60_000;
|
|
1081
1077
|
|
|
1082
1078
|
router.get("/api/projects", async (req, res) => {
|
|
1079
|
+
if (_projectsCache && Date.now() - _projectsCacheTs < PROJECTS_CACHE_TTL) {
|
|
1080
|
+
return res.json(_projectsCache);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
1083
|
const cfg = readConfigFile();
|
|
1084
1084
|
|
|
1085
1085
|
// Fetch active sessions from our own in-memory state (only running PTYs)
|
|
@@ -1113,24 +1113,34 @@ router.get("/api/projects", async (req, res) => {
|
|
|
1113
1113
|
.slice(-10)
|
|
1114
1114
|
.reverse();
|
|
1115
1115
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1116
|
+
// #512: build project-id-to-name map from config and a reverse
|
|
1117
|
+
// lookup from chat message to project name via chatMsgsByProject
|
|
1118
|
+
// (which already knows which AC instance each message came from).
|
|
1119
|
+
// This replaces the expensive allPrs/allIssues gh CLI calls that
|
|
1120
|
+
// were only used for the numberToProject mapping.
|
|
1121
|
+
const projectIdToName = {};
|
|
1122
|
+
for (const p of cfg.projects || []) projectIdToName[p.id] = p.name;
|
|
1123
|
+
const msgToProject = new Map();
|
|
1124
|
+
for (const [pid, msgs] of Object.entries(chatMsgsByProject)) {
|
|
1125
|
+
for (const m of msgs) msgToProject.set(m, projectIdToName[pid]);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// #512: parallelize gh CLI calls across projects using async exec.
|
|
1129
|
+
// Only fetch open PR count and most recent PR activity — drop the
|
|
1130
|
+
// allPrs/allIssues calls that were only used for numberToProject.
|
|
1131
|
+
async function fetchProjectGhData(p) {
|
|
1118
1132
|
let openPrs = 0;
|
|
1119
1133
|
let lastActivity = null;
|
|
1120
|
-
|
|
1121
1134
|
if (REPO_RE.test(p.repo)) {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
const allIssues = ghJson(["issue", "list", "-R", p.repo, "--state", "all", "--json", "number", "--limit", "100"]);
|
|
1131
|
-
for (const issue of allIssues) numberToProject[issue.number] = p.name;
|
|
1135
|
+
try {
|
|
1136
|
+
const [prs, recentPrs] = await Promise.allSettled([
|
|
1137
|
+
ghJsonExecAsync(["pr", "list", "-R", p.repo, "--json", "number", "--limit", "100"]),
|
|
1138
|
+
ghJsonExecAsync(["pr", "list", "-R", p.repo, "--state", "all", "--json", "updatedAt", "--limit", "1"]),
|
|
1139
|
+
]);
|
|
1140
|
+
if (prs.status === "fulfilled") openPrs = prs.value.length;
|
|
1141
|
+
if (recentPrs.status === "fulfilled") lastActivity = recentPrs.value[0]?.updatedAt || null;
|
|
1142
|
+
} catch {}
|
|
1132
1143
|
}
|
|
1133
|
-
|
|
1134
1144
|
const hasAgents = p.agents && Object.keys(p.agents).length > 0;
|
|
1135
1145
|
return {
|
|
1136
1146
|
id: p.id,
|
|
@@ -1141,20 +1151,21 @@ router.get("/api/projects", async (req, res) => {
|
|
|
1141
1151
|
state: hasAgents && activeProjectIds.has(p.id) ? "active" : "idle",
|
|
1142
1152
|
lastActivity,
|
|
1143
1153
|
};
|
|
1144
|
-
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
const projectResults = await Promise.all(
|
|
1157
|
+
(cfg.projects || []).map((p) => fetchProjectGhData(p))
|
|
1158
|
+
);
|
|
1145
1159
|
|
|
1146
|
-
// Build activity feed
|
|
1160
|
+
// Build activity feed — use chat-based project association instead
|
|
1161
|
+
// of the dropped numberToProject gh lookup.
|
|
1147
1162
|
const recentEvents = [];
|
|
1148
1163
|
for (const m of workflowMsgs) {
|
|
1164
|
+
// First: try text match against repo/project name
|
|
1149
1165
|
let projectName = (cfg.projects || []).find((p) => m.text.includes(p.repo) || m.text.includes(p.name))?.name;
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
}
|
|
1154
|
-
if (!projectName) {
|
|
1155
|
-
const branchMatch = m.text.match(/task\/(\d+)/);
|
|
1156
|
-
if (branchMatch) projectName = numberToProject[parseInt(branchMatch[1], 10)];
|
|
1157
|
-
}
|
|
1166
|
+
// Second: use the AC instance the message came from
|
|
1167
|
+
if (!projectName) projectName = msgToProject.get(m);
|
|
1168
|
+
// Fallback: single-project installs
|
|
1158
1169
|
if (!projectName && cfg.projects && cfg.projects.length === 1) {
|
|
1159
1170
|
projectName = cfg.projects[0].name;
|
|
1160
1171
|
}
|
|
@@ -1169,7 +1180,10 @@ router.get("/api/projects", async (req, res) => {
|
|
|
1169
1180
|
if (recentEvents.length >= 10) break;
|
|
1170
1181
|
}
|
|
1171
1182
|
|
|
1172
|
-
|
|
1183
|
+
const result = { projects: projectResults, recentEvents };
|
|
1184
|
+
_projectsCache = result;
|
|
1185
|
+
_projectsCacheTs = Date.now();
|
|
1186
|
+
res.json(result);
|
|
1173
1187
|
});
|
|
1174
1188
|
|
|
1175
1189
|
// ─── GitHub Issues / PRs ───────────────────────────────────────────────────
|
|
@@ -3066,20 +3080,19 @@ router.post("/api/discord", async (req, res) => {
|
|
|
3066
3080
|
const venvPip = path.join(venvDir, "bin", "pip");
|
|
3067
3081
|
let pipOutput = "";
|
|
3068
3082
|
try {
|
|
3069
|
-
//
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
// On upgrade: overwrite script, keep venv
|
|
3074
|
-
fs.cpSync(
|
|
3075
|
-
path.join(DISCORD_BRIDGE_SRC, "discord_bridge.py"),
|
|
3076
|
-
path.join(DISCORD_BRIDGE_DIR, "discord_bridge.py"),
|
|
3077
|
-
);
|
|
3078
|
-
fs.cpSync(
|
|
3079
|
-
path.join(DISCORD_BRIDGE_SRC, "requirements.txt"),
|
|
3080
|
-
path.join(DISCORD_BRIDGE_DIR, "requirements.txt"),
|
|
3081
|
-
);
|
|
3083
|
+
// #506: always copy bundled bridge files (not just on first install)
|
|
3084
|
+
// so re-installing after a QuadWork upgrade refreshes the script.
|
|
3085
|
+
if (!fs.existsSync(DISCORD_BRIDGE_DIR)) {
|
|
3086
|
+
fs.mkdirSync(DISCORD_BRIDGE_DIR, { recursive: true });
|
|
3082
3087
|
}
|
|
3088
|
+
fs.cpSync(
|
|
3089
|
+
path.join(DISCORD_BRIDGE_SRC, "discord_bridge.py"),
|
|
3090
|
+
path.join(DISCORD_BRIDGE_DIR, "discord_bridge.py"),
|
|
3091
|
+
);
|
|
3092
|
+
fs.cpSync(
|
|
3093
|
+
path.join(DISCORD_BRIDGE_SRC, "requirements.txt"),
|
|
3094
|
+
path.join(DISCORD_BRIDGE_DIR, "requirements.txt"),
|
|
3095
|
+
);
|
|
3083
3096
|
if (!fs.existsSync(venvPython)) {
|
|
3084
3097
|
execFileSync("python3", ["-m", "venv", venvDir], { encoding: "utf-8", timeout: 60000 });
|
|
3085
3098
|
}
|