quadwork 0.1.2 → 0.1.3
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 -4
- package/bin/quadwork.js +153 -52
- package/out/404.html +1 -1
- package/out/__next.__PAGE__.txt +1 -1
- package/out/__next._full.txt +2 -2
- 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/02ul7y114vj2f.js +13 -0
- package/out/_next/static/chunks/{0jsosmtclw5n5.js → 038g944ax83al.js} +1 -1
- package/out/_next/static/chunks/0gy_9ugdx7ueh.js +1 -0
- package/out/_next/static/chunks/0idtc5k0469of.js +1 -0
- package/out/_next/static/chunks/{03hi.hdp6l230.js → 0wda-2lcle8c4.js} +8 -8
- package/out/_next/static/chunks/0yxmvmvm1dx_d.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/index.html +1 -1
- package/out/index.txt +2 -2
- 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/_/memory/__next._full.txt +3 -3
- package/out/project/_/memory/__next._head.txt +1 -1
- package/out/project/_/memory/__next._index.txt +2 -2
- package/out/project/_/memory/__next._tree.txt +2 -2
- package/out/project/_/memory/__next.project.$d$id.memory.__PAGE__.txt +2 -2
- package/out/project/_/memory/__next.project.$d$id.memory.txt +1 -1
- package/out/project/_/memory/__next.project.$d$id.txt +1 -1
- package/out/project/_/memory/__next.project.txt +1 -1
- package/out/project/_/memory.html +1 -1
- package/out/project/_/memory.txt +3 -3
- package/out/project/_/queue/__next._full.txt +3 -3
- 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 +2 -2
- 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 +3 -3
- package/out/project/_.html +1 -1
- package/out/project/_.txt +3 -3
- package/out/settings/__next._full.txt +3 -3
- 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 +2 -2
- package/out/settings/__next.settings.txt +1 -1
- package/out/settings.html +1 -1
- package/out/settings.txt +3 -3
- package/out/setup/__next._full.txt +3 -3
- 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 +2 -2
- package/out/setup/__next.setup.txt +1 -1
- package/out/setup.html +1 -1
- package/out/setup.txt +3 -3
- package/package.json +1 -1
- package/server/config.js +42 -2
- package/server/index.js +103 -55
- package/server/routes.js +104 -66
- package/templates/CLAUDE.md +16 -17
- package/templates/config.toml +12 -12
- package/templates/seeds/{t3.AGENTS.md → dev.AGENTS.md} +19 -19
- package/templates/seeds/{t1.AGENTS.md → head.AGENTS.md} +18 -18
- package/templates/seeds/{t2a.AGENTS.md → reviewer1.AGENTS.md} +16 -16
- package/templates/seeds/{t2b.AGENTS.md → reviewer2.AGENTS.md} +16 -16
- package/out/_next/static/chunks/03yov._jigv17.js +0 -1
- package/out/_next/static/chunks/0iqqouh_3i5y5.js +0 -13
- package/out/_next/static/chunks/15kwal..m9r49.css +0 -2
- package/out/_next/static/chunks/17sk4qv6_d0co.js +0 -1
- /package/out/_next/static/{vELqtMegFMn5_6zFOkhtG → 91YUiFoMbLQ9sZW4uk45J}/_buildManifest.js +0 -0
- /package/out/_next/static/{vELqtMegFMn5_6zFOkhtG → 91YUiFoMbLQ9sZW4uk45J}/_clientMiddlewareManifest.js +0 -0
- /package/out/_next/static/{vELqtMegFMn5_6zFOkhtG → 91YUiFoMbLQ9sZW4uk45J}/_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/15kwal..m9r49.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/13uu.sohs74zg.js"/><script src="/_next/static/chunks/0excsn2a_5qsb.js" async=""></script><script src="/_next/static/chunks/0r7t_sj_sejq9.js" async=""></script><script src="/_next/static/chunks/0.dzh0qf9zq1l.js" async=""></script><script src="/_next/static/chunks/turbopack-06pqx~0d8czn_.js" async=""></script><script src="/_next/static/chunks/08fgie1bcjynm.js" async=""></script><script src="/_next/static/chunks/0ox7p_szjhn69.js" async=""></script><script src="/_next/static/chunks/03yov._jigv17.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.0x3dzn~oxb6tn.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex"><div hidden=""><!--$--><!--/$--></div><aside class="w-16 shrink-0 h-full border-r border-border bg-bg-surface flex flex-col items-center py-3"><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="w-6 h-px bg-border my-2"></div><div class="flex-1 flex flex-col items-center gap-2 overflow-y-auto min-h-0"><a class="w-10 h-10 flex items-center justify-center rounded-full border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="w-6 h-px bg-border my-2"></div><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto p-6 max-w-4xl"><h1 class="text-lg font-semibold text-text tracking-tight mb-6">New Project Setup</h1><div class="flex gap-8"><div class="w-48 shrink-0"><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-accent text-accent bg-accent/10">1</span><span class="text-[11px] text-text font-semibold">Project Name</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">2</span><span class="text-[11px] text-text-muted">GitHub Repo</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">3</span><span class="text-[11px] text-text-muted">Branch Protection</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">4</span><span class="text-[11px] text-text-muted">CLI Backend</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">5</span><span class="text-[11px] text-text-muted">Working Directory</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">6</span><span class="text-[11px] text-text-muted">Worktree Setup</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">7</span><span class="text-[11px] text-text-muted">Seed Files</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">8</span><span class="text-[11px] text-text-muted">AgentChattr Config</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">9</span><span class="text-[11px] text-text-muted">Save Config</span></div></div><div class="flex-1 border border-border p-4"><div><h2 class="text-sm font-semibold text-text mb-3">Project Name</h2><input placeholder="My Project" class="w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-3" 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><!--$--><!--/$--></main><script src="/_next/static/chunks/13uu.sohs74zg.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[86081,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n3:I[12527,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n4:I[59763,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n5:I[64618,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\",\"/_next/static/chunks/03yov._jigv17.js\"],\"default\"]\n6:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"OutletBoundary\"]\n7:\"$Sreact.suspense\"\na:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"ViewportBoundary\"]\nc:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"MetadataBoundary\"]\ne:I[92243,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/15kwal..m9r49.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/15kwal..m9r49.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/08fgie1bcjynm.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0ox7p_szjhn69.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L5\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/03yov._jigv17.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L6\",null,{\"children\":[\"$\",\"$7\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@8\"}]}]]}],{},null,false,null]},null,false,\"$@9\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$La\",null,{\"children\":\"$Lb\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lc\",null,{\"children\":[\"$\",\"$7\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Ld\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$e\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/15kwal..m9r49.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"vELqtMegFMn5_6zFOkhtG\"}\n"])</script><script>self.__next_f.push([1,"f:[]\n9:\"$Wf\"\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"10:I[80070,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"IconMark\"]\n8:null\nd:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0x3dzn~oxb6tn.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L10\",\"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/0yxmvmvm1dx_d.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/13uu.sohs74zg.js"/><script src="/_next/static/chunks/0excsn2a_5qsb.js" async=""></script><script src="/_next/static/chunks/0r7t_sj_sejq9.js" async=""></script><script src="/_next/static/chunks/0.dzh0qf9zq1l.js" async=""></script><script src="/_next/static/chunks/turbopack-06pqx~0d8czn_.js" async=""></script><script src="/_next/static/chunks/08fgie1bcjynm.js" async=""></script><script src="/_next/static/chunks/0ox7p_szjhn69.js" async=""></script><script src="/_next/static/chunks/0gy_9ugdx7ueh.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.0x3dzn~oxb6tn.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex"><div hidden=""><!--$--><!--/$--></div><aside class="w-16 shrink-0 h-full border-r border-border bg-bg-surface flex flex-col items-center py-3"><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="w-6 h-px bg-border my-2"></div><div class="flex-1 flex flex-col items-center gap-2 overflow-y-auto min-h-0"><a class="w-10 h-10 flex items-center justify-center rounded-full border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="w-6 h-px bg-border my-2"></div><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto p-6 max-w-4xl"><h1 class="text-lg font-semibold text-text tracking-tight mb-6">New Project Setup</h1><div class="flex gap-8"><div class="w-48 shrink-0"><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-accent text-accent bg-accent/10">1</span><span class="text-[11px] text-text font-semibold">Project Name</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">2</span><span class="text-[11px] text-text-muted">GitHub Repo</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">3</span><span class="text-[11px] text-text-muted">Branch Protection</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">4</span><span class="text-[11px] text-text-muted">CLI Backend</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">5</span><span class="text-[11px] text-text-muted">Working Directory</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">6</span><span class="text-[11px] text-text-muted">Worktree Setup</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">7</span><span class="text-[11px] text-text-muted">Seed Files</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">8</span><span class="text-[11px] text-text-muted">AgentChattr Config</span></div><div class="flex items-center gap-2 py-1.5"><span class="w-5 h-5 flex items-center justify-center text-[10px] border border-border text-text-muted">9</span><span class="text-[11px] text-text-muted">Save Config</span></div></div><div class="flex-1 border border-border p-4"><div><h2 class="text-sm font-semibold text-text mb-3">Project Name</h2><input placeholder="My Project" class="w-full bg-transparent border border-border px-2 py-1.5 text-[12px] text-text outline-none focus:border-accent mb-3" 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><!--$--><!--/$--></main><script src="/_next/static/chunks/13uu.sohs74zg.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[86081,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n3:I[12527,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n4:I[59763,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n5:I[64618,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\",\"/_next/static/chunks/0gy_9ugdx7ueh.js\"],\"default\"]\n6:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"OutletBoundary\"]\n7:\"$Sreact.suspense\"\na:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"ViewportBoundary\"]\nc:I[11717,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"MetadataBoundary\"]\ne:I[92243,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0yxmvmvm1dx_d.css\",\"style\"]\n: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/0yxmvmvm1dx_d.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/08fgie1bcjynm.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0ox7p_szjhn69.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L5\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0gy_9ugdx7ueh.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L6\",null,{\"children\":[\"$\",\"$7\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@8\"}]}]]}],{},null,false,null]},null,false,\"$@9\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$La\",null,{\"children\":\"$Lb\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lc\",null,{\"children\":[\"$\",\"$7\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Ld\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$e\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0yxmvmvm1dx_d.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"91YUiFoMbLQ9sZW4uk45J\"}\n"])</script><script>self.__next_f.push([1,"f:[]\n9:\"$Wf\"\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"10:I[80070,[\"/_next/static/chunks/08fgie1bcjynm.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"IconMark\"]\n8:null\nd:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0x3dzn~oxb6tn.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L10\",\"3\",{}]]\n"])</script></body></html>
|
package/out/setup.txt
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
2:I[86081,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
|
|
3
3
|
3:I[12527,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
|
|
4
4
|
4:I[59763,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
|
|
5
|
-
5:I[64618,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js","/_next/static/chunks/
|
|
5
|
+
5:I[64618,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js","/_next/static/chunks/0gy_9ugdx7ueh.js"],"default"]
|
|
6
6
|
6:I[11717,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"OutletBoundary"]
|
|
7
7
|
7:"$Sreact.suspense"
|
|
8
8
|
a:I[11717,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"ViewportBoundary"]
|
|
9
9
|
c:I[11717,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"MetadataBoundary"]
|
|
10
10
|
e:I[92243,["/_next/static/chunks/08fgie1bcjynm.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default",1]
|
|
11
|
-
:HL["/_next/static/chunks/
|
|
11
|
+
:HL["/_next/static/chunks/0yxmvmvm1dx_d.css","style"]
|
|
12
12
|
:HL["/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
13
|
-
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/
|
|
13
|
+
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/0yxmvmvm1dx_d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/08fgie1bcjynm.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0ox7p_szjhn69.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"geist_mono_8d43a2aa-module__8Li5zG__variable h-full","children":["$","body",null,{"className":"h-full flex","children":[["$","$L2",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L3",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]]}]}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L3",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","$L5",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0gy_9ugdx7ueh.js","async":true,"nonce":"$undefined"}]],["$","$L6",null,{"children":["$","$7",null,{"name":"Next.MetadataOutlet","children":"$@8"}]}]]}],{},null,false,null]},null,false,"$@9"]},null,false,null],["$","$1","h",{"children":[null,["$","$La",null,{"children":"$Lb"}],["$","div",null,{"hidden":true,"children":["$","$Lc",null,{"children":["$","$7",null,{"name":"Next.Metadata","children":"$Ld"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$e",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0yxmvmvm1dx_d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"91YUiFoMbLQ9sZW4uk45J"}
|
|
14
14
|
f:[]
|
|
15
15
|
9:"$Wf"
|
|
16
16
|
b:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
package/package.json
CHANGED
package/server/config.js
CHANGED
|
@@ -10,6 +10,31 @@ const DEFAULT_CONFIG = {
|
|
|
10
10
|
projects: [],
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
// Migration: rename old agent keys to new ones
|
|
14
|
+
const AGENT_KEY_MAP = { t1: "head", t2a: "reviewer1", t2b: "reviewer2", t3: "dev" };
|
|
15
|
+
|
|
16
|
+
function migrateAgentKeys(config) {
|
|
17
|
+
let changed = false;
|
|
18
|
+
if (config.projects) {
|
|
19
|
+
for (const project of config.projects) {
|
|
20
|
+
if (!project.agents) continue;
|
|
21
|
+
for (const [oldKey, newKey] of Object.entries(AGENT_KEY_MAP)) {
|
|
22
|
+
if (project.agents[oldKey] && !project.agents[newKey]) {
|
|
23
|
+
project.agents[newKey] = project.agents[oldKey];
|
|
24
|
+
delete project.agents[oldKey];
|
|
25
|
+
changed = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (changed) {
|
|
31
|
+
try {
|
|
32
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|
|
35
|
+
return config;
|
|
36
|
+
}
|
|
37
|
+
|
|
13
38
|
function readConfig() {
|
|
14
39
|
let raw;
|
|
15
40
|
try {
|
|
@@ -28,7 +53,8 @@ function readConfig() {
|
|
|
28
53
|
}
|
|
29
54
|
|
|
30
55
|
try {
|
|
31
|
-
|
|
56
|
+
const config = JSON.parse(raw);
|
|
57
|
+
return migrateAgentKeys(config);
|
|
32
58
|
} catch (err) {
|
|
33
59
|
throw new Error(`Invalid JSON in ${CONFIG_PATH}: ${err.message}`);
|
|
34
60
|
}
|
|
@@ -60,4 +86,18 @@ function resolveAgentCommand(projectId, agentId) {
|
|
|
60
86
|
return agent.command;
|
|
61
87
|
}
|
|
62
88
|
|
|
63
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Resolve AgentChattr connection for a project (per-project → global fallback).
|
|
91
|
+
*/
|
|
92
|
+
function resolveProjectChattr(projectId) {
|
|
93
|
+
const config = readConfig();
|
|
94
|
+
const project = projectId ? config.projects?.find((p) => p.id === projectId) : null;
|
|
95
|
+
return {
|
|
96
|
+
url: project?.agentchattr_url || config.agentchattr_url || "http://127.0.0.1:8300",
|
|
97
|
+
token: project?.agentchattr_token || config.agentchattr_token || null,
|
|
98
|
+
mcp_http_port: project?.mcp_http_port || null,
|
|
99
|
+
mcp_sse_port: project?.mcp_sse_port || null,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = { readConfig, resolveAgentCwd, resolveAgentCommand, resolveProjectChattr, CONFIG_PATH };
|
package/server/index.js
CHANGED
|
@@ -5,7 +5,7 @@ const fs = require("fs");
|
|
|
5
5
|
const { WebSocketServer } = require("ws");
|
|
6
6
|
const pty = require("node-pty");
|
|
7
7
|
const { spawn } = require("child_process");
|
|
8
|
-
const { readConfig, resolveAgentCwd, resolveAgentCommand } = require("./config");
|
|
8
|
+
const { readConfig, resolveAgentCwd, resolveAgentCommand, resolveProjectChattr } = require("./config");
|
|
9
9
|
const routes = require("./routes");
|
|
10
10
|
|
|
11
11
|
const config = readConfig();
|
|
@@ -30,8 +30,8 @@ app.get("/api/health", (_req, res) => {
|
|
|
30
30
|
// PTY (term) is the source of truth for "running". WS is optional (attaches to view terminal).
|
|
31
31
|
const agentSessions = new Map();
|
|
32
32
|
|
|
33
|
-
// AgentChattr server
|
|
34
|
-
|
|
33
|
+
// AgentChattr server processes — per-project (key = projectId)
|
|
34
|
+
const chattrProcesses = new Map();
|
|
35
35
|
|
|
36
36
|
// Helper: spawn a PTY for a project/agent and register in agentSessions
|
|
37
37
|
function spawnAgentPty(project, agent) {
|
|
@@ -99,79 +99,107 @@ app.get("/api/agents", (_req, res) => {
|
|
|
99
99
|
for (const [key, session] of agentSessions) {
|
|
100
100
|
agents[key] = { state: session.state, error: session.error || null };
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
for (const [pid, proc] of chattrProcesses) {
|
|
103
|
+
agents[`_agentchattr/${pid}`] = { state: proc.state, error: proc.error };
|
|
104
|
+
}
|
|
103
105
|
res.json(agents);
|
|
104
106
|
});
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
// Per-project AgentChattr lifecycle: /api/agentchattr/:project/:action
|
|
109
|
+
// Backward compat: /api/agentchattr/:action uses first project
|
|
110
|
+
function handleAgentChattr(req, res) {
|
|
111
|
+
let projectId, action;
|
|
112
|
+
if (req.params.action) {
|
|
113
|
+
projectId = req.params.projectOrAction;
|
|
114
|
+
action = req.params.action;
|
|
115
|
+
} else {
|
|
116
|
+
// Backward compat: single-param = action, use first project
|
|
117
|
+
action = req.params.projectOrAction;
|
|
118
|
+
const cfg = readConfig();
|
|
119
|
+
projectId = cfg.projects?.[0]?.id || "_default";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const { url: chattrUrl } = resolveProjectChattr(projectId);
|
|
110
123
|
const chattrPort = new URL(chattrUrl).port || "8300";
|
|
111
124
|
|
|
125
|
+
// Find per-project config.toml (prefer project working_dir/agentchattr/config.toml)
|
|
126
|
+
const cfg = readConfig();
|
|
127
|
+
const project = cfg.projects?.find((p) => p.id === projectId);
|
|
128
|
+
const projectConfigToml = project?.working_dir
|
|
129
|
+
? path.join(project.working_dir, "agentchattr", "config.toml")
|
|
130
|
+
: null;
|
|
131
|
+
|
|
132
|
+
function getProc() {
|
|
133
|
+
return chattrProcesses.get(projectId) || { process: null, state: "stopped", error: null };
|
|
134
|
+
}
|
|
135
|
+
function setProc(val) {
|
|
136
|
+
chattrProcesses.set(projectId, val);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function spawnChattr() {
|
|
140
|
+
// Use project config.toml if available (isolated data dir + ports), otherwise fall back to --port
|
|
141
|
+
const args = (projectConfigToml && fs.existsSync(projectConfigToml))
|
|
142
|
+
? ["--config", projectConfigToml]
|
|
143
|
+
: ["--port", chattrPort];
|
|
144
|
+
const child = spawn("agentchattr", args, {
|
|
145
|
+
env: process.env,
|
|
146
|
+
stdio: "ignore",
|
|
147
|
+
detached: true,
|
|
148
|
+
});
|
|
149
|
+
child.unref();
|
|
150
|
+
child.on("error", (err) => {
|
|
151
|
+
setProc({ process: null, state: "error", error: err.message });
|
|
152
|
+
});
|
|
153
|
+
child.on("exit", (code) => {
|
|
154
|
+
const cur = getProc();
|
|
155
|
+
if (cur.process === child) {
|
|
156
|
+
setProc({ process: null, state: "stopped", error: code ? `exit:${code}` : null });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
setProc({ process: child, state: "running", error: null });
|
|
160
|
+
return child;
|
|
161
|
+
}
|
|
162
|
+
|
|
112
163
|
if (action === "start") {
|
|
113
|
-
|
|
164
|
+
const proc = getProc();
|
|
165
|
+
if (proc.state === "running" && proc.process) {
|
|
114
166
|
return res.json({ ok: true, state: "running", message: "Already running" });
|
|
115
167
|
}
|
|
116
168
|
try {
|
|
117
|
-
const child =
|
|
118
|
-
env: process.env,
|
|
119
|
-
stdio: "ignore",
|
|
120
|
-
detached: true,
|
|
121
|
-
});
|
|
122
|
-
child.unref();
|
|
123
|
-
child.on("error", (err) => {
|
|
124
|
-
chattrProcess = { process: null, state: "error", error: err.message };
|
|
125
|
-
});
|
|
126
|
-
child.on("exit", (code) => {
|
|
127
|
-
if (chattrProcess.process === child) {
|
|
128
|
-
chattrProcess = { process: null, state: "stopped", error: code ? `exit:${code}` : null };
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
chattrProcess = { process: child, state: "running", error: null };
|
|
169
|
+
const child = spawnChattr();
|
|
132
170
|
res.json({ ok: true, state: "running", pid: child.pid });
|
|
133
171
|
} catch (err) {
|
|
134
|
-
|
|
172
|
+
setProc({ process: null, state: "error", error: err.message });
|
|
135
173
|
res.status(500).json({ ok: false, state: "error", error: err.message });
|
|
136
174
|
}
|
|
137
175
|
} else if (action === "stop") {
|
|
138
|
-
|
|
139
|
-
|
|
176
|
+
const proc = getProc();
|
|
177
|
+
if (proc.process) {
|
|
178
|
+
try { proc.process.kill("SIGTERM"); } catch {}
|
|
140
179
|
}
|
|
141
|
-
|
|
180
|
+
setProc({ process: null, state: "stopped", error: null });
|
|
142
181
|
res.json({ ok: true, state: "stopped" });
|
|
143
182
|
} else if (action === "restart") {
|
|
144
|
-
|
|
145
|
-
|
|
183
|
+
const proc = getProc();
|
|
184
|
+
if (proc.process) {
|
|
185
|
+
try { proc.process.kill("SIGTERM"); } catch {}
|
|
146
186
|
}
|
|
147
|
-
|
|
187
|
+
setProc({ process: null, state: "stopped", error: null });
|
|
148
188
|
setTimeout(() => {
|
|
149
189
|
try {
|
|
150
|
-
const child =
|
|
151
|
-
env: process.env,
|
|
152
|
-
stdio: "ignore",
|
|
153
|
-
detached: true,
|
|
154
|
-
});
|
|
155
|
-
child.unref();
|
|
156
|
-
child.on("error", (err) => {
|
|
157
|
-
chattrProcess = { process: null, state: "error", error: err.message };
|
|
158
|
-
});
|
|
159
|
-
child.on("exit", (code) => {
|
|
160
|
-
if (chattrProcess.process === child) {
|
|
161
|
-
chattrProcess = { process: null, state: "stopped", error: code ? `exit:${code}` : null };
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
chattrProcess = { process: child, state: "running", error: null };
|
|
190
|
+
const child = spawnChattr();
|
|
165
191
|
res.json({ ok: true, state: "running", pid: child.pid });
|
|
166
192
|
} catch (err) {
|
|
167
|
-
|
|
193
|
+
setProc({ process: null, state: "error", error: err.message });
|
|
168
194
|
res.status(500).json({ ok: false, state: "error", error: err.message });
|
|
169
195
|
}
|
|
170
196
|
}, 500);
|
|
171
197
|
} else {
|
|
172
198
|
res.status(400).json({ error: "Unknown action" });
|
|
173
199
|
}
|
|
174
|
-
}
|
|
200
|
+
}
|
|
201
|
+
app.post("/api/agentchattr/:projectOrAction/:action", handleAgentChattr);
|
|
202
|
+
app.post("/api/agentchattr/:projectOrAction", handleAgentChattr);
|
|
175
203
|
|
|
176
204
|
// --- Lifecycle: start spawns PTY (visible in terminal panel) ---
|
|
177
205
|
|
|
@@ -262,17 +290,17 @@ app.post("/api/agents/:project/:agent/write", (req, res) => {
|
|
|
262
290
|
|
|
263
291
|
const triggers = new Map();
|
|
264
292
|
|
|
265
|
-
const DEFAULT_MESSAGE = `@
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
293
|
+
const DEFAULT_MESSAGE = `@head @reviewer1 @reviewer2 @dev — Queue check.
|
|
294
|
+
Head: Merge any PR with both approvals, assign next from queue.
|
|
295
|
+
Dev: Work on assigned ticket or address review feedback.
|
|
296
|
+
Reviewer1/Reviewer2: Review open PRs. If Dev pushed fixes, re-review. Post verdict on PR AND notify here.
|
|
269
297
|
ALL: Communicate via this chat by tagging agents. Your terminal is NOT visible.`;
|
|
270
298
|
|
|
271
299
|
async function sendTriggerMessage(projectId) {
|
|
272
300
|
const cfg = readConfig();
|
|
273
301
|
const project = cfg.projects && cfg.projects.find((p) => p.id === projectId);
|
|
274
|
-
const chattrUrl
|
|
275
|
-
const token =
|
|
302
|
+
const { url: chattrUrl, token: chattrToken } = resolveProjectChattr(projectId);
|
|
303
|
+
const token = chattrToken || "";
|
|
276
304
|
const message = (project && project.trigger_message) || DEFAULT_MESSAGE;
|
|
277
305
|
const headers = { "Content-Type": "application/json" };
|
|
278
306
|
if (token) headers["x-session-token"] = token;
|
|
@@ -359,11 +387,31 @@ if (fs.existsSync(outDir)) {
|
|
|
359
387
|
app.use(express.static(outDir));
|
|
360
388
|
}
|
|
361
389
|
|
|
362
|
-
// SPA fallback: serve
|
|
390
|
+
// SPA fallback: serve the correct pre-rendered HTML for dynamic routes.
|
|
391
|
+
// Static export only generates templates for placeholder params (e.g. /project/_),
|
|
392
|
+
// so we map real dynamic segments back to those template files.
|
|
363
393
|
app.use((req, res, next) => {
|
|
364
394
|
if (req.method !== "GET" || req.path.startsWith("/api/")) {
|
|
365
395
|
return next();
|
|
366
396
|
}
|
|
397
|
+
|
|
398
|
+
// Map dynamic routes to their pre-rendered template HTML
|
|
399
|
+
const dynamicRoutes = [
|
|
400
|
+
{ pattern: /^\/project\/[^/]+\/memory\/?$/, template: "project/_/memory.html" },
|
|
401
|
+
{ pattern: /^\/project\/[^/]+\/queue\/?$/, template: "project/_/queue.html" },
|
|
402
|
+
{ pattern: /^\/project\/[^/]+\/?$/, template: "project/_.html" },
|
|
403
|
+
];
|
|
404
|
+
|
|
405
|
+
for (const route of dynamicRoutes) {
|
|
406
|
+
if (route.pattern.test(req.path)) {
|
|
407
|
+
const templatePath = path.join(outDir, route.template);
|
|
408
|
+
if (fs.existsSync(templatePath)) {
|
|
409
|
+
return res.sendFile(templatePath);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Default fallback to index.html
|
|
367
415
|
const indexPath = path.join(outDir, "index.html");
|
|
368
416
|
if (fs.existsSync(indexPath)) {
|
|
369
417
|
res.sendFile(indexPath);
|