borgmcp 1.1.15 → 2.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 (459) 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.map +1 -0
  71. package/dist/codex-app-wake.js +432 -2
  72. package/dist/codex-app-wake.js.map +1 -0
  73. package/dist/codex-launch.d.ts.map +1 -0
  74. package/dist/codex-launch.js +102 -2
  75. package/dist/codex-launch.js.map +1 -0
  76. package/dist/codex-remote.d.ts +6 -1
  77. package/dist/codex-remote.d.ts.map +1 -0
  78. package/dist/codex-remote.js +394 -1
  79. package/dist/codex-remote.js.map +1 -0
  80. package/dist/codex-wake-resolve.d.ts.map +1 -0
  81. package/dist/codex-wake-resolve.js +127 -1
  82. package/dist/codex-wake-resolve.js.map +1 -0
  83. package/dist/config-utils.d.ts +2 -2
  84. package/dist/config-utils.d.ts.map +1 -0
  85. package/dist/config-utils.js +766 -3
  86. package/dist/config-utils.js.map +1 -0
  87. package/dist/config.d.ts +98 -61
  88. package/dist/config.d.ts.map +1 -0
  89. package/dist/config.js +426 -1
  90. package/dist/config.js.map +1 -0
  91. package/dist/console-prefix.d.ts.map +1 -0
  92. package/dist/console-prefix.js +96 -1
  93. package/dist/console-prefix.js.map +1 -0
  94. package/dist/cube-name.d.ts.map +1 -0
  95. package/dist/cube-name.js +67 -1
  96. package/dist/cube-name.js.map +1 -0
  97. package/dist/cubes.d.ts +126 -18
  98. package/dist/cubes.d.ts.map +1 -0
  99. package/dist/cubes.js +412 -4
  100. package/dist/cubes.js.map +1 -0
  101. package/dist/debug.d.ts.map +1 -0
  102. package/dist/debug.js +71 -1
  103. package/dist/debug.js.map +1 -0
  104. package/dist/direct-log.d.ts.map +1 -0
  105. package/dist/direct-log.js +11 -1
  106. package/dist/direct-log.js.map +1 -0
  107. package/dist/docs-sections.d.ts +11 -10
  108. package/dist/docs-sections.d.ts.map +1 -0
  109. package/dist/docs-sections.js +113 -3
  110. package/dist/docs-sections.js.map +1 -0
  111. package/dist/drone-lifecycle.d.ts +5 -21
  112. package/dist/drone-lifecycle.d.ts.map +1 -0
  113. package/dist/drone-lifecycle.js +57 -8
  114. package/dist/drone-lifecycle.js.map +1 -0
  115. package/dist/drone-management.d.ts +29 -0
  116. package/dist/drone-management.d.ts.map +1 -0
  117. package/dist/drone-management.js +109 -0
  118. package/dist/drone-management.js.map +1 -0
  119. package/dist/ensure-mcp-config.d.ts.map +1 -0
  120. package/dist/ensure-mcp-config.js +36 -1
  121. package/dist/ensure-mcp-config.js.map +1 -0
  122. package/dist/evict-drone.d.ts +10 -2
  123. package/dist/evict-drone.d.ts.map +1 -0
  124. package/dist/evict-drone.js +60 -1
  125. package/dist/evict-drone.js.map +1 -0
  126. package/dist/gc-orphan-inboxes.d.ts.map +1 -0
  127. package/dist/gc-orphan-inboxes.js +177 -1
  128. package/dist/gc-orphan-inboxes.js.map +1 -0
  129. package/dist/inbox-monitor.d.ts +1 -1
  130. package/dist/inbox-monitor.d.ts.map +1 -0
  131. package/dist/inbox-monitor.js +856 -3
  132. package/dist/inbox-monitor.js.map +1 -0
  133. package/dist/index.d.ts +6 -4
  134. package/dist/index.d.ts.map +1 -0
  135. package/dist/index.js +1034 -37
  136. package/dist/index.js.map +1 -0
  137. package/dist/launch-all-cmd.d.ts.map +1 -0
  138. package/dist/launch-all-cmd.js +377 -37
  139. package/dist/launch-all-cmd.js.map +1 -0
  140. package/dist/launch-all-command.d.ts.map +1 -0
  141. package/dist/launch-all-command.js +24 -1
  142. package/dist/launch-all-command.js.map +1 -0
  143. package/dist/launch-all-deps.d.ts +3 -8
  144. package/dist/launch-all-deps.d.ts.map +1 -0
  145. package/dist/launch-all-deps.js +99 -1
  146. package/dist/launch-all-deps.js.map +1 -0
  147. package/dist/launch-all-discovery.d.ts +1 -0
  148. package/dist/launch-all-discovery.d.ts.map +1 -0
  149. package/dist/launch-all-discovery.js +90 -4
  150. package/dist/launch-all-discovery.js.map +1 -0
  151. package/dist/launch-all-locks.d.ts.map +1 -0
  152. package/dist/launch-all-locks.js +54 -1
  153. package/dist/launch-all-locks.js.map +1 -0
  154. package/dist/launch-gate.d.ts +2 -2
  155. package/dist/launch-gate.d.ts.map +1 -0
  156. package/dist/launch-gate.js +73 -1
  157. package/dist/launch-gate.js.map +1 -0
  158. package/dist/lifecycle-log-guard.d.ts.map +1 -0
  159. package/dist/lifecycle-log-guard.js +93 -2
  160. package/dist/lifecycle-log-guard.js.map +1 -0
  161. package/dist/list-roles-render.d.ts.map +1 -0
  162. package/dist/list-roles-render.js +40 -6
  163. package/dist/list-roles-render.js.map +1 -0
  164. package/dist/local-log-routing.d.ts +19 -0
  165. package/dist/local-log-routing.d.ts.map +1 -0
  166. package/dist/local-log-routing.js +67 -0
  167. package/dist/local-log-routing.js.map +1 -0
  168. package/dist/local-manage-tool-result.d.ts +8 -0
  169. package/dist/local-manage-tool-result.d.ts.map +1 -0
  170. package/dist/local-manage-tool-result.js +10 -0
  171. package/dist/local-manage-tool-result.js.map +1 -0
  172. package/dist/local-server-cursor.d.ts +34 -0
  173. package/dist/local-server-cursor.d.ts.map +1 -0
  174. package/dist/local-server-cursor.js +151 -0
  175. package/dist/local-server-cursor.js.map +1 -0
  176. package/dist/log-audit.d.ts.map +1 -0
  177. package/dist/log-audit.js +194 -3
  178. package/dist/log-audit.js.map +1 -0
  179. package/dist/log-stream.d.ts +31 -18
  180. package/dist/log-stream.d.ts.map +1 -0
  181. package/dist/log-stream.js +1214 -12
  182. package/dist/log-stream.js.map +1 -0
  183. package/dist/model-presets.d.ts.map +1 -0
  184. package/dist/model-presets.js +19 -1
  185. package/dist/model-presets.js.map +1 -0
  186. package/dist/name-validator.d.ts.map +1 -0
  187. package/dist/name-validator.js +22 -1
  188. package/dist/name-validator.js.map +1 -0
  189. package/dist/opencode-drone.d.ts.map +1 -0
  190. package/dist/opencode-drone.js +438 -4
  191. package/dist/opencode-drone.js.map +1 -0
  192. package/dist/opencode-plugin.d.ts +1 -1
  193. package/dist/opencode-plugin.d.ts.map +1 -0
  194. package/dist/opencode-plugin.js +29 -4
  195. package/dist/opencode-plugin.js.map +1 -0
  196. package/dist/parse-assimilate-args.d.ts +1 -1
  197. package/dist/parse-assimilate-args.d.ts.map +1 -0
  198. package/dist/parse-assimilate-args.js +125 -1
  199. package/dist/parse-assimilate-args.js.map +1 -0
  200. package/dist/parse-launch-all-args.d.ts.map +1 -0
  201. package/dist/parse-launch-all-args.js +70 -1
  202. package/dist/parse-launch-all-args.js.map +1 -0
  203. package/dist/postinstall-banner.d.ts.map +1 -0
  204. package/dist/postinstall-banner.js +27 -2
  205. package/dist/postinstall-banner.js.map +1 -0
  206. package/dist/postinstall.d.ts.map +1 -0
  207. package/dist/postinstall.js +32 -5
  208. package/dist/postinstall.js.map +1 -0
  209. package/dist/readiness-probe.d.ts.map +1 -0
  210. package/dist/readiness-probe.js +9 -1
  211. package/dist/readiness-probe.js.map +1 -0
  212. package/dist/regen-format.d.ts.map +1 -0
  213. package/dist/regen-format.js +545 -13
  214. package/dist/regen-format.js.map +1 -0
  215. package/dist/regen.d.ts.map +1 -0
  216. package/dist/regen.js +141 -5
  217. package/dist/regen.js.map +1 -0
  218. package/dist/remote-client.d.ts +65 -175
  219. package/dist/remote-client.d.ts.map +1 -0
  220. package/dist/remote-client.js +942 -1
  221. package/dist/remote-client.js.map +1 -0
  222. package/dist/reset-local-seat-cmd.d.ts +50 -0
  223. package/dist/reset-local-seat-cmd.d.ts.map +1 -0
  224. package/dist/reset-local-seat-cmd.js +169 -0
  225. package/dist/reset-local-seat-cmd.js.map +1 -0
  226. package/dist/role-match.d.ts.map +1 -0
  227. package/dist/role-match.js +23 -1
  228. package/dist/role-match.js.map +1 -0
  229. package/dist/role-resolver.d.ts.map +1 -0
  230. package/dist/role-resolver.js +60 -1
  231. package/dist/role-resolver.js.map +1 -0
  232. package/dist/roster-render.d.ts.map +1 -0
  233. package/dist/roster-render.js +121 -3
  234. package/dist/roster-render.js.map +1 -0
  235. package/dist/seat-probe.d.ts +32 -13
  236. package/dist/seat-probe.d.ts.map +1 -0
  237. package/dist/seat-probe.js +78 -1
  238. package/dist/seat-probe.js.map +1 -0
  239. package/dist/seat-store.d.ts +76 -0
  240. package/dist/seat-store.d.ts.map +1 -0
  241. package/dist/seat-store.js +309 -0
  242. package/dist/seat-store.js.map +1 -0
  243. package/dist/seats.d.ts +303 -0
  244. package/dist/seats.d.ts.map +1 -0
  245. package/dist/seats.js +551 -0
  246. package/dist/seats.js.map +1 -0
  247. package/dist/self-path.d.ts +27 -0
  248. package/dist/self-path.d.ts.map +1 -0
  249. package/dist/self-path.js +43 -0
  250. package/dist/self-path.js.map +1 -0
  251. package/dist/server-endpoint.d.ts +9 -0
  252. package/dist/server-endpoint.d.ts.map +1 -0
  253. package/dist/server-endpoint.js +38 -0
  254. package/dist/server-endpoint.js.map +1 -0
  255. package/dist/server-errors.d.ts +50 -0
  256. package/dist/server-errors.d.ts.map +1 -0
  257. package/dist/server-errors.js +79 -0
  258. package/dist/server-errors.js.map +1 -0
  259. package/dist/server-handshake.d.ts +197 -0
  260. package/dist/server-handshake.d.ts.map +1 -0
  261. package/dist/server-handshake.js +505 -0
  262. package/dist/server-handshake.js.map +1 -0
  263. package/dist/server-response.d.ts +3 -0
  264. package/dist/server-response.d.ts.map +1 -0
  265. package/dist/server-response.js +67 -0
  266. package/dist/server-response.js.map +1 -0
  267. package/dist/server-trust.d.ts +14 -0
  268. package/dist/server-trust.d.ts.map +1 -0
  269. package/dist/server-trust.js +225 -0
  270. package/dist/server-trust.js.map +1 -0
  271. package/dist/setup-confirm.d.ts +3 -3
  272. package/dist/setup-confirm.d.ts.map +1 -0
  273. package/dist/setup-confirm.js +126 -2
  274. package/dist/setup-confirm.js.map +1 -0
  275. package/dist/setup.d.ts +5 -3
  276. package/dist/setup.d.ts.map +1 -0
  277. package/dist/setup.js +169 -46
  278. package/dist/setup.js.map +1 -0
  279. package/dist/shell-escape.d.ts.map +1 -0
  280. package/dist/shell-escape.js +22 -1
  281. package/dist/shell-escape.js.map +1 -0
  282. package/dist/spawn.d.ts +2 -2
  283. package/dist/spawn.d.ts.map +1 -0
  284. package/dist/spawn.js +29 -10
  285. package/dist/spawn.js.map +1 -0
  286. package/dist/startup-services.d.ts +0 -1
  287. package/dist/startup-services.d.ts.map +1 -0
  288. package/dist/startup-services.js +26 -1
  289. package/dist/startup-services.js.map +1 -0
  290. package/dist/stream-owner.d.ts +6 -2
  291. package/dist/stream-owner.d.ts.map +1 -0
  292. package/dist/stream-owner.js +547 -2
  293. package/dist/stream-owner.js.map +1 -0
  294. package/dist/stream-status.d.ts +1 -1
  295. package/dist/stream-status.d.ts.map +1 -0
  296. package/dist/stream-status.js +268 -3
  297. package/dist/stream-status.js.map +1 -0
  298. package/dist/sync-roles-render.d.ts.map +1 -0
  299. package/dist/sync-roles-render.js +118 -3
  300. package/dist/sync-roles-render.js.map +1 -0
  301. package/dist/sync.d.ts +1 -1
  302. package/dist/sync.d.ts.map +1 -0
  303. package/dist/sync.js +286 -22
  304. package/dist/sync.js.map +1 -0
  305. package/dist/terminal-title.d.ts.map +1 -0
  306. package/dist/terminal-title.js +68 -1
  307. package/dist/terminal-title.js.map +1 -0
  308. package/dist/token-store.d.ts +17 -111
  309. package/dist/token-store.d.ts.map +1 -0
  310. package/dist/token-store.js +81 -1
  311. package/dist/token-store.js.map +1 -0
  312. package/dist/tool-manifest.d.ts +4 -8
  313. package/dist/tool-manifest.d.ts.map +1 -0
  314. package/dist/tool-manifest.js +554 -1
  315. package/dist/tool-manifest.js.map +1 -0
  316. package/dist/tool-scope.d.ts +8 -12
  317. package/dist/tool-scope.d.ts.map +1 -0
  318. package/dist/tool-scope.js +97 -1
  319. package/dist/tool-scope.js.map +1 -0
  320. package/dist/types.d.ts +1 -5
  321. package/dist/types.d.ts.map +1 -0
  322. package/dist/types.js +5 -0
  323. package/dist/types.js.map +1 -0
  324. package/dist/unknown-subcommand.d.ts +1 -1
  325. package/dist/unknown-subcommand.d.ts.map +1 -0
  326. package/dist/unknown-subcommand.js +37 -1
  327. package/dist/unknown-subcommand.js.map +1 -0
  328. package/dist/version.d.ts +1 -1
  329. package/dist/version.d.ts.map +1 -0
  330. package/dist/version.js +78 -2
  331. package/dist/version.js.map +1 -0
  332. package/dist/working-repo.d.ts.map +1 -0
  333. package/dist/working-repo.js +81 -1
  334. package/dist/working-repo.js.map +1 -0
  335. package/dist/worktree-lifecycle.d.ts.map +1 -0
  336. package/dist/worktree-lifecycle.js +205 -2
  337. package/dist/worktree-lifecycle.js.map +1 -0
  338. package/docs/EXTRACTION_PROVENANCE.md +40 -0
  339. package/docs/LOCAL_SERVER.md +103 -0
  340. package/docs/RELEASING.md +120 -0
  341. package/package.json +52 -34
  342. package/src/agent-runtime.ts +69 -0
  343. package/src/assimilate-cmd.ts +1864 -0
  344. package/src/assimilate-deps.ts +444 -0
  345. package/src/assimilate-guard.ts +84 -0
  346. package/src/assimilate-welcome.ts +39 -0
  347. package/src/auth-env.ts +21 -0
  348. package/src/backends/launch-all-pastelist.ts +18 -0
  349. package/src/backends/launch-all-tmux.ts +75 -0
  350. package/src/backends/launch-all-windows.ts +110 -0
  351. package/src/bare-launch-menu.ts +148 -0
  352. package/src/claude-launch-args.ts +35 -0
  353. package/src/claude.ts +561 -0
  354. package/src/cleanup-cmd.ts +581 -0
  355. package/src/clear-rewake-core.ts +34 -0
  356. package/src/clear-rewake.ts +18 -0
  357. package/src/cli-help.ts +116 -0
  358. package/src/cli-platform.ts +127 -0
  359. package/src/cli-tool-approval.ts +716 -0
  360. package/src/codex-app-server.ts +238 -0
  361. package/src/codex-app-wake.ts +512 -0
  362. package/src/codex-launch.ts +140 -0
  363. package/src/codex-remote.ts +500 -0
  364. package/src/codex-wake-resolve.ts +155 -0
  365. package/src/config-utils.ts +811 -0
  366. package/src/config.ts +595 -0
  367. package/src/console-prefix.ts +99 -0
  368. package/src/cube-name.ts +69 -0
  369. package/src/cubes.ts +583 -0
  370. package/src/debug.ts +73 -0
  371. package/src/direct-log.ts +9 -0
  372. package/src/docs-sections.ts +129 -0
  373. package/src/drone-lifecycle.ts +62 -0
  374. package/src/drone-management.ts +162 -0
  375. package/src/ensure-mcp-config.ts +54 -0
  376. package/src/evict-drone.ts +82 -0
  377. package/src/gc-orphan-inboxes.ts +229 -0
  378. package/src/inbox-monitor.ts +1005 -0
  379. package/src/index.ts +1201 -0
  380. package/src/launch-all-cmd.ts +450 -0
  381. package/src/launch-all-command.ts +30 -0
  382. package/src/launch-all-deps.ts +188 -0
  383. package/src/launch-all-discovery.ts +118 -0
  384. package/src/launch-all-locks.ts +74 -0
  385. package/src/launch-gate.ts +80 -0
  386. package/src/lifecycle-log-guard.ts +144 -0
  387. package/src/list-roles-render.ts +52 -0
  388. package/src/local-log-routing.ts +106 -0
  389. package/src/local-manage-tool-result.ts +10 -0
  390. package/src/local-server-cursor.ts +188 -0
  391. package/src/log-audit.ts +207 -0
  392. package/src/log-stream.ts +1505 -0
  393. package/src/model-presets.ts +22 -0
  394. package/src/name-validator.ts +23 -0
  395. package/src/opencode-drone.ts +528 -0
  396. package/src/opencode-plugin.ts +38 -0
  397. package/src/parse-assimilate-args.ts +125 -0
  398. package/src/parse-launch-all-args.ts +100 -0
  399. package/src/postinstall-banner.ts +37 -0
  400. package/src/postinstall.ts +36 -0
  401. package/src/readiness-probe.ts +12 -0
  402. package/src/regen-format.ts +651 -0
  403. package/src/regen.ts +150 -0
  404. package/src/remote-client.ts +1379 -0
  405. package/src/reset-local-seat-cmd.ts +227 -0
  406. package/src/role-match.ts +29 -0
  407. package/src/role-resolver.ts +93 -0
  408. package/src/roster-render.ts +196 -0
  409. package/src/seat-probe.ts +115 -0
  410. package/src/seat-store.ts +333 -0
  411. package/src/seats.ts +741 -0
  412. package/src/self-path.ts +51 -0
  413. package/src/server-endpoint.ts +38 -0
  414. package/src/server-errors.ts +93 -0
  415. package/src/server-handshake.ts +783 -0
  416. package/src/server-response.ts +76 -0
  417. package/src/server-trust.ts +245 -0
  418. package/src/setup-confirm.ts +171 -0
  419. package/src/setup.ts +186 -0
  420. package/src/shell-escape.ts +22 -0
  421. package/src/spawn.ts +31 -0
  422. package/src/startup-services.ts +36 -0
  423. package/src/stream-owner.ts +686 -0
  424. package/src/stream-status.ts +337 -0
  425. package/src/sync-roles-render.ts +163 -0
  426. package/src/sync.ts +363 -0
  427. package/src/terminal-title.ts +76 -0
  428. package/src/token-store.ts +102 -0
  429. package/src/tool-manifest.ts +610 -0
  430. package/src/tool-scope.ts +110 -0
  431. package/src/types.ts +5 -0
  432. package/src/unknown-subcommand.ts +35 -0
  433. package/src/version.ts +82 -0
  434. package/src/working-repo.ts +99 -0
  435. package/src/worktree-lifecycle.ts +254 -0
  436. package/dist/auth-recovery.d.ts +0 -33
  437. package/dist/auth-recovery.js +0 -1
  438. package/dist/auth.d.ts +0 -103
  439. package/dist/auth.js +0 -39
  440. package/dist/device-auth.d.ts +0 -75
  441. package/dist/device-auth.js +0 -1
  442. package/dist/drone-address.d.ts +0 -26
  443. package/dist/drone-address.js +0 -1
  444. package/dist/get-started.d.ts +0 -20
  445. package/dist/get-started.js +0 -2
  446. package/dist/health-beat.d.ts +0 -134
  447. package/dist/health-beat.js +0 -1
  448. package/dist/role-section.d.ts +0 -110
  449. package/dist/role-section.js +0 -8
  450. package/dist/setup-action.d.ts +0 -20
  451. package/dist/setup-action.js +0 -1
  452. package/dist/stale-version-check.d.ts +0 -40
  453. package/dist/stale-version-check.js +0 -1
  454. package/dist/subscription-retry.d.ts +0 -40
  455. package/dist/subscription-retry.js +0 -1
  456. package/dist/templates.d.ts +0 -107
  457. package/dist/templates.js +0 -359
  458. package/dist/token-crypto.d.ts +0 -50
  459. package/dist/token-crypto.js +0 -1
