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,221 @@
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.Splash = Splash;
37
+ /**
38
+ * Splash screen — landing/home screen with animated metronome, connection
39
+ * status, and ensemble picker.
40
+ *
41
+ * Uses a single Text element with nested virtual-text nodes to minimize
42
+ * Yoga layout nodes (target: <10 total).
43
+ */
44
+ const react_1 = __importStar(require("react"));
45
+ const ink_context_1 = require("../ink-context");
46
+ const platform_1 = require("../utils/platform");
47
+ const theme_1 = require("../utils/theme");
48
+ const SPINNER_FRAMES = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];
49
+ const PING_PONG = [0, 1, 2, 1];
50
+ const MAX_ENSEMBLES_SHOWN = 5;
51
+ function Splash({ status, version, connected, ensembles, onContinue, onCreateEnsemble }) {
52
+ const { Text, useInput } = (0, ink_context_1.useInk)();
53
+ const [metronomeTick, setMetronomeTick] = (0, react_1.useState)(0);
54
+ const [spinnerTick, setSpinnerTick] = (0, react_1.useState)(0);
55
+ const [selectedIdx, setSelectedIdx] = (0, react_1.useState)(0);
56
+ const brailleFrames = (0, react_1.useMemo)(() => (0, platform_1.metronomeBrailleFrames)(), []);
57
+ const ensembleCount = ensembles?.length ?? 0;
58
+ // Total selectable items: ensembles + "create new" item (when loaded)
59
+ const totalItems = ensembles !== undefined ? ensembleCount + 1 : (ensembleCount || 1);
60
+ const hasNavigation = totalItems > 1;
61
+ const isCreateSelected = ensembles !== undefined && selectedIdx === ensembleCount;
62
+ // Handle keys: ↑↓ to select, Enter to continue/create
63
+ const inputRef = react_1.default.useRef({ connected, onContinue, onCreateEnsemble, ensembles, selectedIdx, isCreateSelected, totalItems });
64
+ inputRef.current = { connected, onContinue, onCreateEnsemble, ensembles, selectedIdx, isCreateSelected, totalItems };
65
+ useInput(react_1.default.useCallback((_input, key) => {
66
+ const r = inputRef.current;
67
+ if (!r.connected)
68
+ return;
69
+ if (key.return) {
70
+ if (r.isCreateSelected) {
71
+ r.onCreateEnsemble?.();
72
+ }
73
+ else {
74
+ const selected = r.ensembles?.[r.selectedIdx]?.name;
75
+ r.onContinue?.(selected);
76
+ }
77
+ return;
78
+ }
79
+ if (key.upArrow) {
80
+ setSelectedIdx(i => Math.max(0, i - 1));
81
+ return;
82
+ }
83
+ if (key.downArrow) {
84
+ setSelectedIdx(i => Math.min(r.totalItems - 1, i + 1));
85
+ return;
86
+ }
87
+ }, []));
88
+ // Metronome animation — cleanup stops timer on unmount/transition
89
+ (0, react_1.useEffect)(() => {
90
+ const timer = setInterval(() => {
91
+ setMetronomeTick((t) => (t + 1) % PING_PONG.length);
92
+ }, 300);
93
+ return () => clearInterval(timer);
94
+ }, []);
95
+ // Spinner animation — stops once connected
96
+ (0, react_1.useEffect)(() => {
97
+ if (connected)
98
+ return;
99
+ const timer = setInterval(() => {
100
+ setSpinnerTick((t) => (t + 1) % SPINNER_FRAMES.length);
101
+ }, 80);
102
+ return () => clearInterval(timer);
103
+ }, [connected]);
104
+ // ── Metronome frame (needed for line count) ──
105
+ const frameIndex = PING_PONG[metronomeTick];
106
+ const frame = brailleFrames[frameIndex];
107
+ // ── Centering calculations ──
108
+ const cols = process.stdout.columns || 80;
109
+ const rows = process.stdout.rows || 24;
110
+ /** Center a string horizontally based on its visible width. */
111
+ const center = (text) => {
112
+ const pad = Math.max(0, Math.floor((cols - text.length) / 2));
113
+ return ' '.repeat(pad) + text;
114
+ };
115
+ // Count actual content lines for accurate vertical centering
116
+ const metroLines = frame.length; // ~10 lines
117
+ const titleLines = 5; // 2 blank + title + tagline + version
118
+ const statusLines = 3; // 2 blank + status line
119
+ const ensembleLines = connected && ensembles !== undefined
120
+ ? 1 + Math.min(ensembleCount, MAX_ENSEMBLES_SHOWN) + 1 + (ensembleCount === 0 ? 1 : 0) // gap + items + create + optional "none"
121
+ : (connected ? 3 : 0); // loading or not connected
122
+ const promptLines = 3; // 2 blank + prompt
123
+ const contentHeight = metroLines + titleLines + statusLines + ensembleLines + promptLines;
124
+ const vPad = Math.max(0, Math.floor((rows - contentHeight - 3) / 2));
125
+ // ── Build single Text element with all content as nested virtual-text ──
126
+ const children = [];
127
+ // Vertical centering
128
+ for (let i = 0; i < vPad; i++)
129
+ children.push('\n');
130
+ // Metronome logo (braille characters as nested Text — 0 Yoga nodes)
131
+ for (let li = 0; li < frame.length; li++) {
132
+ if (li > 0)
133
+ children.push('\n');
134
+ const lineWidth = frame[li].reduce((w, seg) => w + seg.char.length, 0);
135
+ const metroPad = ' '.repeat(Math.max(0, Math.floor((cols - lineWidth) / 2)));
136
+ children.push(metroPad);
137
+ for (let si = 0; si < frame[li].length; si++) {
138
+ const seg = frame[li][si];
139
+ children.push(react_1.default.createElement(Text, { key: `m-${li}-${si}`, color: seg.color || undefined }, seg.char));
140
+ }
141
+ }
142
+ // Title + tagline + version
143
+ children.push('\n\n');
144
+ children.push(react_1.default.createElement(Text, { key: 'title', bold: true, color: theme_1.THEME.accent }, center('agent-tempo')));
145
+ children.push('\n');
146
+ children.push(react_1.default.createElement(Text, { key: 'tagline', color: theme_1.THEME.dim }, center('Multi-session orchestration via Temporal')));
147
+ children.push('\n');
148
+ children.push(react_1.default.createElement(Text, { key: 'version', color: theme_1.THEME.muted }, center(`v${version}`)));
149
+ // Connection status
150
+ children.push('\n\n');
151
+ if (connected) {
152
+ children.push(react_1.default.createElement(Text, { key: 'status', color: theme_1.THEME.success }, center('\u2713 Connected')));
153
+ }
154
+ else {
155
+ children.push(react_1.default.createElement(Text, { key: 'status', color: theme_1.THEME.warning }, center(`${SPINNER_FRAMES[spinnerTick]} ${status}`)));
156
+ }
157
+ // Ensemble list + create option (when connected)
158
+ if (connected && ensembles !== undefined) {
159
+ children.push('\n');
160
+ if (ensembles.length > 0) {
161
+ let startIdx = 0;
162
+ if (ensembles.length > MAX_ENSEMBLES_SHOWN) {
163
+ startIdx = Math.max(0, Math.min(selectedIdx - Math.floor(MAX_ENSEMBLES_SHOWN / 2), ensembles.length - MAX_ENSEMBLES_SHOWN));
164
+ }
165
+ const visible = ensembles.slice(startIdx, startIdx + MAX_ENSEMBLES_SHOWN);
166
+ if (startIdx > 0) {
167
+ children.push('\n');
168
+ children.push(react_1.default.createElement(Text, { key: 'sup', color: theme_1.THEME.dim }, center(`\u2191 ${startIdx} more`)));
169
+ }
170
+ for (let i = 0; i < visible.length; i++) {
171
+ const ens = visible[i];
172
+ const actualIdx = startIdx + i;
173
+ const isSelected = actualIdx === selectedIdx;
174
+ const icon = ens.hasConductor ? '\u2605' : '\u2022';
175
+ const indicator = isSelected ? '\u25B8 ' : ' ';
176
+ children.push('\n');
177
+ children.push(react_1.default.createElement(Text, {
178
+ key: `ens-${ens.name}`,
179
+ color: isSelected ? theme_1.THEME.accent : theme_1.THEME.textMuted,
180
+ bold: isSelected,
181
+ }, center(`${indicator}${icon} ${ens.name} (${ens.playerCount} player${ens.playerCount !== 1 ? 's' : ''})`)));
182
+ }
183
+ if (startIdx + MAX_ENSEMBLES_SHOWN < ensembles.length) {
184
+ children.push('\n');
185
+ children.push(react_1.default.createElement(Text, { key: 'sdn', color: theme_1.THEME.dim }, center(`\u2193 ${ensembles.length - startIdx - MAX_ENSEMBLES_SHOWN} more`)));
186
+ }
187
+ }
188
+ else {
189
+ // Loaded but empty
190
+ children.push('\n');
191
+ children.push(react_1.default.createElement(Text, { key: 'none', color: theme_1.THEME.dim }, center('No ensembles running.')));
192
+ }
193
+ // "+ Create new ensemble" — always selectable
194
+ children.push('\n');
195
+ const createIndicator = isCreateSelected ? '\u25B8 ' : ' ';
196
+ children.push(react_1.default.createElement(Text, {
197
+ key: 'create',
198
+ color: isCreateSelected ? theme_1.THEME.accent : theme_1.THEME.dim,
199
+ bold: isCreateSelected,
200
+ }, center(`${createIndicator}+ Create new ensemble`)));
201
+ }
202
+ else if (connected) {
203
+ // Connected but ensembles not yet loaded
204
+ children.push('\n\n');
205
+ children.push(react_1.default.createElement(Text, { key: 'loading', color: theme_1.THEME.dim }, center('\u27F3 Discovering ensembles...')));
206
+ }
207
+ // Bottom prompt
208
+ children.push('\n\n');
209
+ if (connected) {
210
+ children.push(react_1.default.createElement(Text, { key: 'prompt', bold: true, color: theme_1.THEME.accent }, ensembles === undefined
211
+ ? center('Press Ctrl+C to exit')
212
+ : hasNavigation
213
+ ? center('\u2191\u2193 to select, Enter to continue')
214
+ : center('Press Enter to continue')));
215
+ }
216
+ else {
217
+ children.push(react_1.default.createElement(Text, { key: 'prompt', color: theme_1.THEME.muted }, center('Press Ctrl+C to cancel')));
218
+ }
219
+ // Single Text element wrapping everything (1 Yoga node)
220
+ return react_1.default.createElement(Text, null, ...children);
221
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * StatusBar — persistent one-line status summary.
3
+ * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
4
+ */
5
+ import React from 'react';
6
+ import type { MaestroPlayerInfo } from '../../types';
7
+ export interface StatusBarProps {
8
+ ensemble: string | null;
9
+ players: MaestroPlayerInfo[];
10
+ /** True after the first player poll completes. False = still loading. */
11
+ playersLoaded: boolean;
12
+ scheduleCount: number;
13
+ connected: boolean;
14
+ /**
15
+ * Bug B: Whether the active ensemble's maestro hub is paused. Drives a
16
+ * yellow "paused" segment so users see why a conductor is silently
17
+ * swallowing typed messages (the session-level `paused` flag gates the
18
+ * outbox dispatcher).
19
+ */
20
+ ensemblePaused?: boolean;
21
+ /**
22
+ * #306 follow-up: Whether at least one session in the active ensemble
23
+ * has its outbox locked (`held`). Drives a yellow "held" segment.
24
+ * Independent of `ensemblePaused` because `/load_lineup` flips both
25
+ * flags at once but `/play` only clears pause — users would otherwise
26
+ * see "no paused indicator" and assume the ensemble is fully resumed
27
+ * when held players were still frozen behind the locked outbox.
28
+ */
29
+ ensembleHeld?: boolean;
30
+ }
31
+ /**
32
+ * One rendered text segment of the status bar. Returned by
33
+ * {@link buildStatusBarSegments} so tests can inspect the bar's contents
34
+ * without spinning up Ink. Each segment becomes a nested ink-virtual-text
35
+ * inside the single outer Text element.
36
+ */
37
+ export interface StatusBarSegment {
38
+ key: string;
39
+ color: string;
40
+ text: string;
41
+ }
42
+ /**
43
+ * Pure helper: compute the StatusBar's segment list from props. Keeps the
44
+ * render-path logic testable without an Ink context. The component below
45
+ * just maps each segment to a `<Text>` element.
46
+ */
47
+ export declare function buildStatusBarSegments(props: StatusBarProps): StatusBarSegment[];
48
+ export declare function StatusBar(props: StatusBarProps): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
@@ -0,0 +1,128 @@
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.buildStatusBarSegments = buildStatusBarSegments;
7
+ exports.StatusBar = StatusBar;
8
+ /**
9
+ * StatusBar — persistent one-line status summary.
10
+ * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
11
+ */
12
+ const react_1 = __importDefault(require("react"));
13
+ const ink_context_1 = require("../ink-context");
14
+ const theme_1 = require("../utils/theme");
15
+ const format_1 = require("../utils/format");
16
+ /**
17
+ * Pure helper: compute the StatusBar's segment list from props. Keeps the
18
+ * render-path logic testable without an Ink context. The component below
19
+ * just maps each segment to a `<Text>` element.
20
+ */
21
+ function buildStatusBarSegments(props) {
22
+ const { ensemble, players, playersLoaded, scheduleCount, connected, ensemblePaused, ensembleHeld } = props;
23
+ const healthColor = connected ? theme_1.THEME.success : theme_1.THEME.error;
24
+ const healthDot = connected ? '●' : '○';
25
+ const healthLabel = connected ? 'Connected' : 'Disconnected';
26
+ const ensembleLabel = ensemble || 'no ensemble';
27
+ const segments = [
28
+ { key: 'lead', color: theme_1.THEME.dim, text: ' ' },
29
+ { key: 'ens', color: ensemble ? theme_1.THEME.accent : theme_1.THEME.dim, text: ensembleLabel },
30
+ { key: 's1', color: theme_1.THEME.dim, text: ' · ' },
31
+ ];
32
+ if (ensemble && !playersLoaded) {
33
+ // Still loading — don't show incorrect counts
34
+ segments.push({ key: 'pl', color: theme_1.THEME.dim, text: 'Loading...' });
35
+ }
36
+ else {
37
+ // Exclude the maestro session from headline counts — it is the TUI's own
38
+ // dashboard attachment, not a peer agent. The full list (including the
39
+ // maestro) is still surfaced in `/players` and the status overlay so the
40
+ // user can see internal state honestly.
41
+ const realPlayers = (0, format_1.filterRealPlayers)(players);
42
+ // Player breakdown by phase label (Option-B five buckets collapsed to four
43
+ // meaningful ones for the bar — `gone` players are terminal and not
44
+ // shown in the ensemble list).
45
+ let active = 0;
46
+ let idle = 0;
47
+ let disconnected = 0;
48
+ let pending = 0;
49
+ for (const p of realPlayers) {
50
+ switch ((0, format_1.phaseToLabel)(p.phase)) {
51
+ case 'active':
52
+ active++;
53
+ break;
54
+ case 'idle':
55
+ idle++;
56
+ break;
57
+ case 'disconnected':
58
+ disconnected++;
59
+ break;
60
+ case 'pending':
61
+ pending++;
62
+ break;
63
+ // 'gone' / 'unknown' intentionally not counted in the summary line.
64
+ }
65
+ }
66
+ const parts = [];
67
+ if (active > 0)
68
+ parts.push(`${active} active`);
69
+ if (idle > 0)
70
+ parts.push(`${idle} idle`);
71
+ if (disconnected > 0)
72
+ parts.push(`${disconnected} disconnected`);
73
+ if (pending > 0)
74
+ parts.push(`${pending} pending`);
75
+ const breakdown = parts.length > 0 ? ` (${parts.join(', ')})` : '';
76
+ const playerLabel = `${realPlayers.length} player${realPlayers.length !== 1 ? 's' : ''}${breakdown}`;
77
+ segments.push({ key: 'pl', color: theme_1.THEME.dim, text: playerLabel });
78
+ if (scheduleCount > 0) {
79
+ segments.push({ key: 's2', color: theme_1.THEME.dim, text: ' · ' }, { key: 'sc', color: theme_1.THEME.dim, text: `${scheduleCount} schedule${scheduleCount !== 1 ? 's' : ''}` });
80
+ }
81
+ // Bug B + #306 follow-up: yellow `paused`/`held`/`paused + held` segment
82
+ // when the maestro hub is paused or any session has its outbox locked
83
+ // (or both — `/load_lineup` flips both flags at once). Placed before
84
+ // the "No conductor" warning so the most actionable state reads first
85
+ // when both apply. The same guard (`ensemble && …`) keeps the segment
86
+ // off the home view.
87
+ //
88
+ // Combined-glyph variant for paused + held picks `⏸⊕ paused + held`
89
+ // over two separate segments — scans cleaner at terminal density and
90
+ // lets the matching tip below the input ("Tip: type /play to unpause
91
+ // + /go to release held players.") read as one instruction.
92
+ if (ensemble && (ensemblePaused || ensembleHeld)) {
93
+ let label;
94
+ if (ensemblePaused && ensembleHeld) {
95
+ label = '⏸⊕ paused + held';
96
+ }
97
+ else if (ensemblePaused) {
98
+ // U+23F8 PAUSE SYMBOL — single glyph, mirrors the U+26A0 warning below.
99
+ label = '⏸ paused';
100
+ }
101
+ else {
102
+ // U+2295 CIRCLED PLUS — distinct from pause, suggests "more buffered".
103
+ label = '⊕ held';
104
+ }
105
+ segments.push({ key: 'sp', color: theme_1.THEME.dim, text: ' · ' }, { key: 'pa', color: theme_1.THEME.warning, text: label });
106
+ }
107
+ // #358: derive from `players` (single source of truth) so the badge
108
+ // updates on incremental SSE events (`player.added`/`player.removed`)
109
+ // without waiting for the next snapshot. Pre-#358 this depended on a
110
+ // separate `conductorName` cache populated only by the snapshot path,
111
+ // so a `/destroy conductor` mid-session left "No conductor" stuck off
112
+ // until the next snapshot intervened.
113
+ if (ensemble && !players.some(p => p.isConductor)) {
114
+ segments.push({ key: 's3', color: theme_1.THEME.dim, text: ' · ' }, { key: 'nc', color: theme_1.THEME.warning, text: '⚠ No conductor' });
115
+ }
116
+ }
117
+ segments.push({ key: 's4', color: theme_1.THEME.dim, text: ' · ' }, { key: 'hd', color: healthColor, text: healthDot }, { key: 'hl', color: theme_1.THEME.dim, text: ` ${healthLabel}` });
118
+ return segments;
119
+ }
120
+ function StatusBar(props) {
121
+ const { Text } = (0, ink_context_1.useInk)();
122
+ const segments = buildStatusBarSegments(props);
123
+ // Single Text element — all children are ink-virtual-text (0 Yoga nodes)
124
+ const children = segments.map((s) => s.key === 'lead'
125
+ ? s.text
126
+ : react_1.default.createElement(Text, { key: s.key, color: s.color }, s.text));
127
+ return react_1.default.createElement(Text, null, ...children);
128
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * StatusOverlay — dismissible overlay showing ensemble player cards.
3
+ *
4
+ * Performance: Single <Text> root with nested virtual-text children.
5
+ * Zero Yoga <Box> nodes.
6
+ */
7
+ import React from 'react';
8
+ import type { MaestroPlayerInfo } from '../../types';
9
+ export interface StatusOverlayProps {
10
+ players: MaestroPlayerInfo[];
11
+ ensemble: string;
12
+ scrollOffset: number;
13
+ contentHeight: number;
14
+ }
15
+ export declare function StatusOverlay({ players, ensemble, scrollOffset, contentHeight }: StatusOverlayProps): React.CElement<{}, React.Component<{}, any, any>>;
@@ -0,0 +1,76 @@
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.StatusOverlay = StatusOverlay;
7
+ /**
8
+ * StatusOverlay — dismissible overlay showing ensemble player cards.
9
+ *
10
+ * Performance: Single <Text> root with nested virtual-text children.
11
+ * Zero Yoga <Box> nodes.
12
+ */
13
+ const react_1 = __importDefault(require("react"));
14
+ const ink_context_1 = require("../ink-context");
15
+ const theme_1 = require("../utils/theme");
16
+ const format_1 = require("../utils/format");
17
+ const platform_1 = require("../utils/platform");
18
+ function StatusOverlay({ players, ensemble, scrollOffset, contentHeight }) {
19
+ const { Text } = (0, ink_context_1.useInk)();
20
+ const icons = (0, platform_1.statusIcons)((0, platform_1.supportsUnicode)());
21
+ const cols = process.stdout.columns || 80;
22
+ const indent = 4;
23
+ const maxWidth = Math.max(20, cols - indent);
24
+ const wrap = (text) => {
25
+ if (text.length <= maxWidth)
26
+ return text;
27
+ const prefix = ' '.repeat(indent);
28
+ const chunks = [];
29
+ let rem = text;
30
+ while (rem.length > maxWidth) {
31
+ let brk = rem.lastIndexOf(' ', maxWidth);
32
+ if (brk <= 0)
33
+ brk = maxWidth;
34
+ chunks.push(rem.slice(0, brk));
35
+ rem = rem.slice(brk).trimStart();
36
+ }
37
+ if (rem)
38
+ chunks.push(rem);
39
+ return chunks.join('\n' + prefix);
40
+ };
41
+ const maxVisible = Math.max(2, Math.floor((contentHeight - 3) / 4));
42
+ const clampedOffset = Math.min(scrollOffset, Math.max(0, players.length - maxVisible));
43
+ const visiblePlayers = players.slice(clampedOffset, clampedOffset + maxVisible);
44
+ const children = [];
45
+ children.push(react_1.default.createElement(Text, { key: 'h', bold: true, color: theme_1.THEME.accent }, ` Ensemble: ${ensemble} (${players.length} player${players.length !== 1 ? 's' : ''})`));
46
+ if (clampedOffset > 0) {
47
+ children.push('\n');
48
+ children.push(react_1.default.createElement(Text, { key: 'sup', color: theme_1.THEME.dim }, ` \u2191 ${clampedOffset} more above`));
49
+ }
50
+ for (const p of visiblePlayers) {
51
+ // Attachment-phase → icon/color lookup (post-#177 Option-B mapping).
52
+ const icon = icons[(0, format_1.phaseToIconName)(p.phase)];
53
+ const iconColor = (0, format_1.phaseToColor)(p.phase);
54
+ const conductor = p.isConductor ? ' \u2605' : '';
55
+ children.push('\n\n');
56
+ children.push(react_1.default.createElement(react_1.default.Fragment, { key: `${p.playerId}-1` }, react_1.default.createElement(Text, { color: iconColor }, ` ${icon} `), react_1.default.createElement(Text, { bold: true, color: theme_1.THEME.text }, p.playerId), conductor ? react_1.default.createElement(Text, { color: theme_1.THEME.warning }, conductor) : null));
57
+ const details = [(0, format_1.phaseToLabel)(p.phase)];
58
+ if (p.gitBranch)
59
+ details.push(p.gitBranch);
60
+ if (p.playerType || p.agentType)
61
+ details.push(p.playerType || p.agentType || '');
62
+ children.push('\n');
63
+ children.push(react_1.default.createElement(Text, { key: `${p.playerId}-2`, color: theme_1.THEME.dim }, ` ${wrap(details.join(' \u00B7 '))}`));
64
+ if (p.part) {
65
+ children.push('\n');
66
+ children.push(react_1.default.createElement(Text, { key: `${p.playerId}-3`, color: theme_1.THEME.textMuted }, ` ${wrap(p.part)}`));
67
+ }
68
+ }
69
+ if (clampedOffset + maxVisible < players.length) {
70
+ children.push('\n\n');
71
+ children.push(react_1.default.createElement(Text, { key: 'sdn', color: theme_1.THEME.dim }, ` \u2193 ${players.length - clampedOffset - maxVisible} more below`));
72
+ }
73
+ children.push('\n\n');
74
+ children.push(react_1.default.createElement(Text, { key: 'hint', color: theme_1.THEME.dim }, ' \u2191\u2193 scroll, Esc to dismiss'));
75
+ return react_1.default.createElement(Text, null, ...children);
76
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * TitleBar — pinned top bar for the TUI shell.
3
+ * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
4
+ */
5
+ import React from 'react';
6
+ export interface TitleBarProps {
7
+ /** Context text displayed on the right side. */
8
+ context: string;
9
+ }
10
+ export declare function TitleBar({ context }: TitleBarProps): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
@@ -0,0 +1,21 @@
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.TitleBar = TitleBar;
7
+ /**
8
+ * TitleBar — pinned top bar for the TUI shell.
9
+ * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
10
+ */
11
+ const react_1 = __importDefault(require("react"));
12
+ const ink_context_1 = require("../ink-context");
13
+ const theme_1 = require("../utils/theme");
14
+ function TitleBar({ context }) {
15
+ const { Text } = (0, ink_context_1.useInk)();
16
+ const cols = process.stdout.columns || 80;
17
+ const left = 'agent-tempo';
18
+ // Pad between left and right to push context to the right edge
19
+ const padding = Math.max(1, cols - left.length - context.length - 4); // -4 for paddingX
20
+ return react_1.default.createElement(Text, null, ' ', react_1.default.createElement(Text, { bold: true, color: theme_1.THEME.accent }, left), ' '.repeat(padding), react_1.default.createElement(Text, { color: theme_1.THEME.dim }, context));
21
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Top bar — shows ensemble name, player count, and keybindings.
3
+ */
4
+ import React from 'react';
5
+ export interface TopBarProps {
6
+ ensemble: string;
7
+ playerCount: number;
8
+ connected: boolean;
9
+ }
10
+ export declare function TopBar({ ensemble, playerCount, connected }: TopBarProps): React.FunctionComponentElement<{
11
+ paddingX: number;
12
+ }>;
@@ -0,0 +1,15 @@
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.TopBar = TopBar;
7
+ /**
8
+ * Top bar — shows ensemble name, player count, and keybindings.
9
+ */
10
+ const react_1 = __importDefault(require("react"));
11
+ const ink_context_1 = require("../ink-context");
12
+ function TopBar({ ensemble, playerCount, connected }) {
13
+ const { Box, Text, Spacer } = (0, ink_context_1.useInk)();
14
+ return react_1.default.createElement(Box, { paddingX: 1 }, react_1.default.createElement(Text, { bold: true, color: 'cyan' }, 'claude-tempo'), react_1.default.createElement(Text, null, ' | '), react_1.default.createElement(Text, { color: connected ? 'green' : 'red' }, ensemble), react_1.default.createElement(Text, null, ' | '), react_1.default.createElement(Text, { dimColor: true }, `${playerCount} player${playerCount !== 1 ? 's' : ''}`), react_1.default.createElement(Spacer, null), react_1.default.createElement(Text, { dimColor: true }, 'q: quit tab: switch panel'));
15
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Core API for the TUI — wraps Temporal client queries to the Maestro and conductor workflows.
3
+ * Pure TypeScript, no Ink/React dependency. Used by hooks in the TUI layer.
4
+ */
5
+ import { Client } from '@temporalio/client';
6
+ import type { MaestroPlayerInfo, MaestroEvent, MaestroPendingCommand, HistoryEntry } from '../types';
7
+ export interface TuiApi {
8
+ /** Query current player snapshot from Maestro. */
9
+ getPlayers(): Promise<MaestroPlayerInfo[]>;
10
+ /** Query event log from Maestro. */
11
+ getEvents(limit?: number): Promise<MaestroEvent[]>;
12
+ /** Query pending commands from Maestro. */
13
+ getPendingCommands(): Promise<MaestroPendingCommand[]>;
14
+ /** Send a command to the conductor via Maestro's update handler. */
15
+ sendCommand(text: string, source: string): Promise<string>;
16
+ /** Query conductor command/report history. */
17
+ getConductorHistory(): Promise<HistoryEntry[]>;
18
+ /** Check if Maestro workflow is running. */
19
+ isConnected(): Promise<boolean>;
20
+ /** Ensemble name. */
21
+ ensemble: string;
22
+ }
23
+ /**
24
+ * Create a TUI API instance bound to a Temporal client and ensemble.
25
+ */
26
+ export declare function createTuiApi(client: Client, ensemble: string): TuiApi;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTuiApi = createTuiApi;
4
+ const config_1 = require("../config");
5
+ /**
6
+ * Create a TUI API instance bound to a Temporal client and ensemble.
7
+ */
8
+ function createTuiApi(client, ensemble) {
9
+ const maestroWfId = (0, config_1.maestroWorkflowId)(ensemble);
10
+ const conductorWfId = (0, config_1.conductorWorkflowId)(ensemble);
11
+ return {
12
+ ensemble,
13
+ async getPlayers() {
14
+ try {
15
+ const handle = client.workflow.getHandle(maestroWfId);
16
+ return await handle.query('maestroPlayers');
17
+ }
18
+ catch {
19
+ return [];
20
+ }
21
+ },
22
+ async getEvents(limit) {
23
+ try {
24
+ const handle = client.workflow.getHandle(maestroWfId);
25
+ const events = await handle.query('maestroEvents');
26
+ return limit ? events.slice(-limit) : events;
27
+ }
28
+ catch {
29
+ return [];
30
+ }
31
+ },
32
+ async getPendingCommands() {
33
+ try {
34
+ const handle = client.workflow.getHandle(maestroWfId);
35
+ return await handle.query('maestroPendingCommands');
36
+ }
37
+ catch {
38
+ return [];
39
+ }
40
+ },
41
+ async sendCommand(text, source) {
42
+ const handle = client.workflow.getHandle(maestroWfId);
43
+ return await handle.executeUpdate('maestroSendCommand', {
44
+ args: [{ text, source }],
45
+ });
46
+ },
47
+ async getConductorHistory() {
48
+ try {
49
+ const handle = client.workflow.getHandle(conductorWfId);
50
+ return await handle.query('history');
51
+ }
52
+ catch {
53
+ return [];
54
+ }
55
+ },
56
+ async isConnected() {
57
+ try {
58
+ const handle = client.workflow.getHandle(maestroWfId);
59
+ const desc = await handle.describe();
60
+ return desc.status.name === 'RUNNING';
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ },
66
+ };
67
+ }
@@ -0,0 +1,3 @@
1
+ import type { TuiApi } from '../core-api';
2
+ import type { TuiAction } from '../store';
3
+ export declare function useEnsembleDiscovery(api: TuiApi, taskQueue: string, dispatch: React.Dispatch<TuiAction>, enabled: boolean): void;