borgmcp 1.1.15 → 2.0.2

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 (466) hide show
  1. package/CONTRIBUTING.md +15 -0
  2. package/LICENSE +201 -33
  3. package/NOTICE +2 -0
  4. package/README.md +85 -36
  5. package/SECURITY.md +7 -0
  6. package/dist/agent-runtime.d.ts.map +1 -0
  7. package/dist/agent-runtime.js +63 -1
  8. package/dist/agent-runtime.js.map +1 -0
  9. package/dist/assimilate-cmd.d.ts +96 -17
  10. package/dist/assimilate-cmd.d.ts.map +1 -0
  11. package/dist/assimilate-cmd.js +1396 -48
  12. package/dist/assimilate-cmd.js.map +1 -0
  13. package/dist/assimilate-deps.d.ts.map +1 -0
  14. package/dist/assimilate-deps.js +384 -3
  15. package/dist/assimilate-deps.js.map +1 -0
  16. package/dist/assimilate-guard.d.ts +5 -7
  17. package/dist/assimilate-guard.d.ts.map +1 -0
  18. package/dist/assimilate-guard.js +60 -2
  19. package/dist/assimilate-guard.js.map +1 -0
  20. package/dist/assimilate-welcome.d.ts +1 -1
  21. package/dist/assimilate-welcome.d.ts.map +1 -0
  22. package/dist/assimilate-welcome.js +32 -2
  23. package/dist/assimilate-welcome.js.map +1 -0
  24. package/dist/auth-env.d.ts +7 -50
  25. package/dist/auth-env.d.ts.map +1 -0
  26. package/dist/auth-env.js +22 -1
  27. package/dist/auth-env.js.map +1 -0
  28. package/dist/backends/launch-all-pastelist.d.ts.map +1 -0
  29. package/dist/backends/launch-all-pastelist.js +11 -4
  30. package/dist/backends/launch-all-pastelist.js.map +1 -0
  31. package/dist/backends/launch-all-tmux.d.ts.map +1 -0
  32. package/dist/backends/launch-all-tmux.js +49 -1
  33. package/dist/backends/launch-all-tmux.js.map +1 -0
  34. package/dist/backends/launch-all-windows.d.ts.map +1 -0
  35. package/dist/backends/launch-all-windows.js +86 -12
  36. package/dist/backends/launch-all-windows.js.map +1 -0
  37. package/dist/bare-launch-menu.d.ts.map +1 -0
  38. package/dist/bare-launch-menu.js +83 -6
  39. package/dist/bare-launch-menu.js.map +1 -0
  40. package/dist/claude-launch-args.d.ts.map +1 -0
  41. package/dist/claude-launch-args.js +34 -1
  42. package/dist/claude-launch-args.js.map +1 -0
  43. package/dist/claude.d.ts.map +1 -0
  44. package/dist/claude.js +486 -14
  45. package/dist/claude.js.map +1 -0
  46. package/dist/cleanup-cmd.d.ts +5 -5
  47. package/dist/cleanup-cmd.d.ts.map +1 -0
  48. package/dist/cleanup-cmd.js +453 -14
  49. package/dist/cleanup-cmd.js.map +1 -0
  50. package/dist/clear-rewake-core.d.ts.map +1 -0
  51. package/dist/clear-rewake-core.js +23 -2
  52. package/dist/clear-rewake-core.js.map +1 -0
  53. package/dist/clear-rewake.d.ts.map +1 -0
  54. package/dist/clear-rewake.js +19 -1
  55. package/dist/clear-rewake.js.map +1 -0
  56. package/dist/cli-help.d.ts +5 -0
  57. package/dist/cli-help.d.ts.map +1 -0
  58. package/dist/cli-help.js +104 -56
  59. package/dist/cli-help.js.map +1 -0
  60. package/dist/cli-platform.d.ts.map +1 -0
  61. package/dist/cli-platform.js +106 -4
  62. package/dist/cli-platform.js.map +1 -0
  63. package/dist/cli-tool-approval.d.ts +84 -0
  64. package/dist/cli-tool-approval.d.ts.map +1 -0
  65. package/dist/cli-tool-approval.js +583 -0
  66. package/dist/cli-tool-approval.js.map +1 -0
  67. package/dist/codex-app-server.d.ts.map +1 -0
  68. package/dist/codex-app-server.js +228 -4
  69. package/dist/codex-app-server.js.map +1 -0
  70. package/dist/codex-app-wake.d.ts +9 -11
  71. package/dist/codex-app-wake.d.ts.map +1 -0
  72. package/dist/codex-app-wake.js +436 -2
  73. package/dist/codex-app-wake.js.map +1 -0
  74. package/dist/codex-launch.d.ts.map +1 -0
  75. package/dist/codex-launch.js +102 -2
  76. package/dist/codex-launch.js.map +1 -0
  77. package/dist/codex-remote.d.ts +6 -1
  78. package/dist/codex-remote.d.ts.map +1 -0
  79. package/dist/codex-remote.js +394 -1
  80. package/dist/codex-remote.js.map +1 -0
  81. package/dist/codex-wake-resolve.d.ts +4 -4
  82. package/dist/codex-wake-resolve.d.ts.map +1 -0
  83. package/dist/codex-wake-resolve.js +127 -1
  84. package/dist/codex-wake-resolve.js.map +1 -0
  85. package/dist/config-utils.d.ts +2 -2
  86. package/dist/config-utils.d.ts.map +1 -0
  87. package/dist/config-utils.js +766 -3
  88. package/dist/config-utils.js.map +1 -0
  89. package/dist/config.d.ts +98 -61
  90. package/dist/config.d.ts.map +1 -0
  91. package/dist/config.js +426 -1
  92. package/dist/config.js.map +1 -0
  93. package/dist/console-prefix.d.ts.map +1 -0
  94. package/dist/console-prefix.js +96 -1
  95. package/dist/console-prefix.js.map +1 -0
  96. package/dist/cube-name.d.ts.map +1 -0
  97. package/dist/cube-name.js +67 -1
  98. package/dist/cube-name.js.map +1 -0
  99. package/dist/cubes.d.ts +126 -18
  100. package/dist/cubes.d.ts.map +1 -0
  101. package/dist/cubes.js +412 -4
  102. package/dist/cubes.js.map +1 -0
  103. package/dist/debug.d.ts.map +1 -0
  104. package/dist/debug.js +71 -1
  105. package/dist/debug.js.map +1 -0
  106. package/dist/direct-log.d.ts.map +1 -0
  107. package/dist/direct-log.js +11 -1
  108. package/dist/direct-log.js.map +1 -0
  109. package/dist/docs-sections.d.ts +11 -10
  110. package/dist/docs-sections.d.ts.map +1 -0
  111. package/dist/docs-sections.js +113 -3
  112. package/dist/docs-sections.js.map +1 -0
  113. package/dist/drone-lifecycle.d.ts +5 -21
  114. package/dist/drone-lifecycle.d.ts.map +1 -0
  115. package/dist/drone-lifecycle.js +57 -8
  116. package/dist/drone-lifecycle.js.map +1 -0
  117. package/dist/drone-management.d.ts +29 -0
  118. package/dist/drone-management.d.ts.map +1 -0
  119. package/dist/drone-management.js +109 -0
  120. package/dist/drone-management.js.map +1 -0
  121. package/dist/ensure-mcp-config.d.ts.map +1 -0
  122. package/dist/ensure-mcp-config.js +36 -1
  123. package/dist/ensure-mcp-config.js.map +1 -0
  124. package/dist/evict-drone.d.ts +10 -2
  125. package/dist/evict-drone.d.ts.map +1 -0
  126. package/dist/evict-drone.js +60 -1
  127. package/dist/evict-drone.js.map +1 -0
  128. package/dist/gc-orphan-inboxes.d.ts.map +1 -0
  129. package/dist/gc-orphan-inboxes.js +177 -1
  130. package/dist/gc-orphan-inboxes.js.map +1 -0
  131. package/dist/inbox-monitor.d.ts +1 -1
  132. package/dist/inbox-monitor.d.ts.map +1 -0
  133. package/dist/inbox-monitor.js +856 -3
  134. package/dist/inbox-monitor.js.map +1 -0
  135. package/dist/index.d.ts +6 -4
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +1034 -37
  138. package/dist/index.js.map +1 -0
  139. package/dist/launch-all-cmd.d.ts.map +1 -0
  140. package/dist/launch-all-cmd.js +377 -37
  141. package/dist/launch-all-cmd.js.map +1 -0
  142. package/dist/launch-all-command.d.ts.map +1 -0
  143. package/dist/launch-all-command.js +24 -1
  144. package/dist/launch-all-command.js.map +1 -0
  145. package/dist/launch-all-deps.d.ts +3 -8
  146. package/dist/launch-all-deps.d.ts.map +1 -0
  147. package/dist/launch-all-deps.js +99 -1
  148. package/dist/launch-all-deps.js.map +1 -0
  149. package/dist/launch-all-discovery.d.ts +1 -0
  150. package/dist/launch-all-discovery.d.ts.map +1 -0
  151. package/dist/launch-all-discovery.js +90 -4
  152. package/dist/launch-all-discovery.js.map +1 -0
  153. package/dist/launch-all-locks.d.ts.map +1 -0
  154. package/dist/launch-all-locks.js +54 -1
  155. package/dist/launch-all-locks.js.map +1 -0
  156. package/dist/launch-gate.d.ts +2 -2
  157. package/dist/launch-gate.d.ts.map +1 -0
  158. package/dist/launch-gate.js +73 -1
  159. package/dist/launch-gate.js.map +1 -0
  160. package/dist/lifecycle-log-guard.d.ts.map +1 -0
  161. package/dist/lifecycle-log-guard.js +93 -2
  162. package/dist/lifecycle-log-guard.js.map +1 -0
  163. package/dist/list-roles-render.d.ts.map +1 -0
  164. package/dist/list-roles-render.js +40 -6
  165. package/dist/list-roles-render.js.map +1 -0
  166. package/dist/local-log-routing.d.ts +19 -0
  167. package/dist/local-log-routing.d.ts.map +1 -0
  168. package/dist/local-log-routing.js +67 -0
  169. package/dist/local-log-routing.js.map +1 -0
  170. package/dist/local-manage-tool-result.d.ts +8 -0
  171. package/dist/local-manage-tool-result.d.ts.map +1 -0
  172. package/dist/local-manage-tool-result.js +10 -0
  173. package/dist/local-manage-tool-result.js.map +1 -0
  174. package/dist/local-server-cursor.d.ts +34 -0
  175. package/dist/local-server-cursor.d.ts.map +1 -0
  176. package/dist/local-server-cursor.js +151 -0
  177. package/dist/local-server-cursor.js.map +1 -0
  178. package/dist/log-audit.d.ts.map +1 -0
  179. package/dist/log-audit.js +194 -3
  180. package/dist/log-audit.js.map +1 -0
  181. package/dist/log-stream.d.ts +35 -18
  182. package/dist/log-stream.d.ts.map +1 -0
  183. package/dist/log-stream.js +1270 -12
  184. package/dist/log-stream.js.map +1 -0
  185. package/dist/model-presets.d.ts.map +1 -0
  186. package/dist/model-presets.js +19 -1
  187. package/dist/model-presets.js.map +1 -0
  188. package/dist/name-validator.d.ts.map +1 -0
  189. package/dist/name-validator.js +22 -1
  190. package/dist/name-validator.js.map +1 -0
  191. package/dist/opencode-drone.d.ts.map +1 -0
  192. package/dist/opencode-drone.js +438 -4
  193. package/dist/opencode-drone.js.map +1 -0
  194. package/dist/opencode-plugin.d.ts +1 -1
  195. package/dist/opencode-plugin.d.ts.map +1 -0
  196. package/dist/opencode-plugin.js +29 -4
  197. package/dist/opencode-plugin.js.map +1 -0
  198. package/dist/parse-assimilate-args.d.ts +1 -1
  199. package/dist/parse-assimilate-args.d.ts.map +1 -0
  200. package/dist/parse-assimilate-args.js +125 -1
  201. package/dist/parse-assimilate-args.js.map +1 -0
  202. package/dist/parse-launch-all-args.d.ts.map +1 -0
  203. package/dist/parse-launch-all-args.js +70 -1
  204. package/dist/parse-launch-all-args.js.map +1 -0
  205. package/dist/postinstall-banner.d.ts.map +1 -0
  206. package/dist/postinstall-banner.js +27 -2
  207. package/dist/postinstall-banner.js.map +1 -0
  208. package/dist/postinstall.d.ts.map +1 -0
  209. package/dist/postinstall.js +32 -5
  210. package/dist/postinstall.js.map +1 -0
  211. package/dist/readiness-probe.d.ts.map +1 -0
  212. package/dist/readiness-probe.js +9 -1
  213. package/dist/readiness-probe.js.map +1 -0
  214. package/dist/regen-format.d.ts.map +1 -0
  215. package/dist/regen-format.js +545 -13
  216. package/dist/regen-format.js.map +1 -0
  217. package/dist/regen.d.ts.map +1 -0
  218. package/dist/regen.js +141 -5
  219. package/dist/regen.js.map +1 -0
  220. package/dist/remote-client.d.ts +88 -173
  221. package/dist/remote-client.d.ts.map +1 -0
  222. package/dist/remote-client.js +997 -1
  223. package/dist/remote-client.js.map +1 -0
  224. package/dist/reset-local-seat-cmd.d.ts +50 -0
  225. package/dist/reset-local-seat-cmd.d.ts.map +1 -0
  226. package/dist/reset-local-seat-cmd.js +169 -0
  227. package/dist/reset-local-seat-cmd.js.map +1 -0
  228. package/dist/role-match.d.ts.map +1 -0
  229. package/dist/role-match.js +23 -1
  230. package/dist/role-match.js.map +1 -0
  231. package/dist/role-resolver.d.ts.map +1 -0
  232. package/dist/role-resolver.js +60 -1
  233. package/dist/role-resolver.js.map +1 -0
  234. package/dist/roster-render.d.ts.map +1 -0
  235. package/dist/roster-render.js +121 -3
  236. package/dist/roster-render.js.map +1 -0
  237. package/dist/seat-probe.d.ts +32 -13
  238. package/dist/seat-probe.d.ts.map +1 -0
  239. package/dist/seat-probe.js +78 -1
  240. package/dist/seat-probe.js.map +1 -0
  241. package/dist/seat-store.d.ts +76 -0
  242. package/dist/seat-store.d.ts.map +1 -0
  243. package/dist/seat-store.js +309 -0
  244. package/dist/seat-store.js.map +1 -0
  245. package/dist/seats.d.ts +375 -0
  246. package/dist/seats.d.ts.map +1 -0
  247. package/dist/seats.js +670 -0
  248. package/dist/seats.js.map +1 -0
  249. package/dist/self-path.d.ts +27 -0
  250. package/dist/self-path.d.ts.map +1 -0
  251. package/dist/self-path.js +43 -0
  252. package/dist/self-path.js.map +1 -0
  253. package/dist/server-endpoint.d.ts +9 -0
  254. package/dist/server-endpoint.d.ts.map +1 -0
  255. package/dist/server-endpoint.js +38 -0
  256. package/dist/server-endpoint.js.map +1 -0
  257. package/dist/server-errors.d.ts +50 -0
  258. package/dist/server-errors.d.ts.map +1 -0
  259. package/dist/server-errors.js +79 -0
  260. package/dist/server-errors.js.map +1 -0
  261. package/dist/server-handshake.d.ts +197 -0
  262. package/dist/server-handshake.d.ts.map +1 -0
  263. package/dist/server-handshake.js +533 -0
  264. package/dist/server-handshake.js.map +1 -0
  265. package/dist/server-response.d.ts +3 -0
  266. package/dist/server-response.d.ts.map +1 -0
  267. package/dist/server-response.js +67 -0
  268. package/dist/server-response.js.map +1 -0
  269. package/dist/server-trust.d.ts +14 -0
  270. package/dist/server-trust.d.ts.map +1 -0
  271. package/dist/server-trust.js +225 -0
  272. package/dist/server-trust.js.map +1 -0
  273. package/dist/session-continuity.d.ts +33 -0
  274. package/dist/session-continuity.d.ts.map +1 -0
  275. package/dist/session-continuity.js +220 -0
  276. package/dist/session-continuity.js.map +1 -0
  277. package/dist/setup-confirm.d.ts +3 -3
  278. package/dist/setup-confirm.d.ts.map +1 -0
  279. package/dist/setup-confirm.js +126 -2
  280. package/dist/setup-confirm.js.map +1 -0
  281. package/dist/setup.d.ts +5 -3
  282. package/dist/setup.d.ts.map +1 -0
  283. package/dist/setup.js +169 -46
  284. package/dist/setup.js.map +1 -0
  285. package/dist/shell-escape.d.ts.map +1 -0
  286. package/dist/shell-escape.js +22 -1
  287. package/dist/shell-escape.js.map +1 -0
  288. package/dist/spawn.d.ts +2 -2
  289. package/dist/spawn.d.ts.map +1 -0
  290. package/dist/spawn.js +29 -10
  291. package/dist/spawn.js.map +1 -0
  292. package/dist/startup-services.d.ts +0 -1
  293. package/dist/startup-services.d.ts.map +1 -0
  294. package/dist/startup-services.js +26 -1
  295. package/dist/startup-services.js.map +1 -0
  296. package/dist/stream-owner.d.ts +6 -2
  297. package/dist/stream-owner.d.ts.map +1 -0
  298. package/dist/stream-owner.js +547 -2
  299. package/dist/stream-owner.js.map +1 -0
  300. package/dist/stream-status.d.ts +1 -1
  301. package/dist/stream-status.d.ts.map +1 -0
  302. package/dist/stream-status.js +268 -3
  303. package/dist/stream-status.js.map +1 -0
  304. package/dist/sync-roles-render.d.ts.map +1 -0
  305. package/dist/sync-roles-render.js +118 -3
  306. package/dist/sync-roles-render.js.map +1 -0
  307. package/dist/sync.d.ts +1 -1
  308. package/dist/sync.d.ts.map +1 -0
  309. package/dist/sync.js +286 -22
  310. package/dist/sync.js.map +1 -0
  311. package/dist/terminal-title.d.ts.map +1 -0
  312. package/dist/terminal-title.js +68 -1
  313. package/dist/terminal-title.js.map +1 -0
  314. package/dist/token-store.d.ts +17 -111
  315. package/dist/token-store.d.ts.map +1 -0
  316. package/dist/token-store.js +81 -1
  317. package/dist/token-store.js.map +1 -0
  318. package/dist/tool-manifest.d.ts +4 -8
  319. package/dist/tool-manifest.d.ts.map +1 -0
  320. package/dist/tool-manifest.js +554 -1
  321. package/dist/tool-manifest.js.map +1 -0
  322. package/dist/tool-scope.d.ts +8 -12
  323. package/dist/tool-scope.d.ts.map +1 -0
  324. package/dist/tool-scope.js +97 -1
  325. package/dist/tool-scope.js.map +1 -0
  326. package/dist/types.d.ts +1 -5
  327. package/dist/types.d.ts.map +1 -0
  328. package/dist/types.js +5 -0
  329. package/dist/types.js.map +1 -0
  330. package/dist/unknown-subcommand.d.ts +1 -1
  331. package/dist/unknown-subcommand.d.ts.map +1 -0
  332. package/dist/unknown-subcommand.js +37 -1
  333. package/dist/unknown-subcommand.js.map +1 -0
  334. package/dist/version.d.ts +1 -1
  335. package/dist/version.d.ts.map +1 -0
  336. package/dist/version.js +78 -2
  337. package/dist/version.js.map +1 -0
  338. package/dist/working-repo.d.ts.map +1 -0
  339. package/dist/working-repo.js +81 -1
  340. package/dist/working-repo.js.map +1 -0
  341. package/dist/worktree-lifecycle.d.ts.map +1 -0
  342. package/dist/worktree-lifecycle.js +205 -2
  343. package/dist/worktree-lifecycle.js.map +1 -0
  344. package/docs/EXTRACTION_PROVENANCE.md +42 -0
  345. package/docs/LOCAL_SERVER.md +103 -0
  346. package/docs/RELEASING.md +129 -0
  347. package/package.json +52 -34
  348. package/src/agent-runtime.ts +69 -0
  349. package/src/assimilate-cmd.ts +1864 -0
  350. package/src/assimilate-deps.ts +444 -0
  351. package/src/assimilate-guard.ts +84 -0
  352. package/src/assimilate-welcome.ts +39 -0
  353. package/src/auth-env.ts +21 -0
  354. package/src/backends/launch-all-pastelist.ts +18 -0
  355. package/src/backends/launch-all-tmux.ts +75 -0
  356. package/src/backends/launch-all-windows.ts +110 -0
  357. package/src/bare-launch-menu.ts +148 -0
  358. package/src/claude-launch-args.ts +35 -0
  359. package/src/claude.ts +561 -0
  360. package/src/cleanup-cmd.ts +581 -0
  361. package/src/clear-rewake-core.ts +34 -0
  362. package/src/clear-rewake.ts +18 -0
  363. package/src/cli-help.ts +116 -0
  364. package/src/cli-platform.ts +127 -0
  365. package/src/cli-tool-approval.ts +716 -0
  366. package/src/codex-app-server.ts +238 -0
  367. package/src/codex-app-wake.ts +524 -0
  368. package/src/codex-launch.ts +140 -0
  369. package/src/codex-remote.ts +500 -0
  370. package/src/codex-wake-resolve.ts +155 -0
  371. package/src/config-utils.ts +811 -0
  372. package/src/config.ts +595 -0
  373. package/src/console-prefix.ts +99 -0
  374. package/src/cube-name.ts +69 -0
  375. package/src/cubes.ts +583 -0
  376. package/src/debug.ts +73 -0
  377. package/src/direct-log.ts +9 -0
  378. package/src/docs-sections.ts +129 -0
  379. package/src/drone-lifecycle.ts +62 -0
  380. package/src/drone-management.ts +162 -0
  381. package/src/ensure-mcp-config.ts +54 -0
  382. package/src/evict-drone.ts +82 -0
  383. package/src/gc-orphan-inboxes.ts +229 -0
  384. package/src/inbox-monitor.ts +1005 -0
  385. package/src/index.ts +1201 -0
  386. package/src/launch-all-cmd.ts +450 -0
  387. package/src/launch-all-command.ts +30 -0
  388. package/src/launch-all-deps.ts +188 -0
  389. package/src/launch-all-discovery.ts +118 -0
  390. package/src/launch-all-locks.ts +74 -0
  391. package/src/launch-gate.ts +80 -0
  392. package/src/lifecycle-log-guard.ts +144 -0
  393. package/src/list-roles-render.ts +52 -0
  394. package/src/local-log-routing.ts +106 -0
  395. package/src/local-manage-tool-result.ts +10 -0
  396. package/src/local-server-cursor.ts +188 -0
  397. package/src/log-audit.ts +207 -0
  398. package/src/log-stream.ts +1567 -0
  399. package/src/model-presets.ts +22 -0
  400. package/src/name-validator.ts +23 -0
  401. package/src/opencode-drone.ts +528 -0
  402. package/src/opencode-plugin.ts +38 -0
  403. package/src/parse-assimilate-args.ts +125 -0
  404. package/src/parse-launch-all-args.ts +100 -0
  405. package/src/postinstall-banner.ts +37 -0
  406. package/src/postinstall.ts +36 -0
  407. package/src/readiness-probe.ts +12 -0
  408. package/src/regen-format.ts +651 -0
  409. package/src/regen.ts +150 -0
  410. package/src/remote-client.ts +1457 -0
  411. package/src/reset-local-seat-cmd.ts +227 -0
  412. package/src/role-match.ts +29 -0
  413. package/src/role-resolver.ts +93 -0
  414. package/src/roster-render.ts +196 -0
  415. package/src/seat-probe.ts +115 -0
  416. package/src/seat-store.ts +333 -0
  417. package/src/seats.ts +911 -0
  418. package/src/self-path.ts +51 -0
  419. package/src/server-endpoint.ts +38 -0
  420. package/src/server-errors.ts +95 -0
  421. package/src/server-handshake.ts +816 -0
  422. package/src/server-response.ts +76 -0
  423. package/src/server-trust.ts +245 -0
  424. package/src/session-continuity.ts +280 -0
  425. package/src/setup-confirm.ts +171 -0
  426. package/src/setup.ts +186 -0
  427. package/src/shell-escape.ts +22 -0
  428. package/src/spawn.ts +31 -0
  429. package/src/startup-services.ts +36 -0
  430. package/src/stream-owner.ts +686 -0
  431. package/src/stream-status.ts +337 -0
  432. package/src/sync-roles-render.ts +163 -0
  433. package/src/sync.ts +363 -0
  434. package/src/terminal-title.ts +76 -0
  435. package/src/token-store.ts +102 -0
  436. package/src/tool-manifest.ts +610 -0
  437. package/src/tool-scope.ts +110 -0
  438. package/src/types.ts +5 -0
  439. package/src/unknown-subcommand.ts +35 -0
  440. package/src/version.ts +82 -0
  441. package/src/working-repo.ts +99 -0
  442. package/src/worktree-lifecycle.ts +254 -0
  443. package/dist/auth-recovery.d.ts +0 -33
  444. package/dist/auth-recovery.js +0 -1
  445. package/dist/auth.d.ts +0 -103
  446. package/dist/auth.js +0 -39
  447. package/dist/device-auth.d.ts +0 -75
  448. package/dist/device-auth.js +0 -1
  449. package/dist/drone-address.d.ts +0 -26
  450. package/dist/drone-address.js +0 -1
  451. package/dist/get-started.d.ts +0 -20
  452. package/dist/get-started.js +0 -2
  453. package/dist/health-beat.d.ts +0 -134
  454. package/dist/health-beat.js +0 -1
  455. package/dist/role-section.d.ts +0 -110
  456. package/dist/role-section.js +0 -8
  457. package/dist/setup-action.d.ts +0 -20
  458. package/dist/setup-action.js +0 -1
  459. package/dist/stale-version-check.d.ts +0 -40
  460. package/dist/stale-version-check.js +0 -1
  461. package/dist/subscription-retry.d.ts +0 -40
  462. package/dist/subscription-retry.js +0 -1
  463. package/dist/templates.d.ts +0 -107
  464. package/dist/templates.js +0 -359
  465. package/dist/token-crypto.d.ts +0 -50
  466. package/dist/token-crypto.js +0 -1
