agent-tempo 1.0.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 (484) hide show
  1. package/CLAUDE.md +213 -0
  2. package/LICENSE +21 -0
  3. package/README.md +289 -0
  4. package/assets/icon-32.png +0 -0
  5. package/assets/icon-512.png +0 -0
  6. package/assets/icon-64.png +0 -0
  7. package/assets/icon-dark-32.png +0 -0
  8. package/assets/icon-dark-64.png +0 -0
  9. package/assets/icon-dark.svg +9 -0
  10. package/assets/icon.svg +9 -0
  11. package/assets/logo-dark.svg +11 -0
  12. package/assets/logo-light.svg +11 -0
  13. package/dashboard/README.md +91 -0
  14. package/dashboard/dist/assets/index-CB78ToNE.css +2 -0
  15. package/dashboard/dist/assets/index-_5jV0Znu.js +62 -0
  16. package/dashboard/dist/assets/index-_5jV0Znu.js.map +1 -0
  17. package/dashboard/dist/index.html +21 -0
  18. package/dashboard/package.json +47 -0
  19. package/dist/activities/hard-terminate.d.ts +32 -0
  20. package/dist/activities/hard-terminate.js +460 -0
  21. package/dist/activities/maestro.d.ts +72 -0
  22. package/dist/activities/maestro.js +254 -0
  23. package/dist/activities/outbox.d.ts +188 -0
  24. package/dist/activities/outbox.js +849 -0
  25. package/dist/activities/resolve.d.ts +64 -0
  26. package/dist/activities/resolve.js +129 -0
  27. package/dist/activities/schedule-fire.d.ts +36 -0
  28. package/dist/activities/schedule-fire.js +147 -0
  29. package/dist/adapters/base.d.ts +426 -0
  30. package/dist/adapters/base.js +1270 -0
  31. package/dist/adapters/claude-api/adapter.d.ts +168 -0
  32. package/dist/adapters/claude-api/adapter.js +797 -0
  33. package/dist/adapters/claude-api/api-error.d.ts +96 -0
  34. package/dist/adapters/claude-api/api-error.js +191 -0
  35. package/dist/adapters/claude-api/index.d.ts +16 -0
  36. package/dist/adapters/claude-api/index.js +21 -0
  37. package/dist/adapters/claude-api/mcp-bridge.d.ts +50 -0
  38. package/dist/adapters/claude-api/mcp-bridge.js +157 -0
  39. package/dist/adapters/claude-code/adapter.d.ts +133 -0
  40. package/dist/adapters/claude-code/adapter.js +274 -0
  41. package/dist/adapters/claude-code/index.d.ts +15 -0
  42. package/dist/adapters/claude-code/index.js +20 -0
  43. package/dist/adapters/claude-code-headless/adapter.d.ts +131 -0
  44. package/dist/adapters/claude-code-headless/adapter.js +710 -0
  45. package/dist/adapters/claude-code-headless/error-mapper.d.ts +107 -0
  46. package/dist/adapters/claude-code-headless/error-mapper.js +281 -0
  47. package/dist/adapters/claude-code-headless/index.d.ts +17 -0
  48. package/dist/adapters/claude-code-headless/index.js +26 -0
  49. package/dist/adapters/claude-code-headless/pre-flight.d.ts +51 -0
  50. package/dist/adapters/claude-code-headless/pre-flight.js +207 -0
  51. package/dist/adapters/claude-code-headless/prompt.d.ts +93 -0
  52. package/dist/adapters/claude-code-headless/prompt.js +79 -0
  53. package/dist/adapters/claude-code-headless/stream-json.d.ts +242 -0
  54. package/dist/adapters/claude-code-headless/stream-json.js +208 -0
  55. package/dist/adapters/claude-code-headless/types.d.ts +28 -0
  56. package/dist/adapters/claude-code-headless/types.js +36 -0
  57. package/dist/adapters/copilot/adapter.d.ts +100 -0
  58. package/dist/adapters/copilot/adapter.js +730 -0
  59. package/dist/adapters/copilot/index.d.ts +15 -0
  60. package/dist/adapters/copilot/index.js +20 -0
  61. package/dist/adapters/index.d.ts +42 -0
  62. package/dist/adapters/index.js +115 -0
  63. package/dist/adapters/opencode/adapter.d.ts +82 -0
  64. package/dist/adapters/opencode/adapter.js +710 -0
  65. package/dist/adapters/opencode/config.d.ts +90 -0
  66. package/dist/adapters/opencode/config.js +137 -0
  67. package/dist/adapters/opencode/helpers.d.ts +40 -0
  68. package/dist/adapters/opencode/helpers.js +144 -0
  69. package/dist/adapters/opencode/index.d.ts +12 -0
  70. package/dist/adapters/opencode/index.js +17 -0
  71. package/dist/adapters/opencode/server-bridge.d.ts +124 -0
  72. package/dist/adapters/opencode/server-bridge.js +216 -0
  73. package/dist/adapters/sdk/base.d.ts +95 -0
  74. package/dist/adapters/sdk/base.js +134 -0
  75. package/dist/adapters/sdk/system-prompt.d.ts +64 -0
  76. package/dist/adapters/sdk/system-prompt.js +78 -0
  77. package/dist/adapters/terminal-error.d.ts +27 -0
  78. package/dist/adapters/terminal-error.js +39 -0
  79. package/dist/channel.d.ts +3 -0
  80. package/dist/channel.js +48 -0
  81. package/dist/cli/commands.d.ts +245 -0
  82. package/dist/cli/commands.js +2438 -0
  83. package/dist/cli/config-command.d.ts +8 -0
  84. package/dist/cli/config-command.js +254 -0
  85. package/dist/cli/daemon-command.d.ts +57 -0
  86. package/dist/cli/daemon-command.js +493 -0
  87. package/dist/cli/daemon.d.ts +217 -0
  88. package/dist/cli/daemon.js +632 -0
  89. package/dist/cli/dashboard-command.d.ts +20 -0
  90. package/dist/cli/dashboard-command.js +241 -0
  91. package/dist/cli/dev-banner.d.ts +107 -0
  92. package/dist/cli/dev-banner.js +190 -0
  93. package/dist/cli/dev-mode-bootstrap.d.ts +29 -0
  94. package/dist/cli/dev-mode-bootstrap.js +36 -0
  95. package/dist/cli/dev-verbs.d.ts +43 -0
  96. package/dist/cli/dev-verbs.js +254 -0
  97. package/dist/cli/help-text.d.ts +1 -0
  98. package/dist/cli/help-text.js +158 -0
  99. package/dist/cli/legacy-migration.d.ts +35 -0
  100. package/dist/cli/legacy-migration.js +335 -0
  101. package/dist/cli/mcp.d.ts +8 -0
  102. package/dist/cli/mcp.js +63 -0
  103. package/dist/cli/output.d.ts +12 -0
  104. package/dist/cli/output.js +37 -0
  105. package/dist/cli/preflight.d.ts +9 -0
  106. package/dist/cli/preflight.js +96 -0
  107. package/dist/cli/removed-verbs.d.ts +9 -0
  108. package/dist/cli/removed-verbs.js +78 -0
  109. package/dist/cli/sa-preflight.d.ts +99 -0
  110. package/dist/cli/sa-preflight.js +183 -0
  111. package/dist/cli/scenarios-command.d.ts +6 -0
  112. package/dist/cli/scenarios-command.js +167 -0
  113. package/dist/cli/startup.d.ts +112 -0
  114. package/dist/cli/startup.js +641 -0
  115. package/dist/cli/upgrade-command.d.ts +5 -0
  116. package/dist/cli/upgrade-command.js +240 -0
  117. package/dist/cli.d.ts +2 -0
  118. package/dist/cli.js +680 -0
  119. package/dist/client/core.d.ts +33 -0
  120. package/dist/client/core.js +1260 -0
  121. package/dist/client/ensure-conductor-spawned.d.ts +35 -0
  122. package/dist/client/ensure-conductor-spawned.js +48 -0
  123. package/dist/client/index.d.ts +32 -0
  124. package/dist/client/index.js +22 -0
  125. package/dist/client/interface.d.ts +461 -0
  126. package/dist/client/interface.js +2 -0
  127. package/dist/client/subscribe.d.ts +108 -0
  128. package/dist/client/subscribe.js +598 -0
  129. package/dist/client/with-spawn.d.ts +27 -0
  130. package/dist/client/with-spawn.js +87 -0
  131. package/dist/config.d.ts +323 -0
  132. package/dist/config.js +593 -0
  133. package/dist/connection.d.ts +7 -0
  134. package/dist/connection.js +46 -0
  135. package/dist/constants.d.ts +50 -0
  136. package/dist/constants.js +74 -0
  137. package/dist/copilot-bridge.d.ts +22 -0
  138. package/dist/copilot-bridge.js +565 -0
  139. package/dist/daemon-adapter-versions.d.ts +52 -0
  140. package/dist/daemon-adapter-versions.js +170 -0
  141. package/dist/daemon.d.ts +275 -0
  142. package/dist/daemon.js +989 -0
  143. package/dist/ensemble/agent-types.d.ts +23 -0
  144. package/dist/ensemble/agent-types.js +132 -0
  145. package/dist/ensemble/loader.d.ts +14 -0
  146. package/dist/ensemble/loader.js +140 -0
  147. package/dist/ensemble/saver.d.ts +49 -0
  148. package/dist/ensemble/saver.js +201 -0
  149. package/dist/ensemble/schema.d.ts +71 -0
  150. package/dist/ensemble/schema.js +3 -0
  151. package/dist/git-info.d.ts +4 -0
  152. package/dist/git-info.js +29 -0
  153. package/dist/http/aggregate.d.ts +319 -0
  154. package/dist/http/aggregate.js +684 -0
  155. package/dist/http/auth.d.ts +67 -0
  156. package/dist/http/auth.js +177 -0
  157. package/dist/http/body.d.ts +71 -0
  158. package/dist/http/body.js +121 -0
  159. package/dist/http/catalog.d.ts +67 -0
  160. package/dist/http/catalog.js +209 -0
  161. package/dist/http/cors.d.ts +42 -0
  162. package/dist/http/cors.js +111 -0
  163. package/dist/http/dashboard-pair.d.ts +94 -0
  164. package/dist/http/dashboard-pair.js +148 -0
  165. package/dist/http/dashboard.d.ts +20 -0
  166. package/dist/http/dashboard.js +160 -0
  167. package/dist/http/event-bus.d.ts +217 -0
  168. package/dist/http/event-bus.js +365 -0
  169. package/dist/http/event-id.d.ts +77 -0
  170. package/dist/http/event-id.js +117 -0
  171. package/dist/http/event-types.d.ts +348 -0
  172. package/dist/http/event-types.js +36 -0
  173. package/dist/http/fixtures/chat-stress.d.ts +8 -0
  174. package/dist/http/fixtures/chat-stress.js +63 -0
  175. package/dist/http/fixtures/conductor-leaving.d.ts +8 -0
  176. package/dist/http/fixtures/conductor-leaving.js +80 -0
  177. package/dist/http/fixtures/constants.d.ts +10 -0
  178. package/dist/http/fixtures/constants.js +13 -0
  179. package/dist/http/fixtures/eight-player-broadcast.d.ts +10 -0
  180. package/dist/http/fixtures/eight-player-broadcast.js +81 -0
  181. package/dist/http/fixtures/empty-ensemble.d.ts +6 -0
  182. package/dist/http/fixtures/empty-ensemble.js +26 -0
  183. package/dist/http/fixtures/index.d.ts +55 -0
  184. package/dist/http/fixtures/index.js +110 -0
  185. package/dist/http/fixtures/single-conductor.d.ts +7 -0
  186. package/dist/http/fixtures/single-conductor.js +46 -0
  187. package/dist/http/fixtures/sse-reconnect.d.ts +8 -0
  188. package/dist/http/fixtures/sse-reconnect.js +77 -0
  189. package/dist/http/index.d.ts +21 -0
  190. package/dist/http/index.js +61 -0
  191. package/dist/http/port-file.d.ts +22 -0
  192. package/dist/http/port-file.js +132 -0
  193. package/dist/http/responses.d.ts +27 -0
  194. package/dist/http/responses.js +40 -0
  195. package/dist/http/ring-buffer.d.ts +41 -0
  196. package/dist/http/ring-buffer.js +80 -0
  197. package/dist/http/server.d.ts +122 -0
  198. package/dist/http/server.js +459 -0
  199. package/dist/http/snapshot.d.ts +85 -0
  200. package/dist/http/snapshot.js +180 -0
  201. package/dist/http/sse-handler.d.ts +87 -0
  202. package/dist/http/sse-handler.js +294 -0
  203. package/dist/http/writes.d.ts +55 -0
  204. package/dist/http/writes.js +240 -0
  205. package/dist/palette/index.d.ts +138 -0
  206. package/dist/palette/index.js +221 -0
  207. package/dist/reconcile/orphans.d.ts +255 -0
  208. package/dist/reconcile/orphans.js +340 -0
  209. package/dist/scripts/258-spotcheck.js +303 -0
  210. package/dist/scripts/check-components-css-sync.js +199 -0
  211. package/dist/scripts/run-shard.js +121 -0
  212. package/dist/scripts/verify-daemon-isolation-guard.js +128 -0
  213. package/dist/server-tools.d.ts +87 -0
  214. package/dist/server-tools.js +146 -0
  215. package/dist/server.d.ts +2 -0
  216. package/dist/server.js +366 -0
  217. package/dist/spawn.d.ts +296 -0
  218. package/dist/spawn.js +747 -0
  219. package/dist/tools/agent-types.d.ts +2 -0
  220. package/dist/tools/agent-types.js +21 -0
  221. package/dist/tools/attachment-info.d.ts +4 -0
  222. package/dist/tools/attachment-info.js +48 -0
  223. package/dist/tools/broadcast.d.ts +4 -0
  224. package/dist/tools/broadcast.js +76 -0
  225. package/dist/tools/cancel-stage.d.ts +3 -0
  226. package/dist/tools/cancel-stage.js +20 -0
  227. package/dist/tools/clear-state.d.ts +3 -0
  228. package/dist/tools/clear-state.js +37 -0
  229. package/dist/tools/coat-check-evict.d.ts +4 -0
  230. package/dist/tools/coat-check-evict.js +43 -0
  231. package/dist/tools/coat-check-get.d.ts +4 -0
  232. package/dist/tools/coat-check-get.js +56 -0
  233. package/dist/tools/coat-check-list.d.ts +4 -0
  234. package/dist/tools/coat-check-list.js +60 -0
  235. package/dist/tools/coat-check-put.d.ts +4 -0
  236. package/dist/tools/coat-check-put.js +53 -0
  237. package/dist/tools/cue.d.ts +44 -0
  238. package/dist/tools/cue.js +201 -0
  239. package/dist/tools/destroy.d.ts +4 -0
  240. package/dist/tools/destroy.js +188 -0
  241. package/dist/tools/detach.d.ts +4 -0
  242. package/dist/tools/detach.js +45 -0
  243. package/dist/tools/encore.d.ts +4 -0
  244. package/dist/tools/encore.js +31 -0
  245. package/dist/tools/ensemble.d.ts +32 -0
  246. package/dist/tools/ensemble.js +198 -0
  247. package/dist/tools/evaluate-gate.d.ts +3 -0
  248. package/dist/tools/evaluate-gate.js +32 -0
  249. package/dist/tools/fetch-state.d.ts +13 -0
  250. package/dist/tools/fetch-state.js +78 -0
  251. package/dist/tools/gates.d.ts +3 -0
  252. package/dist/tools/gates.js +41 -0
  253. package/dist/tools/helpers.d.ts +21 -0
  254. package/dist/tools/helpers.js +25 -0
  255. package/dist/tools/hosts.d.ts +4 -0
  256. package/dist/tools/hosts.js +40 -0
  257. package/dist/tools/listen.d.ts +3 -0
  258. package/dist/tools/listen.js +22 -0
  259. package/dist/tools/load-lineup.d.ts +5 -0
  260. package/dist/tools/load-lineup.js +381 -0
  261. package/dist/tools/migrate.d.ts +4 -0
  262. package/dist/tools/migrate.js +60 -0
  263. package/dist/tools/pause-ensemble.d.ts +4 -0
  264. package/dist/tools/pause-ensemble.js +58 -0
  265. package/dist/tools/pause.d.ts +4 -0
  266. package/dist/tools/pause.js +36 -0
  267. package/dist/tools/play.d.ts +4 -0
  268. package/dist/tools/play.js +57 -0
  269. package/dist/tools/quality-gate.d.ts +3 -0
  270. package/dist/tools/quality-gate.js +26 -0
  271. package/dist/tools/recall.d.ts +3 -0
  272. package/dist/tools/recall.js +32 -0
  273. package/dist/tools/recruit.d.ts +38 -0
  274. package/dist/tools/recruit.js +447 -0
  275. package/dist/tools/release.d.ts +4 -0
  276. package/dist/tools/release.js +98 -0
  277. package/dist/tools/report.d.ts +3 -0
  278. package/dist/tools/report.js +29 -0
  279. package/dist/tools/resolve.d.ts +1 -0
  280. package/dist/tools/resolve.js +7 -0
  281. package/dist/tools/restart.d.ts +35 -0
  282. package/dist/tools/restart.js +131 -0
  283. package/dist/tools/restore.d.ts +4 -0
  284. package/dist/tools/restore.js +107 -0
  285. package/dist/tools/resume-ensemble.d.ts +4 -0
  286. package/dist/tools/resume-ensemble.js +79 -0
  287. package/dist/tools/save-lineup.d.ts +4 -0
  288. package/dist/tools/save-lineup.js +36 -0
  289. package/dist/tools/save-state.d.ts +3 -0
  290. package/dist/tools/save-state.js +57 -0
  291. package/dist/tools/schedule.d.ts +4 -0
  292. package/dist/tools/schedule.js +152 -0
  293. package/dist/tools/schedules.d.ts +4 -0
  294. package/dist/tools/schedules.js +54 -0
  295. package/dist/tools/set-ensemble-description.d.ts +4 -0
  296. package/dist/tools/set-ensemble-description.js +37 -0
  297. package/dist/tools/set-name.d.ts +4 -0
  298. package/dist/tools/set-name.js +45 -0
  299. package/dist/tools/set-part.d.ts +3 -0
  300. package/dist/tools/set-part.js +20 -0
  301. package/dist/tools/shutdown.d.ts +4 -0
  302. package/dist/tools/shutdown.js +54 -0
  303. package/dist/tools/stage.d.ts +3 -0
  304. package/dist/tools/stage.js +28 -0
  305. package/dist/tools/stages.d.ts +3 -0
  306. package/dist/tools/stages.js +35 -0
  307. package/dist/tools/stop.d.ts +4 -0
  308. package/dist/tools/stop.js +29 -0
  309. package/dist/tools/unschedule.d.ts +4 -0
  310. package/dist/tools/unschedule.js +35 -0
  311. package/dist/tools/who-am-i.d.ts +3 -0
  312. package/dist/tools/who-am-i.js +34 -0
  313. package/dist/tools/worktree.d.ts +4 -0
  314. package/dist/tools/worktree.js +181 -0
  315. package/dist/tui/App.d.ts +85 -0
  316. package/dist/tui/App.js +1791 -0
  317. package/dist/tui/bootstrap-types.d.ts +46 -0
  318. package/dist/tui/bootstrap-types.js +7 -0
  319. package/dist/tui/client.d.ts +6 -0
  320. package/dist/tui/client.js +9 -0
  321. package/dist/tui/commands.d.ts +71 -0
  322. package/dist/tui/commands.js +1375 -0
  323. package/dist/tui/components/ActivityLog.d.ts +16 -0
  324. package/dist/tui/components/ActivityLog.js +36 -0
  325. package/dist/tui/components/ChatView.d.ts +35 -0
  326. package/dist/tui/components/ChatView.js +54 -0
  327. package/dist/tui/components/CommandOverlay.d.ts +15 -0
  328. package/dist/tui/components/CommandOverlay.js +34 -0
  329. package/dist/tui/components/CommandPalette.d.ts +21 -0
  330. package/dist/tui/components/CommandPalette.js +67 -0
  331. package/dist/tui/components/ConductorChat.d.ts +16 -0
  332. package/dist/tui/components/ConductorChat.js +32 -0
  333. package/dist/tui/components/ConversationStream.d.ts +114 -0
  334. package/dist/tui/components/ConversationStream.js +307 -0
  335. package/dist/tui/components/CreateEnsembleWizard.d.ts +19 -0
  336. package/dist/tui/components/CreateEnsembleWizard.js +223 -0
  337. package/dist/tui/components/DestroyConfirmModal.d.ts +17 -0
  338. package/dist/tui/components/DestroyConfirmModal.js +62 -0
  339. package/dist/tui/components/EnsembleListView.d.ts +14 -0
  340. package/dist/tui/components/EnsembleListView.js +32 -0
  341. package/dist/tui/components/EnsemblePanel.d.ts +12 -0
  342. package/dist/tui/components/EnsemblePanel.js +40 -0
  343. package/dist/tui/components/ErrorView.d.ts +31 -0
  344. package/dist/tui/components/ErrorView.js +129 -0
  345. package/dist/tui/components/HomeView.d.ts +54 -0
  346. package/dist/tui/components/HomeView.js +306 -0
  347. package/dist/tui/components/InputBar.d.ts +13 -0
  348. package/dist/tui/components/InputBar.js +58 -0
  349. package/dist/tui/components/LoadLineupModal.d.ts +18 -0
  350. package/dist/tui/components/LoadLineupModal.js +79 -0
  351. package/dist/tui/components/MainView.d.ts +21 -0
  352. package/dist/tui/components/MainView.js +107 -0
  353. package/dist/tui/components/NewEnsembleModal.d.ts +9 -0
  354. package/dist/tui/components/NewEnsembleModal.js +73 -0
  355. package/dist/tui/components/Picker.d.ts +23 -0
  356. package/dist/tui/components/Picker.js +70 -0
  357. package/dist/tui/components/PlayerDetailView.d.ts +26 -0
  358. package/dist/tui/components/PlayerDetailView.js +118 -0
  359. package/dist/tui/components/PromptArea.d.ts +50 -0
  360. package/dist/tui/components/PromptArea.js +303 -0
  361. package/dist/tui/components/RecruitWizard.d.ts +17 -0
  362. package/dist/tui/components/RecruitWizard.js +221 -0
  363. package/dist/tui/components/RestoreConfirmModal.d.ts +18 -0
  364. package/dist/tui/components/RestoreConfirmModal.js +71 -0
  365. package/dist/tui/components/ScheduleOverlay.d.ts +13 -0
  366. package/dist/tui/components/ScheduleOverlay.js +113 -0
  367. package/dist/tui/components/ScheduleWizard.d.ts +19 -0
  368. package/dist/tui/components/ScheduleWizard.js +259 -0
  369. package/dist/tui/components/Splash.d.ts +23 -0
  370. package/dist/tui/components/Splash.js +221 -0
  371. package/dist/tui/components/StatusBar.d.ts +48 -0
  372. package/dist/tui/components/StatusBar.js +128 -0
  373. package/dist/tui/components/StatusOverlay.d.ts +15 -0
  374. package/dist/tui/components/StatusOverlay.js +76 -0
  375. package/dist/tui/components/TitleBar.d.ts +10 -0
  376. package/dist/tui/components/TitleBar.js +21 -0
  377. package/dist/tui/components/TopBar.d.ts +12 -0
  378. package/dist/tui/components/TopBar.js +15 -0
  379. package/dist/tui/core-api.d.ts +26 -0
  380. package/dist/tui/core-api.js +67 -0
  381. package/dist/tui/hooks/useEnsembleDiscovery.d.ts +3 -0
  382. package/dist/tui/hooks/useEnsembleDiscovery.js +30 -0
  383. package/dist/tui/hooks/useMaestroPoller.d.ts +3 -0
  384. package/dist/tui/hooks/useMaestroPoller.js +36 -0
  385. package/dist/tui/hooks/useSendCommand.d.ts +7 -0
  386. package/dist/tui/hooks/useSendCommand.js +29 -0
  387. package/dist/tui/index.d.ts +15 -0
  388. package/dist/tui/index.js +156 -0
  389. package/dist/tui/ink-context.d.ts +18 -0
  390. package/dist/tui/ink-context.js +59 -0
  391. package/dist/tui/ink-loader.d.ts +26 -0
  392. package/dist/tui/ink-loader.js +42 -0
  393. package/dist/tui/removed-commands.d.ts +9 -0
  394. package/dist/tui/removed-commands.js +22 -0
  395. package/dist/tui/sse-handler.d.ts +52 -0
  396. package/dist/tui/sse-handler.js +157 -0
  397. package/dist/tui/store.d.ts +598 -0
  398. package/dist/tui/store.js +753 -0
  399. package/dist/tui/utils/format.d.ts +56 -0
  400. package/dist/tui/utils/format.js +155 -0
  401. package/dist/tui/utils/fullscreen.d.ts +23 -0
  402. package/dist/tui/utils/fullscreen.js +71 -0
  403. package/dist/tui/utils/history.d.ts +10 -0
  404. package/dist/tui/utils/history.js +85 -0
  405. package/dist/tui/utils/platform.d.ts +45 -0
  406. package/dist/tui/utils/platform.js +258 -0
  407. package/dist/tui/utils/theme.d.ts +21 -0
  408. package/dist/tui/utils/theme.js +24 -0
  409. package/dist/types.d.ts +1020 -0
  410. package/dist/types.js +39 -0
  411. package/dist/utils/attachment-format.d.ts +22 -0
  412. package/dist/utils/attachment-format.js +32 -0
  413. package/dist/utils/default-part.d.ts +43 -0
  414. package/dist/utils/default-part.js +104 -0
  415. package/dist/utils/duration.d.ts +30 -0
  416. package/dist/utils/duration.js +69 -0
  417. package/dist/utils/ensemble-ops.d.ts +61 -0
  418. package/dist/utils/ensemble-ops.js +77 -0
  419. package/dist/utils/format-hosts.d.ts +21 -0
  420. package/dist/utils/format-hosts.js +73 -0
  421. package/dist/utils/hosts.d.ts +113 -0
  422. package/dist/utils/hosts.js +265 -0
  423. package/dist/utils/parent-death-watchdog.d.ts +1 -0
  424. package/dist/utils/parent-death-watchdog.js +47 -0
  425. package/dist/utils/query-timeout.d.ts +103 -0
  426. package/dist/utils/query-timeout.js +113 -0
  427. package/dist/utils/recall-format.d.ts +78 -0
  428. package/dist/utils/recall-format.js +105 -0
  429. package/dist/utils/restore-format.d.ts +49 -0
  430. package/dist/utils/restore-format.js +91 -0
  431. package/dist/utils/safe-path.d.ts +10 -0
  432. package/dist/utils/safe-path.js +43 -0
  433. package/dist/utils/sdk-probe.d.ts +9 -0
  434. package/dist/utils/sdk-probe.js +45 -0
  435. package/dist/utils/search-attributes.d.ts +76 -0
  436. package/dist/utils/search-attributes.js +86 -0
  437. package/dist/utils/validation.d.ts +113 -0
  438. package/dist/utils/validation.js +163 -0
  439. package/dist/utils/visibility-deadline.d.ts +186 -0
  440. package/dist/utils/visibility-deadline.js +158 -0
  441. package/dist/utils/worktree.d.ts +103 -0
  442. package/dist/utils/worktree.js +327 -0
  443. package/dist/worker.d.ts +14 -0
  444. package/dist/worker.js +146 -0
  445. package/dist/workflows/attachment-math.d.ts +56 -0
  446. package/dist/workflows/attachment-math.js +47 -0
  447. package/dist/workflows/index.d.ts +3 -0
  448. package/dist/workflows/index.js +11 -0
  449. package/dist/workflows/maestro-signals.d.ts +217 -0
  450. package/dist/workflows/maestro-signals.js +155 -0
  451. package/dist/workflows/maestro.d.ts +3 -0
  452. package/dist/workflows/maestro.js +812 -0
  453. package/dist/workflows/scheduler-signals.d.ts +10 -0
  454. package/dist/workflows/scheduler-signals.js +14 -0
  455. package/dist/workflows/scheduler.d.ts +17 -0
  456. package/dist/workflows/scheduler.js +143 -0
  457. package/dist/workflows/session.d.ts +2 -0
  458. package/dist/workflows/session.js +1638 -0
  459. package/dist/workflows/signals.d.ts +297 -0
  460. package/dist/workflows/signals.js +239 -0
  461. package/examples/agents/tempo-composer.md +56 -0
  462. package/examples/agents/tempo-conductor.md +117 -0
  463. package/examples/agents/tempo-critic.md +73 -0
  464. package/examples/agents/tempo-improv.md +74 -0
  465. package/examples/agents/tempo-liner.md +75 -0
  466. package/examples/agents/tempo-roadie.md +61 -0
  467. package/examples/agents/tempo-soloist.md +71 -0
  468. package/examples/agents/tempo-tuner.md +94 -0
  469. package/examples/ensembles/tempo-big-band.yaml +146 -0
  470. package/examples/ensembles/tempo-dev-team.yaml +58 -0
  471. package/examples/ensembles/tempo-headless-jam.yaml +77 -0
  472. package/examples/ensembles/tempo-jam-session.yaml +41 -0
  473. package/examples/ensembles/tempo-mock-jam.yaml +79 -0
  474. package/examples/ensembles/tempo-review-squad.yaml +32 -0
  475. package/package.json +172 -0
  476. package/packaging/launchd/com.agent.tempo.plist +46 -0
  477. package/packaging/systemd/agent-tempo.service +32 -0
  478. package/packaging/windows/install-task.ps1 +71 -0
  479. package/scenarios/conductor-recruit-mock.yaml +33 -0
  480. package/scenarios/echo-roundtrip.yaml +15 -0
  481. package/scenarios/multi-player-handoff.yaml +38 -0
  482. package/scenarios/recruit-cascade.yaml +38 -0
  483. package/scenarios/two-player-conversation.yaml +33 -0
  484. package/workflow-bundle.js +14146 -0