@@ -0,0 +1,67 @@
1
+ import { roleSlug } from './role-resolver.js';
2
+ /**
3
+ * Resolve the public `borg_log to:` addressing forms against the local
4
+ * server's authoritative cube roster. This intentionally mirrors the hosted
5
+ * route resolver: exact drone id/label first, then displayed short UUID, then
6
+ * role name/slug expansion. Every failure is closed before the log POST so a
7
+ * miss can never degrade into a broadcast.
8
+ */
9
+ export function resolveLocalLogRecipients(recipients, drones, roles) {
10
+ const ids = new Set();
11
+ for (const recipient of recipients) {
12
+ if (recipient === '@human-seat') {
13
+ const roleIds = new Set(roles.filter((role) => role.is_human_seat === true).map((role) => role.id));
14
+ const matches = drones.filter((drone) => drone.role_id !== null && drone.role_id !== undefined && roleIds.has(drone.role_id));
15
+ if (roleIds.size === 0 || matches.length === 0) {
16
+ throw new Error('Direct-message role recipient has no active drones: @human-seat. ' +
17
+ 'Use borg_roster to find active recipients, or omit to broadcast if your role can broadcast.');
18
+ }
19
+ for (const drone of matches)
20
+ ids.add(drone.id);
21
+ continue;
22
+ }
23
+ const droneMatches = drones.filter((drone) => drone.id === recipient || drone.label === recipient);
24
+ const uniqueDroneIds = [...new Set(droneMatches.map((drone) => drone.id))];
25
+ if (uniqueDroneIds.length > 1) {
26
+ throw new Error(`Ambiguous direct-message recipient: ${recipient} matches multiple drones`);
27
+ }
28
+ if (uniqueDroneIds.length === 1) {
29
+ ids.add(uniqueDroneIds[0]);
30
+ continue;
31
+ }
32
+ const shortUuid = recipient.replace(/`/g, '').replace(/^id:/i, '').toLowerCase();
33
+ if (/^[0-9a-f]{8,}$/.test(shortUuid)) {
34
+ const prefixMatches = drones.filter((drone) => drone.id.toLowerCase().startsWith(shortUuid));
35
+ const uniquePrefixIds = [...new Set(prefixMatches.map((drone) => drone.id))];
36
+ if (uniquePrefixIds.length > 1) {
37
+ const listed = prefixMatches
38
+ .map((drone) => `${drone.id} (${drone.label ?? 'unlabeled'})`)
39
+ .join(', ');
40
+ throw new Error(`Ambiguous short-uuid recipient: ${recipient} matches multiple drones — ${listed}. ` +
41
+ 'Address by the full drone id.');
42
+ }
43
+ if (uniquePrefixIds.length === 1) {
44
+ ids.add(uniquePrefixIds[0]);
45
+ continue;
46
+ }
47
+ }
48
+ const roleMatches = roles.filter((role) => roleSlug(role.name) === roleSlug(recipient));
49
+ const uniqueRoleIds = [...new Set(roleMatches.map((role) => role.id))];
50
+ if (uniqueRoleIds.length > 1) {
51
+ throw new Error(`Ambiguous direct-message recipient: ${recipient} matches multiple roles`);
52
+ }
53
+ if (uniqueRoleIds.length === 0) {
54
+ throw new Error(`Unknown direct-message recipient: ${recipient}. ` +
55
+ 'Use an exact drone label, drone id, role name, or role slug.');
56
+ }
57
+ const roleDrones = drones.filter((drone) => drone.role_id === uniqueRoleIds[0]);
58
+ if (roleDrones.length === 0) {
59
+ throw new Error(`Direct-message role recipient has no active drones: ${recipient}. ` +
60
+ 'Use borg_roster to find active recipients, or omit to broadcast if your role can broadcast.');
61
+ }
62
+ for (const drone of roleDrones)
63
+ ids.add(drone.id);
64
+ }
65
+ return [...ids];
66
+ }
67
+ //# sourceMappingURL=local-log-routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-log-routing.js","sourceRoot":"","sources":["../src/local-log-routing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function formatLocalManageToolResult(error: unknown): {
2
+ content: {
3
+ type: "text";
4
+ text: string;
5
+ }[];
6
+ isError: true;
7
+ } | null;
8
+ //# sourceMappingURL=local-manage-tool-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-manage-tool-result.d.ts","sourceRoot":"","sources":["../src/local-manage-tool-result.ts"],"names":[],"mappings":"AAEA,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO;;;;;;SAOzD"}
@@ -0,0 +1,10 @@
1
+ import { LocalManageRequiredError } from './server-errors.js';
2
+ export function formatLocalManageToolResult(error) {
3
+ if (!(error instanceof LocalManageRequiredError))
4
+ return null;
5
+ return {
6
+ content: [{ type: 'text', text: error.message }],
7
+ isError: true,
8
+ };
9
+ }
10
+ //# sourceMappingURL=local-manage-tool-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-manage-tool-result.js","sourceRoot":"","sources":["../src/local-manage-tool-result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,MAAM,UAAU,2BAA2B,CAAC,KAAc;IACxD,IAAI,CAAC,CAAC,KAAK,YAAY,wBAAwB,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9D,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QACzD,OAAO,EAAE,IAAa;KACvB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ export interface LocalServerCursor {
2
+ id: string;
3
+ created_at: string;
4
+ }
5
+ export interface LocalServerCursorBinding {
6
+ origin: string;
7
+ trustIdentity: string;
8
+ cubeId: string;
9
+ droneId: string;
10
+ /**
11
+ * client#41: cursor-purpose namespace. Absent (the default) is the UNREAD
12
+ * WATERMARK — the point `read-log unread_only` reads from and advances only
13
+ * on an explicit successful drain. `'stream'` is the SSE DELIVERY/RESUME
14
+ * cursor the live tail advances as it delivers events. Keeping these under
15
+ * separate keys stops SSE delivery from consuming the unread watermark (a
16
+ * wake-triggering entry would otherwise disappear from `unread_only` before
17
+ * the agent drained it — a silent missed wake).
18
+ */
19
+ purpose?: 'stream';
20
+ }
21
+ export declare function getLocalServerCursor(binding: LocalServerCursorBinding): Promise<LocalServerCursor | null>;
22
+ export declare function advanceLocalServerCursor(binding: LocalServerCursorBinding, cursor: LocalServerCursor): Promise<void>;
23
+ /**
24
+ * client#42: reset (delete) a persisted cursor for `binding`. Used by the SSE
25
+ * recovery path when the server returns 410 CURSOR_EXPIRED for the stream's
26
+ * resume cursor — the pointed-at entry has been pruned server-side, so the
27
+ * stale cursor can never be resumed and must be cleared, letting the next
28
+ * stream connect re-establish from a fresh valid point (the current tail)
29
+ * instead of looping forever on the dead cursor. No-op when no cursor is
30
+ * stored for the binding.
31
+ */
32
+ export declare function clearLocalServerCursor(binding: LocalServerCursorBinding): Promise<void>;
33
+ export declare function encodeLocalServerCursor(cursor: LocalServerCursor): string;
34
+ //# sourceMappingURL=local-server-cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-server-cursor.d.ts","sourceRoot":"","sources":["../src/local-server-cursor.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB;AAyGD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAInC;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAGzE"}
@@ -0,0 +1,151 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, open, readFile, rename, stat, unlink, writeFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, join } from 'node:path';
5
+ const CURSOR_FILE = join(homedir(), '.config', 'borgmcp', 'local-server-cursors.json');
6
+ const CURSOR_LOCK = `${CURSOR_FILE}.lock`;
7
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
8
+ function cursorKey(binding) {
9
+ if (new URL(binding.origin).origin !== binding.origin ||
10
+ !UUID_RE.test(binding.cubeId) ||
11
+ !UUID_RE.test(binding.droneId)) {
12
+ throw new Error('invalid local Borg server cursor binding');
13
+ }
14
+ const hash = createHash('sha256')
15
+ .update(binding.origin)
16
+ .update('\0')
17
+ .update(binding.trustIdentity)
18
+ .update('\0')
19
+ .update(binding.cubeId)
20
+ .update('\0')
21
+ .update(binding.droneId);
22
+ // The purpose component is appended ONLY when present, so the unread-watermark
23
+ // key (purpose absent) stays byte-identical to the pre-client#41 key — already
24
+ // persisted watermarks are not orphaned by the upgrade. The 'stream' delivery
25
+ // cursor gets a distinct key.
26
+ if (binding.purpose) {
27
+ hash.update('\0').update(binding.purpose);
28
+ }
29
+ return hash.digest('hex');
30
+ }
31
+ function validCursor(value) {
32
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
33
+ return false;
34
+ const cursor = value;
35
+ return UUID_RE.test(String(cursor.id ?? '')) &&
36
+ typeof cursor.created_at === 'string' &&
37
+ Number.isFinite(Date.parse(cursor.created_at)) &&
38
+ new Date(cursor.created_at).toISOString() === cursor.created_at;
39
+ }
40
+ async function readState() {
41
+ try {
42
+ const parsed = JSON.parse(await readFile(CURSOR_FILE, 'utf8'));
43
+ if (parsed.version !== 1 ||
44
+ typeof parsed.cursors !== 'object' ||
45
+ parsed.cursors === null ||
46
+ Array.isArray(parsed.cursors) ||
47
+ Object.values(parsed.cursors).some((cursor) => !validCursor(cursor))) {
48
+ throw new Error('invalid');
49
+ }
50
+ return parsed;
51
+ }
52
+ catch (error) {
53
+ if (error.code === 'ENOENT') {
54
+ return { version: 1, cursors: {} };
55
+ }
56
+ throw new Error('local Borg server cursor state is corrupt');
57
+ }
58
+ }
59
+ async function writeState(state) {
60
+ await mkdir(dirname(CURSOR_FILE), { recursive: true });
61
+ const temporary = `${CURSOR_FILE}.${process.pid}.${Date.now()}.tmp`;
62
+ await writeFile(temporary, JSON.stringify(state, null, 2) + '\n', { mode: 0o600 });
63
+ await rename(temporary, CURSOR_FILE);
64
+ }
65
+ async function withLock(operation) {
66
+ await mkdir(dirname(CURSOR_LOCK), { recursive: true });
67
+ for (let attempt = 0; attempt < 200; attempt += 1) {
68
+ let handle;
69
+ try {
70
+ handle = await open(CURSOR_LOCK, 'wx', 0o600);
71
+ }
72
+ catch (error) {
73
+ if (error.code !== 'EEXIST')
74
+ throw error;
75
+ try {
76
+ const metadata = await stat(CURSOR_LOCK);
77
+ if (Date.now() - metadata.mtimeMs > 30_000) {
78
+ await unlink(CURSOR_LOCK);
79
+ continue;
80
+ }
81
+ }
82
+ catch (inspectionError) {
83
+ if (inspectionError.code === 'ENOENT')
84
+ continue;
85
+ throw inspectionError;
86
+ }
87
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, 10));
88
+ continue;
89
+ }
90
+ try {
91
+ return await operation();
92
+ }
93
+ finally {
94
+ await handle.close();
95
+ try {
96
+ await unlink(CURSOR_LOCK);
97
+ }
98
+ catch (error) {
99
+ if (error.code !== 'ENOENT')
100
+ throw error;
101
+ }
102
+ }
103
+ }
104
+ throw new Error('local Borg server cursor state is busy');
105
+ }
106
+ export async function getLocalServerCursor(binding) {
107
+ const key = cursorKey(binding);
108
+ const state = await readState();
109
+ return state.cursors[key] ?? null;
110
+ }
111
+ export async function advanceLocalServerCursor(binding, cursor) {
112
+ if (!validCursor(cursor))
113
+ throw new Error('invalid local Borg server cursor');
114
+ const key = cursorKey(binding);
115
+ await withLock(async () => {
116
+ const state = await readState();
117
+ const prior = state.cursors[key];
118
+ if (prior &&
119
+ (prior.created_at > cursor.created_at ||
120
+ (prior.created_at === cursor.created_at && prior.id >= cursor.id))) {
121
+ return;
122
+ }
123
+ state.cursors[key] = cursor;
124
+ await writeState(state);
125
+ });
126
+ }
127
+ /**
128
+ * client#42: reset (delete) a persisted cursor for `binding`. Used by the SSE
129
+ * recovery path when the server returns 410 CURSOR_EXPIRED for the stream's
130
+ * resume cursor — the pointed-at entry has been pruned server-side, so the
131
+ * stale cursor can never be resumed and must be cleared, letting the next
132
+ * stream connect re-establish from a fresh valid point (the current tail)
133
+ * instead of looping forever on the dead cursor. No-op when no cursor is
134
+ * stored for the binding.
135
+ */
136
+ export async function clearLocalServerCursor(binding) {
137
+ const key = cursorKey(binding);
138
+ await withLock(async () => {
139
+ const state = await readState();
140
+ if (!(key in state.cursors))
141
+ return;
142
+ delete state.cursors[key];
143
+ await writeState(state);
144
+ });
145
+ }
146
+ export function encodeLocalServerCursor(cursor) {
147
+ if (!validCursor(cursor))
148
+ throw new Error('invalid local Borg server cursor');
149
+ return Buffer.from(JSON.stringify(cursor), 'utf8').toString('base64url');
150
+ }
151
+ //# sourceMappingURL=local-server-cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-server-cursor.js","sourceRoot":"","sources":["../src/local-server-cursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-audit.d.ts","sourceRoot":"","sources":["../src/log-audit.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
package/dist/log-audit.js CHANGED
@@ -1,4 +1,195 @@
1
1
  #!/usr/bin/env node
2
- import{existsSync as l,readFileSync as g}from"node:fs";import{getActiveCube as m}from"./cubes.js";import{handleVersionFlag as h}from"./version.js";import{gateAllowsActivation as d}from"./launch-gate.js";const u=new Set(["Edit","Write","MultiEdit","NotebookEdit","Bash","apply_patch","exec_command","functions.exec_command","functions.apply_patch"]),f="mcp__borg__borg_log",y=3,_=400;function A(t){if((t?.type??t?.role)!=="user")return!1;const o=t?.message?.content??t?.content;return typeof o=="string"?o.trim().length>0:Array.isArray(o)?o.some(e=>e?.type==="text"):!1}function b(t){const n=t?.type??t?.role;return n==="assistant"||n==="response_item"}function w(t,n){const o=t?.payload,e=o?.type==="function_call"||o?.type==="custom_tool_call"?o.name:null;if(typeof e=="string"){if(e===f){n.loggedRecently=!0;return}u.has(e)&&(n.material+=1)}const r=t?.message?.content??t?.content??[];if(Array.isArray(r))for(let s=r.length-1;s>=0;s--){const i=r[s];if(i?.type==="tool_use"){if(i.name===f){n.loggedRecently=!0;return}u.has(i.name)&&(n.material+=1)}}}async function S(){if(process.stdin.isTTY)return"";const t=[];for await(const n of process.stdin)t.push(n);return Buffer.concat(t).toString("utf-8")}async function O(){if(h(),!d("borg-log-audit UserPromptSubmit hook"))return;const t=await S();let n={};if(t.trim())try{n=JSON.parse(t)}catch{return}if(!n.transcript_path||!l(n.transcript_path))return;if(n.cwd&&l(n.cwd))try{process.chdir(n.cwd)}catch{}if(!await m())return;const e=g(n.transcript_path,"utf-8").split(`
3
- `).filter(Boolean);if(e.length===0)return;let r=e.length-1;const s=p(e[r]);s&&A(s)&&r--;const i={material:0,loggedRecently:!1};let c=0;for(;r>=0&&c<_;r--,c++){const a=p(e[r]);if(a&&b(a)){if(w(a,i),i.material>=y){process.stdout.write(`Heads up: ${i.material}+ state-changing tool calls since the last \`borg_log\` post. If that work was a substantive unit (a change that ships, a blocker hit, a finding worth sharing), post to the cube log per your role's conventions before continuing.
4
- `);return}if(i.loggedRecently)return}}}function p(t){try{return JSON.parse(t)}catch{return null}}O().catch(()=>{});
2
+ /**
3
+ * borg-log-audit
4
+ *
5
+ * Domain-agnostic nudge: scans the Claude Code transcript and emits a
6
+ * one-line warning to stdout if the drone has accumulated MATERIAL_THRESHOLD
7
+ * or more state-changing tool calls (Edit / Write / Bash / etc.) since the
8
+ * last borg_log post. Wired in as a UserPromptSubmit hook so the warning
9
+ * becomes additional context for the next turn.
10
+ *
11
+ * Two refinements vs the v1 1-tool threshold (per drone-6's review):
12
+ * 1. Counts material tools across all assistant turns until either the
13
+ * threshold is hit OR a borg_log call is found (cooldown). One
14
+ * diagnostic Bash no longer triggers; substantive work always does.
15
+ * 2. Any borg_log in the scanback suppresses the nudge — so the drone
16
+ * gets a turn of breathing room after each post.
17
+ *
18
+ * Stays generic — knows nothing about git, branches, or any project's
19
+ * conventions. Only the Anthropic tool name `mcp__borg__borg_log` and a
20
+ * small set of canonical mutating tool names. If no cube is active in
21
+ * this project, silently exits.
22
+ *
23
+ * Hook input arrives as JSON on stdin (Claude Code's standard hook
24
+ * contract). The relevant field is `transcript_path`.
25
+ */
26
+ import { existsSync, readFileSync } from 'node:fs';
27
+ import { getActiveCube } from './cubes.js';
28
+ import { handleVersionFlag } from './version.js';
29
+ import { gateAllowsActivation } from './launch-gate.js';
30
+ const MATERIAL_TOOLS = new Set([
31
+ 'Edit',
32
+ 'Write',
33
+ 'MultiEdit',
34
+ 'NotebookEdit',
35
+ 'Bash',
36
+ 'apply_patch',
37
+ 'exec_command',
38
+ 'functions.exec_command',
39
+ 'functions.apply_patch',
40
+ ]);
41
+ const LOG_TOOL = 'mcp__borg__borg_log';
42
+ // Number of state-changing tool calls since the last borg_log that the
43
+ // drone is allowed before the audit nudges. 1 false-positives on
44
+ // diagnostic Bash (git status, ls, etc.); 3 has been comfortable in
45
+ // dogfooding — any substantive work crosses it within a turn or two.
46
+ const MATERIAL_THRESHOLD = 3;
47
+ // Cap on how many transcript entries we scan backwards before giving up.
48
+ // Sessions with thousands of turns still resolve in milliseconds at this
49
+ // bound, and anything truly old is no longer "the last span the drone
50
+ // failed to log."
51
+ const MAX_SCAN = 400;
52
+ function isUserPrompt(entry) {
53
+ const type = entry?.type ?? entry?.role;
54
+ if (type !== 'user')
55
+ return false;
56
+ const content = entry?.message?.content ?? entry?.content;
57
+ if (typeof content === 'string')
58
+ return content.trim().length > 0;
59
+ if (!Array.isArray(content))
60
+ return false;
61
+ // A "real" user prompt has at least one text block. A tool_result-only
62
+ // user message is a continuation of an assistant span, not a prompt.
63
+ return content.some((b) => b?.type === 'text');
64
+ }
65
+ function isAssistant(entry) {
66
+ const type = entry?.type ?? entry?.role;
67
+ return type === 'assistant' || type === 'response_item';
68
+ }
69
+ function scanAssistant(entry, state) {
70
+ const payload = entry?.payload;
71
+ const payloadToolName = payload?.type === 'function_call' || payload?.type === 'custom_tool_call'
72
+ ? payload.name
73
+ : null;
74
+ if (typeof payloadToolName === 'string') {
75
+ if (payloadToolName === LOG_TOOL) {
76
+ state.loggedRecently = true;
77
+ return;
78
+ }
79
+ if (MATERIAL_TOOLS.has(payloadToolName))
80
+ state.material += 1;
81
+ }
82
+ const content = entry?.message?.content ?? entry?.content ?? [];
83
+ if (!Array.isArray(content))
84
+ return;
85
+ // Walk the blocks newest-first WITHIN the entry. The caller already
86
+ // visits entries newest-first. Counting forward within an entry would
87
+ // either miss post-log material work (if log is in the same entry as
88
+ // later material blocks) or inflate the count with pre-log work that
89
+ // the log already covered. Reversing here keeps "material since the
90
+ // last log" honest at block granularity.
91
+ for (let i = content.length - 1; i >= 0; i--) {
92
+ const block = content[i];
93
+ if (block?.type !== 'tool_use')
94
+ continue;
95
+ if (block.name === LOG_TOOL) {
96
+ state.loggedRecently = true;
97
+ return;
98
+ }
99
+ if (MATERIAL_TOOLS.has(block.name))
100
+ state.material += 1;
101
+ }
102
+ }
103
+ async function readStdin() {
104
+ if (process.stdin.isTTY)
105
+ return '';
106
+ const chunks = [];
107
+ for await (const chunk of process.stdin)
108
+ chunks.push(chunk);
109
+ return Buffer.concat(chunks).toString('utf-8');
110
+ }
111
+ async function main() {
112
+ handleVersionFlag();
113
+ // gh#673 P1 (WI-4): the log-audit nudge only activates in
114
+ // borg-launched sessions — vanilla `claude` gets no borg hook output.
115
+ // Exit-0 no-op (a UserPromptSubmit hook must never block the prompt).
116
+ // ACTIVATION-only, never a security gate.
117
+ if (!gateAllowsActivation('borg-log-audit UserPromptSubmit hook')) {
118
+ return;
119
+ }
120
+ const raw = await readStdin();
121
+ let input = {};
122
+ if (raw.trim()) {
123
+ try {
124
+ input = JSON.parse(raw);
125
+ }
126
+ catch {
127
+ // No usable input — silent exit.
128
+ return;
129
+ }
130
+ }
131
+ if (!input.transcript_path || !existsSync(input.transcript_path))
132
+ return;
133
+ if (input.cwd && existsSync(input.cwd)) {
134
+ try {
135
+ process.chdir(input.cwd);
136
+ }
137
+ catch {
138
+ // Best-effort only; fall back to the hook process cwd.
139
+ }
140
+ }
141
+ // Only nudge if there's an active cube in this project. Otherwise the
142
+ // hook is fully inert.
143
+ const active = await getActiveCube();
144
+ if (!active)
145
+ return;
146
+ const lines = readFileSync(input.transcript_path, 'utf-8').split('\n').filter(Boolean);
147
+ if (lines.length === 0)
148
+ return;
149
+ // Walk the transcript backwards from the end. The trailing entry MAY
150
+ // be the user prompt that triggered this hook; skip it if so. From
151
+ // there, accumulate material tool calls until either we hit a borg_log
152
+ // (cooldown — suppress) or we cross MATERIAL_THRESHOLD (nudge). The
153
+ // scan stops after MAX_SCAN entries to bound work on huge sessions.
154
+ let i = lines.length - 1;
155
+ const tail = safeParse(lines[i]);
156
+ if (tail && isUserPrompt(tail))
157
+ i--;
158
+ const state = { material: 0, loggedRecently: false };
159
+ let scanned = 0;
160
+ for (; i >= 0 && scanned < MAX_SCAN; i--, scanned++) {
161
+ const entry = safeParse(lines[i]);
162
+ if (!entry)
163
+ continue;
164
+ if (isAssistant(entry)) {
165
+ scanAssistant(entry, state);
166
+ // Threshold has primacy over cooldown: when both could fire on the
167
+ // same entry (e.g. an entry containing [log, Bash, Bash, Bash]
168
+ // where the reversed scan first counts 3 material blocks before
169
+ // hitting the log), we want the nudge — the post-log material
170
+ // work hasn't been logged yet.
171
+ if (state.material >= MATERIAL_THRESHOLD) {
172
+ process.stdout.write(`Heads up: ${state.material}+ state-changing tool calls since the last \`borg_log\` post. ` +
173
+ 'If that work was a substantive unit (a change that ships, a blocker hit, a finding ' +
174
+ "worth sharing), post to the cube log per your role's conventions before continuing.\n");
175
+ return;
176
+ }
177
+ if (state.loggedRecently)
178
+ return; // cooldown
179
+ }
180
+ }
181
+ // Reached MAX_SCAN or start of transcript without finding either a
182
+ // log call or enough material work. Silent.
183
+ }
184
+ function safeParse(line) {
185
+ try {
186
+ return JSON.parse(line);
187
+ }
188
+ catch {
189
+ return null;
190
+ }
191
+ }
192
+ main().catch(() => {
193
+ // Never fail a hook — silent on error.
194
+ });
195
+ //# sourceMappingURL=log-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-audit.js","sourceRoot":"","sources":["../src/log-audit.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Real-time drone wakeup via Server-Sent Events.
3
3
  *
