@loompad/cli 0.1.0 → 1.1.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 (687) hide show
  1. package/ARCHITECTURE.md +96 -11
  2. package/CHANGELOG.md +1042 -0
  3. package/README.md +1473 -44
  4. package/THIRD_PARTY_NOTICES.md +275 -0
  5. package/dist/adapters/antigravity-cli.d.ts +62 -0
  6. package/dist/adapters/antigravity-cli.js +258 -0
  7. package/dist/adapters/antigravity-cli.js.map +1 -0
  8. package/dist/adapters/base.d.ts +61 -9
  9. package/dist/adapters/base.js +266 -15
  10. package/dist/adapters/base.js.map +1 -1
  11. package/dist/adapters/bridges/antigravity.d.ts +9 -12
  12. package/dist/adapters/bridges/antigravity.js +9 -12
  13. package/dist/adapters/bridges/antigravity.js.map +1 -1
  14. package/dist/adapters/echo.d.ts +1 -0
  15. package/dist/adapters/echo.js +59 -3
  16. package/dist/adapters/echo.js.map +1 -1
  17. package/dist/adapters/grok.d.ts +7 -0
  18. package/dist/adapters/grok.js +20 -10
  19. package/dist/adapters/grok.js.map +1 -1
  20. package/dist/adapters/index.d.ts +5 -1
  21. package/dist/adapters/index.js +53 -7
  22. package/dist/adapters/index.js.map +1 -1
  23. package/dist/adapters/model.d.ts +137 -0
  24. package/dist/adapters/model.js +527 -0
  25. package/dist/adapters/model.js.map +1 -0
  26. package/dist/adapters/opencode.d.ts +101 -1
  27. package/dist/adapters/opencode.js +874 -98
  28. package/dist/adapters/opencode.js.map +1 -1
  29. package/dist/cli/doctor.d.ts +32 -0
  30. package/dist/cli/doctor.js +89 -4
  31. package/dist/cli/doctor.js.map +1 -1
  32. package/dist/cli/index.js +2651 -87
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/tui-model.js +3 -1
  35. package/dist/cli/tui-model.js.map +1 -1
  36. package/dist/cli/tui.js +44 -1
  37. package/dist/cli/tui.js.map +1 -1
  38. package/dist/cli/ui.d.ts +2 -0
  39. package/dist/cli/ui.js +13 -0
  40. package/dist/cli/ui.js.map +1 -1
  41. package/dist/core/ades.d.ts +32 -16
  42. package/dist/core/ades.js +57 -20
  43. package/dist/core/ades.js.map +1 -1
  44. package/dist/core/agent-state.d.ts +14 -0
  45. package/dist/core/agent-state.js +32 -0
  46. package/dist/core/agent-state.js.map +1 -0
  47. package/dist/core/approvals.d.ts +33 -0
  48. package/dist/core/approvals.js +29 -0
  49. package/dist/core/approvals.js.map +1 -0
  50. package/dist/core/backup.d.ts +19 -0
  51. package/dist/core/backup.js +86 -0
  52. package/dist/core/backup.js.map +1 -0
  53. package/dist/core/baton.d.ts +2 -2
  54. package/dist/core/baton.js.map +1 -1
  55. package/dist/core/brain-extract.d.ts +17 -0
  56. package/dist/core/brain-extract.js +28 -2
  57. package/dist/core/brain-extract.js.map +1 -1
  58. package/dist/core/brain-index.d.ts +71 -0
  59. package/dist/core/brain-index.js +204 -5
  60. package/dist/core/brain-index.js.map +1 -1
  61. package/dist/core/brain.d.ts +58 -2
  62. package/dist/core/brain.js +79 -1
  63. package/dist/core/brain.js.map +1 -1
  64. package/dist/core/chat-import.d.ts +71 -0
  65. package/dist/core/chat-import.js +419 -0
  66. package/dist/core/chat-import.js.map +1 -0
  67. package/dist/core/checkpoint.d.ts +107 -0
  68. package/dist/core/checkpoint.js +259 -0
  69. package/dist/core/checkpoint.js.map +1 -0
  70. package/dist/core/claude-cli.js +1 -1
  71. package/dist/core/claude-cli.js.map +1 -1
  72. package/dist/core/continuity/artifacts.d.ts +14 -0
  73. package/dist/core/continuity/artifacts.js +118 -0
  74. package/dist/core/continuity/artifacts.js.map +1 -0
  75. package/dist/core/continuity/capabilities.d.ts +65 -0
  76. package/dist/core/continuity/capabilities.js +129 -0
  77. package/dist/core/continuity/capabilities.js.map +1 -0
  78. package/dist/core/continuity/contracts.d.ts +352 -0
  79. package/dist/core/continuity/contracts.js +117 -0
  80. package/dist/core/continuity/contracts.js.map +1 -0
  81. package/dist/core/continuity/engine.d.ts +55 -0
  82. package/dist/core/continuity/engine.js +504 -0
  83. package/dist/core/continuity/engine.js.map +1 -0
  84. package/dist/core/continuity/store.d.ts +73 -0
  85. package/dist/core/continuity/store.js +438 -0
  86. package/dist/core/continuity/store.js.map +1 -0
  87. package/dist/core/conversations.d.ts +19 -0
  88. package/dist/core/conversations.js +87 -0
  89. package/dist/core/conversations.js.map +1 -0
  90. package/dist/core/crew-coordination.d.ts +6 -0
  91. package/dist/core/crew-coordination.js +24 -0
  92. package/dist/core/crew-coordination.js.map +1 -0
  93. package/dist/core/crew-policy.d.ts +18 -0
  94. package/dist/core/crew-policy.js +40 -0
  95. package/dist/core/crew-policy.js.map +1 -0
  96. package/dist/core/crew-protocol.d.ts +64 -0
  97. package/dist/core/crew-protocol.js +146 -0
  98. package/dist/core/crew-protocol.js.map +1 -0
  99. package/dist/core/crew-requests.d.ts +14 -0
  100. package/dist/core/crew-requests.js +22 -0
  101. package/dist/core/crew-requests.js.map +1 -0
  102. package/dist/core/crew.d.ts +395 -0
  103. package/dist/core/crew.js +1857 -0
  104. package/dist/core/crew.js.map +1 -0
  105. package/dist/core/digest.d.ts +40 -0
  106. package/dist/core/digest.js +94 -0
  107. package/dist/core/digest.js.map +1 -0
  108. package/dist/core/distill.js +3 -5
  109. package/dist/core/distill.js.map +1 -1
  110. package/dist/core/eventlog.d.ts +27 -25
  111. package/dist/core/eventlog.js +97 -150
  112. package/dist/core/eventlog.js.map +1 -1
  113. package/dist/core/events/contracts.d.ts +51 -0
  114. package/dist/core/events/contracts.js +2 -0
  115. package/dist/core/events/contracts.js.map +1 -0
  116. package/dist/core/events/jsonl-store.d.ts +23 -0
  117. package/dist/core/events/jsonl-store.js +90 -0
  118. package/dist/core/events/jsonl-store.js.map +1 -0
  119. package/dist/core/events/sqlite-store.d.ts +37 -0
  120. package/dist/core/events/sqlite-store.js +215 -0
  121. package/dist/core/events/sqlite-store.js.map +1 -0
  122. package/dist/core/forecast.d.ts +44 -0
  123. package/dist/core/forecast.js +46 -0
  124. package/dist/core/forecast.js.map +1 -0
  125. package/dist/core/free-pool.d.ts +65 -0
  126. package/dist/core/free-pool.js +171 -0
  127. package/dist/core/free-pool.js.map +1 -0
  128. package/dist/core/git.d.ts +30 -0
  129. package/dist/core/git.js +50 -2
  130. package/dist/core/git.js.map +1 -1
  131. package/dist/core/github-events.d.ts +53 -0
  132. package/dist/core/github-events.js +227 -0
  133. package/dist/core/github-events.js.map +1 -0
  134. package/dist/core/goal-lanes.d.ts +53 -0
  135. package/dist/core/goal-lanes.js +99 -0
  136. package/dist/core/goal-lanes.js.map +1 -0
  137. package/dist/core/hosted.d.ts +27 -0
  138. package/dist/core/hosted.js +50 -0
  139. package/dist/core/hosted.js.map +1 -0
  140. package/dist/core/http-server.d.ts +5 -0
  141. package/dist/core/http-server.js +8 -0
  142. package/dist/core/http-server.js.map +1 -0
  143. package/dist/core/invite-link.d.ts +31 -0
  144. package/dist/core/invite-link.js +45 -0
  145. package/dist/core/invite-link.js.map +1 -0
  146. package/dist/core/loops.d.ts +37 -0
  147. package/dist/core/loops.js +81 -0
  148. package/dist/core/loops.js.map +1 -0
  149. package/dist/core/mcp-catalog.d.ts +182 -0
  150. package/dist/core/mcp-catalog.js +431 -0
  151. package/dist/core/mcp-catalog.js.map +1 -0
  152. package/dist/core/mcp.d.ts +87 -0
  153. package/dist/core/mcp.js +181 -0
  154. package/dist/core/mcp.js.map +1 -0
  155. package/dist/core/memory.d.ts +1 -0
  156. package/dist/core/memory.js +5 -2
  157. package/dist/core/memory.js.map +1 -1
  158. package/dist/core/model-tools.d.ts +97 -0
  159. package/dist/core/model-tools.js +388 -0
  160. package/dist/core/model-tools.js.map +1 -0
  161. package/dist/core/notify.js +19 -1
  162. package/dist/core/notify.js.map +1 -1
  163. package/dist/core/orchestra.d.ts +635 -0
  164. package/dist/core/orchestra.js +2120 -0
  165. package/dist/core/orchestra.js.map +1 -0
  166. package/dist/core/permissions.d.ts +56 -0
  167. package/dist/core/permissions.js +122 -0
  168. package/dist/core/permissions.js.map +1 -0
  169. package/dist/core/preview-proxy.d.ts +70 -0
  170. package/dist/core/preview-proxy.js +563 -0
  171. package/dist/core/preview-proxy.js.map +1 -0
  172. package/dist/core/preview-shot.d.ts +46 -0
  173. package/dist/core/preview-shot.js +109 -0
  174. package/dist/core/preview-shot.js.map +1 -0
  175. package/dist/core/process.d.ts +36 -0
  176. package/dist/core/process.js +168 -0
  177. package/dist/core/process.js.map +1 -0
  178. package/dist/core/prompt-queue.d.ts +136 -0
  179. package/dist/core/prompt-queue.js +269 -0
  180. package/dist/core/prompt-queue.js.map +1 -0
  181. package/dist/core/prompts.d.ts +53 -0
  182. package/dist/core/prompts.js +127 -0
  183. package/dist/core/prompts.js.map +1 -0
  184. package/dist/core/proof.d.ts +82 -0
  185. package/dist/core/proof.js +216 -0
  186. package/dist/core/proof.js.map +1 -0
  187. package/dist/core/provider-text.d.ts +23 -0
  188. package/dist/core/provider-text.js +66 -0
  189. package/dist/core/provider-text.js.map +1 -0
  190. package/dist/core/providers.d.ts +152 -0
  191. package/dist/core/providers.js +343 -0
  192. package/dist/core/providers.js.map +1 -0
  193. package/dist/core/quota.d.ts +33 -0
  194. package/dist/core/quota.js +74 -0
  195. package/dist/core/quota.js.map +1 -0
  196. package/dist/core/recipes.d.ts +50 -0
  197. package/dist/core/recipes.js +99 -0
  198. package/dist/core/recipes.js.map +1 -0
  199. package/dist/core/registry.d.ts +54 -0
  200. package/dist/core/registry.js +62 -5
  201. package/dist/core/registry.js.map +1 -1
  202. package/dist/core/relay-client.d.ts +67 -0
  203. package/dist/core/relay-client.js +184 -0
  204. package/dist/core/relay-client.js.map +1 -0
  205. package/dist/core/relay-protocol.d.ts +140 -0
  206. package/dist/core/relay-protocol.js +189 -0
  207. package/dist/core/relay-protocol.js.map +1 -0
  208. package/dist/core/replay.d.ts +18 -0
  209. package/dist/core/replay.js +191 -0
  210. package/dist/core/replay.js.map +1 -0
  211. package/dist/core/review-triage.d.ts +41 -0
  212. package/dist/core/review-triage.js +124 -0
  213. package/dist/core/review-triage.js.map +1 -0
  214. package/dist/core/router.js +2 -2
  215. package/dist/core/router.js.map +1 -1
  216. package/dist/core/routes.d.ts +39 -3
  217. package/dist/core/routes.js +137 -4
  218. package/dist/core/routes.js.map +1 -1
  219. package/dist/core/run-command.d.ts +14 -0
  220. package/dist/core/run-command.js +45 -0
  221. package/dist/core/run-command.js.map +1 -0
  222. package/dist/core/runner-setup.d.ts +36 -0
  223. package/dist/core/runner-setup.js +114 -0
  224. package/dist/core/runner-setup.js.map +1 -0
  225. package/dist/core/search.js +0 -0
  226. package/dist/core/search.js.map +1 -1
  227. package/dist/core/semantic.d.ts +92 -0
  228. package/dist/core/semantic.js +227 -0
  229. package/dist/core/semantic.js.map +1 -0
  230. package/dist/core/servers.d.ts +115 -0
  231. package/dist/core/servers.js +305 -0
  232. package/dist/core/servers.js.map +1 -0
  233. package/dist/core/setup.js +64 -6
  234. package/dist/core/setup.js.map +1 -1
  235. package/dist/core/shield.d.ts +17 -0
  236. package/dist/core/shield.js +81 -0
  237. package/dist/core/shield.js.map +1 -0
  238. package/dist/core/shift.d.ts +69 -0
  239. package/dist/core/shift.js +120 -0
  240. package/dist/core/shift.js.map +1 -0
  241. package/dist/core/skill-install.d.ts +125 -0
  242. package/dist/core/skill-install.js +328 -0
  243. package/dist/core/skill-install.js.map +1 -0
  244. package/dist/core/skills.d.ts +116 -0
  245. package/dist/core/skills.js +223 -0
  246. package/dist/core/skills.js.map +1 -0
  247. package/dist/core/step-conditions.d.ts +65 -0
  248. package/dist/core/step-conditions.js +102 -0
  249. package/dist/core/step-conditions.js.map +1 -0
  250. package/dist/core/subagents.d.ts +45 -0
  251. package/dist/core/subagents.js +90 -0
  252. package/dist/core/subagents.js.map +1 -0
  253. package/dist/core/team-canon.d.ts +42 -0
  254. package/dist/core/team-canon.js +121 -0
  255. package/dist/core/team-canon.js.map +1 -0
  256. package/dist/core/team-crypto.d.ts +97 -0
  257. package/dist/core/team-crypto.js +175 -0
  258. package/dist/core/team-crypto.js.map +1 -0
  259. package/dist/core/team-hub.d.ts +514 -0
  260. package/dist/core/team-hub.js +964 -0
  261. package/dist/core/team-hub.js.map +1 -0
  262. package/dist/core/team-landing.d.ts +239 -0
  263. package/dist/core/team-landing.js +504 -0
  264. package/dist/core/team-landing.js.map +1 -0
  265. package/dist/core/team-leases.d.ts +44 -0
  266. package/dist/core/team-leases.js +145 -0
  267. package/dist/core/team-leases.js.map +1 -0
  268. package/dist/core/team-memory.d.ts +42 -0
  269. package/dist/core/team-memory.js +84 -0
  270. package/dist/core/team-memory.js.map +1 -0
  271. package/dist/core/team-policy.d.ts +85 -0
  272. package/dist/core/team-policy.js +191 -0
  273. package/dist/core/team-policy.js.map +1 -0
  274. package/dist/core/thread-md.d.ts +6 -0
  275. package/dist/core/thread-md.js +42 -0
  276. package/dist/core/thread-md.js.map +1 -0
  277. package/dist/core/turn-stats.d.ts +61 -0
  278. package/dist/core/turn-stats.js +124 -0
  279. package/dist/core/turn-stats.js.map +1 -0
  280. package/dist/core/updater.d.ts +73 -0
  281. package/dist/core/updater.js +153 -0
  282. package/dist/core/updater.js.map +1 -0
  283. package/dist/core/usage.d.ts +75 -0
  284. package/dist/core/usage.js +163 -0
  285. package/dist/core/usage.js.map +1 -0
  286. package/dist/core/windows-jobs.d.ts +15 -0
  287. package/dist/core/windows-jobs.js +170 -0
  288. package/dist/core/windows-jobs.js.map +1 -0
  289. package/dist/core/worktree-merge.d.ts +57 -0
  290. package/dist/core/worktree-merge.js +123 -0
  291. package/dist/core/worktree-merge.js.map +1 -0
  292. package/dist/core/worktree.d.ts +5 -0
  293. package/dist/core/worktree.js +45 -5
  294. package/dist/core/worktree.js.map +1 -1
  295. package/dist/core/worktrees.d.ts +6 -0
  296. package/dist/core/worktrees.js +21 -0
  297. package/dist/core/worktrees.js.map +1 -0
  298. package/dist/daemon/app-page.d.ts +0 -17
  299. package/dist/daemon/app-page.js +10 -6346
  300. package/dist/daemon/app-page.js.map +1 -1
  301. package/dist/daemon/auth.d.ts +24 -3
  302. package/dist/daemon/auth.js +66 -7
  303. package/dist/daemon/auth.js.map +1 -1
  304. package/dist/daemon/board.d.ts +7 -0
  305. package/dist/daemon/board.js +12 -1
  306. package/dist/daemon/board.js.map +1 -1
  307. package/dist/daemon/brand-icons.d.ts +6 -1
  308. package/dist/daemon/brand-icons.js +11 -3
  309. package/dist/daemon/brand-icons.js.map +1 -1
  310. package/dist/daemon/client.d.ts +665 -1
  311. package/dist/daemon/client.js +381 -3
  312. package/dist/daemon/client.js.map +1 -1
  313. package/dist/daemon/delivery.d.ts +34 -0
  314. package/dist/daemon/delivery.js +63 -0
  315. package/dist/daemon/delivery.js.map +1 -0
  316. package/dist/daemon/deploys.d.ts +62 -0
  317. package/dist/daemon/deploys.js +159 -0
  318. package/dist/daemon/deploys.js.map +1 -0
  319. package/dist/daemon/landing.d.ts +192 -0
  320. package/dist/daemon/landing.js +992 -0
  321. package/dist/daemon/landing.js.map +1 -0
  322. package/dist/daemon/onboard.d.ts +150 -0
  323. package/dist/daemon/onboard.js +390 -0
  324. package/dist/daemon/onboard.js.map +1 -0
  325. package/dist/daemon/proof.d.ts +70 -0
  326. package/dist/daemon/proof.js +172 -0
  327. package/dist/daemon/proof.js.map +1 -0
  328. package/dist/daemon/push.d.ts +19 -1
  329. package/dist/daemon/push.js +90 -3
  330. package/dist/daemon/push.js.map +1 -1
  331. package/dist/daemon/relay.d.ts +82 -0
  332. package/dist/daemon/relay.js +351 -0
  333. package/dist/daemon/relay.js.map +1 -0
  334. package/dist/daemon/routes/agent-discovery.d.ts +4 -0
  335. package/dist/daemon/routes/agent-discovery.js +29 -0
  336. package/dist/daemon/routes/agent-discovery.js.map +1 -0
  337. package/dist/daemon/routes/agent-settings.d.ts +4 -0
  338. package/dist/daemon/routes/agent-settings.js +94 -0
  339. package/dist/daemon/routes/agent-settings.js.map +1 -0
  340. package/dist/daemon/routes/agents.d.ts +4 -0
  341. package/dist/daemon/routes/agents.js +105 -0
  342. package/dist/daemon/routes/agents.js.map +1 -0
  343. package/dist/daemon/routes/alerts.d.ts +4 -0
  344. package/dist/daemon/routes/alerts.js +137 -0
  345. package/dist/daemon/routes/alerts.js.map +1 -0
  346. package/dist/daemon/routes/approvals.d.ts +4 -0
  347. package/dist/daemon/routes/approvals.js +40 -0
  348. package/dist/daemon/routes/approvals.js.map +1 -0
  349. package/dist/daemon/routes/assets.d.ts +3 -0
  350. package/dist/daemon/routes/assets.js +64 -0
  351. package/dist/daemon/routes/assets.js.map +1 -0
  352. package/dist/daemon/routes/board.d.ts +4 -0
  353. package/dist/daemon/routes/board.js +147 -0
  354. package/dist/daemon/routes/board.js.map +1 -0
  355. package/dist/daemon/routes/brain.d.ts +4 -0
  356. package/dist/daemon/routes/brain.js +270 -0
  357. package/dist/daemon/routes/brain.js.map +1 -0
  358. package/dist/daemon/routes/chats.d.ts +4 -0
  359. package/dist/daemon/routes/chats.js +249 -0
  360. package/dist/daemon/routes/chats.js.map +1 -0
  361. package/dist/daemon/routes/clients.d.ts +4 -0
  362. package/dist/daemon/routes/clients.js +49 -0
  363. package/dist/daemon/routes/clients.js.map +1 -0
  364. package/dist/daemon/routes/cloud.d.ts +4 -0
  365. package/dist/daemon/routes/cloud.js +46 -0
  366. package/dist/daemon/routes/cloud.js.map +1 -0
  367. package/dist/daemon/routes/config.d.ts +4 -0
  368. package/dist/daemon/routes/config.js +35 -0
  369. package/dist/daemon/routes/config.js.map +1 -0
  370. package/dist/daemon/routes/context.d.ts +51 -0
  371. package/dist/daemon/routes/context.js +2 -0
  372. package/dist/daemon/routes/context.js.map +1 -0
  373. package/dist/daemon/routes/crews.d.ts +4 -0
  374. package/dist/daemon/routes/crews.js +149 -0
  375. package/dist/daemon/routes/crews.js.map +1 -0
  376. package/dist/daemon/routes/files.d.ts +3 -0
  377. package/dist/daemon/routes/files.js +253 -0
  378. package/dist/daemon/routes/files.js.map +1 -0
  379. package/dist/daemon/routes/git.d.ts +4 -0
  380. package/dist/daemon/routes/git.js +96 -0
  381. package/dist/daemon/routes/git.js.map +1 -0
  382. package/dist/daemon/routes/history.d.ts +4 -0
  383. package/dist/daemon/routes/history.js +101 -0
  384. package/dist/daemon/routes/history.js.map +1 -0
  385. package/dist/daemon/routes/integrations-project.d.ts +3 -0
  386. package/dist/daemon/routes/integrations-project.js +103 -0
  387. package/dist/daemon/routes/integrations-project.js.map +1 -0
  388. package/dist/daemon/routes/integrations.d.ts +3 -0
  389. package/dist/daemon/routes/integrations.js +111 -0
  390. package/dist/daemon/routes/integrations.js.map +1 -0
  391. package/dist/daemon/routes/logs.d.ts +3 -0
  392. package/dist/daemon/routes/logs.js +40 -0
  393. package/dist/daemon/routes/logs.js.map +1 -0
  394. package/dist/daemon/routes/messages.d.ts +4 -0
  395. package/dist/daemon/routes/messages.js +60 -0
  396. package/dist/daemon/routes/messages.js.map +1 -0
  397. package/dist/daemon/routes/observability.d.ts +4 -0
  398. package/dist/daemon/routes/observability.js +247 -0
  399. package/dist/daemon/routes/observability.js.map +1 -0
  400. package/dist/daemon/routes/onboard.d.ts +12 -0
  401. package/dist/daemon/routes/onboard.js +67 -0
  402. package/dist/daemon/routes/onboard.js.map +1 -0
  403. package/dist/daemon/routes/orchestra.d.ts +4 -0
  404. package/dist/daemon/routes/orchestra.js +110 -0
  405. package/dist/daemon/routes/orchestra.js.map +1 -0
  406. package/dist/daemon/routes/pairing.d.ts +4 -0
  407. package/dist/daemon/routes/pairing.js +155 -0
  408. package/dist/daemon/routes/pairing.js.map +1 -0
  409. package/dist/daemon/routes/preview.d.ts +24 -0
  410. package/dist/daemon/routes/preview.js +122 -0
  411. package/dist/daemon/routes/preview.js.map +1 -0
  412. package/dist/daemon/routes/project-actions.d.ts +4 -0
  413. package/dist/daemon/routes/project-actions.js +53 -0
  414. package/dist/daemon/routes/project-actions.js.map +1 -0
  415. package/dist/daemon/routes/project-team.d.ts +4 -0
  416. package/dist/daemon/routes/project-team.js +201 -0
  417. package/dist/daemon/routes/project-team.js.map +1 -0
  418. package/dist/daemon/routes/projects.d.ts +14 -0
  419. package/dist/daemon/routes/projects.js +138 -0
  420. package/dist/daemon/routes/projects.js.map +1 -0
  421. package/dist/daemon/routes/prompts.d.ts +4 -0
  422. package/dist/daemon/routes/prompts.js +44 -0
  423. package/dist/daemon/routes/prompts.js.map +1 -0
  424. package/dist/daemon/routes/proof.d.ts +4 -0
  425. package/dist/daemon/routes/proof.js +22 -0
  426. package/dist/daemon/routes/proof.js.map +1 -0
  427. package/dist/daemon/routes/providers.d.ts +3 -0
  428. package/dist/daemon/routes/providers.js +60 -0
  429. package/dist/daemon/routes/providers.js.map +1 -0
  430. package/dist/daemon/routes/public.d.ts +4 -0
  431. package/dist/daemon/routes/public.js +64 -0
  432. package/dist/daemon/routes/public.js.map +1 -0
  433. package/dist/daemon/routes/queue.d.ts +4 -0
  434. package/dist/daemon/routes/queue.js +140 -0
  435. package/dist/daemon/routes/queue.js.map +1 -0
  436. package/dist/daemon/routes/routing.d.ts +4 -0
  437. package/dist/daemon/routes/routing.js +61 -0
  438. package/dist/daemon/routes/routing.js.map +1 -0
  439. package/dist/daemon/routes/runtime-handler.d.ts +2 -0
  440. package/dist/daemon/routes/runtime-handler.js +63 -0
  441. package/dist/daemon/routes/runtime-handler.js.map +1 -0
  442. package/dist/daemon/routes/search.d.ts +4 -0
  443. package/dist/daemon/routes/search.js +17 -0
  444. package/dist/daemon/routes/search.js.map +1 -0
  445. package/dist/daemon/routes/servers.d.ts +4 -0
  446. package/dist/daemon/routes/servers.js +133 -0
  447. package/dist/daemon/routes/servers.js.map +1 -0
  448. package/dist/daemon/routes/setup.d.ts +3 -0
  449. package/dist/daemon/routes/setup.js +50 -0
  450. package/dist/daemon/routes/setup.js.map +1 -0
  451. package/dist/daemon/routes/shift.d.ts +4 -0
  452. package/dist/daemon/routes/shift.js +30 -0
  453. package/dist/daemon/routes/shift.js.map +1 -0
  454. package/dist/daemon/routes/specs.d.ts +4 -0
  455. package/dist/daemon/routes/specs.js +57 -0
  456. package/dist/daemon/routes/specs.js.map +1 -0
  457. package/dist/daemon/routes/task-delivery.d.ts +4 -0
  458. package/dist/daemon/routes/task-delivery.js +38 -0
  459. package/dist/daemon/routes/task-delivery.js.map +1 -0
  460. package/dist/daemon/routes/team.d.ts +4 -0
  461. package/dist/daemon/routes/team.js +193 -0
  462. package/dist/daemon/routes/team.js.map +1 -0
  463. package/dist/daemon/routes/terminals.d.ts +4 -0
  464. package/dist/daemon/routes/terminals.js +87 -0
  465. package/dist/daemon/routes/terminals.js.map +1 -0
  466. package/dist/daemon/routes/tools.d.ts +4 -0
  467. package/dist/daemon/routes/tools.js +180 -0
  468. package/dist/daemon/routes/tools.js.map +1 -0
  469. package/dist/daemon/routes/updates.d.ts +4 -0
  470. package/dist/daemon/routes/updates.js +89 -0
  471. package/dist/daemon/routes/updates.js.map +1 -0
  472. package/dist/daemon/routes/voice.d.ts +4 -0
  473. package/dist/daemon/routes/voice.js +53 -0
  474. package/dist/daemon/routes/voice.js.map +1 -0
  475. package/dist/daemon/runner.d.ts +186 -0
  476. package/dist/daemon/runner.js +612 -0
  477. package/dist/daemon/runner.js.map +1 -0
  478. package/dist/daemon/runtime/accounting.d.ts +130 -0
  479. package/dist/daemon/runtime/accounting.js +303 -0
  480. package/dist/daemon/runtime/accounting.js.map +1 -0
  481. package/dist/daemon/runtime/agents.d.ts +16 -0
  482. package/dist/daemon/runtime/agents.js +71 -0
  483. package/dist/daemon/runtime/agents.js.map +1 -0
  484. package/dist/daemon/runtime/briefings.d.ts +134 -0
  485. package/dist/daemon/runtime/briefings.js +329 -0
  486. package/dist/daemon/runtime/briefings.js.map +1 -0
  487. package/dist/daemon/runtime/native-usage.d.ts +21 -0
  488. package/dist/daemon/runtime/native-usage.js +71 -0
  489. package/dist/daemon/runtime/native-usage.js.map +1 -0
  490. package/dist/daemon/runtime/queue.d.ts +94 -0
  491. package/dist/daemon/runtime/queue.js +222 -0
  492. package/dist/daemon/runtime/queue.js.map +1 -0
  493. package/dist/daemon/runtime/relay.d.ts +93 -0
  494. package/dist/daemon/runtime/relay.js +240 -0
  495. package/dist/daemon/runtime/relay.js.map +1 -0
  496. package/dist/daemon/runtime/turns.d.ts +202 -0
  497. package/dist/daemon/runtime/turns.js +663 -0
  498. package/dist/daemon/runtime/turns.js.map +1 -0
  499. package/dist/daemon/runtime-support.d.ts +76 -0
  500. package/dist/daemon/runtime-support.js +134 -0
  501. package/dist/daemon/runtime-support.js.map +1 -0
  502. package/dist/daemon/runtime.d.ts +739 -70
  503. package/dist/daemon/runtime.js +2751 -470
  504. package/dist/daemon/runtime.js.map +1 -1
  505. package/dist/daemon/server.d.ts +82 -55
  506. package/dist/daemon/server.js +674 -1435
  507. package/dist/daemon/server.js.map +1 -1
  508. package/dist/daemon/shift.d.ts +70 -0
  509. package/dist/daemon/shift.js +170 -0
  510. package/dist/daemon/shift.js.map +1 -0
  511. package/dist/daemon/specs.d.ts +92 -0
  512. package/dist/daemon/specs.js +285 -0
  513. package/dist/daemon/specs.js.map +1 -0
  514. package/dist/daemon/system.d.ts +208 -0
  515. package/dist/daemon/system.js +557 -0
  516. package/dist/daemon/system.js.map +1 -0
  517. package/dist/daemon/tasks.js +1 -1
  518. package/dist/daemon/team-brain.d.ts +136 -0
  519. package/dist/daemon/team-brain.js +659 -0
  520. package/dist/daemon/team-brain.js.map +1 -0
  521. package/dist/daemon/team-coordinator.d.ts +78 -0
  522. package/dist/daemon/team-coordinator.js +408 -0
  523. package/dist/daemon/team-coordinator.js.map +1 -0
  524. package/dist/daemon/team.d.ts +339 -0
  525. package/dist/daemon/team.js +1433 -0
  526. package/dist/daemon/team.js.map +1 -0
  527. package/dist/daemon/terminals.d.ts +22 -3
  528. package/dist/daemon/terminals.js +236 -16
  529. package/dist/daemon/terminals.js.map +1 -1
  530. package/dist/hub/client.d.ts +120 -0
  531. package/dist/hub/client.js +228 -0
  532. package/dist/hub/client.js.map +1 -0
  533. package/dist/hub/server.d.ts +32 -0
  534. package/dist/hub/server.js +180 -0
  535. package/dist/hub/server.js.map +1 -0
  536. package/dist/hub/supabase-client.d.ts +220 -0
  537. package/dist/hub/supabase-client.js +843 -0
  538. package/dist/hub/supabase-client.js.map +1 -0
  539. package/dist/observability/ask.d.ts +91 -0
  540. package/dist/observability/ask.js +179 -0
  541. package/dist/observability/ask.js.map +1 -0
  542. package/dist/observability/clickhouse.d.ts +33 -0
  543. package/dist/observability/clickhouse.js +48 -0
  544. package/dist/observability/clickhouse.js.map +1 -0
  545. package/dist/observability/decisions.d.ts +176 -0
  546. package/dist/observability/decisions.js +377 -0
  547. package/dist/observability/decisions.js.map +1 -0
  548. package/dist/observability/index.d.ts +89 -0
  549. package/dist/observability/index.js +348 -0
  550. package/dist/observability/index.js.map +1 -0
  551. package/dist/observability/insights.d.ts +151 -0
  552. package/dist/observability/insights.js +319 -0
  553. package/dist/observability/insights.js.map +1 -0
  554. package/dist/observability/logs-query.d.ts +82 -0
  555. package/dist/observability/logs-query.js +102 -0
  556. package/dist/observability/logs-query.js.map +1 -0
  557. package/dist/observability/logs.d.ts +72 -0
  558. package/dist/observability/logs.js +295 -0
  559. package/dist/observability/logs.js.map +1 -0
  560. package/dist/observability/metrics.d.ts +86 -0
  561. package/dist/observability/metrics.js +303 -0
  562. package/dist/observability/metrics.js.map +1 -0
  563. package/dist/observability/otlp.d.ts +127 -0
  564. package/dist/observability/otlp.js +242 -0
  565. package/dist/observability/otlp.js.map +1 -0
  566. package/dist/observability/snapshots.d.ts +43 -0
  567. package/dist/observability/snapshots.js +129 -0
  568. package/dist/observability/snapshots.js.map +1 -0
  569. package/dist/observability/triage.d.ts +49 -0
  570. package/dist/observability/triage.js +284 -0
  571. package/dist/observability/triage.js.map +1 -0
  572. package/dist/providers/adapter.d.ts +50 -0
  573. package/dist/providers/adapter.js +38 -0
  574. package/dist/providers/adapter.js.map +1 -0
  575. package/dist/providers/agent.d.ts +110 -0
  576. package/dist/providers/agent.js +487 -0
  577. package/dist/providers/agent.js.map +1 -0
  578. package/dist/providers/approvals.d.ts +24 -0
  579. package/dist/providers/approvals.js +78 -0
  580. package/dist/providers/approvals.js.map +1 -0
  581. package/dist/providers/attachments.d.ts +20 -0
  582. package/dist/providers/attachments.js +51 -0
  583. package/dist/providers/attachments.js.map +1 -0
  584. package/dist/providers/claude/adapter.d.ts +99 -0
  585. package/dist/providers/claude/adapter.js +790 -0
  586. package/dist/providers/claude/adapter.js.map +1 -0
  587. package/dist/providers/codex/adapter.d.ts +113 -0
  588. package/dist/providers/codex/adapter.js +881 -0
  589. package/dist/providers/codex/adapter.js.map +1 -0
  590. package/dist/providers/codex/instructions.d.ts +11 -0
  591. package/dist/providers/codex/instructions.js +154 -0
  592. package/dist/providers/codex/instructions.js.map +1 -0
  593. package/dist/providers/codex/rpc.d.ts +36 -0
  594. package/dist/providers/codex/rpc.js +104 -0
  595. package/dist/providers/codex/rpc.js.map +1 -0
  596. package/dist/providers/contracts.d.ts +339 -0
  597. package/dist/providers/contracts.js +19 -0
  598. package/dist/providers/contracts.js.map +1 -0
  599. package/dist/providers/directory.d.ts +70 -0
  600. package/dist/providers/directory.js +95 -0
  601. package/dist/providers/directory.js.map +1 -0
  602. package/dist/providers/errors.d.ts +47 -0
  603. package/dist/providers/errors.js +24 -0
  604. package/dist/providers/errors.js.map +1 -0
  605. package/dist/providers/index.d.ts +18 -0
  606. package/dist/providers/index.js +19 -0
  607. package/dist/providers/index.js.map +1 -0
  608. package/dist/providers/ingestion.d.ts +80 -0
  609. package/dist/providers/ingestion.js +330 -0
  610. package/dist/providers/ingestion.js.map +1 -0
  611. package/dist/providers/live.d.ts +22 -0
  612. package/dist/providers/live.js +56 -0
  613. package/dist/providers/live.js.map +1 -0
  614. package/dist/providers/process.d.ts +29 -0
  615. package/dist/providers/process.js +71 -0
  616. package/dist/providers/process.js.map +1 -0
  617. package/dist/providers/reaper.d.ts +33 -0
  618. package/dist/providers/reaper.js +65 -0
  619. package/dist/providers/reaper.js.map +1 -0
  620. package/dist/providers/service.d.ts +87 -0
  621. package/dist/providers/service.js +256 -0
  622. package/dist/providers/service.js.map +1 -0
  623. package/dist/sdk.d.ts +1 -1
  624. package/dist/sdk.js +1 -1
  625. package/dist/sdk.js.map +1 -1
  626. package/dist/types.d.ts +385 -6
  627. package/dist/types.js +1 -0
  628. package/dist/types.js.map +1 -1
  629. package/dist/version.d.ts +7 -0
  630. package/dist/version.js +16 -0
  631. package/dist/version.js.map +1 -0
  632. package/dist/web/app.css +4643 -0
  633. package/dist/web/app.js +22640 -0
  634. package/dist/web/app.js.map +7 -0
  635. package/dist/web/shell.html +39 -0
  636. package/docs/README.md +21 -0
  637. package/docs/SETUP.md +10 -0
  638. package/docs/adapters.md +21 -8
  639. package/docs/brain-continuity.md +186 -0
  640. package/docs/cloud.md +108 -0
  641. package/docs/crews.md +62 -0
  642. package/docs/design-system.md +31 -2
  643. package/docs/integration-notes.md +128 -20
  644. package/docs/loompad.md +105 -0
  645. package/docs/observability.md +220 -0
  646. package/docs/play-store.md +123 -0
  647. package/docs/proposals/agent-teams.md +249 -0
  648. package/docs/proposals/brain-continuity-implementation.md +468 -0
  649. package/docs/proposals/brain-session-continuity.md +623 -0
  650. package/docs/proposals/t3code-port.md +81 -0
  651. package/docs/proposals/t3code-reference.md +95 -0
  652. package/docs/refactoring/AGENT-TEAMS-PROGRESS.md +88 -0
  653. package/docs/refactoring/BOUNDARIES.md +120 -0
  654. package/docs/refactoring/BRAIN-AUDIT.md +176 -0
  655. package/docs/refactoring/BRAIN-NOTES.md +390 -0
  656. package/docs/refactoring/BRAIN-TODO.md +214 -0
  657. package/docs/refactoring/NOTES.md +129 -0
  658. package/docs/refactoring/T3-PORT-NOTES.md +165 -0
  659. package/docs/refactoring/T3-PORT-TODO.md +123 -0
  660. package/docs/refactoring/TODO.md +46 -0
  661. package/docs/refactoring/brain-benchmark-2026-09-28.json +48 -0
  662. package/docs/refactoring/brain-benchmark-audit-2026-09-28.json +48 -0
  663. package/docs/release-notes/v0.2.0.md +35 -0
  664. package/docs/release-notes/v0.2.1.md +59 -0
  665. package/docs/release-notes/v0.2.3.md +77 -0
  666. package/docs/release-notes/v0.2.4.md +128 -0
  667. package/docs/release-notes/v0.2.5.md +153 -0
  668. package/docs/release-notes/v0.2.6.md +62 -0
  669. package/docs/release-notes/v1.0.0.md +120 -0
  670. package/docs/release-notes/v1.0.1.md +77 -0
  671. package/docs/release-notes/v1.1.0.md +71 -0
  672. package/docs/release-notes/v1.1.1.md +38 -0
  673. package/docs/teams-architecture.md +697 -0
  674. package/docs/teams.md +171 -0
  675. package/docs/windows.md +85 -0
  676. package/package.json +22 -9
  677. package/dist/adapters/claude-code.d.ts +0 -26
  678. package/dist/adapters/claude-code.js +0 -209
  679. package/dist/adapters/claude-code.js.map +0 -1
  680. package/dist/adapters/codex.d.ts +0 -51
  681. package/dist/adapters/codex.js +0 -291
  682. package/dist/adapters/codex.js.map +0 -1
  683. package/docs/img/board-linear.png +0 -0
  684. package/docs/img/board-projects.png +0 -0
  685. package/docs/img/brain.png +0 -0
  686. package/docs/img/settings.png +0 -0
  687. package/docs/img/workspace.png +0 -0
