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,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.emptyEnsemble = void 0;
4
+ const constants_1 = require("./constants");
5
+ exports.emptyEnsemble = {
6
+ name: 'empty-ensemble',
7
+ description: 'No players, no chat, no schedules. Empty-state UI exercise.',
8
+ snapshot: {
9
+ v: 1,
10
+ ensemble: 'demo-empty',
11
+ capturedAt: '2026-04-27T00:00:00.000Z',
12
+ lastEventId: `${constants_1.FIXTURE_BOOT_EPOCH}:0`,
13
+ state: 'online',
14
+ hasConductor: false,
15
+ flags: { paused: false, held: false },
16
+ players: [],
17
+ schedules: [],
18
+ chat: { messages: [], total: 0, hasMore: false },
19
+ hostProfiles: {},
20
+ description: '',
21
+ startedAt: '',
22
+ currentBpm: 0,
23
+ tempoSeries: [],
24
+ },
25
+ events: [],
26
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Test-fixture mode for the daemon HTTP/SSE surface — PR-3 of #340.
3
+ *
4
+ * Adds a `?fixture=<name>` query param to `/v1/state/:ensemble` and
5
+ * `/v1/events/:ensemble`. When set to a known fixture, the daemon
6
+ * returns canned data instead of running live Temporal queries / wiring
7
+ * the aggregate poll loop.
8
+ *
9
+ * **Why this exists**: PR-4 onwards (dashboard SPA work) needs
10
+ * deterministic, reproducible scenarios — a conductor leaving, a
11
+ * broadcast fan-out, a chat-ring overflow, an SSE reconnect. Real
12
+ * ensemble events are flaky for UI-driven testing; fixtures aren't.
13
+ *
14
+ * **Auth posture**: fixture mode honours the existing bearer-auth gate
15
+ * (loopback no-auth, non-loopback bearer required). The fixture
16
+ * endpoint is NOT a backdoor — it's an alternate *projection* of an
17
+ * authorised request. See `docs/SSE-PROTOCOL.md` § 11a.
18
+ *
19
+ * **Type safety**: fixture data imports its types from
20
+ * {@link ../event-types} so a wire-protocol change here breaks the
21
+ * `tsc` build of every fixture module. Don't redeclare shapes inside
22
+ * fixture files.
23
+ */
24
+ import type { IncomingMessage, ServerResponse } from 'http';
25
+ import type { TempoEvent, EnsembleStateV1 } from '../event-types';
26
+ export interface FixtureScenario {
27
+ name: string;
28
+ description: string;
29
+ /** Returned by `/v1/state/:ensemble?fixture=<name>` verbatim. */
30
+ snapshot: EnsembleStateV1;
31
+ /** Walked in order by `/v1/events/:ensemble?fixture=<name>` after the snapshot prelude. */
32
+ events: TempoEvent[];
33
+ /** Delay between events in ms. `0` (default) ⇒ flush all at once. */
34
+ eventCadenceMs?: number;
35
+ }
36
+ /** Lookup by name. Returns `null` for unknown fixtures. */
37
+ export declare function getFixture(name: string): FixtureScenario | null;
38
+ /** Listing for diagnostics — used by potential future `/v1/fixtures` listing. */
39
+ export declare function listFixtures(): {
40
+ name: string;
41
+ description: string;
42
+ }[];
43
+ /** Handler for `GET /v1/state/:ensemble?fixture=<name>`. */
44
+ export declare function handleFixtureSnapshot(res: ServerResponse, fixtureName: string): void;
45
+ /**
46
+ * Handler for `GET /v1/events/:ensemble?fixture=<name>`. Streams the
47
+ * fixture's snapshot prelude followed by its event list, with optional
48
+ * inter-event delays. Closes the connection when all events have been
49
+ * delivered (or sooner if the client disconnects).
50
+ *
51
+ * The snapshot prelude reuses the fixture's `lastEventId` so a consumer
52
+ * comparing `Last-Event-ID` against subsequent events sees the
53
+ * snapshot ordered before the live events.
54
+ */
55
+ export declare function handleFixtureSse(req: IncomingMessage, res: ServerResponse, fixtureName: string): Promise<void>;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFixture = getFixture;
4
+ exports.listFixtures = listFixtures;
5
+ exports.handleFixtureSnapshot = handleFixtureSnapshot;
6
+ exports.handleFixtureSse = handleFixtureSse;
7
+ const responses_1 = require("../responses");
8
+ const sse_handler_1 = require("../sse-handler");
9
+ const empty_ensemble_1 = require("./empty-ensemble");
10
+ const single_conductor_1 = require("./single-conductor");
11
+ const eight_player_broadcast_1 = require("./eight-player-broadcast");
12
+ const conductor_leaving_1 = require("./conductor-leaving");
13
+ const sse_reconnect_1 = require("./sse-reconnect");
14
+ const chat_stress_1 = require("./chat-stress");
15
+ const FIXTURES = {
16
+ [empty_ensemble_1.emptyEnsemble.name]: empty_ensemble_1.emptyEnsemble,
17
+ [single_conductor_1.singleConductor.name]: single_conductor_1.singleConductor,
18
+ [eight_player_broadcast_1.eightPlayerBroadcast.name]: eight_player_broadcast_1.eightPlayerBroadcast,
19
+ [conductor_leaving_1.conductorLeaving.name]: conductor_leaving_1.conductorLeaving,
20
+ [sse_reconnect_1.sseReconnect.name]: sse_reconnect_1.sseReconnect,
21
+ [chat_stress_1.chatStress.name]: chat_stress_1.chatStress,
22
+ };
23
+ /** Lookup by name. Returns `null` for unknown fixtures. */
24
+ function getFixture(name) {
25
+ return FIXTURES[name] ?? null;
26
+ }
27
+ /** Listing for diagnostics — used by potential future `/v1/fixtures` listing. */
28
+ function listFixtures() {
29
+ return Object.values(FIXTURES).map((f) => ({ name: f.name, description: f.description }));
30
+ }
31
+ /** Handler for `GET /v1/state/:ensemble?fixture=<name>`. */
32
+ function handleFixtureSnapshot(res, fixtureName) {
33
+ const fixture = getFixture(fixtureName);
34
+ if (!fixture) {
35
+ return (0, responses_1.errorResponse)(res, 404, { error: 'unknown-fixture', fixture: fixtureName });
36
+ }
37
+ (0, responses_1.jsonResponse)(res, 200, fixture.snapshot);
38
+ }
39
+ /**
40
+ * Handler for `GET /v1/events/:ensemble?fixture=<name>`. Streams the
41
+ * fixture's snapshot prelude followed by its event list, with optional
42
+ * inter-event delays. Closes the connection when all events have been
43
+ * delivered (or sooner if the client disconnects).
44
+ *
45
+ * The snapshot prelude reuses the fixture's `lastEventId` so a consumer
46
+ * comparing `Last-Event-ID` against subsequent events sees the
47
+ * snapshot ordered before the live events.
48
+ */
49
+ async function handleFixtureSse(req, res, fixtureName) {
50
+ const fixture = getFixture(fixtureName);
51
+ if (!fixture) {
52
+ return (0, responses_1.errorResponse)(res, 404, { error: 'unknown-fixture', fixture: fixtureName });
53
+ }
54
+ (0, sse_handler_1.openSseResponse)(res, 'agent-tempo SSE (fixture)');
55
+ // AbortController is the single source of truth for "client disconnected".
56
+ // Fires on TCP drop, abort, or natural end-of-events. `once()` ensures
57
+ // each underlying close event registers exactly one tick, and the
58
+ // `finally` cleanup detaches the listeners regardless of how we exit.
59
+ const abort = new AbortController();
60
+ const onClose = () => abort.abort();
61
+ req.once('close', onClose);
62
+ res.once('close', onClose);
63
+ try {
64
+ if (abort.signal.aborted)
65
+ return;
66
+ res.write((0, sse_handler_1.frameSseEventData)(fixture.snapshot.lastEventId, 'snapshot', fixture.snapshot));
67
+ const cadence = fixture.eventCadenceMs ?? 0;
68
+ for (let i = 0; i < fixture.events.length; i++) {
69
+ if (abort.signal.aborted)
70
+ return;
71
+ const ev = fixture.events[i];
72
+ res.write((0, sse_handler_1.frameSseEventData)(ev.eventId, ev.type, ev.payload));
73
+ if (cadence > 0 && i < fixture.events.length - 1) {
74
+ const ok = await delay(cadence, abort.signal);
75
+ if (!ok)
76
+ return;
77
+ }
78
+ }
79
+ }
80
+ finally {
81
+ req.removeListener('close', onClose);
82
+ res.removeListener('close', onClose);
83
+ if (!res.writableEnded) {
84
+ try {
85
+ res.end();
86
+ }
87
+ catch { /* socket already gone */ }
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Sleep for `ms` milliseconds, returning `false` if the abort signal
93
+ * fires first. Lets the event loop unblock the moment the client
94
+ * disconnects rather than running out the cadence timer.
95
+ */
96
+ function delay(ms, signal) {
97
+ return new Promise((resolve) => {
98
+ if (signal.aborted)
99
+ return resolve(false);
100
+ const onAbort = () => {
101
+ clearTimeout(timer);
102
+ resolve(false);
103
+ };
104
+ const timer = setTimeout(() => {
105
+ signal.removeEventListener('abort', onAbort);
106
+ resolve(true);
107
+ }, ms);
108
+ signal.addEventListener('abort', onAbort, { once: true });
109
+ });
110
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Fixture: a single conductor player, no other players, no chat.
3
+ * Exercises the "conductor-only" lobby state the dashboard renders
4
+ * before any soloists join.
5
+ */
6
+ import type { FixtureScenario } from './index';
7
+ export declare const singleConductor: FixtureScenario;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.singleConductor = void 0;
4
+ const constants_1 = require("./constants");
5
+ exports.singleConductor = {
6
+ name: 'single-conductor',
7
+ description: 'One conductor, no other players. Lobby state.',
8
+ snapshot: {
9
+ v: 1,
10
+ ensemble: 'demo-conductor',
11
+ capturedAt: '2026-04-27T00:00:00.000Z',
12
+ lastEventId: `${constants_1.FIXTURE_BOOT_EPOCH}:0`,
13
+ state: 'online',
14
+ hasConductor: true,
15
+ flags: { paused: false, held: false },
16
+ players: [{
17
+ playerId: 'conductor',
18
+ ensemble: 'demo-conductor',
19
+ hostname: 'demo-host',
20
+ isConductor: true,
21
+ agentType: 'claude',
22
+ playerType: 'tempo-conductor',
23
+ phase: 'attached',
24
+ part: 'Orchestrating the demo',
25
+ workDir: '/repo/demo',
26
+ gitBranch: 'main',
27
+ lastHeartbeatAt: '2026-04-27T00:00:00.000Z',
28
+ }],
29
+ schedules: [],
30
+ chat: { messages: [], total: 0, hasMore: false },
31
+ hostProfiles: {
32
+ 'demo-host': {
33
+ hostname: 'demo-host',
34
+ version: '0.28.0',
35
+ defaultAgent: 'claude',
36
+ platform: 'linux',
37
+ capabilities: [],
38
+ },
39
+ },
40
+ description: '',
41
+ startedAt: '',
42
+ currentBpm: 0,
43
+ tempoSeries: [],
44
+ },
45
+ events: [],
46
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Fixture: a normal stream interrupted by a `gap` event mid-stream.
3
+ * Exercises the dashboard's reconnect / re-fetch flow — when a `gap`
4
+ * arrives, consumers SHOULD drop their cache and re-pull
5
+ * `/v1/state/:ensemble` (per SSE-PROTOCOL.md §7.2).
6
+ */
7
+ import type { FixtureScenario } from './index';
8
+ export declare const sseReconnect: FixtureScenario;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sseReconnect = void 0;
4
+ const constants_1 = require("./constants");
5
+ const ENSEMBLE = 'demo-reconnect';
6
+ exports.sseReconnect = {
7
+ name: 'sse-reconnect',
8
+ description: 'Two chat events, then a gap (overflow), then more chat. Tests the dashboard reconnect / re-fetch path.',
9
+ snapshot: {
10
+ v: 1,
11
+ ensemble: ENSEMBLE,
12
+ capturedAt: '2026-04-27T00:00:00.000Z',
13
+ lastEventId: `${constants_1.FIXTURE_BOOT_EPOCH}:0`,
14
+ state: 'online',
15
+ hasConductor: true,
16
+ flags: { paused: false, held: false },
17
+ players: [{
18
+ playerId: 'conductor',
19
+ ensemble: ENSEMBLE,
20
+ hostname: 'demo-host',
21
+ isConductor: true,
22
+ agentType: 'claude',
23
+ phase: 'attached',
24
+ part: 'Reconnect demo',
25
+ workDir: '/repo/demo',
26
+ }],
27
+ schedules: [],
28
+ chat: { messages: [], total: 0, hasMore: false },
29
+ hostProfiles: {},
30
+ description: '',
31
+ startedAt: '',
32
+ currentBpm: 0,
33
+ tempoSeries: [],
34
+ },
35
+ events: [
36
+ {
37
+ v: 1,
38
+ type: 'chat.appended',
39
+ eventId: `${constants_1.FIXTURE_BOOT_EPOCH}:1`,
40
+ payload: {
41
+ id: 'msg-1', from: 'maestro', to: 'conductor',
42
+ text: 'Hello before the gap.',
43
+ timestamp: '2026-04-27T00:00:01.000Z',
44
+ role: 'maestro-out',
45
+ },
46
+ },
47
+ {
48
+ v: 1,
49
+ type: 'chat.appended',
50
+ eventId: `${constants_1.FIXTURE_BOOT_EPOCH}:2`,
51
+ payload: {
52
+ id: 'msg-2', from: 'conductor', to: 'maestro',
53
+ text: 'About to drop a gap...',
54
+ timestamp: '2026-04-27T00:00:02.000Z',
55
+ role: 'conductor-in',
56
+ },
57
+ },
58
+ {
59
+ v: 1,
60
+ type: 'gap',
61
+ eventId: `${constants_1.FIXTURE_BOOT_EPOCH}:3`,
62
+ payload: { from: `${constants_1.FIXTURE_BOOT_EPOCH}:2`, to: `${constants_1.FIXTURE_BOOT_EPOCH}:50`, reason: 'overflow' },
63
+ },
64
+ {
65
+ v: 1,
66
+ type: 'chat.appended',
67
+ eventId: `${constants_1.FIXTURE_BOOT_EPOCH}:51`,
68
+ payload: {
69
+ id: 'msg-51', from: 'maestro', to: 'conductor',
70
+ text: 'After the gap — dashboard should have re-fetched.',
71
+ timestamp: '2026-04-27T00:00:05.000Z',
72
+ role: 'maestro-out',
73
+ },
74
+ },
75
+ ],
76
+ eventCadenceMs: 250,
77
+ };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Barrel re-exports for the daemon HTTP/SSE event source (#94, #95).
3
+ *
4
+ * - PR-1 (this file's first revision): snapshot endpoints + bearer/CORS
5
+ * middleware + port-file lifecycle. Drives `/v1/health`, `/v1/ensembles`,
6
+ * `/v1/state/:ensemble`, `/v1/hosts`.
7
+ * - PR-2 (future): `EnsembleEventBus`, ring buffer, `/v1/events*` SSE.
8
+ * - PR-3 (future, eng-4): `TempoClient.subscribe` AsyncIterable.
9
+ *
10
+ * Public surface kept narrow on purpose — implementation modules are the
11
+ * source of truth.
12
+ */
13
+ export { startHttpServer, DEFAULT_BIND_ADDR, DEFAULT_PORT, type HttpServerOptions, type HttpServerHandle, } from './server';
14
+ export { PR1_SENTINEL_EVENT_ID, SSE_EVENT_KINDS, type SseEventKind, type TempoEvent, type SubscribeOptions, type SubscribeTopic, type EnsembleStateV1, type PlayerSummaryV1, type HealthV1, } from './event-types';
15
+ export { DAEMON_PORT_PATH, readPortFile, removePortFile, writePortFileAtomic, } from './port-file';
16
+ export { buildEnsembleSnapshot, EnsembleNotFoundError, toPlayerSummaryV1, SNAPSHOT_CHAT_LIMIT, } from './snapshot';
17
+ export { AggregateRunner, DEFAULT_POLL_INTERVAL_MS, canonicalize, hashOf, diffEnsembleSet, diffEnsembleSnapshot, diffHostProfiles, } from './aggregate';
18
+ export { EnsembleEventBus, type EventBus, type Subscription, type BusEvent, type SubscribeOpts, type TopicCategory, topicOf, startHeartbeatTimer, DEFAULT_HEARTBEAT_MS, } from './event-bus';
19
+ export { SeqAllocator, formatEventId, parseEventId, compareEventIds, type EventIdTuple, } from './event-id';
20
+ export { ConnectionCap, DEFAULT_MAX_CONNECTIONS, PER_CONNECTION_BUFFER_LIMIT, frameSseEvent, frameSseComment, parseTopicQuery, handleSseRequest, } from './sse-handler';
21
+ export { createRingBuffer, RING_BUFFER_CAPACITY, type RingBuffer, } from './ring-buffer';
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RING_BUFFER_CAPACITY = exports.createRingBuffer = exports.handleSseRequest = exports.parseTopicQuery = exports.frameSseComment = exports.frameSseEvent = exports.PER_CONNECTION_BUFFER_LIMIT = exports.DEFAULT_MAX_CONNECTIONS = exports.ConnectionCap = exports.compareEventIds = exports.parseEventId = exports.formatEventId = exports.SeqAllocator = exports.DEFAULT_HEARTBEAT_MS = exports.startHeartbeatTimer = exports.topicOf = exports.EnsembleEventBus = exports.diffHostProfiles = exports.diffEnsembleSnapshot = exports.diffEnsembleSet = exports.hashOf = exports.canonicalize = exports.DEFAULT_POLL_INTERVAL_MS = exports.AggregateRunner = exports.SNAPSHOT_CHAT_LIMIT = exports.toPlayerSummaryV1 = exports.EnsembleNotFoundError = exports.buildEnsembleSnapshot = exports.writePortFileAtomic = exports.removePortFile = exports.readPortFile = exports.DAEMON_PORT_PATH = exports.SSE_EVENT_KINDS = exports.PR1_SENTINEL_EVENT_ID = exports.DEFAULT_PORT = exports.DEFAULT_BIND_ADDR = exports.startHttpServer = void 0;
4
+ /**
5
+ * Barrel re-exports for the daemon HTTP/SSE event source (#94, #95).
6
+ *
7
+ * - PR-1 (this file's first revision): snapshot endpoints + bearer/CORS
8
+ * middleware + port-file lifecycle. Drives `/v1/health`, `/v1/ensembles`,
9
+ * `/v1/state/:ensemble`, `/v1/hosts`.
10
+ * - PR-2 (future): `EnsembleEventBus`, ring buffer, `/v1/events*` SSE.
11
+ * - PR-3 (future, eng-4): `TempoClient.subscribe` AsyncIterable.
12
+ *
13
+ * Public surface kept narrow on purpose — implementation modules are the
14
+ * source of truth.
15
+ */
16
+ var server_1 = require("./server");
17
+ Object.defineProperty(exports, "startHttpServer", { enumerable: true, get: function () { return server_1.startHttpServer; } });
18
+ Object.defineProperty(exports, "DEFAULT_BIND_ADDR", { enumerable: true, get: function () { return server_1.DEFAULT_BIND_ADDR; } });
19
+ Object.defineProperty(exports, "DEFAULT_PORT", { enumerable: true, get: function () { return server_1.DEFAULT_PORT; } });
20
+ var event_types_1 = require("./event-types");
21
+ Object.defineProperty(exports, "PR1_SENTINEL_EVENT_ID", { enumerable: true, get: function () { return event_types_1.PR1_SENTINEL_EVENT_ID; } });
22
+ Object.defineProperty(exports, "SSE_EVENT_KINDS", { enumerable: true, get: function () { return event_types_1.SSE_EVENT_KINDS; } });
23
+ var port_file_1 = require("./port-file");
24
+ Object.defineProperty(exports, "DAEMON_PORT_PATH", { enumerable: true, get: function () { return port_file_1.DAEMON_PORT_PATH; } });
25
+ Object.defineProperty(exports, "readPortFile", { enumerable: true, get: function () { return port_file_1.readPortFile; } });
26
+ Object.defineProperty(exports, "removePortFile", { enumerable: true, get: function () { return port_file_1.removePortFile; } });
27
+ Object.defineProperty(exports, "writePortFileAtomic", { enumerable: true, get: function () { return port_file_1.writePortFileAtomic; } });
28
+ var snapshot_1 = require("./snapshot");
29
+ Object.defineProperty(exports, "buildEnsembleSnapshot", { enumerable: true, get: function () { return snapshot_1.buildEnsembleSnapshot; } });
30
+ Object.defineProperty(exports, "EnsembleNotFoundError", { enumerable: true, get: function () { return snapshot_1.EnsembleNotFoundError; } });
31
+ Object.defineProperty(exports, "toPlayerSummaryV1", { enumerable: true, get: function () { return snapshot_1.toPlayerSummaryV1; } });
32
+ Object.defineProperty(exports, "SNAPSHOT_CHAT_LIMIT", { enumerable: true, get: function () { return snapshot_1.SNAPSHOT_CHAT_LIMIT; } });
33
+ var aggregate_1 = require("./aggregate");
34
+ Object.defineProperty(exports, "AggregateRunner", { enumerable: true, get: function () { return aggregate_1.AggregateRunner; } });
35
+ Object.defineProperty(exports, "DEFAULT_POLL_INTERVAL_MS", { enumerable: true, get: function () { return aggregate_1.DEFAULT_POLL_INTERVAL_MS; } });
36
+ Object.defineProperty(exports, "canonicalize", { enumerable: true, get: function () { return aggregate_1.canonicalize; } });
37
+ Object.defineProperty(exports, "hashOf", { enumerable: true, get: function () { return aggregate_1.hashOf; } });
38
+ Object.defineProperty(exports, "diffEnsembleSet", { enumerable: true, get: function () { return aggregate_1.diffEnsembleSet; } });
39
+ Object.defineProperty(exports, "diffEnsembleSnapshot", { enumerable: true, get: function () { return aggregate_1.diffEnsembleSnapshot; } });
40
+ Object.defineProperty(exports, "diffHostProfiles", { enumerable: true, get: function () { return aggregate_1.diffHostProfiles; } });
41
+ var event_bus_1 = require("./event-bus");
42
+ Object.defineProperty(exports, "EnsembleEventBus", { enumerable: true, get: function () { return event_bus_1.EnsembleEventBus; } });
43
+ Object.defineProperty(exports, "topicOf", { enumerable: true, get: function () { return event_bus_1.topicOf; } });
44
+ Object.defineProperty(exports, "startHeartbeatTimer", { enumerable: true, get: function () { return event_bus_1.startHeartbeatTimer; } });
45
+ Object.defineProperty(exports, "DEFAULT_HEARTBEAT_MS", { enumerable: true, get: function () { return event_bus_1.DEFAULT_HEARTBEAT_MS; } });
46
+ var event_id_1 = require("./event-id");
47
+ Object.defineProperty(exports, "SeqAllocator", { enumerable: true, get: function () { return event_id_1.SeqAllocator; } });
48
+ Object.defineProperty(exports, "formatEventId", { enumerable: true, get: function () { return event_id_1.formatEventId; } });
49
+ Object.defineProperty(exports, "parseEventId", { enumerable: true, get: function () { return event_id_1.parseEventId; } });
50
+ Object.defineProperty(exports, "compareEventIds", { enumerable: true, get: function () { return event_id_1.compareEventIds; } });
51
+ var sse_handler_1 = require("./sse-handler");
52
+ Object.defineProperty(exports, "ConnectionCap", { enumerable: true, get: function () { return sse_handler_1.ConnectionCap; } });
53
+ Object.defineProperty(exports, "DEFAULT_MAX_CONNECTIONS", { enumerable: true, get: function () { return sse_handler_1.DEFAULT_MAX_CONNECTIONS; } });
54
+ Object.defineProperty(exports, "PER_CONNECTION_BUFFER_LIMIT", { enumerable: true, get: function () { return sse_handler_1.PER_CONNECTION_BUFFER_LIMIT; } });
55
+ Object.defineProperty(exports, "frameSseEvent", { enumerable: true, get: function () { return sse_handler_1.frameSseEvent; } });
56
+ Object.defineProperty(exports, "frameSseComment", { enumerable: true, get: function () { return sse_handler_1.frameSseComment; } });
57
+ Object.defineProperty(exports, "parseTopicQuery", { enumerable: true, get: function () { return sse_handler_1.parseTopicQuery; } });
58
+ Object.defineProperty(exports, "handleSseRequest", { enumerable: true, get: function () { return sse_handler_1.handleSseRequest; } });
59
+ var ring_buffer_1 = require("./ring-buffer");
60
+ Object.defineProperty(exports, "createRingBuffer", { enumerable: true, get: function () { return ring_buffer_1.createRingBuffer; } });
61
+ Object.defineProperty(exports, "RING_BUFFER_CAPACITY", { enumerable: true, get: function () { return ring_buffer_1.RING_BUFFER_CAPACITY; } });
@@ -0,0 +1,22 @@
1
+ /** Default location, anchored to `~/.agent-tempo/`. */
2
+ export declare const DAEMON_PORT_PATH: string;
3
+ /**
4
+ * Atomically write `port` (decimal ASCII, no trailing newline) to
5
+ * `filePath`. Identical retry shape to `writePidFileAtomic` so Windows
6
+ * EPERM/EBUSY/EACCES from antivirus scanners don't crash boot.
7
+ *
8
+ * Exported so tests can target an isolated path.
9
+ */
10
+ export declare function writePortFileAtomic(filePath: string, port: number): Promise<void>;
11
+ /**
12
+ * Best-effort `unlink`. Silent when the file is missing — consumers
13
+ * cleaning up a half-booted daemon should NOT see a "no such file" stack
14
+ * trace just because the port file never made it to disk.
15
+ */
16
+ export declare function removePortFile(filePath?: string): void;
17
+ /**
18
+ * Read the current port from disk, or `null` when the file is missing,
19
+ * empty, or not a parseable port. Used by clients (TempoClient HTTP
20
+ * transport, `agent-tempo daemon status`, …) to discover the live port.
21
+ */
22
+ export declare function readPortFile(filePath?: string): number | null;
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DAEMON_PORT_PATH = void 0;
37
+ exports.writePortFileAtomic = writePortFileAtomic;
38
+ exports.removePortFile = removePortFile;
39
+ exports.readPortFile = readPortFile;
40
+ /**
41
+ * `~/.agent-tempo/daemon.port` — atomic write + cleanup helpers.
42
+ *
43
+ * The TUI / CLI / web dashboard read this file to discover the daemon's
44
+ * bound HTTP port without any out-of-band config. SSE-PROTOCOL.md §1
45
+ * makes the file part of the public contract, so its lifecycle MUST be:
46
+ *
47
+ * 1. Atomic write on daemon boot, after the HTTP listener is `listening`
48
+ * (so a racing reader who polls during startup either sees the prior
49
+ * file or the new one — never a half-written one).
50
+ * 2. Removal on graceful shutdown. Best-effort on crash (a stale file
51
+ * points at a dead port; consumers MUST also tolerate ECONNREFUSED).
52
+ *
53
+ * Both behaviours mirror the existing PID-file pattern in
54
+ * `src/daemon.ts`. Extracted as its own module so HTTP-server tests
55
+ * can exercise the contract without booting the daemon.
56
+ */
57
+ const fs = __importStar(require("fs"));
58
+ const path = __importStar(require("path"));
59
+ const promises_1 = require("timers/promises");
60
+ const config_1 = require("../config");
61
+ /** Default location, anchored to `~/.agent-tempo/`. */
62
+ exports.DAEMON_PORT_PATH = path.join(config_1.AGENT_TEMPO_HOME, 'daemon.port');
63
+ /**
64
+ * Atomically write `port` (decimal ASCII, no trailing newline) to
65
+ * `filePath`. Identical retry shape to `writePidFileAtomic` so Windows
66
+ * EPERM/EBUSY/EACCES from antivirus scanners don't crash boot.
67
+ *
68
+ * Exported so tests can target an isolated path.
69
+ */
70
+ async function writePortFileAtomic(filePath, port) {
71
+ if (!Number.isInteger(port) || port < 0 || port > 65535) {
72
+ throw new Error(`writePortFileAtomic: invalid port ${port}`);
73
+ }
74
+ const dir = path.dirname(filePath);
75
+ fs.mkdirSync(dir, { recursive: true });
76
+ const tmp = `${filePath}.tmp.${process.pid}`;
77
+ fs.writeFileSync(tmp, String(port));
78
+ const retryCodes = new Set(['EPERM', 'EBUSY', 'EACCES']);
79
+ const backoffs = [50, 100, 200, 400]; // ≤ 750 ms total
80
+ let lastErr;
81
+ for (let attempt = 0; attempt <= backoffs.length; attempt++) {
82
+ try {
83
+ fs.renameSync(tmp, filePath);
84
+ return;
85
+ }
86
+ catch (err) {
87
+ lastErr = err;
88
+ const code = err.code;
89
+ if (!code || !retryCodes.has(code) || attempt === backoffs.length) {
90
+ try {
91
+ fs.unlinkSync(tmp);
92
+ }
93
+ catch { /* ignore */ }
94
+ throw err;
95
+ }
96
+ await (0, promises_1.setTimeout)(backoffs[attempt]);
97
+ }
98
+ }
99
+ throw lastErr;
100
+ }
101
+ /**
102
+ * Best-effort `unlink`. Silent when the file is missing — consumers
103
+ * cleaning up a half-booted daemon should NOT see a "no such file" stack
104
+ * trace just because the port file never made it to disk.
105
+ */
106
+ function removePortFile(filePath = exports.DAEMON_PORT_PATH) {
107
+ try {
108
+ fs.unlinkSync(filePath);
109
+ }
110
+ catch { /* ignore */ }
111
+ }
112
+ /**
113
+ * Read the current port from disk, or `null` when the file is missing,
114
+ * empty, or not a parseable port. Used by clients (TempoClient HTTP
115
+ * transport, `agent-tempo daemon status`, …) to discover the live port.
116
+ */
117
+ function readPortFile(filePath = exports.DAEMON_PORT_PATH) {
118
+ let raw;
119
+ try {
120
+ raw = fs.readFileSync(filePath, 'utf8');
121
+ }
122
+ catch {
123
+ return null;
124
+ }
125
+ const trimmed = raw.trim();
126
+ if (!trimmed)
127
+ return null;
128
+ const port = Number(trimmed);
129
+ if (!Number.isInteger(port) || port < 1 || port > 65535)
130
+ return null;
131
+ return port;
132
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Tiny response helpers. Wrap `http.ServerResponse` writes so handlers
3
+ * stay declarative (`return jsonResponse(res, 200, body)`) and we have
4
+ * one place to enforce the §1 contract: UTF-8, JSON content-type,
5
+ * `Cache-Control: no-store` (snapshot endpoints reflect live state).
6
+ */
7
+ import type { ServerResponse } from 'http';
8
+ /** Snapshot Content-Type per SSE-PROTOCOL.md §1. */
9
+ export declare const JSON_CONTENT_TYPE = "application/json; charset=utf-8";
10
+ /**
11
+ * Write a JSON response. Always serializes via `JSON.stringify`; consumers
12
+ * that need a custom replacer should encode upstream and use
13
+ * {@link rawJsonResponse}.
14
+ */
15
+ export declare function jsonResponse(res: ServerResponse, status: number, body: unknown, extraHeaders?: Record<string, string>): void;
16
+ /**
17
+ * Write a pre-serialized JSON string (caller has already stringified).
18
+ * Used by tests that want to verify byte-exact output.
19
+ */
20
+ export declare function rawJsonResponse(res: ServerResponse, status: number, body: string, extraHeaders?: Record<string, string>): void;
21
+ /** SSE-PROTOCOL.md §9 — error response shape. */
22
+ export interface HttpErrorBody {
23
+ error: string;
24
+ /** Optional context, e.g. `{ ensemble: 'foo' }`. */
25
+ [key: string]: unknown;
26
+ }
27
+ export declare function errorResponse(res: ServerResponse, status: number, body: HttpErrorBody, extraHeaders?: Record<string, string>): void;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JSON_CONTENT_TYPE = void 0;
4
+ exports.jsonResponse = jsonResponse;
5
+ exports.rawJsonResponse = rawJsonResponse;
6
+ exports.errorResponse = errorResponse;
7
+ /** Snapshot Content-Type per SSE-PROTOCOL.md §1. */
8
+ exports.JSON_CONTENT_TYPE = 'application/json; charset=utf-8';
9
+ /**
10
+ * Write a JSON response. Always serializes via `JSON.stringify`; consumers
11
+ * that need a custom replacer should encode upstream and use
12
+ * {@link rawJsonResponse}.
13
+ */
14
+ function jsonResponse(res, status, body, extraHeaders = {}) {
15
+ const payload = Buffer.from(JSON.stringify(body), 'utf8');
16
+ res.writeHead(status, {
17
+ 'Content-Type': exports.JSON_CONTENT_TYPE,
18
+ 'Content-Length': payload.length,
19
+ 'Cache-Control': 'no-store',
20
+ ...extraHeaders,
21
+ });
22
+ res.end(payload);
23
+ }
24
+ /**
25
+ * Write a pre-serialized JSON string (caller has already stringified).
26
+ * Used by tests that want to verify byte-exact output.
27
+ */
28
+ function rawJsonResponse(res, status, body, extraHeaders = {}) {
29
+ const payload = Buffer.from(body, 'utf8');
30
+ res.writeHead(status, {
31
+ 'Content-Type': exports.JSON_CONTENT_TYPE,
32
+ 'Content-Length': payload.length,
33
+ 'Cache-Control': 'no-store',
34
+ ...extraHeaders,
35
+ });
36
+ res.end(payload);
37
+ }
38
+ function errorResponse(res, status, body, extraHeaders = {}) {
39
+ jsonResponse(res, status, body, extraHeaders);
40
+ }