4
- * Replaces the long-poll + inbox-file-shim path in `client/src/inbox.ts`
4
+ * Replaces the former long-poll + inbox-file-shim wire path
5
5
  * for the wire layer; the local inbox file is preserved as the
6
6
  * Claude-side wake primitive (Monitor on tail -F) because Claude Code
7
7
  * does not currently wake idle agent loops on MCP-protocol
@@ -9,7 +9,7 @@
9
9
  * docs/superpowers/specs/2026-05-11-server-push-log-subscription.md
10
10
  *
11
11
  * Lifetimes:
12
- * - One persistent fetch-streaming connection to /api/drone/stream
12
+ * - One persistent fetch-streaming connection to the cube-scoped stream
13
13
  * per active cube.
14
14
  * - On every received `event: log`, a single line is appended to the
15
15
  * per-drone inbox file (same format the old poller wrote).
@@ -23,8 +23,29 @@
23
23
  * MCP tool can probe without perturbing the stream (no second
24
24
  * connection, no second auth — just an in-process state snapshot).
25
25
  */
26
+ import { type BroadcastHwm } from 'borgmcp-shared/log-stream-hwm';
26
27
  import { getActiveCube } from './cubes.js';
28
+ import { loadBorgServerTrust } from './server-trust.js';
29
+ import { getLocalServerCursor, type LocalServerCursor } from './local-server-cursor.js';
27
30
  import { acquireStreamLease, type StreamOwnershipSnapshot } from './stream-owner.js';
