quadwork 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/bin/quadwork.js +128 -0
  2. package/out/404.html +1 -1
  3. package/out/__next.__PAGE__.txt +3 -3
  4. package/out/__next._full.txt +12 -12
  5. package/out/__next._head.txt +4 -4
  6. package/out/__next._index.txt +6 -6
  7. package/out/__next._tree.txt +2 -2
  8. package/out/_next/static/chunks/{18cmux34jwe.p.js → 0-7v31f-nsgw-.js} +1 -1
  9. package/out/_next/static/chunks/{05ok82hwk0x-c.js → 04_t39bv8y9pe.js} +1 -1
  10. package/out/_next/static/chunks/084lff9v4p_vh.js +1 -0
  11. package/out/_next/static/chunks/0ccoe1hsu70ql.css +2 -0
  12. package/out/_next/static/chunks/0e.ktwt1nyj...js +1 -0
  13. package/out/_next/static/chunks/{0zqyw6q.jp~1i.js → 0m83k84.midd1.js} +14 -13
  14. package/out/_not-found/__next._full.txt +11 -11
  15. package/out/_not-found/__next._head.txt +4 -4
  16. package/out/_not-found/__next._index.txt +6 -6
  17. package/out/_not-found/__next._not-found.__PAGE__.txt +2 -2
  18. package/out/_not-found/__next._not-found.txt +3 -3
  19. package/out/_not-found/__next._tree.txt +2 -2
  20. package/out/_not-found.html +1 -1
  21. package/out/_not-found.txt +11 -11
  22. package/out/app-shell/__next._full.txt +11 -11
  23. package/out/app-shell/__next._head.txt +4 -4
  24. package/out/app-shell/__next._index.txt +6 -6
  25. package/out/app-shell/__next._tree.txt +2 -2
  26. package/out/app-shell/__next.app-shell.__PAGE__.txt +2 -2
  27. package/out/app-shell/__next.app-shell.txt +3 -3
  28. package/out/app-shell.html +1 -1
  29. package/out/app-shell.txt +11 -11
  30. package/out/index.html +1 -1
  31. package/out/index.txt +12 -12
  32. package/out/project/_/__next._full.txt +12 -12
  33. package/out/project/_/__next._head.txt +4 -4
  34. package/out/project/_/__next._index.txt +6 -6
  35. package/out/project/_/__next._tree.txt +2 -2
  36. package/out/project/_/__next.project.$d$id.__PAGE__.txt +3 -3
  37. package/out/project/_/__next.project.$d$id.txt +3 -3
  38. package/out/project/_/__next.project.txt +3 -3
  39. package/out/project/_/memory/__next._full.txt +12 -12
  40. package/out/project/_/memory/__next._head.txt +4 -4
  41. package/out/project/_/memory/__next._index.txt +6 -6
  42. package/out/project/_/memory/__next._tree.txt +2 -2
  43. package/out/project/_/memory/__next.project.$d$id.memory.__PAGE__.txt +3 -3
  44. package/out/project/_/memory/__next.project.$d$id.memory.txt +3 -3
  45. package/out/project/_/memory/__next.project.$d$id.txt +3 -3
  46. package/out/project/_/memory/__next.project.txt +3 -3
  47. package/out/project/_/memory.html +1 -1
  48. package/out/project/_/memory.txt +12 -12
  49. package/out/project/_/queue/__next._full.txt +12 -12
  50. package/out/project/_/queue/__next._head.txt +4 -4
  51. package/out/project/_/queue/__next._index.txt +6 -6
  52. package/out/project/_/queue/__next._tree.txt +2 -2
  53. package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +3 -3
  54. package/out/project/_/queue/__next.project.$d$id.queue.txt +3 -3
  55. package/out/project/_/queue/__next.project.$d$id.txt +3 -3
  56. package/out/project/_/queue/__next.project.txt +3 -3
  57. package/out/project/_/queue.html +1 -1
  58. package/out/project/_/queue.txt +12 -12
  59. package/out/project/_.html +1 -1
  60. package/out/project/_.txt +12 -12
  61. package/out/settings/__next._full.txt +12 -12
  62. package/out/settings/__next._head.txt +4 -4
  63. package/out/settings/__next._index.txt +6 -6
  64. package/out/settings/__next._tree.txt +2 -2
  65. package/out/settings/__next.settings.__PAGE__.txt +3 -3
  66. package/out/settings/__next.settings.txt +3 -3
  67. package/out/settings.html +1 -1
  68. package/out/settings.txt +12 -12
  69. package/out/setup/__next._full.txt +12 -12
  70. package/out/setup/__next._head.txt +4 -4
  71. package/out/setup/__next._index.txt +6 -6
  72. package/out/setup/__next._tree.txt +2 -2
  73. package/out/setup/__next.setup.__PAGE__.txt +3 -3
  74. package/out/setup/__next.setup.txt +3 -3
  75. package/out/setup.html +1 -1
  76. package/out/setup.txt +12 -12
  77. package/package.json +1 -1
  78. package/server/index.js +31 -4
  79. package/server/queue-watcher.js +47 -10
  80. package/server/queue-watcher.test.js +64 -0
  81. package/server/routes.batchProgress.test.js +94 -0
  82. package/server/routes.js +398 -23
  83. package/server/routes.parseActiveBatch.test.js +88 -0
  84. package/server/routes.telegramBridge.test.js +95 -0
  85. package/templates/CLAUDE.md +0 -1
  86. package/templates/seeds/head.AGENTS.md +1 -1
  87. package/out/_next/static/chunks/006g3lco-9xqf.js +0 -1
  88. package/out/_next/static/chunks/035rt-n0oid7d.js +0 -1
  89. package/out/_next/static/chunks/0u~7e4fgf-u06.css +0 -2
  90. /package/out/_next/static/{6uvV3nUfwr_t_JKrZJSP8 → wxXtT0v8ALxniu3OdJwt5}/_buildManifest.js +0 -0
  91. /package/out/_next/static/{6uvV3nUfwr_t_JKrZJSP8 → wxXtT0v8ALxniu3OdJwt5}/_clientMiddlewareManifest.js +0 -0
  92. /package/out/_next/static/{6uvV3nUfwr_t_JKrZJSP8 → wxXtT0v8ALxniu3OdJwt5}/_ssgManifest.js +0 -0