package/src/claude.ts ADDED
@@ -0,0 +1,561 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Borg CLI launcher
4
+ *
5
+ * Spawns Claude Code with a minimal kickoff prompt so the SessionStart
6
+ * hook's injected drone playbook actually fires on the first turn.
7
+ * Without this, Claude sits waiting for user input and the autonomous
8
+ * "look at the log and act" directive never executes.
9
+ *
10
+ * Commands:
11
+ * borg → Launch Claude with kickoff prompt
12
+ * borg setup → Re-route to the setup wizard
13
+ * borg spawn <name> → Create a sibling git worktree + launch a
14
+ * fresh drone inside it (see spawn.ts)
15
+ * borg sync → Advance the current worktree across the 5
16
+ * lifecycle states (see sync.ts, gh#33)
17
+ */
18
+
19
+ import { spawn } from 'child_process';
20
+ import { randomUUID } from 'node:crypto';
21
+ import { basename } from 'node:path';
22
+ import { createInterface } from 'node:readline/promises';
23
+ import chalk from 'chalk';
24
+ import { findProjectRoot, getActiveCube, inboxPathForDrone, setCodexWakeTarget, pruneDeadCodexWakeTargets } from './cubes.js';
25
+ import { monitorStateRootForWorktree } from './inbox-monitor.js';
26
+ import { handleVersionFlag, getPackageVersion } from './version.js';
27
+ import { isHelpFlag, setupHelpText, topLevelHelpText, assimilateHelpText, resetLocalSeatHelpText } from './cli-help.js';
28
+ import { runSpawn } from './spawn.js';
29
+ import { buildClaudeLaunchArgs } from './claude-launch-args.js';
30
+ import { parseSyncArgs, runSync } from './sync.js';
31
+ import { parseCleanupArgs, runCleanup } from './cleanup-cmd.js';
32
+ import { parseAssimilateArgs } from './parse-assimilate-args.js';
33
+ import { runAssimilate } from './assimilate-cmd.js';
34
+ import { buildDefaultAssimilateDeps } from './assimilate-deps.js';
35
+ import {
36
+ parseResetLocalSeatArgs,
37
+ runResetLocalSeat,
38
+ buildDefaultResetLocalSeatDeps,
39
+ } from './reset-local-seat-cmd.js';
40
+ import { parseLaunchAllArgs } from './parse-launch-all-args.js';
41
+ import { unknownSubcommand } from './unknown-subcommand.js';
42
+ import { runLaunchAll } from './launch-all-cmd.js';
43
+ import { buildDefaultLaunchAllDeps } from './launch-all-deps.js';
44
+ import { discoverDroneCandidates } from './launch-all-discovery.js';
45
+ import {
46
+ explicitCliLaunchHint,
47
+ runBareLaunchMenu,
48
+ shouldResolveExplicitCliLaunchHintTargets,
49
+ shouldShowLaunchMenu,
50
+ } from './bare-launch-menu.js';
51
+ import { setTerminalTitle } from './terminal-title.js';
52
+ import { initConsolePrefix, consolePrefix } from './console-prefix.js';
53
+ import { initDebugFromArgv } from './debug.js';
54
+ import { defaultCliChoiceDeps, detectCliAvailability, installedCliNames, parseCliFlag, resolveCliChoice } from './cli-platform.js';
55
+ import { prepareCodexRemoteLaunch, resolveCodexLaunchCwd, withCodexCwdArg, defaultCodexRemoteDeps, checkCodexBridgeHealthy } from './codex-remote.js';
56
+ import {
57
+ BORG_CODEX_REMOTE_WAKE_ENV,
58
+ codexAgentKindConfigArgs,
59
+ codexRemoteWakeConfigArgs,
60
+ withAgentRuntimeEnv,
61
+ } from './agent-runtime.js';
62
+ import { findLoadedCodexThread } from './codex-app-server.js';
63
+ import {
64
+ buildAgentKickoffPrompt,
65
+ buildKickoffWakePathClause,
66
+ recordCodexWakeTarget,
67
+ socketPathFromRemoteArgs,
68
+ } from './codex-launch.js';
69
+ import { codexBorgSessionConfigArgs } from './launch-gate.js';
70
+ import {
71
+ addCodexSessionStartHook,
72
+ addCodexUserPromptSubmitHook,
73
+ addProjectSessionStartHook,
74
+ addUserPromptSubmitHook,
75
+ removeSessionStartHook,
76
+ } from './config-utils.js';
77
+ import { ensureCliMcpConfigured } from './ensure-mcp-config.js';
78
+ import { installBorgPlugin } from './opencode-plugin.js';
79
+ import { connectOpenCodeDrone, computeOpenCodePort, createOpenCodeLaunchKickoff, injectInitialKickoff } from './opencode-drone.js';
80
+ import { buildOpenCodeLaunchArgs, defaultApprovalIo, resolveLaunchBorgApprovals } from './cli-tool-approval.js';
81
+
82
+ async function main() {
83
+ // `--debug` / BORG_DEBUG: enable HTTP request/response logging to stderr
84
+ // (observability for failures like the cross-account assimilate 404).
85
+ // Done first so debug covers everything below; strips `--debug` from argv
86
+ // so subcommand parsers (which reject unknown flags) never see it. Covers
87
+ // the top-level dispatcher + `borg setup` + `borg assimilate` — all route
88
+ // through this main.
89
+ initDebugFromArgv(process.argv);
90
+
91
+ // Honor `--version` / `-v` before any other work.
92
+ handleVersionFlag();
93
+
94
+ // Resolve drone self-identification prefix (gh#25) before any error
95
+ // emission so messages carry `[drone-X · cube]` from launch onward.
96
+ await initConsolePrefix();
97
+
98
+ // Local-only client: bare `borg` performs NO automatic external network I/O
99
+ // (no npm-registry stale-version check) before authority selection. Only the
100
+ // explicitly selected local server may be contacted. A version comparison is
101
+ // available as an explicit operator action via `borg --version`.
102
+
103
+ // Intercept --help / -h before handing off to Claude.
104
+ if (process.argv[2] === '--help' || process.argv[2] === '-h') {
105
+ process.stdout.write(topLevelHelpText(getPackageVersion()));
106
+ process.exit(0);
107
+ }
108
+
109
+ // Re-route subcommands.
110
+ if (process.argv[2] === 'setup') {
111
+ // gh#520: `borg setup --help` must show help, not run the wizard.
112
+ if (isHelpFlag(process.argv[3])) {
113
+ process.stdout.write(setupHelpText(getPackageVersion()));
114
+ process.exit(0);
115
+ }
116
+ await import('./setup.js');
117
+ return;
118
+ }
119
+ if (process.argv[2] === 'assimilate') {
120
+ // `borg assimilate --help` (or `... <role> --help`) must show help, not be
121
+ // rejected by the parser as an unknown flag.
122
+ if (process.argv.slice(3).some(isHelpFlag)) {
123
+ process.stdout.write(assimilateHelpText(getPackageVersion()));
124
+ process.exit(0);
125
+ }
126
+ const parsed = parseAssimilateArgs(process.argv.slice(3));
127
+ if (!parsed.ok) {
128
+ process.stderr.write(
129
+ chalk.red(`${consolePrefix()}◼ borg assimilate: ${parsed.error}\n`)
130
+ );
131
+ process.stderr.write(`Run \`borg --help\` for usage.\n`);
132
+ process.exit(1);
133
+ }
134
+ const deps = buildDefaultAssimilateDeps();
135
+ const code = await runAssimilate({ role: parsed.role, flags: parsed.flags }, deps);
136
+ process.exit(code);
137
+ }
138
+ if (process.argv[2] === 'reset-local-seat') {
139
+ if (process.argv.slice(3).some(isHelpFlag)) {
140
+ process.stdout.write(resetLocalSeatHelpText(getPackageVersion()));
141
+ process.exit(0);
142
+ }
143
+ const parsed = parseResetLocalSeatArgs(process.argv.slice(3));
144
+ if (!parsed.ok) {
145
+ process.stderr.write(
146
+ chalk.red(`${consolePrefix()}◼ borg reset-local-seat: ${parsed.error}\n`)
147
+ );
148
+ process.stderr.write(`Run \`borg --help\` for usage.\n`);
149
+ process.exit(1);
150
+ }
151
+ const code = await runResetLocalSeat(parsed.flags, buildDefaultResetLocalSeatDeps());
152
+ process.exit(code);
153
+ }
154
+ if (process.argv[2] === 'spawn') {
155
+ // Deprecated; the stub prints a redirect message and exits 2.
156
+ const code = await runSpawn();
157
+ process.exit(code);
158
+ }
159
+ if (process.argv[2] === 'sync') {
160
+ const parsed = parseSyncArgs(process.argv.slice(3));
161
+ if (!parsed.ok) {
162
+ process.stderr.write(
163
+ chalk.red(`${consolePrefix()}◼ borg sync: ${parsed.error}\n`)
164
+ );
165
+ process.stderr.write(`Run \`borg --help\` for usage.\n`);
166
+ process.exit(1);
167
+ }
168
+ const code = await runSync({}, parsed.options);
169
+ process.exit(code);
170
+ }
171
+ if (process.argv[2] === 'cleanup') {
172
+ const parsed = parseCleanupArgs(process.argv.slice(3));
173
+ if (!parsed.ok) {
174
+ process.stderr.write(
175
+ chalk.red(`${consolePrefix()}◼ borg cleanup: ${parsed.error}\n`)
176
+ );
177
+ process.stderr.write(`Run \`borg --help\` for usage.\n`);
178
+ process.exit(1);
179
+ }
180
+ const code = await runCleanup({}, parsed.options);
181
+ process.exit(code);
182
+ }
183
+ if (process.argv[2] === 'launch-all') {
184
+ const parsed = parseLaunchAllArgs(process.argv.slice(3));
185
+ if (!parsed.ok) {
186
+ process.stderr.write(
187
+ chalk.red(`${consolePrefix()}◼ borg launch-all: ${parsed.error}\n`)
188
+ );
189
+ process.stderr.write(`Run \`borg --help\` for usage.\n`);
190
+ process.exit(1);
191
+ }
192
+ const deps = buildDefaultLaunchAllDeps();
193
+ const code = await runLaunchAll(parsed.args, deps);
194
+ process.exit(code);
195
+ }
196
+
197
+ // gh#911: an unknown NON-FLAG argv[2] that isn't a known subcommand must
198
+ // ERROR, not silently fall through and launch an agent with the typo'd word
199
+ // as its prompt (the `borg evict-drone X` footgun). Bare `borg` and
200
+ // recognized flags still fall through to launch below.
201
+ const unknownCmd = unknownSubcommand(process.argv[2]);
202
+ if (unknownCmd !== null) {
203
+ process.stderr.write(
204
+ chalk.red(`${consolePrefix()}◼ unknown command: ${unknownCmd}\n`)
205
+ );
206
+ process.stderr.write(`Run \`borg --help\` for usage.\n`);
207
+ process.exit(1);
208
+ }
209
+
210
+ const parsedCli = parseCliFlag(process.argv.slice(2));
211
+ if (parsedCli.error) {
212
+ process.stderr.write(chalk.red(`${consolePrefix()}◼ ${parsedCli.error}\n`));
213
+ process.stderr.write(`Run \`borg --help\` for usage.\n`);
214
+ process.exit(1);
215
+ }
216
+
217
+ const prompt = async (message: string): Promise<string> => {
218
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
219
+ try {
220
+ return await rl.question(message);
221
+ } finally {
222
+ rl.close();
223
+ }
224
+ };
225
+
226
+ let cli = await resolveCliChoice(
227
+ parsedCli.cli,
228
+ defaultCliChoiceDeps(prompt, () => process.stdin.isTTY === true)
229
+ );
230
+ ensureDetectedCliConfigured();
231
+
232
+ // Active cube for this directory — needed for the launch menu's option-3
233
+ // availability, the terminal title, and the inbox-Monitor clause below.
234
+ const active = await getActiveCube();
235
+ let launchAllTargetsAvailable: boolean | undefined;
236
+ const hasLaunchAllTargets = async (): Promise<boolean> => {
237
+ if (!active) return false;
238
+ if (launchAllTargetsAvailable === undefined) {
239
+ const candidates = await discoverDroneCandidates(
240
+ { targetCubeId: active.cubeId },
241
+ buildDefaultLaunchAllDeps()
242
+ );
243
+ launchAllTargetsAvailable = candidates.length > 0;
244
+ }
245
+ return launchAllTargetsAvailable;
246
+ };
247
+
248
+ const stdinIsTTY = process.stdin.isTTY === true;
249
+ const stdoutIsTTY = process.stdout.isTTY === true;
250
+ const explicitCliHint = explicitCliLaunchHint({
251
+ explicitCli: parsedCli.cli,
252
+ stdinIsTTY,
253
+ stdoutIsTTY,
254
+ hasActiveCube: active !== null,
255
+ hasLaunchAllTargets: shouldResolveExplicitCliLaunchHintTargets({
256
+ explicitCli: parsedCli.cli,
257
+ stdinIsTTY,
258
+ stdoutIsTTY,
259
+ hasActiveCube: active !== null,
260
+ }) ? await hasLaunchAllTargets() : false,
261
+ });
262
+ if (explicitCliHint) process.stderr.write(explicitCliHint);
263
+
264
+ // gh#853: bare `borg` (no args) interactive launch menu. TTY-only + bare-args-
265
+ // only (shouldShowLaunchMenu) so every scripted/programmatic `borg` and every
266
+ // explicit subcommand/flag is untouched; the get-started breadcrumb already
267
+ // exited above, so it keeps precedence over the menu. The option-set and
268
+ // selection→action mapping are pure (bare-launch-menu.ts) — this is the glue
269
+ // that computes inputs and dispatches the chosen action.
270
+ if (
271
+ shouldShowLaunchMenu({
272
+ extraArgs: process.argv.slice(2),
273
+ stdinIsTTY,
274
+ stdoutIsTTY,
275
+ })
276
+ ) {
277
+ const otherInstalledClis =
278
+ installedCliNames(detectCliAvailability()).filter((c) => c !== cli);
279
+ const action = await runBareLaunchMenu(
280
+ { defaultCli: cli, otherInstalledClis, hasLaunchAllTargets: await hasLaunchAllTargets() },
281
+ prompt
282
+ );
283
+ if (action.kind === 'launch-all') {
284
+ const parsed = parseLaunchAllArgs([]); // empty args → active cube, auto backend
285
+ const code = parsed.ok ? await runLaunchAll(parsed.args, buildDefaultLaunchAllDeps()) : 1;
286
+ process.exit(code);
287
+ }
288
+ // option 1 → configured default; option 2 → the other agent, ONE-SHOT
289
+ // (we deliberately do NOT call setProjectCliPreference — the saved
290
+ // preference is changed only via `borg --cli <agent>`).
291
+ cli = action.cli;
292
+ }
293
+
294
+ // client#20: inspect only the SELECTED harness after the one-shot launch
295
+ // menu choice. Explicit consent enables a narrow per-process override;
296
+ // Borg never rewrites the user's approval policy here.
297
+ const approvalCwd = cli === 'codex'
298
+ ? resolveCodexLaunchCwd(parsedCli.rest, process.cwd())
299
+ : process.cwd();
300
+ const launchApproval = await resolveLaunchBorgApprovals(
301
+ cli,
302
+ defaultApprovalIo(prompt, () => process.stdin.isTTY === true, {
303
+ cwd: approvalCwd,
304
+ env: process.env,
305
+ codexArgs: parsedCli.rest,
306
+ })
307
+ );
308
+ if (launchApproval.warning) {
309
+ console.error(`${consolePrefix()}${chalk.yellow(`warning: ${launchApproval.warning}`)}`);
310
+ }
311
+
312
+ // Forward any user-supplied flags (e.g. --resume <id>, --cwd, etc.) to
313
+ // the selected agent CLI unchanged.
314
+ //
315
+ // The kickoff prompt goes at the end as the positional user-message
316
+ // argument so the SessionStart hook + drone playbook get a turn to
317
+ // execute on session start. Works for fresh sessions and resumed ones.
318
+ //
319
+ // The /loop wrapper (dynamic mode — no fixed interval) lets Claude
320
+ // self-pace iterations. We instruct it to arm a persistent Monitor on
321
+ // the inbox file so it wakes the moment another drone posts to the
322
+ // cube (the MCP client appends a line to that file in real time via
323
+ // the long-poll poller). One adaptive ScheduleWakeup recovery deadline
324
+ // backs it up: 3h ±30m while Monitor status is healthy or indeterminate,
325
+ // 15m ±3m only while explicitly broken; a real Monitor wake replaces it.
326
+ const passthroughArgs = parsedCli.rest;
327
+
328
+ // `active` (resolved above for the launch menu) also gates the inbox-Monitor
329
+ // instruction: only arm it when this project is assimilated to a cube —
330
+ // otherwise we don't know which inbox file to watch and a Monitor on a
331
+ // not-yet-relevant path produces no signal. The user can assimilate and
332
+ // relaunch to engage real-time wake; the /loop heartbeat covers the meantime.
333
+
334
+ // Set the terminal title so sibling drone sessions are
335
+ // distinguishable in Cmd-Tab / tab bars / Mission Control. No-op
336
+ // when stdout isn't a TTY (piped invocation, CI). Claude Code does
337
+ // not set its own title, so this persists for the session.
338
+ setTerminalTitle(
339
+ active ? { label: active.droneLabel, cubeName: active.name } : null,
340
+ basename(process.cwd())
341
+ );
342
+
343
+ // gh#929: the claude wake-path/Monitor-arming clause is the SHARED
344
+ // wakePathArming (same core the SessionStart hook + /clear orientation use)
345
+ // + the NEVER-TaskStop reminder. Codex / opencode / no-active-cube → empty.
346
+ const monitorClause = buildKickoffWakePathClause(
347
+ cli,
348
+ active && cli === 'claude' ? inboxPathForDrone(active.cubeId, active.droneId) : null,
349
+ active && cli === 'claude'
350
+ ? monitorStateRootForWorktree(findProjectRoot(process.cwd()))
351
+ : null
352
+ );
353
+
354
+ const codexWakeNonce = cli === 'codex' ? `borg-wake-${randomUUID()}` : null;
355
+ let codexWakePathClause: string | undefined;
356
+ let remoteArgs: string[] = [];
357
+ // gh#673 P1: mark the agent session as borg-launched. Claude Code's MCP
358
+ // child + hook commands inherit this env, gating the borg activation
359
+ // surface (launch-gate.ts). ACTIVATION-only — never a security gate.
360
+ // OpenCode MCP children get BORG_SESSION from the pinned env in the
361
+ // opencode.json config (same mechanism as codex's pinned env).
362
+ // Pin CLI identity independently of a model selection and the optional
363
+ // Codex remote-wake transport. In particular, clear a stale Codex marker
364
+ // before a Codex -> Claude relaunch can reach its MCP child.
365
+ let launchEnv: NodeJS.ProcessEnv = { ...withAgentRuntimeEnv(process.env, cli), BORG_SESSION: '1' };
366
+ if (cli === 'opencode' && launchApproval.openCodePermission) {
367
+ launchEnv.OPENCODE_PERMISSION = launchApproval.openCodePermission;
368
+ }
369
+ let codexSocketPath: string | null = null;
370
+ let codexServerCleanup: (() => void) | null = null;
371
+ if (cli === 'codex' && !passthroughArgs.includes('--remote')) {
372
+ console.error(`${consolePrefix()}${chalk.gray('◼ Starting Codex remote-wake app-server…')}`);
373
+ const remote = await prepareCodexRemoteLaunch(defaultCodexRemoteDeps());
374
+ if (remote.warning) {
375
+ console.error(`${consolePrefix()}${chalk.yellow(`warning: ${remote.warning}`)}`);
376
+ codexWakePathClause =
377
+ `⚠ Codex wake-path capability check failed: remote-control is unavailable for this session. Run borg_regen manually whenever you return, and expect only fallback wakeups until relaunch.`;
378
+ } else {
379
+ codexWakePathClause =
380
+ `Codex wake-path capability check passed: remote-control socket established for this session.`;
381
+ }
382
+ remoteArgs = remote.args;
383
+ launchEnv = {
384
+ ...withAgentRuntimeEnv(process.env, cli),
385
+ ...remote.env,
386
+ BORG_SESSION: '1',
387
+ };
388
+ codexSocketPath = socketPathFromRemoteArgs(remote.args);
389
+ codexServerCleanup = remote.server?.cleanup ?? null;
390
+ } else if (cli === 'codex' && passthroughArgs.includes('--remote')) {
391
+ codexWakePathClause =
392
+ `Codex wake-path capability check: using caller-provided --remote socket; if no wake arrives, run borg_regen manually when returning to the session.`;
393
+ codexSocketPath = socketPathFromRemoteArgs(passthroughArgs);
394
+ if (codexSocketPath) {
395
+ launchEnv = {
396
+ ...withAgentRuntimeEnv(process.env, cli),
397
+ [BORG_CODEX_REMOTE_WAKE_ENV]: '1',
398
+ BORG_SESSION: '1',
399
+ };
400
+ }
401
+ }
402
+
403
+ const kickoff = buildAgentKickoffPrompt({
404
+ cli,
405
+ codexWakeNonce,
406
+ monitorClause,
407
+ codexWakePathClause,
408
+ });
409
+ // This stays separate from the shared kickoff so Claude and Codex preserve
410
+ // their existing launch prompts. OpenCode records this nonce-bearing copy
411
+ // and later uses the nonce to bind its separately spawned MCP child.
412
+ let openCodeKickoff: ReturnType<typeof createOpenCodeLaunchKickoff> | null = null;
413
+ let launchArgs: string[];
414
+ if (cli === 'codex') {
415
+ // gh#673 P1-codex: codex MCP children only see the pinned
416
+ // [mcp_servers.borg.env], never inherited env (V2 probe) — deliver
417
+ // the borg-launch marker and selected CLI identity via per-invocation
418
+ // -c overrides instead (V2b-proven). Remote wake remains a separate
419
+ // transport capability, explicitly disabled when this launch has no
420
+ // socket so legacy static config cannot spuriously arm a bridge.
421
+ // client#20: the exact approval overrides above are launch-scoped and
422
+ // consented. They remain separate from activation/identity/wake config.
423
+ launchArgs = [
424
+ ...launchApproval.codexArgs,
425
+ ...codexBorgSessionConfigArgs(),
426
+ ...codexAgentKindConfigArgs(),
427
+ ...codexRemoteWakeConfigArgs(codexSocketPath !== null),
428
+ ...remoteArgs,
429
+ ...withCodexCwdArg([...passthroughArgs, kickoff], process.cwd()),
430
+ ];
431
+ } else if (cli === 'opencode') {
432
+ // OpenCode launch: start TUI with the kickoff passed via --prompt
433
+ // (auto-submits it as the first message). BORG_SESSION is pinned in
434
+ // opencode.json. A unique port is assigned so the MCP child can connect
435
+ // via the HTTP API for context-streaming (injectOpenCodeEntry).
436
+ const dronePort = active
437
+ ? computeOpenCodePort(active.droneId)
438
+ : 14096;
439
+ installBorgPlugin();
440
+ openCodeKickoff = createOpenCodeLaunchKickoff(kickoff);
441
+ launchArgs = buildOpenCodeLaunchArgs(process.cwd(), dronePort, openCodeKickoff.prompt, passthroughArgs);
442
+ } else {
443
+ // gh#702: borg-launched claude drones auto-allow ONLY mcp__borg__* so they
444
+ // never prompt on borg coordination calls; Bash/file/web still prompt.
445
+ launchArgs = buildClaudeLaunchArgs(passthroughArgs, kickoff);
446
+ }
447
+
448
+ const cliDisplayName = cli === 'claude' ? 'Claude Code' : cli === 'codex' ? 'Codex' : 'OpenCode';
449
+ console.error(`${consolePrefix()}${chalk.blue(`◼ Launching ${cliDisplayName}…`)}`);
450
+
451
+ const agentProcess = spawn(cli, launchArgs, {
452
+ stdio: 'inherit',
453
+ shell: false,
454
+ env: launchEnv,
455
+ });
456
+
457
+ // gh#opencode: find the opened session after launch. The kickoff was already
458
+ // submitted via --prompt, so we just discover the session ID for inbox
459
+ // entry injection. Fire-and-forget; never delay the launch.
460
+ if (cli === 'opencode' && openCodeKickoff) {
461
+ const launchKickoff = openCodeKickoff;
462
+ const dronePort = active
463
+ ? computeOpenCodePort(active.droneId)
464
+ : 14096;
465
+ const serverUrl = `http://127.0.0.1:${dronePort}`;
466
+ // Fire-and-forget; never delay the launch or crash on failure.
467
+ connectOpenCodeDrone({ serverUrl, directory: process.cwd(), droneLabel: active?.droneLabel ?? 'opencode', cubeName: active?.name ?? 'borg' })
468
+ .then(() => injectInitialKickoff(launchKickoff))
469
+ .catch(() => {});
470
+ }
471
+
472
+ // gh#857 WI-2: wake-target recording is codex-only (app-server bridge).
473
+ // OpenCode has no remote-wake mechanisms yet; claude uses the inbox Monitor.
474
+ if (cli === 'codex' && active && codexSocketPath) {
475
+ void recordCodexWakeTarget({
476
+ deps: { setCodexWakeTarget, findLoadedCodexThread },
477
+ cubeId: active.cubeId,
478
+ droneId: active.droneId,
479
+ socketPath: codexSocketPath,
480
+ passthroughArgs,
481
+ previewNeedle: codexWakeNonce ?? kickoff.slice(0, 120),
482
+ cwd: process.cwd(),
483
+ launchedAtSeconds: Math.floor(Date.now() / 1000),
484
+ });
485
+ // gh#855: self-heal the wake-target file — drop entries whose app-server
486
+ // socket is positively dead (crashed prior launches), mirroring the
487
+ // socket-dir pruneStaleSockets. Best-effort; never blocks the launch.
488
+ void pruneDeadCodexWakeTargets((sock) => checkCodexBridgeHealthy(sock));
489
+ }
490
+
491
+ agentProcess.on('error', (err: NodeJS.ErrnoException) => {
492
+ if (codexServerCleanup) {
493
+ try {
494
+ codexServerCleanup();
495
+ } catch {
496
+ // best-effort
497
+ }
498
+ }
499
+ if (err.code === 'ENOENT') {
500
+ console.error(`${consolePrefix()}${chalk.red(`\n◼ Failed to launch ${cli}`)}`);
501
+ const cliName = cli === 'opencode' ? 'opencode' : cli;
502
+ console.error(`${consolePrefix()}${chalk.gray(`Make sure ${cliName} is installed.\n`)}`);
503
+ } else {
504
+ console.error(`${consolePrefix()}${chalk.red(`\n◼ Failed to launch ${cli}: ${err.message}\n`)}`);
505
+ }
506
+ process.exit(1);
507
+ });
508
+
509
+ agentProcess.on('exit', (code) => {
510
+ if (codexServerCleanup) {
511
+ try {
512
+ codexServerCleanup();
513
+ } catch {
514
+ // best-effort
515
+ }
516
+ }
517
+ process.exit(code ?? 0);
518
+ });
519
+ }
520
+
521
+ function ensureDetectedCliConfigured(): void {
522
+ const found = detectCliAvailability();
523
+ if (found.claude) {
524
+ try {
525
+ ensureCliMcpConfigured('claude');
526
+ // gh#673 P2 (WI-1): the orientation hook lives PROJECT-LOCAL in
527
+ // <root>/.claude/settings.local.json — ensured on every bare
528
+ // `borg` launch so pre-P2 worktrees self-heal. The legacy GLOBAL
529
+ // hook is then removed: safe because this ensure precedes every
530
+ // borg-launched agent spawn (other projects get their local hook
531
+ // at their own next launch/assimilate), and P1's BORG_SESSION
532
+ // gate already no-ops the global hook in non-borg sessions.
533
+ addProjectSessionStartHook(findProjectRoot(process.cwd()));
534
+ removeSessionStartHook();
535
+ addUserPromptSubmitHook();
536
+ } catch (err: any) {
537
+ console.error(`${consolePrefix()}${chalk.yellow(`warning: Claude Code integration check failed: ${err?.message ?? err}`)}`);
538
+ }
539
+ }
540
+ if (found.codex) {
541
+ try {
542
+ ensureCliMcpConfigured('codex');
543
+ addCodexSessionStartHook();
544
+ addCodexUserPromptSubmitHook();
545
+ } catch (err: any) {
546
+ console.error(`${consolePrefix()}${chalk.yellow(`warning: Codex integration check failed: ${err?.message ?? err}`)}`);
547
+ }
548
+ }
549
+ if (found.opencode) {
550
+ try {
551
+ ensureCliMcpConfigured('opencode');
552
+ } catch (err: any) {
553
+ console.error(`${consolePrefix()}${chalk.yellow(`warning: OpenCode integration check failed: ${err?.message ?? err}`)}`);
554
+ }
555
+ }
556
+ }
557
+
558
+ main().catch((error) => {
559
+ console.error(`${consolePrefix()}${chalk.red(`\n◼ Error: ${error.message}\n`)}`);
560
+ process.exit(1);
561
+ });