31
+ export declare const LOCAL_SERVER_SSE_FRAME_LIMIT_BYTES: number;
32
+ /**
33
+ * client#42: the server's structured code for an expired stream resume cursor
34
+ * (server 410 CURSOR_EXPIRED — the pointed-at entry was pruned). Recoverable,
35
+ * NOT terminal: distinct from DRONE_EVICTED.
36
+ */
37
+ export declare const CURSOR_EXPIRED_CODE = "CURSOR_EXPIRED";
38
+ /**
39
+ * client#42: recoverable stream error thrown when the server rejects the resume
40
+ * cursor as expired. The resume cursor is reset BEFORE this is thrown, so the
41
+ * reconnect loop's next connect re-establishes from a fresh valid point instead
42
+ * of looping forever on the dead cursor. Deliberately NOT a DroneEvictedError —
43
+ * the reconnect loop treats only DroneEvictedError as terminal, so this falls
44
+ * through to the ordinary backoff-reconnect (which now recovers).
45
+ */
46
+ export declare class StreamCursorExpiredError extends Error {
47
+ constructor(message?: string);
48
+ }
28
49
  export declare function setModuleInjectOpenCode(fn: (text: string) => Promise<boolean>): void;
29
50
  export declare const INBOX_TAIL_LINES_CAP = 512;
