@chorus-aidlc/chorus 0.15.0 → 0.16.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 (317) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-build-manifest.json +411 -411
  3. package/.next/standalone/.next/app-path-routes-manifest.json +49 -49
  4. package/.next/standalone/.next/build-manifest.json +5 -5
  5. package/.next/standalone/.next/prerender-manifest.json +42 -42
  6. package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page.js +1 -1
  7. package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/activity/page.js +1 -1
  10. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/activity/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/[ideaUuid]/page.js +1 -1
  12. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/[ideaUuid]/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page.js +2 -2
  14. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page.js +2 -2
  17. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page.js +2 -2
  19. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page.js +2 -2
  21. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js +2 -2
  24. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page_client-reference-manifest.js +1 -1
  26. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page.js +2 -2
  27. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page_client-reference-manifest.js +1 -1
  28. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page.js +2 -2
  29. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page_client-reference-manifest.js +1 -1
  30. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page.js +1 -1
  31. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page_client-reference-manifest.js +1 -1
  33. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page.js +1 -1
  34. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/(dashboard)/projects/page.js +1 -1
  37. package/.next/standalone/.next/server/app/(dashboard)/projects/page.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/(dashboard)/projects/page_client-reference-manifest.js +1 -1
  39. package/.next/standalone/.next/server/app/(dashboard)/settings/page.js +2 -2
  40. package/.next/standalone/.next/server/app/(dashboard)/settings/page.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
  42. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  44. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  45. package/.next/standalone/.next/server/app/admin/companies/[uuid]/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/admin/companies/new/page_client-reference-manifest.js +1 -1
  47. package/.next/standalone/.next/server/app/admin/companies/new.html +2 -2
  48. package/.next/standalone/.next/server/app/admin/companies/new.rsc +2 -2
  49. package/.next/standalone/.next/server/app/admin/companies/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/admin/companies.html +2 -2
  51. package/.next/standalone/.next/server/app/admin/companies.rsc +2 -2
  52. package/.next/standalone/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/admin.html +2 -2
  54. package/.next/standalone/.next/server/app/admin.rsc +2 -2
  55. package/.next/standalone/.next/server/app/api/admin/companies/[uuid]/route_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/app/api/admin/companies/route_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/api/admin/login/route_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/api/admin/session/route_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/app/api/agent-connections/route_client-reference-manifest.js +1 -1
  60. package/.next/standalone/.next/server/app/api/agents/[uuid]/route_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/api/agents/route_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/api/api-keys/[uuid]/route_client-reference-manifest.js +1 -1
  64. package/.next/standalone/.next/server/app/api/api-keys/route_client-reference-manifest.js +1 -1
  65. package/.next/standalone/.next/server/app/api/auth/callback/route_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/app/api/auth/check-default/route_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/api/auth/company-oidc/route_client-reference-manifest.js +1 -1
  68. package/.next/standalone/.next/server/app/api/auth/default-login/route_client-reference-manifest.js +1 -1
  69. package/.next/standalone/.next/server/app/api/auth/identify/route_client-reference-manifest.js +1 -1
  70. package/.next/standalone/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/api/auth/me/route_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/api/auth/sync-token/route_client-reference-manifest.js +1 -1
  73. package/.next/standalone/.next/server/app/api/comments/route_client-reference-manifest.js +1 -1
  74. package/.next/standalone/.next/server/app/api/daemon/connection-heartbeat/route_client-reference-manifest.js +1 -1
  75. package/.next/standalone/.next/server/app/api/daemon/control/route_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/api/daemon/directory-request/report/route_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/api/daemon/execution-state/route_client-reference-manifest.js +1 -1
  78. package/.next/standalone/.next/server/app/api/daemon/executions/route_client-reference-manifest.js +1 -1
  79. package/.next/standalone/.next/server/app/api/daemon/pending-turns/route_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/api/daemon/report-interrupt/route_client-reference-manifest.js +1 -1
  81. package/.next/standalone/.next/server/app/api/daemon/resume/route_client-reference-manifest.js +1 -1
  82. package/.next/standalone/.next/server/app/api/daemon/transcript/route_client-reference-manifest.js +1 -1
  83. package/.next/standalone/.next/server/app/api/daemon/turn-advance/route_client-reference-manifest.js +1 -1
  84. package/.next/standalone/.next/server/app/api/daemon-directory-requests/[uuid]/route_client-reference-manifest.js +1 -1
  85. package/.next/standalone/.next/server/app/api/daemon-directory-requests/route_client-reference-manifest.js +1 -1
  86. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route_client-reference-manifest.js +1 -1
  87. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route_client-reference-manifest.js +1 -1
  89. package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route_client-reference-manifest.js +1 -1
  90. package/.next/standalone/.next/server/app/api/daemon-sessions/route_client-reference-manifest.js +1 -1
  91. package/.next/standalone/.next/server/app/api/documents/[uuid]/route_client-reference-manifest.js +1 -1
  92. package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route_client-reference-manifest.js +1 -1
  93. package/.next/standalone/.next/server/app/api/events/notifications/route_client-reference-manifest.js +1 -1
  94. package/.next/standalone/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
  95. package/.next/standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  96. package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route_client-reference-manifest.js +1 -1
  97. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route_client-reference-manifest.js +1 -1
  98. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route_client-reference-manifest.js +1 -1
  99. package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route_client-reference-manifest.js +1 -1
  100. package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route_client-reference-manifest.js +1 -1
  101. package/.next/standalone/.next/server/app/api/ideas/[uuid]/route_client-reference-manifest.js +1 -1
  102. package/.next/standalone/.next/server/app/api/ideas/[uuid]/wake-preview/route_client-reference-manifest.js +1 -1
  103. package/.next/standalone/.next/server/app/api/ideas/conversational/route_client-reference-manifest.js +1 -1
  104. package/.next/standalone/.next/server/app/api/mcp/route_client-reference-manifest.js +1 -1
  105. package/.next/standalone/.next/server/app/api/me/assignments/route_client-reference-manifest.js +1 -1
  106. package/.next/standalone/.next/server/app/api/mentionables/route_client-reference-manifest.js +1 -1
  107. package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route_client-reference-manifest.js +1 -1
  108. package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route_client-reference-manifest.js +1 -1
  109. package/.next/standalone/.next/server/app/api/notifications/preferences/route_client-reference-manifest.js +1 -1
  110. package/.next/standalone/.next/server/app/api/notifications/read-all/route_client-reference-manifest.js +1 -1
  111. package/.next/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  112. package/.next/standalone/.next/server/app/api/notifications/unread-count/route_client-reference-manifest.js +1 -1
  113. package/.next/standalone/.next/server/app/api/project-groups/[uuid]/dashboard/route_client-reference-manifest.js +1 -1
  114. package/.next/standalone/.next/server/app/api/project-groups/[uuid]/route_client-reference-manifest.js +1 -1
  115. package/.next/standalone/.next/server/app/api/project-groups/route_client-reference-manifest.js +1 -1
  116. package/.next/standalone/.next/server/app/api/project-visits/pin/route_client-reference-manifest.js +1 -1
  117. package/.next/standalone/.next/server/app/api/project-visits/route_client-reference-manifest.js +1 -1
  118. package/.next/standalone/.next/server/app/api/project-visits/visit/route_client-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/app/api/projects/[uuid]/activity/route_client-reference-manifest.js +1 -1
  120. package/.next/standalone/.next/server/app/api/projects/[uuid]/agent-cwds/route_client-reference-manifest.js +1 -1
  121. package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route_client-reference-manifest.js +1 -1
  122. package/.next/standalone/.next/server/app/api/projects/[uuid]/documents/route_client-reference-manifest.js +1 -1
  123. package/.next/standalone/.next/server/app/api/projects/[uuid]/group/route_client-reference-manifest.js +1 -1
  124. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route_client-reference-manifest.js +1 -1
  125. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route_client-reference-manifest.js +1 -1
  126. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/[proposalUuid]/validate/route_client-reference-manifest.js +1 -1
  127. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/route_client-reference-manifest.js +1 -1
  128. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/summary/route_client-reference-manifest.js +1 -1
  129. package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route_client-reference-manifest.js +1 -1
  130. package/.next/standalone/.next/server/app/api/projects/[uuid]/route_client-reference-manifest.js +1 -1
  131. package/.next/standalone/.next/server/app/api/projects/[uuid]/stats/route_client-reference-manifest.js +1 -1
  132. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route_client-reference-manifest.js +1 -1
  133. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route_client-reference-manifest.js +1 -1
  134. package/.next/standalone/.next/server/app/api/projects/agent-cwd-options/route_client-reference-manifest.js +1 -1
  135. package/.next/standalone/.next/server/app/api/projects/route.js +1 -1
  136. package/.next/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  137. package/.next/standalone/.next/server/app/api/proposals/[uuid]/approve/route_client-reference-manifest.js +1 -1
  138. package/.next/standalone/.next/server/app/api/proposals/[uuid]/close/route_client-reference-manifest.js +1 -1
  139. package/.next/standalone/.next/server/app/api/proposals/[uuid]/reject/route_client-reference-manifest.js +1 -1
  140. package/.next/standalone/.next/server/app/api/proposals/[uuid]/revoke/route_client-reference-manifest.js +1 -1
  141. package/.next/standalone/.next/server/app/api/proposals/[uuid]/route_client-reference-manifest.js +1 -1
  142. package/.next/standalone/.next/server/app/api/references/[uuid]/route_client-reference-manifest.js +1 -1
  143. package/.next/standalone/.next/server/app/api/references/route_client-reference-manifest.js +1 -1
  144. package/.next/standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  145. package/.next/standalone/.next/server/app/api/session/route_client-reference-manifest.js +1 -1
  146. package/.next/standalone/.next/server/app/api/sessions/[uuid]/route_client-reference-manifest.js +1 -1
  147. package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route_client-reference-manifest.js +1 -1
  148. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route_client-reference-manifest.js +1 -1
  149. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route_client-reference-manifest.js +1 -1
  150. package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route_client-reference-manifest.js +1 -1
  151. package/.next/standalone/.next/server/app/api/tasks/[uuid]/route_client-reference-manifest.js +1 -1
  152. package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route_client-reference-manifest.js +1 -1
  153. package/.next/standalone/.next/server/app/index.html +2 -2
  154. package/.next/standalone/.next/server/app/index.rsc +2 -2
  155. package/.next/standalone/.next/server/app/login/admin/page_client-reference-manifest.js +1 -1
  156. package/.next/standalone/.next/server/app/login/admin.html +2 -2
  157. package/.next/standalone/.next/server/app/login/admin.rsc +2 -2
  158. package/.next/standalone/.next/server/app/login/callback/page_client-reference-manifest.js +1 -1
  159. package/.next/standalone/.next/server/app/login/callback.html +2 -2
  160. package/.next/standalone/.next/server/app/login/callback.rsc +2 -2
  161. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  162. package/.next/standalone/.next/server/app/login/pick-workspace/page_client-reference-manifest.js +1 -1
  163. package/.next/standalone/.next/server/app/login/pick-workspace.html +2 -2
  164. package/.next/standalone/.next/server/app/login/pick-workspace.rsc +2 -2
  165. package/.next/standalone/.next/server/app/login.html +2 -2
  166. package/.next/standalone/.next/server/app/login.rsc +2 -2
  167. package/.next/standalone/.next/server/app/onboarding/page.js +2 -2
  168. package/.next/standalone/.next/server/app/onboarding/page.js.nft.json +1 -1
  169. package/.next/standalone/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
  170. package/.next/standalone/.next/server/app/onboarding.html +2 -2
  171. package/.next/standalone/.next/server/app/onboarding.rsc +3 -3
  172. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  173. package/.next/standalone/.next/server/app/projects.html +2 -2
  174. package/.next/standalone/.next/server/app/projects.rsc +4 -4
  175. package/.next/standalone/.next/server/app/settings.html +2 -2
  176. package/.next/standalone/.next/server/app/settings.rsc +4 -4
  177. package/.next/standalone/.next/server/app-paths-manifest.json +49 -49
  178. package/.next/standalone/.next/server/chunks/1114.js +1 -1
  179. package/.next/standalone/.next/server/chunks/1318.js +1 -1
  180. package/.next/standalone/.next/server/chunks/1559.js +2 -2
  181. package/.next/standalone/.next/server/chunks/1722.js +1 -1
  182. package/.next/standalone/.next/server/chunks/2570.js +2 -2
  183. package/.next/standalone/.next/server/chunks/2572.js +1 -1
  184. package/.next/standalone/.next/server/chunks/2961.js +1 -1
  185. package/.next/standalone/.next/server/chunks/3594.js +1 -0
  186. package/.next/standalone/.next/server/chunks/4394.js +1 -0
  187. package/.next/standalone/.next/server/chunks/5245.js +1 -1
  188. package/.next/standalone/.next/server/chunks/{2282.js → 5351.js} +3 -3
  189. package/.next/standalone/.next/server/chunks/6113.js +1 -1
  190. package/.next/standalone/.next/server/chunks/6207.js +1 -1
  191. package/.next/standalone/.next/server/chunks/6506.js +1 -1
  192. package/.next/standalone/.next/server/chunks/6667.js +1 -0
  193. package/.next/standalone/.next/server/chunks/679.js +1 -1
  194. package/.next/standalone/.next/server/chunks/6995.js +1 -0
  195. package/.next/standalone/.next/server/chunks/7368.js +1 -1
  196. package/.next/standalone/.next/server/chunks/7530.js +1 -1
  197. package/.next/standalone/.next/server/chunks/920.js +1 -1
  198. package/.next/standalone/.next/server/chunks/9213.js +1 -1
  199. package/.next/standalone/.next/server/chunks/9378.js +1 -1
  200. package/.next/standalone/.next/server/chunks/9793.js +1 -0
  201. package/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
  202. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  203. package/.next/standalone/.next/server/pages/404.html +2 -2
  204. package/.next/standalone/.next/server/pages/500.html +1 -1
  205. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  206. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  207. package/.next/standalone/.next/static/chunks/11595.1bcd2b65089007ae.js +1 -0
  208. package/.next/standalone/.next/static/chunks/19887-4d76db57a7ce4437.js +1 -0
  209. package/.next/standalone/.next/static/chunks/29108-e171d8b8c680cbb5.js +1 -0
  210. package/.next/standalone/.next/static/chunks/33456.c98d3e21528b61d8.js +1 -0
  211. package/.next/standalone/.next/static/chunks/4860.9122a86d33dc6b62.js +1 -0
  212. package/.next/standalone/.next/static/chunks/53073-5fd399cb25a11740.js +1 -0
  213. package/.next/standalone/.next/static/chunks/53402-a54163001f3d953a.js +1 -0
  214. package/.next/standalone/.next/static/chunks/6603-07faab08560f7ecd.js +1 -0
  215. package/.next/standalone/.next/static/chunks/7777-5dad34f6bdc13482.js +1 -0
  216. package/.next/standalone/.next/static/chunks/78155-db70d9684a1e77a2.js +1 -0
  217. package/.next/standalone/.next/static/chunks/78917-7354d3b6908da7d1.js +1 -0
  218. package/.next/standalone/.next/static/chunks/82751-de255af4418d53e4.js +1 -0
  219. package/.next/standalone/.next/static/chunks/94643-90a9ec7b9a9abaf0.js +1 -0
  220. package/.next/standalone/.next/static/chunks/99366-425e9ef22e60e3e2.js +1 -0
  221. package/.next/standalone/.next/static/chunks/99373.585230dcb315a068.js +1 -0
  222. package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-3d3b3b9e16c03cda.js +1 -0
  223. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-69d746c98079024d.js +1 -0
  224. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-2af705f6c3789131.js +1 -0
  225. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/{page-2c9d3f4c6e0ff807.js → page-82404154708e48a9.js} +1 -1
  226. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/page-8119df915138a9c3.js +1 -0
  227. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-f619bd65e1eed8c9.js +1 -0
  228. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-d5b222f379b2e8ca.js +1 -0
  229. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/{page-ed9415921188b4d3.js → page-6abc7d1785e2b999.js} +1 -1
  230. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/{page-c70af8cac7bdc483.js → page-0789c6589363154c.js} +1 -1
  231. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/{page-715b000c156a080c.js → page-a612f6fc5be0239d.js} +1 -1
  232. package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-5fb9fd3db155d5ca.js +1 -0
  233. package/.next/standalone/.next/static/chunks/app/onboarding/page-e85315278aafc300.js +1 -0
  234. package/.next/standalone/.next/static/chunks/{webpack-84e2db1b2418c974.js → webpack-dec1f54ebb9bf963.js} +1 -1
  235. package/.next/standalone/.next/static/css/67fba0943f494f0e.css +1 -0
  236. package/.next/standalone/package.json +1 -1
  237. package/.next/standalone/public/chorus-plugin/.claude-plugin/plugin.json +1 -1
  238. package/.next/standalone/public/chorus-plugin/skills/brainstorm/SKILL.md +1 -1
  239. package/.next/standalone/public/chorus-plugin/skills/chorus/SKILL.md +2 -1
  240. package/.next/standalone/public/chorus-plugin/skills/develop/SKILL.md +1 -1
  241. package/.next/standalone/public/chorus-plugin/skills/docs/SKILL.md +68 -0
  242. package/.next/standalone/public/chorus-plugin/skills/idea/SKILL.md +1 -1
  243. package/.next/standalone/public/chorus-plugin/skills/openspec-aware/SKILL.md +1 -1
  244. package/.next/standalone/public/chorus-plugin/skills/proposal/SKILL.md +1 -1
  245. package/.next/standalone/public/chorus-plugin/skills/quick-dev/SKILL.md +1 -1
  246. package/.next/standalone/public/chorus-plugin/skills/review/SKILL.md +1 -1
  247. package/.next/standalone/public/chorus-plugin/skills/yolo/SKILL.md +1 -1
  248. package/.next/standalone/public/install-kiro.sh +10 -7
  249. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus.json +1 -0
  250. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-brainstorm/SKILL.md +1 -1
  251. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-develop/SKILL.md +1 -1
  252. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-docs/SKILL.md +68 -0
  253. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-idea/SKILL.md +1 -1
  254. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-openspec-aware/SKILL.md +1 -1
  255. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-proposal/SKILL.md +1 -1
  256. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-quick-dev/SKILL.md +1 -1
  257. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-review/SKILL.md +1 -1
  258. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-yolo/SKILL.md +1 -1
  259. package/.next/standalone/public/kiro-plugin/.kiro/steering/chorus.md +1 -0
  260. package/.next/standalone/public/kiro-plugin/bin/chorus-api.sh +1 -1
  261. package/.next/standalone/public/skill/brainstorm-chorus/SKILL.md +1 -1
  262. package/.next/standalone/public/skill/chorus/SKILL.md +2 -1
  263. package/.next/standalone/public/skill/code-reviewer-chorus/SKILL.md +1 -1
  264. package/.next/standalone/public/skill/develop-chorus/SKILL.md +1 -1
  265. package/.next/standalone/public/skill/docs-chorus/SKILL.md +70 -0
  266. package/.next/standalone/public/skill/idea-chorus/SKILL.md +1 -1
  267. package/.next/standalone/public/skill/package.json +9 -5
  268. package/.next/standalone/public/skill/proposal-chorus/SKILL.md +1 -1
  269. package/.next/standalone/public/skill/proposal-reviewer-chorus/SKILL.md +1 -1
  270. package/.next/standalone/public/skill/quick-dev-chorus/SKILL.md +1 -1
  271. package/.next/standalone/public/skill/review-chorus/SKILL.md +1 -1
  272. package/.next/standalone/public/skill/task-reviewer-chorus/SKILL.md +1 -1
  273. package/.next/standalone/public/skill/yolo-chorus/SKILL.md +1 -1
  274. package/README.ja.md +6 -14
  275. package/README.ko.md +6 -14
  276. package/README.md +6 -14
  277. package/README.zh.md +6 -14
  278. package/cli/claude-spawner.mjs +15 -6
  279. package/cli/client-args.mjs +8 -0
  280. package/cli/codex-spawner.mjs +7 -3
  281. package/cli/credentials.mjs +41 -0
  282. package/cli/daemon-config.mjs +202 -1
  283. package/cli/daemon-install-config.mjs +38 -1
  284. package/cli/daemon.mjs +222 -1
  285. package/cli/login.mjs +90 -2
  286. package/package.json +1 -1
  287. package/.next/standalone/.next/server/chunks/1524.js +0 -1
  288. package/.next/standalone/.next/server/chunks/330.js +0 -1
  289. package/.next/standalone/.next/server/chunks/3525.js +0 -1
  290. package/.next/standalone/.next/server/chunks/4070.js +0 -1
  291. package/.next/standalone/.next/server/chunks/8540.js +0 -1
  292. package/.next/standalone/.next/static/chunks/11595.f1e55e827d67f2bc.js +0 -1
  293. package/.next/standalone/.next/static/chunks/18351-12dc856208d79e10.js +0 -1
  294. package/.next/standalone/.next/static/chunks/33456.4817cdce41593c7e.js +0 -1
  295. package/.next/standalone/.next/static/chunks/37938-0b9a2b891c04b166.js +0 -1
  296. package/.next/standalone/.next/static/chunks/4860.bb2749ebaf8eb15f.js +0 -1
  297. package/.next/standalone/.next/static/chunks/53402-be6989c3f3968e7b.js +0 -1
  298. package/.next/standalone/.next/static/chunks/68326-61feeb2f6cddd338.js +0 -1
  299. package/.next/standalone/.next/static/chunks/72974-714dcca796895c40.js +0 -1
  300. package/.next/standalone/.next/static/chunks/7777-13466138aa42bd5f.js +0 -1
  301. package/.next/standalone/.next/static/chunks/78917-f91904c6c2d12dab.js +0 -1
  302. package/.next/standalone/.next/static/chunks/80748-e971c5a5d6ef967d.js +0 -1
  303. package/.next/standalone/.next/static/chunks/80904-973284d1fe916c38.js +0 -1
  304. package/.next/standalone/.next/static/chunks/94470-0c74a933d5a2902f.js +0 -1
  305. package/.next/standalone/.next/static/chunks/94643-ba1ebff5769d2b50.js +0 -1
  306. package/.next/standalone/.next/static/chunks/99373.ae03246bdf49c700.js +0 -1
  307. package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-177a3fa88be94b4a.js +0 -1
  308. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-03b8510273520572.js +0 -1
  309. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-4a8ac49308a4e23b.js +0 -1
  310. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/page-03408be00dc4822b.js +0 -1
  311. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-be353989e67e7b55.js +0 -1
  312. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-596d97796dd55e2f.js +0 -1
  313. package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-e786a59c24eb5bda.js +0 -1
  314. package/.next/standalone/.next/static/chunks/app/onboarding/page-df7c97cefb508201.js +0 -1
  315. package/.next/standalone/.next/static/css/ef995b001437e3ef.css +0 -1
  316. /package/.next/standalone/.next/static/{oHZy43Le4b2I7pg7_cQ0Z → H92ZuhpmDWcL3WOfYRc--}/_buildManifest.js +0 -0
  317. /package/.next/standalone/.next/static/{oHZy43Le4b2I7pg7_cQ0Z → H92ZuhpmDWcL3WOfYRc--}/_ssgManifest.js +0 -0
