@chorus-aidlc/chorus 0.17.3 → 0.18.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 (457) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-build-manifest.json +345 -341
  3. package/.next/standalone/.next/app-path-routes-manifest.json +35 -35
  4. package/.next/standalone/.next/build-manifest.json +5 -5
  5. package/.next/standalone/.next/prerender-manifest.json +27 -27
  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.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page.js +2 -2
  20. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page_client-reference-manifest.js +1 -1
  21. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page.js +2 -2
  22. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js +2 -2
  25. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page_client-reference-manifest.js +1 -1
  27. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page.js +2 -2
  28. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page_client-reference-manifest.js +1 -1
  30. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page.js +2 -2
  31. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page.js +1 -1
  33. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page.js +1 -1
  36. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page_client-reference-manifest.js +1 -1
  38. package/.next/standalone/.next/server/app/(dashboard)/projects/page.js +1 -1
  39. package/.next/standalone/.next/server/app/(dashboard)/projects/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/(dashboard)/projects/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/(dashboard)/settings/page.js +2 -2
  42. package/.next/standalone/.next/server/app/(dashboard)/settings/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  46. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  47. package/.next/standalone/.next/server/app/admin/companies/[uuid]/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/admin/companies/new/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/admin/companies/new.html +2 -2
  50. package/.next/standalone/.next/server/app/admin/companies/new.rsc +2 -2
  51. package/.next/standalone/.next/server/app/admin/companies/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/admin/companies.html +2 -2
  53. package/.next/standalone/.next/server/app/admin/companies.rsc +2 -2
  54. package/.next/standalone/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/admin.html +2 -2
  56. package/.next/standalone/.next/server/app/admin.rsc +2 -2
  57. package/.next/standalone/.next/server/app/api/admin/companies/[uuid]/route_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/api/admin/companies/route_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/app/api/admin/login/route_client-reference-manifest.js +1 -1
  60. package/.next/standalone/.next/server/app/api/admin/session/route_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/api/agent-connections/route.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/api/agent-connections/route_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/api/agents/[uuid]/route_client-reference-manifest.js +1 -1
  64. package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route.js +1 -1
  65. package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/api/agents/route_client-reference-manifest.js +1 -1
  68. package/.next/standalone/.next/server/app/api/api-keys/[uuid]/route_client-reference-manifest.js +1 -1
  69. package/.next/standalone/.next/server/app/api/api-keys/route_client-reference-manifest.js +1 -1
  70. package/.next/standalone/.next/server/app/api/auth/callback/route_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/api/auth/check-default/route_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/api/auth/company-oidc/route_client-reference-manifest.js +1 -1
  73. package/.next/standalone/.next/server/app/api/auth/default-login/route_client-reference-manifest.js +1 -1
  74. package/.next/standalone/.next/server/app/api/auth/identify/route_client-reference-manifest.js +1 -1
  75. package/.next/standalone/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/api/auth/me/route_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/api/auth/sync-token/route_client-reference-manifest.js +1 -1
  78. package/.next/standalone/.next/server/app/api/comments/route.js +1 -1
  79. package/.next/standalone/.next/server/app/api/comments/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/comments/route_client-reference-manifest.js +1 -1
  81. package/.next/standalone/.next/server/app/api/daemon/connection-heartbeat/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/daemon/connection-heartbeat/route_client-reference-manifest.js +1 -1
  83. package/.next/standalone/.next/server/app/api/daemon/control/route.js +1 -1
  84. package/.next/standalone/.next/server/app/api/daemon/control/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/daemon/control/route_client-reference-manifest.js +1 -1
  86. package/.next/standalone/.next/server/app/api/daemon/directory-request/report/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/daemon/directory-request/report/route_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/api/daemon/execution-state/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/daemon/execution-state/route_client-reference-manifest.js +1 -1
  90. package/.next/standalone/.next/server/app/api/daemon/executions/route.js.nft.json +1 -1
  91. package/.next/standalone/.next/server/app/api/daemon/executions/route_client-reference-manifest.js +1 -1
  92. package/.next/standalone/.next/server/app/api/daemon/pending-turns/route.js +1 -1
  93. package/.next/standalone/.next/server/app/api/daemon/pending-turns/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/daemon/pending-turns/route_client-reference-manifest.js +1 -1
  95. package/.next/standalone/.next/server/app/api/daemon/report-interrupt/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/daemon/report-interrupt/route_client-reference-manifest.js +1 -1
  97. package/.next/standalone/.next/server/app/api/daemon/resume/route.js +1 -1
  98. package/.next/standalone/.next/server/app/api/daemon/resume/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/daemon/resume/route_client-reference-manifest.js +1 -1
  100. package/.next/standalone/.next/server/app/api/daemon/transcript/route.js +1 -1
  101. package/.next/standalone/.next/server/app/api/daemon/transcript/route.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/api/daemon/transcript/route_client-reference-manifest.js +1 -1
  103. package/.next/standalone/.next/server/app/api/daemon/turn-advance/route.js +1 -1
  104. package/.next/standalone/.next/server/app/api/daemon/turn-advance/route.js.nft.json +1 -1
  105. package/.next/standalone/.next/server/app/api/daemon/turn-advance/route_client-reference-manifest.js +1 -1
  106. package/.next/standalone/.next/server/app/api/daemon-directory-requests/[uuid]/route.js.nft.json +1 -1
  107. package/.next/standalone/.next/server/app/api/daemon-directory-requests/[uuid]/route_client-reference-manifest.js +1 -1
  108. package/.next/standalone/.next/server/app/api/daemon-directory-requests/route.js.nft.json +1 -1
  109. package/.next/standalone/.next/server/app/api/daemon-directory-requests/route_client-reference-manifest.js +1 -1
  110. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route.js +1 -1
  111. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route_client-reference-manifest.js +1 -1
  113. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route.js +1 -1
  114. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route.js.nft.json +1 -1
  115. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route_client-reference-manifest.js +1 -1
  116. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route.js +1 -1
  117. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route_client-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route.js +1 -1
  120. package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route.js.nft.json +1 -1
  121. package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route_client-reference-manifest.js +1 -1
  122. package/.next/standalone/.next/server/app/api/daemon-sessions/route.js +1 -1
  123. package/.next/standalone/.next/server/app/api/daemon-sessions/route.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/api/daemon-sessions/route_client-reference-manifest.js +1 -1
  125. package/.next/standalone/.next/server/app/api/documents/[uuid]/route_client-reference-manifest.js +1 -1
  126. package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route.js +1 -1
  127. package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route_client-reference-manifest.js +1 -1
  129. package/.next/standalone/.next/server/app/api/events/notifications/route.js +1 -1
  130. package/.next/standalone/.next/server/app/api/events/notifications/route.js.nft.json +1 -1
  131. package/.next/standalone/.next/server/app/api/events/notifications/route_client-reference-manifest.js +1 -1
  132. package/.next/standalone/.next/server/app/api/events/route.js +1 -1
  133. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
  135. package/.next/standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  136. package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route.js +1 -1
  137. package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route.js.nft.json +1 -1
  138. package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route_client-reference-manifest.js +1 -1
  139. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route.js +1 -1
  140. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route.js.nft.json +1 -1
  141. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route_client-reference-manifest.js +1 -1
  142. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route.js +1 -1
  143. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route_client-reference-manifest.js +1 -1
  145. package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route.js +1 -1
  146. package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route.js.nft.json +1 -1
  147. package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route_client-reference-manifest.js +1 -1
  148. package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route.js +1 -1
  149. package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route_client-reference-manifest.js +1 -1
  151. package/.next/standalone/.next/server/app/api/ideas/[uuid]/route.js +1 -1
  152. package/.next/standalone/.next/server/app/api/ideas/[uuid]/route.js.nft.json +1 -1
  153. package/.next/standalone/.next/server/app/api/ideas/[uuid]/route_client-reference-manifest.js +1 -1
  154. package/.next/standalone/.next/server/app/api/ideas/[uuid]/wake-preview/route.js.nft.json +1 -1
  155. package/.next/standalone/.next/server/app/api/ideas/[uuid]/wake-preview/route_client-reference-manifest.js +1 -1
  156. package/.next/standalone/.next/server/app/api/ideas/conversational/route.js +1 -1
  157. package/.next/standalone/.next/server/app/api/ideas/conversational/route.js.nft.json +1 -1
  158. package/.next/standalone/.next/server/app/api/ideas/conversational/route_client-reference-manifest.js +1 -1
  159. package/.next/standalone/.next/server/app/api/mcp/route.js +1 -1
  160. package/.next/standalone/.next/server/app/api/mcp/route.js.nft.json +1 -1
  161. package/.next/standalone/.next/server/app/api/mcp/route_client-reference-manifest.js +1 -1
  162. package/.next/standalone/.next/server/app/api/me/assignments/route.js +1 -1
  163. package/.next/standalone/.next/server/app/api/me/assignments/route.js.nft.json +1 -1
  164. package/.next/standalone/.next/server/app/api/me/assignments/route_client-reference-manifest.js +1 -1
  165. package/.next/standalone/.next/server/app/api/mentionables/route.js +1 -1
  166. package/.next/standalone/.next/server/app/api/mentionables/route.js.nft.json +1 -1
  167. package/.next/standalone/.next/server/app/api/mentionables/route_client-reference-manifest.js +1 -1
  168. package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route.js +1 -1
  169. package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route.js.nft.json +1 -1
  170. package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route_client-reference-manifest.js +1 -1
  171. package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route.js +1 -1
  172. package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route.js.nft.json +1 -1
  173. package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route_client-reference-manifest.js +1 -1
  174. package/.next/standalone/.next/server/app/api/notifications/preferences/route.js +1 -1
  175. package/.next/standalone/.next/server/app/api/notifications/preferences/route.js.nft.json +1 -1
  176. package/.next/standalone/.next/server/app/api/notifications/preferences/route_client-reference-manifest.js +1 -1
  177. package/.next/standalone/.next/server/app/api/notifications/read-all/route.js +1 -1
  178. package/.next/standalone/.next/server/app/api/notifications/read-all/route.js.nft.json +1 -1
  179. package/.next/standalone/.next/server/app/api/notifications/read-all/route_client-reference-manifest.js +1 -1
  180. package/.next/standalone/.next/server/app/api/notifications/route.js +1 -1
  181. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  183. package/.next/standalone/.next/server/app/api/notifications/unread-count/route.js +1 -1
  184. package/.next/standalone/.next/server/app/api/notifications/unread-count/route.js.nft.json +1 -1
  185. package/.next/standalone/.next/server/app/api/notifications/unread-count/route_client-reference-manifest.js +1 -1
  186. package/.next/standalone/.next/server/app/api/project-groups/[uuid]/dashboard/route_client-reference-manifest.js +1 -1
  187. package/.next/standalone/.next/server/app/api/project-groups/[uuid]/route_client-reference-manifest.js +1 -1
  188. package/.next/standalone/.next/server/app/api/project-groups/route_client-reference-manifest.js +1 -1
  189. package/.next/standalone/.next/server/app/api/project-visits/pin/route_client-reference-manifest.js +1 -1
  190. package/.next/standalone/.next/server/app/api/project-visits/route_client-reference-manifest.js +1 -1
  191. package/.next/standalone/.next/server/app/api/project-visits/visit/route_client-reference-manifest.js +1 -1
  192. package/.next/standalone/.next/server/app/api/projects/[uuid]/activity/route_client-reference-manifest.js +1 -1
  193. package/.next/standalone/.next/server/app/api/projects/[uuid]/agent-cwds/route.js.nft.json +1 -1
  194. package/.next/standalone/.next/server/app/api/projects/[uuid]/agent-cwds/route_client-reference-manifest.js +1 -1
  195. package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route.js +1 -1
  196. package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route.js.nft.json +1 -1
  197. package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route_client-reference-manifest.js +1 -1
  198. package/.next/standalone/.next/server/app/api/projects/[uuid]/documents/route_client-reference-manifest.js +1 -1
  199. package/.next/standalone/.next/server/app/api/projects/[uuid]/group/route_client-reference-manifest.js +1 -1
  200. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route.js +1 -1
  201. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route.js.nft.json +1 -1
  202. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route_client-reference-manifest.js +1 -1
  203. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route.js +1 -1
  204. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route.js.nft.json +1 -1
  205. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route_client-reference-manifest.js +1 -1
  206. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/[proposalUuid]/validate/route_client-reference-manifest.js +1 -1
  207. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/route_client-reference-manifest.js +1 -1
  208. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/summary/route_client-reference-manifest.js +1 -1
  209. package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route.js +1 -1
  210. package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route.js.nft.json +1 -1
  211. package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route_client-reference-manifest.js +1 -1
  212. package/.next/standalone/.next/server/app/api/projects/[uuid]/route_client-reference-manifest.js +1 -1
  213. package/.next/standalone/.next/server/app/api/projects/[uuid]/stats/route_client-reference-manifest.js +1 -1
  214. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route.js +1 -1
  215. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route.js.nft.json +1 -1
  216. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route_client-reference-manifest.js +1 -1
  217. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route.js +1 -1
  218. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route.js.nft.json +1 -1
  219. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route_client-reference-manifest.js +1 -1
  220. package/.next/standalone/.next/server/app/api/projects/agent-cwd-options/route.js.nft.json +1 -1
  221. package/.next/standalone/.next/server/app/api/projects/agent-cwd-options/route_client-reference-manifest.js +1 -1
  222. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  223. package/.next/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  224. package/.next/standalone/.next/server/app/api/proposals/[uuid]/approve/route_client-reference-manifest.js +1 -1
  225. package/.next/standalone/.next/server/app/api/proposals/[uuid]/close/route_client-reference-manifest.js +1 -1
  226. package/.next/standalone/.next/server/app/api/proposals/[uuid]/reject/route_client-reference-manifest.js +1 -1
  227. package/.next/standalone/.next/server/app/api/proposals/[uuid]/revoke/route_client-reference-manifest.js +1 -1
  228. package/.next/standalone/.next/server/app/api/proposals/[uuid]/route_client-reference-manifest.js +1 -1
  229. package/.next/standalone/.next/server/app/api/references/[uuid]/route_client-reference-manifest.js +1 -1
  230. package/.next/standalone/.next/server/app/api/references/route_client-reference-manifest.js +1 -1
  231. package/.next/standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  232. package/.next/standalone/.next/server/app/api/session/route_client-reference-manifest.js +1 -1
  233. package/.next/standalone/.next/server/app/api/sessions/[uuid]/route.js +1 -1
  234. package/.next/standalone/.next/server/app/api/sessions/[uuid]/route.js.nft.json +1 -1
  235. package/.next/standalone/.next/server/app/api/sessions/[uuid]/route_client-reference-manifest.js +1 -1
  236. package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route.js +1 -1
  237. package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route.js.nft.json +1 -1
  238. package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route_client-reference-manifest.js +1 -1
  239. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route.js +1 -1
  240. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route.js.nft.json +1 -1
  241. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route_client-reference-manifest.js +1 -1
  242. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route.js +1 -1
  243. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route.js.nft.json +1 -1
  244. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route_client-reference-manifest.js +1 -1
  245. package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route.js +1 -1
  246. package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route.js.nft.json +1 -1
  247. package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route_client-reference-manifest.js +1 -1
  248. package/.next/standalone/.next/server/app/api/tasks/[uuid]/route.js +1 -1
  249. package/.next/standalone/.next/server/app/api/tasks/[uuid]/route.js.nft.json +1 -1
  250. package/.next/standalone/.next/server/app/api/tasks/[uuid]/route_client-reference-manifest.js +1 -1
  251. package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route.js +1 -1
  252. package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route.js.nft.json +1 -1
  253. package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route_client-reference-manifest.js +1 -1
  254. package/.next/standalone/.next/server/app/index.html +2 -2
  255. package/.next/standalone/.next/server/app/index.rsc +2 -2
  256. package/.next/standalone/.next/server/app/login/admin/page_client-reference-manifest.js +1 -1
  257. package/.next/standalone/.next/server/app/login/admin.html +2 -2
  258. package/.next/standalone/.next/server/app/login/admin.rsc +2 -2
  259. package/.next/standalone/.next/server/app/login/callback/page_client-reference-manifest.js +1 -1
  260. package/.next/standalone/.next/server/app/login/callback.html +2 -2
  261. package/.next/standalone/.next/server/app/login/callback.rsc +2 -2
  262. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  263. package/.next/standalone/.next/server/app/login/pick-workspace/page_client-reference-manifest.js +1 -1
  264. package/.next/standalone/.next/server/app/login/pick-workspace.html +2 -2
  265. package/.next/standalone/.next/server/app/login/pick-workspace.rsc +2 -2
  266. package/.next/standalone/.next/server/app/login.html +2 -2
  267. package/.next/standalone/.next/server/app/login.rsc +2 -2
  268. package/.next/standalone/.next/server/app/onboarding/page.js +2 -2
  269. package/.next/standalone/.next/server/app/onboarding/page.js.nft.json +1 -1
  270. package/.next/standalone/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
  271. package/.next/standalone/.next/server/app/onboarding.html +2 -2
  272. package/.next/standalone/.next/server/app/onboarding.rsc +3 -3
  273. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  274. package/.next/standalone/.next/server/app/projects.html +2 -2
  275. package/.next/standalone/.next/server/app/projects.rsc +3 -3
  276. package/.next/standalone/.next/server/app/settings.html +2 -2
  277. package/.next/standalone/.next/server/app/settings.rsc +4 -4
  278. package/.next/standalone/.next/server/app-paths-manifest.json +35 -35
  279. package/.next/standalone/.next/server/chunks/1318.js +1 -1
  280. package/.next/standalone/.next/server/chunks/{5201.js → 1416.js} +2 -2
  281. package/.next/standalone/.next/server/chunks/1559.js +2 -2
  282. package/.next/standalone/.next/server/chunks/{3630.js → 2195.js} +1 -1
  283. package/.next/standalone/.next/server/chunks/2460.js +1 -0
  284. package/.next/standalone/.next/server/chunks/2572.js +2 -2
  285. package/.next/standalone/.next/server/chunks/2758.js +1 -0
  286. package/.next/standalone/.next/server/chunks/2961.js +1 -1
  287. package/.next/standalone/.next/server/chunks/3419.js +1 -1
  288. package/.next/standalone/.next/server/chunks/4066.js +1 -0
  289. package/.next/standalone/.next/server/chunks/4827.js +1 -1
  290. package/.next/standalone/.next/server/chunks/5245.js +1 -1
  291. package/.next/standalone/.next/server/chunks/5453.js +1 -1
  292. package/.next/standalone/.next/server/chunks/5489.js +1 -1
  293. package/.next/standalone/.next/server/chunks/6113.js +1 -1
  294. package/.next/standalone/.next/server/chunks/6506.js +2 -2
  295. package/.next/standalone/.next/server/chunks/6737.js +1 -0
  296. package/.next/standalone/.next/server/chunks/679.js +1 -1
  297. package/.next/standalone/.next/server/chunks/7368.js +1 -1
  298. package/.next/standalone/.next/server/chunks/7530.js +1 -1
  299. package/.next/standalone/.next/server/chunks/7578.js +2 -2
  300. package/.next/standalone/.next/server/chunks/7675.js +1 -0
  301. package/.next/standalone/.next/server/chunks/7789.js +1 -0
  302. package/.next/standalone/.next/server/chunks/{1201.js → 8030.js} +2 -2
  303. package/.next/standalone/.next/server/chunks/920.js +1 -1
  304. package/.next/standalone/.next/server/chunks/9213.js +1 -1
  305. package/.next/standalone/.next/server/chunks/9378.js +1 -1
  306. package/.next/standalone/.next/server/chunks/9931.js +1 -1
  307. package/.next/standalone/.next/server/instrumentation.js +1 -1
  308. package/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
  309. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  310. package/.next/standalone/.next/server/pages/404.html +2 -2
  311. package/.next/standalone/.next/server/pages/500.html +1 -1
  312. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  313. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  314. package/.next/standalone/.next/static/chunks/11595.f080a1d100972212.js +1 -0
  315. package/.next/standalone/.next/static/chunks/14628-283d3983d1fb36c9.js +1 -0
  316. package/.next/standalone/.next/static/chunks/{29305-f587e7e81bc0b200.js → 17562-56f932146e9e6c94.js} +4 -4
  317. package/.next/standalone/.next/static/chunks/25080-25ad29e64c855338.js +1 -0
  318. package/.next/standalone/.next/static/chunks/28698-7fb271ffc6e63a26.js +1 -0
  319. package/.next/standalone/.next/static/chunks/{95225-96b44da3ebd6ddad.js → 32736-aeaaa1e4c4d5529b.js} +1 -1
  320. package/.next/standalone/.next/static/chunks/33456.20313bd67a5c41cc.js +1 -0
  321. package/.next/standalone/.next/static/chunks/4860.3b555a398cdffb19.js +1 -0
  322. package/.next/standalone/.next/static/chunks/75257-99c0ce24b436847b.js +1 -0
  323. package/.next/standalone/.next/static/chunks/79919-0c6dcda1dd8646f0.js +1 -0
  324. package/.next/standalone/.next/static/chunks/91328-f501e3c3ca519a92.js +1 -0
  325. package/.next/standalone/.next/static/chunks/94643-e54eff17e941a93b.js +1 -0
  326. package/.next/standalone/.next/static/chunks/99373.b8a95d1bec5ad4e7.js +1 -0
  327. package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-f3c6431432d42c7c.js +1 -0
  328. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/{page-77b175e52a85f3cb.js → page-5d723f974bdad33b.js} +1 -1
  329. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-8d3b1f4d8b76d66c.js +1 -0
  330. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/page-57c698dea2fa6e29.js +1 -0
  331. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/{page-69d3162667f85677.js → page-d2bb622855e746f1.js} +1 -1
  332. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-fc255dc3612032b9.js +1 -0
  333. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/{page-a3f83031dfbafc81.js → page-f032ee8a80d1f56a.js} +1 -1
  334. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-46a0ddfd0421b0a8.js +1 -0
  335. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/{page-3c7ff3a40a4615ac.js → page-3a83748ce0ae1c4f.js} +1 -1
  336. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/{page-7b8e11fdc5b596d0.js → page-8af9bb9f96ab0258.js} +1 -1
  337. package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-b02939820affdae5.js +1 -0
  338. package/.next/standalone/.next/static/chunks/app/onboarding/page-d2c0c7951114e763.js +1 -0
  339. package/.next/standalone/.next/static/chunks/{webpack-dffb97a4feb8faba.js → webpack-de8a36d232a91d6b.js} +1 -1
  340. package/.next/standalone/.next/static/css/44f13b43a3de716d.css +1 -0
  341. package/.next/standalone/package.json +1 -1
  342. package/.next/standalone/public/chorus-plugin/.claude-plugin/plugin.json +2 -2
  343. package/.next/standalone/public/chorus-plugin/agents/code-reviewer.md +1 -0
  344. package/.next/standalone/public/chorus-plugin/agents/proposal-reviewer.md +12 -3
  345. package/.next/standalone/public/chorus-plugin/agents/task-reviewer.md +4 -0
  346. package/.next/standalone/public/chorus-plugin/bin/chorus-api.sh +1 -1
  347. package/.next/standalone/public/chorus-plugin/bin/on-post-submit-for-verify.sh +3 -3
  348. package/.next/standalone/public/chorus-plugin/bin/on-post-submit-proposal.sh +3 -3
  349. package/.next/standalone/public/chorus-plugin/bin/on-post-verify-task.sh +2 -2
  350. package/.next/standalone/public/chorus-plugin/bin/on-pre-spawn-agent.sh +22 -9
  351. package/.next/standalone/public/chorus-plugin/bin/on-session-start.sh +39 -64
  352. package/.next/standalone/public/chorus-plugin/bin/on-subagent-start.sh +44 -29
  353. package/.next/standalone/public/chorus-plugin/bin/on-subagent-stop.sh +100 -29
  354. package/.next/standalone/public/chorus-plugin/bin/resolve-spec-mode.sh +107 -0
  355. package/.next/standalone/public/chorus-plugin/bin/test-syntax.sh +6 -2
  356. package/.next/standalone/public/chorus-plugin/bin/tests/test-resolver-drift.sh +46 -0
  357. package/.next/standalone/public/chorus-plugin/bin/tests/test-skill-harness-fidelity-negative.sh +328 -0
  358. package/.next/standalone/public/chorus-plugin/bin/tests/test-skill-harness-fidelity.sh +372 -0
  359. package/.next/standalone/public/chorus-plugin/bin/tests/test-spec-mode-resolution.sh +83 -0
  360. package/.next/standalone/public/chorus-plugin/bin/tests/test-subagent-session-name.sh +599 -0
  361. package/.next/standalone/public/chorus-plugin/skills/brainstorm/SKILL.md +1 -1
  362. package/.next/standalone/public/chorus-plugin/skills/chorus/SKILL.md +11 -6
  363. package/.next/standalone/public/chorus-plugin/skills/chorus-cli/SKILL.md +1 -1
  364. package/.next/standalone/public/chorus-plugin/skills/develop/SKILL.md +14 -9
  365. package/.next/standalone/public/chorus-plugin/skills/docs/SKILL.md +1 -1
  366. package/.next/standalone/public/chorus-plugin/skills/idea/SKILL.md +1 -1
  367. package/.next/standalone/public/chorus-plugin/skills/openspec-aware/SKILL.md +27 -31
  368. package/.next/standalone/public/chorus-plugin/skills/orchestrate/SKILL.md +11 -1
  369. package/.next/standalone/public/chorus-plugin/skills/proposal/SKILL.md +14 -7
  370. package/.next/standalone/public/chorus-plugin/skills/quick-dev/SKILL.md +6 -4
  371. package/.next/standalone/public/chorus-plugin/skills/review/SKILL.md +10 -8
  372. package/.next/standalone/public/chorus-plugin/skills/spec-lite/SKILL.md +147 -0
  373. package/.next/standalone/public/chorus-plugin/skills/yolo/SKILL.md +49 -34
  374. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-code-reviewer.json +1 -1
  375. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-proposal-reviewer.json +2 -1
  376. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-task-reviewer.json +1 -1
  377. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus.md +1 -1
  378. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-brainstorm/SKILL.md +1 -1
  379. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-cli/SKILL.md +1 -1
  380. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-develop/SKILL.md +9 -7
  381. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-docs/SKILL.md +1 -1
  382. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-idea/SKILL.md +1 -1
  383. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-openspec-aware/SKILL.md +35 -27
  384. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-orchestrate/SKILL.md +9 -1
  385. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-proposal/SKILL.md +14 -7
  386. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-quick-dev/SKILL.md +2 -2
  387. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-review/SKILL.md +8 -8
  388. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-spec-lite/SKILL.md +147 -0
  389. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-yolo/SKILL.md +39 -25
  390. package/.next/standalone/public/kiro-plugin/.kiro/steering/chorus.md +11 -6
  391. package/.next/standalone/public/kiro-plugin/bin/chorus-api.sh +1 -1
  392. package/.next/standalone/public/kiro-plugin/bin/on-agent-spawn.sh +41 -0
  393. package/.next/standalone/public/kiro-plugin/bin/on-post-submit-for-verify.sh +3 -3
  394. package/.next/standalone/public/kiro-plugin/bin/on-post-submit-proposal.sh +3 -3
  395. package/.next/standalone/public/kiro-plugin/bin/on-post-verify-task.sh +2 -2
  396. package/.next/standalone/public/kiro-plugin/bin/resolve-spec-mode.sh +107 -0
  397. package/.next/standalone/public/kiro-plugin/manifest.txt +2 -0
  398. package/.next/standalone/public/skill/chorus/SKILL.md +11 -1
  399. package/.next/standalone/public/skill/code-reviewer-chorus/SKILL.md +1 -0
  400. package/.next/standalone/public/skill/develop-chorus/SKILL.md +1 -1
  401. package/.next/standalone/public/skill/orchestrate-chorus/SKILL.md +11 -1
  402. package/.next/standalone/public/skill/proposal-reviewer-chorus/SKILL.md +5 -2
  403. package/.next/standalone/public/skill/quick-dev-chorus/SKILL.md +1 -1
  404. package/.next/standalone/public/skill/review-chorus/SKILL.md +5 -3
  405. package/.next/standalone/public/skill/task-reviewer-chorus/SKILL.md +4 -0
  406. package/.next/standalone/public/skill/yolo-chorus/SKILL.md +23 -7
  407. package/README.ja.md +3 -3
  408. package/README.ko.md +3 -3
  409. package/README.md +3 -3
  410. package/README.zh.md +3 -3
  411. package/chorus.mjs +30 -2
  412. package/cli/agent-cli-config.mjs +323 -0
  413. package/cli/agent-launcher.mjs +44 -16
  414. package/cli/child-exit.mjs +77 -0
  415. package/cli/claude-spawner.mjs +26 -14
  416. package/cli/codex-spawner.mjs +27 -16
  417. package/cli/control-handler.mjs +104 -6
  418. package/cli/credentials.mjs +7 -0
  419. package/cli/daemon-config.mjs +14 -0
  420. package/cli/daemon-rest-client.mjs +98 -29
  421. package/cli/daemon.mjs +37 -7
  422. package/cli/dsh-managed-config.mjs +26 -28
  423. package/cli/dsh-spawner.mjs +27 -16
  424. package/cli/init/steps/credential-seed.mjs +1 -1
  425. package/cli/kiro-spawner.mjs +26 -16
  426. package/cli/launch-diagnostics.mjs +67 -0
  427. package/cli/login.mjs +17 -1
  428. package/cli/pi-spawner.mjs +23 -13
  429. package/cli/prompts.mjs +52 -2
  430. package/cli/spawner-select.mjs +6 -11
  431. package/package.json +1 -1
  432. package/.next/standalone/.next/server/chunks/1114.js +0 -1
  433. package/.next/standalone/.next/server/chunks/1155.js +0 -1
  434. package/.next/standalone/.next/server/chunks/6465.js +0 -1
  435. package/.next/standalone/.next/server/chunks/8105.js +0 -1
  436. package/.next/standalone/.next/server/chunks/8232.js +0 -1
  437. package/.next/standalone/.next/static/chunks/11595.f7c3ef5cd7fc8feb.js +0 -1
  438. package/.next/standalone/.next/static/chunks/33456.c81079032acc2966.js +0 -1
  439. package/.next/standalone/.next/static/chunks/45262-38b332523f00a223.js +0 -1
  440. package/.next/standalone/.next/static/chunks/46021-f5d072b0cbcb7fac.js +0 -1
  441. package/.next/standalone/.next/static/chunks/4860.f0cfb1201191ae88.js +0 -1
  442. package/.next/standalone/.next/static/chunks/66609-64a01d5cb415465b.js +0 -1
  443. package/.next/standalone/.next/static/chunks/79919-c5a2a3fd8f5f9204.js +0 -1
  444. package/.next/standalone/.next/static/chunks/94394-38194b81b489275c.js +0 -1
  445. package/.next/standalone/.next/static/chunks/94643-f1bdf37fb3bb6adb.js +0 -1
  446. package/.next/standalone/.next/static/chunks/96482-2b3bdb2544d72e5a.js +0 -1
  447. package/.next/standalone/.next/static/chunks/99373.3c23ac2efbd4db02.js +0 -1
  448. package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-66328332f62c7371.js +0 -1
  449. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-87ceae13c4950fc9.js +0 -1
  450. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/page-45e95154e546460e.js +0 -1
  451. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-b7b2017e5be69564.js +0 -1
  452. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-8b06834ca0f663bb.js +0 -1
  453. package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-efe5326c47aca9ca.js +0 -1
  454. package/.next/standalone/.next/static/chunks/app/onboarding/page-0ce33b9327fe3d8c.js +0 -1
  455. package/.next/standalone/.next/static/css/1d9cf83f50b6db00.css +0 -1
  456. /package/.next/standalone/.next/static/{wuqYN129vOIGymh_NEdZe → dot63ILT878Tloqi7Czj_}/_buildManifest.js +0 -0
  457. /package/.next/standalone/.next/static/{wuqYN129vOIGymh_NEdZe → dot63ILT878Tloqi7Czj_}/_ssgManifest.js +0 -0
