quadwork 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/{13xk0vgfbrcld.css → 0pfyuhd8ccue..css} +1 -1
- package/out/_next/static/chunks/{0jllnzexn48._.js → 0ud0uv.699had.js} +1 -1
- package/out/_next/static/chunks/{163_ddkdca5q4.js → 0zk4tzycn0w4g.js} +7 -7
- package/out/_not-found/__next._full.txt +2 -2
- package/out/_not-found/__next._head.txt +1 -1
- package/out/_not-found/__next._index.txt +2 -2
- package/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/out/_not-found/__next._not-found.txt +1 -1
- package/out/_not-found/__next._tree.txt +2 -2
- package/out/_not-found.html +1 -1
- package/out/_not-found.txt +2 -2
- package/out/app-shell/__next._full.txt +2 -2
- package/out/app-shell/__next._head.txt +1 -1
- package/out/app-shell/__next._index.txt +2 -2
- package/out/app-shell/__next._tree.txt +2 -2
- package/out/app-shell/__next.app-shell.__PAGE__.txt +1 -1
- package/out/app-shell/__next.app-shell.txt +1 -1
- package/out/app-shell.html +1 -1
- package/out/app-shell.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +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/_/queue/__next._full.txt +2 -2
- package/out/project/_/queue/__next._head.txt +1 -1
- package/out/project/_/queue/__next._index.txt +2 -2
- package/out/project/_/queue/__next._tree.txt +2 -2
- package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +1 -1
- package/out/project/_/queue/__next.project.$d$id.queue.txt +1 -1
- package/out/project/_/queue/__next.project.$d$id.txt +1 -1
- package/out/project/_/queue/__next.project.txt +1 -1
- package/out/project/_/queue.html +1 -1
- package/out/project/_/queue.txt +2 -2
- package/out/project/_.html +1 -1
- package/out/project/_.txt +3 -3
- package/out/settings/__next._full.txt +2 -2
- package/out/settings/__next._head.txt +1 -1
- package/out/settings/__next._index.txt +2 -2
- package/out/settings/__next._tree.txt +2 -2
- package/out/settings/__next.settings.__PAGE__.txt +1 -1
- package/out/settings/__next.settings.txt +1 -1
- package/out/settings.html +1 -1
- package/out/settings.txt +2 -2
- package/out/setup/__next._full.txt +2 -2
- package/out/setup/__next._head.txt +1 -1
- package/out/setup/__next._index.txt +2 -2
- package/out/setup/__next._tree.txt +2 -2
- package/out/setup/__next.setup.__PAGE__.txt +1 -1
- package/out/setup/__next.setup.txt +1 -1
- package/out/setup.html +1 -1
- package/out/setup.txt +2 -2
- package/package.json +1 -1
- package/server/index.js +22 -1
- package/server/routes.js +61 -5
- /package/out/_next/static/{MmPC1Rj12BOy4-HvMJjEX → vvtpLPTwziTD3klXH46MU}/_buildManifest.js +0 -0
- /package/out/_next/static/{MmPC1Rj12BOy4-HvMJjEX → vvtpLPTwziTD3klXH46MU}/_clientMiddlewareManifest.js +0 -0
- /package/out/_next/static/{MmPC1Rj12BOy4-HvMJjEX → vvtpLPTwziTD3klXH46MU}/_ssgManifest.js +0 -0
package/out/setup.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en" class="geist_mono_8d43a2aa-module__8Li5zG__variable h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/13xk0vgfbrcld.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0ze4gu236oq96.js"/><script src="/_next/static/chunks/0.bbxho1vnxin.js" async=""></script><script src="/_next/static/chunks/07lhk_q6pmm3r.js" async=""></script><script src="/_next/static/chunks/0oxv9vrvc17to.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0y2u-q0l2m67w.js" async=""></script><script src="/_next/static/chunks/0q4bm04c1jl_3.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/0py7102i226n5.js" async=""></script><meta name="next-size-adjust" content=""/><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.05o2q2p4kvnq_.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex flex-col"><div hidden=""><!--$--><!--/$--></div><header class="sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur" aria-hidden="true"></header><div class="flex flex-1 min-h-0"><button type="button" class="fixed top-14 left-2 z-30 lg:hidden w-10 h-10 flex items-center justify-center bg-bg-surface border border-border text-text-muted hover:text-accent"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M3 5h14M3 10h14M3 15h14"></path></svg></button><aside class="fixed inset-y-0 left-0 z-50 w-52 bg-bg-surface border-r border-border flex flex-col py-3 px-2 items-stretch overflow-y-auto transition-transform duration-200 ease-in-out lg:hidden -translate-x-full"><button type="button" class="self-end shrink-0 w-10 h-10 flex items-center justify-center text-text-muted hover:text-accent mb-1"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M5 5l10 10M15 5L5 15"></path></svg></button><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg><span class="text-xs">Home</span></a><div class="h-px bg-border my-2 "></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 "><a class="flex items-center gap-2 rounded-full transition-colors px-2 py-2 border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] rounded-sm" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg><span class="text-xs text-text-muted">New Project</span></a></div><div class="h-px bg-border my-2 "></div><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg><span class="text-xs">Settings</span></a></aside><aside class="hidden lg:flex shrink-0 h-full border-r border-border bg-bg-surface flex-col py-3 transition-[width] duration-200 ease-in-out overflow-hidden w-16 items-center"><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="h-px bg-border my-2 w-6 self-center"></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 items-center"><a class="flex items-center gap-2 rounded-full transition-colors w-10 h-10 justify-center border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="h-px bg-border my-2 w-6 self-center"></div><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a><div class="h-1"></div><button class="flex shrink-0 items-center justify-center w-10 h-10 rounded-sm border border-border text-text-muted hover:text-accent hover:border-accent/50 transition-colors self-center" title="Expand sidebar"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"></path></svg></button></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto"></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/0ze4gu236oq96.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[52368,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"LocaleProvider\"]\n3:I[43688,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[26704,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[22140,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[39756,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[37457,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n8:I[94810,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/0py7102i226n5.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\na:\"$Sreact.suspense\"\nd:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n11:I[68027,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/13xk0vgfbrcld.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"setup\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"setup\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/13xk0vgfbrcld.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex flex-col\",\"children\":[\"$\",\"$L2\",null,{\"children\":[[\"$\",\"$L3\",null,{}],[\"$\",\"$L4\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]]}]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L8\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0py7102i226n5.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@b\"}]}]]}],{},null,false,null]},null,false,\"$@c\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L10\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$11\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/13xk0vgfbrcld.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"MmPC1Rj12BOy4-HvMJjEX\"}\n"])</script><script>self.__next_f.push([1,"12:[]\nc:\"$W12\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\nb:null\n10:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.05o2q2p4kvnq_.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"3\",{}]]\n"])</script></body></html>
|
|
1
|
+
<!DOCTYPE html><html lang="en" class="geist_mono_8d43a2aa-module__8Li5zG__variable h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/0pfyuhd8ccue..css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0ze4gu236oq96.js"/><script src="/_next/static/chunks/0.bbxho1vnxin.js" async=""></script><script src="/_next/static/chunks/07lhk_q6pmm3r.js" async=""></script><script src="/_next/static/chunks/0oxv9vrvc17to.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0y2u-q0l2m67w.js" async=""></script><script src="/_next/static/chunks/0q4bm04c1jl_3.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><script src="/_next/static/chunks/0py7102i226n5.js" async=""></script><meta name="next-size-adjust" content=""/><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.05o2q2p4kvnq_.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex flex-col"><div hidden=""><!--$--><!--/$--></div><header class="sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur" aria-hidden="true"></header><div class="flex flex-1 min-h-0"><button type="button" class="fixed top-14 left-2 z-30 lg:hidden w-10 h-10 flex items-center justify-center bg-bg-surface border border-border text-text-muted hover:text-accent"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M3 5h14M3 10h14M3 15h14"></path></svg></button><aside class="fixed inset-y-0 left-0 z-50 w-52 bg-bg-surface border-r border-border flex flex-col py-3 px-2 items-stretch overflow-y-auto transition-transform duration-200 ease-in-out lg:hidden -translate-x-full"><button type="button" class="self-end shrink-0 w-10 h-10 flex items-center justify-center text-text-muted hover:text-accent mb-1"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M5 5l10 10M15 5L5 15"></path></svg></button><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg><span class="text-xs">Home</span></a><div class="h-px bg-border my-2 "></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 "><a class="flex items-center gap-2 rounded-full transition-colors px-2 py-2 border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] rounded-sm" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg><span class="text-xs text-text-muted">New Project</span></a></div><div class="h-px bg-border my-2 "></div><a class="flex items-center gap-2 rounded-sm transition-colors px-2 py-2 text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg><span class="text-xs">Settings</span></a></aside><aside class="hidden lg:flex shrink-0 h-full border-r border-border bg-bg-surface flex-col py-3 transition-[width] duration-200 ease-in-out overflow-hidden w-16 items-center"><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="h-px bg-border my-2 w-6 self-center"></div><div class="flex-1 flex flex-col gap-2 overflow-y-auto min-h-0 items-center"><a class="flex items-center gap-2 rounded-full transition-colors w-10 h-10 justify-center border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="h-px bg-border my-2 w-6 self-center"></div><a class="flex items-center gap-2 rounded-sm transition-colors w-10 h-10 justify-center self-center text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a><div class="h-1"></div><button class="flex shrink-0 items-center justify-center w-10 h-10 rounded-sm border border-border text-text-muted hover:text-accent hover:border-accent/50 transition-colors self-center" title="Expand sidebar"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"></path></svg></button></aside><main class="flex-1 min-w-0 overflow-auto"><div class="h-full overflow-y-auto"></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/0ze4gu236oq96.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[52368,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"LocaleProvider\"]\n3:I[43688,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[26704,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[22140,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[39756,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[37457,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n8:I[94810,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"/_next/static/chunks/0py7102i226n5.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\na:\"$Sreact.suspense\"\nd:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\n11:I[68027,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0pfyuhd8ccue..css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"setup\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"setup\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0pfyuhd8ccue..css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex flex-col\",\"children\":[\"$\",\"$L2\",null,{\"children\":[[\"$\",\"$L3\",null,{}],[\"$\",\"$L4\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]]}]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L8\",null,{}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0py7102i226n5.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@b\"}]}]]}],{},null,false,null]},null,false,\"$@c\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"$a\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L10\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$11\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0pfyuhd8ccue..css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"vvtpLPTwziTD3klXH46MU\"}\n"])</script><script>self.__next_f.push([1,"12:[]\nc:\"$W12\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/0q4bm04c1jl_3.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\nb:null\n10:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.05o2q2p4kvnq_.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"3\",{}]]\n"])</script></body></html>
|
package/out/setup.txt
CHANGED
|
@@ -11,9 +11,9 @@ a:"$Sreact.suspense"
|
|
|
11
11
|
d:I[97367,["/_next/static/chunks/0q4bm04c1jl_3.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"ViewportBoundary"]
|
|
12
12
|
f:I[97367,["/_next/static/chunks/0q4bm04c1jl_3.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"MetadataBoundary"]
|
|
13
13
|
11:I[68027,["/_next/static/chunks/0q4bm04c1jl_3.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default",1]
|
|
14
|
-
:HL["/_next/static/chunks/
|
|
14
|
+
:HL["/_next/static/chunks/0pfyuhd8ccue..css","style"]
|
|
15
15
|
:HL["/_next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
16
|
-
0:{"P":null,"c":["","setup"],"q":"","i":false,"f":[[["",{"children":["setup",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/
|
|
16
|
+
0:{"P":null,"c":["","setup"],"q":"","i":false,"f":[[["",{"children":["setup",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0pfyuhd8ccue..css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0q4bm04c1jl_3.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"geist_mono_8d43a2aa-module__8Li5zG__variable h-full","children":["$","body",null,{"className":"h-full flex flex-col","children":["$","$L2",null,{"children":[["$","$L3",null,{}],["$","$L4",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L5",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]]}]]}]}]}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","$L8",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0py7102i226n5.js","async":true,"nonce":"$undefined"}]],["$","$L9",null,{"children":["$","$a",null,{"name":"Next.MetadataOutlet","children":"$@b"}]}]]}],{},null,false,null]},null,false,"$@c"]},null,false,null],["$","$1","h",{"children":[null,["$","$Ld",null,{"children":"$Le"}],["$","div",null,{"hidden":true,"children":["$","$Lf",null,{"children":["$","$a",null,{"name":"Next.Metadata","children":"$L10"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$11",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0pfyuhd8ccue..css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"vvtpLPTwziTD3klXH46MU"}
|
|
17
17
|
12:[]
|
|
18
18
|
c:"$W12"
|
|
19
19
|
e:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -1183,6 +1183,13 @@ app.get("/api/triggers", (_req, res) => {
|
|
|
1183
1183
|
res.json(result);
|
|
1184
1184
|
});
|
|
1185
1185
|
|
|
1186
|
+
// #812: a parked (idle) project gets no trigger starts/pulses. Read
|
|
1187
|
+
// the live config so a config-write that sets idle takes effect at once.
|
|
1188
|
+
function isProjectIdleId(projectId) {
|
|
1189
|
+
try { return !!readConfig().projects?.find((p) => p.id === projectId)?.idle; }
|
|
1190
|
+
catch { return false; }
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1186
1193
|
function stopTrigger(project) {
|
|
1187
1194
|
const existing = triggers.get(project);
|
|
1188
1195
|
if (existing) {
|
|
@@ -1194,6 +1201,11 @@ function stopTrigger(project) {
|
|
|
1194
1201
|
|
|
1195
1202
|
app.post("/api/triggers/:project/start", (req, res) => {
|
|
1196
1203
|
const { project } = req.params;
|
|
1204
|
+
// #812: refuse to start a trigger for a parked (idle) project — no
|
|
1205
|
+
// timer created, no agents pulsed. Toggle the project off idle first.
|
|
1206
|
+
if (isProjectIdleId(project)) {
|
|
1207
|
+
return res.json({ ok: false, idle: true, enabled: false });
|
|
1208
|
+
}
|
|
1197
1209
|
// #418 / quadwork#306: sendImmediately was an always-true
|
|
1198
1210
|
// send-and-start flag from the original #210 button; operators
|
|
1199
1211
|
// asked for a pure scheduler (the button is now just "Start
|
|
@@ -1265,6 +1277,10 @@ app.post("/api/triggers/:project/stop", (req, res) => {
|
|
|
1265
1277
|
|
|
1266
1278
|
app.post("/api/triggers/:project/send-now", (req, res) => {
|
|
1267
1279
|
const { project } = req.params;
|
|
1280
|
+
// #812: parked (idle) project — do not pulse agents.
|
|
1281
|
+
if (isProjectIdleId(project)) {
|
|
1282
|
+
return res.json({ ok: false, idle: true, sent: false });
|
|
1283
|
+
}
|
|
1268
1284
|
sendTriggerMessage(project);
|
|
1269
1285
|
res.json({ ok: true, sent: true });
|
|
1270
1286
|
});
|
|
@@ -1593,7 +1609,11 @@ function syncTriggersFromConfig() {
|
|
|
1593
1609
|
|
|
1594
1610
|
if (cfg.projects) {
|
|
1595
1611
|
for (const project of cfg.projects) {
|
|
1596
|
-
|
|
1612
|
+
// #812: idle (parked) projects get no trigger. Excluding them from
|
|
1613
|
+
// activeIds also makes the cleanup loop below clear any timer they
|
|
1614
|
+
// had — so writing idle:true via PUT /api/config (which calls this)
|
|
1615
|
+
// stops a running trigger with no separate stop call.
|
|
1616
|
+
if (project.trigger_enabled && !project.idle) {
|
|
1597
1617
|
activeIds.add(project.id);
|
|
1598
1618
|
const ms = (project.trigger_interval || 30) * 60 * 1000;
|
|
1599
1619
|
const existing = triggers.get(project.id);
|
|
@@ -1631,6 +1651,7 @@ async function autoStopPollingTick() {
|
|
|
1631
1651
|
if (!cfg.projects) return;
|
|
1632
1652
|
|
|
1633
1653
|
for (const project of cfg.projects) {
|
|
1654
|
+
if (project.idle) continue; // #812: parked project — no batch-progress polling
|
|
1634
1655
|
const hasTriggerAuto = project.trigger_auto && triggers.has(project.id);
|
|
1635
1656
|
const hasBridgeAuto = project.telegram_auto || project.discord_auto;
|
|
1636
1657
|
if (!hasTriggerAuto && !hasBridgeAuto) continue;
|
package/server/routes.js
CHANGED
|
@@ -120,9 +120,17 @@ function _ghEnqueueRefresh(cacheKey, ghArgs, transform) {
|
|
|
120
120
|
_ghDrainQueue();
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
function cachedGhEndpoint(cacheKey, ghArgs, res, { transform } = {}) {
|
|
124
|
-
const ttl = adaptiveTTL(GH_ENDPOINT_CACHE_TTL);
|
|
123
|
+
function cachedGhEndpoint(cacheKey, ghArgs, res, { transform, idle } = {}) {
|
|
125
124
|
const cached = _ghEndpointCache.get(cacheKey);
|
|
125
|
+
// #812: a parked (idle) project must never initiate a gh fetch. Serve
|
|
126
|
+
// whatever we last cached, or an empty list — never call gh. The list
|
|
127
|
+
// endpoints return a bare array (client contract), so signal idle via a
|
|
128
|
+
// response header rather than mutating the JSON shape.
|
|
129
|
+
if (idle) {
|
|
130
|
+
res.set("X-QuadWork-Idle", "1");
|
|
131
|
+
return res.json(cached ? cached.data : []);
|
|
132
|
+
}
|
|
133
|
+
const ttl = adaptiveTTL(GH_ENDPOINT_CACHE_TTL);
|
|
126
134
|
if (cached && Date.now() - cached.ts < ttl) {
|
|
127
135
|
return res.json(cached.stale ? { ...cached.data, _stale: true } : cached.data);
|
|
128
136
|
}
|
|
@@ -850,6 +858,20 @@ router.get("/api/projects", async (req, res) => {
|
|
|
850
858
|
async function fetchProjectGhData(p) {
|
|
851
859
|
let openPrs = 0;
|
|
852
860
|
let lastActivity = null;
|
|
861
|
+
// #812: parked (idle) project — no gh calls; return zero/last-known metadata.
|
|
862
|
+
if (p.idle) {
|
|
863
|
+
const hasAgentsIdle = p.agents && Object.keys(p.agents).length > 0;
|
|
864
|
+
return {
|
|
865
|
+
id: p.id,
|
|
866
|
+
name: p.name,
|
|
867
|
+
repo: p.repo,
|
|
868
|
+
agentCount: hasAgentsIdle ? Object.keys(p.agents).length : 0,
|
|
869
|
+
openPrs: 0,
|
|
870
|
+
state: "idle",
|
|
871
|
+
lastActivity: null,
|
|
872
|
+
_idle: true,
|
|
873
|
+
};
|
|
874
|
+
}
|
|
853
875
|
if (REPO_RE.test(p.repo)) {
|
|
854
876
|
try {
|
|
855
877
|
const [prs, recentPrs] = await Promise.allSettled([
|
|
@@ -937,6 +959,20 @@ function getRepo(projectId) {
|
|
|
937
959
|
}
|
|
938
960
|
}
|
|
939
961
|
|
|
962
|
+
// #812: per-project Idle toggle. When a project is idle, QuadWork must
|
|
963
|
+
// initiate ZERO project-specific GitHub/API activity for it. Callers
|
|
964
|
+
// (board fetch, per-endpoint handlers, batch-progress, /api/projects)
|
|
965
|
+
// check this before issuing any gh call.
|
|
966
|
+
function isProjectIdle(projectId) {
|
|
967
|
+
if (!projectId) return false;
|
|
968
|
+
try {
|
|
969
|
+
const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
|
|
970
|
+
return !!cfg.projects?.find((p) => p.id === projectId)?.idle;
|
|
971
|
+
} catch {
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
940
976
|
// ─── #703: Batched GraphQL layer ──────────────────────────────────────────
|
|
941
977
|
// Instead of spawning individual `gh issue list` / `gh pr list` subprocesses
|
|
942
978
|
// per project per endpoint, we fetch ALL configured projects' GitHub data in
|
|
@@ -959,7 +995,7 @@ async function fetchAllProjectsGraphQL() {
|
|
|
959
995
|
} catch {
|
|
960
996
|
return null;
|
|
961
997
|
}
|
|
962
|
-
const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo));
|
|
998
|
+
const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo) && !p.idle); // #812: skip idle (parked) projects
|
|
963
999
|
if (projects.length === 0) return null;
|
|
964
1000
|
|
|
965
1001
|
// Build aliased repository fields — one per project.
|
|
@@ -1238,7 +1274,7 @@ router.get("/api/github/all", async (req, res) => {
|
|
|
1238
1274
|
const anyStale = (() => {
|
|
1239
1275
|
let cfg;
|
|
1240
1276
|
try { cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); } catch { return true; }
|
|
1241
|
-
const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo));
|
|
1277
|
+
const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo) && !p.idle); // #812: skip idle (parked) projects
|
|
1242
1278
|
for (const p of projects) {
|
|
1243
1279
|
const cached = _graphqlCache.get(p.repo);
|
|
1244
1280
|
if (!cached || Date.now() - cached.ts > adaptiveTTL(GRAPHQL_CACHE_TTL)) return true;
|
|
@@ -1250,13 +1286,21 @@ router.get("/api/github/all", async (req, res) => {
|
|
|
1250
1286
|
// Build response.
|
|
1251
1287
|
let cfg;
|
|
1252
1288
|
try { cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); } catch { return res.status(500).json({ error: "Config unreadable" }); }
|
|
1253
|
-
const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo));
|
|
1289
|
+
const projects = (cfg.projects || []).filter((p) => p.repo && REPO_RE.test(p.repo)); // #812: include idle projects — served stale below, never fetched
|
|
1254
1290
|
|
|
1255
1291
|
const result = {};
|
|
1256
1292
|
const fallbackNeeded = [];
|
|
1257
1293
|
for (const p of projects) {
|
|
1258
1294
|
if (projectFilter && p.id !== projectFilter) continue;
|
|
1259
1295
|
const cached = _graphqlCache.get(p.repo);
|
|
1296
|
+
// #812: idle (parked) project — serve last-known data flagged _idle,
|
|
1297
|
+
// never trigger a fetch or fall back to gh.
|
|
1298
|
+
if (p.idle) {
|
|
1299
|
+
result[p.id] = cached
|
|
1300
|
+
? { issues: cached.issues, prs: cached.prs, closedIssues: cached.closedIssues, mergedPrs: cached.mergedPrs, _idle: true }
|
|
1301
|
+
: { issues: [], prs: [], closedIssues: [], mergedPrs: [], _idle: true };
|
|
1302
|
+
continue;
|
|
1303
|
+
}
|
|
1260
1304
|
if (cached) {
|
|
1261
1305
|
result[p.id] = {
|
|
1262
1306
|
issues: cached.issues,
|
|
@@ -1320,6 +1364,7 @@ router.get("/api/github/issues", (req, res) => {
|
|
|
1320
1364
|
`issues:${repo}`,
|
|
1321
1365
|
["issue", "list", "-R", repo, "--json", "number,title,state,assignees,labels,createdAt,url", "--limit", "50"],
|
|
1322
1366
|
res,
|
|
1367
|
+
{ idle: isProjectIdle(req.query.project || "") },
|
|
1323
1368
|
);
|
|
1324
1369
|
});
|
|
1325
1370
|
|
|
@@ -1330,6 +1375,7 @@ router.get("/api/github/prs", (req, res) => {
|
|
|
1330
1375
|
`prs:${repo}`,
|
|
1331
1376
|
["pr", "list", "-R", repo, "--json", "number,title,state,author,assignees,reviewDecision,reviews,statusCheckRollup,url,createdAt", "--limit", "50"],
|
|
1332
1377
|
res,
|
|
1378
|
+
{ idle: isProjectIdle(req.query.project || "") },
|
|
1333
1379
|
);
|
|
1334
1380
|
});
|
|
1335
1381
|
|
|
@@ -1351,6 +1397,7 @@ router.get("/api/github/closed-issues", (req, res) => {
|
|
|
1351
1397
|
["issue", "list", "-R", repo, "--state", "closed", "--json", "number,title,state,url,closedAt", "--limit", String(RECENT_FETCH_LIMIT)],
|
|
1352
1398
|
res,
|
|
1353
1399
|
{
|
|
1400
|
+
idle: isProjectIdle(req.query.project || ""),
|
|
1354
1401
|
transform: (items) =>
|
|
1355
1402
|
Array.isArray(items)
|
|
1356
1403
|
? items
|
|
@@ -1378,6 +1425,7 @@ router.get("/api/github/merged-prs", (req, res) => {
|
|
|
1378
1425
|
["pr", "list", "-R", repo, "--state", "merged", "--json", "number,title,state,url,mergedAt,author", "--limit", String(RECENT_FETCH_LIMIT)],
|
|
1379
1426
|
res,
|
|
1380
1427
|
{
|
|
1428
|
+
idle: isProjectIdle(req.query.project || ""),
|
|
1381
1429
|
transform: (items) =>
|
|
1382
1430
|
Array.isArray(items)
|
|
1383
1431
|
? items
|
|
@@ -1803,6 +1851,14 @@ router.get("/api/batch-progress", async (req, res) => {
|
|
|
1803
1851
|
if (!projectId) return res.status(400).json({ error: "Missing project" });
|
|
1804
1852
|
|
|
1805
1853
|
const cached = _batchProgressCache.get(projectId);
|
|
1854
|
+
// #812: parked (idle) project — never run batch-progress gh/GraphQL calls,
|
|
1855
|
+
// and ALWAYS flag the payload _idle (even on a fresh cache hit), so the
|
|
1856
|
+
// endpoint contract is consistent regardless of cache freshness. This must
|
|
1857
|
+
// precede the fresh-cache and rate-limit returns below.
|
|
1858
|
+
if (isProjectIdle(projectId)) {
|
|
1859
|
+
if (cached) return res.json({ ...cached.data, _idle: true });
|
|
1860
|
+
return res.json({ batch_number: null, items: [], summary: "", complete: false, _idle: true });
|
|
1861
|
+
}
|
|
1806
1862
|
const batchTTL = adaptiveTTL(BATCH_PROGRESS_TTL_MS);
|
|
1807
1863
|
if (cached && Date.now() - cached.ts < batchTTL) {
|
|
1808
1864
|
return res.json(cached.data);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|