@@ -0,0 +1,365 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EnsembleEventBus = exports.Subscription = exports.THROTTLE_SUPPRESS_MS = exports.RATE_LIMIT_WINDOW_MS = exports.DEFAULT_CHAT_RATE_LIMIT = exports.DEFAULT_ENSEMBLE_RATE_LIMIT = exports.DEFAULT_HEARTBEAT_SUPPRESS_MS = exports.DEFAULT_HEARTBEAT_MS = void 0;
4
+ exports.topicOf = topicOf;
5
+ exports.startHeartbeatTimer = startHeartbeatTimer;
6
+ /**
7
+ * `EnsembleEventBus` — fan-out + ring buffer + replay engine that backs
8
+ * the `/v1/events/:ensemble` SSE endpoint (SSE-PROTOCOL.md §6, §7, §8).
9
+ *
10
+ * **Responsibilities**:
11
+ * - Allocate `<bootEpoch>:<seq>` ids via {@link SeqAllocator}.
12
+ * - Buffer the most recent N events for `Last-Event-ID` replay.
13
+ * - Fan out to every live subscriber, with a per-subscription queue
14
+ * so a slow consumer doesn't backpressure faster ones.
15
+ * - Enforce wire-level rate caps (§8): ensemble-wide 50 ev/s ceiling
16
+ * produces a `throttled` event and pauses non-essential streams
17
+ * (`heartbeat`, `flags.changed`) for 1 s; chat 100 msg/s collapses
18
+ * to a single `chat.compressed`.
19
+ * - Heartbeat: emit `heartbeat` every `heartbeatMs` (default 10 s) on
20
+ * the bus, suppressed if any other event has been emitted in the
21
+ * last `heartbeatSuppressMs` (default 8 s).
22
+ *
23
+ * **NOT in this module**:
24
+ * - Coalescing (phase debounce, schedule SHA-256 diff, flag diff,
25
+ * host-profile hash compare) — those live in `aggregate.ts` and
26
+ * feed clean events to the bus.
27
+ * - SSE framing / `Last-Event-ID` parsing — `sse-handler.ts` owns
28
+ * that and consults the bus for replay slices.
29
+ */
30
+ const ring_buffer_1 = require("./ring-buffer");
31
+ /** Default heartbeat cadence — locked in by §6 / §8. */
32
+ exports.DEFAULT_HEARTBEAT_MS = 10_000;
33
+ /** Default heartbeat suppression window — §6. */
34
+ exports.DEFAULT_HEARTBEAT_SUPPRESS_MS = 8_000;
35
+ /** Ensemble-wide rate ceiling — §8. */
36
+ exports.DEFAULT_ENSEMBLE_RATE_LIMIT = 50;
37
+ /** Chat-only rate ceiling — §8. */
38
+ exports.DEFAULT_CHAT_RATE_LIMIT = 100;
39
+ /** Window over which both rate caps are evaluated. */
40
+ exports.RATE_LIMIT_WINDOW_MS = 1_000;
41
+ /** How long to suppress non-essential streams after `throttled` fires. */
42
+ exports.THROTTLE_SUPPRESS_MS = 1_000;
43
+ /** Event types that are essential — never dropped under throttling. */
44
+ const ESSENTIAL_TYPES = new Set([
45
+ 'snapshot',
46
+ 'gap',
47
+ 'throttled',
48
+ 'chat.compressed',
49
+ 'ensemble.created',
50
+ 'ensemble.destroyed',
51
+ 'player.added',
52
+ 'player.removed',
53
+ 'player.phase_changed',
54
+ 'chat.appended',
55
+ 'schedules.changed',
56
+ 'host_profile.changed',
57
+ ]);
58
+ /** Event types the bus suppresses for `THROTTLE_SUPPRESS_MS` after a `throttled` fires. */
59
+ const NON_ESSENTIAL_AFTER_THROTTLE = new Set([
60
+ 'heartbeat',
61
+ 'flags.changed',
62
+ ]);
63
+ /** Maps a `SseEventKind` to its filterable topic, or null when essential. */
64
+ function topicOf(kind) {
65
+ switch (kind) {
66
+ case 'player.phase_changed': return 'phase';
67
+ case 'chat.appended':
68
+ case 'chat.compressed': return 'chat';
69
+ case 'flags.changed': return 'flags';
70
+ case 'schedules.changed': return 'schedules';
71
+ case 'heartbeat': return 'heartbeat';
72
+ default: return null;
73
+ }
74
+ }
75
+ /**
76
+ * One open SSE connection's view of the bus. Async iterator yields
77
+ * events in the order the bus emitted them. `close()` is idempotent
78
+ * and must be called when the underlying socket goes away.
79
+ */
80
+ class Subscription {
81
+ opts;
82
+ queue = [];
83
+ resolveNext = null;
84
+ closed = false;
85
+ /** Caller's hook — bus calls this on close so the parent can drop us from its set. */
86
+ onClose = null;
87
+ constructor(opts) {
88
+ this.opts = opts;
89
+ }
90
+ /** Push an event onto the consumer queue. Bus → subscription. */
91
+ push(e) {
92
+ if (this.closed)
93
+ return;
94
+ if (!this.passesTopicFilter(e))
95
+ return;
96
+ if (this.resolveNext) {
97
+ const r = this.resolveNext;
98
+ this.resolveNext = null;
99
+ r({ value: e, done: false });
100
+ }
101
+ else {
102
+ this.queue.push(e);
103
+ }
104
+ }
105
+ next() {
106
+ if (this.closed && this.queue.length === 0) {
107
+ return Promise.resolve({ value: undefined, done: true });
108
+ }
109
+ if (this.queue.length > 0) {
110
+ return Promise.resolve({ value: this.queue.shift(), done: false });
111
+ }
112
+ return new Promise((resolve) => {
113
+ this.resolveNext = resolve;
114
+ });
115
+ }
116
+ async return() {
117
+ this.close();
118
+ return { value: undefined, done: true };
119
+ }
120
+ [Symbol.asyncIterator]() {
121
+ return this;
122
+ }
123
+ close() {
124
+ if (this.closed)
125
+ return;
126
+ this.closed = true;
127
+ if (this.resolveNext) {
128
+ const r = this.resolveNext;
129
+ this.resolveNext = null;
130
+ r({ value: undefined, done: true });
131
+ }
132
+ if (this.onClose) {
133
+ const fn = this.onClose;
134
+ this.onClose = null;
135
+ try {
136
+ fn();
137
+ }
138
+ catch { /* ignore — bus internal */ }
139
+ }
140
+ }
141
+ /** True when `close()` has been called. */
142
+ get isClosed() { return this.closed; }
143
+ /** Snapshot of unread items — exposed for tests + diagnostics only. */
144
+ get pending() { return this.queue; }
145
+ passesTopicFilter(e) {
146
+ if (!this.opts.topics)
147
+ return true;
148
+ const cat = topicOf(e.type);
149
+ if (cat === null)
150
+ return true; // essential / always-emit
151
+ return this.opts.topics.has(cat);
152
+ }
153
+ }
154
+ exports.Subscription = Subscription;
155
+ /** Concrete implementation. Same class powers per-ensemble + global buses. */
156
+ class EnsembleEventBus {
157
+ scope;
158
+ bootEpoch;
159
+ allocator;
160
+ ring;
161
+ now;
162
+ subs = new Set();
163
+ ensembleRateLimit;
164
+ chatRateLimit;
165
+ heartbeatMs;
166
+ heartbeatSuppressMs;
167
+ closed = false;
168
+ /** Sliding window of recent emit timestamps for the ensemble-wide cap. */
169
+ recentEmits = [];
170
+ /** Sliding window of recent chat emit timestamps. */
171
+ recentChat = [];
172
+ /** Last time *any* non-heartbeat event was emitted — drives §6 heartbeat suppression. */
173
+ lastNonHeartbeatAt = 0;
174
+ /** When set, suppress `heartbeat` and `flags.changed` until this timestamp (post-`throttled` window). */
175
+ nonEssentialSuppressUntil = 0;
176
+ /** Last time `throttled` was emitted — at most once per `THROTTLE_SUPPRESS_MS` window. */
177
+ lastThrottledAt = 0;
178
+ /**
179
+ * `chat.compressed` deferred-emission state (PR #324 review followup).
180
+ *
181
+ * **Why deferred**: §6 says "excess collapses into a single
182
+ * `chat.compressed` event" — singular. If we emitted on the first
183
+ * drop, the `dropped` field would always read `1` even when 50+
184
+ * messages got dropped in the same burst. Misleading metadata —
185
+ * eng-4's PR-3 wrapper might surface the count as "N messages
186
+ * dropped" or use it for retry logic.
187
+ *
188
+ * **Resolution**: track every drop in `chatDropCount`; on first
189
+ * drop schedule a `chat.compressed` emission `RATE_LIMIT_WINDOW_MS`
190
+ * later. Subsequent drops in the same burst just increment the
191
+ * counter — no second timer, no second event. When the timer
192
+ * fires, emit `chat.compressed { dropped: <total>, since: <iso> }`
193
+ * and reset. A 150-message burst at rate 1/s now yields one
194
+ * `chat.compressed { dropped: 149 }` event, matching the spec
195
+ * intent.
196
+ *
197
+ * Note: "compression event fired" (timer ran, message went on the
198
+ * wire) is separate from "drop count accumulated" (drops have
199
+ * happened but the timer is still pending). Tests differentiate
200
+ * the two by advancing the fake timer and re-draining.
201
+ */
202
+ chatDropCount = 0;
203
+ chatCompressedTimer = null;
204
+ constructor(opts) {
205
+ this.scope = opts.scope;
206
+ this.allocator = opts.allocator;
207
+ this.bootEpoch = opts.allocator.bootEpoch;
208
+ this.ring = (0, ring_buffer_1.createRingBuffer)(opts.bufferCapacity ?? ring_buffer_1.RING_BUFFER_CAPACITY);
209
+ this.now = opts.now ?? Date.now;
210
+ this.ensembleRateLimit = opts.ensembleRateLimit ?? exports.DEFAULT_ENSEMBLE_RATE_LIMIT;
211
+ this.chatRateLimit = opts.chatRateLimit ?? exports.DEFAULT_CHAT_RATE_LIMIT;
212
+ this.heartbeatMs = opts.heartbeatMs ?? exports.DEFAULT_HEARTBEAT_MS;
213
+ this.heartbeatSuppressMs = opts.heartbeatSuppressMs ?? exports.DEFAULT_HEARTBEAT_SUPPRESS_MS;
214
+ }
215
+ oldestSeq() { return this.ring.oldestSeq; }
216
+ newestSeq() { return this.ring.newestSeq; }
217
+ nextSeq() { return this.allocator.peekNextSeq(); }
218
+ subscriberCount() { return this.subs.size; }
219
+ emit(type, payload) {
220
+ if (this.closed)
221
+ return null;
222
+ const now = this.now();
223
+ // Heartbeat path: respect §6 suppression — skip when any other
224
+ // event was emitted within the last `heartbeatSuppressMs`.
225
+ if (type === 'heartbeat') {
226
+ if (now - this.lastNonHeartbeatAt < this.heartbeatSuppressMs)
227
+ return null;
228
+ if (now < this.nonEssentialSuppressUntil)
229
+ return null;
230
+ }
231
+ // §8 chat 100/s cap — collapse excess to a single `chat.compressed`.
232
+ if (type === 'chat.appended') {
233
+ this.trimWindow(this.recentChat, now);
234
+ if (this.recentChat.length >= this.chatRateLimit) {
235
+ this.chatDropCount++;
236
+ if (!this.chatCompressedTimer) {
237
+ // Defer emission so a single `chat.compressed` can carry the
238
+ // total burst count, not just the first drop. See the
239
+ // `chatDropCount` field comment for the contract.
240
+ this.chatCompressedTimer = setTimeout(() => this.flushChatCompressed(), exports.RATE_LIMIT_WINDOW_MS);
241
+ if (typeof this.chatCompressedTimer.unref === 'function') {
242
+ this.chatCompressedTimer.unref();
243
+ }
244
+ }
245
+ return null;
246
+ }
247
+ this.recentChat.push(now);
248
+ }
249
+ // §8 ensemble-wide 50/s cap — emit `throttled` once + suppress
250
+ // non-essential streams for 1 s.
251
+ if (NON_ESSENTIAL_AFTER_THROTTLE.has(type) && now < this.nonEssentialSuppressUntil) {
252
+ return null;
253
+ }
254
+ this.trimWindow(this.recentEmits, now);
255
+ if (!ESSENTIAL_TYPES.has(type) && this.recentEmits.length >= this.ensembleRateLimit) {
256
+ // Drop this non-essential event and emit `throttled` (capped per window).
257
+ if (now - this.lastThrottledAt >= exports.THROTTLE_SUPPRESS_MS) {
258
+ this.lastThrottledAt = now;
259
+ this.nonEssentialSuppressUntil = now + exports.THROTTLE_SUPPRESS_MS;
260
+ const since = new Date(now - exports.RATE_LIMIT_WINDOW_MS).toISOString();
261
+ this.emitInternal('throttled', { droppedSince: since, count: 1 }, now);
262
+ }
263
+ return null;
264
+ }
265
+ this.recentEmits.push(now);
266
+ return this.emitInternal(type, payload, now);
267
+ }
268
+ /**
269
+ * Internal emit — bypasses the §8 gates so the bus can self-emit
270
+ * `throttled` and `chat.compressed` while the gate is denying their
271
+ * trigger. Caller has already updated the rate-limit windows.
272
+ */
273
+ emitInternal(type, payload, now) {
274
+ const { eventId, tuple } = this.allocator.next();
275
+ const bufferable = type !== 'heartbeat'; // §7.1 — heartbeats are not replayed.
276
+ const event = { eventId, tuple, type, payload, emittedAt: now, bufferable };
277
+ if (bufferable)
278
+ this.ring.push({ seq: tuple.seq, payload: event });
279
+ if (type !== 'heartbeat')
280
+ this.lastNonHeartbeatAt = now;
281
+ for (const sub of this.subs)
282
+ sub.push(event);
283
+ return { eventId };
284
+ }
285
+ /**
286
+ * Emit the deferred `chat.compressed` event with the accumulated
287
+ * drop count, then reset. Called by the `setTimeout` scheduled in
288
+ * the chat-rate-cap path; tests may invoke it directly to bypass
289
+ * `vi.advanceTimersByTime` plumbing.
290
+ */
291
+ flushChatCompressed() {
292
+ this.chatCompressedTimer = null;
293
+ if (this.chatDropCount === 0)
294
+ return;
295
+ const dropped = this.chatDropCount;
296
+ this.chatDropCount = 0;
297
+ const now = this.now();
298
+ this.emitInternal('chat.compressed', {
299
+ dropped,
300
+ since: new Date(now - exports.RATE_LIMIT_WINDOW_MS).toISOString(),
301
+ }, now);
302
+ }
303
+ /** Test seam — force a deferred `chat.compressed` to flush synchronously. */
304
+ _flushChatCompressedForTest() {
305
+ if (this.chatCompressedTimer) {
306
+ clearTimeout(this.chatCompressedTimer);
307
+ this.chatCompressedTimer = null;
308
+ }
309
+ this.flushChatCompressed();
310
+ }
311
+ replayFrom(afterSeq) {
312
+ return this.ring.sliceFrom(afterSeq + 1).map((b) => b.payload);
313
+ }
314
+ subscribe(opts = {}) {
315
+ const sub = new Subscription(opts);
316
+ if (this.closed) {
317
+ // New subscriber on a closed bus — yield no events, just close.
318
+ sub.close();
319
+ return sub;
320
+ }
321
+ if (typeof opts.afterSeq === 'number') {
322
+ const replay = this.replayFrom(opts.afterSeq);
323
+ for (const e of replay)
324
+ sub.push(e);
325
+ }
326
+ sub.onClose = () => { this.subs.delete(sub); };
327
+ this.subs.add(sub);
328
+ return sub;
329
+ }
330
+ tickHeartbeat() {
331
+ return this.emit('heartbeat', { at: new Date(this.now()).toISOString() });
332
+ }
333
+ close() {
334
+ if (this.closed)
335
+ return;
336
+ this.closed = true;
337
+ if (this.chatCompressedTimer) {
338
+ clearTimeout(this.chatCompressedTimer);
339
+ this.chatCompressedTimer = null;
340
+ }
341
+ for (const sub of [...this.subs])
342
+ sub.close();
343
+ this.subs.clear();
344
+ }
345
+ /** Drop entries older than `now - RATE_LIMIT_WINDOW_MS` from a sliding window. */
346
+ trimWindow(window, now) {
347
+ const cutoff = now - exports.RATE_LIMIT_WINDOW_MS;
348
+ while (window.length > 0 && window[0] < cutoff)
349
+ window.shift();
350
+ }
351
+ }
352
+ exports.EnsembleEventBus = EnsembleEventBus;
353
+ /**
354
+ * Drive the heartbeat on a real timer. Returns a stop function. Call
355
+ * sites pass the bus's own `tickHeartbeat` so test wiring can stay
356
+ * synchronous.
357
+ */
358
+ function startHeartbeatTimer(bus, intervalMs = exports.DEFAULT_HEARTBEAT_MS) {
359
+ const handle = setInterval(() => { bus.tickHeartbeat(); }, intervalMs);
360
+ // Don't keep the daemon alive solely on the heartbeat — workers + HTTP
361
+ // listener are the durable long-running references.
362
+ if (typeof handle.unref === 'function')
363
+ handle.unref();
364
+ return () => clearInterval(handle);
365
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `<bootEpoch>:<seq>` event-id allocator (SSE-PROTOCOL.md §5).
3
+ *
4
+ * **Format**: `"<bootEpoch>:<seq>"`. Two decimal-ASCII parts separated by
5
+ * a single `:`. `bootEpoch` is the daemon process boot time as Unix
6
+ * epoch milliseconds, frozen for the process lifetime. `seq` is a
7
+ * uint64 monotonic counter (starting at `0`) owned by a specific bus.
8
+ *
9
+ * **Why**: a daemon restart must NOT silently lose the snapshot bridge.
10
+ * Without an epoch prefix, a client reconnecting with `Last-Event-ID:
11
+ * 1234` after a daemon restart would be `seq > ringStart=0` and the
12
+ * server would try to replay events that don't exist. The two-stage
13
+ * gate (epoch first → `gap epoch-mismatch`, then seq → `gap overflow`)
14
+ * fixes that.
15
+ *
16
+ * **Scope**: `bootEpoch` is process-global. `seq` is per-bus —
17
+ * `EnsembleEventBus` owns one counter per ensemble; the global bus
18
+ * owns its own. Both v2 upgrade paths in ADR 0004 preserve this
19
+ * contract through the `EnsembleEventBus` interface.
20
+ */
21
+ /** Parsed `(epoch, seq)` tuple. */
22
+ export interface EventIdTuple {
23
+ epoch: number;
24
+ seq: number;
25
+ }
26
+ /**
27
+ * Format an `(epoch, seq)` tuple to the wire token. Both components
28
+ * MUST be non-negative integers; callers should never reach for
29
+ * floating-point arithmetic on these values.
30
+ */
31
+ export declare function formatEventId(epoch: number, seq: number): string;
32
+ /**
33
+ * Parse a wire token back into a tuple. Returns `null` for malformed
34
+ * input — caller treats that the same as an `epoch-mismatch` gap (the
35
+ * client is from a previous daemon process / a corrupt header / etc.).
36
+ *
37
+ * Permissive on whitespace because some HTTP intermediaries normalize
38
+ * `Last-Event-ID`; rejects anything outside `[0-9]:[0-9]`.
39
+ */
40
+ export declare function parseEventId(token: string | undefined | null): EventIdTuple | null;
41
+ /**
42
+ * Compare two event-id tuples lexicographically — epoch first, then seq.
43
+ * Returns negative / zero / positive following the standard
44
+ * comparator convention.
45
+ */
46
+ export declare function compareEventIds(a: EventIdTuple, b: EventIdTuple): number;
47
+ /**
48
+ * Allocates `seq` values for one bus. Each call to {@link next} returns
49
+ * the next monotonic id token bound to the configured `bootEpoch`.
50
+ *
51
+ * `bootEpoch` is supplied by the caller — the daemon constructs one
52
+ * value (`Date.now()`) and threads it through every bus instance so
53
+ * every event in the same process lifetime shares the prefix.
54
+ *
55
+ * **Overflow**: `seq` is a JavaScript `number`, safe up to
56
+ * `Number.MAX_SAFE_INTEGER` (2^53 − 1). At a sustained 1 event/ms
57
+ * that's ~285,000 years before wrap, so practically unreachable.
58
+ * If a single bus ever did approach this limit, the bus would need
59
+ * to `continueAsNew`-style re-bootstrap with a fresh `bootEpoch` —
60
+ * documented here so the assumption is on the record rather than
61
+ * implicit in the type.
62
+ */
63
+ export declare class SeqAllocator {
64
+ readonly bootEpoch: number;
65
+ private nextSeq;
66
+ constructor(bootEpoch: number);
67
+ /** Allocate the next `(epoch, seq)` and return the formatted token. */
68
+ next(): {
69
+ eventId: string;
70
+ tuple: EventIdTuple;
71
+ };
72
+ /**
73
+ * The seq the next allocation will use — useful for ring buffer
74
+ * `ringStart` math without having to peek into a buffer.
75
+ */
76
+ peekNextSeq(): number;
77
+ }
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ /**
3
+ * `<bootEpoch>:<seq>` event-id allocator (SSE-PROTOCOL.md §5).
4
+ *
5
+ * **Format**: `"<bootEpoch>:<seq>"`. Two decimal-ASCII parts separated by
6
+ * a single `:`. `bootEpoch` is the daemon process boot time as Unix
7
+ * epoch milliseconds, frozen for the process lifetime. `seq` is a
8
+ * uint64 monotonic counter (starting at `0`) owned by a specific bus.
9
+ *
10
+ * **Why**: a daemon restart must NOT silently lose the snapshot bridge.
11
+ * Without an epoch prefix, a client reconnecting with `Last-Event-ID:
12
+ * 1234` after a daemon restart would be `seq > ringStart=0` and the
13
+ * server would try to replay events that don't exist. The two-stage
14
+ * gate (epoch first → `gap epoch-mismatch`, then seq → `gap overflow`)
15
+ * fixes that.
16
+ *
17
+ * **Scope**: `bootEpoch` is process-global. `seq` is per-bus —
18
+ * `EnsembleEventBus` owns one counter per ensemble; the global bus
19
+ * owns its own. Both v2 upgrade paths in ADR 0004 preserve this
20
+ * contract through the `EnsembleEventBus` interface.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.SeqAllocator = void 0;
24
+ exports.formatEventId = formatEventId;
25
+ exports.parseEventId = parseEventId;
26
+ exports.compareEventIds = compareEventIds;
27
+ /**
28
+ * Format an `(epoch, seq)` tuple to the wire token. Both components
29
+ * MUST be non-negative integers; callers should never reach for
30
+ * floating-point arithmetic on these values.
31
+ */
32
+ function formatEventId(epoch, seq) {
33
+ if (!Number.isInteger(epoch) || epoch < 0) {
34
+ throw new Error(`formatEventId: invalid epoch ${epoch}`);
35
+ }
36
+ if (!Number.isInteger(seq) || seq < 0) {
37
+ throw new Error(`formatEventId: invalid seq ${seq}`);
38
+ }
39
+ return `${epoch}:${seq}`;
40
+ }
41
+ /**
42
+ * Parse a wire token back into a tuple. Returns `null` for malformed
43
+ * input — caller treats that the same as an `epoch-mismatch` gap (the
44
+ * client is from a previous daemon process / a corrupt header / etc.).
45
+ *
46
+ * Permissive on whitespace because some HTTP intermediaries normalize
47
+ * `Last-Event-ID`; rejects anything outside `[0-9]:[0-9]`.
48
+ */
49
+ function parseEventId(token) {
50
+ if (token == null)
51
+ return null;
52
+ const trimmed = token.trim();
53
+ const m = /^(\d+):(\d+)$/.exec(trimmed);
54
+ if (!m)
55
+ return null;
56
+ const epoch = Number(m[1]);
57
+ const seq = Number(m[2]);
58
+ if (!Number.isFinite(epoch) || !Number.isFinite(seq))
59
+ return null;
60
+ if (!Number.isInteger(epoch) || !Number.isInteger(seq))
61
+ return null;
62
+ return { epoch, seq };
63
+ }
64
+ /**
65
+ * Compare two event-id tuples lexicographically — epoch first, then seq.
66
+ * Returns negative / zero / positive following the standard
67
+ * comparator convention.
68
+ */
69
+ function compareEventIds(a, b) {
70
+ if (a.epoch !== b.epoch)
71
+ return a.epoch < b.epoch ? -1 : 1;
72
+ if (a.seq !== b.seq)
73
+ return a.seq < b.seq ? -1 : 1;
74
+ return 0;
75
+ }
76
+ /**
77
+ * Allocates `seq` values for one bus. Each call to {@link next} returns
78
+ * the next monotonic id token bound to the configured `bootEpoch`.
79
+ *
80
+ * `bootEpoch` is supplied by the caller — the daemon constructs one
81
+ * value (`Date.now()`) and threads it through every bus instance so
82
+ * every event in the same process lifetime shares the prefix.
83
+ *
84
+ * **Overflow**: `seq` is a JavaScript `number`, safe up to
85
+ * `Number.MAX_SAFE_INTEGER` (2^53 − 1). At a sustained 1 event/ms
86
+ * that's ~285,000 years before wrap, so practically unreachable.
87
+ * If a single bus ever did approach this limit, the bus would need
88
+ * to `continueAsNew`-style re-bootstrap with a fresh `bootEpoch` —
89
+ * documented here so the assumption is on the record rather than
90
+ * implicit in the type.
91
+ */
92
+ class SeqAllocator {
93
+ bootEpoch;
94
+ nextSeq = 0;
95
+ constructor(bootEpoch) {
96
+ this.bootEpoch = bootEpoch;
97
+ if (!Number.isInteger(bootEpoch) || bootEpoch < 0) {
98
+ throw new Error(`SeqAllocator: invalid bootEpoch ${bootEpoch}`);
99
+ }
100
+ }
101
+ /** Allocate the next `(epoch, seq)` and return the formatted token. */
102
+ next() {
103
+ const seq = this.nextSeq++;
104
+ return {
105
+ eventId: formatEventId(this.bootEpoch, seq),
106
+ tuple: { epoch: this.bootEpoch, seq },
107
+ };
108
+ }
109
+ /**
110
+ * The seq the next allocation will use — useful for ring buffer
111
+ * `ringStart` math without having to peek into a buffer.
112
+ */
113
+ peekNextSeq() {
114
+ return this.nextSeq;
115
+ }
116
+ }
117
+ exports.SeqAllocator = SeqAllocator;