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,216 @@
1
+ "use strict";
2
+ /**
3
+ * Thin HTTP/SSE wrapper around `opencode serve`.
4
+ *
5
+ * Hand-rolled over native `fetch` rather than `@opencode-ai/sdk` per design
6
+ * §8.3 LoC tightening proposal #2 — the SDK is auto-generated from
7
+ * OpenAPI 3.1, so it pulls in OpenAPI runtime + per-endpoint typed clients
8
+ * for ~50 endpoints. Our hot path uses ~5 endpoints + the `/event` SSE
9
+ * stream; the SDK weight isn't worth it. The architectural shape of the
10
+ * adapter is identical either way.
11
+ *
12
+ * The SDK is still listed as an `optionalDependency` and `require.resolve`
13
+ * gates the recruit pre-flight (ADR 0015 §85) — operators install it as
14
+ * the signal that opencode integration is intended on this host. Adapter
15
+ * runtime, however, never imports it.
16
+ *
17
+ * Contract surface (5 methods + 1 generator):
18
+ * - `waitForHealth(timeoutMs)`
19
+ * - `getHealth()`
20
+ * - `createSession()`
21
+ * - `promptAsync(sessionId, body)`
22
+ * - `abortSession(sessionId)`
23
+ * - `deleteSession(sessionId)`
24
+ * - `subscribeEvents(abortSignal)` — async generator yielding parsed events
25
+ *
26
+ * Design reference: docs/design/449-opencode-adapter.md §5.3, §8.1.
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.OpenCodeServerBridge = void 0;
30
+ /** Default health-probe poll interval. Tight loop — opencode boots in <1s. */
31
+ const HEALTH_POLL_INTERVAL_MS = 200;
32
+ class OpenCodeServerBridge {
33
+ baseUrl;
34
+ log;
35
+ fetchImpl;
36
+ constructor(opts) {
37
+ this.baseUrl = opts.baseUrl.replace(/\/$/, '');
38
+ this.log = opts.log ?? ((..._args) => { });
39
+ this.fetchImpl = opts.fetchImpl ?? fetch;
40
+ }
41
+ /**
42
+ * Poll `GET /global/health` until 200 or `timeoutMs` elapses. Throws on
43
+ * timeout — caller is the adapter `run()` and a missing health probe
44
+ * means opencode didn't boot.
45
+ */
46
+ async waitForHealth(timeoutMs) {
47
+ const deadline = Date.now() + timeoutMs;
48
+ let lastErr = null;
49
+ while (Date.now() < deadline) {
50
+ try {
51
+ const res = await this.fetchImpl(`${this.baseUrl}/global/health`);
52
+ if (res.ok)
53
+ return;
54
+ lastErr = new Error(`/global/health returned ${res.status}`);
55
+ }
56
+ catch (err) {
57
+ // Connection refused while opencode is still booting — keep polling.
58
+ lastErr = err;
59
+ }
60
+ await sleep(HEALTH_POLL_INTERVAL_MS);
61
+ }
62
+ throw new Error(`opencode serve did not become healthy within ${timeoutMs}ms${lastErr ? ` (last error: ${lastErr?.message ?? lastErr})` : ''}`);
63
+ }
64
+ /** `GET /global/health` — version + healthy flag. */
65
+ async getHealth() {
66
+ const res = await this.fetchImpl(`${this.baseUrl}/global/health`);
67
+ if (!res.ok) {
68
+ throw new Error(`/global/health returned ${res.status} ${res.statusText}`);
69
+ }
70
+ return (await res.json());
71
+ }
72
+ /** `POST /session` — create a new session; returns the session id + meta. */
73
+ async createSession() {
74
+ const res = await this.fetchImpl(`${this.baseUrl}/session`, {
75
+ method: 'POST',
76
+ headers: { 'content-type': 'application/json' },
77
+ body: '{}',
78
+ });
79
+ if (!res.ok) {
80
+ const body = await res.text().catch(() => '');
81
+ throw new Error(`POST /session returned ${res.status} ${res.statusText}${body ? ': ' + body : ''}`);
82
+ }
83
+ return (await res.json());
84
+ }
85
+ /**
86
+ * `POST /session/:id/prompt_async` — send a turn; returns 204 immediately
87
+ * and the turn streams over `/event` SSE. Caller is responsible for
88
+ * subscribing to events first.
89
+ */
90
+ async promptAsync(sessionId, body) {
91
+ const res = await this.fetchImpl(`${this.baseUrl}/session/${encodeURIComponent(sessionId)}/prompt_async`, {
92
+ method: 'POST',
93
+ headers: { 'content-type': 'application/json' },
94
+ body: JSON.stringify(body),
95
+ });
96
+ if (!res.ok) {
97
+ const text = await res.text().catch(() => '');
98
+ throw new Error(`prompt_async returned ${res.status} ${res.statusText}${text ? ': ' + text : ''}`);
99
+ }
100
+ }
101
+ /**
102
+ * `POST /session/:id/abort` — graceful turn cancellation. The primary
103
+ * cancellation path on lease revocation; subprocess SIGTERM is the
104
+ * fallback only if this hangs.
105
+ *
106
+ * Best-effort — swallows non-2xx so the adapter's superseded path can
107
+ * still fall through to subprocess kill without surfacing an error.
108
+ */
109
+ async abortSession(sessionId, opts) {
110
+ try {
111
+ await this.fetchImpl(`${this.baseUrl}/session/${encodeURIComponent(sessionId)}/abort`, { method: 'POST', signal: opts?.signal });
112
+ }
113
+ catch (err) {
114
+ this.log('abortSession suppressed error:', err?.message ?? err);
115
+ }
116
+ }
117
+ /**
118
+ * `DELETE /session/:id` — free server-side session resources. Called on
119
+ * graceful detach. Best-effort — swallows non-2xx.
120
+ */
121
+ async deleteSession(sessionId) {
122
+ try {
123
+ await this.fetchImpl(`${this.baseUrl}/session/${encodeURIComponent(sessionId)}/`, { method: 'DELETE' });
124
+ }
125
+ catch (err) {
126
+ this.log('deleteSession suppressed error:', err?.message ?? err);
127
+ }
128
+ }
129
+ /**
130
+ * `GET /event` — SSE stream of session events. Returns an async
131
+ * generator that yields parsed `OpenCodeEvent` objects until the
132
+ * abort signal fires or the stream closes.
133
+ *
134
+ * The caller is responsible for filtering events by session id —
135
+ * `/event` is global per `opencode serve` instance, but the v1
136
+ * subprocess-per-player model means there's only ever one session
137
+ * per stream anyway. Phase 2 subprocess-shared optimization would
138
+ * make filtering meaningful.
139
+ */
140
+ async *subscribeEvents(signal) {
141
+ const res = await this.fetchImpl(`${this.baseUrl}/event`, {
142
+ headers: { accept: 'text/event-stream' },
143
+ signal,
144
+ });
145
+ if (!res.ok || !res.body) {
146
+ throw new Error(`/event returned ${res.status} ${res.statusText}`);
147
+ }
148
+ const reader = res.body.getReader();
149
+ const decoder = new TextDecoder('utf-8');
150
+ let buffer = '';
151
+ try {
152
+ while (true) {
153
+ const { value, done } = await reader.read();
154
+ if (done)
155
+ return;
156
+ buffer += decoder.decode(value, { stream: true });
157
+ // SSE: events are separated by blank lines (\n\n). One event may
158
+ // span multiple `data:` lines; concatenate and parse as JSON.
159
+ let sep = buffer.indexOf('\n\n');
160
+ while (sep !== -1) {
161
+ const block = buffer.slice(0, sep);
162
+ buffer = buffer.slice(sep + 2);
163
+ const event = parseSseBlock(block);
164
+ if (event)
165
+ yield event;
166
+ sep = buffer.indexOf('\n\n');
167
+ }
168
+ }
169
+ }
170
+ finally {
171
+ // Release the reader so the underlying connection can close.
172
+ try {
173
+ reader.releaseLock();
174
+ }
175
+ catch { /* already released */ }
176
+ }
177
+ }
178
+ }
179
+ exports.OpenCodeServerBridge = OpenCodeServerBridge;
180
+ /**
181
+ * Parse one SSE block (the text between two blank-line separators) into
182
+ * an `OpenCodeEvent`. Returns `null` on parse failure or empty `data`.
183
+ *
184
+ * Format per SSE spec:
185
+ * event: foo (optional — most OpenCode events use only `data:`)
186
+ * data: { ... }
187
+ * data: ... (continuation of data; concatenated with `\n`)
188
+ */
189
+ function parseSseBlock(block) {
190
+ const dataLines = [];
191
+ for (const line of block.split('\n')) {
192
+ if (line.startsWith('data:')) {
193
+ dataLines.push(line.slice(5).trimStart());
194
+ }
195
+ // event: / id: / retry: lines ignored — agent-tempo only consumes data.
196
+ }
197
+ if (dataLines.length === 0)
198
+ return null;
199
+ const payload = dataLines.join('\n');
200
+ if (!payload)
201
+ return null;
202
+ try {
203
+ const parsed = JSON.parse(payload);
204
+ if (parsed && typeof parsed === 'object' && typeof parsed.type === 'string') {
205
+ return parsed;
206
+ }
207
+ return null;
208
+ }
209
+ catch {
210
+ // Non-JSON event — opencode shouldn't emit these; ignore safely.
211
+ return null;
212
+ }
213
+ }
214
+ function sleep(ms) {
215
+ return new Promise((r) => setTimeout(r, ms));
216
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * SDK-class adapter base.
3
+ *
4
+ * Class hierarchy per design §4.1: `SdkAttachment extends BaseAttachment`. Concrete
5
+ * SDK adapters (copilot, future `headless-claude`) extend this.
6
+ *
7
+ * PR-C commit 3 fills in the shared SDK lifecycle on top of the V2 attachment
8
+ * machinery landed in commit 2's `BaseAttachment`:
9
+ *
10
+ * - **Processing-signal pairing.** `deliver()` wraps each SDK turn in
11
+ * `processingStart` (update) → `invokeSdk()` (concrete) → `processingEnd`
12
+ * (update) → `markDelivered` (signal). Updates are synchronous (§7.1) — a
13
+ * dropped `processingStart` is observable, not silent.
14
+ * - **Split-brain cancellation.** When the base-class phase watcher fires
15
+ * `onLeaseRevoked`, `SdkAttachment` calls the concrete `onSuperseded()`
16
+ * hook. The concrete adapter (Copilot, headless-claude, …) aborts the
17
+ * in-flight `sendAndWait` via its SDK-specific mechanism and exits.
18
+ * Residual ghost-reply window is documented in §9.3.
19
+ *
20
+ * **This file runs in the Node.js adapter process, NOT the Temporal workflow
21
+ * sandbox.** Node.js timers are appropriate here; workflow-bundle code lives
22
+ * elsewhere (in `src/workflows/`).
23
+ *
24
+ * Design reference: docs/design/session-lifecycle-rebuild-v2.md §§4.1, 4.4, 6.1,
25
+ * 6.2, 7.1, 9.3.
26
+ */
27
+ import type { WorkflowHandle } from '@temporalio/client';
28
+ import { BaseAttachment, type BaseAttachmentOptions } from '../base';
29
+ import type { Message, DetachReason } from '../../types';
30
+ /** Per-message result from `SdkAttachment.deliver()`. */
31
+ export interface SdkDeliverResult {
32
+ /** Whatever `invokeSdk()` returned — up to the concrete adapter to define. */
33
+ sdkResult: unknown;
34
+ /** Time spent inside `invokeSdk()` in milliseconds. */
35
+ elapsedMs: number;
36
+ }
37
+ /**
38
+ * Abstract base for SDK-class adapters.
39
+ *
40
+ * Owns processing-signal pairing and split-brain cancellation wiring. Concrete
41
+ * subclasses (`CopilotSdkAttachment`, future `HeadlessClaudeAttachment`) provide:
42
+ *
43
+ * - `invokeSdk(prompt, timeoutMs)` — the actual blocking SDK call.
44
+ * - `onSuperseded()` — abort the in-flight SDK call on lease revocation.
45
+ *
46
+ * Subclasses set up the V2 lifecycle by calling `startV2Lifecycle(workflowId)`
47
+ * on `BaseAttachment` (inherited from commit 2) to claim the attachment + start
48
+ * heartbeat + phase watcher. Then they drive a poll loop that calls
49
+ * `this.deliver(msg)` per message; `deliver()` handles the processing-signal
50
+ * pairing and the final `markDelivered` ack.
51
+ */
52
+ export declare abstract class SdkAttachment extends BaseAttachment {
53
+ /** Subclass hook — cancel the in-flight SDK invocation (AbortController / session.cancel / disconnect). */
54
+ protected abstract onSuperseded(): void;
55
+ /**
56
+ * Whether we are currently inside an `invokeSdk` call. Read by `onSuperseded`
57
+ * implementations to decide whether cancellation actually has an effect.
58
+ */
59
+ protected sdkInFlight: boolean;
60
+ constructor(options?: BaseAttachmentOptions);
61
+ /**
62
+ * Deliver one message through the SDK turn. Wire-protocol surface:
63
+ *
64
+ * 1. `processingStart` update — synchronous (§7.1). If the update rejects
65
+ * with `AttachmentMismatch` or `WorkflowGone`, we propagate the error
66
+ * without calling `invokeSdk` — lease revocation is already in flight
67
+ * via the phase watcher and the ghost-turn SHOULD be skipped.
68
+ * 2. `invokeSdk(prompt, timeoutMs)` — the concrete blocking call. Runs
69
+ * under `sdkInFlight = true` so `onSuperseded` can identify the target.
70
+ * 3. `processingEnd` update — synchronous, in a `finally` so any throw
71
+ * from `invokeSdk` still releases the in-flight marker on the workflow.
72
+ * Errors here are logged and swallowed: if the workflow is gone or the
73
+ * attachment was revoked, the processing set is meaningless.
74
+ * 4. `markDelivered` signal — fires only on successful `invokeSdk` return,
75
+ * so at-least-once delivery survives crashes mid-turn.
76
+ *
77
+ * @param pinned Pinned `WorkflowHandle` returned by `startV2Lifecycle()`.
78
+ * @param msg Representative message for the in-flight set — its id is
79
+ * used in `processingStart`/`processingEnd`.
80
+ * @param prompt Formatted prompt for the SDK (concrete subclass formats).
81
+ * @param timeoutMs SDK invocation timeout.
82
+ * @param invokeSdk Concrete SDK call. Receives formatted prompt + timeout.
83
+ * @param ackIds Message ids to mark delivered after the SDK turn completes.
84
+ * Defaults to `[msg.id]`. Copilot's bridge joins multiple
85
+ * pending messages into a single prompt and acks them all
86
+ * with one `markDelivered` signal — pass the full batch.
87
+ */
88
+ protected deliver(pinned: WorkflowHandle, msg: Message, prompt: string, timeoutMs: number, invokeSdk: (prompt: string, timeoutMs: number) => Promise<unknown>, ackIds?: string[]): Promise<SdkDeliverResult>;
89
+ /**
90
+ * Subclass-facing convenience: call this from `startV2Lifecycle` path to
91
+ * fire `adapterExited` on clean shutdown and tear down the V2 machinery.
92
+ * Forwards to `BaseAttachment.stopV2Lifecycle` with graceful=true.
93
+ */
94
+ protected detachGracefully(reason?: DetachReason): Promise<void>;
95
+ }
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SdkAttachment = void 0;
4
+ const base_1 = require("../base");
5
+ const signals_1 = require("../../workflows/signals");
6
+ const log = (...args) => console.error('[agent-tempo:sdk-adapter]', ...args);
7
+ /**
8
+ * Abstract base for SDK-class adapters.
9
+ *
10
+ * Owns processing-signal pairing and split-brain cancellation wiring. Concrete
11
+ * subclasses (`CopilotSdkAttachment`, future `HeadlessClaudeAttachment`) provide:
12
+ *
13
+ * - `invokeSdk(prompt, timeoutMs)` — the actual blocking SDK call.
14
+ * - `onSuperseded()` — abort the in-flight SDK call on lease revocation.
15
+ *
16
+ * Subclasses set up the V2 lifecycle by calling `startV2Lifecycle(workflowId)`
17
+ * on `BaseAttachment` (inherited from commit 2) to claim the attachment + start
18
+ * heartbeat + phase watcher. Then they drive a poll loop that calls
19
+ * `this.deliver(msg)` per message; `deliver()` handles the processing-signal
20
+ * pairing and the final `markDelivered` ack.
21
+ */
22
+ class SdkAttachment extends base_1.BaseAttachment {
23
+ /**
24
+ * Whether we are currently inside an `invokeSdk` call. Read by `onSuperseded`
25
+ * implementations to decide whether cancellation actually has an effect.
26
+ */
27
+ sdkInFlight = false;
28
+ constructor(options = {}) {
29
+ super(options);
30
+ // Wire the V2 lease-revoked signal (fired by BaseAttachment's phase watcher
31
+ // when `attachmentInfo.currentAttachment.attachmentId` diverges from our
32
+ // token) into the concrete subclass's cancel hook. BaseAttachment has
33
+ // already stopped the heartbeat + watcher at this point — our job is to
34
+ // abort the blocking SDK turn before it produces a ghost reply (§9.3).
35
+ this.onLeaseRevoked((reason) => {
36
+ log(`lease revoked (${reason}) — firing onSuperseded`);
37
+ try {
38
+ this.onSuperseded();
39
+ }
40
+ catch (err) {
41
+ log('onSuperseded threw:', err?.message ?? err);
42
+ }
43
+ });
44
+ }
45
+ /**
46
+ * Deliver one message through the SDK turn. Wire-protocol surface:
47
+ *
48
+ * 1. `processingStart` update — synchronous (§7.1). If the update rejects
49
+ * with `AttachmentMismatch` or `WorkflowGone`, we propagate the error
50
+ * without calling `invokeSdk` — lease revocation is already in flight
51
+ * via the phase watcher and the ghost-turn SHOULD be skipped.
52
+ * 2. `invokeSdk(prompt, timeoutMs)` — the concrete blocking call. Runs
53
+ * under `sdkInFlight = true` so `onSuperseded` can identify the target.
54
+ * 3. `processingEnd` update — synchronous, in a `finally` so any throw
55
+ * from `invokeSdk` still releases the in-flight marker on the workflow.
56
+ * Errors here are logged and swallowed: if the workflow is gone or the
57
+ * attachment was revoked, the processing set is meaningless.
58
+ * 4. `markDelivered` signal — fires only on successful `invokeSdk` return,
59
+ * so at-least-once delivery survives crashes mid-turn.
60
+ *
61
+ * @param pinned Pinned `WorkflowHandle` returned by `startV2Lifecycle()`.
62
+ * @param msg Representative message for the in-flight set — its id is
63
+ * used in `processingStart`/`processingEnd`.
64
+ * @param prompt Formatted prompt for the SDK (concrete subclass formats).
65
+ * @param timeoutMs SDK invocation timeout.
66
+ * @param invokeSdk Concrete SDK call. Receives formatted prompt + timeout.
67
+ * @param ackIds Message ids to mark delivered after the SDK turn completes.
68
+ * Defaults to `[msg.id]`. Copilot's bridge joins multiple
69
+ * pending messages into a single prompt and acks them all
70
+ * with one `markDelivered` signal — pass the full batch.
71
+ */
72
+ async deliver(pinned, msg, prompt, timeoutMs, invokeSdk, ackIds) {
73
+ if (!this.token) {
74
+ throw new Error('SdkAttachment.deliver called with no attachment token — did startV2Lifecycle run?');
75
+ }
76
+ // (1) Announce in-flight work. Synchronous per §7.1 — if the workflow has
77
+ // been destroyed or the lease revoked, the update throws and we bail
78
+ // before burning an SDK turn.
79
+ await pinned.executeUpdate(signals_1.processingStartUpdate, {
80
+ args: [{
81
+ messageId: msg.id,
82
+ expectedAttachmentId: this.token.attachmentId,
83
+ }],
84
+ });
85
+ const t0 = Date.now();
86
+ let sdkResult;
87
+ this.sdkInFlight = true;
88
+ try {
89
+ // (2) Concrete SDK call. Blocks until the LLM turn completes or the
90
+ // concrete adapter aborts via `onSuperseded`.
91
+ sdkResult = await invokeSdk(prompt, timeoutMs);
92
+ }
93
+ finally {
94
+ this.sdkInFlight = false;
95
+ // (3) Always release the in-flight marker, even on throw. Swallow errors:
96
+ // if the workflow is gone or the lease was revoked during the turn, the
97
+ // in-flight set is already dead-lettered on the workflow side.
98
+ try {
99
+ await pinned.executeUpdate(signals_1.processingEndUpdate, {
100
+ args: [{
101
+ messageId: msg.id,
102
+ expectedAttachmentId: this.token.attachmentId,
103
+ }],
104
+ });
105
+ }
106
+ catch (err) {
107
+ log(`processingEnd suppressed error: ${err?.message ?? err}`);
108
+ }
109
+ }
110
+ const elapsedMs = Date.now() - t0;
111
+ // (4) Ack delivery only after the SDK turn completed cleanly. If invokeSdk
112
+ // threw, we never reach here and messages stay pending for retry.
113
+ // C4 (PR-C dual-QA follow-up): use the typed signal constant so the
114
+ // ts-morph wire-protocol drift detector can see the reference — a string
115
+ // literal would be invisible to the static scan.
116
+ const toAck = ackIds ?? [msg.id];
117
+ try {
118
+ await pinned.signal(signals_1.markDeliveredSignal, toAck);
119
+ }
120
+ catch (err) {
121
+ log(`markDelivered suppressed error: ${err?.message ?? err}`);
122
+ }
123
+ return { sdkResult, elapsedMs };
124
+ }
125
+ /**
126
+ * Subclass-facing convenience: call this from `startV2Lifecycle` path to
127
+ * fire `adapterExited` on clean shutdown and tear down the V2 machinery.
128
+ * Forwards to `BaseAttachment.stopV2Lifecycle` with graceful=true.
129
+ */
130
+ async detachGracefully(reason = 'user-stop') {
131
+ await this.stopV2Lifecycle(reason, /* graceful */ true);
132
+ }
133
+ }
134
+ exports.SdkAttachment = SdkAttachment;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Shared SDK-class adapter system-prompt helpers (#536).
3
+ *
4
+ * Two SDK-class adapters in this repo currently mirror an *identical*
5
+ * "use your MCP tools to reply" framing onto the model — copilot
6
+ * (`src/adapters/copilot/adapter.ts:283-297`) and, post-#536,
7
+ * claude-code-headless (`src/adapters/claude-code-headless/adapter.ts`).
8
+ * Pre-#536 the framing only existed on copilot's side, hand-typed
9
+ * inline; this module factors it out so:
10
+ *
11
+ * - There is one canonical source for the prompt content (no copy
12
+ * drift when someone tweaks the wording in one place and forgets
13
+ * the other).
14
+ * - The MAESTRO_ACK augmentation that copilot's poll loop applies
15
+ * to human-from-dashboard messages is identifiable by name from
16
+ * either adapter's prompt-build site.
17
+ *
18
+ * **Why not `buildServerInstructions` from `src/server-tools.ts`?**
19
+ * The other two SDK-class adapters (claude-api, opencode) DO use
20
+ * `buildServerInstructions` for their per-turn system prompt. Copilot
21
+ * predates that helper and ships its own inline framing with a more
22
+ * explicit "tools available" enumeration. Issue #536 directs
23
+ * claude-code-headless to mirror **copilot's** content (so the two
24
+ * adapters speak the same dialect to the model), not the canonical
25
+ * helper. A future consolidation pass could migrate ALL four SDK
26
+ * adapters onto `buildServerInstructions` — out of scope here.
27
+ */
28
+ /**
29
+ * SDK-class adapter system-prompt template, parameterized by ensemble.
30
+ *
31
+ * Lifted verbatim from `src/adapters/copilot/adapter.ts:283-297` (the
32
+ * pre-#536 inline `systemMessage.content`). Both copilot and
33
+ * claude-code-headless feed this into their per-turn invocation:
34
+ * - copilot via `sessionConfig.systemMessage` to the SDK's
35
+ * `createSession` call.
36
+ * - claude-code-headless via `--append-system-prompt <content>` on
37
+ * the per-turn `claude -p` argv.
38
+ *
39
+ * Returning a function (rather than a constant) preserves the
40
+ * `${ensemble}` interpolation hook — different ensembles see different
41
+ * names without templating in the call site.
42
+ *
43
+ * @param opts.ensemble Ensemble name shown to the model in the first
44
+ * line ("You are part of the …"). Pass `config.ensemble`.
45
+ */
46
+ export declare function buildSdkSystemPrompt(opts: {
47
+ ensemble: string;
48
+ }): string;
49
+ /**
50
+ * Per-message augmentation appended to messages whose `isMaestro`
51
+ * field is `true`. The maestro flag identifies messages originating
52
+ * from a human operator at the dashboard (vs. ensemble-internal
53
+ * cues from other player sessions).
54
+ *
55
+ * Lifted verbatim from `src/adapters/copilot/adapter.ts:462`. Both
56
+ * copilot's poll-loop prompt-build and claude-code-headless's
57
+ * per-turn `buildPromptText` apply this conditionally per
58
+ * `m.isMaestro` — a human-from-dashboard message gets the ack
59
+ * directive; an ensemble-internal cue does not.
60
+ *
61
+ * The leading `\n\n` separates the directive from the human's
62
+ * message text inside the same prompt frame.
63
+ */
64
+ export declare const MAESTRO_ACK = "\n\n[IMPORTANT: This message is from a human (Maestro). Immediately cue the sender back with a brief acknowledgment and your planned next step before doing the work.]";
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * Shared SDK-class adapter system-prompt helpers (#536).
4
+ *
5
+ * Two SDK-class adapters in this repo currently mirror an *identical*
6
+ * "use your MCP tools to reply" framing onto the model — copilot
7
+ * (`src/adapters/copilot/adapter.ts:283-297`) and, post-#536,
8
+ * claude-code-headless (`src/adapters/claude-code-headless/adapter.ts`).
9
+ * Pre-#536 the framing only existed on copilot's side, hand-typed
10
+ * inline; this module factors it out so:
11
+ *
12
+ * - There is one canonical source for the prompt content (no copy
13
+ * drift when someone tweaks the wording in one place and forgets
14
+ * the other).
15
+ * - The MAESTRO_ACK augmentation that copilot's poll loop applies
16
+ * to human-from-dashboard messages is identifiable by name from
17
+ * either adapter's prompt-build site.
18
+ *
19
+ * **Why not `buildServerInstructions` from `src/server-tools.ts`?**
20
+ * The other two SDK-class adapters (claude-api, opencode) DO use
21
+ * `buildServerInstructions` for their per-turn system prompt. Copilot
22
+ * predates that helper and ships its own inline framing with a more
23
+ * explicit "tools available" enumeration. Issue #536 directs
24
+ * claude-code-headless to mirror **copilot's** content (so the two
25
+ * adapters speak the same dialect to the model), not the canonical
26
+ * helper. A future consolidation pass could migrate ALL four SDK
27
+ * adapters onto `buildServerInstructions` — out of scope here.
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.MAESTRO_ACK = void 0;
31
+ exports.buildSdkSystemPrompt = buildSdkSystemPrompt;
32
+ /**
33
+ * SDK-class adapter system-prompt template, parameterized by ensemble.
34
+ *
35
+ * Lifted verbatim from `src/adapters/copilot/adapter.ts:283-297` (the
36
+ * pre-#536 inline `systemMessage.content`). Both copilot and
37
+ * claude-code-headless feed this into their per-turn invocation:
38
+ * - copilot via `sessionConfig.systemMessage` to the SDK's
39
+ * `createSession` call.
40
+ * - claude-code-headless via `--append-system-prompt <content>` on
41
+ * the per-turn `claude -p` argv.
42
+ *
43
+ * Returning a function (rather than a constant) preserves the
44
+ * `${ensemble}` interpolation hook — different ensembles see different
45
+ * names without templating in the call site.
46
+ *
47
+ * @param opts.ensemble Ensemble name shown to the model in the first
48
+ * line ("You are part of the …"). Pass `config.ensemble`.
49
+ */
50
+ function buildSdkSystemPrompt(opts) {
51
+ return (`You are part of the "${opts.ensemble}" ensemble coordinated via Temporal. ` +
52
+ `You have MCP tools available — ALWAYS use these tools directly, NEVER try to run them as shell commands:\n` +
53
+ `- set_name: Set your player name (call this FIRST if instructed)\n` +
54
+ `- ensemble: List active sessions\n` +
55
+ `- cue: Send a message to another player\n` +
56
+ `- set_part: Update your status/description\n` +
57
+ `- listen: Check for pending messages\n` +
58
+ `- recruit: Spawn a new player session\n` +
59
+ `- report: Report to the conductor\n` +
60
+ `- stop: Stop a session\n\n` +
61
+ `When you receive a message from another session, treat it like a coworker asking for help — respond promptly using your MCP tools.`);
62
+ }
63
+ /**
64
+ * Per-message augmentation appended to messages whose `isMaestro`
65
+ * field is `true`. The maestro flag identifies messages originating
66
+ * from a human operator at the dashboard (vs. ensemble-internal
67
+ * cues from other player sessions).
68
+ *
69
+ * Lifted verbatim from `src/adapters/copilot/adapter.ts:462`. Both
70
+ * copilot's poll-loop prompt-build and claude-code-headless's
71
+ * per-turn `buildPromptText` apply this conditionally per
72
+ * `m.isMaestro` — a human-from-dashboard message gets the ack
73
+ * directive; an ensemble-internal cue does not.
74
+ *
75
+ * The leading `\n\n` separates the directive from the human's
76
+ * message text inside the same prompt frame.
77
+ */
78
+ exports.MAESTRO_ACK = '\n\n[IMPORTANT: This message is from a human (Maestro). Immediately cue the sender back with a brief acknowledgment and your planned next step before doing the work.]';
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared terminal-class error classifier for adapter code (#249 Bug 4).
3
+ *
4
+ * The Temporal TS SDK conflates two terminal sub-kinds on pinned-runId
5
+ * signal/query failures:
6
+ * (a) the closed run's specific runId no longer accepting traffic (CAN,
7
+ * true COMPLETE, TERMINATED, FAILED), and
8
+ * (b) the workflow id having been fully GC'd.
9
+ * Both surface as `WorkflowNotFoundError` with message
10
+ * "workflow execution already completed". This classifier says "yes, this is a
11
+ * terminal-class error" vs "transient, keep retrying" — it does NOT distinguish
12
+ * the sub-kinds. Callers that need sub-kind resolution consult
13
+ * `fetchHistory` (see {@link BaseAttachment.handleRunEndError}).
14
+ *
15
+ * **Extracted from `BaseAttachment.isTerminalErr` to break a code-duplication
16
+ * risk** — both the heartbeat/watcher ticks (in `base.ts`) and the delivery
17
+ * poller (in `claude-code/adapter.ts`) need to classify the same errors, and
18
+ * divergence between the two would re-create the #249 Bug 4 regression surface.
19
+ * One implementation, one import point.
20
+ *
21
+ * Uses name/message-sniffing rather than `instanceof` to tolerate the slightly
22
+ * different shapes errors take between `@temporalio/client` and the raw gRPC
23
+ * layer. The tradeoff is a narrow window where gRPC could add a new phrasing
24
+ * for the same error class — but that's caught by the existing adapter
25
+ * reconnect integration tests.
26
+ */
27
+ export declare function isTerminalWorkflowError(err: unknown): boolean;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isTerminalWorkflowError = isTerminalWorkflowError;
4
+ /**
5
+ * Shared terminal-class error classifier for adapter code (#249 Bug 4).
6
+ *
7
+ * The Temporal TS SDK conflates two terminal sub-kinds on pinned-runId
8
+ * signal/query failures:
9
+ * (a) the closed run's specific runId no longer accepting traffic (CAN,
10
+ * true COMPLETE, TERMINATED, FAILED), and
11
+ * (b) the workflow id having been fully GC'd.
12
+ * Both surface as `WorkflowNotFoundError` with message
13
+ * "workflow execution already completed". This classifier says "yes, this is a
14
+ * terminal-class error" vs "transient, keep retrying" — it does NOT distinguish
15
+ * the sub-kinds. Callers that need sub-kind resolution consult
16
+ * `fetchHistory` (see {@link BaseAttachment.handleRunEndError}).
17
+ *
18
+ * **Extracted from `BaseAttachment.isTerminalErr` to break a code-duplication
19
+ * risk** — both the heartbeat/watcher ticks (in `base.ts`) and the delivery
20
+ * poller (in `claude-code/adapter.ts`) need to classify the same errors, and
21
+ * divergence between the two would re-create the #249 Bug 4 regression surface.
22
+ * One implementation, one import point.
23
+ *
24
+ * Uses name/message-sniffing rather than `instanceof` to tolerate the slightly
25
+ * different shapes errors take between `@temporalio/client` and the raw gRPC
26
+ * layer. The tradeoff is a narrow window where gRPC could add a new phrasing
27
+ * for the same error class — but that's caught by the existing adapter
28
+ * reconnect integration tests.
29
+ */
30
+ function isTerminalWorkflowError(err) {
31
+ const e = err;
32
+ const name = e?.name ?? '';
33
+ const msg = e?.message ?? '';
34
+ return (name.includes('WorkflowNotFound') ||
35
+ name.includes('WorkflowExecutionAlreadyCompleted') ||
36
+ msg.includes('WorkflowGone') ||
37
+ msg.includes('NOT_FOUND') ||
38
+ msg.includes('workflow execution already completed'));
39
+ }
@@ -0,0 +1,3 @@
1
+ import { WorkflowHandle } from '@temporalio/client';
2
+ import { Message } from './types';
3
+ export declare function startMessagePoller(handle: WorkflowHandle, onMessages: (messages: Message[]) => Promise<void> | void): () => void;