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,730 @@
1
+ "use strict";
2
+ /**
3
+ * Copilot adapter — SDK class.
4
+ *
5
+ * Content lifted verbatim from `src/copilot-bridge.ts` into a class wrapper as
6
+ * part of PR-B (v0.25 rebuild step 2/7). Zero behavior change: the same
7
+ * createSession / event-logger / poll / sendAndWait / cleanup flow runs, and
8
+ * the PR-A compat shim in `src/workflows/session.ts` translates
9
+ * `updateMetadata({ status })` onto the attachment phase machine.
10
+ *
11
+ * Dual-purpose file:
12
+ * - `import { CopilotSdkAttachment } from '.../adapter'` → class reference for
13
+ * the adapter registry. `run()` is NOT invoked.
14
+ * - `node .../adapter.js` (or `ts-node .../adapter.ts`) → executes `run()` as
15
+ * the spawned subprocess entry point, gated by `require.main === module`.
16
+ *
17
+ * PR-C rewrites this adapter against the v0.25 attachment wire protocol —
18
+ * `claimAttachment` + heartbeat, `processingStart`/`End` via SdkAttachment.deliver()
19
+ * wrapper, `onSuperseded` cancellation hook. Until then, the bridge runs its
20
+ * lifecycle stand-alone.
21
+ *
22
+ * Usage (dev / prod):
23
+ * npx ts-node src/adapters/copilot/adapter.ts
24
+ * node dist/adapters/copilot/adapter.js
25
+ *
26
+ * Environment variables:
27
+ * AGENT_TEMPO_ENSEMBLE — ensemble name (default: "default")
28
+ * AGENT_TEMPO_PLAYER_NAME — player ID for workflow registration (set by spawner for deterministic workflow IDs)
29
+ * COPILOT_BRIDGE_NAME — player name for set_name (optional)
30
+ * COPILOT_BRIDGE_MODEL — model to use (optional)
31
+ * COPILOT_BRIDGE_SESSION_ID — deterministic session ID for resumable sessions (optional)
32
+ * GITHUB_TOKEN — GitHub auth token (optional, uses logged-in user by default)
33
+ *
34
+ * Design reference: docs/design/session-lifecycle-rebuild-v2.md §6 (Class 2 —
35
+ * SDK), §4.2, §4.4.
36
+ */
37
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
38
+ if (k2 === undefined) k2 = k;
39
+ var desc = Object.getOwnPropertyDescriptor(m, k);
40
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
41
+ desc = { enumerable: true, get: function() { return m[k]; } };
42
+ }
43
+ Object.defineProperty(o, k2, desc);
44
+ }) : (function(o, m, k, k2) {
45
+ if (k2 === undefined) k2 = k;
46
+ o[k2] = m[k];
47
+ }));
48
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
49
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
50
+ }) : function(o, v) {
51
+ o["default"] = v;
52
+ });
53
+ var __importStar = (this && this.__importStar) || (function () {
54
+ var ownKeys = function(o) {
55
+ ownKeys = Object.getOwnPropertyNames || function (o) {
56
+ var ar = [];
57
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
58
+ return ar;
59
+ };
60
+ return ownKeys(o);
61
+ };
62
+ return function (mod) {
63
+ if (mod && mod.__esModule) return mod;
64
+ var result = {};
65
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
66
+ __setModuleDefault(result, mod);
67
+ return result;
68
+ };
69
+ })();
70
+ Object.defineProperty(exports, "__esModule", { value: true });
71
+ exports.CopilotSdkAttachment = exports.copilotDescriptor = void 0;
72
+ const fs = __importStar(require("fs"));
73
+ const path = __importStar(require("path"));
74
+ const client_1 = require("@temporalio/client");
75
+ const config_1 = require("../../config");
76
+ const connection_1 = require("../../connection");
77
+ const base_1 = require("../sdk/base");
78
+ // #536 — shared SDK-class system-prompt + MAESTRO_ACK (was inline
79
+ // here pre-#536; moved to the shared module so the post-#536
80
+ // claude-code-headless adapter mirrors the same dialect).
81
+ const system_prompt_1 = require("../sdk/system-prompt");
82
+ const signals_1 = require("../../workflows/signals");
83
+ const parent_death_watchdog_1 = require("../../utils/parent-death-watchdog");
84
+ /**
85
+ * Descriptor for the copilot adapter. Kept colocated with the class so
86
+ * `adapter.ts` has no import dependency on `index.ts` (breaks the circular
87
+ * module-graph cycle flagged in QA review of PR-B). `index.ts` re-exports
88
+ * this constant alongside the class.
89
+ *
90
+ * Design reference: docs/design/session-lifecycle-rebuild-v2.md §4.2–4.3.
91
+ */
92
+ exports.copilotDescriptor = {
93
+ adapterId: 'copilot',
94
+ adapterClass: 'sdk',
95
+ // Copilot's sendAndWait blocks on the LLM turn — processingStart/End pairing
96
+ // is required (handled today inline in the bridge; PR-C centralizes it in
97
+ // SdkAttachment.deliver()).
98
+ blocksOnLLMTurn: true,
99
+ // SDK class — 30s cadence per design §4.3. PR-C wires this into the
100
+ // heartbeat loop on BaseAttachment.
101
+ heartbeatMs: 30_000,
102
+ };
103
+ // Optional dependency — must be installed separately: npm install @github/copilot-sdk
104
+ let CopilotClient;
105
+ let approveAll;
106
+ try {
107
+ const sdk = require('@github/copilot-sdk');
108
+ CopilotClient = sdk.CopilotClient;
109
+ approveAll = sdk.approveAll;
110
+ }
111
+ catch {
112
+ // When run as the Copilot bridge subprocess entrypoint, print an actionable
113
+ // error and exit so the user knows what to install. When imported by the
114
+ // adapter registry during normal MCP server startup, stay silent — the SDK
115
+ // is optional and non-Copilot users should see no noise. (#122)
116
+ if (require.main === module) {
117
+ console.error('Error: @github/copilot-sdk is not installed.\n' +
118
+ 'Install it with: npm install @github/copilot-sdk\n' +
119
+ 'See the Copilot CLI integration section in the README.');
120
+ process.exit(1);
121
+ }
122
+ }
123
+ // Unbuffered logging — fs.writeSync(2, ...) bypasses Node.js stream buffering,
124
+ // ensuring log output appears immediately even when stderr is redirected to a file.
125
+ const log = (...args) => {
126
+ const msg = `[copilot-bridge] ${args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ')}\n`;
127
+ fs.writeSync(2, msg);
128
+ };
129
+ /** Filter process.env to exclude undefined values (safe to spread as Record<string, string>). */
130
+ const cleanEnv = () => Object.fromEntries(Object.entries(process.env).filter((e) => e[1] !== undefined));
131
+ const POLL_INTERVAL_MS = 2000;
132
+ const CREATE_SESSION_TIMEOUT_MS = 45_000;
133
+ const MAX_CONSECUTIVE_FAILURES = 3;
134
+ const MAX_SESSION_RECREATIONS = 2;
135
+ /** Check workflow status every N polls (~30s at 2s interval). */
136
+ const WORKFLOW_STATUS_CHECK_INTERVAL = 15;
137
+ /** Proactively recreate the Copilot session after this idle period (ms). Default 60 min. */
138
+ const SESSION_MAX_IDLE_MS = 60 * 60 * 1000;
139
+ /** Wrap createSession with a timeout so auth/network hangs don't block forever. */
140
+ async function createSessionWithTimeout(copilotClient, sessionConfig, timeoutMs = CREATE_SESSION_TIMEOUT_MS) {
141
+ let timer;
142
+ const timeout = new Promise((_, reject) => {
143
+ timer = setTimeout(() => reject(new Error(`createSession timed out after ${timeoutMs / 1000}s — check Copilot auth and network connectivity`)), timeoutMs);
144
+ });
145
+ try {
146
+ return await Promise.race([
147
+ copilotClient.createSession(sessionConfig),
148
+ timeout,
149
+ ]);
150
+ }
151
+ finally {
152
+ clearTimeout(timer);
153
+ }
154
+ }
155
+ /**
156
+ * SDK-class adapter for the GitHub Copilot CLI.
157
+ *
158
+ * Delivery model is pull-based (blocks on LLM turn): the bridge polls the
159
+ * workflow for pending messages, injects them as prompts via the Copilot SDK's
160
+ * `session.sendAndWait`, then marks them delivered. `processingStart`/`End` are
161
+ * paired around each blocking call so the workflow's stale detection doesn't
162
+ * misclassify a long tool execution as a dead session (fix for #99).
163
+ *
164
+ * PR-B lands this as a verbatim lift from the old `src/copilot-bridge.ts`.
165
+ * PR-C moves the processingStart/End wrapping up into SdkAttachment.deliver()
166
+ * and introduces `claimAttachment` + heartbeat + `onSuperseded` hooks.
167
+ */
168
+ class CopilotSdkAttachment extends base_1.SdkAttachment {
169
+ descriptor = exports.copilotDescriptor;
170
+ /**
171
+ * The currently-active Copilot SDK session, stashed here so the
172
+ * `onSuperseded` hook can disconnect it on lease revocation. Populated in
173
+ * `run()` after `copilotClient.createSession(...)` and refreshed on each
174
+ * successful `recreateSession()`. `undefined` before the session is created
175
+ * and after shutdown.
176
+ */
177
+ activeSession;
178
+ /**
179
+ * Split-brain cancellation hook (§9.3). Called by `SdkAttachment` when the
180
+ * base-class phase watcher detects that our `attachmentId` no longer matches
181
+ * the current attachment on the workflow — i.e., another claimant stole the
182
+ * lease. We tear down the active Copilot session: it's the only
183
+ * cancellation primitive the SDK exposes, and the adapter is about to exit
184
+ * anyway.
185
+ *
186
+ * Residual ghost-reply window: if `sendAndWait` is already producing a reply
187
+ * over the network, disconnect may race the response. The reply is dropped
188
+ * (processingEnd will throw `AttachmentMismatch`, markDelivered never fires)
189
+ * so delivery semantics stay at-most-once. One LLM turn is wasted; this is
190
+ * documented in the adapter README per §9.3's guidance.
191
+ */
192
+ onSuperseded() {
193
+ log('lease revoked — disconnecting Copilot session');
194
+ const s = this.activeSession;
195
+ this.activeSession = undefined;
196
+ if (!s)
197
+ return;
198
+ // Fire-and-forget. disconnect() can be sync or async depending on SDK version;
199
+ // we don't await because the phase-watcher listener is synchronous.
200
+ try {
201
+ const maybePromise = s.disconnect();
202
+ if (maybePromise && typeof maybePromise.catch === 'function') {
203
+ maybePromise.catch((err) => log('session.disconnect during onSuperseded threw:', err?.message ?? err));
204
+ }
205
+ }
206
+ catch (err) {
207
+ log('session.disconnect during onSuperseded threw:', err?.message ?? err);
208
+ }
209
+ }
210
+ /**
211
+ * Entry point for the bridge subprocess.
212
+ *
213
+ * Kept as a single async method (instead of being broken up into lifecycle
214
+ * hooks) to preserve the exact behavior of the pre-PR-B `main()` function.
215
+ * The bridge claims the attachment via `startV2Lifecycle`, drives
216
+ * `deliver()` through `SdkAttachment` (synchronous processingStart/End
217
+ * per §7.1, `expectedAttachmentId` carried on both), and installs
218
+ * `onSuperseded` to disconnect the Copilot session on lease revocation.
219
+ *
220
+ * PR-H (#132): the legacy fire-and-forget processingStart/End path
221
+ * gated on `AGENT_TEMPO_LIFECYCLE_V2=0` has been removed. V2 is the
222
+ * only path.
223
+ */
224
+ async run() {
225
+ const config = (0, config_1.getConfig)();
226
+ const playerName = process.env[config_1.ENV.BRIDGE_NAME];
227
+ const model = process.env[config_1.ENV.BRIDGE_MODEL];
228
+ const copilotSessionId = process.env[config_1.ENV.BRIDGE_SESSION_ID] || `tempo-${config.ensemble}-${playerName || 'unknown'}-${Date.now()}-${process.pid}`;
229
+ const workDir = process.cwd();
230
+ log(`Starting Copilot bridge in ${workDir} (ensemble: ${config.ensemble})`);
231
+ // Connect Temporal client (for polling only — the MCP server child process runs its own worker)
232
+ const connection = await (0, connection_1.createTemporalConnection)(config);
233
+ const client = new client_1.Client({
234
+ connection,
235
+ namespace: config.temporalNamespace,
236
+ });
237
+ // Hand the client + host to BaseAttachment so startV2Lifecycle (below) can
238
+ // issue claimAttachment + heartbeat against it. No-op on legacy path.
239
+ const os = require('os');
240
+ this.configureV2(client, os.hostname());
241
+ // Determine the expected workflow ID. The MCP server uses the pattern
242
+ // `agent-session-{ensemble}-{playerId}`, where playerId comes from
243
+ // AGENT_TEMPO_PLAYER_NAME or a random hex. We pass AGENT_TEMPO_PLAYER_NAME
244
+ // to the MCP server env so both sides agree on the ID.
245
+ const isConductor = process.env[config_1.ENV.CONDUCTOR] === 'true';
246
+ const requestedName = process.env[config_1.ENV.PLAYER_NAME] || playerName || '';
247
+ const playerIdForWorkflow = isConductor
248
+ ? 'conductor'
249
+ : (requestedName && requestedName !== 'conductor' ? requestedName : '') || `copilot-${Date.now()}`;
250
+ const expectedWorkflowId = `agent-session-${config.ensemble}-${playerIdForWorkflow}`;
251
+ // Build the MCP server command — always use the compiled dist/server.js
252
+ // Run `npm run build` (or `pnpm build`) before using the bridge.
253
+ const serverJsPath = path.resolve(__dirname, '..', '..', '..', 'dist', 'server.js');
254
+ if (!fs.existsSync(serverJsPath)) {
255
+ log(`ERROR: ${serverJsPath} not found. Run 'pnpm build' first.`);
256
+ process.exit(1);
257
+ }
258
+ log(`MCP server path: ${serverJsPath}`);
259
+ const serverCommand = 'node';
260
+ const serverArgs = [serverJsPath];
261
+ const mcpEnv = {
262
+ ...cleanEnv(),
263
+ [config_1.ENV.ENSEMBLE]: config.ensemble,
264
+ [config_1.ENV.TEMPORAL_ADDRESS]: config.temporalAddress,
265
+ [config_1.ENV.TEMPORAL_NAMESPACE]: config.temporalNamespace,
266
+ [config_1.ENV.TASK_QUEUE]: config.taskQueue,
267
+ [config_1.ENV.CONDUCTOR]: isConductor ? 'true' : '',
268
+ [config_1.ENV.BRIDGE_MODE]: '1', // disable MCP server's message poller — bridge handles delivery
269
+ [config_1.ENV.PLAYER_NAME]: playerIdForWorkflow, // ensures MCP server uses same workflow ID
270
+ ...(config.temporalApiKey ? { [config_1.ENV.TEMPORAL_API_KEY]: config.temporalApiKey } : {}),
271
+ ...(config.temporalTlsCertPath ? { [config_1.ENV.TEMPORAL_TLS_CERT_PATH]: config.temporalTlsCertPath } : {}),
272
+ ...(config.temporalTlsKeyPath ? { [config_1.ENV.TEMPORAL_TLS_KEY_PATH]: config.temporalTlsKeyPath } : {}),
273
+ };
274
+ // Spawn Copilot SDK client and session
275
+ const copilotClient = new CopilotClient({
276
+ logLevel: 'debug',
277
+ env: {
278
+ ...cleanEnv(),
279
+ ...(process.env.GITHUB_TOKEN ? { GITHUB_TOKEN: process.env.GITHUB_TOKEN } : {}),
280
+ },
281
+ });
282
+ const sessionConfig = {
283
+ sessionId: copilotSessionId,
284
+ // approveAll is intentional: Copilot bridge sessions run headless with no
285
+ // interactive terminal, so there is no way to prompt for permission approval.
286
+ // All tool calls are auto-approved by design — the bridge operator accepts
287
+ // this when launching the bridge process.
288
+ onPermissionRequest: approveAll,
289
+ workingDirectory: workDir,
290
+ mcpServers: {
291
+ 'agent-tempo': {
292
+ command: serverCommand,
293
+ args: serverArgs,
294
+ env: mcpEnv,
295
+ tools: ['*'],
296
+ },
297
+ },
298
+ systemMessage: {
299
+ mode: 'append',
300
+ // #536 — content extracted to `src/adapters/sdk/system-prompt.ts`
301
+ // so claude-code-headless can use the same template via its
302
+ // `--append-system-prompt` argv. Behavior here is unchanged.
303
+ content: (0, system_prompt_1.buildSdkSystemPrompt)({ ensemble: config.ensemble }),
304
+ },
305
+ excludedTools: ['write_powershell', 'read_powershell', 'list_powershell'],
306
+ ...(model ? { model } : {}),
307
+ };
308
+ log('Creating Copilot session...');
309
+ let session = await createSessionWithTimeout(copilotClient, sessionConfig);
310
+ log(`Copilot session created: ${session.sessionId}`);
311
+ // Stash for onSuperseded (V2 path). Refreshed on each successful recreate.
312
+ this.activeSession = session;
313
+ // Track session health — resets to true on any successful interaction
314
+ let sessionAlive = true;
315
+ let lastEventTime = Date.now();
316
+ let lastEventType = 'session.created';
317
+ function attachEventLogger(s) {
318
+ s.on((event) => {
319
+ lastEventTime = Date.now();
320
+ lastEventType = event.type;
321
+ // Log tool calls and completions fully, truncate verbose events
322
+ if (event.type === 'tool.execution_start' || event.type === 'tool.execution_complete') {
323
+ log(`[event:${event.type}]`, JSON.stringify(event.data ?? event).substring(0, 800));
324
+ }
325
+ else if (event.type === 'assistant.message') {
326
+ const data = event.data ?? event;
327
+ const tools = data.toolRequests?.map((t) => t.name).join(', ') || 'none';
328
+ log(`[event:${event.type}] content="${(data.content || '').substring(0, 200)}" tools=[${tools}]`);
329
+ }
330
+ else if (event.type === 'session.info') {
331
+ log(`[session.info] ${JSON.stringify(event.data)}`);
332
+ }
333
+ else if (event.type === 'session.warning') {
334
+ log(`[session.warning] ${JSON.stringify(event.data)}`);
335
+ }
336
+ else if (event.type === 'session.mcp_servers_loaded') {
337
+ log(`[mcp_servers_loaded] ${JSON.stringify(event.data)}`);
338
+ }
339
+ else if (event.type === 'session.mcp_server_status_changed') {
340
+ log(`[mcp_server_status_changed] ${JSON.stringify(event.data)}`);
341
+ }
342
+ else if (event.type === 'session.idle') {
343
+ log(`[event:session.idle] Session is idle`);
344
+ }
345
+ else if (event.type?.includes('error') || event.type?.includes('disconnect')) {
346
+ log(`[event:${event.type}]`, JSON.stringify(event.data ?? event).substring(0, 500));
347
+ sessionAlive = false;
348
+ }
349
+ else {
350
+ log(`[event:${event.type}]`);
351
+ }
352
+ });
353
+ }
354
+ attachEventLogger(session);
355
+ // Send an initial prompt to trigger MCP server initialization.
356
+ // The Copilot SDK doesn't start MCP server subprocesses until the session
357
+ // processes a message that could use tools. We await this so the workflow
358
+ // registers before we try to find it, and so subsequent sendAndWait calls
359
+ // don't collide with this one.
360
+ log('Sending initial prompt to trigger MCP server startup...');
361
+ try {
362
+ const t0 = Date.now();
363
+ const initResult = await session.sendAndWait({ prompt: 'Call the ensemble tool to list active sessions. Respond in one short sentence.' }, 120_000);
364
+ log(`Initial prompt completed in ${Date.now() - t0}ms, result:`, JSON.stringify(initResult)?.substring(0, 300));
365
+ // Dump available tools for diagnostics
366
+ try {
367
+ const toolList = await session.rpc.tools.list({});
368
+ log('Available tools:', JSON.stringify(toolList.tools?.map((t) => t.name || t.namespacedName)));
369
+ }
370
+ catch (toolErr) {
371
+ log('Failed to list tools:', toolErr?.message);
372
+ }
373
+ }
374
+ catch (err) {
375
+ log(`Initial prompt error after ${Date.now()}ms:`, err?.message, err?.stack?.substring(0, 300));
376
+ }
377
+ // PID file paths — computed early so early-exit paths can clean up
378
+ const pidDir = path.join(workDir, 'logs');
379
+ const pidFile = path.join(pidDir, `${playerName || playerIdForWorkflow}.pid`);
380
+ // Wait for the MCP server's workflow to register in Temporal.
381
+ // We know the exact workflow ID because we pass AGENT_TEMPO_PLAYER_NAME to the
382
+ // MCP server — no need for a time-window heuristic that could misidentify workflows.
383
+ log(`Waiting for workflow ${expectedWorkflowId} to register...`);
384
+ let handle = client.workflow.getHandle(expectedWorkflowId);
385
+ let workflowReady = false;
386
+ let pinnedRunId;
387
+ for (let attempt = 0; attempt < 30; attempt++) {
388
+ try {
389
+ const desc = await handle.describe();
390
+ if (desc.status.name === 'RUNNING') {
391
+ workflowReady = true;
392
+ pinnedRunId = desc.runId;
393
+ break;
394
+ }
395
+ }
396
+ catch {
397
+ // Workflow not yet started
398
+ }
399
+ await new Promise((r) => setTimeout(r, 1000));
400
+ if (attempt % 5 === 4)
401
+ log(`Still waiting... attempt ${attempt + 1}/30`);
402
+ }
403
+ if (!workflowReady) {
404
+ log(`ERROR: Workflow ${expectedWorkflowId} did not register within 30 seconds`);
405
+ await session.disconnect();
406
+ await copilotClient.stop();
407
+ // Clean up PID file to avoid stale entries in `agent-tempo status`
408
+ try {
409
+ fs.unlinkSync(pidFile);
410
+ }
411
+ catch { /* may not exist yet */ }
412
+ process.exit(1);
413
+ }
414
+ // Pin all subsequent interactions to the runId we observed — prevents the
415
+ // zombie-resurrection hazard from #102. If this run completes (e.g. destroy),
416
+ // a later USE_EXISTING start would spawn a new run with the same workflow ID;
417
+ // an unpinned handle would silently attach to the new run, but a pinned handle
418
+ // returns WorkflowNotFound and lets the bridge exit cleanly.
419
+ handle = client.workflow.getHandle(expectedWorkflowId, pinnedRunId);
420
+ log(`Workflow ready: ${expectedWorkflowId} (pinned runId ${pinnedRunId})`);
421
+ // V2 path: claim the attachment + start the base-class heartbeat & phase
422
+ // watcher loops. `startV2Lifecycle` returns its own pinned handle (same
423
+ // runId we already have); we prefer it going forward so the heartbeat
424
+ // and delivery use a consistent handle. `onTerminal` (WorkflowNotFound,
425
+ // phase=gone, lease revoked) triggers clean shutdown below.
426
+ //
427
+ // PR-H (#132): unconditional — the V1 fallback gated on
428
+ // `AGENT_TEMPO_LIFECYCLE_V2=0` has been removed.
429
+ // Wire terminal handler BEFORE claiming so a race between claim + lease
430
+ // loss can't drop the event.
431
+ this.onTerminal((reason) => {
432
+ log(`V2 terminal (${reason}) — triggering cleanup`);
433
+ // Fire-and-forget: `cleanup` is idempotent.
434
+ cleanup().catch((err) => log('terminal cleanup error:', err?.message ?? err));
435
+ });
436
+ try {
437
+ // PR-D: read pre-claimed attachmentId (set by the spawn activity when
438
+ // the workflow called `claimAttachment` before enqueueing this spawn).
439
+ // Forwarding it selects §9.2's renewal branch so the adapter takes
440
+ // over an existing lease atomically; absent on first-recruit spawn.
441
+ const expectedAttachmentId = process.env[config_1.ENV.ATTACHMENT_ID] || undefined;
442
+ handle = await this.startV2Lifecycle(expectedWorkflowId, expectedAttachmentId);
443
+ log(`V2 attachment claimed (attachmentId=${this.token?.attachmentId}${expectedAttachmentId ? ', renewed' : ''})`);
444
+ }
445
+ catch (err) {
446
+ log(`ERROR: V2 claimAttachment failed: ${err?.message ?? err}`);
447
+ try {
448
+ await session.disconnect();
449
+ }
450
+ catch { /* best effort */ }
451
+ try {
452
+ fs.unlinkSync(pidFile);
453
+ }
454
+ catch { /* may not exist */ }
455
+ await copilotClient.stop();
456
+ process.exit(1);
457
+ }
458
+ // Store sessionId in workflow metadata for future restart/resume.
459
+ // PR-D: migrated from string-literal `'updateMetadata'` to the typed
460
+ // constant so the ts-morph wire-protocol drift detector sees this call.
461
+ try {
462
+ await handle.signal(signals_1.updateMetadataSignal, { sessionId: copilotSessionId });
463
+ }
464
+ catch { /* workflow may not be ready yet */ }
465
+ // If a name was requested, send the set_name instruction
466
+ if (playerName) {
467
+ log(`Sending set_name instruction for "${playerName}"...`);
468
+ const t0 = Date.now();
469
+ await session.sendAndWait({ prompt: `Call set_name("${playerName}") immediately. Respond in one short sentence.` }, 120_000);
470
+ log(`set_name completed in ${Date.now() - t0}ms`);
471
+ }
472
+ // #536 — `MAESTRO_ACK` lifted into `src/adapters/sdk/system-prompt.ts`
473
+ // so claude-code-headless's prompt-build applies the same string.
474
+ // Imported at the top of this module.
475
+ // Write PID file so callers can find/kill orphaned bridge processes
476
+ try {
477
+ fs.mkdirSync(pidDir, { recursive: true });
478
+ fs.writeFileSync(pidFile, String(process.pid));
479
+ log(`PID file written: ${pidFile}`);
480
+ }
481
+ catch (err) {
482
+ log(`Warning: could not write PID file: ${err?.message}`);
483
+ }
484
+ // Start message poller — inject messages into the Copilot session.
485
+ // Tracks consecutive failures and attempts session recreation before giving up.
486
+ let polling = true;
487
+ let processing = false;
488
+ let pollCount = 0;
489
+ let consecutiveFailures = 0;
490
+ let sessionRecreations = 0;
491
+ let proactiveRecreations = 0;
492
+ let lastActivityTime = Date.now();
493
+ // interval declared here, assigned after poll is defined
494
+ let interval;
495
+ // Shared cleanup — disconnects session, removes PID file, stops client.
496
+ let shuttingDown = false;
497
+ const cleanup = async () => {
498
+ if (shuttingDown)
499
+ return;
500
+ shuttingDown = true;
501
+ polling = false;
502
+ clearInterval(interval);
503
+ // V2 graceful detach — fires `adapterExited` so the workflow collapses
504
+ // draining → detached immediately per §11.1. No-op if V2 was off or if
505
+ // startV2Lifecycle never ran successfully.
506
+ //
507
+ // PR-C commit 4 retired the former `updateMetadata({ status: 'terminated' })`
508
+ // follow-up signal: closing the Copilot bridge subprocess is a graceful
509
+ // detach, not a session destroy. The workflow stays in `detached` waiting
510
+ // for the next claim (e.g. `restart`). Explicit operator termination goes
511
+ // through the `destroy` tool / CLI, which uses `destroyUpdate` directly.
512
+ await this.stopV2Lifecycle('user-stop', /* graceful */ true).catch((err) => log(`stopV2Lifecycle suppressed error: ${err?.message ?? err}`));
513
+ try {
514
+ await session.disconnect();
515
+ }
516
+ catch { /* already disconnected */ }
517
+ this.activeSession = undefined;
518
+ try {
519
+ fs.unlinkSync(pidFile);
520
+ }
521
+ catch { /* already gone */ }
522
+ await copilotClient.stop();
523
+ };
524
+ /** Attempt to recreate the Copilot session after repeated failures. */
525
+ const recreateSession = async () => {
526
+ // Fixes #102: before recreating, check whether the pinned-runId workflow has
527
+ // been destroyed. If so, the user explicitly stopped this session — do NOT
528
+ // bring it back as a zombie. This also covers WorkflowNotFound (the pinned
529
+ // run has completed/terminated) since the query throws cleanly.
530
+ try {
531
+ const isDestroyed = await handle.query('isDestroyed');
532
+ if (isDestroyed) {
533
+ log('Workflow is destroyed — not reconnecting (session was intentionally stopped)');
534
+ return false;
535
+ }
536
+ }
537
+ catch (err) {
538
+ const errName = err?.name || '';
539
+ const errMsg = err?.message || '';
540
+ if (errName.includes('WorkflowNotFound') || errMsg.includes('NOT_FOUND')) {
541
+ log('Workflow not found (likely terminated) — not reconnecting');
542
+ return false;
543
+ }
544
+ // Query failed for another reason — log and continue with recreation.
545
+ log(`isDestroyed query failed (${errMsg}), continuing with recreation`);
546
+ }
547
+ sessionRecreations++;
548
+ if (sessionRecreations > MAX_SESSION_RECREATIONS) {
549
+ log(`ERROR: Exceeded max session recreations (${MAX_SESSION_RECREATIONS}). Giving up.`);
550
+ return false;
551
+ }
552
+ log(`Attempting session recovery (${sessionRecreations}/${MAX_SESSION_RECREATIONS})...`);
553
+ try {
554
+ await session.disconnect().catch(() => { });
555
+ // Try resumeSession first to preserve conversation history
556
+ try {
557
+ const { sessionId: _discard, ...resumeConfig } = sessionConfig;
558
+ session = await copilotClient.resumeSession(copilotSessionId, resumeConfig);
559
+ attachEventLogger(session);
560
+ this.activeSession = session; // refresh V2 onSuperseded target
561
+ sessionAlive = true;
562
+ consecutiveFailures = 0;
563
+ lastActivityTime = Date.now();
564
+ log(`Session resumed successfully: ${session.sessionId}`);
565
+ return true;
566
+ }
567
+ catch (resumeErr) {
568
+ log(`resumeSession failed (${resumeErr?.message}), falling back to createSession`);
569
+ session = await createSessionWithTimeout(copilotClient, sessionConfig);
570
+ attachEventLogger(session);
571
+ this.activeSession = session; // refresh V2 onSuperseded target
572
+ sessionAlive = true;
573
+ consecutiveFailures = 0;
574
+ lastActivityTime = Date.now();
575
+ log(`Session recreated (fresh) successfully: ${session.sessionId}`);
576
+ return true;
577
+ }
578
+ }
579
+ catch (err) {
580
+ log(`Session recovery failed: ${err?.message}`);
581
+ return false;
582
+ }
583
+ };
584
+ const poll = async () => {
585
+ if (!polling || processing)
586
+ return;
587
+ pollCount++;
588
+ // Periodic health check
589
+ if (pollCount % 30 === 0) { // every ~60 seconds
590
+ const silenceSec = ((Date.now() - lastEventTime) / 1000).toFixed(0);
591
+ log(`[health] poll #${pollCount}, sessionAlive=${sessionAlive}, lastEvent=${lastEventType} ${silenceSec}s ago`);
592
+ }
593
+ // Periodic workflow status check — detect external termination/completion
594
+ if (pollCount % WORKFLOW_STATUS_CHECK_INTERVAL === 0) {
595
+ try {
596
+ const desc = await handle.describe();
597
+ const wfStatus = desc.status.name;
598
+ if (wfStatus !== 'RUNNING') {
599
+ log(`Workflow status is ${wfStatus} — exiting cleanly`);
600
+ await cleanup();
601
+ process.exit(0);
602
+ }
603
+ // Also check the in-workflow destroy flag — the workflow may still be RUNNING
604
+ // (draining) but has been destroyed. Exit cleanly without attempting signals
605
+ // that would be rejected.
606
+ try {
607
+ const isDestroyed = await handle.query('isDestroyed');
608
+ if (isDestroyed) {
609
+ log('Workflow destroyed — exiting cleanly');
610
+ await cleanup();
611
+ process.exit(0);
612
+ }
613
+ }
614
+ catch { /* isDestroyed query unavailable pre-upgrade — safe to ignore */ }
615
+ }
616
+ catch (err) {
617
+ // If we can't describe (e.g., workflow not found), it was likely terminated
618
+ log(`Workflow describe failed: ${err?.message} — treating as terminated`);
619
+ await cleanup();
620
+ process.exit(0);
621
+ }
622
+ }
623
+ // Proactive stale-session detection — recreate before the SDK server GCs the session
624
+ const idleMs = Date.now() - lastActivityTime;
625
+ if (idleMs > SESSION_MAX_IDLE_MS && !processing) {
626
+ try {
627
+ processing = true; // guard against overlapping polls during async recreation
628
+ log(`Session idle for ${(idleMs / 1000 / 60).toFixed(0)}min — proactively recreating`);
629
+ proactiveRecreations++;
630
+ const recovered = await recreateSession();
631
+ if (recovered) {
632
+ // Proactive recreation is lifecycle management, not failure recovery — restore failure budget
633
+ // but don't reset to 0: use proactiveRecreations to cap total lifecycle recreations
634
+ sessionRecreations = Math.max(0, sessionRecreations - 1);
635
+ }
636
+ else {
637
+ // Session is almost certainly dead server-side — force immediate recovery on next message
638
+ // Use MAX - 1 so the next poll error increments to the threshold and triggers recovery
639
+ consecutiveFailures = MAX_CONSECUTIVE_FAILURES - 1;
640
+ sessionAlive = false;
641
+ log('ERROR: Proactive session recreation failed — will force recovery on next message');
642
+ }
643
+ }
644
+ finally {
645
+ processing = false;
646
+ }
647
+ }
648
+ try {
649
+ const messages = await handle.query('pendingMessages');
650
+ if (messages.length === 0)
651
+ return;
652
+ processing = true;
653
+ const ids = messages.map((m) => m.id);
654
+ // Format messages into a single prompt, appending ack instruction for Maestro messages
655
+ const prompt = messages
656
+ .map((m) => {
657
+ const line = `[Message from ${m.from}]: ${m.text}`;
658
+ return m.isMaestro ? line + system_prompt_1.MAESTRO_ACK : line;
659
+ })
660
+ .join('\n\n');
661
+ log(`Injecting ${messages.length} message(s) into Copilot session`);
662
+ log(`Prompt: ${prompt.substring(0, 300)}`);
663
+ if (!sessionAlive) {
664
+ log('WARNING: session appears dead, sendAndWait may hang');
665
+ }
666
+ // Fixes #99: mark in-flight before the blocking LLM call so the workflow's
667
+ // stale detection doesn't misclassify a long tool call as dead. The V2
668
+ // path goes through `SdkAttachment.deliver()` which makes these updates
669
+ // synchronous (§7.1) and carries `expectedAttachmentId` so a revoked
670
+ // lease is observable. PR-H (#132): the `AGENT_TEMPO_LIFECYCLE_V2=0`
671
+ // legacy fire-and-forget fallback has been removed.
672
+ if (!this.token) {
673
+ // Should be unreachable: `startV2Lifecycle` populates token before
674
+ // `run()` reaches the delivery loop. Fail loudly rather than
675
+ // silently fall back.
676
+ throw new Error('Copilot bridge invariant: attachment token missing in delivery loop');
677
+ }
678
+ // SdkAttachment.deliver wraps processingStart → sendAndWait → processingEnd
679
+ // → markDelivered(ids). Invokes onSuperseded on lease revocation mid-turn.
680
+ const delivered = await this.deliver(handle, messages[0], // representative message
681
+ prompt, 300_000, async (p, t) => session.sendAndWait({ prompt: p }, t), ids);
682
+ const result = delivered.sdkResult;
683
+ const elapsed = delivered.elapsedMs;
684
+ log(`sendAndWait completed in ${elapsed}ms`);
685
+ log(`Response: ${JSON.stringify(result)?.substring(0, 500)}`);
686
+ // Success — reset failure tracking
687
+ consecutiveFailures = 0;
688
+ lastActivityTime = Date.now();
689
+ sessionAlive = true;
690
+ processing = false;
691
+ }
692
+ catch (err) {
693
+ processing = false;
694
+ consecutiveFailures++;
695
+ log(`Poll error (${consecutiveFailures}/${MAX_CONSECUTIVE_FAILURES}): ${err?.message}`);
696
+ log(`Error stack: ${err?.stack?.substring(0, 300)}`);
697
+ if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
698
+ log('Consecutive failure threshold reached — attempting session recovery');
699
+ const recovered = await recreateSession();
700
+ if (!recovered) {
701
+ log('ERROR: Session recovery failed. Shutting down bridge.');
702
+ await cleanup();
703
+ process.exit(2);
704
+ }
705
+ }
706
+ }
707
+ };
708
+ interval = setInterval(poll, POLL_INTERVAL_MS);
709
+ log('Message poller started. Bridge is running.');
710
+ // Graceful shutdown on SIGINT/SIGTERM — signal the workflow before exiting
711
+ const shutdown = async () => {
712
+ log('Shutting down (signal received)...');
713
+ await cleanup();
714
+ process.exit(0);
715
+ };
716
+ process.on('SIGINT', shutdown);
717
+ process.on('SIGTERM', shutdown);
718
+ }
719
+ }
720
+ exports.CopilotSdkAttachment = CopilotSdkAttachment;
721
+ // Subprocess entry point — only fires when this file is executed directly by
722
+ // `node .../adapter.js` or `ts-node .../adapter.ts`. Keeps the file usable both
723
+ // as an importable class and as a spawn target.
724
+ if (require.main === module) {
725
+ (0, parent_death_watchdog_1.installParentDeathWatchdog)();
726
+ new CopilotSdkAttachment().run().catch((err) => {
727
+ log('Fatal error:', err);
728
+ process.exit(1);
729
+ });
730
+ }