@@ -1,3 +1,3 @@
1
- :HL["/_next/static/chunks/0u~7e4fgf-u06.css","style"]
1
+ :HL["/_next/static/chunks/0ccoe1hsu70ql.css","style"]
2
2
  :HL["/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
3
- 0:{"tree":{"name":"","param":null,"prefetchHints":16,"slots":{"children":{"name":"setup","param":null,"prefetchHints":0,"slots":{"children":{"name":"__PAGE__","param":null,"prefetchHints":0,"slots":null}}}}},"staleTime":300,"buildId":"6uvV3nUfwr_t_JKrZJSP8"}
3
+ 0:{"tree":{"name":"","param":null,"prefetchHints":16,"slots":{"children":{"name":"setup","param":null,"prefetchHints":0,"slots":{"children":{"name":"__PAGE__","param":null,"prefetchHints":0,"slots":null}}}}},"staleTime":300,"buildId":"wxXtT0v8ALxniu3OdJwt5"}
@@ -1,6 +1,6 @@
1
1
  1:"$Sreact.fragment"
2
- 2:I[64618,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js","/_next/static/chunks/035rt-n0oid7d.js"],"default"]
3
- 3:I[11717,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"OutletBoundary"]
2
+ 2:I[64618,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js","/_next/static/chunks/084lff9v4p_vh.js"],"default"]
3
+ 3:I[11717,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"OutletBoundary"]
4
4
  4:"$Sreact.suspense"
5
- 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/035rt-n0oid7d.js","async":true}]],["$","$L3",null,{"children":["$","$4",null,{"name":"Next.MetadataOutlet","children":"$@5"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"6uvV3nUfwr_t_JKrZJSP8"}
5
+ 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/084lff9v4p_vh.js","async":true}]],["$","$L3",null,{"children":["$","$4",null,{"name":"Next.MetadataOutlet","children":"$@5"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"wxXtT0v8ALxniu3OdJwt5"}
6
6
  5:null
@@ -1,5 +1,5 @@
1
1
  1:"$Sreact.fragment"
2
- 2:I[12527,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
3
- 3:I[59763,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
2
+ 2:I[12527,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
3
+ 3:I[59763,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.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":"6uvV3nUfwr_t_JKrZJSP8"}
5
+ 0:{"rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"isPartial":false,"staleTime":300,"varyParams":"$W4","buildId":"wxXtT0v8ALxniu3OdJwt5"}
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/0u~7e4fgf-u06.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/05ok82hwk0x-c.js" async=""></script><script src="/_next/static/chunks/0ox7p_szjhn69.js" async=""></script><script src="/_next/static/chunks/035rt-n0oid7d.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"><div class="flex items-center gap-3 min-w-0"><a class="text-sm font-bold text-white hover:text-blue-400 shrink-0" href="/">QuadWork</a><span class="hidden sm:inline text-neutral-600">|</span><span class="hidden sm:inline text-[13px] text-neutral-400 truncate">Your AI dev team while you<!-- --> <span class="text-neutral-200"></span><span class="ml-0.5 inline-block w-[1px] h-[12px] align-middle bg-neutral-400 animate-qw-blink"></span></span></div><div class="flex items-center gap-3 shrink-0"><button type="button" aria-label="About QuadWork" class="rounded p-1 text-neutral-400 hover:bg-white/5 hover:text-white"><svg width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="10" cy="10" r="8"></circle><path d="M10 9v5" stroke-linecap="round"></path><circle cx="10" cy="6.5" r="0.8" fill="currentColor"></circle></svg></button><a href="https://github.com/realproject7/quadwork" target="_blank" rel="noopener noreferrer" class="text-[12px] text-neutral-400 hover:text-white">QuadWork github</a></div></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 &amp; 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/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n3:I[86081,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n4:I[12527,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n5:I[59763,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\"]\n6:I[64618,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\",\"/_next/static/chunks/035rt-n0oid7d.js\"],\"default\"]\n7:I[11717,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"OutletBoundary\"]\n8:\"$Sreact.suspense\"\nb:I[11717,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"ViewportBoundary\"]\nd:I[11717,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"MetadataBoundary\"]\nf:I[92243,[\"/_next/static/chunks/05ok82hwk0x-c.js\",\"/_next/static/chunks/0ox7p_szjhn69.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0u~7e4fgf-u06.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/0u~7e4fgf-u06.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/05ok82hwk0x-c.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/035rt-n0oid7d.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/0u~7e4fgf-u06.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"6uvV3nUfwr_t_JKrZJSP8\"}\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/05ok82hwk0x-c.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/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 &amp; 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\":\"wxXtT0v8ALxniu3OdJwt5\"}\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>
package/out/setup.txt CHANGED
@@ -1,20 +1,20 @@
1
1
  1:"$Sreact.fragment"
2
- 2:I[34852,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
3
- 3:I[86081,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
4
- 4:I[12527,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
5
- 5:I[59763,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
6
- 6:I[64618,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js","/_next/static/chunks/035rt-n0oid7d.js"],"default"]
7
- 7:I[11717,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"OutletBoundary"]
2
+ 2:I[34852,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
3
+ 3:I[86081,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
4
+ 4:I[12527,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
5
+ 5:I[59763,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default"]
6
+ 6:I[64618,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js","/_next/static/chunks/084lff9v4p_vh.js"],"default"]
7
+ 7:I[11717,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"OutletBoundary"]
8
8
  8:"$Sreact.suspense"
9
- b:I[11717,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"ViewportBoundary"]
10
- d:I[11717,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"MetadataBoundary"]
11
- f:I[92243,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default",1]
12
- :HL["/_next/static/chunks/0u~7e4fgf-u06.css","style"]
9
+ b:I[11717,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"ViewportBoundary"]
10
+ d:I[11717,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"MetadataBoundary"]
11
+ f:I[92243,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.js"],"default",1]
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/0u~7e4fgf-u06.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/05ok82hwk0x-c.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/035rt-n0oid7d.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/0u~7e4fgf-u06.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"6uvV3nUfwr_t_JKrZJSP8"}
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/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":"wxXtT0v8ALxniu3OdJwt5"}
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[80070,["/_next/static/chunks/05ok82hwk0x-c.js","/_next/static/chunks/0ox7p_szjhn69.js"],"IconMark"]
18
+ 11:I[80070,["/_next/static/chunks/04_t39bv8y9pe.js","/_next/static/chunks/0ox7p_szjhn69.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quadwork",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "Unified dashboard for multi-agent coding teams — 4 AI agents, one terminal",
5
5
  "bin": {
6
6
  "quadwork": "./bin/quadwork.js"
package/server/index.js CHANGED
@@ -312,6 +312,32 @@ async function buildAgentArgs(projectId, agentId) {
312
312
  if (flags) args.push(...flags);
313
313
  }
314
314
 
315
+ // #343: per-agent model + reasoning effort overrides. Persist in
316
+ // project.agents[agentId].{model,reasoning_effort} via the
317
+ // dashboard Agent Models widget. When unset, fall back to the
318
+ // CLI's own default so existing projects without overrides keep
319
+ // their current behavior.
320
+ //
321
+ // Codex: -c model="<slug>" / -c model_reasoning_effort="<level>"
322
+ // reasoning levels: minimal | low | medium | high (xhigh is
323
+ // deliberately NOT offered — it's the capacity-failure hot
324
+ // spot #343 was filed for).
325
+ // Claude: --model <slug>
326
+ // reasoning_effort is not wired for Claude — Anthropic's CLI
327
+ // doesn't expose an equivalent flag.
328
+ if (cliBase === "codex") {
329
+ if (agentCfg.model && typeof agentCfg.model === "string") {
330
+ args.push("-c", `model="${agentCfg.model}"`);
331
+ }
332
+ if (agentCfg.reasoning_effort && typeof agentCfg.reasoning_effort === "string") {
333
+ args.push("-c", `model_reasoning_effort="${agentCfg.reasoning_effort}"`);
334
+ }
335
+ } else if (cliBase === "claude") {
336
+ if (agentCfg.model && typeof agentCfg.model === "string") {
337
+ args.push("--model", agentCfg.model);
338
+ }
339
+ }
340
+
315
341
  // MCP config injection
316
342
  const mcpHttpPort = project.mcp_http_port;
317
343
  const token = project.agentchattr_token;
@@ -1205,10 +1231,11 @@ function stopTrigger(project) {
1205
1231
  app.post("/api/triggers/:project/start", (req, res) => {
1206
1232
  const { project } = req.params;
1207
1233
  // #418 / quadwork#306: sendImmediately was an always-true
1208
- // "Send Message and Start Trigger" flag from #210; operators
1209
- // asked for a pure scheduler ("Start Trigger" wait for the
1210
- // first interval). The field is ignored here; the send-now
1211
- // endpoint below still exists for the explicit one-shot path.
1234
+ // send-and-start flag from the original #210 button; operators
1235
+ // asked for a pure scheduler (the button is now just "Start
1236
+ // Trigger" — wait for the first interval). The field is
1237
+ // ignored here; the send-now endpoint below still exists for
1238
+ // the explicit one-shot path.
1212
1239
  const { interval, duration, message } = req.body || {};
1213
1240
  const ms = (interval || 30) * 60 * 1000;
1214
1241
  const durationMs = duration ? duration * 60 * 1000 : 0; // duration in minutes, 0 = indefinite
@@ -11,8 +11,19 @@
11
11
  * Reference: /Users/cho/Projects/agentchattr/wrapper.py lines 438-541
12
12
  * (`_queue_watcher`). Polling (not fs.watch) is intentional: matches
13
13
  * wrapper.py's behavior and avoids the cross-platform fs.watch
14
- * footguns. The role/rules/identity-hint additions from wrapper.py
15
- * lines 501-528 are intentionally out of scope for v1 per the issue.
14
+ * footguns.
15
+ *
16
+ * #342 / quadwork#342: the v1 prompt intentionally omitted the
17
+ * identity hints from wrapper.py lines 501-528, which broke
18
+ * Claude Code agent sessions. Claude's default self-concept is
19
+ * `@claude`, so a bare `mcp read #general - you were mentioned`
20
+ * causes chat_read(sender: "claude") and a filter on `@claude`
21
+ * mentions — both wrong when the agent is actually @dev /
22
+ * @reviewerN. Codex doesn't trip the same way because its init
23
+ * path already claims identity. The fix here is to scope the
24
+ * wrapper.py additions to identity only: the injected prompt
25
+ * now explicitly names the agent slug and tells the agent which
26
+ * sender to use on chat_read and which mentions to look for.
16
27
  */
17
28
 
18
29
  const fs = require("fs");
@@ -20,6 +31,38 @@ const path = require("path");
20
31
 
21
32
  const POLL_INTERVAL_MS = 1000;
22
33
 
34
+ /**
35
+ * Pure helper: build the injected prompt text for a given agent
36
+ * slug + trigger shape. Exported so it can be unit-tested without
37
+ * a PTY or a filesystem queue. Priority matches the tick() call
38
+ * site below: customPrompt > jobId > channel.
39
+ *
40
+ * agentName is expected to be the registered agent slug such as
41
+ * `dev`, `head`, `reviewer1`, `reviewer2`. The helper does not
42
+ * validate — upstream already controls who may register.
43
+ */
44
+ function buildInjectionPrompt(agentName, { channel, jobId, customPrompt } = {}) {
45
+ if (customPrompt && typeof customPrompt === "string" && customPrompt.trim()) {
46
+ // Operator-supplied prompts already control the identity
47
+ // wording; leave them alone.
48
+ return customPrompt.trim();
49
+ }
50
+ if (jobId) {
51
+ return (
52
+ `You are @${agentName} in this AgentChattr instance. ` +
53
+ `mcp read job_id=${jobId} with sender: "${agentName}" — ` +
54
+ `you (@${agentName}) were mentioned in a job thread, take appropriate action.`
55
+ );
56
+ }
57
+ const ch = channel || "general";
58
+ return (
59
+ `You are @${agentName} in this AgentChattr instance. ` +
60
+ `mcp read #${ch} with sender: "${agentName}" — ` +
61
+ `look for @${agentName} mentions (NOT @claude). ` +
62
+ `You were mentioned, take appropriate action.`
63
+ );
64
+ }
65
+
23
66
  /**
24
67
  * Start polling `{dataDir}/{agentName}_queue.jsonl`. When non-empty,
25
68
  * read all lines, truncate the file (atomic-ish claim — same race the
@@ -78,14 +121,7 @@ function startQueueWatcher(dataDir, agentName, ptyTerm) {
78
121
  }
79
122
  if (!hasTrigger) return;
80
123
 
81
- let prompt;
82
- if (customPrompt) {
83
- prompt = customPrompt;
84
- } else if (jobId) {
85
- prompt = `mcp read job_id=${jobId} - you were mentioned in a job thread, take appropriate action`;
86
- } else {
87
- prompt = `mcp read #${channel} - you were mentioned, take appropriate action`;
88
- }
124
+ const prompt = buildInjectionPrompt(agentName, { channel, jobId, customPrompt });
89
125
 
90
126
  // Flatten newlines: multi-line writes trigger paste detection in
91
127
  // Claude Code (shows "[Pasted text +N]") and can break injection
@@ -122,4 +158,5 @@ function stopQueueWatcher(handle) {
122
158
  module.exports = {
123
159
  startQueueWatcher,
124
160
  stopQueueWatcher,
161
+ buildInjectionPrompt,
125
162
  };
@@ -0,0 +1,64 @@
1
+ // #342 / quadwork#342: unit test for the identity-aware prompt
2
+ // builder. No test runner is wired up in this repo, so this file
3
+ // is a plain node:assert script — run it with `node server/queue-watcher.test.js`
4
+ // and it exits non-zero on any failure.
5
+
6
+ const assert = require("node:assert/strict");
7
+ const { buildInjectionPrompt } = require("./queue-watcher");
8
+
9
+ const DEFAULT_AGENT_SLUGS = ["dev", "head", "reviewer1", "reviewer2"];
10
+
11
+ // 1) Channel prompt — each of the 4 default slugs must:
12
+ // - name the agent with @<slug>
13
+ // - pass sender: "<slug>" explicitly
14
+ // - tell the agent to look for @<slug> mentions (NOT @claude)
15
+ for (const slug of DEFAULT_AGENT_SLUGS) {
16
+ const p = buildInjectionPrompt(slug, { channel: "general" });
17
+ assert.match(p, new RegExp(`You are @${slug} `), `channel: names @${slug}`);
18
+ assert.match(p, new RegExp(`sender: "${slug}"`), `channel: sender string for ${slug}`);
19
+ assert.match(p, new RegExp(`@${slug} mentions`), `channel: @${slug} mention filter`);
20
+ assert.match(p, /NOT @claude/, `channel: explicit NOT @claude guard for ${slug}`);
21
+ assert.match(p, /#general/, `channel: channel name for ${slug}`);
22
+ }
23
+
24
+ // 2) Channel defaults to "general" when not provided.
25
+ {
26
+ const p = buildInjectionPrompt("dev", {});
27
+ assert.match(p, /#general/, "channel defaults to general");
28
+ }
29
+
30
+ // 3) Non-default channel is passed through.
31
+ {
32
+ const p = buildInjectionPrompt("dev", { channel: "batch-33" });
33
+ assert.match(p, /#batch-33/, "custom channel is used");
34
+ }
35
+
36
+ // 4) Job-thread prompt — each slug must:
37
+ // - name the agent with @<slug>
38
+ // - reference the job_id
39
+ // - pass sender: "<slug>" explicitly
40
+ for (const slug of DEFAULT_AGENT_SLUGS) {
41
+ const p = buildInjectionPrompt(slug, { jobId: "42" });
42
+ assert.match(p, new RegExp(`You are @${slug} `), `job: names @${slug}`);
43
+ assert.match(p, /job_id=42/, `job: job_id for ${slug}`);
44
+ assert.match(p, new RegExp(`sender: "${slug}"`), `job: sender string for ${slug}`);
45
+ }
46
+
47
+ // 5) customPrompt wins over channel and jobId and is returned as-is.
48
+ {
49
+ const p = buildInjectionPrompt("dev", {
50
+ channel: "general",
51
+ jobId: "99",
52
+ customPrompt: " do the thing ",
53
+ });
54
+ assert.equal(p, "do the thing", "customPrompt overrides + trims");
55
+ }
56
+
57
+ // 6) Blank customPrompt is ignored (falls through to channel/job path).
58
+ {
59
+ const p = buildInjectionPrompt("reviewer2", { customPrompt: " ", channel: "general" });
60
+ assert.match(p, /You are @reviewer2 /);
61
+ assert.match(p, /#general/);
62
+ }
63
+
64
+ console.log(`queue-watcher.test.js: all assertions passed (${DEFAULT_AGENT_SLUGS.length * 2 + 4} cases)`);
@@ -0,0 +1,94 @@
1
+ // #350 / quadwork#350: batch-progress no-linked-PR row builder +
2
+ // summarizer tests. Plain node:assert script — run with
3
+ // `node server/routes.batchProgress.test.js`.
4
+
5
+ const assert = require("node:assert/strict");
6
+ const { buildNoPrRow, summarizeItems } = require("./routes");
7
+
8
+ // 1) #350 regression fixture: CLOSED issue with no linked PR
9
+ // must render as 100% complete, not 0% queued.
10
+ {
11
+ const issue = {
12
+ number: 336,
13
+ title: "superseded by #338",
14
+ state: "CLOSED",
15
+ url: "https://github.com/realproject7/quadwork/issues/336",
16
+ };
17
+ const row = buildNoPrRow(issue);
18
+ assert.equal(row.status, "closed", "CLOSED with no PR → status=closed");
19
+ assert.equal(row.progress, 100, "CLOSED with no PR → 100%");
20
+ assert.match(row.label, /Closed.*✓/, "label has Closed and ✓ marker");
21
+ assert.equal(row.issue_number, 336);
22
+ assert.equal(row.url, issue.url);
23
+ }
24
+
25
+ // 2) OPEN issue with no linked PR still renders as queued.
26
+ {
27
+ const issue = {
28
+ number: 400,
29
+ title: "still open",
30
+ state: "OPEN",
31
+ url: "https://github.com/realproject7/quadwork/issues/400",
32
+ };
33
+ const row = buildNoPrRow(issue);
34
+ assert.equal(row.status, "queued", "OPEN with no PR → queued");
35
+ assert.equal(row.progress, 0);
36
+ assert.equal(row.label, "Issue · queued");
37
+ }
38
+
39
+ // 3) summarizeItems with a mix of merged and closed-without-PR:
40
+ // should count both toward the complete total, label "complete"
41
+ // when closed > 0.
42
+ {
43
+ const items = [
44
+ { status: "merged" },
45
+ { status: "merged" },
46
+ { status: "merged" },
47
+ { status: "merged" },
48
+ { status: "merged" },
49
+ { status: "closed" },
50
+ { status: "closed" },
51
+ ];
52
+ const out = summarizeItems(items);
53
+ assert.equal(out, "7/7 complete", "mixed merged+closed → X/N complete");
54
+ }
55
+
56
+ // 4) summarizeItems with only merged items keeps the classic
57
+ // "X/N merged" wording (no behavior change for PR-only batches).
58
+ {
59
+ const items = [
60
+ { status: "merged" },
61
+ { status: "merged" },
62
+ { status: "merged" },
63
+ ];
64
+ assert.equal(summarizeItems(items), "3/3 merged");
65
+ }
66
+
67
+ // 5) summarizeItems with a queued + closed mix: done count is
68
+ // closed only, queued surfaces in the detail tail.
69
+ {
70
+ const items = [
71
+ { status: "closed" },
72
+ { status: "queued" },
73
+ { status: "queued" },
74
+ ];
75
+ assert.equal(summarizeItems(items), "1/3 complete · 2 queued");
76
+ }
77
+
78
+ // 6) summarizeItems with in-flight PR states still tallies them
79
+ // in the detail tail and keeps the done count at merged-only.
80
+ {
81
+ const items = [
82
+ { status: "merged" },
83
+ { status: "ready" },
84
+ { status: "approved1" },
85
+ { status: "in_review" },
86
+ { status: "queued" },
87
+ ];
88
+ assert.equal(
89
+ summarizeItems(items),
90
+ "1/5 merged · 1 ready to merge · 1 needs 2nd approval · 1 in review · 1 queued",
91
+ );
92
+ }
93
+
94
+ console.log("routes.batchProgress.test.js: all assertions passed (6 cases)");