quadwork 1.5.3 → 1.5.4
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/bin/quadwork.js +4 -1
- package/out/404.html +1 -1
- package/out/__next.__PAGE__.txt +3 -3
- package/out/__next._full.txt +11 -11
- package/out/__next._head.txt +4 -4
- package/out/__next._index.txt +5 -5
- package/out/__next._tree.txt +1 -1
- package/out/_next/static/chunks/0.bbxho1vnxin.js +1 -0
- package/out/_next/static/chunks/{0wreuebrwlg.2.js → 0.fo6qk3ltnbn.js} +2 -2
- package/out/_next/static/chunks/00n1ppi~-l_sv.js +1 -0
- package/out/_next/static/chunks/{0.57eg262w~qg.js → 01xlw8hd842-c.js} +1 -1
- package/out/_next/static/chunks/{135rms05ismy4.js → 0656i.-.r7.a9.js} +2 -2
- package/out/_next/static/chunks/09elx026_5z7..js +1 -0
- package/out/_next/static/chunks/0d3shmwh5_nmn.js +1 -0
- package/out/_next/static/chunks/0fkhi51bdw9~~.js +1 -0
- package/out/_next/static/chunks/0fpg8z.yd2xb7.js +1 -0
- package/out/_next/static/chunks/0iwycgwby2dd_.js +1 -0
- package/out/_next/static/chunks/0mtmv-f5qymoi.js +1 -0
- package/out/_next/static/chunks/0pqt~8bl3ukh4.js +4 -0
- package/out/_next/static/chunks/0ze4gu236oq96.js +31 -0
- package/out/_next/static/chunks/0zfotsowwll1x.js +2 -0
- package/out/_next/static/chunks/0~xrqi87fqraz.js +1 -0
- package/out/_next/static/chunks/11v7tu7pto6_x.js +1 -0
- package/out/_next/static/chunks/{0dmi9pk2bd712.js → 12i404gkhv7q..js} +2 -2
- package/out/_next/static/chunks/16g.ca89g7fib.js +1 -0
- package/out/_next/static/chunks/{turbopack-0wh29ykoy-rb5.js → turbopack-0lcwh84lrj9gi.js} +1 -1
- package/out/_not-found/__next._full.txt +10 -10
- package/out/_not-found/__next._head.txt +4 -4
- package/out/_not-found/__next._index.txt +5 -5
- package/out/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/out/_not-found/__next._not-found.txt +3 -3
- package/out/_not-found/__next._tree.txt +1 -1
- package/out/_not-found.html +1 -1
- package/out/_not-found.txt +10 -10
- package/out/app-shell/__next._full.txt +10 -10
- package/out/app-shell/__next._head.txt +4 -4
- package/out/app-shell/__next._index.txt +5 -5
- package/out/app-shell/__next._tree.txt +1 -1
- package/out/app-shell/__next.app-shell.__PAGE__.txt +2 -2
- package/out/app-shell/__next.app-shell.txt +3 -3
- package/out/app-shell.html +1 -1
- package/out/app-shell.txt +10 -10
- package/out/index.html +1 -1
- package/out/index.txt +11 -11
- package/out/project/_/__next._full.txt +11 -11
- package/out/project/_/__next._head.txt +4 -4
- package/out/project/_/__next._index.txt +5 -5
- package/out/project/_/__next._tree.txt +1 -1
- package/out/project/_/__next.project.$d$id.__PAGE__.txt +3 -3
- package/out/project/_/__next.project.$d$id.txt +3 -3
- package/out/project/_/__next.project.txt +3 -3
- package/out/project/_/memory/__next._full.txt +11 -11
- package/out/project/_/memory/__next._head.txt +4 -4
- package/out/project/_/memory/__next._index.txt +5 -5
- package/out/project/_/memory/__next._tree.txt +1 -1
- package/out/project/_/memory/__next.project.$d$id.memory.__PAGE__.txt +3 -3
- package/out/project/_/memory/__next.project.$d$id.memory.txt +3 -3
- package/out/project/_/memory/__next.project.$d$id.txt +3 -3
- package/out/project/_/memory/__next.project.txt +3 -3
- package/out/project/_/memory.html +1 -1
- package/out/project/_/memory.txt +11 -11
- package/out/project/_/queue/__next._full.txt +11 -11
- package/out/project/_/queue/__next._head.txt +4 -4
- package/out/project/_/queue/__next._index.txt +5 -5
- package/out/project/_/queue/__next._tree.txt +1 -1
- package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +3 -3
- package/out/project/_/queue/__next.project.$d$id.queue.txt +3 -3
- package/out/project/_/queue/__next.project.$d$id.txt +3 -3
- package/out/project/_/queue/__next.project.txt +3 -3
- package/out/project/_/queue.html +1 -1
- package/out/project/_/queue.txt +11 -11
- package/out/project/_.html +1 -1
- package/out/project/_.txt +11 -11
- package/out/settings/__next._full.txt +11 -11
- package/out/settings/__next._head.txt +4 -4
- package/out/settings/__next._index.txt +5 -5
- package/out/settings/__next._tree.txt +1 -1
- package/out/settings/__next.settings.__PAGE__.txt +3 -3
- package/out/settings/__next.settings.txt +3 -3
- package/out/settings.html +1 -1
- package/out/settings.txt +11 -11
- package/out/setup/__next._full.txt +11 -11
- package/out/setup/__next._head.txt +4 -4
- package/out/setup/__next._index.txt +5 -5
- package/out/setup/__next._tree.txt +1 -1
- package/out/setup/__next.setup.__PAGE__.txt +3 -3
- package/out/setup/__next.setup.txt +3 -3
- package/out/setup.html +1 -1
- package/out/setup.txt +11 -11
- package/package.json +1 -1
- package/server/index.js +130 -41
- package/server/install-agentchattr.js +53 -0
- package/server/routes.js +25 -3
- package/server/routes.telegramBridge.test.js +4 -1
- package/templates/CLAUDE.md +2 -1
- package/templates/seeds/dev.AGENTS.md +2 -0
- package/templates/seeds/head.AGENTS.md +2 -0
- package/templates/seeds/reviewer1.AGENTS.md +3 -1
- package/templates/seeds/reviewer2.AGENTS.md +3 -1
- package/out/_next/static/chunks/04_t39bv8y9pe.js +0 -1
- package/out/_next/static/chunks/084lff9v4p_vh.js +0 -1
- package/out/_next/static/chunks/09sq17vme9g6p.js +0 -1
- package/out/_next/static/chunks/0e.ktwt1nyj...js +0 -1
- package/out/_next/static/chunks/0excsn2a_5qsb.js +0 -4
- package/out/_next/static/chunks/0ezniz80psxr6.js +0 -1
- package/out/_next/static/chunks/0g-nq4.uckan-.js +0 -1
- package/out/_next/static/chunks/0ox7p_szjhn69.js +0 -1
- package/out/_next/static/chunks/0r7t_sj_sejq9.js +0 -1
- package/out/_next/static/chunks/0r_tb4lmfa_yb.js +0 -1
- package/out/_next/static/chunks/0whtwwbpg72ar.js +0 -1
- package/out/_next/static/chunks/0z~0.4hivi.f2.js +0 -31
- package/out/_next/static/chunks/15i5_ay.0ap.6.js +0 -2
- package/out/_next/static/chunks/17y2walb2um9w.js +0 -1
- /package/out/_next/static/{X4zdS6Y6HkLOaElNeHwnq → XCVQTR6dRg8tK75W8jDzw}/_buildManifest.js +0 -0
- /package/out/_next/static/{X4zdS6Y6HkLOaElNeHwnq → XCVQTR6dRg8tK75W8jDzw}/_clientMiddlewareManifest.js +0 -0
- /package/out/_next/static/{X4zdS6Y6HkLOaElNeHwnq → XCVQTR6dRg8tK75W8jDzw}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
1:"$Sreact.fragment"
|
|
2
|
-
2:I[
|
|
3
|
-
3:I[
|
|
2
|
+
2:I[94810,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js","/_next/static/chunks/0mtmv-f5qymoi.js"],"default"]
|
|
3
|
+
3:I[97367,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"OutletBoundary"]
|
|
4
4
|
4:"$Sreact.suspense"
|
|
5
|
-
0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/
|
|
5
|
+
0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0mtmv-f5qymoi.js","async":true}]],["$","$L3",null,{"children":["$","$4",null,{"name":"Next.MetadataOutlet","children":"$@5"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"XCVQTR6dRg8tK75W8jDzw"}
|
|
6
6
|
5:null
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
1:"$Sreact.fragment"
|
|
2
|
-
2:I[
|
|
3
|
-
3:I[
|
|
2
|
+
2:I[39756,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
|
|
3
|
+
3:I[37457,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
|
|
4
4
|
4:[]
|
|
5
|
-
0:{"rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"isPartial":false,"staleTime":300,"varyParams":"$W4","buildId":"
|
|
5
|
+
0:{"rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"isPartial":false,"staleTime":300,"varyParams":"$W4","buildId":"XCVQTR6dRg8tK75W8jDzw"}
|
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/0ccoe1hsu70ql.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0z~0.4hivi.f2.js"/><script src="/_next/static/chunks/0ezniz80psxr6.js" async=""></script><script src="/_next/static/chunks/0r7t_sj_sejq9.js" async=""></script><script src="/_next/static/chunks/15i5_ay.0ap.6.js" async=""></script><script src="/_next/static/chunks/0excsn2a_5qsb.js" async=""></script><script src="/_next/static/chunks/turbopack-0wh29ykoy-rb5.js" async=""></script><script src="/_next/static/chunks/04_t39bv8y9pe.js" async=""></script><script src="/_next/static/chunks/0ox7p_szjhn69.js" async=""></script><script src="/_next/static/chunks/084lff9v4p_vh.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 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="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"><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">reviewer1</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">reviewer2</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/0z~0.4hivi.f2.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[34852,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n3:I[86081,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n4:I[12527,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n5:I[59763,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n6:I[64618,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\",\"/_next/static/chunks/084lff9v4p_vh.js\"],\"default\"]\n7:I[11717,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"OutletBoundary\"]\n8:\"$Sreact.suspense\"\nb:I[11717,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"ViewportBoundary\"]\nd:I[11717,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"MetadataBoundary\"]\nf:I[92243,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0ccoe1hsu70ql.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/0ccoe1hsu70ql.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/04_t39bv8y9pe.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 flex-col\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L3\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",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,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L6\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/084lff9v4p_vh.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L7\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@9\"}]}]]}],{},null,false,null]},null,false,\"$@a\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Lb\",null,{\"children\":\"$Lc\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Ld\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Le\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$f\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0ccoe1hsu70ql.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"X4zdS6Y6HkLOaElNeHwnq\"}\n"])</script><script>self.__next_f.push([1,"10:[]\na:\"$W10\"\n"])</script><script>self.__next_f.push([1,"c:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"11:I[80070,[\"/_next/static/chunks/04_t39bv8y9pe.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"IconMark\"]\n9:null\ne:[[\"$\",\"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\"}],[\"$\",\"$L11\",\"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/0ccoe1hsu70ql.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/0fkhi51bdw9~~.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/0mtmv-f5qymoi.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 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="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"><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">reviewer1</span><span class="text-accent">claude</span></div><div class="flex justify-between"><span class="text-text capitalize">reviewer2</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[26704,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n3:I[22140,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[39756,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[37457,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[94810,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/0mtmv-f5qymoi.js\"],\"default\"]\n7:I[97367,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\n8:\"$Sreact.suspense\"\nb:I[97367,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nd:I[97367,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\nf:I[68027,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0ccoe1hsu70ql.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/0ccoe1hsu70ql.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0fkhi51bdw9~~.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,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L3\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",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,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L6\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0mtmv-f5qymoi.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L7\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@9\"}]}]]}],{},null,false,null]},null,false,\"$@a\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Lb\",null,{\"children\":\"$Lc\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Ld\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Le\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$f\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0ccoe1hsu70ql.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"XCVQTR6dRg8tK75W8jDzw\"}\n"])</script><script>self.__next_f.push([1,"10:[]\na:\"$W10\"\n"])</script><script>self.__next_f.push([1,"c:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"11:I[27201,[\"/_next/static/chunks/0fkhi51bdw9~~.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\n9:null\ne:[[\"$\",\"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\"}],[\"$\",\"$L11\",\"3\",{}]]\n"])</script></body></html>
|
package/out/setup.txt
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
1:"$Sreact.fragment"
|
|
2
|
-
2:I[
|
|
3
|
-
3:I[
|
|
4
|
-
4:I[
|
|
5
|
-
5:I[
|
|
6
|
-
6:I[
|
|
7
|
-
7:I[
|
|
2
|
+
2:I[26704,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
|
|
3
|
+
3:I[22140,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
|
|
4
|
+
4:I[39756,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
|
|
5
|
+
5:I[37457,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
|
|
6
|
+
6:I[94810,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js","/_next/static/chunks/0mtmv-f5qymoi.js"],"default"]
|
|
7
|
+
7:I[97367,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"OutletBoundary"]
|
|
8
8
|
8:"$Sreact.suspense"
|
|
9
|
-
b:I[
|
|
10
|
-
d:I[
|
|
11
|
-
f:I[
|
|
9
|
+
b:I[97367,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"ViewportBoundary"]
|
|
10
|
+
d:I[97367,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"MetadataBoundary"]
|
|
11
|
+
f:I[68027,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default",1]
|
|
12
12
|
:HL["/_next/static/chunks/0ccoe1hsu70ql.css","style"]
|
|
13
13
|
:HL["/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
14
|
-
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/0ccoe1hsu70ql.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/
|
|
14
|
+
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/0ccoe1hsu70ql.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0fkhi51bdw9~~.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,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L3",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",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,["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","$L6",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0mtmv-f5qymoi.js","async":true,"nonce":"$undefined"}]],["$","$L7",null,{"children":["$","$8",null,{"name":"Next.MetadataOutlet","children":"$@9"}]}]]}],{},null,false,null]},null,false,"$@a"]},null,false,null],["$","$1","h",{"children":[null,["$","$Lb",null,{"children":"$Lc"}],["$","div",null,{"hidden":true,"children":["$","$Ld",null,{"children":["$","$8",null,{"name":"Next.Metadata","children":"$Le"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$f",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0ccoe1hsu70ql.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"XCVQTR6dRg8tK75W8jDzw"}
|
|
15
15
|
10:[]
|
|
16
16
|
a:"$W10"
|
|
17
17
|
c:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
|
18
|
-
11:I[
|
|
18
|
+
11:I[27201,["/_next/static/chunks/0fkhi51bdw9~~.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"IconMark"]
|
|
19
19
|
9:null
|
|
20
20
|
e:[["$","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"}],["$","$L11","3",{}]]
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const { spawn } = require("child_process");
|
|
|
9
9
|
const { readConfig, resolveAgentCwd, resolveAgentCommand, resolveProjectChattr, resolveChattrSpawn, syncChattrToken, CONFIG_PATH } = require("./config");
|
|
10
10
|
const routes = require("./routes");
|
|
11
11
|
const { waitForAgentChattrReady, registerAgent, deregisterAgent, startHeartbeat, stopHeartbeat } = require("./agentchattr-registry");
|
|
12
|
+
const { patchAgentchattrCss } = require("./install-agentchattr");
|
|
12
13
|
const { startQueueWatcher, stopQueueWatcher } = require("./queue-watcher");
|
|
13
14
|
|
|
14
15
|
const net = require("net");
|
|
@@ -800,6 +801,9 @@ async function handleAgentChattr(req, res) {
|
|
|
800
801
|
|
|
801
802
|
// Resolve AgentChattr from its cloned directory
|
|
802
803
|
const { dir: acDir } = resolveProjectChattr(projectId);
|
|
804
|
+
// #394: backfill sender-overflow CSS/JS patch on every spawn so
|
|
805
|
+
// existing installs receive the fix without manual update.
|
|
806
|
+
patchAgentchattrCss(acDir);
|
|
803
807
|
const acSpawn = resolveChattrSpawn(acDir);
|
|
804
808
|
if (!acSpawn) {
|
|
805
809
|
setProc({ process: null, state: "error", error: `AgentChattr not installed. Clone it: git clone https://github.com/bcurts/agentchattr.git ${acDir}` });
|
|
@@ -834,11 +838,77 @@ async function handleAgentChattr(req, res) {
|
|
|
834
838
|
return child;
|
|
835
839
|
}
|
|
836
840
|
|
|
841
|
+
// #386: Kill any process listening on the AC port. Handles orphaned
|
|
842
|
+
// processes that survive QuadWork restarts (detached + unref'd spawns
|
|
843
|
+
// lose their tracked reference when the Node process recycles).
|
|
844
|
+
function killProcessOnPort(port) {
|
|
845
|
+
try {
|
|
846
|
+
const pids = execSync(`lsof -ti TCP:${port} -sTCP:LISTEN`, {
|
|
847
|
+
encoding: "utf-8",
|
|
848
|
+
timeout: 5000,
|
|
849
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
850
|
+
}).trim();
|
|
851
|
+
if (!pids) return;
|
|
852
|
+
for (const line of pids.split("\n")) {
|
|
853
|
+
const pid = parseInt(line, 10);
|
|
854
|
+
if (pid > 0) {
|
|
855
|
+
try { process.kill(pid, "SIGTERM"); } catch {}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
} catch {
|
|
859
|
+
// lsof exits non-zero when no matching process — expected
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// #386: Poll until the port is free or timeout expires.
|
|
864
|
+
function waitForPortFree(port, timeoutMs = 3000) {
|
|
865
|
+
const start = Date.now();
|
|
866
|
+
return new Promise((resolve) => {
|
|
867
|
+
function check() {
|
|
868
|
+
try {
|
|
869
|
+
execSync(`lsof -ti TCP:${port} -sTCP:LISTEN`, {
|
|
870
|
+
encoding: "utf-8",
|
|
871
|
+
timeout: 2000,
|
|
872
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
873
|
+
});
|
|
874
|
+
// Still occupied — retry if within budget
|
|
875
|
+
if (Date.now() - start < timeoutMs) {
|
|
876
|
+
setTimeout(check, 200);
|
|
877
|
+
} else {
|
|
878
|
+
resolve(false);
|
|
879
|
+
}
|
|
880
|
+
} catch {
|
|
881
|
+
// lsof found nothing — port is free
|
|
882
|
+
resolve(true);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
check();
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
|
|
837
889
|
if (action === "start") {
|
|
838
890
|
const proc = getProc();
|
|
839
891
|
if (proc.state === "running" && proc.process) {
|
|
840
892
|
return res.json({ ok: true, state: "running", message: "Already running" });
|
|
841
893
|
}
|
|
894
|
+
// #401: validate AgentChattr is installed BEFORE killing anything on
|
|
895
|
+
// the port. Without this guard, clicking Start when AC is missing
|
|
896
|
+
// kills an unrelated process then fails with "not installed".
|
|
897
|
+
const { dir: acDir } = resolveProjectChattr(projectId);
|
|
898
|
+
const acSpawn = resolveChattrSpawn(acDir);
|
|
899
|
+
if (!acSpawn) {
|
|
900
|
+
const errMsg = `AgentChattr not installed. Clone it: git clone https://github.com/bcurts/agentchattr.git ${acDir}`;
|
|
901
|
+
setProc({ process: null, state: "error", error: errMsg });
|
|
902
|
+
return res.status(500).json({ ok: false, state: "error", error: errMsg });
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// #393: kill any orphaned process on the port before spawning
|
|
906
|
+
// (same pattern as restart/stop from #386).
|
|
907
|
+
killProcessOnPort(chattrPort);
|
|
908
|
+
const portFree = await waitForPortFree(chattrPort, 3000);
|
|
909
|
+
if (!portFree) {
|
|
910
|
+
console.warn(`[agentchattr] ${projectId} port ${chattrPort} still occupied after 3s — spawning anyway`);
|
|
911
|
+
}
|
|
842
912
|
try {
|
|
843
913
|
const child = spawnChattr();
|
|
844
914
|
if (!child) {
|
|
@@ -857,6 +927,8 @@ async function handleAgentChattr(req, res) {
|
|
|
857
927
|
if (proc.process) {
|
|
858
928
|
try { proc.process.kill("SIGTERM"); } catch {}
|
|
859
929
|
}
|
|
930
|
+
// #386: also kill any orphaned process holding the port
|
|
931
|
+
killProcessOnPort(chattrPort);
|
|
860
932
|
setProc({ process: null, state: "stopped", error: null });
|
|
861
933
|
res.json({ ok: true, state: "stopped" });
|
|
862
934
|
} else if (action === "restart") {
|
|
@@ -876,46 +948,53 @@ async function handleAgentChattr(req, res) {
|
|
|
876
948
|
if (proc.process) {
|
|
877
949
|
try { proc.process.kill("SIGTERM"); } catch {}
|
|
878
950
|
}
|
|
951
|
+
// #386: also kill any orphaned process holding the port (handles
|
|
952
|
+
// detached processes that survived a QuadWork restart).
|
|
953
|
+
killProcessOnPort(chattrPort);
|
|
879
954
|
setProc({ process: null, state: "stopped", error: null });
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
// Best-effort: never blocks the restart response or
|
|
892
|
-
// rolls back on error.
|
|
893
|
-
if (shouldAutoRestore) {
|
|
894
|
-
setTimeout(async () => {
|
|
895
|
-
try {
|
|
896
|
-
const snapDir = path.join(require("os").homedir(), ".quadwork", projectId, "history-snapshots");
|
|
897
|
-
if (!fs.existsSync(snapDir)) return;
|
|
898
|
-
const newest = fs.readdirSync(snapDir)
|
|
899
|
-
.filter((f) => f.endsWith(".json"))
|
|
900
|
-
.map((f) => ({ f, t: fs.statSync(path.join(snapDir, f)).mtimeMs }))
|
|
901
|
-
.sort((a, b) => b.t - a.t)[0];
|
|
902
|
-
if (!newest) return;
|
|
903
|
-
const r = await fetch(`http://127.0.0.1:${PORT}/api/project-history/restore?project=${encodeURIComponent(projectId)}&name=${encodeURIComponent(newest.f)}`, {
|
|
904
|
-
method: "POST",
|
|
905
|
-
});
|
|
906
|
-
if (r.ok) console.log(`[snapshot] ${projectId} auto-restored ${newest.f}`);
|
|
907
|
-
else console.warn(`[snapshot] ${projectId} auto-restore returned ${r.status}`);
|
|
908
|
-
} catch (err) {
|
|
909
|
-
console.warn(`[snapshot] ${projectId} auto-restore failed: ${err.message || err}`);
|
|
910
|
-
}
|
|
911
|
-
}, 3000);
|
|
912
|
-
}
|
|
913
|
-
res.json({ ok: true, state: "running", pid: child.pid });
|
|
914
|
-
} catch (err) {
|
|
915
|
-
setProc({ process: null, state: "error", error: err.message });
|
|
916
|
-
res.status(500).json({ ok: false, state: "error", error: err.message });
|
|
955
|
+
// #386: wait for the port to actually be free before spawning,
|
|
956
|
+
// instead of a fixed 500ms that may race the old process.
|
|
957
|
+
const portFree = await waitForPortFree(chattrPort, 3000);
|
|
958
|
+
if (!portFree) {
|
|
959
|
+
console.warn(`[agentchattr] ${projectId} port ${chattrPort} still occupied after 3s — spawning anyway`);
|
|
960
|
+
}
|
|
961
|
+
try {
|
|
962
|
+
const child = spawnChattr();
|
|
963
|
+
if (!child) {
|
|
964
|
+
const errProc = getProc();
|
|
965
|
+
return res.status(500).json({ ok: false, state: "error", error: errProc.error || "Failed to start AgentChattr" });
|
|
917
966
|
}
|
|
918
|
-
|
|
967
|
+
// Sync token after AgentChattr restarts
|
|
968
|
+
setTimeout(() => syncChattrToken(projectId), 2000);
|
|
969
|
+
// #424 / quadwork#304 Phase 3: optional auto-restore.
|
|
970
|
+
// Fire the restore 3s after spawn so AC's ws is ready.
|
|
971
|
+
// Best-effort: never blocks the restart response or
|
|
972
|
+
// rolls back on error.
|
|
973
|
+
if (shouldAutoRestore) {
|
|
974
|
+
setTimeout(async () => {
|
|
975
|
+
try {
|
|
976
|
+
const snapDir = path.join(require("os").homedir(), ".quadwork", projectId, "history-snapshots");
|
|
977
|
+
if (!fs.existsSync(snapDir)) return;
|
|
978
|
+
const newest = fs.readdirSync(snapDir)
|
|
979
|
+
.filter((f) => f.endsWith(".json"))
|
|
980
|
+
.map((f) => ({ f, t: fs.statSync(path.join(snapDir, f)).mtimeMs }))
|
|
981
|
+
.sort((a, b) => b.t - a.t)[0];
|
|
982
|
+
if (!newest) return;
|
|
983
|
+
const r = await fetch(`http://127.0.0.1:${PORT}/api/project-history/restore?project=${encodeURIComponent(projectId)}&name=${encodeURIComponent(newest.f)}`, {
|
|
984
|
+
method: "POST",
|
|
985
|
+
});
|
|
986
|
+
if (r.ok) console.log(`[snapshot] ${projectId} auto-restored ${newest.f}`);
|
|
987
|
+
else console.warn(`[snapshot] ${projectId} auto-restore returned ${r.status}`);
|
|
988
|
+
} catch (err) {
|
|
989
|
+
console.warn(`[snapshot] ${projectId} auto-restore failed: ${err.message || err}`);
|
|
990
|
+
}
|
|
991
|
+
}, 3000);
|
|
992
|
+
}
|
|
993
|
+
res.json({ ok: true, state: "running", pid: child.pid });
|
|
994
|
+
} catch (err) {
|
|
995
|
+
setProc({ process: null, state: "error", error: err.message });
|
|
996
|
+
res.status(500).json({ ok: false, state: "error", error: err.message });
|
|
997
|
+
}
|
|
919
998
|
} else if (action === "update") {
|
|
920
999
|
// Update AgentChattr: stop → git pull → pip install → restart
|
|
921
1000
|
const { dir: acDir } = resolveProjectChattr(projectId);
|
|
@@ -939,12 +1018,18 @@ async function handleAgentChattr(req, res) {
|
|
|
939
1018
|
const wasRunning = proc.process && proc.state === "running";
|
|
940
1019
|
if (wasRunning) {
|
|
941
1020
|
try { proc.process.kill("SIGTERM"); } catch {}
|
|
1021
|
+
}
|
|
1022
|
+
// #386: kill orphaned processes on the port too
|
|
1023
|
+
killProcessOnPort(chattrPort);
|
|
1024
|
+
if (wasRunning) {
|
|
942
1025
|
setProc({ process: null, state: "stopped", error: null });
|
|
943
|
-
//
|
|
944
|
-
await
|
|
1026
|
+
// Wait for the port to be released before pulling/restarting
|
|
1027
|
+
await waitForPortFree(chattrPort, 3000);
|
|
945
1028
|
}
|
|
946
1029
|
|
|
947
1030
|
const pullResult = execSync("git pull 2>&1", { cwd: acDir, encoding: "utf-8", timeout: 30000 }).trim();
|
|
1031
|
+
// #388: re-apply sender-overflow CSS patch after git pull
|
|
1032
|
+
patchAgentchattrCss(acDir);
|
|
948
1033
|
const venvPython = path.join(acDir, ".venv", "bin", "python");
|
|
949
1034
|
let pipResult = "";
|
|
950
1035
|
const reqFile = path.join(acDir, "requirements.txt");
|
|
@@ -1658,10 +1743,14 @@ setInterval(runLoopGuardPollingTick, LOOP_GUARD_POLL_INTERVAL_MS);
|
|
|
1658
1743
|
server.listen(PORT, "127.0.0.1", () => {
|
|
1659
1744
|
console.log(`QuadWork server listening on http://127.0.0.1:${PORT}`);
|
|
1660
1745
|
syncTriggersFromConfig();
|
|
1661
|
-
// Sync AgentChattr tokens for all projects on startup
|
|
1746
|
+
// Sync AgentChattr tokens for all projects on startup and backfill
|
|
1747
|
+
// the sender-overflow CSS/JS patch (#402) so already-running AC
|
|
1748
|
+
// instances receive the fix without requiring a restart.
|
|
1662
1749
|
const startupCfg = readConfig();
|
|
1663
1750
|
for (const p of (startupCfg.projects || [])) {
|
|
1664
1751
|
syncChattrToken(p.id);
|
|
1752
|
+
const { dir: acDir } = resolveProjectChattr(p.id);
|
|
1753
|
+
if (acDir) patchAgentchattrCss(acDir);
|
|
1665
1754
|
}
|
|
1666
1755
|
});
|
|
1667
1756
|
|
|
@@ -192,6 +192,8 @@ function _installAgentChattrLocked(dir, setError) {
|
|
|
192
192
|
if (pipResult === null) return setError(`pip install -r ${reqFile} failed`);
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
// #388: patch sender-column overflow CSS after clone/install
|
|
196
|
+
patchAgentchattrCss(dir);
|
|
195
197
|
return dir;
|
|
196
198
|
}
|
|
197
199
|
|
|
@@ -207,9 +209,60 @@ function chattrSpawnArgs(dir, extraArgs) {
|
|
|
207
209
|
return { command: venvPython, spawnArgs: ["run.py", ...(extraArgs || [])], cwd: dir };
|
|
208
210
|
}
|
|
209
211
|
|
|
212
|
+
/**
|
|
213
|
+
* #388: Patch AgentChattr's static files for sender-column overflow.
|
|
214
|
+
* Idempotent — skips if the marker is already present.
|
|
215
|
+
* Called after install and after update (git pull overwrites static/).
|
|
216
|
+
*
|
|
217
|
+
* CSS: cap .msg-sender width with ellipsis truncation.
|
|
218
|
+
* JS: add title attribute to .msg-sender spans for hover tooltip.
|
|
219
|
+
*/
|
|
220
|
+
function patchAgentchattrCss(dir) {
|
|
221
|
+
if (!dir) return;
|
|
222
|
+
// --- CSS patch ---
|
|
223
|
+
const cssPath = path.join(dir, "static", "style.css");
|
|
224
|
+
if (fs.existsSync(cssPath)) {
|
|
225
|
+
try {
|
|
226
|
+
const content = fs.readFileSync(cssPath, "utf-8");
|
|
227
|
+
if (!content.includes("/* quadwork#388 sender-overflow fix */")) {
|
|
228
|
+
const patch = `
|
|
229
|
+
/* quadwork#388 sender-overflow fix */
|
|
230
|
+
.msg-sender {
|
|
231
|
+
max-width: 80px;
|
|
232
|
+
overflow: hidden;
|
|
233
|
+
text-overflow: ellipsis;
|
|
234
|
+
white-space: nowrap;
|
|
235
|
+
display: inline-block;
|
|
236
|
+
vertical-align: middle;
|
|
237
|
+
}
|
|
238
|
+
`;
|
|
239
|
+
fs.writeFileSync(cssPath, content + patch);
|
|
240
|
+
}
|
|
241
|
+
} catch {}
|
|
242
|
+
}
|
|
243
|
+
// --- JS patch: add title attribute to .msg-sender for hover tooltip ---
|
|
244
|
+
const jsPath = path.join(dir, "static", "chat.js");
|
|
245
|
+
if (fs.existsSync(jsPath)) {
|
|
246
|
+
try {
|
|
247
|
+
const content = fs.readFileSync(jsPath, "utf-8");
|
|
248
|
+
if (!content.includes("quadwork#388")) {
|
|
249
|
+
// Add title= to the msg-sender span so truncated names show full on hover
|
|
250
|
+
const patched = content.replace(
|
|
251
|
+
/(<span class="msg-sender" style="color: \$\{senderColor\}">)/g,
|
|
252
|
+
`<span class="msg-sender" title="\${escapeHtml(msg.sender)}" style="color: \${senderColor}">`,
|
|
253
|
+
);
|
|
254
|
+
if (patched !== content) {
|
|
255
|
+
fs.writeFileSync(jsPath, patched + "\n// quadwork#388\n");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} catch {}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
210
262
|
module.exports = {
|
|
211
263
|
AGENTCHATTR_REPO,
|
|
212
264
|
findAgentChattr,
|
|
213
265
|
installAgentChattr,
|
|
214
266
|
chattrSpawnArgs,
|
|
267
|
+
patchAgentchattrCss,
|
|
215
268
|
};
|
package/server/routes.js
CHANGED
|
@@ -2407,12 +2407,19 @@ function resolveProjectAgentchattrUrl(cfg, project) {
|
|
|
2407
2407
|
// #383 Bug 2: the upstream bridge only reads `agentchattr_url` from
|
|
2408
2408
|
// inside `[telegram]`. A separate `[agentchattr]` section is silently
|
|
2409
2409
|
// ignored and the bridge falls back to its hardcoded :8300 default.
|
|
2410
|
-
|
|
2410
|
+
// #404: accept projectId so we can write a per-project cursor_file
|
|
2411
|
+
// path. Without this, multiple project bridges share the same default
|
|
2412
|
+
// cursor and clobber each other's position — the project with higher
|
|
2413
|
+
// AC message IDs advances the cursor past the other project's range,
|
|
2414
|
+
// silently killing AC→TG forwarding for that project.
|
|
2415
|
+
function buildTelegramBridgeToml(tg, projectId) {
|
|
2416
|
+
const cursorFile = path.join(CONFIG_DIR, `telegram-bridge-cursor-${projectId}.json`);
|
|
2411
2417
|
return (
|
|
2412
2418
|
`[telegram]\n` +
|
|
2413
2419
|
`bot_token = "${tg.bot_token}"\n` +
|
|
2414
2420
|
`chat_id = "${tg.chat_id}"\n` +
|
|
2415
|
-
`agentchattr_url = "${tg.agentchattr_url}"\n`
|
|
2421
|
+
`agentchattr_url = "${tg.agentchattr_url}"\n` +
|
|
2422
|
+
`cursor_file = "${cursorFile}"\n`
|
|
2416
2423
|
);
|
|
2417
2424
|
}
|
|
2418
2425
|
|
|
@@ -2745,7 +2752,7 @@ router.post("/api/telegram", async (req, res) => {
|
|
|
2745
2752
|
const tomlPath = telegramConfigToml(projectId);
|
|
2746
2753
|
// #383 Bug 2: write agentchattr_url inside [telegram]; the
|
|
2747
2754
|
// bridge's load_config only reads from that section.
|
|
2748
|
-
const tomlContent = buildTelegramBridgeToml(tg);
|
|
2755
|
+
const tomlContent = buildTelegramBridgeToml(tg, projectId);
|
|
2749
2756
|
fs.writeFileSync(tomlPath, tomlContent, { mode: 0o600 });
|
|
2750
2757
|
fs.chmodSync(tomlPath, 0o600);
|
|
2751
2758
|
// #353: pre-flight import check so a fresh install with no
|
|
@@ -2837,6 +2844,21 @@ router.post("/api/telegram", async (req, res) => {
|
|
|
2837
2844
|
case "stop": {
|
|
2838
2845
|
const projectId = body.project_id;
|
|
2839
2846
|
if (!projectId) return res.json({ ok: false, error: "Missing project_id" });
|
|
2847
|
+
// #388: deregister the bridge from AC before killing so the slot
|
|
2848
|
+
// clears immediately instead of lingering for 60s as a stale -2/-3.
|
|
2849
|
+
// Awaited so a fast stop→start cycle doesn't race the deregister.
|
|
2850
|
+
try {
|
|
2851
|
+
const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
|
|
2852
|
+
const project = cfg.projects?.find((p) => p.id === projectId);
|
|
2853
|
+
const acUrl = resolveProjectAgentchattrUrl(cfg, project);
|
|
2854
|
+
if (acUrl) {
|
|
2855
|
+
const acPort = new URL(acUrl).port || "8300";
|
|
2856
|
+
await fetch(`http://127.0.0.1:${acPort}/api/deregister/telegram-bridge`, {
|
|
2857
|
+
method: "POST",
|
|
2858
|
+
signal: AbortSignal.timeout(3000),
|
|
2859
|
+
}).catch(() => {});
|
|
2860
|
+
}
|
|
2861
|
+
} catch {}
|
|
2840
2862
|
try {
|
|
2841
2863
|
const pf = telegramPidFile(projectId);
|
|
2842
2864
|
if (fs.existsSync(pf)) {
|
|
@@ -176,11 +176,14 @@ try {
|
|
|
176
176
|
bot_token: "123:abc",
|
|
177
177
|
chat_id: "-42",
|
|
178
178
|
agentchattr_url: "http://127.0.0.1:8301",
|
|
179
|
-
});
|
|
179
|
+
}, "testproject");
|
|
180
180
|
assert.match(toml13, /^\[telegram\]/);
|
|
181
181
|
assert.match(toml13, /bot_token = "123:abc"/);
|
|
182
182
|
assert.match(toml13, /chat_id = "-42"/);
|
|
183
183
|
assert.match(toml13, /agentchattr_url = "http:\/\/127\.0\.0\.1:8301"/);
|
|
184
|
+
// #404: cursor_file must be per-project so multiple bridges
|
|
185
|
+
// don't clobber each other's position.
|
|
186
|
+
assert.match(toml13, /cursor_file = ".*telegram-bridge-cursor-testproject\.json"/);
|
|
184
187
|
// Must NOT emit a separate [agentchattr] section — the bridge
|
|
185
188
|
// would silently ignore it.
|
|
186
189
|
assert.equal(toml13.includes("\n[agentchattr]\n"), false);
|
package/templates/CLAUDE.md
CHANGED
|
@@ -33,7 +33,8 @@ Branch naming (strict): `task/<issue-number>-<short-slug>`
|
|
|
33
33
|
|
|
34
34
|
## Communication Rules
|
|
35
35
|
|
|
36
|
-
- **
|
|
36
|
+
- **Always reply to the operator** — when the operator (sender: "user") addresses you in chat, you MUST reply via `chat_send`. The operator's terminal is invisible; if you don't `chat_send`, your response does not exist.
|
|
37
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
37
38
|
- **No status updates to Head** — Dev works silently until PR is ready
|
|
38
39
|
- **Strict routing**: Dev→Reviewer1/Reviewer2 (review) → Dev→Head (merge request) → Head→Dev (merged)
|
|
39
40
|
- **Post-merge silence**: Head sends ONE "merged" message. No further replies from anyone.
|
|
@@ -85,5 +85,7 @@ Head owns this file — do not edit it. Read it when you need context on the bat
|
|
|
85
85
|
- After BOTH Reviewer1 AND Reviewer2 approve → ONLY THEN message **@head** to request merge.
|
|
86
86
|
- Always include issue/PR numbers in messages
|
|
87
87
|
- Report blockers to @head immediately
|
|
88
|
+
- **Always reply to the operator**: when the operator (sender: "user") sends a message that mentions you or is addressed to you, you MUST reply via `chat_send`. If it's a question, answer it. If it's an instruction, confirm what you will do, then do it. If it's not actionable for your role, reply explaining that and suggest which agent should handle it. The operator's terminal is invisible — if you don't `chat_send`, your response does not exist.
|
|
89
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
88
90
|
- **Do NOT send ANY message to @head between assignment and merge request** — no acks, no status updates.
|
|
89
91
|
- **After merge confirmation from Head**: do NOT reply. The loop is COMPLETE — silence is required.
|
|
@@ -97,5 +97,7 @@ When the operator asks you in chat to start a task or batch:
|
|
|
97
97
|
- **ALWAYS @mention the next agent** — never @user or @human
|
|
98
98
|
- Route: you → @dev for task assignments. You do NOT message @reviewer1 or @reviewer2 directly.
|
|
99
99
|
- Include issue/PR numbers in all messages
|
|
100
|
+
- **Always reply to the operator**: when the operator (sender: "user") sends a message that mentions you or is addressed to you, you MUST reply via `chat_send`. If it's a question, answer it. If it's an instruction, confirm what you will do, then do it. If it's not actionable for your role, reply explaining that and suggest which agent should handle it. The operator's terminal is invisible — if you don't `chat_send`, your response does not exist.
|
|
101
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
100
102
|
- **Do NOT reply to acknowledgments** — if Dev says "on it" or similar, do NOT respond. Wait silently for the PR.
|
|
101
103
|
- **After merge**: send ONE message: "@dev PR #<number> merged. Issue #<number> closed." — no further replies needed.
|
|
@@ -101,5 +101,7 @@ Run this once at the start of each session.
|
|
|
101
101
|
- **After BLOCK**: send message to @head AND @dev — Head decides whether to reassign or close
|
|
102
102
|
- Always include PR number in messages
|
|
103
103
|
- Tag specific findings with file:line references
|
|
104
|
-
- **
|
|
104
|
+
- **Always reply to the operator**: when the operator (sender: "user") sends a message that mentions you or is addressed to you, you MUST reply via `chat_send`. If it's a question, answer it. If it's an instruction, confirm what you will do, then do it. If it's not actionable for your role, reply explaining that and suggest which agent should handle it. The operator's terminal is invisible — if you don't `chat_send`, your response does not exist.
|
|
105
|
+
- **No acknowledgment messages between agents** — don't send "on it", "noted", "standing by" to other agents. This rule does NOT apply to operator messages — always reply to the operator.
|
|
106
|
+
- Only send unsolicited messages when delivering a completed review verdict. But ALWAYS reply when the operator addresses you directly — even if the message is not a review request. The operator may be asking about your status, giving instructions, or testing connectivity.
|
|
105
107
|
- **After merge confirmation from Head**: do NOT reply. The loop is complete — no acknowledgment needed.
|