@@ -27,10 +27,13 @@
27
27
  // stream parse) and the PATH-walk shape of resolveClaudePath.
28
28
 
29
29
  import { spawn } from "node:child_process";
30
+ import { safeSpawnError } from "./launch-diagnostics.mjs";
31
+ import { validateAgentCliConfig, overlayAgentEnv, getAgentEnv, assertConfiguredShimArgs } from "./agent-cli-config.mjs";
30
32
  import { readFileSync, statSync } from "node:fs";
31
33
  import { homedir } from "node:os";
32
34
  import { join, win32 as pathWin32, posix as pathPosix } from "node:path";
33
35
  import { parseNdjsonChunk } from "./claude-spawner.mjs";
36
+ import { awaitChildSettled } from "./child-exit.mjs";
34
37
  import { getThreadId as defaultGetThreadId, setThreadId as defaultSetThreadId } from "./codex-session-map.mjs";
35
38
  import {
36
39
  getCodexUsageSnapshot as defaultGetUsageSnapshot,
@@ -49,8 +52,9 @@ const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
49
52
  export function hasChorusMcpServer(deps = {}) {
50
53
  const env = deps.env ?? process.env;
51
54
  const readFile = deps.readFile ?? readFileSync;
52
- const home = deps.home ?? homedir();
53
- const configPath = join(env.CODEX_HOME || join(home, ".codex"), "config.toml");
55
+ const platform = deps.platform ?? process.platform;
56
+ const home = deps.home ?? getAgentEnv(env, "HOME", platform) ?? getAgentEnv(env, "USERPROFILE", platform) ?? homedir();
57
+ const configPath = join(getAgentEnv(env, "CODEX_HOME", platform) || join(home, ".codex"), "config.toml");
54
58
  try {
55
59
  const config = readFile(configPath, "utf8");
56
60
  return /^\s*\[mcp_servers\.chorus\]\s*(?:#.*)?$/m.test(config);
@@ -148,14 +152,15 @@ export function resolveCodexPath(deps = {}) {
148
152
  }
149
153
  });
150
154
 
151
- if (env.CHORUS_CODEX_PATH && isFile(env.CHORUS_CODEX_PATH)) {
152
- return env.CHORUS_CODEX_PATH;
155
+ const override = getAgentEnv(env, "CHORUS_CODEX_PATH", platform);
156
+ if (override && isFile(override)) {
157
+ return override;
153
158
  }
154
159
 
155
160
  const isWin = platform === "win32";
156
161
  const p = isWin ? pathWin32 : pathPosix;
157
162
  const names = isWin ? ["codex.cmd", "codex.exe", "codex"] : ["codex"];
158
- const pathVar = env.PATH || env.Path || "";
163
+ const pathVar = getAgentEnv(env, "PATH", platform) || env.Path || "";
159
164
  const dirs = pathVar.split(p.delimiter).filter(Boolean);
160
165
  for (const dir of dirs) {
161
166
  for (const name of names) {
@@ -178,7 +183,7 @@ export function resolveSpawnCommand(codexPath, args, platform = process.platform
178
183
  const isWin = platform === "win32";
179
184
  const lower = codexPath.toLowerCase();
180
185
  if (isWin && (lower.endsWith(".cmd") || lower.endsWith(".bat"))) {
181
- const comspec = env.ComSpec || env.COMSPEC || "cmd.exe";
186
+ const comspec = getAgentEnv(env, "COMSPEC", platform) || "cmd.exe";
182
187
  return { command: comspec, argv: ["/d", "/s", "/c", codexPath, ...args] };
183
188
  }
184
189
  return { command: codexPath, argv: args };
@@ -210,6 +215,8 @@ export class CodexSpawner {
210
215
  this.permissionMode = opts.permissionMode ?? "chorus";
211
216
  this.creds = opts.creds ?? null;
212
217
  this.platform = opts.platform ?? process.platform;
218
+ this.cliConfig = validateAgentCliConfig(opts.cliConfig, "codex", opts.label);
219
+ this.env = overlayAgentEnv(opts.env ?? process.env, this.cliConfig.env, this.platform);
213
220
  this.getThreadIdFn = opts.getThreadIdFn ?? defaultGetThreadId;
214
221
  this.setThreadIdFn = opts.setThreadIdFn ?? defaultSetThreadId;
215
222
  this.getUsageSnapshotFn = opts.getUsageSnapshotFn ?? defaultGetUsageSnapshot;
@@ -246,7 +253,7 @@ export class CodexSpawner {
246
253
  // instead of publishing the entire historical cumulative total.
247
254
  let needsUsageSeed = Boolean(knownThreadId && !previousUsage);
248
255
 
249
- const codexPath = this.codexPath ?? this.resolveCodexPathFn();
256
+ const codexPath = this.codexPath ?? this.resolveCodexPathFn({ env: this.env, platform: this.platform });
250
257
  if (!codexPath) {
251
258
  // No crash — surface visibly and resolve with a failure result.
252
259
  this.logger.error("[Chorus] cannot locate the `codex` executable on PATH; skipping wake");
@@ -255,15 +262,17 @@ export class CodexSpawner {
255
262
 
256
263
  if (!this.mcpConfigChecked) {
257
264
  this.mcpConfigChecked = true;
258
- if (!this.hasChorusMcpServerFn()) {
265
+ if (!this.hasChorusMcpServerFn({ env: this.env, platform: this.platform })) {
259
266
  this.logger.warn(
260
267
  "[Chorus] Codex config has no [mcp_servers.chorus] entry; wake will continue without Chorus MCP tools",
261
268
  );
262
269
  }
263
270
  }
264
271
 
265
- const args = buildCodexArgs({ isNew, threadId: knownThreadId, permissionMode: this.permissionMode });
266
- const { command, argv } = resolveSpawnCommand(codexPath, args, this.platform);
272
+ assertConfiguredShimArgs(codexPath, this.cliConfig.args, this.platform);
273
+ const args = [...buildCodexArgs({ isNew, threadId: knownThreadId, permissionMode: this.permissionMode }), ...this.cliConfig.args,
274
+ ...(this.cliConfig.args.length ? ["-"] : [])];
275
+ const { command, argv } = resolveSpawnCommand(codexPath, args, this.platform, this.env);
267
276
 
268
277
  // POSIX: detached process group so the interrupt path can group-kill the tree
269
278
  // (codex exec forks child shells for tools). Windows uses taskkill /T. stdio
@@ -273,7 +282,7 @@ export class CodexSpawner {
273
282
  // Export the daemon's resolved connection pair for both Codex MCP auth and
274
283
  // SessionStart hooks. Explicitly overwrite inherited values so the hook and
275
284
  // daemon cannot disagree about which Chorus instance this wake belongs to.
276
- const childEnv = { ...process.env, CHORUS_DAEMON_HEADLESS: "1" };
285
+ const childEnv = { ...this.env, CHORUS_DAEMON_HEADLESS: "1" };
277
286
  if (this.creds) {
278
287
  if (this.creds.url) childEnv.CHORUS_URL = this.creds.url;
279
288
  if (this.creds.apiKey) childEnv.CHORUS_API_KEY = this.creds.apiKey;
@@ -294,8 +303,8 @@ export class CodexSpawner {
294
303
  detached,
295
304
  windowsHide: true,
296
305
  });
297
- } catch (err) {
298
- this.logger.error(`[Chorus] failed to spawn codex: ${err}`);
306
+ } catch (error) {
307
+ this.logger.error(`[Chorus] failed to spawn codex: ${safeSpawnError(error)}`);
299
308
  resolve({ sessionId: anchor, backendSessionId: knownThreadId, exitCode: null, isNew });
300
309
  return;
301
310
  }
@@ -357,12 +366,14 @@ export class CodexSpawner {
357
366
  if (text) this.logger.warn(`[Chorus] codex stderr: ${text}`);
358
367
  });
359
368
 
360
- child.on("error", (err) => {
361
- this.logger.error(`[Chorus] codex process error: ${err}`);
369
+ child.on("error", (error) => {
370
+ this.logger.error(`[Chorus] codex process error: ${safeSpawnError(error)}`);
362
371
  resolve({ sessionId: anchor, backendSessionId: observedThreadId, exitCode: null, isNew });
363
372
  });
364
373
 
365
- child.on("close", (code) => {
374
+ // Settle on process exit, not only on stdio close: a detached descendant can
375
+ // inherit the pipes and keep `close` from ever firing (see cli/child-exit.mjs).
376
+ awaitChildSettled(child, { logger: this.logger, label: "codex" }).then((code) => {
366
377
  if (code !== 0) {
367
378
  this.logger.warn(`[Chorus] codex exited with code ${code}`);
368
379
  }
@@ -12,6 +12,17 @@
12
12
  // so a stale / recycled connection uuid can never make the daemon kill the wrong
13
13
  // subprocess (Tech Design "Risks": mis-kill after a reconnect).
14
14
  //
15
+ // When Check-2 fails for an `interrupt` (no live child here) the command is NOT
16
+ // silently dropped (fix-phantom-running-turn, Tech Design "D — a no-child interrupt
17
+ // reports the truth"): the handler logs the miss AND fire-and-forgets one
18
+ // `advanceTurn({ status: "interrupted", interruptedReason: "user" })` so a server-side
19
+ // `running` turn with no daemon child behind it converges instead of hanging forever.
20
+ // The session business key is derived without any lookup, and therefore only for the
21
+ // two control entity types where the derivation is an identity (`idea`,
22
+ // `daemon_session` → sessionId === entityUuid). `task` / `proposal` / `document` keep
23
+ // the pure-log behaviour: their session is anchored on the resource's DIRECT idea,
24
+ // which the daemon cannot resolve locally, and guessing would converge the wrong turn.
25
+ //
15
26
  // On a verified match it (a) sets a per-entity "interrupting" flag on the waker so
16
27
  // the waker reports the resulting exit as interrupted(reason="user") rather than a
17
28
  // crash, then (b) invokes the injected killer (process-killer.killProcessTree) on
@@ -25,6 +36,16 @@ import { killProcessTree } from "./process-killer.mjs";
25
36
 
26
37
  const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
27
38
 
39
+ /**
40
+ * Control entity types whose session business key is the entityUuid itself, so a
41
+ * no-child interrupt can report the turn terminal WITHOUT any REST lookup:
42
+ * • `idea` — the session anchor IS the direct idea uuid.
43
+ * • `daemon_session` — the ad-hoc session's own business id.
44
+ * Every other member of CONTROL_ENTITY_TYPES (`task`, `proposal`, `document`) is
45
+ * anchored on that resource's DIRECT idea, which is not derivable locally.
46
+ */
47
+ const SELF_ANCHORED_ENTITY_TYPES = new Set(["idea", "daemon_session"]);
48
+
28
49
  /**
29
50
  * Build the `onControl(event)` callback the SseListener invokes for a
30
51
  * `type:"control"` event.
@@ -56,6 +77,15 @@ const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
56
77
  * other still-pending turn along. Injected by the
57
78
  * daemon (`backfill.pendingTurnsOnly`); the
58
79
  * arg-less form (reconnect) still sweeps all.
80
+ * advanceTurn?: (params: { sessionId: string, status: string, interruptedReason?: string,
81
+ * entityType?: string|null, entityUuid?: string|null }) => any,
82
+ * The SAME `createTurnReporter(...)` instance the
83
+ * waker uses (injected by `cli/daemon.mjs`; no
84
+ * second transport, no new endpoint). Invoked
85
+ * fire-and-forget ONLY when an `interrupt` finds no
86
+ * live child for a self-anchored entity type, to
87
+ * close a server-side `running` turn that nothing
88
+ * else would ever close.
59
89
  * logger?: { info(m:string):void, warn(m:string):void, error(m:string):void },
60
90
  * }} deps
61
91
  * @returns {(event: any) => void} The onControl callback (synchronous, non-throwing).
@@ -67,6 +97,7 @@ export function createControlHandler(deps) {
67
97
  const sigintTimeoutMs = deps.sigintTimeoutMs;
68
98
  const redispatchResume = deps.redispatchResume;
69
99
  const deliverTurn = deps.deliverTurn;
100
+ const advanceTurn = deps.advanceTurn;
70
101
  const handleDirectoryRequest = deps.handleDirectoryRequest;
71
102
  const reportDirectoryRequest = deps.reportDirectoryRequest;
72
103
  const logger = deps.logger ?? NOOP_LOGGER;
@@ -202,11 +233,76 @@ export function createControlHandler(deps) {
202
233
  }
203
234
 
204
235
  // --- interrupt path: Check 2 — in-memory entity ownership (running child) ---
236
+ //
237
+ // The registry is keyed by the WAKE's own resource (`task:T`), while a
238
+ // conversation's control key is its session anchor (`idea:A`). A wake on a CHILD
239
+ // resource of idea A runs on session A (waker: `sessionId = directIdeaUuid`), so an
240
+ // `idea:A` interrupt must also find a running `task:T` / `proposal:P` / `document:D`
241
+ // entry whose `directIdeaUuid` is A — the same rule the UI's `executionMatchesSession`
242
+ // applies. Without this the exact-key lookup misses, we report a turn miss, the
243
+ // server's FIFO resolution grabs the SIBLING wake's `running` turn, and NOTHING is
244
+ // killed: the UI would say interrupted while the agent keeps working.
205
245
  const key = execKey(entityType, entityUuid);
206
- const entry = waker?.executions?.get(key);
246
+ let entry = waker?.executions?.get(key);
247
+ // The entity the kill actually targets — normally the command's own, but a sibling
248
+ // wake when the match below re-points it.
249
+ let killEntityType = entityType;
250
+ let killEntityUuid = entityUuid;
251
+ let killKey = key;
252
+ if ((!entry || entry.status !== "running" || !entry.child) && entityType === "idea") {
253
+ for (const candidate of waker?.executions?.values() ?? []) {
254
+ if (
255
+ candidate.status === "running" &&
256
+ candidate.child &&
257
+ candidate.directIdeaUuid === entityUuid
258
+ ) {
259
+ killEntityType = candidate.entityType;
260
+ killEntityUuid = candidate.entityUuid;
261
+ killKey = execKey(killEntityType, killEntityUuid);
262
+ logger.info(
263
+ `[Chorus] control: no direct child for ${key}, but sibling wake ${killKey} ` +
264
+ `runs on this session; interrupting that instead`
265
+ );
266
+ entry = candidate;
267
+ break;
268
+ }
269
+ }
270
+ }
207
271
  if (!entry || entry.status !== "running" || !entry.child) {
208
272
  // Either we never ran this entity, it's only queued (no child yet), or the
209
- // wake already finished (race: interrupt arrived after exit). Safe no-op.
273
+ // wake already finished (race: interrupt arrived after exit). There is nothing
274
+ // to kill — but the SERVER may still hold a `running` turn for this session
275
+ // that nothing else will ever close (the phantom-running-turn bug). Report it
276
+ // terminal so the UI converges. Only for the self-anchored entity types; for
277
+ // the rest we cannot know the session locally, so keep the old pure log.
278
+ if (SELF_ANCHORED_ENTITY_TYPES.has(entityType)) {
279
+ logger.info(
280
+ `[Chorus] control: no running subprocess for ${key} on this daemon; ` +
281
+ `reporting the turn as interrupted(user)`
282
+ );
283
+ // Fire-and-forget: createTurnReporter never throws and logs its own
284
+ // failures, but guard both the synchronous throw and the rejection so
285
+ // nothing escapes into the SSE loop. A server with no `running` turn
286
+ // answers not_found — a harmless no-op (losing race).
287
+ try {
288
+ Promise.resolve(
289
+ advanceTurn?.({
290
+ sessionId: entityUuid,
291
+ status: "interrupted",
292
+ interruptedReason: "user",
293
+ entityType,
294
+ entityUuid,
295
+ })
296
+ ).catch((err) => {
297
+ logger.warn(
298
+ `[Chorus] control: interrupted-turn report rejected for ${key}: ${err}`
299
+ );
300
+ });
301
+ } catch (err) {
302
+ logger.warn(`[Chorus] control: interrupted-turn report failed for ${key}: ${err}`);
303
+ }
304
+ return;
305
+ }
210
306
  logger.info(
211
307
  `[Chorus] control: no running subprocess for ${key} on this daemon; ignoring interrupt`
212
308
  );
@@ -215,18 +311,20 @@ export function createControlHandler(deps) {
215
311
 
216
312
  // --- Both checks passed: mark interrupting (so the waker reports reason=user),
217
313
  // then kill the tree. ---
218
- logger.info(`[Chorus] control: interrupting running subprocess for ${key} (pid=${entry.child.pid})`);
314
+ logger.info(`[Chorus] control: interrupting running subprocess for ${killKey} (pid=${entry.child.pid})`);
219
315
  try {
220
- waker.markInterrupting?.(entityType, entityUuid);
316
+ // Flag the entity whose wake we are actually killing — a sibling re-point must
317
+ // mark THAT wake interrupting, or its exit would be reported as a crash.
318
+ waker.markInterrupting?.(killEntityType, killEntityUuid);
221
319
  } catch (err) {
222
- logger.warn(`[Chorus] control: markInterrupting failed for ${key}: ${err}`);
320
+ logger.warn(`[Chorus] control: markInterrupting failed for ${killKey}: ${err}`);
223
321
  }
224
322
 
225
323
  // Fire-and-forget the kill: the waker observes the child's exit and reports
226
324
  // the interrupted state. The killer never throws, but guard the promise
227
325
  // anyway so a rejection can't surface as an unhandled rejection.
228
326
  Promise.resolve(killer(entry.child, { sigintTimeoutMs, logger })).catch((err) => {
229
- logger.warn(`[Chorus] control: killProcessTree rejected for ${key}: ${err}`);
327
+ logger.warn(`[Chorus] control: killProcessTree rejected for ${killKey}: ${err}`);
230
328
  });
231
329
  } catch (err) {
232
330
  // Absolute backstop — a control event must never crash the SSE loop.
@@ -19,6 +19,7 @@
19
19
  import { readFileSync } from "node:fs";
20
20
  import { homedir } from "node:os";
21
21
  import { join, resolve } from "node:path";
22
+ import { rejectSharedCliConfig } from "./agent-cli-config.mjs";
22
23
 
23
24
  /** Absolute path to the login file written by `chorus login`. */
24
25
  export function loginFilePath() {
@@ -425,6 +426,7 @@ export function resolveLaunchAgent(flags = {}, deps = {}) {
425
426
  const wanted = nonEmpty(flags.name) ?? nonEmpty(flags.agent) ?? nonEmpty(env.CHORUS_AGENT_PROFILE);
426
427
 
427
428
  const file = readJson(loginPath);
429
+ rejectSharedCliConfig(file);
428
430
  const agentEntries =
429
431
  file && Array.isArray(file.agents)
430
432
  ? file.agents.filter((a) => a && typeof a === "object")
@@ -448,6 +450,8 @@ export function resolveLaunchAgent(flags = {}, deps = {}) {
448
450
  agentUuid: nonEmpty(entry.agentUuid),
449
451
  agentName: nonEmpty(entry.agentName) ?? nonEmpty(entry.name),
450
452
  agentType: nonEmpty(entry.agentType),
453
+ args: entry.args,
454
+ env: entry.env,
451
455
  }));
452
456
  const labels = resolved.map((a) => a.label).join(", ");
453
457
 
@@ -479,6 +483,9 @@ export function resolveLaunchAgent(flags = {}, deps = {}) {
479
483
  agentUuid: selected.agentUuid,
480
484
  agentName: selected.agentName,
481
485
  agentType: selected.agentType,
486
+ // Validation uses the launcher's effective --type, not the stored classification.
487
+ args: selected.args,
488
+ env: selected.env,
482
489
  label: selected.label,
483
490
  };
484
491
  }
@@ -18,6 +18,14 @@ import { isAbsolute, resolve as resolvePath } from "node:path";
18
18
  import { loginFilePath, resolveCredentials, resolveCredentialDefaults } from "./credentials.mjs";
19
19
  import { resolveAgentType, KNOWN_AGENTS } from "./daemon-agent.mjs";
20
20
  import { resolvePermissionMode } from "./daemon-permission-mode.mjs";
21
+ import { rejectSharedCliConfig, validateAgentCliConfig } from "./agent-cli-config.mjs";
22
+
23
+ /** Read only the flat profile customization; also used by the legacy startup path. */
24
+ export function resolveFlatAgentCliConfig(type, deps = {}) {
25
+ const file = (deps.readJson ?? readJsonSafe)(deps.loginPath ?? loginFilePath());
26
+ rejectSharedCliConfig(file);
27
+ return validateAgentCliConfig(file ?? {}, type, "agent");
28
+ }
21
29
 
22
30
  /** Built-in default escalation window (ms) — matches the spec's 10 seconds. */
23
31
  export const DEFAULT_SIGINT_TIMEOUT_MS = 10_000;
@@ -307,6 +315,8 @@ function positiveInt(value) {
307
315
  * @property {string} url Chorus server URL for this agent.
308
316
  * @property {string} apiKey This agent's `cho_` API key.
309
317
  * @property {string} agentType Backend: claude-code | codex | kiro | dsh | offline.
318
+ * @property {string[]} args Literal extra backend arguments (per-agent only).
319
+ * @property {Record<string,string>} env Literal child environment overrides (per-agent only).
310
320
  * @property {boolean} [daemonWake] Wake opt-in for a wakeable backend; only
311
321
  * `false` disables (absent/true ⇒ woken).
312
322
  * @property {Array<string|undefined>} cwds Served paths (`undefined` ⇒ process cwd).
@@ -344,6 +354,8 @@ export function resolveAgentConfigs(flags = {}, deps = {}) {
344
354
  const home = deps.home ?? homedir();
345
355
  const file = readJson(loginPath);
346
356
 
357
+ rejectSharedCliConfig(file);
358
+
347
359
  // Global default permission posture; a per-agent `permissionMode` overrides it.
348
360
  // needConfirm/hasAck is vestigial, so isTTY/hasAck do not affect the resolved mode.
349
361
  const defaultPermissionMode =
@@ -365,6 +377,7 @@ export function resolveAgentConfigs(flags = {}, deps = {}) {
365
377
  url: creds.url,
366
378
  apiKey: creds.apiKey,
367
379
  agentType: at.agent,
380
+ ...validateAgentCliConfig(file ?? {}, at.agent, "agent"),
368
381
  cwds: resolveDaemonCwds(flags, deps),
369
382
  permissionMode: defaultPermissionMode,
370
383
  maxConcurrency: positiveInt(file?.maxConcurrency) ?? DEFAULT_MAX_CONCURRENCY,
@@ -449,6 +462,7 @@ export function resolveAgentConfigs(flags = {}, deps = {}) {
449
462
  url,
450
463
  apiKey,
451
464
  agentType,
465
+ ...validateAgentCliConfig(entry, agentType, label),
452
466
  cwds,
453
467
  permissionMode,
454
468
  maxConcurrency,
@@ -40,6 +40,26 @@
40
40
 
41
41
  const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
42
42
 
43
+ // Bounded retry policy for the TERMINAL turn-advance edge only (fix-phantom-running-turn).
44
+ // A lost terminal report is the one failure that leaves a permanently phantom `running`
45
+ // turn, so it — and only it — is worth retrying. Fixed constants on purpose: one more
46
+ // configuration knob buys nothing here.
47
+ const TERMINAL_TURN_ADVANCE_ATTEMPTS = 3;
48
+ const TERMINAL_TURN_ADVANCE_DELAYS_MS = [500, 2000];
49
+
50
+ /** Real-time delay; tests inject their own so they never sleep for real. */
51
+ const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
52
+
53
+ /**
54
+ * A failure is retryable when repeating it can plausibly succeed: a network-level failure
55
+ * (no HTTP response at all), a `429`, or any `5xx`. Every `4xx` is a server VERDICT
56
+ * (invalid_transition, not_found, auth) — repeating it cannot make it true.
57
+ * @param {number|null} status
58
+ */
59
+ function isRetryableFailure(status) {
60
+ return status === null || status === 429 || status >= 500;
61
+ }
62
+
43
63
  /**
44
64
  * @typedef {Object} DaemonRestResult
45
65
  * @property {boolean} ok True only on a 2xx response (and, for reads, a
@@ -70,6 +90,8 @@ const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
70
90
  * executionState, reportInterrupt, readPendingTurns)
71
91
  * require it; a null value skips the call (logged).
72
92
  * fetchImpl?: typeof fetch, Injectable for tests (defaults to global fetch).
93
+ * sleep?: (ms: number) => Promise<void>, Injectable retry delay (defaults to setTimeout).
94
+ * Only the terminal turn-advance edge retries.
73
95
  * logger?: { info(m:string):void, warn(m:string):void, error(m:string):void },
74
96
  * }} opts
75
97
  * @returns {{
@@ -88,6 +110,8 @@ export function createDaemonRestClient(opts) {
88
110
  const getConnectionUuid = opts.getConnectionUuid ?? (() => null);
89
111
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
90
112
  const logger = opts.logger ?? NOOP_LOGGER;
113
+ // Injectable retry delay so tests assert the schedule without spending real seconds.
114
+ const sleepImpl = opts.sleep ?? realSleep;
91
115
 
92
116
  const jsonHeaders = {
93
117
  Authorization: `Bearer ${apiKey}`,
@@ -111,41 +135,71 @@ export function createDaemonRestClient(opts) {
111
135
  * `<op> request failed` / `<op> returned <status>` core, so the
112
136
  * failing entity stays visible in the log without disturbing the
113
137
  * established op-prefixed message.
138
+ * @param {boolean} [readData] Parse the response envelope's `data` on success.
139
+ * @param {{ attempts: number, delaysMs: number[], sleep?: (ms: number) => Promise<void> }|null} [retry]
140
+ * Optional bounded retry policy. Absent/null = today's exact
141
+ * single-shot behaviour (used by every op but the terminal
142
+ * turn-advance edge).
114
143
  * @returns {Promise<DaemonRestResult>}
115
144
  */
116
- async function post(op, path, body, successLog, context = "", readData = false) {
117
- let response;
118
- try {
119
- response = await fetchImpl(`${url}${path}`, {
120
- method: "POST",
121
- headers: jsonHeaders,
122
- body: JSON.stringify(body),
123
- });
124
- } catch (err) {
125
- // Network-level failure (DNS, connection refused, abort, …). Surface WITH cause.
126
- const error = `${op} request failed${context}: ${err}`;
127
- logger.warn(`[Chorus] ${error}`);
128
- return { ok: false, status: null, error };
129
- }
130
- if (!response.ok) {
131
- // Non-2xx. Surface WITH the status so a 4xx/5xx is debuggable.
132
- const error = `${op} returned ${response.status}${context}`;
133
- logger.warn(`[Chorus] ${error}`);
134
- return { ok: false, status: response.status, error };
135
- }
136
- let data;
137
- if (readData) {
145
+ async function post(op, path, body, successLog, context = "", readData = false, retry = null) {
146
+ const attempts = retry ? retry.attempts : 1;
147
+ const delaysMs = retry?.delaysMs ?? [];
148
+ // Named distinctly from the module-closure `sleepImpl` so this local never reads as a
149
+ // shadow: callers with a retry policy pass their own sleep explicitly.
150
+ const retrySleep = retry?.sleep ?? realSleep;
151
+
152
+ let failure;
153
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
154
+ failure = undefined;
155
+ let response;
138
156
  try {
139
- const parsed = await response.json();
140
- data = parsed && typeof parsed === "object" ? parsed.data : undefined;
157
+ response = await fetchImpl(`${url}${path}`, {
158
+ method: "POST",
159
+ headers: jsonHeaders,
160
+ body: JSON.stringify(body),
161
+ });
141
162
  } catch (err) {
142
- // Mixed-version fallback: older servers may return an empty successful body.
143
- // Keep the lifecycle report successful, but make the missing correlation visible.
144
- logger.warn(`[Chorus] ${op} response correlation unavailable: ${err}`);
163
+ // Network-level failure (DNS, connection refused, abort, …). Surface WITH cause.
164
+ // `head`/`tail` are split so the attempt ordinal can be injected before the cause.
165
+ failure = { status: null, head: `${op} request failed${context}`, tail: `: ${err}` };
166
+ }
167
+ if (!failure && !response.ok) {
168
+ // Non-2xx. Surface WITH the status so a 4xx/5xx is debuggable.
169
+ failure = { status: response.status, head: `${op} returned ${response.status}${context}`, tail: "" };
145
170
  }
171
+ if (!failure) {
172
+ let data;
173
+ if (readData) {
174
+ try {
175
+ const parsed = await response.json();
176
+ data = parsed && typeof parsed === "object" ? parsed.data : undefined;
177
+ } catch (err) {
178
+ // Mixed-version fallback: older servers may return an empty successful body.
179
+ // Keep the lifecycle report successful, but make the missing correlation visible.
180
+ logger.warn(`[Chorus] ${op} response correlation unavailable: ${err}`);
181
+ }
182
+ }
183
+ if (successLog) logger.info(`[Chorus] ${successLog}`);
184
+ return { ok: true, status: response.status, ...(data !== undefined ? { data } : {}) };
185
+ }
186
+
187
+ const canRetry = attempt < attempts && isRetryableFailure(failure.status);
188
+ // Per-attempt visibility, but ONLY when another attempt actually follows: the ordinal
189
+ // exists to explain a retry. A single-shot op, or a terminal failure that will be
190
+ // re-logged verbatim two lines below, must not emit a redundant ordinal line.
191
+ if (canRetry) {
192
+ logger.warn(`[Chorus] ${failure.head} (attempt ${attempt}/${attempts})${failure.tail}`);
193
+ }
194
+ if (!canRetry) break;
195
+ await retrySleep(delaysMs[attempt - 1] ?? delaysMs[delaysMs.length - 1] ?? 0);
146
196
  }
147
- if (successLog) logger.info(`[Chorus] ${successLog}`);
148
- return { ok: true, status: response.status, ...(data !== undefined ? { data } : {}) };
197
+
198
+ // Final failure: the message and the structured result are EXACTLY what they were
199
+ // before retries existed, so existing log-grep expectations still match.
200
+ const error = `${failure.head}${failure.tail}`;
201
+ logger.warn(`[Chorus] ${error}`);
202
+ return { ok: false, status: failure.status, error };
149
203
  }
150
204
 
151
205
  return {
@@ -203,6 +257,21 @@ export function createDaemonRestClient(opts) {
203
257
  `advanced turn for session ${sessionId} → ${status}`,
204
258
  "",
205
259
  status === "running",
260
+ // Bounded retry on the TERMINAL edge only. A lost `→ ended`/`→ interrupted` report
261
+ // is what strands a turn as phantom `running` forever; the `→ running` edge is not
262
+ // retried because the wake is about to run anyway and a stale retry could race the
263
+ // terminal edge. The repeat is safe: the daemon sends the `turnUuid` it learned
264
+ // from its own → running report, and advanceTurnForWake returns the existing
265
+ // projection for a same-turn same-terminal-status replay (no second usage rollup,
266
+ // timestamp write or SSE publish). Without a turnUuid, the FIFO lookup finds no
267
+ // `running` turn and answers not_found, changing nothing.
268
+ isTerminal
269
+ ? {
270
+ attempts: TERMINAL_TURN_ADVANCE_ATTEMPTS,
271
+ delaysMs: TERMINAL_TURN_ADVANCE_DELAYS_MS,
272
+ sleep: sleepImpl,
273
+ }
274
+ : null,
206
275
  );
207
276
  const resolvedTurnUuid =
208
277
  typeof result.data?.turn?.uuid === "string" ? result.data.turn.uuid : null;