30
51
  export declare const INBOX_TAIL_TRIM_THRESHOLD_LINES: number;
@@ -39,10 +60,6 @@ export interface StreamStatus {
39
60
  runLoopRestartCount: number;
40
61
  ownership?: StreamOwnershipSnapshot;
41
62
  }
42
- export interface BroadcastHwm {
43
- id: string;
44
- created_at: string;
45
- }
46
63
  /**
47
64
  * Snapshot of the current stream status. Safe to call at any time
48
65
  * (returns a copy, does not interact with the running connection).
@@ -94,12 +111,14 @@ export declare function startLogStream(opts?: {
94
111
  export interface StreamDeps {
95
112
  /** Override the global fetch (tests inject a controlled Response). */
96
113
  fetchImpl?: typeof fetch;
114
+ /** Override persisted trust loading to verify pre-network confinement. */
115
+ loadTrust?: typeof loadBorgServerTrust;
116
+ /** Override stream cursor loading to verify pre-storage confinement. */
117
+ getCursor?: typeof getLocalServerCursor;
97
118
  /** Override the inbox-line append (tests assert against the calls). */
98
119
  appendLine?: (cubeId: string, droneId: string, line: string) => Promise<void>;
99
120
  /** Override durable inbox-entry dedup (tests avoid real filesystem). */
