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
package/dist/types.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ // Shared types used by both workflow code (V8 sandbox) and Node.js server code.
3
+ // This file must NOT import from @temporalio/* — it's pure TypeScript types.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.ZERO_CHAT_HIGH_WATER = exports.MOCK_MODES = exports.AGENT_TYPES = void 0;
6
+ /**
7
+ * Agent runtime selector.
8
+ *
9
+ * - `'claude'` / `'copilot'` — production adapters; ship in the npm tarball.
10
+ * - `'mock'` — dev-mode-only adapter (ADR 0014 PR-2). Defense-in-depth gates
11
+ * (build-time exclusion, registry gate behind `isDevMode()`, recruit-time
12
+ * rejection, runtime banner) keep this off production paths. The string
13
+ * value lives in the type union so workflow / outbox / recruit code can
14
+ * discriminate without `any` casts even in production builds; the runtime
15
+ * gates are what actually prevent execution.
16
+ *
17
+ * Single source of truth: {@link AGENT_TYPES}. The CLI argv parser
18
+ * (`src/cli.ts`'s `--agent` validation) and the recruit MCP tool's
19
+ * `z.enum` import this tuple so adding a new adapter only requires
20
+ * editing one line — see #476 (the `claude-api` allowlist drift bug
21
+ * that motivated centralising this).
22
+ */
23
+ exports.AGENT_TYPES = ['claude', 'copilot', 'mock', 'claude-api', 'opencode', 'claude-code-headless'];
24
+ /**
25
+ * Mock-adapter mode (ADR 0014 §4.2). Single source of truth shared by the
26
+ * adapter, the recruit tool's zod enum (`z.enum(MOCK_MODES)`), the spawn
27
+ * options, the recruit outbox entry, the lineup schema, and the lineup
28
+ * dispatcher. `'echo' | 'scripted'` shipped in PR-2; `'silent' | 'chaos'`
29
+ * landed in PR-3.
30
+ *
31
+ * Declared here rather than in `src/adapters/mock/` so non-dev-mode modules
32
+ * (recruit, spawn, schema) can reference the type without pulling the
33
+ * adapter source unit into their dep graph.
34
+ */
35
+ exports.MOCK_MODES = ['echo', 'scripted', 'silent', 'chaos'];
36
+ /** Zero-value for ChatHighWater — use as default when no prior fetch. */
37
+ exports.ZERO_CHAT_HIGH_WATER = {
38
+ maestroRecv: 0, maestroSent: 0, conductorRecv: 0, conductorSent: 0,
39
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared attachment-info display formatter.
3
+ *
4
+ * Renders an {@link AttachmentInfo} snapshot into an array of plain strings
5
+ * suitable for either stdout (`agent-tempo attachment-info`) or the TUI
6
+ * overlay (`/attachment-info`). Pure — no Temporal, no stdout, no ANSI
7
+ * colors — so unit tests can assert exact lines without booting a client.
8
+ *
9
+ * Lives in `src/utils/` (not `src/cli/`) because both the CLI and TUI
10
+ * consume it; #264 carved it out of `src/cli/commands.ts` to eliminate the
11
+ * cross-surface drift where only the CLI rendered heartbeat age.
12
+ *
13
+ * `now` is injectable so tests can freeze the clock and assert the
14
+ * heartbeat-age string deterministically. Heartbeat age uses
15
+ * {@link formatDurationMs} (same helper the scheduler output uses) suffixed
16
+ * with "ago" — e.g. `5s ago`, `2m ago`. Clock-skew (heartbeat timestamp in
17
+ * the future) renders as `just now`; a malformed timestamp renders as
18
+ * `unknown`.
19
+ */
20
+ import type { AttachmentInfo } from '../types';
21
+ export declare function formatAttachmentInfoForDisplay(name: string, info: AttachmentInfo, now?: number): string[];
22
+ export declare function formatHeartbeatAge(lastHeartbeatAt: string, now: number): string;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatAttachmentInfoForDisplay = formatAttachmentInfoForDisplay;
4
+ exports.formatHeartbeatAge = formatHeartbeatAge;
5
+ const duration_1 = require("./duration");
6
+ function formatAttachmentInfoForDisplay(name, info, now = Date.now()) {
7
+ const lines = [
8
+ `${name} — phase: ${info.phase}`,
9
+ ` in-flight: ${info.inFlightCount}`,
10
+ ];
11
+ if (info.currentAttachment) {
12
+ const a = info.currentAttachment;
13
+ lines.push(` attached on: ${a.hostname} (adapter: ${a.adapterId}/${a.adapterClass})`);
14
+ lines.push(` attachmentId: ${a.attachmentId}`);
15
+ lines.push(` lease expires: ${a.expiresAt}`);
16
+ lines.push(` heartbeat: ${formatHeartbeatAge(a.lastHeartbeatAt, now)}`);
17
+ }
18
+ if (info.preferredHost)
19
+ lines.push(` preferred host: ${info.preferredHost}`);
20
+ if (info.processingSince)
21
+ lines.push(` processing since: ${info.processingSince}`);
22
+ return lines;
23
+ }
24
+ function formatHeartbeatAge(lastHeartbeatAt, now) {
25
+ const then = Date.parse(lastHeartbeatAt);
26
+ if (!Number.isFinite(then))
27
+ return 'unknown';
28
+ const ageMs = now - then;
29
+ if (ageMs < 0)
30
+ return 'just now'; // adapter clock ran ahead of ours — degrade gracefully
31
+ return `${(0, duration_1.formatDurationMs)(ageMs)} ago`;
32
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Adapter types that are considered "headless" — i.e. they run without
3
+ * an interactive terminal. When a session has no explicit `part` and no
4
+ * player type, a headless adapter gets `'Headless <adapter> session'`
5
+ * instead of the generic `'Session in <basename>'`.
6
+ *
7
+ * Issue #537.
8
+ */
9
+ export declare const HEADLESS_ADAPTERS: Set<string>;
10
+ /**
11
+ * Compute the default `part` text seeded into a fresh session workflow.
12
+ *
13
+ * Issue #450 — replaces the hardcoded `'Conductor session'` literal
14
+ * (which leaked through to non-conductor players via the rev3-cert
15
+ * deferred audit item R3.P2.5) and the role-agnostic
16
+ * `'Session in <basename>'` fallback with a single helper that picks a
17
+ * default reflecting the player's role whenever a player type is
18
+ * resolvable.
19
+ *
20
+ * Resolution order:
21
+ * 1. If `playerType` is set, derive from the suffix after stripping
22
+ * `tempo-` / `my-tempo-` / `la-tempo-`. Abbreviations live in
23
+ * `ROLE_ABBREVIATIONS`; everything else is title-cased:
24
+ * `tempo-conductor` → `'Conductor session'`
25
+ * `my-tempo-engineer` → `'Engineer session'`
26
+ * `my-tempo-qa` → `'QA session'`
27
+ * `my-tempo-devops` → `'DevOps session'`
28
+ * `la-tempo-advisor` → `'Advisor session'`
29
+ * `acme-reviewer` → `'Acme-reviewer session'` (no prefix match)
30
+ * 2. Else if `isConductor`, return `'Conductor session'` (the
31
+ * pre-#450 conductor literal — kept so untyped conductor sessions
32
+ * still read correctly).
33
+ * 3. Else if the adapter is headless (#537), return
34
+ * `'Headless <adapterType> session'`.
35
+ * 4. Else fall back to `'Session in <basename(workDir)>'`, or
36
+ * `'New session'` when no `workDir` is provided.
37
+ */
38
+ export declare function defaultPart(opts: {
39
+ playerType?: string;
40
+ isConductor?: boolean;
41
+ workDir?: string;
42
+ adapterType?: string;
43
+ }): string;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HEADLESS_ADAPTERS = void 0;
7
+ exports.defaultPart = defaultPart;
8
+ const path_1 = __importDefault(require("path"));
9
+ /**
10
+ * Match the common agent-tempo agent-type prefixes so the suffix can be
11
+ * surfaced as a human-readable role:
12
+ * - `tempo-*` (shipped types: tempo-conductor, tempo-soloist, …)
13
+ * - `my-tempo-*` (per-user overrides under `~/.claude/agents/`)
14
+ * - `la-tempo-*` (workspace/project agents under `.claude/agents/`)
15
+ *
16
+ * Anything that doesn't match falls through and the full type name is
17
+ * title-cased instead, so a custom `acme-reviewer` type still reads as
18
+ * `'Acme-reviewer session'` rather than something nonsensical.
19
+ */
20
+ const PLAYER_TYPE_PREFIX = /^(my-|la-)?tempo-/i;
21
+ /**
22
+ * Roles whose canonical capitalisation is not what naive title-casing
23
+ * produces (e.g. `qa` would become `'Qa'`). Keys are the lowercased
24
+ * suffix after `PLAYER_TYPE_PREFIX` is stripped; values are the
25
+ * display string spliced into `'<value> session'`.
26
+ *
27
+ * Add entries sparingly — most types follow the title-case rule and
28
+ * shouldn't need a special case.
29
+ */
30
+ const ROLE_ABBREVIATIONS = {
31
+ qa: 'QA',
32
+ po: 'PO',
33
+ devops: 'DevOps',
34
+ };
35
+ /**
36
+ * Adapter types that are considered "headless" — i.e. they run without
37
+ * an interactive terminal. When a session has no explicit `part` and no
38
+ * player type, a headless adapter gets `'Headless <adapter> session'`
39
+ * instead of the generic `'Session in <basename>'`.
40
+ *
41
+ * Issue #537.
42
+ */
43
+ exports.HEADLESS_ADAPTERS = new Set([
44
+ 'claude-code-headless',
45
+ 'copilot',
46
+ 'opencode',
47
+ 'claude-api',
48
+ 'mock',
49
+ ]);
50
+ /**
51
+ * Compute the default `part` text seeded into a fresh session workflow.
52
+ *
53
+ * Issue #450 — replaces the hardcoded `'Conductor session'` literal
54
+ * (which leaked through to non-conductor players via the rev3-cert
55
+ * deferred audit item R3.P2.5) and the role-agnostic
56
+ * `'Session in <basename>'` fallback with a single helper that picks a
57
+ * default reflecting the player's role whenever a player type is
58
+ * resolvable.
59
+ *
60
+ * Resolution order:
61
+ * 1. If `playerType` is set, derive from the suffix after stripping
62
+ * `tempo-` / `my-tempo-` / `la-tempo-`. Abbreviations live in
63
+ * `ROLE_ABBREVIATIONS`; everything else is title-cased:
64
+ * `tempo-conductor` → `'Conductor session'`
65
+ * `my-tempo-engineer` → `'Engineer session'`
66
+ * `my-tempo-qa` → `'QA session'`
67
+ * `my-tempo-devops` → `'DevOps session'`
68
+ * `la-tempo-advisor` → `'Advisor session'`
69
+ * `acme-reviewer` → `'Acme-reviewer session'` (no prefix match)
70
+ * 2. Else if `isConductor`, return `'Conductor session'` (the
71
+ * pre-#450 conductor literal — kept so untyped conductor sessions
72
+ * still read correctly).
73
+ * 3. Else if the adapter is headless (#537), return
74
+ * `'Headless <adapterType> session'`.
75
+ * 4. Else fall back to `'Session in <basename(workDir)>'`, or
76
+ * `'New session'` when no `workDir` is provided.
77
+ */
78
+ function defaultPart(opts) {
79
+ const playerType = opts.playerType?.trim();
80
+ if (playerType) {
81
+ const suffix = playerType.replace(PLAYER_TYPE_PREFIX, '');
82
+ if (suffix) {
83
+ const abbrev = ROLE_ABBREVIATIONS[suffix.toLowerCase()];
84
+ if (abbrev) {
85
+ return `${abbrev} session`;
86
+ }
87
+ const titled = suffix.charAt(0).toUpperCase() + suffix.slice(1);
88
+ return `${titled} session`;
89
+ }
90
+ }
91
+ if (opts.isConductor) {
92
+ return 'Conductor session';
93
+ }
94
+ // Issue #537 — headless adapters get a descriptive default when
95
+ // neither playerType nor isConductor identify the session.
96
+ const adapterType = opts.adapterType?.trim();
97
+ if (adapterType && exports.HEADLESS_ADAPTERS.has(adapterType)) {
98
+ return `Headless ${adapterType} session`;
99
+ }
100
+ if (opts.workDir && opts.workDir.trim()) {
101
+ return `Session in ${path_1.default.basename(opts.workDir)}`;
102
+ }
103
+ return 'New session';
104
+ }
@@ -0,0 +1,30 @@
1
+ /** Parse a duration string like "30s", "10m", "2h", "1d" into milliseconds. */
2
+ export declare function parseDuration(dur: string): number | null;
3
+ /**
4
+ * Humanise a millisecond count as a short duration string: `30s` / `5m` /
5
+ * `2h` / `1d`. Picks the largest unit whose integer-or-fractional value is
6
+ * ≥ 1. Inverse (roughly) of {@link parseDuration}; matches the output shape
7
+ * several other surfaces emit (scheduler listings, attachment-info CLI).
8
+ *
9
+ * Consolidated here as part of #264 so the shared attachment-info formatter
10
+ * in `src/utils/attachment-format.ts` doesn't drag the CLI-local duplicate.
11
+ * Other local duplicates exist at `src/ensemble/saver.ts` and
12
+ * `src/tools/schedules.ts` — those can be migrated incrementally; leaving
13
+ * them alone keeps this PR's scope tight.
14
+ */
15
+ export declare function formatDurationMs(ms: number): string;
16
+ /**
17
+ * Render an ISO timestamp as a coarse "N{s,m,h,d} ago" string for human-
18
+ * readable listings. Returns `"just now"` for ≤1s, `"unknown"` if the
19
+ * timestamp can't be parsed.
20
+ *
21
+ * `now` is injectable for deterministic tests; defaults to `Date.now()`.
22
+ *
23
+ * **Why a second time helper exists** (the TUI has `formatRelativeTime`
24
+ * in `src/tui/utils/format.ts` doing roughly the same thing):
25
+ * `src/tui/` carries Ink/React transitive imports the headless tools layer
26
+ * mustn't take on. This helper has zero dependencies and is freely
27
+ * importable by any layer. Consolidation across the two homes is tracked
28
+ * as future deduplication work, not in scope here.
29
+ */
30
+ export declare function formatTimeAgo(iso: string, now?: number): string;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDuration = parseDuration;
4
+ exports.formatDurationMs = formatDurationMs;
5
+ exports.formatTimeAgo = formatTimeAgo;
6
+ /** Parse a duration string like "30s", "10m", "2h", "1d" into milliseconds. */
7
+ function parseDuration(dur) {
8
+ const match = dur.match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d)$/i);
9
+ if (!match)
10
+ return null;
11
+ const value = parseFloat(match[1]);
12
+ switch (match[2].toLowerCase()) {
13
+ case 's': return value * 1000;
14
+ case 'm': return value * 60_000;
15
+ case 'h': return value * 3_600_000;
16
+ case 'd': return value * 86_400_000;
17
+ default: return null;
18
+ }
19
+ }
20
+ /**
21
+ * Humanise a millisecond count as a short duration string: `30s` / `5m` /
22
+ * `2h` / `1d`. Picks the largest unit whose integer-or-fractional value is
23
+ * ≥ 1. Inverse (roughly) of {@link parseDuration}; matches the output shape
24
+ * several other surfaces emit (scheduler listings, attachment-info CLI).
25
+ *
26
+ * Consolidated here as part of #264 so the shared attachment-info formatter
27
+ * in `src/utils/attachment-format.ts` doesn't drag the CLI-local duplicate.
28
+ * Other local duplicates exist at `src/ensemble/saver.ts` and
29
+ * `src/tools/schedules.ts` — those can be migrated incrementally; leaving
30
+ * them alone keeps this PR's scope tight.
31
+ */
32
+ function formatDurationMs(ms) {
33
+ if (ms >= 86_400_000)
34
+ return `${ms / 86_400_000}d`;
35
+ if (ms >= 3_600_000)
36
+ return `${ms / 3_600_000}h`;
37
+ if (ms >= 60_000)
38
+ return `${ms / 60_000}m`;
39
+ return `${ms / 1000}s`;
40
+ }
41
+ /**
42
+ * Render an ISO timestamp as a coarse "N{s,m,h,d} ago" string for human-
43
+ * readable listings. Returns `"just now"` for ≤1s, `"unknown"` if the
44
+ * timestamp can't be parsed.
45
+ *
46
+ * `now` is injectable for deterministic tests; defaults to `Date.now()`.
47
+ *
48
+ * **Why a second time helper exists** (the TUI has `formatRelativeTime`
49
+ * in `src/tui/utils/format.ts` doing roughly the same thing):
50
+ * `src/tui/` carries Ink/React transitive imports the headless tools layer
51
+ * mustn't take on. This helper has zero dependencies and is freely
52
+ * importable by any layer. Consolidation across the two homes is tracked
53
+ * as future deduplication work, not in scope here.
54
+ */
55
+ function formatTimeAgo(iso, now = Date.now()) {
56
+ const t = Date.parse(iso);
57
+ if (!Number.isFinite(t))
58
+ return 'unknown';
59
+ const ms = now - t;
60
+ if (ms < 1000)
61
+ return 'just now';
62
+ if (ms < 60_000)
63
+ return `${Math.floor(ms / 1000)}s ago`;
64
+ if (ms < 3_600_000)
65
+ return `${Math.floor(ms / 60_000)}m ago`;
66
+ if (ms < 86_400_000)
67
+ return `${Math.floor(ms / 3_600_000)}h ago`;
68
+ return `${Math.floor(ms / 86_400_000)}d ago`;
69
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Shared ensemble-scope plumbing for the MCP tool handlers (`pause`, `play`,
3
+ * `shutdown`, `restore`, ensemble-scope `destroy`) and their `TempoClient`
4
+ * counterparts.
5
+ *
6
+ * All of these verbs need the same bits:
7
+ * 1. Toggle the maestro + scheduler pause signals, tolerating "workflow
8
+ * not running" on each because a bare-bones ensemble may lack either.
9
+ * 2. Fan out a signal (or update) across every session in the ensemble.
10
+ *
11
+ * Inlining these at each call site was pushing the diff past the architect's
12
+ * 500-line budget on PR #287 and bloating every new verb with near-identical
13
+ * try/catch scaffolding. This module is the single source of truth for both
14
+ * layers (tools + TempoClient) so a future signal-name rename or fan-out
15
+ * concurrency tweak only has to change here.
16
+ */
17
+ import type { Client } from '@temporalio/client';
18
+ /**
19
+ * Result of a pause/unpause toggle. Each flag reflects whether the signal
20
+ * was actually delivered — `false` means the workflow wasn't running and
21
+ * the error was swallowed (the common bare-ensemble case).
22
+ */
23
+ export interface MaestroSchedulerToggleResult {
24
+ maestro: boolean;
25
+ scheduler: boolean;
26
+ }
27
+ /** Pause the ensemble's maestro + scheduler. Best-effort on both. */
28
+ export declare function pauseMaestroAndScheduler(client: Client, ensemble: string): Promise<MaestroSchedulerToggleResult>;
29
+ /** Unpause the ensemble's maestro + scheduler. Best-effort on both. */
30
+ export declare function unpauseMaestroAndScheduler(client: Client, ensemble: string): Promise<MaestroSchedulerToggleResult>;
31
+ /**
32
+ * Fan-out a signal across every session in the ensemble. Per-session calls
33
+ * run in parallel via `Promise.allSettled` so a slow / failing session
34
+ * doesn't block the others — all Temporal ensembles are inherently
35
+ * unordered at this boundary (each session has its own workflow).
36
+ *
37
+ * `skip(playerId)` lets the caller exclude specific sessions (e.g. the
38
+ * caller's own session) without an extra pass.
39
+ */
40
+ export interface FanoutSignalResult {
41
+ sent: number;
42
+ skipped: number;
43
+ failed: number;
44
+ perSession: Array<{
45
+ playerId: string;
46
+ workflowId: string;
47
+ outcome: 'sent';
48
+ } | {
49
+ playerId: string;
50
+ workflowId: string;
51
+ outcome: 'skipped';
52
+ } | {
53
+ playerId: string;
54
+ workflowId: string;
55
+ outcome: 'failed';
56
+ error: string;
57
+ }>;
58
+ }
59
+ export declare function signalAllSessions(client: Client, ensemble: string, signalName: string, payload: unknown, opts?: {
60
+ skip?: (playerId: string) => boolean;
61
+ }): Promise<FanoutSignalResult>;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pauseMaestroAndScheduler = pauseMaestroAndScheduler;
4
+ exports.unpauseMaestroAndScheduler = unpauseMaestroAndScheduler;
5
+ exports.signalAllSessions = signalAllSessions;
6
+ const config_1 = require("../config");
7
+ const resolve_1 = require("../activities/resolve");
8
+ const maestro_signals_1 = require("../workflows/maestro-signals");
9
+ const scheduler_signals_1 = require("../workflows/scheduler-signals");
10
+ /** Pause the ensemble's maestro + scheduler. Best-effort on both. */
11
+ async function pauseMaestroAndScheduler(client, ensemble) {
12
+ return toggleMaestroAndScheduler(client, ensemble, true);
13
+ }
14
+ /** Unpause the ensemble's maestro + scheduler. Best-effort on both. */
15
+ async function unpauseMaestroAndScheduler(client, ensemble) {
16
+ return toggleMaestroAndScheduler(client, ensemble, false);
17
+ }
18
+ async function toggleMaestroAndScheduler(client, ensemble, paused) {
19
+ // Two independent RPCs — run them in parallel. Each catches its own
20
+ // error so one missing workflow doesn't block the other's state change.
21
+ const [maestro, scheduler] = await Promise.all([
22
+ safeSignal(client, (0, config_1.maestroWorkflowId)(ensemble), maestro_signals_1.maestroSetPausedSignal.name, paused),
23
+ safeSignal(client, (0, config_1.schedulerWorkflowId)(ensemble), scheduler_signals_1.setSchedulerPausedSignal.name, paused),
24
+ ]);
25
+ return { maestro, scheduler };
26
+ }
27
+ async function safeSignal(client, workflowId, signalName, payload) {
28
+ try {
29
+ await client.workflow.getHandle(workflowId).signal(signalName, payload);
30
+ return true;
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ async function signalAllSessions(client, ensemble, signalName, payload, opts = {}) {
37
+ const sessions = await (0, resolve_1.scanEnsembleSessions)(client, ensemble);
38
+ const shouldSkip = opts.skip ?? (() => false);
39
+ const result = { sent: 0, skipped: 0, failed: 0, perSession: [] };
40
+ const settled = await Promise.allSettled(sessions.map(async (s) => {
41
+ if (shouldSkip(s.playerId)) {
42
+ return { session: s, outcome: 'skipped' };
43
+ }
44
+ try {
45
+ await client.workflow.getHandle(s.workflowId).signal(signalName, payload);
46
+ return { session: s, outcome: 'sent' };
47
+ }
48
+ catch (err) {
49
+ return {
50
+ session: s,
51
+ outcome: 'failed',
52
+ error: err instanceof Error ? err.message : String(err),
53
+ };
54
+ }
55
+ }));
56
+ for (const r of settled) {
57
+ // `Promise.allSettled` only rejects if the mapper itself throws, and
58
+ // the mapper catches all signal errors internally — so every entry
59
+ // here will be `fulfilled`.
60
+ if (r.status !== 'fulfilled')
61
+ continue;
62
+ const v = r.value;
63
+ if (v.outcome === 'sent') {
64
+ result.sent++;
65
+ result.perSession.push({ playerId: v.session.playerId, workflowId: v.session.workflowId, outcome: 'sent' });
66
+ }
67
+ else if (v.outcome === 'skipped') {
68
+ result.skipped++;
69
+ result.perSession.push({ playerId: v.session.playerId, workflowId: v.session.workflowId, outcome: 'skipped' });
70
+ }
71
+ else {
72
+ result.failed++;
73
+ result.perSession.push({ playerId: v.session.playerId, workflowId: v.session.workflowId, outcome: 'failed', error: v.error });
74
+ }
75
+ }
76
+ return result;
77
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared formatter for the #274 `hosts` surface.
3
+ *
4
+ * Single source of truth consumed by:
5
+ * - `src/tools/hosts.ts` (MCP tool) — formatted text in `ok(...)` payload
6
+ * - `src/cli/commands.ts` (CLI `hosts` command) — stdout table
7
+ * - `src/tui/commands.ts` (TUI `/hosts` slash) — overlay content
8
+ *
9
+ * Pure: no Temporal, no I/O, no ANSI colors (the CLI can wrap lines in
10
+ * color downstream if desired; the formatter emits plain strings so
11
+ * tests can assert exact output without stripping escape codes).
12
+ */
13
+ import type { HostInfo } from '../types';
14
+ export interface FormatHostsOpts {
15
+ /**
16
+ * Include hosts whose freshness is `'stale'`. Default `false`:
17
+ * CLI/TUI hide them by default; `--all` opts in.
18
+ */
19
+ includeStale?: boolean;
20
+ }
21
+ export declare function formatHostList(hosts: HostInfo[], opts?: FormatHostsOpts): string;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatHostList = formatHostList;
4
+ function formatHostList(hosts, opts = {}) {
5
+ const includeStale = opts.includeStale ?? false;
6
+ const visible = includeStale ? hosts : hosts.filter((h) => h.freshness === 'live');
7
+ if (visible.length === 0) {
8
+ if (!includeStale && hosts.length > 0) {
9
+ return 'No live hosts connected. Pass `--all` to include stale hosts.';
10
+ }
11
+ return 'No hosts connected.';
12
+ }
13
+ const lines = [];
14
+ lines.push(`${visible.length} host${visible.length === 1 ? '' : 's'} connected:`);
15
+ lines.push('');
16
+ for (const host of visible) {
17
+ lines.push(...formatSingleHost(host));
18
+ lines.push('');
19
+ }
20
+ // Drop the final empty line so consumers don't have to `.trim()`.
21
+ if (lines[lines.length - 1] === '')
22
+ lines.pop();
23
+ return lines.join('\n');
24
+ }
25
+ function formatSingleHost(host) {
26
+ const lines = [];
27
+ const tag = host.freshness === 'live' ? '' : ' (stale)';
28
+ const recruit = host.recruitReady ? 'recruit-ready' : 'not recruit-ready';
29
+ lines.push(`**${host.hostname}**${tag} — ${recruit}`);
30
+ // Instance(s). One-liner per pid.
31
+ for (const inst of host.instances) {
32
+ const bits = [`pid ${inst.pid}`, `version ${inst.version}`];
33
+ const workerBits = [];
34
+ if (inst.hasWorkflowWorker)
35
+ workerBits.push('wf');
36
+ if (inst.hasActivityWorker)
37
+ workerBits.push('act');
38
+ if (inst.hasHostQueueWorker)
39
+ workerBits.push('host');
40
+ bits.push(`workers: ${workerBits.length > 0 ? workerBits.join('+') : 'none'}`);
41
+ if (inst.lastAccessTime)
42
+ bits.push(`last seen ${inst.lastAccessTime}`);
43
+ if (inst.legacy)
44
+ bits.push('legacy-identity');
45
+ lines.push(` - ${bits.join(' · ')}`);
46
+ }
47
+ // Profile (capability).
48
+ if (host.profile) {
49
+ const p = host.profile;
50
+ const profileBits = [];
51
+ if (p.platform)
52
+ profileBits.push(`platform: ${p.platform}`);
53
+ if (p.defaultAgent)
54
+ profileBits.push(`default agent: ${p.defaultAgent}`);
55
+ if (p.claudeBin)
56
+ profileBits.push(`claude bin: ${p.claudeBin}`);
57
+ if (profileBits.length > 0)
58
+ lines.push(` profile · ${profileBits.join(' · ')}`);
59
+ if (p.availableAgentTypes && p.availableAgentTypes.length > 0) {
60
+ lines.push(` available agents: ${p.availableAgentTypes.join(', ')}`);
61
+ }
62
+ if (p.availablePlayerTypes && p.availablePlayerTypes.length > 0) {
63
+ lines.push(` available player types: ${p.availablePlayerTypes.join(', ')}`);
64
+ }
65
+ if (host.profileStaleness === 'stale') {
66
+ lines.push(` ⚠ profile version disagrees with live identity — awaiting re-signal`);
67
+ }
68
+ }
69
+ else if (host.profileStaleness === 'missing') {
70
+ lines.push(` (profile unavailable)`);
71
+ }
72
+ return lines;
73
+ }