agent-tempo 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. package/CLAUDE.md +213 -0
  2. package/LICENSE +21 -0
  3. package/README.md +289 -0
  4. package/assets/icon-32.png +0 -0
  5. package/assets/icon-512.png +0 -0
  6. package/assets/icon-64.png +0 -0
  7. package/assets/icon-dark-32.png +0 -0
  8. package/assets/icon-dark-64.png +0 -0
  9. package/assets/icon-dark.svg +9 -0
  10. package/assets/icon.svg +9 -0
  11. package/assets/logo-dark.svg +11 -0
  12. package/assets/logo-light.svg +11 -0
  13. package/dashboard/README.md +91 -0
  14. package/dashboard/dist/assets/index-CB78ToNE.css +2 -0
  15. package/dashboard/dist/assets/index-_5jV0Znu.js +62 -0
  16. package/dashboard/dist/assets/index-_5jV0Znu.js.map +1 -0
  17. package/dashboard/dist/index.html +21 -0
  18. package/dashboard/package.json +47 -0
  19. package/dist/activities/hard-terminate.d.ts +32 -0
  20. package/dist/activities/hard-terminate.js +460 -0
  21. package/dist/activities/maestro.d.ts +72 -0
  22. package/dist/activities/maestro.js +254 -0
  23. package/dist/activities/outbox.d.ts +188 -0
  24. package/dist/activities/outbox.js +849 -0
  25. package/dist/activities/resolve.d.ts +64 -0
  26. package/dist/activities/resolve.js +129 -0
  27. package/dist/activities/schedule-fire.d.ts +36 -0
  28. package/dist/activities/schedule-fire.js +147 -0
  29. package/dist/adapters/base.d.ts +426 -0
  30. package/dist/adapters/base.js +1270 -0
  31. package/dist/adapters/claude-api/adapter.d.ts +168 -0
  32. package/dist/adapters/claude-api/adapter.js +797 -0
  33. package/dist/adapters/claude-api/api-error.d.ts +96 -0
  34. package/dist/adapters/claude-api/api-error.js +191 -0
  35. package/dist/adapters/claude-api/index.d.ts +16 -0
  36. package/dist/adapters/claude-api/index.js +21 -0
  37. package/dist/adapters/claude-api/mcp-bridge.d.ts +50 -0
  38. package/dist/adapters/claude-api/mcp-bridge.js +157 -0
  39. package/dist/adapters/claude-code/adapter.d.ts +133 -0
  40. package/dist/adapters/claude-code/adapter.js +274 -0
  41. package/dist/adapters/claude-code/index.d.ts +15 -0
  42. package/dist/adapters/claude-code/index.js +20 -0
  43. package/dist/adapters/claude-code-headless/adapter.d.ts +131 -0
  44. package/dist/adapters/claude-code-headless/adapter.js +710 -0
  45. package/dist/adapters/claude-code-headless/error-mapper.d.ts +107 -0
  46. package/dist/adapters/claude-code-headless/error-mapper.js +281 -0
  47. package/dist/adapters/claude-code-headless/index.d.ts +17 -0
  48. package/dist/adapters/claude-code-headless/index.js +26 -0
  49. package/dist/adapters/claude-code-headless/pre-flight.d.ts +51 -0
  50. package/dist/adapters/claude-code-headless/pre-flight.js +207 -0
  51. package/dist/adapters/claude-code-headless/prompt.d.ts +93 -0
  52. package/dist/adapters/claude-code-headless/prompt.js +79 -0
  53. package/dist/adapters/claude-code-headless/stream-json.d.ts +242 -0
  54. package/dist/adapters/claude-code-headless/stream-json.js +208 -0
  55. package/dist/adapters/claude-code-headless/types.d.ts +28 -0
  56. package/dist/adapters/claude-code-headless/types.js +36 -0
  57. package/dist/adapters/copilot/adapter.d.ts +100 -0
  58. package/dist/adapters/copilot/adapter.js +730 -0
  59. package/dist/adapters/copilot/index.d.ts +15 -0
  60. package/dist/adapters/copilot/index.js +20 -0
  61. package/dist/adapters/index.d.ts +42 -0
  62. package/dist/adapters/index.js +115 -0
  63. package/dist/adapters/opencode/adapter.d.ts +82 -0
  64. package/dist/adapters/opencode/adapter.js +710 -0
  65. package/dist/adapters/opencode/config.d.ts +90 -0
  66. package/dist/adapters/opencode/config.js +137 -0
  67. package/dist/adapters/opencode/helpers.d.ts +40 -0
  68. package/dist/adapters/opencode/helpers.js +144 -0
  69. package/dist/adapters/opencode/index.d.ts +12 -0
  70. package/dist/adapters/opencode/index.js +17 -0
  71. package/dist/adapters/opencode/server-bridge.d.ts +124 -0
  72. package/dist/adapters/opencode/server-bridge.js +216 -0
  73. package/dist/adapters/sdk/base.d.ts +95 -0
  74. package/dist/adapters/sdk/base.js +134 -0
  75. package/dist/adapters/sdk/system-prompt.d.ts +64 -0
  76. package/dist/adapters/sdk/system-prompt.js +78 -0
  77. package/dist/adapters/terminal-error.d.ts +27 -0
  78. package/dist/adapters/terminal-error.js +39 -0
  79. package/dist/channel.d.ts +3 -0
  80. package/dist/channel.js +48 -0
  81. package/dist/cli/commands.d.ts +245 -0
  82. package/dist/cli/commands.js +2438 -0
  83. package/dist/cli/config-command.d.ts +8 -0
  84. package/dist/cli/config-command.js +254 -0
  85. package/dist/cli/daemon-command.d.ts +57 -0
  86. package/dist/cli/daemon-command.js +493 -0
  87. package/dist/cli/daemon.d.ts +217 -0
  88. package/dist/cli/daemon.js +632 -0
  89. package/dist/cli/dashboard-command.d.ts +20 -0
  90. package/dist/cli/dashboard-command.js +241 -0
  91. package/dist/cli/dev-banner.d.ts +107 -0
  92. package/dist/cli/dev-banner.js +190 -0
  93. package/dist/cli/dev-mode-bootstrap.d.ts +29 -0
  94. package/dist/cli/dev-mode-bootstrap.js +36 -0
  95. package/dist/cli/dev-verbs.d.ts +43 -0
  96. package/dist/cli/dev-verbs.js +254 -0
  97. package/dist/cli/help-text.d.ts +1 -0
  98. package/dist/cli/help-text.js +158 -0
  99. package/dist/cli/legacy-migration.d.ts +35 -0
  100. package/dist/cli/legacy-migration.js +335 -0
  101. package/dist/cli/mcp.d.ts +8 -0
  102. package/dist/cli/mcp.js +63 -0
  103. package/dist/cli/output.d.ts +12 -0
  104. package/dist/cli/output.js +37 -0
  105. package/dist/cli/preflight.d.ts +9 -0
  106. package/dist/cli/preflight.js +96 -0
  107. package/dist/cli/removed-verbs.d.ts +9 -0
  108. package/dist/cli/removed-verbs.js +78 -0
  109. package/dist/cli/sa-preflight.d.ts +99 -0
  110. package/dist/cli/sa-preflight.js +183 -0
  111. package/dist/cli/scenarios-command.d.ts +6 -0
  112. package/dist/cli/scenarios-command.js +167 -0
  113. package/dist/cli/startup.d.ts +112 -0
  114. package/dist/cli/startup.js +641 -0
  115. package/dist/cli/upgrade-command.d.ts +5 -0
  116. package/dist/cli/upgrade-command.js +240 -0
  117. package/dist/cli.d.ts +2 -0
  118. package/dist/cli.js +680 -0
  119. package/dist/client/core.d.ts +33 -0
  120. package/dist/client/core.js +1260 -0
  121. package/dist/client/ensure-conductor-spawned.d.ts +35 -0
  122. package/dist/client/ensure-conductor-spawned.js +48 -0
  123. package/dist/client/index.d.ts +32 -0
  124. package/dist/client/index.js +22 -0
  125. package/dist/client/interface.d.ts +461 -0
  126. package/dist/client/interface.js +2 -0
  127. package/dist/client/subscribe.d.ts +108 -0
  128. package/dist/client/subscribe.js +598 -0
  129. package/dist/client/with-spawn.d.ts +27 -0
  130. package/dist/client/with-spawn.js +87 -0
  131. package/dist/config.d.ts +323 -0
  132. package/dist/config.js +593 -0
  133. package/dist/connection.d.ts +7 -0
  134. package/dist/connection.js +46 -0
  135. package/dist/constants.d.ts +50 -0
  136. package/dist/constants.js +74 -0
  137. package/dist/copilot-bridge.d.ts +22 -0
  138. package/dist/copilot-bridge.js +565 -0
  139. package/dist/daemon-adapter-versions.d.ts +52 -0
  140. package/dist/daemon-adapter-versions.js +170 -0
  141. package/dist/daemon.d.ts +275 -0
  142. package/dist/daemon.js +989 -0
  143. package/dist/ensemble/agent-types.d.ts +23 -0
  144. package/dist/ensemble/agent-types.js +132 -0
  145. package/dist/ensemble/loader.d.ts +14 -0
  146. package/dist/ensemble/loader.js +140 -0
  147. package/dist/ensemble/saver.d.ts +49 -0
  148. package/dist/ensemble/saver.js +201 -0
  149. package/dist/ensemble/schema.d.ts +71 -0
  150. package/dist/ensemble/schema.js +3 -0
  151. package/dist/git-info.d.ts +4 -0
  152. package/dist/git-info.js +29 -0
  153. package/dist/http/aggregate.d.ts +319 -0
  154. package/dist/http/aggregate.js +684 -0
  155. package/dist/http/auth.d.ts +67 -0
  156. package/dist/http/auth.js +177 -0
  157. package/dist/http/body.d.ts +71 -0
  158. package/dist/http/body.js +121 -0
  159. package/dist/http/catalog.d.ts +67 -0
  160. package/dist/http/catalog.js +209 -0
  161. package/dist/http/cors.d.ts +42 -0
  162. package/dist/http/cors.js +111 -0
  163. package/dist/http/dashboard-pair.d.ts +94 -0
  164. package/dist/http/dashboard-pair.js +148 -0
  165. package/dist/http/dashboard.d.ts +20 -0
  166. package/dist/http/dashboard.js +160 -0
  167. package/dist/http/event-bus.d.ts +217 -0
  168. package/dist/http/event-bus.js +365 -0
  169. package/dist/http/event-id.d.ts +77 -0
  170. package/dist/http/event-id.js +117 -0
  171. package/dist/http/event-types.d.ts +348 -0
  172. package/dist/http/event-types.js +36 -0
  173. package/dist/http/fixtures/chat-stress.d.ts +8 -0
  174. package/dist/http/fixtures/chat-stress.js +63 -0
  175. package/dist/http/fixtures/conductor-leaving.d.ts +8 -0
  176. package/dist/http/fixtures/conductor-leaving.js +80 -0
  177. package/dist/http/fixtures/constants.d.ts +10 -0
  178. package/dist/http/fixtures/constants.js +13 -0
  179. package/dist/http/fixtures/eight-player-broadcast.d.ts +10 -0
  180. package/dist/http/fixtures/eight-player-broadcast.js +81 -0
  181. package/dist/http/fixtures/empty-ensemble.d.ts +6 -0
  182. package/dist/http/fixtures/empty-ensemble.js +26 -0
  183. package/dist/http/fixtures/index.d.ts +55 -0
  184. package/dist/http/fixtures/index.js +110 -0
  185. package/dist/http/fixtures/single-conductor.d.ts +7 -0
  186. package/dist/http/fixtures/single-conductor.js +46 -0
  187. package/dist/http/fixtures/sse-reconnect.d.ts +8 -0
  188. package/dist/http/fixtures/sse-reconnect.js +77 -0
  189. package/dist/http/index.d.ts +21 -0
  190. package/dist/http/index.js +61 -0
  191. package/dist/http/port-file.d.ts +22 -0
  192. package/dist/http/port-file.js +132 -0
  193. package/dist/http/responses.d.ts +27 -0
  194. package/dist/http/responses.js +40 -0
  195. package/dist/http/ring-buffer.d.ts +41 -0
  196. package/dist/http/ring-buffer.js +80 -0
  197. package/dist/http/server.d.ts +122 -0
  198. package/dist/http/server.js +459 -0
  199. package/dist/http/snapshot.d.ts +85 -0
  200. package/dist/http/snapshot.js +180 -0
  201. package/dist/http/sse-handler.d.ts +87 -0
  202. package/dist/http/sse-handler.js +294 -0
  203. package/dist/http/writes.d.ts +55 -0
  204. package/dist/http/writes.js +240 -0
  205. package/dist/palette/index.d.ts +138 -0
  206. package/dist/palette/index.js +221 -0
  207. package/dist/reconcile/orphans.d.ts +255 -0
  208. package/dist/reconcile/orphans.js +340 -0
  209. package/dist/scripts/258-spotcheck.js +303 -0
  210. package/dist/scripts/check-components-css-sync.js +199 -0
  211. package/dist/scripts/run-shard.js +121 -0
  212. package/dist/scripts/verify-daemon-isolation-guard.js +128 -0
  213. package/dist/server-tools.d.ts +87 -0
  214. package/dist/server-tools.js +146 -0
  215. package/dist/server.d.ts +2 -0
  216. package/dist/server.js +366 -0
  217. package/dist/spawn.d.ts +296 -0
  218. package/dist/spawn.js +747 -0
  219. package/dist/tools/agent-types.d.ts +2 -0
  220. package/dist/tools/agent-types.js +21 -0
  221. package/dist/tools/attachment-info.d.ts +4 -0
  222. package/dist/tools/attachment-info.js +48 -0
  223. package/dist/tools/broadcast.d.ts +4 -0
  224. package/dist/tools/broadcast.js +76 -0
  225. package/dist/tools/cancel-stage.d.ts +3 -0
  226. package/dist/tools/cancel-stage.js +20 -0
  227. package/dist/tools/clear-state.d.ts +3 -0
  228. package/dist/tools/clear-state.js +37 -0
  229. package/dist/tools/coat-check-evict.d.ts +4 -0
  230. package/dist/tools/coat-check-evict.js +43 -0
  231. package/dist/tools/coat-check-get.d.ts +4 -0
  232. package/dist/tools/coat-check-get.js +56 -0
  233. package/dist/tools/coat-check-list.d.ts +4 -0
  234. package/dist/tools/coat-check-list.js +60 -0
  235. package/dist/tools/coat-check-put.d.ts +4 -0
  236. package/dist/tools/coat-check-put.js +53 -0
  237. package/dist/tools/cue.d.ts +44 -0
  238. package/dist/tools/cue.js +201 -0
  239. package/dist/tools/destroy.d.ts +4 -0
  240. package/dist/tools/destroy.js +188 -0
  241. package/dist/tools/detach.d.ts +4 -0
  242. package/dist/tools/detach.js +45 -0
  243. package/dist/tools/encore.d.ts +4 -0
  244. package/dist/tools/encore.js +31 -0
  245. package/dist/tools/ensemble.d.ts +32 -0
  246. package/dist/tools/ensemble.js +198 -0
  247. package/dist/tools/evaluate-gate.d.ts +3 -0
  248. package/dist/tools/evaluate-gate.js +32 -0
  249. package/dist/tools/fetch-state.d.ts +13 -0
  250. package/dist/tools/fetch-state.js +78 -0
  251. package/dist/tools/gates.d.ts +3 -0
  252. package/dist/tools/gates.js +41 -0
  253. package/dist/tools/helpers.d.ts +21 -0
  254. package/dist/tools/helpers.js +25 -0
  255. package/dist/tools/hosts.d.ts +4 -0
  256. package/dist/tools/hosts.js +40 -0
  257. package/dist/tools/listen.d.ts +3 -0
  258. package/dist/tools/listen.js +22 -0
  259. package/dist/tools/load-lineup.d.ts +5 -0
  260. package/dist/tools/load-lineup.js +381 -0
  261. package/dist/tools/migrate.d.ts +4 -0
  262. package/dist/tools/migrate.js +60 -0
  263. package/dist/tools/pause-ensemble.d.ts +4 -0
  264. package/dist/tools/pause-ensemble.js +58 -0
  265. package/dist/tools/pause.d.ts +4 -0
  266. package/dist/tools/pause.js +36 -0
  267. package/dist/tools/play.d.ts +4 -0
  268. package/dist/tools/play.js +57 -0
  269. package/dist/tools/quality-gate.d.ts +3 -0
  270. package/dist/tools/quality-gate.js +26 -0
  271. package/dist/tools/recall.d.ts +3 -0
  272. package/dist/tools/recall.js +32 -0
  273. package/dist/tools/recruit.d.ts +38 -0
  274. package/dist/tools/recruit.js +447 -0
  275. package/dist/tools/release.d.ts +4 -0
  276. package/dist/tools/release.js +98 -0
  277. package/dist/tools/report.d.ts +3 -0
  278. package/dist/tools/report.js +29 -0
  279. package/dist/tools/resolve.d.ts +1 -0
  280. package/dist/tools/resolve.js +7 -0
  281. package/dist/tools/restart.d.ts +35 -0
  282. package/dist/tools/restart.js +131 -0
  283. package/dist/tools/restore.d.ts +4 -0
  284. package/dist/tools/restore.js +107 -0
  285. package/dist/tools/resume-ensemble.d.ts +4 -0
  286. package/dist/tools/resume-ensemble.js +79 -0
  287. package/dist/tools/save-lineup.d.ts +4 -0
  288. package/dist/tools/save-lineup.js +36 -0
  289. package/dist/tools/save-state.d.ts +3 -0
  290. package/dist/tools/save-state.js +57 -0
  291. package/dist/tools/schedule.d.ts +4 -0
  292. package/dist/tools/schedule.js +152 -0
  293. package/dist/tools/schedules.d.ts +4 -0
  294. package/dist/tools/schedules.js +54 -0
  295. package/dist/tools/set-ensemble-description.d.ts +4 -0
  296. package/dist/tools/set-ensemble-description.js +37 -0
  297. package/dist/tools/set-name.d.ts +4 -0
  298. package/dist/tools/set-name.js +45 -0
  299. package/dist/tools/set-part.d.ts +3 -0
  300. package/dist/tools/set-part.js +20 -0
  301. package/dist/tools/shutdown.d.ts +4 -0
  302. package/dist/tools/shutdown.js +54 -0
  303. package/dist/tools/stage.d.ts +3 -0
  304. package/dist/tools/stage.js +28 -0
  305. package/dist/tools/stages.d.ts +3 -0
  306. package/dist/tools/stages.js +35 -0
  307. package/dist/tools/stop.d.ts +4 -0
  308. package/dist/tools/stop.js +29 -0
  309. package/dist/tools/unschedule.d.ts +4 -0
  310. package/dist/tools/unschedule.js +35 -0
  311. package/dist/tools/who-am-i.d.ts +3 -0
  312. package/dist/tools/who-am-i.js +34 -0
  313. package/dist/tools/worktree.d.ts +4 -0
  314. package/dist/tools/worktree.js +181 -0
  315. package/dist/tui/App.d.ts +85 -0
  316. package/dist/tui/App.js +1791 -0
  317. package/dist/tui/bootstrap-types.d.ts +46 -0
  318. package/dist/tui/bootstrap-types.js +7 -0
  319. package/dist/tui/client.d.ts +6 -0
  320. package/dist/tui/client.js +9 -0
  321. package/dist/tui/commands.d.ts +71 -0
  322. package/dist/tui/commands.js +1375 -0
  323. package/dist/tui/components/ActivityLog.d.ts +16 -0
  324. package/dist/tui/components/ActivityLog.js +36 -0
  325. package/dist/tui/components/ChatView.d.ts +35 -0
  326. package/dist/tui/components/ChatView.js +54 -0
  327. package/dist/tui/components/CommandOverlay.d.ts +15 -0
  328. package/dist/tui/components/CommandOverlay.js +34 -0
  329. package/dist/tui/components/CommandPalette.d.ts +21 -0
  330. package/dist/tui/components/CommandPalette.js +67 -0
  331. package/dist/tui/components/ConductorChat.d.ts +16 -0
  332. package/dist/tui/components/ConductorChat.js +32 -0
  333. package/dist/tui/components/ConversationStream.d.ts +114 -0
  334. package/dist/tui/components/ConversationStream.js +307 -0
  335. package/dist/tui/components/CreateEnsembleWizard.d.ts +19 -0
  336. package/dist/tui/components/CreateEnsembleWizard.js +223 -0
  337. package/dist/tui/components/DestroyConfirmModal.d.ts +17 -0
  338. package/dist/tui/components/DestroyConfirmModal.js +62 -0
  339. package/dist/tui/components/EnsembleListView.d.ts +14 -0
  340. package/dist/tui/components/EnsembleListView.js +32 -0
  341. package/dist/tui/components/EnsemblePanel.d.ts +12 -0
  342. package/dist/tui/components/EnsemblePanel.js +40 -0
  343. package/dist/tui/components/ErrorView.d.ts +31 -0
  344. package/dist/tui/components/ErrorView.js +129 -0
  345. package/dist/tui/components/HomeView.d.ts +54 -0
  346. package/dist/tui/components/HomeView.js +306 -0
  347. package/dist/tui/components/InputBar.d.ts +13 -0
  348. package/dist/tui/components/InputBar.js +58 -0
  349. package/dist/tui/components/LoadLineupModal.d.ts +18 -0
  350. package/dist/tui/components/LoadLineupModal.js +79 -0
  351. package/dist/tui/components/MainView.d.ts +21 -0
  352. package/dist/tui/components/MainView.js +107 -0
  353. package/dist/tui/components/NewEnsembleModal.d.ts +9 -0
  354. package/dist/tui/components/NewEnsembleModal.js +73 -0
  355. package/dist/tui/components/Picker.d.ts +23 -0
  356. package/dist/tui/components/Picker.js +70 -0
  357. package/dist/tui/components/PlayerDetailView.d.ts +26 -0
  358. package/dist/tui/components/PlayerDetailView.js +118 -0
  359. package/dist/tui/components/PromptArea.d.ts +50 -0
  360. package/dist/tui/components/PromptArea.js +303 -0
  361. package/dist/tui/components/RecruitWizard.d.ts +17 -0
  362. package/dist/tui/components/RecruitWizard.js +221 -0
  363. package/dist/tui/components/RestoreConfirmModal.d.ts +18 -0
  364. package/dist/tui/components/RestoreConfirmModal.js +71 -0
  365. package/dist/tui/components/ScheduleOverlay.d.ts +13 -0
  366. package/dist/tui/components/ScheduleOverlay.js +113 -0
  367. package/dist/tui/components/ScheduleWizard.d.ts +19 -0
  368. package/dist/tui/components/ScheduleWizard.js +259 -0
  369. package/dist/tui/components/Splash.d.ts +23 -0
  370. package/dist/tui/components/Splash.js +221 -0
  371. package/dist/tui/components/StatusBar.d.ts +48 -0
  372. package/dist/tui/components/StatusBar.js +128 -0
  373. package/dist/tui/components/StatusOverlay.d.ts +15 -0
  374. package/dist/tui/components/StatusOverlay.js +76 -0
  375. package/dist/tui/components/TitleBar.d.ts +10 -0
  376. package/dist/tui/components/TitleBar.js +21 -0
  377. package/dist/tui/components/TopBar.d.ts +12 -0
  378. package/dist/tui/components/TopBar.js +15 -0
  379. package/dist/tui/core-api.d.ts +26 -0
  380. package/dist/tui/core-api.js +67 -0
  381. package/dist/tui/hooks/useEnsembleDiscovery.d.ts +3 -0
  382. package/dist/tui/hooks/useEnsembleDiscovery.js +30 -0
  383. package/dist/tui/hooks/useMaestroPoller.d.ts +3 -0
  384. package/dist/tui/hooks/useMaestroPoller.js +36 -0
  385. package/dist/tui/hooks/useSendCommand.d.ts +7 -0
  386. package/dist/tui/hooks/useSendCommand.js +29 -0
  387. package/dist/tui/index.d.ts +15 -0
  388. package/dist/tui/index.js +156 -0
  389. package/dist/tui/ink-context.d.ts +18 -0
  390. package/dist/tui/ink-context.js +59 -0
  391. package/dist/tui/ink-loader.d.ts +26 -0
  392. package/dist/tui/ink-loader.js +42 -0
  393. package/dist/tui/removed-commands.d.ts +9 -0
  394. package/dist/tui/removed-commands.js +22 -0
  395. package/dist/tui/sse-handler.d.ts +52 -0
  396. package/dist/tui/sse-handler.js +157 -0
  397. package/dist/tui/store.d.ts +598 -0
  398. package/dist/tui/store.js +753 -0
  399. package/dist/tui/utils/format.d.ts +56 -0
  400. package/dist/tui/utils/format.js +155 -0
  401. package/dist/tui/utils/fullscreen.d.ts +23 -0
  402. package/dist/tui/utils/fullscreen.js +71 -0
  403. package/dist/tui/utils/history.d.ts +10 -0
  404. package/dist/tui/utils/history.js +85 -0
  405. package/dist/tui/utils/platform.d.ts +45 -0
  406. package/dist/tui/utils/platform.js +258 -0
  407. package/dist/tui/utils/theme.d.ts +21 -0
  408. package/dist/tui/utils/theme.js +24 -0
  409. package/dist/types.d.ts +1020 -0
  410. package/dist/types.js +39 -0
  411. package/dist/utils/attachment-format.d.ts +22 -0
  412. package/dist/utils/attachment-format.js +32 -0
  413. package/dist/utils/default-part.d.ts +43 -0
  414. package/dist/utils/default-part.js +104 -0
  415. package/dist/utils/duration.d.ts +30 -0
  416. package/dist/utils/duration.js +69 -0
  417. package/dist/utils/ensemble-ops.d.ts +61 -0
  418. package/dist/utils/ensemble-ops.js +77 -0
  419. package/dist/utils/format-hosts.d.ts +21 -0
  420. package/dist/utils/format-hosts.js +73 -0
  421. package/dist/utils/hosts.d.ts +113 -0
  422. package/dist/utils/hosts.js +265 -0
  423. package/dist/utils/parent-death-watchdog.d.ts +1 -0
  424. package/dist/utils/parent-death-watchdog.js +47 -0
  425. package/dist/utils/query-timeout.d.ts +103 -0
  426. package/dist/utils/query-timeout.js +113 -0
  427. package/dist/utils/recall-format.d.ts +78 -0
  428. package/dist/utils/recall-format.js +105 -0
  429. package/dist/utils/restore-format.d.ts +49 -0
  430. package/dist/utils/restore-format.js +91 -0
  431. package/dist/utils/safe-path.d.ts +10 -0
  432. package/dist/utils/safe-path.js +43 -0
  433. package/dist/utils/sdk-probe.d.ts +9 -0
  434. package/dist/utils/sdk-probe.js +45 -0
  435. package/dist/utils/search-attributes.d.ts +76 -0
  436. package/dist/utils/search-attributes.js +86 -0
  437. package/dist/utils/validation.d.ts +113 -0
  438. package/dist/utils/validation.js +163 -0
  439. package/dist/utils/visibility-deadline.d.ts +186 -0
  440. package/dist/utils/visibility-deadline.js +158 -0
  441. package/dist/utils/worktree.d.ts +103 -0
  442. package/dist/utils/worktree.js +327 -0
  443. package/dist/worker.d.ts +14 -0
  444. package/dist/worker.js +146 -0
  445. package/dist/workflows/attachment-math.d.ts +56 -0
  446. package/dist/workflows/attachment-math.js +47 -0
  447. package/dist/workflows/index.d.ts +3 -0
  448. package/dist/workflows/index.js +11 -0
  449. package/dist/workflows/maestro-signals.d.ts +217 -0
  450. package/dist/workflows/maestro-signals.js +155 -0
  451. package/dist/workflows/maestro.d.ts +3 -0
  452. package/dist/workflows/maestro.js +812 -0
  453. package/dist/workflows/scheduler-signals.d.ts +10 -0
  454. package/dist/workflows/scheduler-signals.js +14 -0
  455. package/dist/workflows/scheduler.d.ts +17 -0
  456. package/dist/workflows/scheduler.js +143 -0
  457. package/dist/workflows/session.d.ts +2 -0
  458. package/dist/workflows/session.js +1638 -0
  459. package/dist/workflows/signals.d.ts +297 -0
  460. package/dist/workflows/signals.js +239 -0
  461. package/examples/agents/tempo-composer.md +56 -0
  462. package/examples/agents/tempo-conductor.md +117 -0
  463. package/examples/agents/tempo-critic.md +73 -0
  464. package/examples/agents/tempo-improv.md +74 -0
  465. package/examples/agents/tempo-liner.md +75 -0
  466. package/examples/agents/tempo-roadie.md +61 -0
  467. package/examples/agents/tempo-soloist.md +71 -0
  468. package/examples/agents/tempo-tuner.md +94 -0
  469. package/examples/ensembles/tempo-big-band.yaml +146 -0
  470. package/examples/ensembles/tempo-dev-team.yaml +58 -0
  471. package/examples/ensembles/tempo-headless-jam.yaml +77 -0
  472. package/examples/ensembles/tempo-jam-session.yaml +41 -0
  473. package/examples/ensembles/tempo-mock-jam.yaml +79 -0
  474. package/examples/ensembles/tempo-review-squad.yaml +32 -0
  475. package/package.json +172 -0
  476. package/packaging/launchd/com.agent.tempo.plist +46 -0
  477. package/packaging/systemd/agent-tempo.service +32 -0
  478. package/packaging/windows/install-task.ps1 +71 -0
  479. package/scenarios/conductor-recruit-mock.yaml +33 -0
  480. package/scenarios/echo-roundtrip.yaml +15 -0
  481. package/scenarios/multi-player-handoff.yaml +38 -0
  482. package/scenarios/recruit-cascade.yaml +38 -0
  483. package/scenarios/two-player-conversation.yaml +33 -0
  484. package/workflow-bundle.js +14146 -0