@@ -0,0 +1,94 @@
1
+ import type { EventJournal } from "../../core/eventlog.js";
2
+ import { OrchestraEngine } from "../../core/orchestra.js";
3
+ import { PromptQueue, type QueueCondition, type QueueInput, type QueueItem, type QueueState, type QueueTarget } from "../../core/prompt-queue.js";
4
+ import { type MergeOutcome } from "../../core/worktree-merge.js";
5
+ import type { AnyAgent, ProjectConfig, RouteState, RouteStepSpec, RouterKind } from "../../types.js";
6
+ import type { TurnOptions, TurnResult } from "./turns.js";
7
+ /** Dependencies owned by the project coordinator, read live for each operation. */
8
+ export interface RuntimeQueueHost {
9
+ queue: PromptQueue;
10
+ agents: ReadonlyMap<string, AnyAgent>;
11
+ routeState: () => RouteState | null;
12
+ validHolder: () => string | null;
13
+ orchestra: OrchestraEngine;
14
+ config: ProjectConfig;
15
+ busySince: Map<string, number>;
16
+ closed: boolean;
17
+ appendIfOpen: (event: Parameters<EventJournal["append"]>[0]) => void;
18
+ startRoute: (opts: {
19
+ task: string;
20
+ spec?: string | RouteStepSpec[];
21
+ router?: RouterKind;
22
+ maxHops?: number;
23
+ }) => Promise<RouteState>;
24
+ handoff: (to: string, opts?: {
25
+ source?: "user" | "route";
26
+ }) => Promise<{
27
+ from: string | null;
28
+ merge?: MergeOutcome;
29
+ }>;
30
+ sendMessage: (text: string, agentId?: string, opts?: TurnOptions) => Promise<TurnResult>;
31
+ }
32
+ /** Owns queue state for exactly one open project. */
33
+ export declare class RuntimeQueue {
34
+ private readonly host;
35
+ constructor(host: RuntimeQueueHost);
36
+ queueListeners: Set<(s: QueueState) => void>;
37
+ draining: boolean;
38
+ /** When the project last went quiet, for a "after N quiet minutes" condition. */
39
+ quietSince: number;
40
+ clockTimer: ReturnType<typeof setInterval> | null;
41
+ /** Live queue changes, for the socket. Returns unsubscribe. */
42
+ onQueueChange(cb: (q: QueueState) => void): () => void;
43
+ /** Line a prompt up; it goes as soon as nothing ahead of it is in the way. */
44
+ enqueue(input: QueueInput): QueueItem;
45
+ /** Change a waiting prompt. A target this project can't run is refused now,
46
+ * not when the queue reaches it and has to stop. */
47
+ editQueued(itemId: string, patch: {
48
+ text?: string;
49
+ target?: QueueTarget;
50
+ plan?: boolean;
51
+ when?: QueueCondition | null;
52
+ }): QueueItem;
53
+ /** An agent in this project that can hold the baton, or the reason it can't. */
54
+ mustTakeTurns(agentId: string): void;
55
+ /** Why the head can't go yet, or null when it can. */
56
+ queueBlocker(item: QueueItem): string | null;
57
+ /**
58
+ * Is a queued prompt's condition still unmet? The reason, or null to go.
59
+ *
60
+ * Every branch reads a fact the daemon already has — the clock, a goal's
61
+ * landing state, its checks — so nothing here can be wrong in an interesting
62
+ * way. A condition about a goal that no longer exists releases the prompt
63
+ * rather than holding it for ever.
64
+ */
65
+ conditionUnmet(when: QueueCondition): string | null;
66
+ /**
67
+ * A prompt held for an hour needs something to notice the hour arriving.
68
+ *
69
+ * Only ticks while such a prompt exists — the queue's other conditions are
70
+ * woken by the events they wait on (a goal landing, checks going green), and
71
+ * a timer that runs when nothing needs it is a battery someone else pays for.
72
+ */
73
+ watchClockConditions(q: QueueState): void;
74
+ /**
75
+ * Hold the queue because `agentId` asked the human something — but only when
76
+ * the queue is actually pointed at that agent. An orchestra worker's question
77
+ * is the orchestrator's to answer (see core/orchestra.ts) and shouldn't
78
+ * freeze a queue lined up for someone else.
79
+ */
80
+ holdQueueFor(agentId: string): void;
81
+ /**
82
+ * You answered, so the hold is over.
83
+ *
84
+ * Only a hold this agent's own question put there: a queue you paused
85
+ * yourself stays paused, and so does one stopped mid-turn. Without this, the
86
+ * next thing you typed while the agent worked would queue behind the held
87
+ * prompt and sit there, in a queue nothing was going to resume.
88
+ */
89
+ releaseQuestionHold(agentId: string): void;
90
+ kickQueue(): void;
91
+ /** Send the head of the queue if it may go; then look again. */
92
+ drainPromptQueue(): Promise<void>;
93
+ dispatchQueued(item: QueueItem): Promise<void>;
94
+ }
@@ -0,0 +1,222 @@
1
+ import { blockedBy } from "../../core/goal-lanes.js";
2
+ import { describeCondition, } from "../../core/prompt-queue.js";
3
+ import { isAdapter } from "../../types.js";
4
+ import { CLOCK_TICK_MS, questionHold } from '../runtime-support.js';
5
+ /** Owns queue state for exactly one open project. */
6
+ export class RuntimeQueue {
7
+ host;
8
+ constructor(host) {
9
+ this.host = host;
10
+ }
11
+ queueListeners = new Set();
12
+ draining = false;
13
+ /** When the project last went quiet, for a "after N quiet minutes" condition. */
14
+ quietSince = 0;
15
+ clockTimer = null;
16
+ /** Live queue changes, for the socket. Returns unsubscribe. */
17
+ onQueueChange(cb) {
18
+ this.queueListeners.add(cb);
19
+ return () => this.queueListeners.delete(cb);
20
+ }
21
+ /** Line a prompt up; it goes as soon as nothing ahead of it is in the way. */
22
+ enqueue(input) {
23
+ const t = input.target ?? { kind: "auto" };
24
+ if (t.kind === "agent")
25
+ this.mustTakeTurns(t.agentId);
26
+ const item = this.host.queue.add(input);
27
+ this.kickQueue();
28
+ return item;
29
+ }
30
+ /** Change a waiting prompt. A target this project can't run is refused now,
31
+ * not when the queue reaches it and has to stop. */
32
+ editQueued(itemId, patch) {
33
+ if (patch.target?.kind === "agent")
34
+ this.mustTakeTurns(patch.target.agentId);
35
+ const item = this.host.queue.edit(itemId, patch);
36
+ this.kickQueue();
37
+ return item;
38
+ }
39
+ /** An agent in this project that can hold the baton, or the reason it can't. */
40
+ mustTakeTurns(agentId) {
41
+ const agent = this.host.agents.get(agentId);
42
+ if (!agent)
43
+ throw new Error(`no agent "${agentId}" in this project`);
44
+ if (!isAdapter(agent))
45
+ throw new Error(`agent "${agentId}" is a bridge (read-only) — it cannot take turns`);
46
+ }
47
+ /** Why the head can't go yet, or null when it can. */
48
+ queueBlocker(item) {
49
+ // A condition comes first: a prompt held for 3am isn't waiting on an agent.
50
+ if (this.host.config.brain?.continuity && this.host.busySince.size)
51
+ return "waiting for the foreground native turn";
52
+ const held = item.when ? this.conditionUnmet(item.when) : null;
53
+ if (held)
54
+ return held;
55
+ const route = this.host.routeState();
56
+ const routing = route && (route.status === "running" || route.status === "waiting_human");
57
+ const holder = this.host.validHolder();
58
+ if (item.target.kind === "orchestra") {
59
+ const running = this.host.orchestra.runningScopes();
60
+ if (!running.length)
61
+ return null;
62
+ const allowed = Math.max(1, this.host.config.maxConcurrentGoals ?? 1);
63
+ // With lanes on, a queued goal that can't collide with what's running
64
+ // starts beside it; the rest wait, with the overlap named.
65
+ return blockedBy({ runId: "queued", goal: item.text, paths: [] }, running, allowed)
66
+ ?? null;
67
+ }
68
+ if (routing)
69
+ return "waiting for the running route";
70
+ if (item.target.kind === "agent" && this.host.busySince.has(item.target.agentId))
71
+ return `waiting for ${item.target.agentId} to finish its turn`;
72
+ if (holder && this.host.busySince.has(holder))
73
+ return `waiting for ${holder} to finish its turn`;
74
+ return null;
75
+ }
76
+ /**
77
+ * Is a queued prompt's condition still unmet? The reason, or null to go.
78
+ *
79
+ * Every branch reads a fact the daemon already has — the clock, a goal's
80
+ * landing state, its checks — so nothing here can be wrong in an interesting
81
+ * way. A condition about a goal that no longer exists releases the prompt
82
+ * rather than holding it for ever.
83
+ */
84
+ conditionUnmet(when) {
85
+ if (when.kind === "at") {
86
+ return Date.now() >= when.at ? null : describeCondition(when);
87
+ }
88
+ if (when.kind === "quiet") {
89
+ const busy = this.host.busySince.size > 0 || Boolean(this.host.orchestra.active());
90
+ if (busy) {
91
+ this.quietSince = 0;
92
+ return describeCondition(when);
93
+ }
94
+ if (!this.quietSince)
95
+ this.quietSince = Date.now();
96
+ return Date.now() - this.quietSince >= when.ms ? null : describeCondition(when);
97
+ }
98
+ const run = this.host.orchestra.get(when.runId);
99
+ if (!run)
100
+ return null; // the goal is gone: holding for it for ever helps nobody
101
+ if (when.kind === "landed") {
102
+ return run.landing?.state === "merged" ? null : describeCondition(when);
103
+ }
104
+ const checks = run.landing?.checks;
105
+ const green = Boolean(checks && !checks.failing.length && !checks.pending.length && checks.passing > 0);
106
+ return green ? null : describeCondition(when);
107
+ }
108
+ /**
109
+ * A prompt held for an hour needs something to notice the hour arriving.
110
+ *
111
+ * Only ticks while such a prompt exists — the queue's other conditions are
112
+ * woken by the events they wait on (a goal landing, checks going green), and
113
+ * a timer that runs when nothing needs it is a battery someone else pays for.
114
+ */
115
+ watchClockConditions(q) {
116
+ const needsClock = q.items.some((i) => i.when && (i.when.kind === "at" || i.when.kind === "quiet"));
117
+ if (needsClock && !this.clockTimer) {
118
+ this.clockTimer = setInterval(() => this.kickQueue(), CLOCK_TICK_MS);
119
+ this.clockTimer.unref?.();
120
+ }
121
+ else if (!needsClock && this.clockTimer) {
122
+ clearInterval(this.clockTimer);
123
+ this.clockTimer = null;
124
+ }
125
+ }
126
+ /**
127
+ * Hold the queue because `agentId` asked the human something — but only when
128
+ * the queue is actually pointed at that agent. An orchestra worker's question
129
+ * is the orchestrator's to answer (see core/orchestra.ts) and shouldn't
130
+ * freeze a queue lined up for someone else.
131
+ */
132
+ holdQueueFor(agentId) {
133
+ const head = this.host.queue.peek();
134
+ if (!head || this.host.queue.paused)
135
+ return;
136
+ const mine = head.target.kind === "agent" ? head.target.agentId === agentId : head.target.kind === "auto";
137
+ if (!mine)
138
+ return;
139
+ this.host.queue.setPaused(true, questionHold(agentId));
140
+ }
141
+ /**
142
+ * You answered, so the hold is over.
143
+ *
144
+ * Only a hold this agent's own question put there: a queue you paused
145
+ * yourself stays paused, and so does one stopped mid-turn. Without this, the
146
+ * next thing you typed while the agent worked would queue behind the held
147
+ * prompt and sit there, in a queue nothing was going to resume.
148
+ */
149
+ releaseQuestionHold(agentId) {
150
+ if (!this.host.queue.paused || this.host.queue.snapshot().reason !== questionHold(agentId))
151
+ return;
152
+ this.host.queue.setPaused(false);
153
+ }
154
+ kickQueue() {
155
+ if (this.host.closed || this.draining || this.host.queue.paused || !this.host.queue.length)
156
+ return;
157
+ queueMicrotask(() => void this.drainPromptQueue());
158
+ }
159
+ /** Send the head of the queue if it may go; then look again. */
160
+ async drainPromptQueue() {
161
+ if (this.host.closed || this.draining || this.host.queue.paused)
162
+ return;
163
+ const head = this.host.queue.peek();
164
+ if (!head || this.queueBlocker(head))
165
+ return;
166
+ this.draining = true;
167
+ // Out of the queue, then sent: what you can still see is what hasn't gone.
168
+ // (Leaving it in place until the send returns would survive a crash
169
+ // mid-dispatch, at the price of a prompt you can edit or remove after it
170
+ // has already reached the agent — a worse thing to be wrong about.)
171
+ const item = this.host.queue.shift();
172
+ try {
173
+ await this.dispatchQueued(item);
174
+ }
175
+ catch (err) {
176
+ // refused (budget, quarantine, policy, a missing agent): keep it where it
177
+ // was and stop, so you can edit it or send it elsewhere — never drop it
178
+ const message = err instanceof Error ? err.message : String(err);
179
+ if (!this.host.closed) {
180
+ this.host.queue.unshift(item);
181
+ this.host.queue.setPaused(true, `the next prompt wasn't sent: ${message}`);
182
+ this.host.appendIfOpen({ kind: "error", chat: item.chat, payload: { message: `queued prompt not sent: ${message}` } });
183
+ }
184
+ }
185
+ finally {
186
+ this.draining = false;
187
+ }
188
+ this.kickQueue();
189
+ }
190
+ async dispatchQueued(item) {
191
+ const t = item.target;
192
+ if (t.kind === "orchestra") {
193
+ await this.host.orchestra.start({
194
+ goal: item.text,
195
+ // A queued goal remembers the thread it was typed in. sendMessage
196
+ // below always honoured that; this branch dropped it (#100).
197
+ ...(item.chat ? { chat: item.chat } : {}),
198
+ ...(t.orchestrator ? { orchestrator: t.orchestrator } : {}),
199
+ ...(t.workers?.length ? { workers: t.workers } : {}),
200
+ ...(t.maxParallel ? { maxParallel: t.maxParallel } : {}),
201
+ ...(t.maxUsd ? { maxUsd: t.maxUsd } : {}),
202
+ ...(item.plan ? { plan: true } : {}),
203
+ });
204
+ return;
205
+ }
206
+ if (t.kind === "auto" && !item.plan) {
207
+ await this.host.startRoute({ task: item.text, spec: "auto" });
208
+ return;
209
+ }
210
+ // one agent: the baton moves to it first, as when you pick it and send
211
+ const to = t.kind === "agent" ? t.agentId : undefined;
212
+ const holder = this.host.validHolder();
213
+ if (to && holder && holder !== to)
214
+ await this.host.handoff(to, { source: item.source });
215
+ await this.host.sendMessage(item.text, to, { source: item.source, chat: item.chat, fromQueue: true,
216
+ requestId: item.continuity?.requestId ?? (item.editedAt ? `queue:${item.id}:edit:${item.editedAt}` : `queue:${item.id}`),
217
+ ...(item.continuity ? { capturedModel: item.continuity.model } : {}),
218
+ ...(item.plan ? { plan: true } : {}),
219
+ ...(item.length ? { length: item.length } : {}) });
220
+ }
221
+ }
222
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../../src/daemon/runtime/queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,EAEL,iBAAiB,GAMlB,MAAM,4BAA4B,CAAC;AAOpC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAmBpE,qDAAqD;AACrD,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAI,CAAC;IAExD,cAAc,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEpD,QAAQ,GAAG,KAAK,CAAC;IAEjB,iFAAiF;IACjF,UAAU,GAAG,CAAC,CAAC;IAEf,UAAU,GAA0C,IAAI,CAAC;IAEzD,+DAA+D;IAC/D,aAAa,CAAC,EAA2B;QACvC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,8EAA8E;IAC9E,OAAO,CAAC,KAAiB;QACvB,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,MAAe,EAAE,CAAC;QACpD,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;YAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;wDACoD;IACpD,UAAU,CAAC,MAAc,EAAE,KAA4F;QACrH,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,OAAO;YAAE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gFAAgF;IAChF,aAAa,CAAC,OAAe;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,OAAO,mBAAmB,CAAC,CAAC;QACrE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,kDAAkD,CAAC,CAAC;IAC9G,CAAC;IAED,sDAAsD;IACtD,YAAY,CAAC,IAAe;QAC1B,4EAA4E;QAC5E,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI;YAAE,OAAO,wCAAwC,CAAC;QACpH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/D,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,eAAe,CAAC,CAAC;QAC1F,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;YACpD,IAAI,CAAC,OAAO,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACjC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,IAAI,CAAC,CAAC,CAAC;YACtE,sEAAsE;YACtE,2DAA2D;YAC3D,OAAO,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC;mBAC9E,IAAI,CAAC;QACZ,CAAC;QACD,IAAI,OAAO;YAAE,OAAO,+BAA+B,CAAC;QACpD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,OAAO,eAAe,IAAI,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC;QACjJ,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO,eAAe,MAAM,qBAAqB,CAAC;QACjG,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;OAOG;IACH,cAAc,CAAC,IAAoB;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;YACnF,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBACpB,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,UAAU;gBAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC,CAAC,yDAAyD;QAChF,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAC,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC;QACnC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QACxG,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAED;;;;;;OAMG;IACH,oBAAoB,CAAC,CAAa;QAChC,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC;QACpG,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACnC,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;YACrE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5B,CAAC;aAAM,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,YAAY,CAAC,OAAe;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC;QAC1G,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;;OAOG;IACH,mBAAmB,CAAC,OAAe;QACjC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC;YAAE,OAAO;QACnG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,SAAS;QACP,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO;QACnG,cAAc,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,gEAAgE;IAChE,KAAK,CAAC,gBAAgB;QACpB,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO;QACxE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;YAAE,OAAO;QAC7C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,2EAA2E;QAC3E,oEAAoE;QACpE,yEAAyE;QACzE,oEAAoE;QACpE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAG,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,0EAA0E;YAC1E,wEAAwE;YACxE,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,gCAAgC,OAAO,EAAE,CAAC,CAAC;gBAC3E,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,2BAA2B,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;YACzH,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,IAAe;QAClC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC3B,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;gBAC9B,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,kEAAkE;gBAClE,6DAA6D;gBAC7D,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3D,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpD,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxD,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACpC,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,uEAAuE;QACvE,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,EAAE,IAAI,MAAM,IAAI,MAAM,KAAK,EAAE;YAAE,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACxF,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI;YAChG,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,EAAE,SAAS,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,EAAE,EAAE,CAAC;YACxH,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC;CACF"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Quota Relay: when an agent runs out of quota mid-task, the next one carries
3
+ * on, with the context, and the first takes the chat back when it resets.
4
+ *
5
+ * Recognising the limit is core/quota.ts. Here: which agent picks up (the
6
+ * project's `relay.to` order, or the other CLI agents in roster order — never
7
+ * a paid API model unless you list it), stopping the parked turn, handing the
8
+ * baton over with a briefing that says what happened, re-sending the request
9
+ * in the same chat, and — when nobody is left — queueing it for the moment the
10
+ * first agent's limit lifts. Everything it does is a `status` event in the
11
+ * thread, so the record says who did what and why.
12
+ */
13
+ import type { AgentConfig, EventKind, LoomEvent } from "../../types.js";
14
+ import type { QueueInput } from "../../core/prompt-queue.js";
15
+ export interface RelayConfig {
16
+ /** Off: a limit is reported, the work waits (default on). */
17
+ auto?: boolean;
18
+ /** Who picks up, in order (agent ids). Default: every other CLI agent in roster order. */
19
+ to?: string[];
20
+ /** Give the chat back to the first agent when its limit resets (default on). */
21
+ handBack?: boolean;
22
+ }
23
+ export interface RelayHost {
24
+ config(): {
25
+ relay?: RelayConfig;
26
+ agents: AgentConfig[];
27
+ };
28
+ busy(agentId: string): boolean;
29
+ /** The chat an agent's current turn is in. */
30
+ turnChat(agentId: string): string | undefined;
31
+ available(agentId: string): Promise<boolean>;
32
+ interrupt(chat: string): Promise<unknown>;
33
+ handoff(to: string): Promise<unknown>;
34
+ holder(): string | null;
35
+ setBriefing(agentId: string, text: string): void;
36
+ send(text: string, agentId: string, chat: string): Promise<unknown>;
37
+ enqueue(input: QueueInput): unknown;
38
+ list(opts: {
39
+ chat?: string;
40
+ limit?: number;
41
+ kinds?: EventKind[];
42
+ }): LoomEvent[];
43
+ append(e: {
44
+ kind: EventKind;
45
+ agentId?: string;
46
+ chat?: string;
47
+ payload: Record<string, unknown>;
48
+ }): LoomEvent;
49
+ warn(message: string, detail?: unknown): void;
50
+ }
51
+ export declare class QuotaRelay {
52
+ private readonly host;
53
+ /** agentId → when its limit lifts. */
54
+ private capped;
55
+ /** One relay per request: `${chat}:${requestEventId}`. */
56
+ private relayed;
57
+ constructor(host: RelayHost);
58
+ /** Is this agent out of quota right now? */
59
+ cappedUntil(agentId: string, now?: number): number | null;
60
+ /** Every agent out of quota, and until when — for status and the UI. */
61
+ caps(now?: number): Record<string, number>;
62
+ /**
63
+ * Where a new prompt for `agentId` should go: itself, or — while it's out of
64
+ * quota and relaying is on — whoever would pick up its work.
65
+ */
66
+ route(agentId: string, chat?: string): Promise<string>;
67
+ /** Every agent event passes through: a limit starts a relay. */
68
+ observe(event: LoomEvent): void;
69
+ private onLimit;
70
+ /** Who picks up from `from`: the configured order, else the other CLI agents; available, not capped, not busy. */
71
+ private next;
72
+ private cap;
73
+ /** Hand-backs under way, so a prompt that arrives mid-way waits for the baton instead of missing it. */
74
+ private lifting;
75
+ /** Reset, but its stand-in was mid-turn: the baton goes back when that turn ends (agent → stand-in). */
76
+ private waitingBack;
77
+ /** Is the relay still holding this agent's work — out of quota, or not yet handed back? */
78
+ holds(agentId: string): boolean;
79
+ private backTimers;
80
+ /**
81
+ * Give the baton back once the stand-in is idle. Its run_complete usually says when (observe), but
82
+ * a turn winds down a moment after that event — a reset landing in between saw it "busy" with no
83
+ * run_complete left to come — so it is also looked at twice a second until then.
84
+ */
85
+ private waitBack;
86
+ private stopWaitingBack;
87
+ private giveBack;
88
+ /** The limit lifted: say so, and (by default) give the chat back — now if the stand-in is idle, else when its turn ends. */
89
+ private lift;
90
+ /** The request the turn was answering: the last message in the chat from a person (or a route), before `at`. */
91
+ private lastRequest;
92
+ stop(): void;
93
+ }
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Quota Relay: when an agent runs out of quota mid-task, the next one carries
3
+ * on, with the context, and the first takes the chat back when it resets.
4
+ *
5
+ * Recognising the limit is core/quota.ts. Here: which agent picks up (the
6
+ * project's `relay.to` order, or the other CLI agents in roster order — never
7
+ * a paid API model unless you list it), stopping the parked turn, handing the
8
+ * baton over with a briefing that says what happened, re-sending the request
9
+ * in the same chat, and — when nobody is left — queueing it for the moment the
10
+ * first agent's limit lifts. Everything it does is a `status` event in the
11
+ * thread, so the record says who did what and why.
12
+ */
13
+ import { backAt, quotaHit } from "../../core/quota.js";
14
+ import { MAIN_CHAT } from "../../types.js";
15
+ /** Kinds that are subscriptions with windows, not metered APIs — safe to hand work to by default. */
16
+ const CLI_KINDS = new Set(["claude-code", "codex", "opencode", "grok-code", "antigravity-cli", "agy"]);
17
+ export class QuotaRelay {
18
+ host;
19
+ /** agentId → when its limit lifts. */
20
+ capped = new Map();
21
+ /** One relay per request: `${chat}:${requestEventId}`. */
22
+ relayed = new Set();
23
+ constructor(host) {
24
+ this.host = host;
25
+ }
26
+ /** Is this agent out of quota right now? */
27
+ cappedUntil(agentId, now = Date.now()) {
28
+ const c = this.capped.get(agentId);
29
+ return c && c.resetAt > now ? c.resetAt : null;
30
+ }
31
+ /** Every agent out of quota, and until when — for status and the UI. */
32
+ caps(now = Date.now()) {
33
+ return Object.fromEntries([...this.capped].filter(([, c]) => c.resetAt > now).map(([id, c]) => [id, c.resetAt]));
34
+ }
35
+ /**
36
+ * Where a new prompt for `agentId` should go: itself, or — while it's out of
37
+ * quota and relaying is on — whoever would pick up its work.
38
+ */
39
+ async route(agentId, chat = MAIN_CHAT) {
40
+ // the window reset but the baton isn't back yet (its timer hasn't fired, or the hand-back is
41
+ // mid-flight): finish giving it back first, so the prompt goes to the agent it was meant for
42
+ const c = this.capped.get(agentId);
43
+ if (c && !this.cappedUntil(agentId)) {
44
+ if (c.timer)
45
+ clearTimeout(c.timer);
46
+ await this.lift(agentId);
47
+ }
48
+ // its stand-in was mid-turn at the reset, so the baton was going back when that turn ended;
49
+ // a prompt for this agent now is you choosing it — give it back now, as picking it and sending does
50
+ const standIn = this.waitingBack.get(agentId);
51
+ if (standIn) {
52
+ this.waitingBack.delete(agentId);
53
+ if (this.host.holder() === standIn)
54
+ await this.giveBack(agentId);
55
+ }
56
+ const lifting = this.lifting.get(agentId);
57
+ if (lifting)
58
+ await lifting;
59
+ if (!this.cappedUntil(agentId) || this.host.config().relay?.auto === false)
60
+ return agentId;
61
+ const next = await this.next(agentId);
62
+ if (!next)
63
+ return agentId;
64
+ this.host.append({ kind: "status", chat: chat === MAIN_CHAT ? undefined : chat, payload: {
65
+ state: "quota_redirect", from: agentId, to: next, resetAt: this.cappedUntil(agentId),
66
+ text: `${agentId} is out of quota until ${backAt(this.cappedUntil(agentId))} — ${next} takes this one`
67
+ } });
68
+ return next;
69
+ }
70
+ /** Every agent event passes through: a limit starts a relay. */
71
+ observe(event) {
72
+ if (!event.agentId)
73
+ return;
74
+ if (event.kind === "run_complete")
75
+ for (const [agentId, standIn] of [...this.waitingBack]) {
76
+ if (standIn !== event.agentId)
77
+ continue;
78
+ this.waitingBack.delete(agentId);
79
+ if (this.host.holder() === standIn)
80
+ this.giveBack(agentId);
81
+ }
82
+ const hit = quotaHit(event);
83
+ if (hit)
84
+ void this.onLimit(event.agentId, event, hit).catch((err) => this.host.warn("quota relay failed", err));
85
+ }
86
+ async onLimit(agentId, event, hit) {
87
+ const chat = event.chat ?? this.host.turnChat(agentId) ?? MAIN_CHAT;
88
+ const already = this.capped.get(agentId);
89
+ if (!already || already.resetAt < hit.resetAt)
90
+ this.cap(agentId, hit.resetAt, chat);
91
+ const request = this.lastRequest(chat, event.id);
92
+ const key = `${chat}:${request?.id ?? event.id}`;
93
+ if (this.relayed.has(key))
94
+ return;
95
+ this.relayed.add(key);
96
+ if (this.relayed.size > 500)
97
+ this.relayed.delete(this.relayed.values().next().value);
98
+ const where = chat === MAIN_CHAT ? undefined : chat;
99
+ const back = backAt(hit.resetAt);
100
+ if (this.host.config().relay?.auto === false || !request) {
101
+ this.host.append({ kind: "status", agentId, chat: where, payload: { state: "quota_limit", resetAt: hit.resetAt, known: hit.known,
102
+ reason: hit.reason, text: `${agentId} is out of quota${hit.known ? ` until ${back}` : ""}; the work waits${request ? " (relay is off)" : ""}` } });
103
+ return;
104
+ }
105
+ // a parked turn (Claude waits inside the CLI until the reset) is stopped, so it can be handed on
106
+ if (this.host.busy(agentId))
107
+ await this.host.interrupt(chat).catch(() => { });
108
+ const next = await this.next(agentId);
109
+ const prompt = String(request.payload.text ?? "");
110
+ if (!next) {
111
+ // nobody left: the request waits in the queue for the first agent's reset
112
+ this.host.enqueue({ text: prompt, target: { kind: "agent", agentId }, chat, source: "route", when: { kind: "at", at: hit.resetAt } });
113
+ this.host.append({ kind: "status", agentId, chat: where, payload: { state: "quota_relay", from: agentId, to: null, resetAt: hit.resetAt,
114
+ reason: hit.reason, text: `${agentId} is out of quota and no other agent can take over — queued for ${back}, when it resets` } });
115
+ return;
116
+ }
117
+ const c = this.capped.get(agentId);
118
+ if (c) {
119
+ c.handedTo = next;
120
+ c.chat = chat;
121
+ }
122
+ this.host.append({ kind: "status", agentId, chat: where, payload: { state: "quota_relay", from: agentId, to: next, resetAt: hit.resetAt,
123
+ known: hit.known, reason: hit.reason, text: `${agentId} hit its usage limit — ${next} carries on${hit.known ? `; ${agentId} is back around ${back}` : ""}` } });
124
+ await this.host.handoff(next);
125
+ this.host.setBriefing(next, [
126
+ `[Loom quota relay] "${agentId}" was working on this request and ran out of usage quota (${hit.reason}).`,
127
+ "Its changes so far are in the working tree — read them before you change anything, then continue the task from where it stopped.",
128
+ "Don't start over unless what it did is wrong; say what you kept.",
129
+ ].join("\n"));
130
+ await this.host.send(prompt, next, chat);
131
+ }
132
+ /** Who picks up from `from`: the configured order, else the other CLI agents; available, not capped, not busy. */
133
+ async next(from) {
134
+ const cfg = this.host.config();
135
+ const enabled = cfg.agents.filter((a) => a.enabled !== false && a.id !== from);
136
+ const order = cfg.relay?.to?.length
137
+ ? cfg.relay.to.map((id) => enabled.find((a) => a.id === id)).filter((a) => Boolean(a))
138
+ : enabled.filter((a) => CLI_KINDS.has(a.kind) || a.kind === "echo");
139
+ for (const a of order) {
140
+ if (this.cappedUntil(a.id) || this.host.busy(a.id))
141
+ continue;
142
+ if (await this.host.available(a.id).catch(() => false))
143
+ return a.id;
144
+ }
145
+ return null;
146
+ }
147
+ cap(agentId, resetAt, chat) {
148
+ const prev = this.capped.get(agentId);
149
+ if (prev?.timer)
150
+ clearTimeout(prev.timer);
151
+ const delay = Math.max(0, Math.min(resetAt - Date.now(), 2 ** 31 - 1));
152
+ const timer = setTimeout(() => void this.lift(agentId), delay);
153
+ timer.unref?.();
154
+ this.capped.set(agentId, { resetAt, timer, ...(prev?.handedTo ? { handedTo: prev.handedTo } : {}), chat: prev?.chat ?? chat });
155
+ }
156
+ /** Hand-backs under way, so a prompt that arrives mid-way waits for the baton instead of missing it. */
157
+ lifting = new Map();
158
+ /** Reset, but its stand-in was mid-turn: the baton goes back when that turn ends (agent → stand-in). */
159
+ waitingBack = new Map();
160
+ /** Is the relay still holding this agent's work — out of quota, or not yet handed back? */
161
+ holds(agentId) { return this.capped.has(agentId) || this.lifting.has(agentId) || this.waitingBack.has(agentId); }
162
+ backTimers = new Map();
163
+ /**
164
+ * Give the baton back once the stand-in is idle. Its run_complete usually says when (observe), but
165
+ * a turn winds down a moment after that event — a reset landing in between saw it "busy" with no
166
+ * run_complete left to come — so it is also looked at twice a second until then.
167
+ */
168
+ waitBack(agentId, standIn) {
169
+ this.waitingBack.set(agentId, standIn);
170
+ if (this.backTimers.has(agentId))
171
+ return;
172
+ const t = setInterval(() => {
173
+ if (this.waitingBack.get(agentId) !== standIn)
174
+ return this.stopWaitingBack(agentId);
175
+ if (this.host.busy(standIn))
176
+ return;
177
+ this.stopWaitingBack(agentId);
178
+ this.waitingBack.delete(agentId);
179
+ if (this.host.holder() === standIn)
180
+ void this.giveBack(agentId);
181
+ }, 500);
182
+ t.unref?.();
183
+ this.backTimers.set(agentId, t);
184
+ }
185
+ stopWaitingBack(agentId) {
186
+ const t = this.backTimers.get(agentId);
187
+ if (t)
188
+ clearInterval(t);
189
+ this.backTimers.delete(agentId);
190
+ }
191
+ giveBack(agentId) {
192
+ this.stopWaitingBack(agentId);
193
+ const back = this.host.handoff(agentId).then(() => { }, () => { }).finally(() => this.lifting.delete(agentId));
194
+ this.lifting.set(agentId, back);
195
+ return back;
196
+ }
197
+ /** The limit lifted: say so, and (by default) give the chat back — now if the stand-in is idle, else when its turn ends. */
198
+ lift(agentId) {
199
+ const c = this.capped.get(agentId);
200
+ this.capped.delete(agentId);
201
+ if (!c)
202
+ return this.lifting.get(agentId) ?? Promise.resolve();
203
+ const chat = c.chat && c.chat !== MAIN_CHAT ? c.chat : undefined;
204
+ const wants = this.host.config().relay?.handBack !== false && c.handedTo && this.host.holder() === c.handedTo;
205
+ const busy = Boolean(wants && this.host.busy(c.handedTo));
206
+ this.host.append({ kind: "status", agentId, chat, payload: { state: "quota_reset", agentId,
207
+ text: `${agentId}'s usage limit reset${wants ? busy ? ` — the baton goes back to ${agentId} when ${c.handedTo} finishes` : ` — the baton is back with ${agentId}` : ""}` } });
208
+ if (!wants)
209
+ return Promise.resolve();
210
+ // the stand-in is mid-turn: don't cut it off — hand back when that turn ends (observe), or sooner if you ask for this agent
211
+ if (busy) {
212
+ this.waitBack(agentId, c.handedTo);
213
+ return Promise.resolve();
214
+ }
215
+ return this.giveBack(agentId);
216
+ }
217
+ /** The request the turn was answering: the last message in the chat from a person (or a route), before `at`. */
218
+ lastRequest(chat, at) {
219
+ const recent = this.host.list({ chat, limit: 200 });
220
+ for (let i = recent.length - 1; i >= 0; i--) {
221
+ const e = recent[i];
222
+ if (e.id > at)
223
+ continue;
224
+ if (e.kind === "message" && !e.agentId && String(e.payload.text ?? "").trim())
225
+ return e;
226
+ }
227
+ return null;
228
+ }
229
+ stop() {
230
+ for (const c of this.capped.values())
231
+ if (c.timer)
232
+ clearTimeout(c.timer);
233
+ this.capped.clear();
234
+ this.waitingBack.clear();
235
+ for (const t of this.backTimers.values())
236
+ clearInterval(t);
237
+ this.backTimers.clear();
238
+ }
239
+ }
240
+ //# sourceMappingURL=relay.js.map