@@ -284,7 +284,11 @@ export class ClaudeSpawner {
284
284
  * so the waker can store the handle in its execution registry for the interrupt
285
285
  * path BEFORE this promise resolves. It is invoked once, synchronously, only on a
286
286
  * successful spawn; a spawn failure never calls it.
287
- * @returns {Promise<{ sessionId: string, exitCode: number|null, isNew: boolean }>}
287
+ * @returns {Promise<{ sessionId: string, backendSessionId: string|null, exitCode: number|null, isNew: boolean }>}
288
+ * `backendSessionId` is the Claude `--resume` anchor (the input `sessionId`) on a
289
+ * terminal resolution after a spawn, so the conversation UI can offer a resumable
290
+ * id — mirrors codex-spawner's shape. `null` on the pre-spawn failure paths (no
291
+ * turn ran, nothing to resume).
288
292
  */
289
293
  async wake({ prompt, sessionId, isNew, mcpConfigPath, cwd, onMessage, onChild }) {
290
294
  const id = sessionId;
@@ -295,14 +299,14 @@ export class ClaudeSpawner {
295
299
  this.logger.error(
296
300
  `[Chorus] refusing to spawn: session id is not a valid lowercase UUID: ${id}`
297
301
  );
298
- return { sessionId: typeof id === "string" ? id : "", exitCode: null, isNew: Boolean(isNew) };
302
+ return { sessionId: typeof id === "string" ? id : "", backendSessionId: null, exitCode: null, isNew: Boolean(isNew) };
299
303
  }
300
304
 
301
305
  const claudePath = this.claudePath ?? resolveClaudePath();
302
306
  if (!claudePath) {
303
307
  // No crash — surface visibly and resolve with a failure result.
304
308
  this.logger.error("[Chorus] cannot locate the `claude` executable on PATH; skipping wake");
305
- return { sessionId: id, exitCode: null, isNew };
309
+ return { sessionId: id, backendSessionId: null, exitCode: null, isNew };
306
310
  }
307
311
 
308
312
  const args = buildArgs({ sessionId: id, isNew, mcpConfigPath, permissionMode: this.permissionMode });
@@ -345,7 +349,7 @@ export class ClaudeSpawner {
345
349
  });