100
121
  hasInboxEntryId?: (cubeId: string, droneId: string, entryId: string, renderedLine: string) => Promise<boolean>;
101
- /** Override the auth-token fetch (tests skip the OS keychain). */
102
- getToken?: () => Promise<string>;
103
122
  /** Optional Codex app-server wake sink; tests inject a spy. */
104
123
  wakeCodex?: (reason: string) => void;
105
124
  /** Override the heartbeat watchdog timeout. */
@@ -112,14 +131,6 @@ export interface StreamDeps {
112
131
  ownerDeps?: import('./stream-owner.js').StreamOwnerDeps;
113
132
  /** Override owner stale threshold in focused duplicate-process tests. */
114
133
  ownerStaleMs?: number;
115
- /**
116
- * gh#541 WU-2: invoked after a delivered inbound entry is freshly written to
117
- * the inbox file (the wake-path RECEIPT — the event that should wake the
118
- * agent). Default records the receipt watermark + emits a best-effort health
119
- * beat (child-process HTTP via the real global fetch — its own wire, NOT the
120
- * SSE stream's fetchImpl — below the agent classifier). Tests inject a spy.
121
- */
122
- onInboxReceipt?: (active: ActiveCube, token: string) => void;
123
134
  /**
124
135
  * Optional opencode entry injector for autonomous drone processing.
125
136
  * When provided AND the injection succeeds, the inbox file write is skipped
@@ -140,6 +151,7 @@ export interface StreamDeps {
140
151
  export interface RunLoopTestDeps {
141
152
  getActiveCube?: typeof getActiveCube;
142
153
  acquireStreamLease?: typeof acquireStreamLease;
154
+ streamOnce?: typeof streamOnce;
143
155
  sleep?: (ms: number) => Promise<void>;
144
156
  maxIterations?: number;
145
157
  }
@@ -159,6 +171,7 @@ export interface ActiveCube {
159
171
  droneId: string;
160
172
  sessionToken: string;
161
173
  apiUrl: string;
174
+ serverTrustIdentity?: string;
162
175
  }
163
176
  export declare function streamOnce(active: ActiveCube, lastEventId: string | null, onEventId: (id: string) => void, deps?: StreamDeps): Promise<void>;
164
177
  export declare function streamOnceIfOwner(active: ActiveCube, lastEventId: string | null, onEventId: (id: string) => void, deps?: StreamDeps): Promise<'streamed' | 'skipped'>;
@@ -166,6 +179,7 @@ export type ParsedEvent = {
166
179
  type: 'log';
167
180
  id: string;
168
181
  data: any;
182
+ cursor?: LocalServerCursor;
169
183
  } | {
170
184
  type: 'heartbeat';
171
185
  ts: string | null;
@@ -187,7 +201,7 @@ export type ParsedEvent = {
187
201
  *
188
202
  * Exported so tests can pump a synthetic ReadableStream through it.
189
203
  */
190
- export declare function parseSSE(body: ReadableStream<Uint8Array>): AsyncGenerator<ParsedEvent>;
204
+ export declare function parseSSE(body: ReadableStream<Uint8Array>, maxFrameBytes?: number): AsyncGenerator<ParsedEvent>;
191
205
  export interface EnrichedEntry {
192
206
  id?: string;
193
207
  entry_id?: string;
@@ -196,7 +210,6 @@ export interface EnrichedEntry {
196
210
  role_name?: string | null;
197
211
  message?: string;
198
212
  }
199
- export declare function compareBroadcastHwm(a: BroadcastHwm, b: BroadcastHwm): number;
200
213
  /**
201
214
  * Format one inbox-file line. Preserves the long-poll inbox.ts prefix
202
215
  * shape (`<iso-ts> <drone-label> (<role-name>): ...`) so existing