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,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatDetachedDeliveryError = formatDetachedDeliveryError;
4
+ exports.registerCueTool = registerCueTool;
5
+ exports.formatUnknownPlayerError = formatUnknownPlayerError;
6
+ exports.findClosestPlayers = findClosestPlayers;
7
+ exports.levenshtein = levenshtein;
8
+ const zod_1 = require("zod");
9
+ const resolve_1 = require("./resolve");
10
+ const resolve_2 = require("../activities/resolve");
11
+ const signals_1 = require("../workflows/signals");
12
+ const query_timeout_1 = require("../utils/query-timeout");
13
+ const helpers_1 = require("./helpers");
14
+ const validation_1 = require("../utils/validation");
15
+ /**
16
+ * Max Levenshtein distance for a fuzzy-match candidate to surface in the
17
+ * unknown-player suggestion. Three insertions/deletions/substitutions covers
18
+ * common typos (transposed chars, dropped chars, off-by-one) without
19
+ * surfacing wildly unrelated names. #560 acceptance criterion 3.
20
+ */
21
+ const FUZZY_MATCH_MAX_DISTANCE = 3;
22
+ /** Cap on suggestions shown in the error to keep the message readable. */
23
+ const FUZZY_MATCH_MAX_SUGGESTIONS = 3;
24
+ /**
25
+ * Phases where the target session has no live adapter — the workflow inbox
26
+ * still queues the signal and auto-redelivers on re-attach, but the
27
+ * operator's "Message sent to X" success line is misleading because no
28
+ * human-readable surface processes the message *now*. #562 surfaces the
29
+ * gap.
30
+ *
31
+ * `draining` is NOT included — it's a brief mid-shutdown state and the
32
+ * adapter is still consuming pending messages; flagging it as undeliverable
33
+ * would false-positive during normal teardown.
34
+ */
35
+ const UNDELIVERABLE_PHASES = new Set(['detached', 'gone']);
36
+ /**
37
+ * Cue pre-flight timeout. Half of {@link DEFAULT_QUERY_TIMEOUT_MS} —
38
+ * `cue` is operator-interactive, so a slow target shouldn't make the
39
+ * user wait the full 2s default before falling through to the best-
40
+ * effort path. 1s strikes the balance between catching the common
41
+ * detached-player case and not wedging the operator.
42
+ */
43
+ const CUE_PHASE_PREFLIGHT_TIMEOUT_MS = 1000;
44
+ /**
45
+ * Build the operator-facing error message when the cue target is in an
46
+ * undeliverable phase. Lists three actionable next steps per the issue
47
+ * body's AC #3.
48
+ *
49
+ * Exported for unit testing.
50
+ */
51
+ function formatDetachedDeliveryError(playerId, phase) {
52
+ return (`Player "${playerId}" is currently '${phase}' — no live adapter to receive. ` +
53
+ `Message NOT delivered. Options: ` +
54
+ `(1) use 'recall' to view their message history, ` +
55
+ `(2) 'restart' to re-attach the session and retry the cue, ` +
56
+ `(3) the workflow inbox queues the signal and auto-delivers on re-attach.`);
57
+ }
58
+ function registerCueTool(server, client, config, getPlayerId, handle) {
59
+ (0, helpers_1.defineTool)(server, 'cue', 'Send a message to another Claude Code session by player name. Delivered instantly via Temporal signal. For content larger than ~100 KB, use `coat_check_put` to stash the body and pass the returned ticket via `attachmentTicket` — the cue body itself should carry a short summary the recipient can act on without fetching.', {
60
+ playerId: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).describe('The player name of the target session'),
61
+ message: zod_1.z.string().max(validation_1.MESSAGE_MAX).describe('The message to send'),
62
+ attachmentTicket: zod_1.z.string().regex(validation_1.COAT_CHECK_TICKET_REGEX).max(validation_1.COAT_CHECK_TICKET_MAX).optional().describe('Optional coat-check ticket (#318). Reference content stashed via `coat_check_put`; the receiver sees the ticket on their `recall` message and can pull the body via `coat_check_get`. Backward-compatible — omit for normal cues.'),
63
+ }, async (args) => {
64
+ const { playerId, message, attachmentTicket } = args;
65
+ const nameError = (0, validation_1.validatePlayerName)(playerId);
66
+ if (nameError)
67
+ return (0, helpers_1.fail)(nameError);
68
+ try {
69
+ const resolved = await (0, resolve_1.resolveSession)(client, config.ensemble, playerId);
70
+ if (!resolved) {
71
+ // #560: replace the generic "no active session found" with an
72
+ // actionable error — active-player list + fuzzy-match suggestion
73
+ // + Agent-tool surface hint. We pay the extra `scanEnsembleSessions`
74
+ // round-trip ONLY on the error path, so the success path is
75
+ // unchanged.
76
+ const sessions = await (0, resolve_2.scanEnsembleSessions)(client, config.ensemble);
77
+ const activePlayers = sessions.map((s) => s.playerId).sort();
78
+ return (0, helpers_1.fail)(formatUnknownPlayerError(playerId, activePlayers));
79
+ }
80
+ // #562: phase pre-flight. Resolves the gap where `cue` to a
81
+ // detached/gone player returns "Message sent" — wire-truthful (the
82
+ // signal IS delivered to the workflow inbox), but operator-
83
+ // misleading because no live adapter surfaces the message.
84
+ let phase;
85
+ try {
86
+ const info = await (0, query_timeout_1.queryHandleWithTimeout)(resolved, signals_1.attachmentInfoQuery, { timeoutMs: CUE_PHASE_PREFLIGHT_TIMEOUT_MS });
87
+ phase = info.phase;
88
+ }
89
+ catch (err) {
90
+ // Query timed out or threw — workflow may be wedged. Don't
91
+ // penalize the operator: fall through to best-effort submit.
92
+ // Auto-redelivery on re-attach still applies. Stderr log keeps
93
+ // the observability trail without surfacing noise to the user.
94
+ console.error(`[agent-tempo:cue] phase pre-flight failed for "${playerId}" — proceeding best-effort:`, err instanceof Error ? err.message : err);
95
+ }
96
+ if (phase && UNDELIVERABLE_PHASES.has(phase)) {
97
+ return (0, helpers_1.fail)(formatDetachedDeliveryError(playerId, phase));
98
+ }
99
+ const entry = {
100
+ type: 'cue',
101
+ targetPlayerId: playerId,
102
+ message,
103
+ ...(attachmentTicket !== undefined ? { attachmentTicket } : {}),
104
+ };
105
+ const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
106
+ return (0, helpers_1.ok)(`Message sent to ${playerId}. (outbox: ${entryId})`);
107
+ }
108
+ catch (err) {
109
+ return (0, helpers_1.fail)(`Failed to send message to ${playerId}: ${(0, helpers_1.formatError)(err)}`);
110
+ }
111
+ });
112
+ }
113
+ /**
114
+ * Format the cue tool's "unknown player" error with actionable suggestions.
115
+ * Exported for direct unit testing — the production path passes the active
116
+ * player list from `scanEnsembleSessions`.
117
+ *
118
+ * The message disambiguates the two common causes per the issue body (#560):
119
+ * 1. Typo / destroyed player → fuzzy-match suggestion (Levenshtein ≤ 3),
120
+ * active-player listing, hint about `recall` for destroyed targets.
121
+ * 2. Agent-tool sub-agent confusion → explicit note that Claude Code
122
+ * `subagent_type:` agents run in the spawner's process and are NOT
123
+ * addressable via `cue`; `recruit` is the cross-process surface.
124
+ *
125
+ * Returns a multi-line string. Caller wraps in {@link fail}.
126
+ */
127
+ function formatUnknownPlayerError(target, activePlayers) {
128
+ const lines = [
129
+ `Player "${target}" is not registered with this tempo ensemble.`,
130
+ ];
131
+ const closest = findClosestPlayers(target, activePlayers);
132
+ if (closest.length > 0) {
133
+ lines.push('');
134
+ lines.push(`Did you mean: ${closest.map((p) => `"${p}"`).join(', ')}?`);
135
+ }
136
+ lines.push('');
137
+ if (activePlayers.length > 0) {
138
+ lines.push(`Active players: ${activePlayers.join(', ')}`);
139
+ }
140
+ else {
141
+ lines.push('No active players in this ensemble. Use `recruit` to start one.');
142
+ }
143
+ lines.push('');
144
+ lines.push("Note: Claude Code Agent-tool sub-agents (e.g. spawned via " +
145
+ "`subagent_type: tempo-*`) are NOT tempo players — they run in the " +
146
+ "spawner's process and aren't addressable via `cue`. Use `recruit` " +
147
+ "for a cross-process player, or `ensemble` to list current players.");
148
+ return lines.join('\n');
149
+ }
150
+ /**
151
+ * Find the closest matching player names by Levenshtein distance.
152
+ * Returns the top-N nearest within {@link FUZZY_MATCH_MAX_DISTANCE},
153
+ * sorted by ascending distance then alphabetically. Empty array if no
154
+ * candidate is close enough.
155
+ *
156
+ * Exported for unit testing.
157
+ */
158
+ function findClosestPlayers(target, candidates) {
159
+ if (!target || candidates.length === 0)
160
+ return [];
161
+ const scored = candidates
162
+ .map((c) => ({ name: c, distance: levenshtein(target, c) }))
163
+ .filter((entry) => entry.distance <= FUZZY_MATCH_MAX_DISTANCE)
164
+ .sort((a, b) => a.distance - b.distance || a.name.localeCompare(b.name));
165
+ return scored.slice(0, FUZZY_MATCH_MAX_SUGGESTIONS).map((e) => e.name);
166
+ }
167
+ /**
168
+ * Plain Levenshtein edit distance — single-row DP, O(|a| · |b|) time,
169
+ * O(min) space. No library dependency.
170
+ *
171
+ * Exported for unit testing.
172
+ */
173
+ function levenshtein(a, b) {
174
+ if (a === b)
175
+ return 0;
176
+ if (a.length === 0)
177
+ return b.length;
178
+ if (b.length === 0)
179
+ return a.length;
180
+ // Ensure b is the shorter string to keep the row small.
181
+ if (a.length < b.length) {
182
+ const tmp = a;
183
+ a = b;
184
+ b = tmp;
185
+ }
186
+ let prev = new Array(b.length + 1);
187
+ let curr = new Array(b.length + 1);
188
+ for (let j = 0; j <= b.length; j++)
189
+ prev[j] = j;
190
+ for (let i = 1; i <= a.length; i++) {
191
+ curr[0] = i;
192
+ for (let j = 1; j <= b.length; j++) {
193
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
194
+ curr[j] = Math.min(curr[j - 1] + 1, // insertion
195
+ prev[j] + 1, // deletion
196
+ prev[j - 1] + cost);
197
+ }
198
+ [prev, curr] = [curr, prev];
199
+ }
200
+ return prev[b.length];
201
+ }
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { Client, WorkflowHandle } from '@temporalio/client';
3
+ import { Config } from '../config';
4
+ export declare function registerDestroyTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string, handle: WorkflowHandle): void;
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerDestroyTool = registerDestroyTool;
4
+ /**
5
+ * `destroy` — terminal end of either a single session or the whole ensemble.
6
+ *
7
+ * **Single-player mode (`playerId` present)**: enqueues a `DestroyOutboxEntry`
8
+ * on the caller's workflow outbox. The session workflow's dispatch loop runs
9
+ * the `deliverDestroy` activity on the target, which calls `destroyUpdate` +
10
+ * (optionally) posts a system message on the ensemble conductor via
11
+ * `receiveMessageSignal`.
12
+ *
13
+ * **Ensemble mode (`playerId` omitted, #287)**: walks every peer session via
14
+ * `destroyUpdate` directly (in parallel), then terminates the scheduler +
15
+ * maestro, then destroys the conductor last. Direct `destroyUpdate` calls
16
+ * (not outbox entries) because ensemble teardown is a batch operation with
17
+ * a fixed ordering invariant (conductor sees peer teardown), not
18
+ * cross-workflow traffic that needs the caller's dispatch loop. The caller's
19
+ * own session is skipped — tools can't destroy themselves safely.
20
+ *
21
+ * For graceful shutdown without destroying workflows, use `shutdown` instead.
22
+ */
23
+ const zod_1 = require("zod");
24
+ const config_1 = require("../config");
25
+ const signals_1 = require("../workflows/signals");
26
+ const resolve_1 = require("../activities/resolve");
27
+ const helpers_1 = require("./helpers");
28
+ const validation_1 = require("../utils/validation");
29
+ const log = (...args) => console.error('[agent-tempo:destroy]', ...args);
30
+ function registerDestroyTool(server, client, config, getPlayerId, handle) {
31
+ (0, helpers_1.defineTool)(server, 'destroy', 'Terminally destroy a session workflow (when `playerId` is given) or the entire ensemble (when omitted): every peer session, the scheduler, the maestro, and the conductor. COMPLETEs workflows and cannot be undone. For graceful reap use `shutdown`; for a clean revive use `restart`.', {
32
+ // #306: `.min(1)` rejects `{playerId: ""}` at the SDK boundary so a
33
+ // buggy MCP caller can't silently fall through to ensemble-wide
34
+ // destroy mode. The handler also guards programmatic callers that
35
+ // bypass Zod (see explicit `playerId === ''` rejection below).
36
+ playerId: zod_1.z.string().min(1).max(validation_1.PLAYER_NAME_MAX).optional().describe('Target player name. Omit to destroy the entire ensemble.'),
37
+ reason: zod_1.z.string().max(500).optional().describe('Optional reason recorded in the workflow\'s audit event'),
38
+ }, async (args) => {
39
+ const { playerId, reason } = args;
40
+ const callerId = getPlayerId();
41
+ // #306: defense-in-depth for callers that bypass Zod (test harnesses,
42
+ // direct handler invocation). Zod's `.min(1)` already covers normal
43
+ // MCP traffic; this guard ensures empty-string never falls through to
44
+ // ensemble-wide destroy mode regardless of how the handler is reached.
45
+ if (playerId === '') {
46
+ return (0, helpers_1.fail)('`playerId` cannot be an empty string. Omit it to destroy the entire ensemble.');
47
+ }
48
+ // ── Single-player mode (existing behaviour) ─────────────────────────
49
+ if (playerId !== undefined) {
50
+ const nameError = (0, validation_1.validatePlayerName)(playerId);
51
+ if (nameError)
52
+ return (0, helpers_1.fail)(nameError);
53
+ if (playerId === callerId) {
54
+ return (0, helpers_1.fail)('Cannot destroy your own session.');
55
+ }
56
+ try {
57
+ const entry = {
58
+ type: 'destroy',
59
+ targetPlayerId: playerId,
60
+ ...(reason !== undefined ? { reason } : {}),
61
+ notifyConductor: true,
62
+ };
63
+ const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
64
+ return (0, helpers_1.ok)(`Destroy queued for **${playerId}**${reason ? ` (reason: ${reason})` : ''}. (outbox: ${entryId})`);
65
+ }
66
+ catch (err) {
67
+ return (0, helpers_1.fail)(`Failed to destroy: ${(0, helpers_1.formatError)(err)}`);
68
+ }
69
+ }
70
+ // ── Ensemble-scope mode (#287) ──────────────────────────────────────
71
+ // Order: peer sessions (parallel) → scheduler + maestro (parallel) →
72
+ // conductor last. The conductor-last step is the invariant the
73
+ // architect's spec relies on so the conductor sees every peer
74
+ // teardown before its own destroy.
75
+ try {
76
+ const destroyReason = reason ?? `ensemble destroy via ${callerId}`;
77
+ const sessions = await (0, resolve_1.scanEnsembleSessions)(client, config.ensemble);
78
+ const conductorWfId = (0, config_1.conductorWorkflowId)(config.ensemble);
79
+ const peers = [];
80
+ let conductorPresent = false;
81
+ for (const s of sessions) {
82
+ if (s.workflowId === conductorWfId) {
83
+ conductorPresent = true;
84
+ }
85
+ else {
86
+ peers.push(s);
87
+ }
88
+ }
89
+ const details = [];
90
+ let destroyed = 0;
91
+ let terminated = 0;
92
+ let failed = 0;
93
+ // Phase 1: destroy every peer in parallel (conductor excluded). Skip
94
+ // the caller's own session — self-destroy is a no-op guard.
95
+ const peerResults = await Promise.allSettled(peers.map(async (s) => {
96
+ if (s.playerId === callerId)
97
+ return { session: s, outcome: 'skipped-self' };
98
+ try {
99
+ await client.workflow.getHandle(s.workflowId).executeUpdate(signals_1.destroyUpdate, {
100
+ args: [{ reason: destroyReason, terminatedBy: callerId }],
101
+ });
102
+ return { session: s, outcome: 'destroyed' };
103
+ }
104
+ catch (err) {
105
+ return { session: s, outcome: 'failed', error: (0, helpers_1.formatError)(err) };
106
+ }
107
+ }));
108
+ for (const r of peerResults) {
109
+ if (r.status !== 'fulfilled')
110
+ continue;
111
+ const v = r.value;
112
+ if (v.outcome === 'destroyed') {
113
+ details.push({ target: v.session.playerId, outcome: 'destroyed' });
114
+ destroyed++;
115
+ }
116
+ else if (v.outcome === 'failed') {
117
+ details.push({ target: v.session.playerId, outcome: 'failed', error: v.error });
118
+ failed++;
119
+ }
120
+ // #299: `'skipped-self'` is an internal control-flow tag for the
121
+ // caller's own session — intentionally NOT surfaced in `details`
122
+ // because `EnsembleDestroyDetail` is consumed publicly via
123
+ // `EnsembleDestroySummary` (TempoClient.destroy), which has no
124
+ // caller-self concept. The skip is a bookkeeping no-op here.
125
+ }
126
+ // Phase 2: scheduler + maestro terminate in parallel (non-session
127
+ // workflows — no destroy handler). `terminate` rejects when the
128
+ // workflow isn't running; treat as "not present" instead of failure.
129
+ const [schedRes, maestroRes] = await Promise.allSettled([
130
+ client.workflow.getHandle((0, config_1.schedulerWorkflowId)(config.ensemble)).terminate(destroyReason),
131
+ client.workflow.getHandle((0, config_1.maestroWorkflowId)(config.ensemble)).terminate(destroyReason),
132
+ ]);
133
+ if (schedRes.status === 'fulfilled') {
134
+ details.push({ target: 'scheduler', outcome: 'terminated' });
135
+ terminated++;
136
+ }
137
+ if (maestroRes.status === 'fulfilled') {
138
+ details.push({ target: 'maestro', outcome: 'terminated' });
139
+ terminated++;
140
+ }
141
+ // Phase 3: conductor last, so it observes peer teardown. Skipped if
142
+ // the caller IS the conductor (same self-destroy guard). #299: the
143
+ // skip is a control-flow no-op — no `details` entry, mirroring the
144
+ // peer-self skip. `EnsembleDestroyDetail.outcome` no longer carries
145
+ // a self-skip member.
146
+ if (callerId === 'conductor') {
147
+ // self-skip; no recording
148
+ }
149
+ else if (conductorPresent) {
150
+ try {
151
+ await client.workflow.getHandle(conductorWfId).executeUpdate(signals_1.destroyUpdate, {
152
+ args: [{ reason: destroyReason, terminatedBy: callerId }],
153
+ });
154
+ details.push({ target: 'conductor', outcome: 'destroyed' });
155
+ destroyed++;
156
+ }
157
+ catch (err) {
158
+ details.push({ target: 'conductor', outcome: 'failed', error: (0, helpers_1.formatError)(err) });
159
+ failed++;
160
+ }
161
+ }
162
+ const summaryLine = `${destroyed} destroyed, ${terminated} terminated, ${failed} failed`;
163
+ const headline = failed > 0
164
+ ? `Ensemble **${config.ensemble}** partially destroyed.`
165
+ : `Ensemble **${config.ensemble}** destroyed.`;
166
+ const lines = [headline, summaryLine];
167
+ const failures = details.filter((d) => d.outcome === 'failed');
168
+ if (failures.length > 0) {
169
+ lines.push(`Errors:\n${failures.map((d) => ` - ${d.target}: ${d.error}`).join('\n')}`);
170
+ // #306 follow-up: surface the indeterminate-state hint from my own
171
+ // PR-#306 holistic review (regression risk #3). `Promise.allSettled`
172
+ // returned `failed` outcomes for these peers — the workflows may
173
+ // be in any state from "still running" to "destroyed but RPC
174
+ // timed out". Re-running `destroy` is safe (idempotent on the
175
+ // workflow side: `destroyUpdate` on a `gone` workflow is a no-op
176
+ // via the `isDestroyedQuery` guard) and the cleanest recovery.
177
+ const noun = failed === 1 ? 'peer' : 'peers';
178
+ lines.push(`⚠ ${failed} ${noun} in indeterminate state — ` +
179
+ `run \`/destroy ${config.ensemble}\` again to clean up.`);
180
+ }
181
+ log(`Ensemble destroy by ${callerId}: ${summaryLine}`);
182
+ return (0, helpers_1.ok)(lines.join('\n'));
183
+ }
184
+ catch (err) {
185
+ return (0, helpers_1.fail)(`Failed to destroy ensemble: ${(0, helpers_1.formatError)(err)}`);
186
+ }
187
+ });
188
+ }
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { Client, WorkflowHandle } from '@temporalio/client';
3
+ import { Config } from '../config';
4
+ export declare function registerDetachTool(server: McpServer, _client: Client, _config: Config, getPlayerId: () => string, handle: WorkflowHandle): void;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerDetachTool = registerDetachTool;
4
+ /**
5
+ * `detach` — graceful reap of a session's adapter without destroying the workflow.
6
+ *
7
+ * QA B1: enqueues a `DetachOutboxEntry` on the caller's workflow outbox rather
8
+ * than firing `requestDetachSignal` directly from tool code. The session
9
+ * workflow's dispatch loop runs the `deliverDetach` activity on the target,
10
+ * which signals `requestDetachSignal` with the supplied `reason` + `deadlineMs`.
11
+ *
12
+ * Design reference: §8.1 (three verbs), §2.4 (phase transitions).
13
+ */
14
+ const zod_1 = require("zod");
15
+ const signals_1 = require("../workflows/signals");
16
+ const helpers_1 = require("./helpers");
17
+ const validation_1 = require("../utils/validation");
18
+ const DEFAULT_DETACH_DEADLINE_MS = 5_000;
19
+ function registerDetachTool(server, _client, _config, getPlayerId, handle) {
20
+ (0, helpers_1.defineTool)(server, 'detach', 'Gracefully detach a session\'s adapter. The session enters `draining` phase and reaps to `detached` after the deadline or when the adapter exits. The workflow survives — use `restart` to attach a new adapter, or `destroy` to terminate permanently.', {
21
+ playerId: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).describe('The player name to detach'),
22
+ deadlineMs: zod_1.z.number().min(0).max(validation_1.MAX_DETACH_DEADLINE_MS).optional().describe(`Max drain time in ms before force-detach (default ${DEFAULT_DETACH_DEADLINE_MS}, max ${validation_1.MAX_DETACH_DEADLINE_MS})`),
23
+ }, async (args) => {
24
+ const { playerId, deadlineMs = DEFAULT_DETACH_DEADLINE_MS } = args;
25
+ const nameError = (0, validation_1.validatePlayerName)(playerId);
26
+ if (nameError)
27
+ return (0, helpers_1.fail)(nameError);
28
+ if (playerId === getPlayerId()) {
29
+ return (0, helpers_1.fail)('Cannot detach your own session.');
30
+ }
31
+ try {
32
+ const entry = {
33
+ type: 'detach',
34
+ targetPlayerId: playerId,
35
+ reason: 'user-stop',
36
+ deadlineMs,
37
+ };
38
+ const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
39
+ return (0, helpers_1.ok)(`Detach queued for **${playerId}** (deadline: ${deadlineMs}ms; outbox: ${entryId}).`);
40
+ }
41
+ catch (err) {
42
+ return (0, helpers_1.fail)(`Failed to detach: ${(0, helpers_1.formatError)(err)}`);
43
+ }
44
+ });
45
+ }
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { Client, WorkflowHandle } from '@temporalio/client';
3
+ import type { Config } from '../config';
4
+ export declare function registerEncoreTool(_server: McpServer, _client: Client, _config: Config, _getPlayerId: () => string, _handle: WorkflowHandle): void;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerEncoreTool = registerEncoreTool;
4
+ /**
5
+ * `encore` — deprecation shim (PR-D).
6
+ *
7
+ * The `encore` verb is retired in v0.25 per design §8.1 "three verbs" —
8
+ * replaced by `restart`, which runs the same §8.2 algorithm (forceDetach +
9
+ * claimAttachment + context replay + enqueueSpawn) but is not limited to
10
+ * `stale`-only targets.
11
+ *
12
+ * The MCP tool remains registered so existing clients discover it via
13
+ * ListTools but returns an `isError` pointing to the replacement. The
14
+ * internal `case 'encore':` outbox dispatch and `performEncore` activity
15
+ * are still live; `restart` doesn't use them, but they stay so scheduler /
16
+ * test fixtures that enqueue encore entries keep working until v0.25.1.
17
+ */
18
+ const zod_1 = require("zod");
19
+ const helpers_1 = require("./helpers");
20
+ function registerEncoreTool(_server, _client, _config, _getPlayerId, _handle) {
21
+ (0, helpers_1.defineTool)(_server, 'encore', '[deprecated in v0.25] The `encore` verb is retired — use `restart` instead, which runs the same forceDetach + claim + context-replay + enqueueSpawn algorithm but is not limited to stale targets.', {
22
+ playerId: zod_1.z.string().describe('The player name to revive'),
23
+ host: zod_1.z.string().optional().describe('Target hostname (legacy)'),
24
+ contextMessages: zod_1.z.number().optional().describe('Number of recent messages (legacy)'),
25
+ }, async () => {
26
+ return (0, helpers_1.fail)('The `encore` tool is deprecated. Use `restart` instead.\n' +
27
+ ' • `restart` runs the same algorithm (forceDetach → claim → context replay → spawn)\n' +
28
+ ' • Not limited to `stale`-only targets — works on any non-`gone` phase\n' +
29
+ ' • Pair with `host=<h>` or use `migrate` for cross-host revive');
30
+ });
31
+ }
@@ -0,0 +1,32 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { Client } from '@temporalio/client';
3
+ import { Config } from '../config';
4
+ import { type EnsembleSessionInfo } from '../activities/resolve';
5
+ /**
6
+ * Default dormancy threshold (1 hour). Per #563: a `detached` player whose
7
+ * last activity is older than this is considered dormant. `phase === 'gone'`
8
+ * is dormant regardless of timestamp.
9
+ */
10
+ export declare const DORMANT_THRESHOLD_MS: number;
11
+ /** Filter mode for the `dormant` arg on the `ensemble` MCP tool. */
12
+ export type DormantFilter = 'show' | 'hide' | 'show-only';
13
+ /**
14
+ * Classify a session as `'active'` or `'dormant'` per the #563 rules.
15
+ *
16
+ * - `phase === 'gone'` → always dormant.
17
+ * - `phase === 'detached'` AND `lastActivityAt` older than `thresholdMs`
18
+ * → dormant.
19
+ * - `phase === 'detached'` AND `lastActivityAt` missing → dormant. (Pre-W2
20
+ * sessions don't carry the timestamp; operator intent is to declutter
21
+ * the active list, so we err toward grouping these with the cruft. The
22
+ * default `--dormant=show` still shows them, just in their own section.)
23
+ * - Otherwise → active. Includes `awaiting` (live attachment), `processing`,
24
+ * `attached`, `booting`, `draining`, and the undefined-phase case (older
25
+ * workflows that predate the attachment lifecycle).
26
+ *
27
+ * Pure function — injectable `now` keeps it deterministic under test.
28
+ *
29
+ * Exported for unit testing.
30
+ */
31
+ export declare function classifyDormancy(session: Pick<EnsembleSessionInfo, 'phase' | 'lastActivityAt'>, now: number, thresholdMs?: number): 'active' | 'dormant';
32
+ export declare function registerEnsembleTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string, ownWorkflowId: string): void;