346
350
  } catch (err) {
347
351
  this.logger.error(`[Chorus] failed to spawn claude: ${err}`);
348
- resolve({ sessionId: id, exitCode: null, isNew });
352
+ resolve({ sessionId: id, backendSessionId: null, exitCode: null, isNew });
349
353
  return;
350
354
  }
351
355
 
@@ -391,14 +395,19 @@ export class ClaudeSpawner {
391
395
  child.on("error", (err) => {
392
396
  // e.g. ENOENT if the resolved path vanished — log, don't throw.
393
397
  this.logger.error(`[Chorus] claude process error: ${err}`);
394
- resolve({ sessionId: observedSessionId, exitCode: null, isNew });
398
+ // backendSessionId is the `--resume` anchor (`id`), NOT observedSessionId:
399
+ // a fork-on-resume claude can emit a new stream session_id, but the daemon
400
+ // resumes and files the transcript under `id`, so `id` is the resumable value.
401
+ resolve({ sessionId: observedSessionId, backendSessionId: id, exitCode: null, isNew });
395
402
  });
396
403
 
397
404
  child.on("close", (code) => {
398
405
  if (code !== 0) {
399
406
  this.logger.warn(`[Chorus] claude exited with code ${code}`);
400
407
  }
401
- resolve({ sessionId: observedSessionId, exitCode: code, isNew });
408
+ // backendSessionId is the `--resume` anchor (`id`), NOT observedSessionId (see
409
+ // the process-error handler above for why the anchor is the resumable value).
410
+ resolve({ sessionId: observedSessionId, backendSessionId: id, exitCode: code, isNew });
402
411
  });
403
412
 
404
413
  // Guard against an ASYNC stdin error (EPIPE): if claude exits/closes
@@ -69,6 +69,7 @@ export function parseClientFlags(argv) {
69
69
  else if (a === "-d" || a === "--detach") out.detach = true;
70
70
  else if (a === "--force") out.force = true;
71
71
  else if (a === "--yes" || a === "-y") out.yes = true;
72
+ else if (a === "--add") out.add = true;
72
73
  else if (a === "--help" || a === "-h") out.help = true;
73
74
  }
74
75
  return out;
@@ -202,9 +203,16 @@ USAGE
202
203
  OPTIONS
203
204
  --url <url> Remote Chorus server URL (env: CHORUS_URL)
204
205
  --api-key <cho_...> Agent API key (env: CHORUS_API_KEY)
206
+ --add Add this key as an ADDITIONAL agent (multi-agent daemon)
207
+ instead of overwriting the single credential
205
208
  -h, --help Show this help message
206
209
 
207
210
  With no flags, login prompts interactively for the URL and a masked API key,
208
211
  validates them against the server, and on success saves the credentials.
212
+
213
+ With --add, the validated key is appended to the daemon.json 'agents[]' array
214
+ so one daemon can serve several independent agents (see docs/DAEMON.md). The
215
+ first --add migrates an existing flat credential into agents[0]; a duplicate
216
+ key is refused and existing agents are never overwritten.
209
217
  `;
210
218
  }
@@ -13,9 +13,13 @@
13
13
  // it and persist anchor→thread_id (codex-session-map.mjs) so a later wake can
14
14
  // `resume <thread_id>`. (serde: ThreadEvent tag="type", rename="thread.started";
15
15
  // ThreadStartedEvent.thread_id: String — codex-rs/exec/src/exec_events.rs.)
16
- // • No `--mcp-config`: MCP comes from the user's ~/.codex/config.toml. The daemon
17
- // exports its resolved URL for SessionStart hooks and its key for the configured
18
- // bearer_token_env_var (default CHORUS_API_KEY) never argv.
16
+ // • No `--mcp-config`: Codex reads MCP servers from the user's ~/.codex/config.toml.
17
+ // The Chorus MCP key there is USER-MANAGED: the installer writes a LITERAL Bearer
18
+ // header and Codex does NOT expand ${VAR} inside http_headers, so the CHORUS_API_KEY
19
+ // the daemon exports does NOT reach Codex's MCP auth. The daemon still exports
20
+ // CHORUS_URL / CHORUS_API_KEY into the child env — but only for the plugin's shell
21
+ // tooling (chorus-api.sh / SessionStart hooks), never argv and never Codex MCP.
22
+ // (Multi-agent: two Codex agents with different keys each need their own CODEX_HOME.)
19
23
  // • Permission is a SANDBOX mode, not a tool allowlist.
20
24
  //
21
25
  // Reuses claude-spawner's platform-neutral helpers: parseNdjsonChunk (NDJSON
@@ -70,6 +70,47 @@ export function readYoloAck(deps = {}) {
70
70
  return file ? nonEmpty(file.yoloAckAt) ?? null : null;
71
71
  }
72
72
 
73
+ /**
74
+ * Resolve the DEFAULT url + apiKey layer (per-field, non-throwing) for the
75
+ * multi-agent config. Unlike `resolveCredentials` (which needs a COMPLETE pair
76
+ * and throws when none resolves), this resolves each field independently and
77
+ * returns `undefined` for any field no source supplies. It is the "top-level
78
+ * defaults" layer that each `agents[]` entry merges over: an agent that omits
79
+ * `url` inherits this default `url`, an agent that omits `apiKey` inherits this
80
+ * default `apiKey` (rarely useful, but symmetric with every other default).
81
+ *
82
+ * Same source order as `resolveCredentials`, applied per field:
83
+ * flag > env > login file (top-level) > plugin fallback.
84
+ *
85
+ * @param {{ url?: string, apiKey?: string }} flags
86
+ * @param {ResolveDeps} [deps]
87
+ * @returns {{ url: string | undefined, apiKey: string | undefined }}
88
+ */
89
+ export function resolveCredentialDefaults(flags = {}, deps = {}) {
90
+ const env = deps.env ?? process.env;
91
+ const readJson = deps.readJson ?? readJsonSafe;
92
+ const loginPath = deps.loginPath ?? loginFilePath();
93
+ const settingsPath = deps.settingsPath ?? claudeSettingsPath();
94
+
95
+ const file = readJson(loginPath);
96
+ const settings = readJson(settingsPath);
97
+ const pluginEnv =
98
+ settings && typeof settings.env === "object" && settings.env !== null
99
+ ? /** @type {Record<string, unknown>} */ (settings.env)
100
+ : null;
101
+
102
+ const pick = (flagVal, envKey, fileKey) =>
103
+ nonEmpty(flagVal) ??
104
+ nonEmpty(env[envKey]) ??
105
+ (file ? nonEmpty(file[fileKey]) : undefined) ??
106
+ (pluginEnv ? nonEmpty(pluginEnv[envKey]) : undefined);
107
+
108
+ return {
109
+ url: pick(flags.url, "CHORUS_URL", "url"),
110
+ apiKey: pick(flags.apiKey, "CHORUS_API_KEY", "apiKey"),
111
+ };
112
+ }
113
+
73
114
  /**
74
115
  * @typedef {Object} ResolvedCredentials
75
116
  * @property {string} url
@@ -15,11 +15,21 @@
15
15
  import { readFileSync } from "node:fs";
16
16
  import { homedir } from "node:os";
17
17
  import { isAbsolute, resolve as resolvePath } from "node:path";
18
- import { loginFilePath } from "./credentials.mjs";
18
+ import { loginFilePath, resolveCredentials, resolveCredentialDefaults } from "./credentials.mjs";
19
+ import { resolveAgentType, KNOWN_AGENTS } from "./daemon-agent.mjs";
20
+ import { resolvePermissionMode } from "./daemon-permission-mode.mjs";
19
21
 
20
22
  /** Built-in default escalation window (ms) — matches the spec's 10 seconds. */
21
23
  export const DEFAULT_SIGINT_TIMEOUT_MS = 10_000;
22
24
 
25
+ /**
26
+ * Built-in default per-agent wake concurrency. This was the process-wide
27
+ * hardcoded WakeQueue cap (`maxConcurrency ?? 4` in daemon.mjs) before it became
28
+ * a per-agent, configurable value — kept at 4 so an agent that specifies no
29
+ * `maxConcurrency` behaves exactly as the daemon did before.
30
+ */
31
+ export const DEFAULT_MAX_CONCURRENCY = 4;
32
+
23
33
  /**
24
34
  * Coerce a value to a positive finite integer of milliseconds, or undefined when it
25
35
  * is absent / not a usable number. Accepts a number or a numeric string (env vars
@@ -235,3 +245,194 @@ export function resolveBrowseRoots(flags = {}, deps = {}) {
235
245
  : [];
236
246
  return fromFile.length ? fromFile : [normalizeCwd(home, home)];
237
247
  }
248
+
249
+ // ===== Multi-agent config (daemon-multi-agent — N independent agents per daemon) =====
250
+ //
251
+ // One daemon process may serve a LIST of fully-independent agents, each with its
252
+ // own credentials + working directories + backend + permission mode + concurrency.
253
+ // `resolveAgentConfigs` returns that list as `AgentConfig[]`, every field already
254
+ // merged with its default. Two shapes are supported:
255
+ //
256
+ // 1. `~/.chorus/daemon.json` has a non-empty `agents: [ … ]` array → one
257
+ // AgentConfig per entry, each entry's fields merged OVER the top-level
258
+ // defaults (per-agent value wins; an omitted field inherits the default).
259
+ // 2. No `agents[]` (or empty) → exactly ONE AgentConfig synthesized from the
260
+ // existing flat resolution (resolveCredentials + resolveDaemonCwds +
261
+ // resolveAgentType + sigint + browseRoots). This is byte-for-byte the
262
+ // daemon's current single-agent behavior — old installs run unchanged, and
263
+ // flags / env still resolve this single agent's fields.
264
+ //
265
+ // Validation is strict and visible: a missing apiKey, an unresolvable url, an
266
+ // unknown agentType, or an invalid permissionMode THROWS an Error naming the
267
+ // offending agent. The daemon's top-level error handler turns that into a
268
+ // non-zero exit — the resolver never silently drops or falls back to a default
269
+ // agent (matching resolveCredentials' throw-on-nothing contract).
270
+
271
+ /** A non-empty trimmed string, or undefined. */
272
+ function nonEmptyStr(value) {
273
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
274
+ }
275
+
276
+ /**
277
+ * True iff `~/.chorus/daemon.json` declares a non-empty `agents[]` with at least
278
+ * one object entry — i.e. the daemon should run in multi-agent mode. Lets the
279
+ * daemon pick the multi-agent startup path (bypassing the flat single-credential
280
+ * preflight) without duplicating the file read. Never throws.
281
+ * @param {{ readJson?: (p: string) => (Record<string, unknown>|null), loginPath?: string }} [deps]
282
+ * @returns {boolean}
283
+ */
284
+ export function hasConfiguredAgents(deps = {}) {
285
+ const readJson = deps.readJson ?? readJsonSafe;
286
+ const loginPath = deps.loginPath ?? loginFilePath();
287
+ const file = readJson(loginPath);
288
+ return Boolean(
289
+ file && Array.isArray(file.agents) && file.agents.some((a) => a && typeof a === "object"),
290
+ );
291
+ }
292
+
293
+ /**
294
+ * Coerce to a positive finite integer (count), or undefined. Accepts number or
295
+ * numeric string; rejects 0, negatives, NaN, Infinity. Used for maxConcurrency.
296
+ * @param {unknown} value @returns {number | undefined}
297
+ */
298
+ function positiveInt(value) {
299
+ if (value === undefined || value === null || value === "") return undefined;
300
+ const n = typeof value === "number" ? value : Number(String(value).trim());
301
+ if (!Number.isFinite(n) || n <= 0) return undefined;
302
+ return Math.floor(n);
303
+ }
304
+
305
+ /**
306
+ * @typedef {Object} AgentConfig One fully-resolved agent runtime config.
307
+ * @property {string} url Chorus server URL for this agent.
308
+ * @property {string} apiKey This agent's `cho_` API key.
309
+ * @property {string} agentType Backend: claude-code | codex | kiro.
310
+ * @property {Array<string|undefined>} cwds Served paths (`undefined` ⇒ process cwd).
311
+ * @property {"yolo"|"chorus"} permissionMode Woken-agent permission posture.
312
+ * @property {number} maxConcurrency This agent's wake-queue cap.
313
+ * @property {number} sigintTimeoutMs Interrupt escalation window (ms).
314
+ * @property {string[]} browseRoots Directory-discovery allowlist.
315
+ * @property {string} label Diagnostic label ("agent" or "agents[i]").
316
+ */
317
+
318
+ /**
319
+ * Resolve the list of agents this daemon serves. See the block comment above.
320
+ *
321
+ * @param {{ url?: string, apiKey?: string, agent?: string, cwd?: string|string[],
322
+ * browseRoot?: string|string[], sigintTimeout?: number|string,
323
+ * chorusOnly?: boolean, yolo?: boolean }} [flags]
324
+ * @param {{
325
+ * env?: Record<string, string|undefined>,
326
+ * readJson?: (path: string) => (Record<string, unknown>|null),
327
+ * loginPath?: string,
328
+ * settingsPath?: string,
329
+ * home?: string,
330
+ * permissionMode?: "yolo"|"chorus", // pre-resolved global posture (else computed)
331
+ * }} [deps]
332
+ * @returns {AgentConfig[]} Non-empty list; throws on an invalid agent entry.
333
+ */
334
+ export function resolveAgentConfigs(flags = {}, deps = {}) {
335
+ const env = deps.env ?? process.env;
336
+ const readJson = deps.readJson ?? readJsonSafe;
337
+ const loginPath = deps.loginPath ?? loginFilePath();
338
+ const home = deps.home ?? homedir();
339
+ const file = readJson(loginPath);
340
+
341
+ // Global default permission posture; a per-agent `permissionMode` overrides it.
342
+ // needConfirm/hasAck is vestigial, so isTTY/hasAck do not affect the resolved mode.
343
+ const defaultPermissionMode =
344
+ deps.permissionMode ??
345
+ resolvePermissionMode(flags, env, { isTTY: false, hasAck: false }).mode;
346
+
347
+ const agentEntries =
348
+ file && Array.isArray(file.agents)
349
+ ? file.agents.filter((a) => a && typeof a === "object")
350
+ : [];
351
+
352
+ // ---- Back-compat: no agents[] → exactly one agent from flat resolution ----
353
+ if (agentEntries.length === 0) {
354
+ const creds = resolveCredentials(flags, deps); // throws if no complete pair (today's behavior)
355
+ const at = resolveAgentType(flags, env, deps);
356
+ if (!at.ok) throw new Error(at.error);
357
+ return [
358
+ {
359
+ url: creds.url,
360
+ apiKey: creds.apiKey,
361
+ agentType: at.agent,
362
+ cwds: resolveDaemonCwds(flags, deps),
363
+ permissionMode: defaultPermissionMode,
364
+ maxConcurrency: positiveInt(file?.maxConcurrency) ?? DEFAULT_MAX_CONCURRENCY,
365
+ sigintTimeoutMs: resolveSigintTimeoutMs(flags, deps),
366
+ browseRoots: resolveBrowseRoots(flags, deps),
367
+ label: "agent",
368
+ },
369
+ ];
370
+ }
371
+
372
+ // ---- Multi-agent: each entry merged over the top-level defaults ----
373
+ const credDefaults = resolveCredentialDefaults(flags, deps);
374
+ const defaultCwds = resolveDaemonCwds(flags, deps);
375
+ const defaultAgentType = resolveAgentType(flags, env, deps); // top-level default (may be {ok:false} if top-level `agent` is garbage)
376
+ const defaultSigint = resolveSigintTimeoutMs(flags, deps);
377
+ const defaultBrowseRoots = resolveBrowseRoots(flags, deps);
378
+ const defaultMaxConcurrency = positiveInt(file?.maxConcurrency) ?? DEFAULT_MAX_CONCURRENCY;
379
+
380
+ return agentEntries.map((entry, i) => {
381
+ const label = nonEmptyStr(entry.label) ?? nonEmptyStr(entry.name) ?? `agents[${i}]`;
382
+
383
+ const url = nonEmptyStr(entry.url) ?? credDefaults.url;
384
+ const apiKey = nonEmptyStr(entry.apiKey) ?? credDefaults.apiKey;
385
+ if (!apiKey) {
386
+ throw new Error(`Agent ${label}: missing apiKey (no per-agent apiKey and no top-level default).`);
387
+ }
388
+ if (!url) {
389
+ throw new Error(`Agent ${label}: missing/unresolvable url (no per-agent url and no top-level default).`);
390
+ }
391
+
392
+ // agentType: per-agent value, else the top-level default (which must itself be valid).
393
+ let agentType;
394
+ if (nonEmptyStr(entry.agentType)) {
395
+ agentType = nonEmptyStr(entry.agentType);
396
+ } else if (defaultAgentType.ok) {
397
+ agentType = defaultAgentType.agent;
398
+ } else {
399
+ throw new Error(
400
+ `Agent ${label}: no agentType and the top-level agent default is invalid (${defaultAgentType.error}).`,
401
+ );
402
+ }
403
+ if (!KNOWN_AGENTS.includes(agentType)) {
404
+ throw new Error(
405
+ `Agent ${label}: unknown agentType "${agentType}". Accepted: ${KNOWN_AGENTS.join(", ")}.`,
406
+ );
407
+ }
408
+
409
+ // permissionMode: per-agent override (yolo|chorus only), else global posture.
410
+ let permissionMode = defaultPermissionMode;
411
+ if (entry.permissionMode !== undefined) {
412
+ const pm = nonEmptyStr(entry.permissionMode);
413
+ if (pm !== "yolo" && pm !== "chorus") {
414
+ throw new Error(
415
+ `Agent ${label}: invalid permissionMode "${entry.permissionMode}". Accepted: yolo, chorus.`,
416
+ );
417
+ }
418
+ permissionMode = pm;
419
+ }
420
+
421
+ // cwds: per-agent list (cleaned); an empty/blank list degrades to [undefined]
422
+ // (serve the process cwd). Omitted → inherit the top-level default set.
423
+ let cwds;
424
+ if (entry.cwds !== undefined) {
425
+ const cleaned = cleanCwdList(entry.cwds, home);
426
+ cwds = cleaned.length ? cleaned : [undefined];
427
+ } else {
428
+ cwds = defaultCwds;
429
+ }
430
+
431
+ const maxConcurrency = positiveInt(entry.maxConcurrency) ?? defaultMaxConcurrency;
432
+ const sigintTimeoutMs = positiveIntMs(entry.sigintTimeoutMs) ?? defaultSigint;
433
+ const browseRoots =
434
+ entry.browseRoots !== undefined ? cleanCwdList(entry.browseRoots, home) : defaultBrowseRoots;
435
+
436
+ return { url, apiKey, agentType, cwds, permissionMode, maxConcurrency, sigintTimeoutMs, browseRoots, label };
437
+ });
438
+ }
@@ -23,7 +23,7 @@
23
23
 
24
24
  import { homedir } from "node:os";
25
25
  import { resolveCredentials, loginFilePath } from "./credentials.mjs";
26
- import { updateDaemonConfig, prompt as defaultPrompt } from "./login.mjs";
26
+ import { updateDaemonConfig, appendAgentConfig, prompt as defaultPrompt } from "./login.mjs";
27
27
  import { validateAndFetchIdentity } from "./chorus-client.mjs";
28
28
  import { normalizeCwd, cleanCwdList } from "./daemon-config.mjs";
29
29
  import { KNOWN_AGENTS, DEFAULT_AGENT } from "./daemon-agent.mjs";
@@ -132,6 +132,43 @@ export async function resolveInstallCredentials(flags = {}, env = {}, opts = {})
132
132
  // field-merge writer preserves cwds / yoloAckAt / sigintTimeoutMs.
133
133
  writeConfig({ url, apiKey, agentUuid: identity.uuid, agentName: identity.name });
134
134
  log(`[Chorus] credentials saved for ${identity.name} (${identity.uuid}).`);
135
+
136
+ // Multi-agent (daemon-multi-agent): with `--add` on a TTY, offer to add more
137
+ // agents in the same run. Each additional key is validated then APPENDED to
138
+ // agents[] (the first agent above is folded into agents[0] on the first
139
+ // append). Opt-in via --add so a plain install prompts for nothing extra;
140
+ // never runs on a non-TTY / --yes / skip run. Hand-editing daemon.json remains
141
+ // fully supported regardless.
142
+ if (isTTY && !skip && flags.add === true) {
143
+ const appendAgent = opts.appendAgent ?? appendAgentConfig;
144
+ // Bound the loop so a stuck/looping prompt can never spin forever.
145
+ for (let added = 0; added < 32; added += 1) {
146
+ const more = nonEmpty(await ask("Add another agent? [y/N]: "));
147
+ if (!more || !/^y(es)?$/i.test(more)) break;
148
+ const u = nonEmpty(await ask(" Chorus URL: "));
149
+ const k = nonEmpty(await ask(" Chorus API key (cho_...): ", { mask: true }));
150
+ if (!u || !k) {
151
+ errLog("[Chorus] both a URL and an API key are required — skipping this agent.");
152
+ continue;
153
+ }
154
+ let id;
155
+ try {
156
+ id = await validate({ url: u, apiKey: k });
157
+ } catch (err) {
158
+ errLog(
159
+ `[Chorus] validation failed: ${err instanceof Error ? err.message : String(err)} — this agent was NOT added.`,
160
+ );
161
+ continue;
162
+ }
163
+ const res = appendAgent({ url: u, apiKey: k, agentUuid: id.uuid, agentName: id.name });
164
+ if (!res.ok) {
165
+ errLog(`[Chorus] agent ${id.name} (${id.uuid}) is already configured — skipping.`);
166
+ continue;
167
+ }
168
+ log(`[Chorus] added agent ${id.name} (${id.uuid}) — this daemon now serves ${res.agents.length} agents.`);
169
+ }
170
+ }
171
+
135
172
  return { ok: true, creds: { url, apiKey }, identity };
136
173
  }
137
174
 
package/cli/daemon.mjs CHANGED
@@ -47,7 +47,13 @@ import { createInterruptReporter } from "./interrupt-reporter.mjs";
47
47
  import { createTurnReporter } from "./turn-reporter.mjs";
48
48
  import { createDaemonRestClient } from "./daemon-rest-client.mjs";
49
49
  import { createControlHandler } from "./control-handler.mjs";
50
- import { resolveSigintTimeoutMs, resolveDaemonCwds, resolveBrowseRoots } from "./daemon-config.mjs";
50
+ import {
51
+ resolveSigintTimeoutMs,
52
+ resolveDaemonCwds,
53
+ resolveBrowseRoots,
54
+ resolveAgentConfigs,
55
+ hasConfiguredAgents,
56
+ } from "./daemon-config.mjs";
51
57
  import { discoverDirectories, validateDirectory } from "./directory-discovery.mjs";
52
58
  import {
53
59
  startBackground,
@@ -544,6 +550,122 @@ export function buildDaemon(creds, deps = {}) {
544
550
  };
545
551
  }
546
552
 
553
+ /**
554
+ * Fan-out builder: compose ONE `buildDaemon` runtime per agent config, so a single
555
+ * daemon process serves N fully-independent agents — each with its own creds,
556
+ * ChorusClient, LineageResolver, spawner (by its `agentType`), WakeQueue (its own
557
+ * `maxConcurrency`), and connections over its OWN cwds. For N=1 this is behaviorally
558
+ * identical to `buildDaemon({url,apiKey}, deps)`.
559
+ *
560
+ * Each agent's runtime is isolated: a build/start failure in one agent is logged and
561
+ * skipped, and the others keep serving. The aggregate `allConflict` settles only when
562
+ * EVERY agent's paths are all already served (nothing left to do at all).
563
+ *
564
+ * Injectable seams mirror `buildDaemon`; array-valued deps (`spawner`, `mcpClient`,
565
+ * `lineage`, `sseListener`, `makeSseListener`) are indexed PER agent for tests.
566
+ *
567
+ * @param {import("./daemon-config.mjs").AgentConfig[]} agentConfigs
568
+ * @param {object} [deps]
569
+ * @returns {{ agents: Array<{cfg: any, daemon: any}>, connections: any[],
570
+ * waker: any, router: any, sseListener: any, allConflict: Promise<void>,
571
+ * start: () => Promise<void>, stop: () => Promise<void> }}
572
+ */
573
+ export function buildMultiAgentDaemon(agentConfigs, deps = {}) {
574
+ const logger = deps.logger ?? defaultLogger();
575
+ if (!Array.isArray(agentConfigs) || agentConfigs.length === 0) {
576
+ throw new Error("buildMultiAgentDaemon: at least one agent config is required");
577
+ }
578
+ const build = deps.build ?? buildDaemon;
579
+ const perAgent = (key, i) => {
580
+ const v = deps[key];
581
+ return Array.isArray(v) ? v[i] : i === 0 ? v : undefined;
582
+ };
583
+
584
+ const agents = agentConfigs
585
+ .map((cfg, i) => {
586
+ // Per-agent deps: cfg fields drive the per-agent runtime; injectable fakes are
587
+ // indexed per agent. `cwd` (singular) is cleared so a caller's single value can
588
+ // never leak across agents — each agent's `cwds` is authoritative.
589
+ const agentDeps = {
590
+ ...deps,
591
+ logger,
592
+ permissionMode: cfg.permissionMode,
593
+ agentType: cfg.agentType,
594
+ cwds: cfg.cwds,
595
+ cwd: undefined,
596
+ maxConcurrency: cfg.maxConcurrency,
597
+ sigintTimeoutMs: cfg.sigintTimeoutMs,
598
+ browseRoots: cfg.browseRoots,
599
+ mcpClient: perAgent("mcpClient", i),
600
+ lineage: perAgent("lineage", i),
601
+ spawner: perAgent("spawner", i),
602
+ sseListener: perAgent("sseListener", i),
603
+ makeSseListener: Array.isArray(deps.makeSseListener)
604
+ ? deps.makeSseListener[i]
605
+ : deps.makeSseListener,
606
+ };
607
+ try {
608
+ return { cfg, daemon: build({ url: cfg.url, apiKey: cfg.apiKey }, agentDeps) };
609
+ } catch (err) {
610
+ logger.error?.(
611
+ `[Chorus] agent ${cfg.label}: failed to build runtime — skipping ` +
612
+ `(${err instanceof Error ? err.message : String(err)})`,
613
+ );
614
+ return null;
615
+ }
616
+ })
617
+ .filter(Boolean);
618
+
619
+ if (agents.length === 0) {
620
+ throw new Error("buildMultiAgentDaemon: all agent runtimes failed to build");
621
+ }
622
+
623
+ const connections = agents.flatMap((a) => a.daemon.connections ?? []);
624
+ const primary = agents[0].daemon;
625
+ // Aggregate all-conflict: settles only when EVERY agent's paths are all already
626
+ // served by a live daemon (each agent's allConflict settles only in that case, and
627
+ // never otherwise). A single serving agent keeps the whole daemon alive.
628
+ const allConflict = Promise.all(
629
+ agents.map((a) => a.daemon.allConflict ?? new Promise(() => {})),
630
+ ).then(() => {});
631
+
632
+ return {
633
+ agents,
634
+ connections,
635
+ // Back-compat single aliases (first agent's primary connection) for inspection.
636
+ waker: primary.waker,
637
+ router: primary.router,
638
+ sseListener: primary.sseListener,
639
+ allConflict,
640
+ async start() {
641
+ // Start each agent independently; one agent's start failure is logged and
642
+ // isolated so the others still serve.
643
+ for (const a of agents) {
644
+ try {
645
+ await a.daemon.start();
646
+ } catch (err) {
647
+ logger.error?.(
648
+ `[Chorus] agent ${a.cfg.label}: start failed — ` +
649
+ `${err instanceof Error ? err.message : String(err)} (other agents continue)`,
650
+ );
651
+ }
652
+ }
653
+ },
654
+ async stop() {
655
+ for (const a of agents) {
656
+ try {
657
+ await a.daemon.stop();
658
+ } catch (err) {
659
+ logger.warn?.(
660
+ `[Chorus] agent ${a.cfg.label}: stop error — ` +
661
+ `${err instanceof Error ? err.message : String(err)}`,
662
+ );
663
+ }
664
+ }
665
+ },
666
+ };
667
+ }
668
+
547
669
  /**
548
670
  * Entry point for `chorus daemon`. Resolves credentials, validates them
549
671
  * (echoing the agent identity), and runs the daemon until terminated.
@@ -650,6 +772,105 @@ export async function runDaemon(flags = {}, deps = {}) {
650
772
  const cwds = resolveDaemonCwds({ cwd: flags.cwd }, { env });
651
773
  const browseRoots = resolveBrowseRoots({ browseRoot: flags.browseRoot }, { env });
652
774
 
775
+ // ===== Multi-agent mode (daemon-multi-agent) =====
776
+ // When daemon.json declares a non-empty agents[], run N fully-independent agents in
777
+ // one process. Each agent carries its OWN creds, so this bypasses the flat single-
778
+ // credential preflight (interactive credential completion is a single-agent
779
+ // affordance). Each agent authenticates on its own key; a failure is isolated
780
+ // (logged + that agent skipped) so the rest still serve.
781
+ if (hasConfiguredAgents({ readJson: deps.readJson, loginPath: deps.loginPath })) {
782
+ const buildMulti = deps.buildMulti ?? buildMultiAgentDaemon;
783
+ let agentConfigs;
784
+ try {
785
+ agentConfigs = resolveAgentConfigs(
786
+ {
787
+ url: flags.url,
788
+ apiKey: flags.apiKey,
789
+ agent: flags.agent,
790
+ cwd: flags.cwd,
791
+ browseRoot: flags.browseRoot,
792
+ sigintTimeout: flags.sigintTimeout,
793
+ chorusOnly: flags.chorusOnly,
794
+ yolo: flags.yolo,
795
+ },
796
+ { env, readJson: deps.readJson, loginPath: deps.loginPath },
797
+ );
798
+ } catch (err) {
799
+ errLog(`[Chorus] ${err instanceof Error ? err.message : String(err)}`);
800
+ return 1;
801
+ }
802
+
803
+ // Validate each agent independently. A validation failure logs + skips that agent
804
+ // (isolation) — the daemon still serves the agents that authenticated.
805
+ const okConfigs = [];
806
+ for (const cfg of agentConfigs) {
807
+ try {
808
+ const id = await validate({ url: cfg.url, apiKey: cfg.apiKey });
809
+ okConfigs.push(cfg);
810
+ log(
811
+ `[Chorus] agent ${cfg.label}: ${id.name} (${id.uuid}) — ${cfg.agentType}, ` +
812
+ `${cfg.permissionMode}, ${cfg.cwds.length} path(s), maxConcurrency=${cfg.maxConcurrency}`,
813
+ );
814
+ if (cfg.permissionMode === "yolo") errLog(`[Chorus] agent ${cfg.label}: ${yoloWarningLine()}`);
815
+ } catch (err) {
816
+ errLog(
817
+ `[Chorus] agent ${cfg.label}: credential validation failed — ` +
818
+ `${err instanceof Error ? err.message : String(err)} (skipping this agent)`,
819
+ );
820
+ }
821
+ }
822
+ if (okConfigs.length === 0) {
823
+ errLog(
824
+ `[Chorus] no agents authenticated — nothing to serve. Check the apiKeys in ${loginFilePath()}.`,
825
+ );
826
+ return 1;
827
+ }
828
+
829
+ const totalPaths = okConfigs.reduce((n, c) => n + c.cwds.length, 0);
830
+ log(
831
+ `[Chorus] multi-agent daemon starting — ${okConfigs.length} agent(s), ` +
832
+ `${totalPaths} connection(s), subscribing to ${okConfigs[0].url}/api/events/notifications`,
833
+ );
834
+ const multiDaemon = buildMulti(okConfigs, {
835
+ logger: { info: log, warn: errLog, error: errLog },
836
+ verbose,
837
+ fetchImpl: deps.fetchImpl,
838
+ killer: deps.killer,
839
+ sseListener: deps.sseListener,
840
+ makeSseListener: deps.makeSseListener,
841
+ spawner: deps.spawner,
842
+ mcpClient: deps.mcpClient,
843
+ lineage: deps.lineage,
844
+ build: deps.build,
845
+ });
846
+
847
+ const shutdownMulti = () => {
848
+ log("[Chorus] shutting down daemon...");
849
+ Promise.resolve(multiDaemon.stop()).finally(() => process.exit(0));
850
+ };
851
+ process.on("SIGINT", shutdownMulti);
852
+ process.on("SIGTERM", shutdownMulti);
853
+ await multiDaemon.start();
854
+ log("[Chorus] multi-agent daemon running. Waiting for task dispatches (Ctrl+C to stop).");
855
+
856
+ const ALL_CONFLICT_M = Symbol("all-conflict");
857
+ const waitForeverM = deps.waitForever ?? (() => new Promise(() => {}));
858
+ const allConflictSignalM = multiDaemon.allConflict ?? new Promise(() => {});
859
+ const outcomeM = await Promise.race([
860
+ waitForeverM().then(() => 0),
861
+ allConflictSignalM.then(() => ALL_CONFLICT_M),
862
+ ]);
863
+ if (outcomeM === ALL_CONFLICT_M) {
864
+ errLog(
865
+ `[Chorus] every declared path for every agent is already served by a live daemon — ` +
866
+ `nothing to do. Stop the other daemon(s) or remove the conflicting path(s), then restart.`,
867
+ );
868
+ await multiDaemon.stop();
869
+ return 1;
870
+ }
871
+ return 0;
872
+ }
873
+
653
874
  // Foreground preflight: resolve/complete credentials + resolve the permission
654
875
  // posture (confirming yolo on a TTY). Reuses the same pfDeps bundle the detach
655
876
  // path uses. Returns a numeric exit code on failure, or