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
@@ -0,0 +1,333 @@
1
+ /**
2
+ * 0600 flocked atomic file store (Queen rescope: replaces the OS keychain).
3
+ *
4
+ * This is the SINGLE storage primitive the collapsed seat/credential model sits
5
+ * on. It provides one advisory lock plus an atomic 0600 read-compare-write so
6
+ * that a record and everything that must stay consistent with it are written as
7
+ * ONE atomic unit (a temp-write + rename either lands wholly or not at all).
8
+ *
9
+ * SR-seven file-store checklist (fb0e446d) implemented here:
10
+ * 1. 0600 AT CREATE — the temp file is opened O_CREAT|O_EXCL mode 0600, and
11
+ * rename preserves the mode, so the secret is never world/group-readable for
12
+ * any window (no write-then-chmod).
13
+ * 2. ATOMIC RENAME — temp in the SAME dir/fs, created 0600, fsync THEN rename;
14
+ * a crash never leaves a torn/readable partial, and the temp is cleaned up
15
+ * on any write failure.
16
+ * 3. PARENT DIR 0700 — created with mode 0700.
17
+ * 4. flock DISCIPLINE — a single advisory lock (O_EXCL lockfile), RULED option
18
+ * (b) (Coordinator cca6957a): NO automatic reclaim, EVER. Acquire is an atomic
19
+ * `open(lockPath,'wx',0o600)`; the whole read-compare-write runs inside ONE
20
+ * continuous hold, released on EVERY path (finally) by unlinking our OWN lock.
21
+ * A pre-existing lock held by a LIVE pid is waited on (bounded) then reported
22
+ * transient-busy; a lock whose recorded pid is DEAD (or whose payload is
23
+ * missing/unparseable) FAILS CLOSED naming the exact lockfile path — Borg NEVER
24
+ * steals or auto-deletes it (rename-claim reclaim is rejected: pathname
25
+ * substitution). No per-account locks, no TOCTOU between acquire and commit.
26
+ *
27
+ * The raw secret rests only in the 0600 file (parity with the server's TLS keys);
28
+ * this module never logs it, and the digest-only observation discipline of the
29
+ * callers keeps the raw bearer from leaving the store owner.
30
+ */
31
+
32
+ import { open, link, mkdir, readFile, rename, stat, unlink } from 'node:fs/promises';
33
+ import { dirname } from 'node:path';
34
+ import { randomBytes } from 'node:crypto';
35
+
36
+ const LOCK_WAIT_MS = 10;
37
+ const LOCK_ATTEMPTS = 500;
38
+
39
+ interface LockPayload {
40
+ pid: number;
41
+ /** ISO process start time — an operator-facing hint and a PID-reuse tell. */
42
+ startTime: string;
43
+ }
44
+
45
+ /**
46
+ * Liveness check for the alive/dead branch (RULED option b). `process.kill(pid, 0)`
47
+ * sends no signal but validates the target: ESRCH ⇒ no such process (DEAD → fail
48
+ * closed); EPERM ⇒ the process exists but is owned by another user (ALIVE → wait).
49
+ * Any success ⇒ alive. This decides ONLY whether to wait vs. fail closed — it never
50
+ * authorizes a reclaim.
51
+ */
52
+ function isProcessAlive(pid: number): boolean {
53
+ if (!Number.isInteger(pid) || pid <= 0) return false;
54
+ try {
55
+ process.kill(pid, 0);
56
+ return true;
57
+ } catch (err) {
58
+ return (err as NodeJS.ErrnoException).code === 'EPERM';
59
+ }
60
+ }
61
+
62
+ /** Approximate wall-clock process start time (Date.now() − uptime). */
63
+ function processStartTime(): string {
64
+ return new Date(Date.now() - Math.round(process.uptime() * 1000)).toISOString();
65
+ }
66
+
67
+ function parseLockPayload(raw: string): LockPayload | null {
68
+ try {
69
+ const parsed = JSON.parse(raw) as { pid?: unknown; startTime?: unknown };
70
+ if (typeof parsed.pid === 'number' && Number.isInteger(parsed.pid) && parsed.pid > 0) {
71
+ return {
72
+ pid: parsed.pid,
73
+ startTime: typeof parsed.startTime === 'string' ? parsed.startTime : 'unknown',
74
+ };
75
+ }
76
+ } catch {
77
+ /* unparseable — treated as a corrupt/foreign lock by the caller (fail closed) */
78
+ }
79
+ return null;
80
+ }
81
+
82
+ /**
83
+ * The fail-closed stale-lock error (RULED option b). Names the EXACT lockfile path
84
+ * plus the recorded dead pid / start time, and tells the operator to delete that
85
+ * file ONLY if no borg process is running. Borg never removes it automatically.
86
+ */
87
+ function staleLockError(lockPath: string, held: LockPayload | null): Error {
88
+ const who = held
89
+ ? `its recorded owner process (pid ${held.pid}, started ${held.startTime}) is no longer running`
90
+ : 'its lock file is missing a valid owner identity or is corrupt';
91
+ return new Error(
92
+ `Borg seat store lock file ${lockPath} is stale: ${who}. ` +
93
+ 'Borg will NOT remove it automatically. If no borg process is running on this ' +
94
+ `machine, delete ${lockPath} and retry; otherwise wait for the other borg process to finish.`,
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Ensure the store's parent directory exists at 0700 (checklist #3) AND repair-or-
100
+ * refuse a loose pre-existing one (CR3c). `mkdir(mode)` does NOT tighten an already-
101
+ * existing directory, so a pre-existing world/group-traversable parent would leave
102
+ * the 0600 credential-at-rest reachable. Fail CLOSED rather than write a secret
103
+ * beneath it.
104
+ */
105
+ async function ensureParentDir(filePath: string): Promise<void> {
106
+ const dir = dirname(filePath);
107
+ let existing: Awaited<ReturnType<typeof stat>> | null = null;
108
+ try {
109
+ existing = await stat(dir);
110
+ } catch (err) {
111
+ if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;
112
+ }
113
+ if (existing) {
114
+ if ((existing.mode & 0o777) !== 0o700) {
115
+ throw new Error(
116
+ `Borg store directory ${dir} has insecure permissions ` +
117
+ `(0${(existing.mode & 0o777).toString(8)}, expected 0700); refusing to write a credential under it`,
118
+ );
119
+ }
120
+ return;
121
+ }
122
+ await mkdir(dir, { recursive: true, mode: 0o700 });
123
+ }
124
+
125
+ /**
126
+ * Atomic 0600 write (checklist #1 + #2): write to a same-dir temp opened
127
+ * O_CREAT|O_EXCL at mode 0600 (never write-then-chmod), fsync the data, then
128
+ * rename over the target (atomic; the mode carries across). A failed write
129
+ * cleans up the temp so no leftover file ever holds the secret.
130
+ */
131
+ export async function atomicWrite0600(filePath: string, data: string): Promise<void> {
132
+ await ensureParentDir(filePath);
133
+ const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`;
134
+ const handle = await open(tmp, 'wx', 0o600);
135
+ try {
136
+ await handle.writeFile(data);
137
+ await handle.sync();
138
+ } catch (err) {
139
+ await handle.close().catch(() => {});
140
+ await unlink(tmp).catch(() => {});
141
+ throw err;
142
+ }
143
+ await handle.close();
144
+ try {
145
+ await rename(tmp, filePath);
146
+ } catch (err) {
147
+ await unlink(tmp).catch(() => {});
148
+ throw err;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * CR#2: enforce the at-rest perms on the READ / no-op paths too (not just
154
+ * atomicWrite). A secret must NEVER be read from a group/other-accessible store
155
+ * file, nor from under a group/other-traversable parent. Fail CLOSED without
156
+ * reading the bytes. Mirrors the server-trust.ts `(mode & 0o077) !== 0` idiom.
157
+ */
158
+ async function assertSecureStorePerms(
159
+ filePath: string,
160
+ fileMode: number,
161
+ ): Promise<void> {
162
+ if ((fileMode & 0o077) !== 0) {
163
+ throw new Error(
164
+ `Borg seat store file ${filePath} has insecure permissions ` +
165
+ `(0${(fileMode & 0o777).toString(8)}, expected 0600); refusing to read a credential from it`,
166
+ );
167
+ }
168
+ const dir = dirname(filePath);
169
+ let dirStat: Awaited<ReturnType<typeof stat>>;
170
+ try {
171
+ dirStat = await stat(dir);
172
+ } catch (err) {
173
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') return; // vanished — readFile handles
174
+ throw err;
175
+ }
176
+ if ((dirStat.mode & 0o077) !== 0) {
177
+ throw new Error(
178
+ `Borg seat store directory ${dir} has insecure permissions ` +
179
+ `(0${(dirStat.mode & 0o777).toString(8)}, expected 0700); refusing to read a credential under it`,
180
+ );
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Read the store file, or null when it does not exist (ONLY the missing-file
186
+ * no-op path initializes empty). When the file exists, the 0600-store + 0700-parent
187
+ * perms are enforced BEFORE the bytes are read (CR#2) — a loosely-permissioned
188
+ * secret fails closed and is never read.
189
+ */
190
+ export async function readStoreFile(filePath: string): Promise<string | null> {
191
+ let fileStat: Awaited<ReturnType<typeof stat>>;
192
+ try {
193
+ fileStat = await stat(filePath);
194
+ } catch (err) {
195
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;
196
+ throw err;
197
+ }
198
+ await assertSecureStorePerms(filePath, fileStat.mode);
199
+ try {
200
+ return await readFile(filePath, 'utf8');
201
+ } catch (err) {
202
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;
203
+ throw err;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Acquire the single advisory lock (checklist #4, RULED option b), run `op`, and
209
+ * release it on EVERY path (finally) by unlinking OUR OWN lock. Acquire is an atomic
210
+ * `open(lockPath,'wx',0o600)`. On EEXIST the lock is held:
211
+ * - holder PID ALIVE → bounded wait/retry (attempts×waitMs), then throw the truthful
212
+ * transient 'Borg seat store is busy' error;
213
+ * - holder PID DEAD, or the payload is missing/unparseable → FAIL CLOSED naming the
214
+ * exact lockfile path + the recorded dead pid/start-time. Borg NEVER auto-deletes
215
+ * or steals it (no reclaim, no rename-claim). The operator clears it by hand only
216
+ * after confirming no borg process is running.
217
+ * Because nothing ever steals a held lock, a plain unlink of our own lock on release
218
+ * is safe (no successor can be holding it).
219
+ */
220
+ export async function withStoreLock<T>(
221
+ lockPath: string,
222
+ op: () => Promise<T>,
223
+ opts: { attempts?: number; waitMs?: number } = {},
224
+ ): Promise<T> {
225
+ const attempts = opts.attempts ?? LOCK_ATTEMPTS;
226
+ const waitMs = opts.waitMs ?? LOCK_WAIT_MS;
227
+ await mkdir(dirname(lockPath), { recursive: true, mode: 0o700 });
228
+ const myPayload = JSON.stringify({ pid: process.pid, startTime: processStartTime() });
229
+ // Stage the FULLY-WRITTEN payload in a same-dir temp, then acquire by atomically
230
+ // hard-linking it into place. `link` is atomic (EEXIST when the lock is held), and
231
+ // because the target appears already carrying the complete payload there is NO
232
+ // empty creation window — a concurrent contender never misreads a just-created
233
+ // lock as a corrupt/missing payload (which under option (b) would wrongly fail
234
+ // closed). A plain `open('wx')` create-then-write leaves exactly that window.
235
+ const tmp = `${lockPath}.${process.pid}.${randomBytes(6).toString('hex')}.acq`;
236
+ const staged = await open(tmp, 'wx', 0o600);
237
+ try {
238
+ await staged.writeFile(myPayload);
239
+ } finally {
240
+ await staged.close();
241
+ }
242
+ try {
243
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
244
+ try {
245
+ await link(tmp, lockPath);
246
+ } catch (err) {
247
+ if ((err as NodeJS.ErrnoException).code !== 'EEXIST') throw err;
248
+ // The lock is held. Inspect the holder — but NEVER reclaim/steal it.
249
+ let raw: string;
250
+ try {
251
+ raw = await readFile(lockPath, 'utf8');
252
+ } catch (readErr) {
253
+ if ((readErr as NodeJS.ErrnoException).code === 'ENOENT') continue; // released — retry
254
+ throw readErr;
255
+ }
256
+ const held = parseLockPayload(raw);
257
+ if (held && isProcessAlive(held.pid)) {
258
+ // A live-but-slow holder keeps its lock: wait a bounded interval and retry.
259
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, waitMs));
260
+ continue;
261
+ }
262
+ // Dead recorded holder, or a missing/unparseable payload → fail closed. The
263
+ // operator must confirm no borg process is running and delete the file by hand.
264
+ throw staleLockError(lockPath, held);
265
+ }
266
+ // We own the lock (it already carries our payload from the staged temp).
267
+ try {
268
+ return await op();
269
+ } finally {
270
+ // No reclaim exists, so nobody can be holding our lock — a plain unlink is safe.
271
+ await unlink(lockPath).catch((e: NodeJS.ErrnoException) => {
272
+ if (e.code !== 'ENOENT') throw e;
273
+ });
274
+ }
275
+ }
276
+ throw new Error('Borg seat store is busy');
277
+ } finally {
278
+ await unlink(tmp).catch(() => {});
279
+ }
280
+ }
281
+
282
+ /** A locked, in-memory transaction over one store file. */
283
+ export interface StoreTxn<S> {
284
+ /** The mutable in-memory state, loaded under the lock. Mutate then commit(). */
285
+ data: S;
286
+ /** Atomically persist `data` (0600) — the single-write commit of the RCW. */
287
+ commit(): Promise<void>;
288
+ }
289
+
290
+ /**
291
+ * Run a read-compare-write transaction over `storePath` under the single store
292
+ * lock: load the current state (or an empty one), hand the caller a mutable view
293
+ * + an atomic commit, and release the lock on every path. The entire read →
294
+ * compare → (mutate) → commit happens inside ONE lock hold — no TOCTOU.
295
+ */
296
+ export async function withStore<S, T>(
297
+ storePath: string,
298
+ emptyState: () => S,
299
+ parse: (raw: string) => S | null,
300
+ op: (txn: StoreTxn<S>) => Promise<T>,
301
+ ): Promise<T> {
302
+ return withStoreLock(`${storePath}.lock`, async () => {
303
+ const raw = await readStoreFile(storePath);
304
+ // CR4 fail-closed: ONLY a missing file (ENOENT → readStoreFile returns null)
305
+ // may initialize an empty state. A present-but-malformed / wrong-version /
306
+ // schema-invalid store must NEVER be silently mapped to empty and then
307
+ // OVERWRITTEN by a subsequent commit — that erases every seat/credential and
308
+ // silently recreates authority. Throw WITHOUT writing so the corrupt bytes are
309
+ // preserved for recovery (parity with getServerCredentialRecord).
310
+ let data: S;
311
+ if (raw === null) {
312
+ data = emptyState();
313
+ } else {
314
+ let loaded: S | null;
315
+ try {
316
+ loaded = parse(raw);
317
+ } catch {
318
+ loaded = null;
319
+ }
320
+ if (loaded === null) {
321
+ throw new Error(
322
+ 'Borg seat store is malformed or has an unsupported version; refusing to overwrite it',
323
+ );
324
+ }
325
+ data = loaded;
326
+ }
327
+ const txn: StoreTxn<S> = {
328
+ data,
329
+ commit: () => atomicWrite0600(storePath, JSON.stringify(data, null, 2) + '\n'),
330
+ };
331
+ return op(txn);
332
+ });
333
+ }