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,459 @@
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.DEFAULT_PORT = exports.DEFAULT_BIND_ADDR = void 0;
37
+ exports.startHttpServer = startHttpServer;
38
+ exports.handle = handle;
39
+ /**
40
+ * Daemon HTTP server — PR-1 of #94/#95.
41
+ *
42
+ * Hosts the read-only snapshot endpoints (`/v1/health`, `/v1/ensembles`,
43
+ * `/v1/state/:ensemble`, `/v1/hosts`) defined in `docs/SSE-PROTOCOL.md`.
44
+ * The SSE streaming endpoints (`/v1/events*`) are PR-2.
45
+ *
46
+ * Boot lifecycle:
47
+ * 1. Caller passes a {@link TempoClient}, namespace, and version to
48
+ * {@link startHttpServer}.
49
+ * 2. Server binds to `127.0.0.1:8473` in production / `:8474` in dev mode
50
+ * (defaults overridable via `AGENT_TEMPO_HTTP_BIND` /
51
+ * `AGENT_TEMPO_DAEMON_PORT`; dev profile per ADR 0014 §5.1).
52
+ * 3. The bound port is written atomically to `~/.agent-tempo/daemon.port`.
53
+ * 4. Caller `await`s {@link HttpServerHandle.close} on shutdown — drains
54
+ * in-flight requests, removes the port file, then resolves.
55
+ */
56
+ const http = __importStar(require("http"));
57
+ const config_1 = require("../config");
58
+ const auth_1 = require("./auth");
59
+ const cors_1 = require("./cors");
60
+ const dashboard_1 = require("./dashboard");
61
+ const dashboard_pair_1 = require("./dashboard-pair");
62
+ const fixtures_1 = require("./fixtures");
63
+ const writes_1 = require("./writes");
64
+ const catalog_1 = require("./catalog");
65
+ const port_file_1 = require("./port-file");
66
+ const responses_1 = require("./responses");
67
+ const snapshot_1 = require("./snapshot");
68
+ const sse_handler_1 = require("./sse-handler");
69
+ const log = (...args) => console.error(`[agent-tempo:http ${new Date().toISOString()}]`, ...args);
70
+ /** Default bind addr per SSE-PROTOCOL.md §1. */
71
+ exports.DEFAULT_BIND_ADDR = '127.0.0.1';
72
+ /**
73
+ * Default port — `t-e-m-p-o` mnemonic for prod (8473), `+1` for dev (8474).
74
+ * ADR 0014 §5.1 flips this with the rest of the dev profile so prod and dev
75
+ * daemons can coexist on the same machine without binding the same port.
76
+ *
77
+ * Evaluated at module load time. The dev daemon child process inherits
78
+ * `AGENT_TEMPO_DEV_MODE=1` from its parent CLI (set by the
79
+ * `dev-mode-bootstrap` side-effect), so by the time this module loads,
80
+ * `isDevMode()` already returns the correct value.
81
+ */
82
+ exports.DEFAULT_PORT = (0, config_1.isDevMode)() ? config_1.DEV_DAEMON_PORT : config_1.PROD_DAEMON_PORT;
83
+ /**
84
+ * Start the HTTP server. Resolves once the listener is bound and the
85
+ * port file has been written.
86
+ */
87
+ async function startHttpServer(opts) {
88
+ const bindAddr = opts.bindAddr ?? process.env[config_1.ENV.HTTP_BIND] ?? exports.DEFAULT_BIND_ADDR;
89
+ const portEnv = process.env[config_1.ENV.DAEMON_PORT];
90
+ const port = opts.port ?? (portEnv != null && portEnv !== '' ? Number(portEnv) : exports.DEFAULT_PORT);
91
+ if (!Number.isInteger(port) || port < 0 || port > 65535) {
92
+ throw new Error(`Invalid HTTP port: ${port}`);
93
+ }
94
+ const allowedOrigins = opts.allowedOrigins ?? (0, cors_1.parseCorsOrigins)(process.env[config_1.ENV.CORS_ORIGINS]);
95
+ const corsConfig = { allowedOrigins };
96
+ // Bearer token resolution: if bind addr is non-loopback, force token
97
+ // generation now so the daemon doesn't crash mid-request when the first
98
+ // bearer-required call shows up.
99
+ const bindIsLoopback = (0, auth_1.isLoopbackBindAddr)(bindAddr);
100
+ const httpToken = opts.httpToken ?? (0, auth_1.loadOrGenerateHttpToken)({ bearerRequired: !bindIsLoopback });
101
+ if (!bindIsLoopback && !httpToken) {
102
+ throw new Error('Bearer token required for non-loopback bind but none configured. ' +
103
+ 'Set httpToken in ~/.agent-tempo/config.json or unset AGENT_TEMPO_HTTP_BIND.');
104
+ }
105
+ const startedAt = opts.startedAtMs ?? Date.now();
106
+ // §7.3 process-wide cap. Defaults to 100 per spec; env var override.
107
+ const capLimitEnv = process.env[config_1.ENV.SSE_MAX_CONNECTIONS];
108
+ const capLimit = opts.maxSseConnections ??
109
+ (capLimitEnv != null && capLimitEnv !== '' ? Number(capLimitEnv) : sse_handler_1.DEFAULT_MAX_CONNECTIONS);
110
+ if (!Number.isInteger(capLimit) || capLimit < 1) {
111
+ throw new Error(`Invalid SSE max connections: ${capLimit}`);
112
+ }
113
+ const sseConnectionCap = new sse_handler_1.ConnectionCap(capLimit);
114
+ // Subscriber count = aggregate's live SSE subscribers. Falls back to
115
+ // 0 when no aggregate (PR-1 server, no SSE).
116
+ const subscriberCount = () => opts.aggregate ? opts.aggregate.totalSubscriberCount() : 0;
117
+ const server = http.createServer((req, res) => handle(req, res, {
118
+ client: opts.client,
119
+ namespace: opts.namespace,
120
+ taskQueue: opts.taskQueue,
121
+ version: opts.version,
122
+ bindAddr,
123
+ corsConfig,
124
+ httpToken,
125
+ startedAt,
126
+ subscriberCount,
127
+ aggregate: opts.aggregate ?? null,
128
+ sseConnectionCap,
129
+ }).catch((err) => {
130
+ log('unhandled handler error:', err instanceof Error ? err.message : err);
131
+ if (!res.headersSent) {
132
+ try {
133
+ (0, responses_1.errorResponse)(res, 500, { error: 'internal-error' });
134
+ }
135
+ catch { /* socket already closed */ }
136
+ }
137
+ else {
138
+ try {
139
+ res.end();
140
+ }
141
+ catch { /* ignore */ }
142
+ }
143
+ }));
144
+ // Defensive: per-connection timeout so a wedged client can't hold a
145
+ // socket indefinitely on the daemon. Snapshot endpoints respond fast;
146
+ // PR-2 will need a much longer / disabled timeout for SSE streams.
147
+ server.requestTimeout = 30_000;
148
+ server.headersTimeout = 35_000;
149
+ // TCP keepalive — matches §1 contract.
150
+ server.keepAliveTimeout = 60_000;
151
+ await new Promise((resolve, reject) => {
152
+ server.once('error', reject);
153
+ server.listen(port, bindAddr, () => {
154
+ server.removeListener('error', reject);
155
+ resolve();
156
+ });
157
+ });
158
+ const address = server.address();
159
+ const boundPort = typeof address === 'object' && address ? address.port : port;
160
+ // Port file → atomic write so a racing reader never sees a half-written
161
+ // value. Skip write if the caller asked for ephemeral binding without a
162
+ // port-file override (tests).
163
+ const portFilePath = opts.portFilePath ?? port_file_1.DAEMON_PORT_PATH;
164
+ try {
165
+ await (0, port_file_1.writePortFileAtomic)(portFilePath, boundPort);
166
+ log(`listening on http://${bindAddr}:${boundPort} (port file: ${portFilePath})`);
167
+ }
168
+ catch (err) {
169
+ log('failed to write port file (non-fatal):', err instanceof Error ? err.message : err);
170
+ }
171
+ // Track open sockets so `close()` can force-close them after a graceful
172
+ // window — Node's `server.close()` only stops accepting new connections.
173
+ const sockets = new Set();
174
+ server.on('connection', (socket) => {
175
+ sockets.add(socket);
176
+ socket.on('close', () => sockets.delete(socket));
177
+ });
178
+ return {
179
+ port: boundPort,
180
+ bindAddr,
181
+ subscriberCount,
182
+ async close() {
183
+ // Stop accepting new connections immediately, then give live sockets
184
+ // a 5 s window to drain before destroying them.
185
+ const closing = new Promise((resolve) => {
186
+ server.close(() => resolve());
187
+ });
188
+ const drainDeadline = setTimeout(() => {
189
+ for (const s of sockets)
190
+ s.destroy();
191
+ }, 5_000);
192
+ drainDeadline.unref();
193
+ try {
194
+ await closing;
195
+ }
196
+ finally {
197
+ clearTimeout(drainDeadline);
198
+ }
199
+ (0, port_file_1.removePortFile)(portFilePath);
200
+ log('server closed');
201
+ },
202
+ };
203
+ }
204
+ /**
205
+ * Top-level request dispatcher — exported for unit tests that want to
206
+ * exercise the handler without spinning up a real listener.
207
+ */
208
+ async function handle(req, res, ctx) {
209
+ const method = (req.method ?? 'GET').toUpperCase();
210
+ const url = new URL(req.url ?? '/', `http://${ctx.bindAddr}`);
211
+ const pathname = url.pathname;
212
+ // CORS preflight short-circuit. Always answer OPTIONS — even in
213
+ // loopback mode — with `204 No Content` and the static headers, so
214
+ // browsers performing a preflight against a loopback dashboard get a
215
+ // clean answer.
216
+ if (method === 'OPTIONS') {
217
+ return handleOptions(req, res, ctx);
218
+ }
219
+ // Health is always reachable, never authenticated, never CORS-gated.
220
+ if (method === 'GET' && pathname === '/v1/health') {
221
+ return handleHealth(res, ctx);
222
+ }
223
+ // Pre-auth carve-out for the cross-device pairing-token consume endpoint
224
+ // (see docs/design/340-web-dashboard.md §4.1). The token IS the auth —
225
+ // single-use, 5-min TTL, opaque base64url. Real pair flow lands here
226
+ // in PR-8 of #340.
227
+ //
228
+ // Regex is intentionally tight — `[^/]+` rejects extra path segments and
229
+ // (after URL-parser normalisation) traversal attempts; both fall through
230
+ // to the post-auth `/dashboard/api/*` 404.
231
+ const pairConsumeMatch = pathname.match(/^\/dashboard\/api\/pair\/([^/]+)$/);
232
+ if (method === 'GET' && pairConsumeMatch) {
233
+ return (0, dashboard_pair_1.handlePairConsume)(req, res, pairConsumeMatch[1]);
234
+ }
235
+ // Authentication gate.
236
+ const originHeader = headerString(req.headers.origin);
237
+ const reqBearer = (0, auth_1.bearerRequired)(ctx.bindAddr, originHeader);
238
+ if (reqBearer) {
239
+ const provided = (0, auth_1.extractBearerToken)(headerString(req.headers.authorization));
240
+ if (!provided || !ctx.httpToken || !(0, auth_1.tokensMatch)(provided, ctx.httpToken)) {
241
+ writeCorsHeaders(res, originHeader, ctx, reqBearer);
242
+ return (0, responses_1.errorResponse)(res, 401, { error: 'unauthorized' });
243
+ }
244
+ }
245
+ // CORS allowlist check (only enforced in bearer mode).
246
+ const cors = (0, cors_1.evaluateOrigin)(originHeader, ctx.corsConfig, reqBearer);
247
+ if (!cors.allowed) {
248
+ return (0, responses_1.errorResponse)(res, 403, { error: 'origin-not-allowed' });
249
+ }
250
+ if (cors.echo) {
251
+ res.setHeader('Access-Control-Allow-Origin', cors.echo);
252
+ res.setHeader('Vary', 'Origin');
253
+ }
254
+ // Write surface (PR-7a of #340) — POST `/v1/ensembles/:ensemble/<action>`
255
+ // Match BEFORE the GET-only method gate; everything else (POST to a
256
+ // read endpoint, GET to a write endpoint) flows into the 405 fallback
257
+ // below with the right `Allow` header.
258
+ const writeMatch = pathname.match(/^\/v1\/ensembles\/([^/]+)\/([^/]+)$/);
259
+ if (writeMatch) {
260
+ const ensemble = decodeURIComponent(writeMatch[1]);
261
+ const action = writeMatch[2];
262
+ if ((0, writes_1.isWriteAction)(action)) {
263
+ if (method !== 'POST') {
264
+ return (0, responses_1.errorResponse)(res, 405, { error: 'method-not-allowed' }, { Allow: 'POST, OPTIONS' });
265
+ }
266
+ return (0, writes_1.handleWriteRoute)(req, res, ctx.client, ensemble, action);
267
+ }
268
+ // Unknown action under /v1/ensembles/:e/<x> → 404 (don't 405; the
269
+ // path simply isn't a known endpoint).
270
+ return (0, responses_1.errorResponse)(res, 404, { error: 'not-found' });
271
+ }
272
+ // Create-ensemble route (issue #400) — POST `/v1/ensembles`. Sits
273
+ // alongside the writeMatch above so it's reached before the GET-only
274
+ // gate; the GET on the same path (list ensembles) is handled below.
275
+ if (pathname === '/v1/ensembles' && method === 'POST') {
276
+ return (0, catalog_1.handleCreateEnsemble)(req, res, ctx.client);
277
+ }
278
+ // POST `/dashboard/api/pair` — mint a pairing for cross-device QR (PR-8
279
+ // of #340). Sits AFTER the bearer-auth gate so the operator on the host
280
+ // proves authority before issuing a token; the token's GET-side consume
281
+ // is the carve-out above the auth gate.
282
+ if (method === 'POST' && pathname === '/dashboard/api/pair') {
283
+ const provided = (0, auth_1.extractBearerToken)(headerString(req.headers.authorization));
284
+ return (0, dashboard_pair_1.handlePairCreate)(req, res, provided);
285
+ }
286
+ // Method gate — read endpoints are GET-only. Both POST paths above
287
+ // (PR-7a writes, PR-8 pair-mint) handle their own method matching;
288
+ // everything else falls through here.
289
+ if (method !== 'GET') {
290
+ return (0, responses_1.errorResponse)(res, 405, { error: 'method-not-allowed' }, { Allow: 'GET, OPTIONS' });
291
+ }
292
+ // Static dashboard SPA (PR-1 of #340). Sits behind the bearer-auth gate
293
+ // so non-loopback binds (LAN, Tailscale) require the same bearer the
294
+ // `/v1/*` API uses. The pre-auth pair-token carve-out above is the
295
+ // single exception that bootstraps cross-device pairing.
296
+ if (pathname === '/dashboard' || pathname.startsWith('/dashboard/')) {
297
+ return (0, dashboard_1.handleDashboardStatic)(req, res, pathname);
298
+ }
299
+ if (pathname === '/v1/ensembles') {
300
+ return handleListEnsembles(res, ctx);
301
+ }
302
+ if (pathname === '/v1/hosts') {
303
+ return handleHosts(res, ctx);
304
+ }
305
+ // Catalog reads (issue #400) — `listAgentTypes` / `listLineups`
306
+ // touch local fs only, no Temporal calls; cheap to serve per-request.
307
+ if (pathname === '/v1/agent-types') {
308
+ return (0, catalog_1.handleListAgentTypes)(res);
309
+ }
310
+ if (pathname === '/v1/lineups') {
311
+ return (0, catalog_1.handleListLineups)(res);
312
+ }
313
+ // /v1/state/:ensemble — single capture group.
314
+ const stateMatch = pathname.match(/^\/v1\/state\/([^/]+)$/);
315
+ if (stateMatch) {
316
+ const ensemble = decodeURIComponent(stateMatch[1]);
317
+ // Fixture mode (PR-3 of #340) — `?fixture=<name>` short-circuits the
318
+ // live snapshot with canned data. Sits behind the bearer-auth gate.
319
+ const fixtureName = url.searchParams.get('fixture');
320
+ if (fixtureName) {
321
+ return (0, fixtures_1.handleFixtureSnapshot)(res, fixtureName);
322
+ }
323
+ return handleState(res, ctx, ensemble);
324
+ }
325
+ // /v1/events* (SSE). Dispatch to the SSE handler when an aggregate
326
+ // is wired; otherwise stay on the PR-1 503 placeholder so the route
327
+ // signals "feature exists, not yet wired" rather than "ensemble
328
+ // doesn't exist".
329
+ if (pathname === '/v1/events') {
330
+ if (!ctx.aggregate) {
331
+ return (0, responses_1.errorResponse)(res, 503, { error: 'streaming-not-implemented' }, { 'Retry-After': '60' });
332
+ }
333
+ return (0, sse_handler_1.handleSseRequest)(req, res, {
334
+ client: ctx.client,
335
+ bus: ctx.aggregate.globalBus(),
336
+ emitSnapshot: false,
337
+ cap: ctx.sseConnectionCap,
338
+ });
339
+ }
340
+ const evtMatch = pathname.match(/^\/v1\/events\/([^/]+)$/);
341
+ if (evtMatch) {
342
+ const ensemble = decodeURIComponent(evtMatch[1]);
343
+ // Fixture mode (PR-3 of #340) — `?fixture=<name>` short-circuits both
344
+ // the existence check and the aggregate poll loop with a canned event
345
+ // sequence. Sits behind the bearer-auth gate.
346
+ const fixtureName = url.searchParams.get('fixture');
347
+ if (fixtureName) {
348
+ return (0, fixtures_1.handleFixtureSse)(req, res, fixtureName);
349
+ }
350
+ if (!ctx.aggregate) {
351
+ return (0, responses_1.errorResponse)(res, 503, { error: 'streaming-not-implemented' }, { 'Retry-After': '60' });
352
+ }
353
+ // Validate existence before opening the SSE stream — clean 404 when
354
+ // the ensemble was never live, instead of an empty stream.
355
+ const list = await ctx.client.listEnsembles().catch(() => []);
356
+ if (!list.find((e) => e.name === ensemble)) {
357
+ return (0, responses_1.errorResponse)(res, 404, { error: 'ensemble-not-found', ensemble });
358
+ }
359
+ const bus = ctx.aggregate.getOrCreateEnsembleBus(ensemble);
360
+ return (0, sse_handler_1.handleSseRequest)(req, res, {
361
+ client: ctx.client,
362
+ bus,
363
+ emitSnapshot: true,
364
+ ensemble,
365
+ cap: ctx.sseConnectionCap,
366
+ });
367
+ }
368
+ return (0, responses_1.errorResponse)(res, 404, { error: 'not-found' });
369
+ }
370
+ /** Pull a single string from a possibly-array header. */
371
+ function headerString(v) {
372
+ if (Array.isArray(v))
373
+ return v[0];
374
+ return v;
375
+ }
376
+ /**
377
+ * Apply CORS response headers when bearer mode is active. Used by
378
+ * paths that bypass the main route flow (e.g. 401 short-circuit) so
379
+ * the browser still sees a CORS-compliant response.
380
+ */
381
+ function writeCorsHeaders(res, originHeader, ctx, bearerActive) {
382
+ if (!bearerActive)
383
+ return;
384
+ const cors = (0, cors_1.evaluateOrigin)(originHeader, ctx.corsConfig, bearerActive);
385
+ if (cors.echo) {
386
+ res.setHeader('Access-Control-Allow-Origin', cors.echo);
387
+ res.setHeader('Vary', 'Origin');
388
+ }
389
+ }
390
+ function handleOptions(req, res, ctx) {
391
+ const originHeader = headerString(req.headers.origin);
392
+ const bearerActive = (0, auth_1.bearerRequired)(ctx.bindAddr, originHeader);
393
+ const cors = (0, cors_1.evaluateOrigin)(originHeader, ctx.corsConfig, bearerActive);
394
+ // Origin rejected → 403, no ACAO header (browser will block fetch).
395
+ if (!cors.allowed) {
396
+ res.writeHead(403, { 'Content-Type': 'text/plain; charset=utf-8' });
397
+ res.end('CORS: origin not allowed');
398
+ return;
399
+ }
400
+ const headers = { ...(0, cors_1.corsResponseHeaders)() };
401
+ if (cors.echo)
402
+ headers['Access-Control-Allow-Origin'] = cors.echo;
403
+ res.writeHead(204, headers);
404
+ res.end();
405
+ }
406
+ function handleHealth(res, ctx) {
407
+ // #336 — sample process memory at request time. `process.memoryUsage()`
408
+ // is synchronous + cheap (~microseconds), safe inside a request handler.
409
+ const mem = process.memoryUsage();
410
+ const body = {
411
+ ok: true,
412
+ namespace: ctx.namespace,
413
+ taskQueue: ctx.taskQueue,
414
+ version: ctx.version,
415
+ uptimeMs: Math.max(0, Date.now() - ctx.startedAt),
416
+ ensembleCount: 0, // populated below
417
+ subscriberCount: ctx.subscriberCount(),
418
+ memory: {
419
+ rss: mem.rss,
420
+ heapTotal: mem.heapTotal,
421
+ heapUsed: mem.heapUsed,
422
+ external: mem.external,
423
+ arrayBuffers: mem.arrayBuffers,
424
+ },
425
+ };
426
+ // Best-effort ensemble count — soft-fail to 0 rather than 500ing on a
427
+ // healthcheck. `/v1/health` MUST stay reachable even when Temporal is
428
+ // wedged; supervisord depends on it.
429
+ ctx.client
430
+ .listEnsembles()
431
+ .then((list) => {
432
+ body.ensembleCount = list.length;
433
+ (0, responses_1.jsonResponse)(res, 200, body);
434
+ })
435
+ .catch(() => {
436
+ (0, responses_1.jsonResponse)(res, 200, body);
437
+ });
438
+ }
439
+ async function handleListEnsembles(res, ctx) {
440
+ const list = await ctx.client.listEnsembles();
441
+ (0, responses_1.jsonResponse)(res, 200, list);
442
+ }
443
+ async function handleHosts(res, ctx) {
444
+ // The 3 s cache lives inside `listHosts`; we don't add another layer.
445
+ const hosts = await ctx.client.listHosts();
446
+ (0, responses_1.jsonResponse)(res, 200, hosts);
447
+ }
448
+ async function handleState(res, ctx, ensemble) {
449
+ try {
450
+ const snapshot = await (0, snapshot_1.buildEnsembleSnapshot)(ctx.client, ensemble);
451
+ (0, responses_1.jsonResponse)(res, 200, snapshot);
452
+ }
453
+ catch (err) {
454
+ if (err instanceof snapshot_1.EnsembleNotFoundError) {
455
+ return (0, responses_1.errorResponse)(res, 404, { error: 'ensemble-not-found', ensemble });
456
+ }
457
+ throw err;
458
+ }
459
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Snapshot builder for `/v1/state/:ensemble`.
3
+ *
4
+ * **PR-1 strategy**: project the existing TempoClient queries through HTTP
5
+ * without an aggregate. PR-2 will replace this with a 750 ms aggregate
6
+ * poll loop that diffs and emits events; the snapshot endpoint stays
7
+ * stable across that swap because the projection lives in the client
8
+ * surface, not the SSE infrastructure.
9
+ *
10
+ * **Ensemble existence gate**: `listEnsembles()` is the one query that
11
+ * cleanly distinguishes "ensemble doesn't exist" from "ensemble exists
12
+ * but is empty". Calling it first lets us return `404 ensemble-not-found`
13
+ * (SSE-PROTOCOL.md §9) before we fan out the rest of the queries.
14
+ *
15
+ * **Atomicity** (§4.3 contract): in PR-1 the snapshot reflects whatever
16
+ * Temporal queries returned at the time of fan-out. The `lastEventId` is
17
+ * the sentinel `"0:0"` — PR-2 subscribers passing it back will hit
18
+ * `epoch-mismatch` and re-fetch, which is the right behavior since the
19
+ * PR-1 snapshot has no provable atomicity against an event log that
20
+ * doesn't yet exist.
21
+ */
22
+ import type { TempoClient } from '../client/interface';
23
+ import type { MaestroPlayerInfo } from '../types';
24
+ import { type EnsembleStateV1, type PlayerSummaryV1 } from './event-types';
25
+ /**
26
+ * Maximum chat messages embedded in the snapshot. Larger paging is left
27
+ * to the explicit `getEnsembleChat` query / `recall` tool — the snapshot
28
+ * is a steady-state view, not a paginator.
29
+ */
30
+ export declare const SNAPSHOT_CHAT_LIMIT = 50;
31
+ /** Thrown when the ensemble doesn't exist; route handler maps to 404. */
32
+ export declare class EnsembleNotFoundError extends Error {
33
+ readonly ensemble: string;
34
+ constructor(ensemble: string);
35
+ }
36
+ /**
37
+ * Per-player wire-extension fields layered on top of `toPlayerSummaryV1`.
38
+ * Issue #399 W2 — `getPlayerWireMeta` fans out 3 session queries; the
39
+ * resulting object is merged into the projection here. `null` (session
40
+ * unreachable) drops the whole wire-meta block rather than emitting
41
+ * half-populated fields.
42
+ */
43
+ export interface PlayerWireMeta {
44
+ runId?: string;
45
+ messaging?: {
46
+ received: number;
47
+ sent: number;
48
+ outbox: string;
49
+ };
50
+ lease?: {
51
+ expiresAt: number | null;
52
+ leaseMs: number | null;
53
+ };
54
+ }
55
+ /**
56
+ * Project a `MaestroPlayerInfo` into the wire-stable `PlayerSummaryV1`.
57
+ * Drops fields that aren't part of the v1 contract; passes `agentType`
58
+ * through verbatim — the wire union mirrors {@link AgentType} from
59
+ * `src/types.ts`, so every shipped adapter projects to its own label
60
+ * (#535). Pre-#535 the wire union was closed at `'claude' | 'copilot' |
61
+ * 'mock'` and headless adapters were coerced to `'claude'`, which made
62
+ * them indistinguishable from interactive Claude Code players in the
63
+ * dashboard. The union expansion is additive per the §6 stability rule
64
+ * in `event-types.ts` — no `/v1/` → `/v2/` bump.
65
+ *
66
+ * `wireMeta` is the session-level projection from
67
+ * `TempoClient.getPlayerWireMeta` (Issue #399 W2). Pass `null` (or omit)
68
+ * when the session workflow couldn't be queried — the projection then
69
+ * carries no `runId` / `messaging` / `lease` fields and the dashboard
70
+ * renders `—` placeholders.
71
+ *
72
+ * `activityCount` passes through from `MaestroPlayerInfo` (Q5.6).
73
+ * `MaestroPlayerInfo.lastActivityAt` maps to the wire field
74
+ * `PlayerSummaryV1.lastHeartbeatAt` — same data, rename happens at the
75
+ * wire boundary so consumers read one canonical name.
76
+ */
77
+ export declare function toPlayerSummaryV1(p: MaestroPlayerInfo, wireMeta?: PlayerWireMeta | null): PlayerSummaryV1;
78
+ /**
79
+ * Build the `/v1/state/:ensemble` payload. Throws
80
+ * {@link EnsembleNotFoundError} when the requested ensemble has no live
81
+ * workflows; route handler turns that into a 404.
82
+ */
83
+ export declare function buildEnsembleSnapshot(client: TempoClient, ensemble: string, opts?: {
84
+ now?: () => Date;
85
+ }): Promise<EnsembleStateV1>;