package/dist/spawn.js ADDED
@@ -0,0 +1,747 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveIconPath = resolveIconPath;
4
+ exports.ensureWindowsTerminalProfile = ensureWindowsTerminalProfile;
5
+ exports.shellQuote = shellQuote;
6
+ exports.resolveClaudePath = resolveClaudePath;
7
+ exports.detectMacTerminal = detectMacTerminal;
8
+ exports.findLinuxTerminal = findLinuxTerminal;
9
+ exports.buildClaudeCommand = buildClaudeCommand;
10
+ exports.spawnInTerminal = spawnInTerminal;
11
+ exports.spawnCopilotBridge = spawnCopilotBridge;
12
+ exports.spawnMockAdapter = spawnMockAdapter;
13
+ exports.spawnClaudeApiAdapter = spawnClaudeApiAdapter;
14
+ exports.spawnOpenCodeAdapter = spawnOpenCodeAdapter;
15
+ exports.spawnClaudeCodeHeadlessAdapter = spawnClaudeCodeHeadlessAdapter;
16
+ const child_process_1 = require("child_process");
17
+ const fs_1 = require("fs");
18
+ const path_1 = require("path");
19
+ const os_1 = require("os");
20
+ const config_1 = require("./config");
21
+ const log = (...args) => console.error('[agent-tempo:spawn]', ...args);
22
+ /** Stable GUID for the agent-tempo Windows Terminal profile. */
23
+ const WT_PROFILE_GUID = '{c1a0d300-0e30-4000-a000-c1a0de00e300}';
24
+ const WT_PROFILE_NAME = 'agent-tempo';
25
+ /** Resolve the absolute path to the package's icon file (PNG for Windows Terminal). */
26
+ function resolveIconPath() {
27
+ // __dirname is src/ in dev or dist/ in production; assets/ is at the package root
28
+ const packageRoot = (0, path_1.resolve)(__dirname, '..');
29
+ return (0, path_1.join)(packageRoot, 'assets', 'icon-dark-32.png');
30
+ }
31
+ /**
32
+ * Strip // and /* comments from JSON-with-comments (JSONC), leaving strings intact.
33
+ * Handles escaped quotes inside strings correctly.
34
+ */
35
+ function stripJsonComments(text) {
36
+ let result = '';
37
+ let i = 0;
38
+ while (i < text.length) {
39
+ // String literal — copy verbatim until closing quote
40
+ if (text[i] === '"') {
41
+ result += '"';
42
+ i++;
43
+ while (i < text.length && text[i] !== '"') {
44
+ if (text[i] === '\\') {
45
+ result += text[i++];
46
+ } // skip escaped char
47
+ if (i < text.length) {
48
+ result += text[i++];
49
+ }
50
+ }
51
+ if (i < text.length) {
52
+ result += text[i++];
53
+ } // closing quote
54
+ // Line comment
55
+ }
56
+ else if (text[i] === '/' && text[i + 1] === '/') {
57
+ while (i < text.length && text[i] !== '\n')
58
+ i++;
59
+ // Block comment
60
+ }
61
+ else if (text[i] === '/' && text[i + 1] === '*') {
62
+ i += 2;
63
+ while (i < text.length && !(text[i] === '*' && text[i + 1] === '/'))
64
+ i++;
65
+ i += 2; // skip closing */
66
+ }
67
+ else {
68
+ result += text[i++];
69
+ }
70
+ }
71
+ return result;
72
+ }
73
+ /**
74
+ * Ensure a "agent-tempo" profile exists in Windows Terminal settings.json
75
+ * with our icon. Returns true if the profile is ready for use.
76
+ *
77
+ * Windows Terminal settings path:
78
+ * %LOCALAPPDATA%/Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/settings.json
79
+ */
80
+ function ensureWindowsTerminalProfile() {
81
+ if (process.platform !== 'win32')
82
+ return false;
83
+ const localAppData = process.env.LOCALAPPDATA;
84
+ if (!localAppData)
85
+ return false;
86
+ const settingsPath = (0, path_1.join)(localAppData, 'Packages', 'Microsoft.WindowsTerminal_8wekyb3d8bbwe', 'LocalState', 'settings.json');
87
+ if (!(0, fs_1.existsSync)(settingsPath)) {
88
+ log('Windows Terminal settings.json not found at', settingsPath);
89
+ return false;
90
+ }
91
+ try {
92
+ const raw = (0, fs_1.readFileSync)(settingsPath, 'utf8');
93
+ // Windows Terminal settings.json may contain comments — strip them for JSON.parse.
94
+ // Naive regex would eat "//" inside strings (e.g., URLs). Walk char-by-char instead.
95
+ const settings = JSON.parse(stripJsonComments(raw));
96
+ if (!settings.profiles?.list)
97
+ return false;
98
+ const iconPath = resolveIconPath().replace(/\\/g, '/');
99
+ if (!(0, fs_1.existsSync)(iconPath.replace(/\//g, '\\'))) {
100
+ log('Icon file not found at', iconPath);
101
+ return false;
102
+ }
103
+ const profiles = settings.profiles.list;
104
+ // Check if our profile already exists (by GUID or name)
105
+ const existing = profiles.find((p) => p.guid === WT_PROFILE_GUID || p.name === WT_PROFILE_NAME);
106
+ if (existing) {
107
+ // Update icon + closeOnExit if they changed (e.g. package moved, or pre-#165 profile)
108
+ let dirty = false;
109
+ if (existing.icon !== iconPath) {
110
+ existing.icon = iconPath;
111
+ dirty = true;
112
+ }
113
+ // Force-killed sessions exit with code 1; "always" ensures WT closes the tab
114
+ // instead of showing "process exited" with a stale prompt.
115
+ if (existing.closeOnExit !== 'always') {
116
+ existing.closeOnExit = 'always';
117
+ dirty = true;
118
+ }
119
+ if (dirty) {
120
+ (0, fs_1.writeFileSync)(settingsPath, JSON.stringify(settings, null, 4) + '\n');
121
+ log('Updated agent-tempo profile in Windows Terminal');
122
+ }
123
+ return true;
124
+ }
125
+ // Add new profile
126
+ profiles.push({
127
+ guid: WT_PROFILE_GUID,
128
+ name: WT_PROFILE_NAME,
129
+ commandline: 'cmd.exe',
130
+ icon: iconPath,
131
+ hidden: true, // Hide from dropdown — only used programmatically
132
+ closeOnExit: 'always', // Force-killed sessions exit non-zero; auto-close the tab
133
+ });
134
+ // Write back with original formatting style (4-space indent to match WT default)
135
+ (0, fs_1.writeFileSync)(settingsPath, JSON.stringify(settings, null, 4) + '\n');
136
+ log('Created agent-tempo profile in Windows Terminal with icon:', iconPath);
137
+ return true;
138
+ }
139
+ catch (e) {
140
+ log('Failed to update Windows Terminal settings:', e);
141
+ return false;
142
+ }
143
+ }
144
+ /** POSIX shell-safe single-quoting (works in bash, zsh, and fish) */
145
+ function shellQuote(s) {
146
+ return `'${s.replace(/'/g, "'\\''")}'`;
147
+ }
148
+ /**
149
+ * Resolve the path to the `claude` binary.
150
+ *
151
+ * Resolution order:
152
+ * 1. `configBin` parameter (from Config.claudeBin — env var or config file)
153
+ * 2. `AGENT_TEMPO_CLAUDE_BIN` env var (checked directly for spawned processes that
154
+ * may not have full config resolution, e.g., activities)
155
+ * 3. `which claude` / `where claude` lookup
156
+ * 4. Bare `claude` fallback
157
+ */
158
+ function resolveClaudePath(configBin) {
159
+ // Priority 1: explicit config value
160
+ if (configBin)
161
+ return configBin;
162
+ // Priority 2: env var (may be set by parent process)
163
+ const envBin = process.env.AGENT_TEMPO_CLAUDE_BIN;
164
+ if (envBin)
165
+ return envBin;
166
+ // Priority 3: which/where lookup
167
+ const cmd = process.platform === 'win32' ? 'where' : 'which';
168
+ try {
169
+ return (0, child_process_1.execFileSync)(cmd, ['claude'], { encoding: 'utf8' }).trim().split('\n')[0];
170
+ }
171
+ catch {
172
+ return 'claude';
173
+ }
174
+ }
175
+ /**
176
+ * Detect the macOS terminal the user is actually running in.
177
+ *
178
+ * Priority:
179
+ * 1. TERM_PROGRAM env var (most reliable when available — set by the terminal itself)
180
+ * 2. Check frontmost app via AppleScript (detects what the user is actively using)
181
+ * 3. Fall back to Terminal.app
182
+ */
183
+ function detectMacTerminal() {
184
+ const termProgram = (process.env.TERM_PROGRAM || '').toLowerCase();
185
+ if (termProgram === 'ghostty')
186
+ return 'ghostty';
187
+ if (termProgram === 'iterm.app' || termProgram === 'iterm2')
188
+ return 'iterm2';
189
+ if (termProgram === 'apple_terminal')
190
+ return 'terminal';
191
+ // MCP servers may not inherit TERM_PROGRAM — check which terminal app is running
192
+ // Prefer frontmost app detection over pgrep to avoid false positives
193
+ try {
194
+ const frontApp = (0, child_process_1.execFileSync)('osascript', ['-e',
195
+ 'tell application "System Events" to get name of first application process whose frontmost is true',
196
+ ], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim().toLowerCase();
197
+ if (frontApp === 'ghostty')
198
+ return 'ghostty';
199
+ if (frontApp === 'iterm2')
200
+ return 'iterm2';
201
+ if (frontApp === 'terminal')
202
+ return 'terminal';
203
+ }
204
+ catch { /* ignore */ }
205
+ // Last resort: check running processes
206
+ try {
207
+ (0, child_process_1.execFileSync)('pgrep', ['-x', 'ghostty'], { stdio: 'ignore' });
208
+ return 'ghostty';
209
+ }
210
+ catch { /* not running */ }
211
+ try {
212
+ (0, child_process_1.execFileSync)('pgrep', ['-x', 'iTerm2'], { stdio: 'ignore' });
213
+ return 'iterm2';
214
+ }
215
+ catch { /* not running */ }
216
+ return 'terminal';
217
+ }
218
+ /** Find the first available terminal emulator on Linux */
219
+ function findLinuxTerminal() {
220
+ const candidates = ['gnome-terminal', 'konsole', 'x-terminal-emulator', 'xfce4-terminal', 'xterm'];
221
+ for (const term of candidates) {
222
+ try {
223
+ (0, child_process_1.execFileSync)('which', [term], { stdio: 'ignore' });
224
+ return term;
225
+ }
226
+ catch {
227
+ // not found, try next
228
+ }
229
+ }
230
+ return null;
231
+ }
232
+ /**
233
+ * Build a shell command string that sets env vars and runs claude.
234
+ * Uses inline `KEY=val` syntax which works in bash, zsh, AND fish.
235
+ */
236
+ function buildClaudeCommand(claudeBin, claudeArgs, envVars) {
237
+ const envInline = Object.entries(envVars)
238
+ .map(([k, v]) => `${k}=${shellQuote(v)}`)
239
+ .join(' ');
240
+ // Quote the binary path if it contains spaces (e.g., "C:\Program Files\...")
241
+ const quotedBin = claudeBin.includes(' ') ? shellQuote(claudeBin) : claudeBin;
242
+ const args = claudeArgs.map(a => shellQuote(a)).join(' ');
243
+ return envInline ? `${envInline} ${quotedBin} ${args}` : `${quotedBin} ${args}`;
244
+ }
245
+ /**
246
+ * Spawn a Claude Code session in a visible terminal window.
247
+ *
248
+ * Strategy per terminal:
249
+ * - Ghostty: `initial input` into a normal window (preserves full shell env)
250
+ * - iTerm2: `write text` via AppleScript (same approach)
251
+ * - Terminal.app: .command script with shell profile sourcing
252
+ * - Windows: shell:true with env vars
253
+ * - Linux: terminal emulator with -e flag
254
+ */
255
+ function spawnInTerminal(claudeArgs, workDir, envVars, options) {
256
+ const claudeBin = resolveClaudePath(options?.claudeBin);
257
+ const claudeInvocation = buildClaudeCommand(claudeBin, claudeArgs, envVars);
258
+ if (process.platform === 'darwin') {
259
+ const detected = detectMacTerminal();
260
+ log(`Terminal detection: TERM_PROGRAM=${JSON.stringify(process.env.TERM_PROGRAM)}, detected=${detected}`);
261
+ if (detected === 'ghostty') {
262
+ // Append `; exit` so the wrapping shell exits when claude does (clean or killed).
263
+ // Without it, claude exit returns control to the shell prompt and the tab lingers —
264
+ // parity with the Windows WT `closeOnExit: 'always'` + parent-walk fix from #166.
265
+ const osaScript = `
266
+ tell application "Ghostty"
267
+ set cfg to new surface configuration
268
+ set initial working directory of cfg to ${JSON.stringify(workDir)}
269
+ set initial input of cfg to ${JSON.stringify(claudeInvocation + '; exit\n')}
270
+ set win to new window with configuration cfg
271
+ end tell`;
272
+ log('Using Ghostty initial-input path');
273
+ const child = (0, child_process_1.spawn)('osascript', ['-e', osaScript], {
274
+ detached: true, stdio: ['ignore', 'pipe', 'pipe'],
275
+ });
276
+ child.stderr?.on('data', (d) => log('osascript stderr:', d.toString()));
277
+ child.stdout?.on('data', (d) => log('osascript stdout:', d.toString()));
278
+ child.unref();
279
+ return { pid: child.pid };
280
+ }
281
+ if (detected === 'iterm2') {
282
+ // Append `; exit` so the wrapping shell exits when claude does. `;` rather than
283
+ // `&&` so exit runs regardless of claude's exit code (force-kill returns non-zero).
284
+ // JSON.stringify embeds the full shell command as a properly-escaped string literal
285
+ // so any `"` or `\` in paths/args doesn't break the AppleScript parser. Parity with
286
+ // the Ghostty path above.
287
+ const shellCmd = `cd ${shellQuote(workDir)} && ${claudeInvocation} ; exit`;
288
+ const osaScript = `
289
+ tell application "iTerm2"
290
+ set newWindow to (create window with default profile)
291
+ tell current session of newWindow
292
+ write text ${JSON.stringify(shellCmd)}
293
+ end tell
294
+ end tell`;
295
+ log('Using iTerm2 write-text path');
296
+ const child = (0, child_process_1.spawn)('osascript', ['-e', osaScript], {
297
+ detached: true, stdio: ['ignore', 'pipe', 'pipe'],
298
+ });
299
+ child.stderr?.on('data', (d) => log('osascript stderr:', d.toString()));
300
+ child.unref();
301
+ return { pid: child.pid };
302
+ }
303
+ // Terminal.app: .command file with shell profile sourcing
304
+ const userShell = process.env.SHELL || '/bin/zsh';
305
+ const scriptPath = (0, path_1.join)((0, os_1.tmpdir)(), `agent-tempo-recruit-${Date.now()}.command`);
306
+ let profileSource;
307
+ if (userShell.endsWith('/fish')) {
308
+ profileSource = `exec fish -c "cd ${shellQuote(workDir)} && ${claudeInvocation}"`;
309
+ }
310
+ else {
311
+ profileSource = [
312
+ `[ -f "$HOME/.zshrc" ] && source "$HOME/.zshrc" 2>/dev/null`,
313
+ `[ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc" 2>/dev/null`,
314
+ `[ -f "$HOME/.nvm/nvm.sh" ] && source "$HOME/.nvm/nvm.sh" 2>/dev/null`,
315
+ `command -v fnm >/dev/null && eval "$(fnm env)" 2>/dev/null`,
316
+ ].join('\n');
317
+ }
318
+ const envExports = Object.entries(envVars)
319
+ .map(([k, v]) => `export ${k}=${shellQuote(v)}`)
320
+ .join('\n');
321
+ const lines = [
322
+ '#!/bin/bash',
323
+ // Env vars BEFORE profile sourcing — profiles that call `exec` (e.g. oh-my-zsh)
324
+ // would otherwise lose the exports and the claude command (#98)
325
+ envExports,
326
+ profileSource,
327
+ `cd ${shellQuote(workDir)}`,
328
+ // `exec` so the shell is replaced by claude — when claude exits (clean or killed),
329
+ // the script process ends and Terminal.app closes the window per its settings.
330
+ // Without `exec`, bash waits for claude and then returns to prompt, leaving the
331
+ // window open. Parity with the WT `closeOnExit: 'always'` fix from #166.
332
+ `exec ${shellQuote(claudeBin)} ${claudeArgs.map(a => shellQuote(a)).join(' ')}`,
333
+ ];
334
+ (0, fs_1.writeFileSync)(scriptPath, lines.join('\n') + '\n', { mode: 0o755 });
335
+ log('Using Terminal.app .command path:', scriptPath);
336
+ const child = (0, child_process_1.spawn)('open', [scriptPath], { detached: true, stdio: 'ignore' });
337
+ child.unref();
338
+ return { pid: child.pid };
339
+ }
340
+ if (process.platform === 'win32') {
341
+ // Detect Windows Terminal: WT_SESSION env var is set when running inside it.
342
+ // wt.exe is a UWP app execution alias that Node.js can't resolve directly,
343
+ // but `cmd.exe /c start "" wt.exe ...` works through the Windows shell.
344
+ const hasWt = Boolean(process.env.WT_SESSION);
345
+ if (hasWt) {
346
+ // Extract player name from claudeArgs (-n <name>) for tab title
347
+ const nameIdx = claudeArgs.indexOf('-n');
348
+ const tabTitle = nameIdx !== -1 && nameIdx + 1 < claudeArgs.length
349
+ ? claudeArgs[nameIdx + 1]
350
+ : 'agent-tempo';
351
+ // Ensure our profile with icon exists in Windows Terminal settings
352
+ const hasProfile = ensureWindowsTerminalProfile();
353
+ // Build inline env var assignments for cmd /c since wt.exe spawns
354
+ // a new process that won't inherit our env.
355
+ // Escape values for cmd.exe: wrap in quotes and escape inner special chars.
356
+ const cmdEscape = (s) => s.replace(/([&|<>^"%])/g, '^$1');
357
+ const setCmds = Object.entries(envVars)
358
+ .map(([k, v]) => `set "${k}=${cmdEscape(v)}"`)
359
+ .join(' && ');
360
+ // Quote the binary path if it contains spaces (e.g., "C:\Program Files\...")
361
+ const quotedWinBin = claudeBin.includes(' ') ? `"${cmdEscape(claudeBin)}"` : cmdEscape(claudeBin);
362
+ const claudeCmd = `${quotedWinBin} ${claudeArgs.map(a => `"${cmdEscape(a)}"`).join(' ')}`;
363
+ const innerCmd = setCmds
364
+ ? `${setCmds} && ${claudeCmd}`
365
+ : claudeCmd;
366
+ // Use `cmd.exe /c start "" wt.exe ...` to resolve the UWP app alias
367
+ // When our profile exists, use --profile to get the tab icon
368
+ const wtArgs = [
369
+ '/c', 'start', '',
370
+ 'wt.exe', '-w', '0',
371
+ 'new-tab',
372
+ ...(hasProfile ? ['--profile', WT_PROFILE_NAME] : []),
373
+ '--title', tabTitle,
374
+ '-d', workDir,
375
+ 'cmd', '/k', innerCmd,
376
+ ];
377
+ const child = (0, child_process_1.spawn)('cmd.exe', wtArgs, {
378
+ detached: true,
379
+ stdio: 'ignore',
380
+ });
381
+ child.unref();
382
+ return { pid: child.pid };
383
+ }
384
+ // Fallback: open a new cmd.exe window
385
+ const child = (0, child_process_1.spawn)('cmd.exe', ['/c', 'start', '""', claudeBin, ...claudeArgs], {
386
+ cwd: workDir,
387
+ detached: true,
388
+ stdio: 'ignore',
389
+ env: { ...process.env, ...envVars },
390
+ });
391
+ child.unref();
392
+ return { pid: child.pid };
393
+ }
394
+ // Linux
395
+ const envExports = Object.entries(envVars)
396
+ .map(([k, v]) => `export ${k}=${shellQuote(v)}`)
397
+ .join('; ');
398
+ const fullCmd = `${envExports}; cd ${shellQuote(workDir)} && ${shellQuote(claudeBin)} ${claudeArgs.map(a => shellQuote(a)).join(' ')}`;
399
+ const terminal = findLinuxTerminal();
400
+ if (!terminal) {
401
+ log('No terminal emulator found on Linux, falling back to headless spawn');
402
+ const child = (0, child_process_1.spawn)('bash', ['-c', fullCmd], { detached: true, stdio: 'ignore' });
403
+ child.unref();
404
+ return { pid: child.pid };
405
+ }
406
+ let child;
407
+ if (terminal === 'gnome-terminal') {
408
+ child = (0, child_process_1.spawn)(terminal, ['--', 'bash', '-c', fullCmd], { detached: true, stdio: 'ignore' });
409
+ }
410
+ else {
411
+ child = (0, child_process_1.spawn)(terminal, ['-e', 'bash', '-c', fullCmd], { detached: true, stdio: 'ignore' });
412
+ }
413
+ child.unref();
414
+ return { pid: child.pid };
415
+ }
416
+ /**
417
+ * Resolve the path to the compiled copilot bridge adapter entry point.
418
+ * In dev (ts-node), returns a ts-node command; in production, returns the dist path.
419
+ *
420
+ * PR-B (v0.25 rebuild step 2/7): the bridge moved from `src/copilot-bridge.ts`
421
+ * to `src/adapters/copilot/adapter.ts`. Behavior unchanged.
422
+ */
423
+ function resolveBridgePath() {
424
+ const isDev = __filename.endsWith('.ts');
425
+ if (isDev) {
426
+ return { cmd: 'npx', args: ['ts-node', (0, path_1.resolve)(__dirname, 'adapters', 'copilot', 'adapter.ts')] };
427
+ }
428
+ return { cmd: 'node', args: [(0, path_1.resolve)(__dirname, 'adapters', 'copilot', 'adapter.js')] };
429
+ }
430
+ /**
431
+ * Spawn a copilot bridge as a detached headless subprocess.
432
+ * Sets up log file, PID file, and all required env vars.
433
+ */
434
+ function spawnCopilotBridge(opts) {
435
+ const { cmd, args } = resolveBridgePath();
436
+ const logDirPath = opts.logDir || (0, path_1.join)(opts.workDir, 'logs');
437
+ const logName = opts.name || `copilot-${Date.now()}`;
438
+ const logPath = (0, path_1.join)(logDirPath, `${logName}.log`);
439
+ const pidPath = (0, path_1.join)(logDirPath, `${logName}.pid`);
440
+ (0, fs_1.mkdirSync)(logDirPath, { recursive: true });
441
+ const logFd = (0, fs_1.openSync)(logPath, 'a');
442
+ let child;
443
+ try {
444
+ child = (0, child_process_1.spawn)(cmd, args, {
445
+ cwd: opts.workDir,
446
+ detached: true,
447
+ stdio: ['ignore', logFd, logFd],
448
+ env: {
449
+ ...process.env,
450
+ [config_1.ENV.ENSEMBLE]: opts.ensemble,
451
+ [config_1.ENV.BRIDGE_NAME]: opts.name,
452
+ [config_1.ENV.PLAYER_NAME]: '', // Clear parent's player name so child uses BRIDGE_NAME
453
+ [config_1.ENV.BRIDGE_MODE]: '', // Clear parent's bridge mode
454
+ [config_1.ENV.TEMPORAL_ADDRESS]: opts.temporalAddress,
455
+ [config_1.ENV.CONDUCTOR]: opts.isConductor ? 'true' : '',
456
+ // Forward Temporal connection settings so child processes can connect
457
+ ...(opts.temporalNamespace ? { [config_1.ENV.TEMPORAL_NAMESPACE]: opts.temporalNamespace } : {}),
458
+ ...(opts.temporalApiKey ? { [config_1.ENV.TEMPORAL_API_KEY]: opts.temporalApiKey } : {}),
459
+ ...(opts.temporalTlsCertPath ? { [config_1.ENV.TEMPORAL_TLS_CERT_PATH]: opts.temporalTlsCertPath } : {}),
460
+ ...(opts.temporalTlsKeyPath ? { [config_1.ENV.TEMPORAL_TLS_KEY_PATH]: opts.temporalTlsKeyPath } : {}),
461
+ ...(opts.sessionId ? { [config_1.ENV.BRIDGE_SESSION_ID]: opts.sessionId } : {}),
462
+ // PR-D attachment handoff — renew rather than fresh-claim in startV2Lifecycle.
463
+ ...(opts.attachmentId ? { [config_1.ENV.ATTACHMENT_ID]: opts.attachmentId } : {}),
464
+ ...(opts.attachmentRunId ? { [config_1.ENV.ATTACHMENT_RUN_ID]: opts.attachmentRunId } : {}),
465
+ ...(opts.adapterId ? { [config_1.ENV.ADAPTER_ID]: opts.adapterId } : {}),
466
+ },
467
+ });
468
+ child.unref();
469
+ }
470
+ finally {
471
+ (0, fs_1.closeSync)(logFd);
472
+ }
473
+ if (child.pid != null) {
474
+ (0, fs_1.writeFileSync)(pidPath, String(child.pid));
475
+ }
476
+ log(`Spawned copilot-bridge (pid ${child.pid}) in ${opts.workDir} as "${opts.name}"`);
477
+ return { pid: child.pid, logPath, pidPath };
478
+ }
479
+ /**
480
+ * Resolve the path to the mock adapter entry point. Mirrors
481
+ * {@link resolveBridgePath} so dev (ts-node) and prod (compiled .js) both
482
+ * launch the same code through the same `require.main === module` gate.
483
+ */
484
+ function resolveMockAdapterPath() {
485
+ const isDev = __filename.endsWith('.ts');
486
+ if (isDev) {
487
+ return { cmd: 'npx', args: ['ts-node', (0, path_1.resolve)(__dirname, 'adapters', 'mock', 'adapter.ts')] };
488
+ }
489
+ return { cmd: 'node', args: [(0, path_1.resolve)(__dirname, 'adapters', 'mock', 'adapter.js')] };
490
+ }
491
+ /**
492
+ * Spawn a mock adapter subprocess. Headless — no terminal window, no
493
+ * "trust this folder" prompt — which is the whole point of the mock for
494
+ * autonomous validation harnesses (ADR 0014 §4.7).
495
+ */
496
+ function spawnMockAdapter(opts) {
497
+ const { cmd, args } = resolveMockAdapterPath();
498
+ const logDirPath = opts.logDir || (0, path_1.join)(opts.workDir, 'logs');
499
+ const logName = opts.name || `mock-${Date.now()}`;
500
+ const logPath = (0, path_1.join)(logDirPath, `${logName}.log`);
501
+ const pidPath = (0, path_1.join)(logDirPath, `${logName}.pid`);
502
+ (0, fs_1.mkdirSync)(logDirPath, { recursive: true });
503
+ const logFd = (0, fs_1.openSync)(logPath, 'a');
504
+ let child;
505
+ try {
506
+ child = (0, child_process_1.spawn)(cmd, args, {
507
+ cwd: opts.workDir,
508
+ detached: true,
509
+ stdio: ['ignore', logFd, logFd],
510
+ env: {
511
+ ...process.env,
512
+ [config_1.ENV.ENSEMBLE]: opts.ensemble,
513
+ [config_1.ENV.PLAYER_NAME]: opts.name,
514
+ [config_1.ENV.CONDUCTOR]: opts.isConductor ? 'true' : '',
515
+ [config_1.ENV.TEMPORAL_ADDRESS]: opts.temporalAddress,
516
+ // Forward Temporal connection settings so the subprocess can connect.
517
+ ...(opts.temporalNamespace ? { [config_1.ENV.TEMPORAL_NAMESPACE]: opts.temporalNamespace } : {}),
518
+ ...(opts.temporalApiKey ? { [config_1.ENV.TEMPORAL_API_KEY]: opts.temporalApiKey } : {}),
519
+ ...(opts.temporalTlsCertPath ? { [config_1.ENV.TEMPORAL_TLS_CERT_PATH]: opts.temporalTlsCertPath } : {}),
520
+ ...(opts.temporalTlsKeyPath ? { [config_1.ENV.TEMPORAL_TLS_KEY_PATH]: opts.temporalTlsKeyPath } : {}),
521
+ // Mock-specific knobs.
522
+ AGENT_TEMPO_MOCK_MODE: opts.mockMode ?? 'echo',
523
+ ...(opts.mockScenario ? { AGENT_TEMPO_MOCK_SCENARIO: opts.mockScenario } : {}),
524
+ // Attachment handoff — adapter renews via startV2Lifecycle.
525
+ ...(opts.attachmentId ? { [config_1.ENV.ATTACHMENT_ID]: opts.attachmentId } : {}),
526
+ ...(opts.attachmentRunId ? { [config_1.ENV.ATTACHMENT_RUN_ID]: opts.attachmentRunId } : {}),
527
+ ...(opts.adapterId ? { [config_1.ENV.ADAPTER_ID]: opts.adapterId } : {}),
528
+ },
529
+ });
530
+ child.unref();
531
+ }
532
+ finally {
533
+ (0, fs_1.closeSync)(logFd);
534
+ }
535
+ if (child.pid != null) {
536
+ (0, fs_1.writeFileSync)(pidPath, String(child.pid));
537
+ }
538
+ log(`Spawned mock adapter (pid ${child.pid}) in ${opts.workDir} as "${opts.name}" (mode=${opts.mockMode ?? 'echo'})`);
539
+ return { pid: child.pid, logPath, pidPath };
540
+ }
541
+ /**
542
+ * Resolve the path to the claude-api adapter entry point. Mirrors
543
+ * {@link resolveBridgePath} so dev (ts-node) and prod (compiled .js) both
544
+ * launch the same code through the same `require.main === module` gate.
545
+ */
546
+ function resolveClaudeApiPath() {
547
+ const isDev = __filename.endsWith('.ts');
548
+ if (isDev) {
549
+ return { cmd: 'npx', args: ['ts-node', (0, path_1.resolve)(__dirname, 'adapters', 'claude-api', 'adapter.ts')] };
550
+ }
551
+ return { cmd: 'node', args: [(0, path_1.resolve)(__dirname, 'adapters', 'claude-api', 'adapter.js')] };
552
+ }
553
+ /**
554
+ * Spawn the claude-api adapter as a detached headless subprocess.
555
+ *
556
+ * Mirrors {@link spawnCopilotBridge} — no TTY, log + PID files in
557
+ * `logs/<name>.log` and `logs/<name>.pid`, env vars carry identity +
558
+ * Temporal connection settings + optional attachment-handoff. The adapter
559
+ * resolves the LLM model from `AGENT_TEMPO_API_MODEL` (set here when
560
+ * `opts.model` is provided) or falls back to the constants-pinned default
561
+ * (`claude-opus-4-7`) inside the adapter's `run()`. `ANTHROPIC_API_KEY`
562
+ * is inherited from the parent's env (recruit pre-flight checks it).
563
+ */
564
+ function spawnClaudeApiAdapter(opts) {
565
+ const { cmd, args } = resolveClaudeApiPath();
566
+ const logDirPath = opts.logDir || (0, path_1.join)(opts.workDir, 'logs');
567
+ const logName = opts.name || `claude-api-${Date.now()}`;
568
+ const logPath = (0, path_1.join)(logDirPath, `${logName}.log`);
569
+ const pidPath = (0, path_1.join)(logDirPath, `${logName}.pid`);
570
+ (0, fs_1.mkdirSync)(logDirPath, { recursive: true });
571
+ const logFd = (0, fs_1.openSync)(logPath, 'a');
572
+ let child;
573
+ try {
574
+ child = (0, child_process_1.spawn)(cmd, args, {
575
+ cwd: opts.workDir,
576
+ detached: true,
577
+ stdio: ['ignore', logFd, logFd],
578
+ env: {
579
+ ...process.env,
580
+ [config_1.ENV.ENSEMBLE]: opts.ensemble,
581
+ [config_1.ENV.PLAYER_NAME]: opts.name,
582
+ [config_1.ENV.CONDUCTOR]: opts.isConductor ? 'true' : '',
583
+ [config_1.ENV.TEMPORAL_ADDRESS]: opts.temporalAddress,
584
+ // Forward Temporal connection settings so the subprocess can connect.
585
+ ...(opts.temporalNamespace ? { [config_1.ENV.TEMPORAL_NAMESPACE]: opts.temporalNamespace } : {}),
586
+ ...(opts.temporalApiKey ? { [config_1.ENV.TEMPORAL_API_KEY]: opts.temporalApiKey } : {}),
587
+ ...(opts.temporalTlsCertPath ? { [config_1.ENV.TEMPORAL_TLS_CERT_PATH]: opts.temporalTlsCertPath } : {}),
588
+ ...(opts.temporalTlsKeyPath ? { [config_1.ENV.TEMPORAL_TLS_KEY_PATH]: opts.temporalTlsKeyPath } : {}),
589
+ // Model selection: recruit-arg → AGENT_TEMPO_API_MODEL → in-adapter default.
590
+ ...(opts.model ? { [config_1.ENV.API_MODEL]: opts.model } : {}),
591
+ // Attachment handoff — adapter renews via startV2Lifecycle.
592
+ ...(opts.attachmentId ? { [config_1.ENV.ATTACHMENT_ID]: opts.attachmentId } : {}),
593
+ ...(opts.attachmentRunId ? { [config_1.ENV.ATTACHMENT_RUN_ID]: opts.attachmentRunId } : {}),
594
+ ...(opts.adapterId ? { [config_1.ENV.ADAPTER_ID]: opts.adapterId } : {}),
595
+ },
596
+ });
597
+ child.unref();
598
+ }
599
+ finally {
600
+ (0, fs_1.closeSync)(logFd);
601
+ }
602
+ if (child.pid != null) {
603
+ (0, fs_1.writeFileSync)(pidPath, String(child.pid));
604
+ }
605
+ log(`Spawned claude-api adapter (pid ${child.pid}) in ${opts.workDir} as "${opts.name}"${opts.model ? ` (model=${opts.model})` : ''}${opts.attachmentId ? ` (attachmentId=${opts.attachmentId})` : ''}`);
606
+ return { pid: child.pid, logPath, pidPath };
607
+ }
608
+ /**
609
+ * Resolve the path to the opencode adapter entry point. Mirrors
610
+ * {@link resolveClaudeApiPath} so dev (ts-node) and prod (compiled .js)
611
+ * both launch the same code through the same `require.main === module` gate.
612
+ */
613
+ function resolveOpenCodePath() {
614
+ const isDev = __filename.endsWith('.ts');
615
+ if (isDev) {
616
+ return { cmd: 'npx', args: ['ts-node', (0, path_1.resolve)(__dirname, 'adapters', 'opencode', 'adapter.ts')] };
617
+ }
618
+ return { cmd: 'node', args: [(0, path_1.resolve)(__dirname, 'adapters', 'opencode', 'adapter.js')] };
619
+ }
620
+ /**
621
+ * Spawn the opencode adapter as a detached headless subprocess.
622
+ *
623
+ * Pattern matches {@link spawnClaudeApiAdapter} — no TTY, log + PID files
624
+ * in `logs/<name>.log` and `logs/<name>.pid`, env vars carry identity +
625
+ * Temporal connection settings + optional attachment-handoff. Provider
626
+ * env vars (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, …) are inherited
627
+ * from the parent's env unchanged — OpenCode reads whichever ones the
628
+ * `model`'s prefix maps to (recruit pre-flight does NOT validate any
629
+ * specific provider key since the model is opaque pass-through).
630
+ */
631
+ function spawnOpenCodeAdapter(opts) {
632
+ const { cmd, args } = resolveOpenCodePath();
633
+ const logDirPath = opts.logDir || (0, path_1.join)(opts.workDir, 'logs');
634
+ const logName = opts.name || `opencode-${Date.now()}`;
635
+ const logPath = (0, path_1.join)(logDirPath, `${logName}.log`);
636
+ const pidPath = (0, path_1.join)(logDirPath, `${logName}.pid`);
637
+ (0, fs_1.mkdirSync)(logDirPath, { recursive: true });
638
+ const logFd = (0, fs_1.openSync)(logPath, 'a');
639
+ let child;
640
+ try {
641
+ child = (0, child_process_1.spawn)(cmd, args, {
642
+ cwd: opts.workDir,
643
+ detached: true,
644
+ stdio: ['ignore', logFd, logFd],
645
+ env: {
646
+ ...process.env,
647
+ [config_1.ENV.ENSEMBLE]: opts.ensemble,
648
+ [config_1.ENV.PLAYER_NAME]: opts.name,
649
+ [config_1.ENV.CONDUCTOR]: opts.isConductor ? 'true' : '',
650
+ [config_1.ENV.TEMPORAL_ADDRESS]: opts.temporalAddress,
651
+ ...(opts.temporalNamespace ? { [config_1.ENV.TEMPORAL_NAMESPACE]: opts.temporalNamespace } : {}),
652
+ ...(opts.temporalApiKey ? { [config_1.ENV.TEMPORAL_API_KEY]: opts.temporalApiKey } : {}),
653
+ ...(opts.temporalTlsCertPath ? { [config_1.ENV.TEMPORAL_TLS_CERT_PATH]: opts.temporalTlsCertPath } : {}),
654
+ ...(opts.temporalTlsKeyPath ? { [config_1.ENV.TEMPORAL_TLS_KEY_PATH]: opts.temporalTlsKeyPath } : {}),
655
+ // Model selection: recruit-arg → AGENT_TEMPO_OPENCODE_MODEL → in-adapter default.
656
+ ...(opts.model ? { [config_1.ENV.OPENCODE_MODEL]: opts.model } : {}),
657
+ // Attachment handoff — adapter renews via startV2Lifecycle.
658
+ ...(opts.attachmentId ? { [config_1.ENV.ATTACHMENT_ID]: opts.attachmentId } : {}),
659
+ ...(opts.attachmentRunId ? { [config_1.ENV.ATTACHMENT_RUN_ID]: opts.attachmentRunId } : {}),
660
+ ...(opts.adapterId ? { [config_1.ENV.ADAPTER_ID]: opts.adapterId } : {}),
661
+ },
662
+ });
663
+ child.unref();
664
+ }
665
+ finally {
666
+ (0, fs_1.closeSync)(logFd);
667
+ }
668
+ if (child.pid != null) {
669
+ (0, fs_1.writeFileSync)(pidPath, String(child.pid));
670
+ }
671
+ log(`Spawned opencode adapter (pid ${child.pid}) in ${opts.workDir} as "${opts.name}"${opts.model ? ` (model=${opts.model})` : ''}${opts.attachmentId ? ` (attachmentId=${opts.attachmentId})` : ''}`);
672
+ return { pid: child.pid, logPath, pidPath };
673
+ }
674
+ /**
675
+ * Resolve the path to the claude-code-headless adapter entry point.
676
+ * Mirrors {@link resolveClaudeApiPath} so dev (ts-node) and prod
677
+ * (compiled .js) both launch the same code through the same
678
+ * `require.main === module` gate.
679
+ */
680
+ function resolveClaudeCodeHeadlessPath() {
681
+ const isDev = __filename.endsWith('.ts');
682
+ if (isDev) {
683
+ return { cmd: 'npx', args: ['ts-node', (0, path_1.resolve)(__dirname, 'adapters', 'claude-code-headless', 'adapter.ts')] };
684
+ }
685
+ return { cmd: 'node', args: [(0, path_1.resolve)(__dirname, 'adapters', 'claude-code-headless', 'adapter.js')] };
686
+ }
687
+ /**
688
+ * Spawn the claude-code-headless adapter as a detached headless subprocess.
689
+ *
690
+ * Pattern matches {@link spawnClaudeApiAdapter} — no TTY, log + PID files
691
+ * in `logs/<name>.log` and `logs/<name>.pid`, env vars carry identity +
692
+ * Temporal connection settings + optional attachment-handoff.
693
+ *
694
+ * **Env hygiene** (design §3.6): the per-turn `claude -p` child needs to
695
+ * use the host's OAuth keychain — NOT a `ANTHROPIC_API_KEY` env var.
696
+ * The adapter strips `ANTHROPIC_API_KEY` and `CLAUDE_CODE_OAUTH_TOKEN`
697
+ * from its child env at spawn time (in `adapter.ts`'s `invokeSdk`); this
698
+ * spawn helper passes the parent's full env through to the adapter
699
+ * itself (which needs other env vars like PATH).
700
+ */
701
+ function spawnClaudeCodeHeadlessAdapter(opts) {
702
+ const { cmd, args } = resolveClaudeCodeHeadlessPath();
703
+ const logDirPath = opts.logDir || (0, path_1.join)(opts.workDir, 'logs');
704
+ const logName = opts.name || `claude-code-headless-${Date.now()}`;
705
+ const logPath = (0, path_1.join)(logDirPath, `${logName}.log`);
706
+ const pidPath = (0, path_1.join)(logDirPath, `${logName}.pid`);
707
+ (0, fs_1.mkdirSync)(logDirPath, { recursive: true });
708
+ const logFd = (0, fs_1.openSync)(logPath, 'a');
709
+ let child;
710
+ try {
711
+ child = (0, child_process_1.spawn)(cmd, args, {
712
+ cwd: opts.workDir,
713
+ detached: true,
714
+ stdio: ['ignore', logFd, logFd],
715
+ env: {
716
+ ...process.env,
717
+ [config_1.ENV.ENSEMBLE]: opts.ensemble,
718
+ [config_1.ENV.PLAYER_NAME]: opts.name,
719
+ [config_1.ENV.CONDUCTOR]: opts.isConductor ? 'true' : '',
720
+ [config_1.ENV.TEMPORAL_ADDRESS]: opts.temporalAddress,
721
+ ...(opts.temporalNamespace ? { [config_1.ENV.TEMPORAL_NAMESPACE]: opts.temporalNamespace } : {}),
722
+ ...(opts.temporalApiKey ? { [config_1.ENV.TEMPORAL_API_KEY]: opts.temporalApiKey } : {}),
723
+ ...(opts.temporalTlsCertPath ? { [config_1.ENV.TEMPORAL_TLS_CERT_PATH]: opts.temporalTlsCertPath } : {}),
724
+ ...(opts.temporalTlsKeyPath ? { [config_1.ENV.TEMPORAL_TLS_KEY_PATH]: opts.temporalTlsKeyPath } : {}),
725
+ // Permission mode: recruit-arg → AGENT_TEMPO_PERMISSION_MODE → in-adapter default.
726
+ ...(opts.permissionMode ? { [config_1.ENV.PERMISSION_MODE]: opts.permissionMode } : {}),
727
+ ...(opts.dangerouslySkipPermissions ? { [config_1.ENV.DANGEROUSLY_SKIP_PERMISSIONS]: '1' } : {}),
728
+ // Attachment handoff — adapter renews via startV2Lifecycle.
729
+ ...(opts.attachmentId ? { [config_1.ENV.ATTACHMENT_ID]: opts.attachmentId } : {}),
730
+ ...(opts.attachmentRunId ? { [config_1.ENV.ATTACHMENT_RUN_ID]: opts.attachmentRunId } : {}),
731
+ ...(opts.adapterId ? { [config_1.ENV.ADAPTER_ID]: opts.adapterId } : {}),
732
+ },
733
+ });
734
+ child.unref();
735
+ }
736
+ finally {
737
+ (0, fs_1.closeSync)(logFd);
738
+ }
739
+ if (child.pid != null) {
740
+ (0, fs_1.writeFileSync)(pidPath, String(child.pid));
741
+ }
742
+ log(`Spawned claude-code-headless adapter (pid ${child.pid}) in ${opts.workDir} ` +
743
+ `as "${opts.name}"${opts.permissionMode ? ` (permissionMode=${opts.permissionMode})` : ''}` +
744
+ `${opts.dangerouslySkipPermissions ? ' (dangerouslySkipPermissions=true)' : ''}` +
745
+ `${opts.attachmentId ? ` (attachmentId=${opts.attachmentId})` : ''}`);
746
+ return { pid: child.pid, logPath, pidPath };
747
+ }