@richhardry/codor 0.10.0

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 (388) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +293 -0
  3. package/bin/codor.mjs +7 -0
  4. package/node_modules/@codor/adapter-antigravity/dist/adapter.d.ts +41 -0
  5. package/node_modules/@codor/adapter-antigravity/dist/adapter.d.ts.map +1 -0
  6. package/node_modules/@codor/adapter-antigravity/dist/adapter.js +275 -0
  7. package/node_modules/@codor/adapter-antigravity/dist/adapter.js.map +1 -0
  8. package/node_modules/@codor/adapter-antigravity/dist/index.d.ts +2 -0
  9. package/node_modules/@codor/adapter-antigravity/dist/index.d.ts.map +1 -0
  10. package/node_modules/@codor/adapter-antigravity/dist/index.js +2 -0
  11. package/node_modules/@codor/adapter-antigravity/dist/index.js.map +1 -0
  12. package/node_modules/@codor/adapter-antigravity/package.json +18 -0
  13. package/node_modules/@codor/adapter-claude-code/dist/adapter.d.ts +94 -0
  14. package/node_modules/@codor/adapter-claude-code/dist/adapter.d.ts.map +1 -0
  15. package/node_modules/@codor/adapter-claude-code/dist/adapter.js +785 -0
  16. package/node_modules/@codor/adapter-claude-code/dist/adapter.js.map +1 -0
  17. package/node_modules/@codor/adapter-claude-code/dist/index.d.ts +8 -0
  18. package/node_modules/@codor/adapter-claude-code/dist/index.d.ts.map +1 -0
  19. package/node_modules/@codor/adapter-claude-code/dist/index.js +5 -0
  20. package/node_modules/@codor/adapter-claude-code/dist/index.js.map +1 -0
  21. package/node_modules/@codor/adapter-claude-code/dist/limits-probe.d.ts +18 -0
  22. package/node_modules/@codor/adapter-claude-code/dist/limits-probe.d.ts.map +1 -0
  23. package/node_modules/@codor/adapter-claude-code/dist/limits-probe.js +67 -0
  24. package/node_modules/@codor/adapter-claude-code/dist/limits-probe.js.map +1 -0
  25. package/node_modules/@codor/adapter-claude-code/dist/peek.d.ts +3 -0
  26. package/node_modules/@codor/adapter-claude-code/dist/peek.d.ts.map +1 -0
  27. package/node_modules/@codor/adapter-claude-code/dist/peek.js +128 -0
  28. package/node_modules/@codor/adapter-claude-code/dist/peek.js.map +1 -0
  29. package/node_modules/@codor/adapter-claude-code/dist/query.d.ts +9 -0
  30. package/node_modules/@codor/adapter-claude-code/dist/query.d.ts.map +1 -0
  31. package/node_modules/@codor/adapter-claude-code/dist/query.js +7 -0
  32. package/node_modules/@codor/adapter-claude-code/dist/query.js.map +1 -0
  33. package/node_modules/@codor/adapter-claude-code/dist/translate.d.ts +40 -0
  34. package/node_modules/@codor/adapter-claude-code/dist/translate.d.ts.map +1 -0
  35. package/node_modules/@codor/adapter-claude-code/dist/translate.js +505 -0
  36. package/node_modules/@codor/adapter-claude-code/dist/translate.js.map +1 -0
  37. package/node_modules/@codor/adapter-claude-code/package.json +18 -0
  38. package/node_modules/@codor/adapter-codex/dist/adapter.d.ts +105 -0
  39. package/node_modules/@codor/adapter-codex/dist/adapter.d.ts.map +1 -0
  40. package/node_modules/@codor/adapter-codex/dist/adapter.js +625 -0
  41. package/node_modules/@codor/adapter-codex/dist/adapter.js.map +1 -0
  42. package/node_modules/@codor/adapter-codex/dist/app-server-transport.d.ts +39 -0
  43. package/node_modules/@codor/adapter-codex/dist/app-server-transport.d.ts.map +1 -0
  44. package/node_modules/@codor/adapter-codex/dist/app-server-transport.js +186 -0
  45. package/node_modules/@codor/adapter-codex/dist/app-server-transport.js.map +1 -0
  46. package/node_modules/@codor/adapter-codex/dist/index.d.ts +8 -0
  47. package/node_modules/@codor/adapter-codex/dist/index.d.ts.map +1 -0
  48. package/node_modules/@codor/adapter-codex/dist/index.js +5 -0
  49. package/node_modules/@codor/adapter-codex/dist/index.js.map +1 -0
  50. package/node_modules/@codor/adapter-codex/dist/limits-probe.d.ts +18 -0
  51. package/node_modules/@codor/adapter-codex/dist/limits-probe.d.ts.map +1 -0
  52. package/node_modules/@codor/adapter-codex/dist/limits-probe.js +87 -0
  53. package/node_modules/@codor/adapter-codex/dist/limits-probe.js.map +1 -0
  54. package/node_modules/@codor/adapter-codex/dist/peek.d.ts +3 -0
  55. package/node_modules/@codor/adapter-codex/dist/peek.d.ts.map +1 -0
  56. package/node_modules/@codor/adapter-codex/dist/peek.js +98 -0
  57. package/node_modules/@codor/adapter-codex/dist/peek.js.map +1 -0
  58. package/node_modules/@codor/adapter-codex/dist/translate.d.ts +17 -0
  59. package/node_modules/@codor/adapter-codex/dist/translate.d.ts.map +1 -0
  60. package/node_modules/@codor/adapter-codex/dist/translate.js +286 -0
  61. package/node_modules/@codor/adapter-codex/dist/translate.js.map +1 -0
  62. package/node_modules/@codor/adapter-codex/package.json +17 -0
  63. package/node_modules/@codor/adapter-copilot/dist/adapter.d.ts +40 -0
  64. package/node_modules/@codor/adapter-copilot/dist/adapter.d.ts.map +1 -0
  65. package/node_modules/@codor/adapter-copilot/dist/adapter.js +190 -0
  66. package/node_modules/@codor/adapter-copilot/dist/adapter.js.map +1 -0
  67. package/node_modules/@codor/adapter-copilot/dist/index.d.ts +4 -0
  68. package/node_modules/@codor/adapter-copilot/dist/index.d.ts.map +1 -0
  69. package/node_modules/@codor/adapter-copilot/dist/index.js +3 -0
  70. package/node_modules/@codor/adapter-copilot/dist/index.js.map +1 -0
  71. package/node_modules/@codor/adapter-copilot/dist/translate.d.ts +11 -0
  72. package/node_modules/@codor/adapter-copilot/dist/translate.d.ts.map +1 -0
  73. package/node_modules/@codor/adapter-copilot/dist/translate.js +184 -0
  74. package/node_modules/@codor/adapter-copilot/dist/translate.js.map +1 -0
  75. package/node_modules/@codor/adapter-copilot/package.json +18 -0
  76. package/node_modules/@codor/adapter-cursor/dist/adapter.d.ts +32 -0
  77. package/node_modules/@codor/adapter-cursor/dist/adapter.d.ts.map +1 -0
  78. package/node_modules/@codor/adapter-cursor/dist/adapter.js +179 -0
  79. package/node_modules/@codor/adapter-cursor/dist/adapter.js.map +1 -0
  80. package/node_modules/@codor/adapter-cursor/dist/index.d.ts +9 -0
  81. package/node_modules/@codor/adapter-cursor/dist/index.d.ts.map +1 -0
  82. package/node_modules/@codor/adapter-cursor/dist/index.js +8 -0
  83. package/node_modules/@codor/adapter-cursor/dist/index.js.map +1 -0
  84. package/node_modules/@codor/adapter-cursor/dist/translate.d.ts +15 -0
  85. package/node_modules/@codor/adapter-cursor/dist/translate.d.ts.map +1 -0
  86. package/node_modules/@codor/adapter-cursor/dist/translate.js +164 -0
  87. package/node_modules/@codor/adapter-cursor/dist/translate.js.map +1 -0
  88. package/node_modules/@codor/adapter-cursor/package.json +17 -0
  89. package/node_modules/@codor/adapter-gemini/dist/adapter.d.ts +36 -0
  90. package/node_modules/@codor/adapter-gemini/dist/adapter.d.ts.map +1 -0
  91. package/node_modules/@codor/adapter-gemini/dist/adapter.js +245 -0
  92. package/node_modules/@codor/adapter-gemini/dist/adapter.js.map +1 -0
  93. package/node_modules/@codor/adapter-gemini/dist/index.d.ts +4 -0
  94. package/node_modules/@codor/adapter-gemini/dist/index.d.ts.map +1 -0
  95. package/node_modules/@codor/adapter-gemini/dist/index.js +3 -0
  96. package/node_modules/@codor/adapter-gemini/dist/index.js.map +1 -0
  97. package/node_modules/@codor/adapter-gemini/dist/translate.d.ts +12 -0
  98. package/node_modules/@codor/adapter-gemini/dist/translate.d.ts.map +1 -0
  99. package/node_modules/@codor/adapter-gemini/dist/translate.js +123 -0
  100. package/node_modules/@codor/adapter-gemini/dist/translate.js.map +1 -0
  101. package/node_modules/@codor/adapter-gemini/package.json +18 -0
  102. package/node_modules/@codor/adapter-opencode/dist/adapter.d.ts +42 -0
  103. package/node_modules/@codor/adapter-opencode/dist/adapter.d.ts.map +1 -0
  104. package/node_modules/@codor/adapter-opencode/dist/adapter.js +240 -0
  105. package/node_modules/@codor/adapter-opencode/dist/adapter.js.map +1 -0
  106. package/node_modules/@codor/adapter-opencode/dist/index.d.ts +4 -0
  107. package/node_modules/@codor/adapter-opencode/dist/index.d.ts.map +1 -0
  108. package/node_modules/@codor/adapter-opencode/dist/index.js +3 -0
  109. package/node_modules/@codor/adapter-opencode/dist/index.js.map +1 -0
  110. package/node_modules/@codor/adapter-opencode/dist/translate.d.ts +12 -0
  111. package/node_modules/@codor/adapter-opencode/dist/translate.d.ts.map +1 -0
  112. package/node_modules/@codor/adapter-opencode/dist/translate.js +144 -0
  113. package/node_modules/@codor/adapter-opencode/dist/translate.js.map +1 -0
  114. package/node_modules/@codor/adapter-opencode/package.json +18 -0
  115. package/node_modules/@codor/cli/dist/artifact.d.ts +33 -0
  116. package/node_modules/@codor/cli/dist/artifact.d.ts.map +1 -0
  117. package/node_modules/@codor/cli/dist/artifact.js +183 -0
  118. package/node_modules/@codor/cli/dist/artifact.js.map +1 -0
  119. package/node_modules/@codor/cli/dist/attach.d.ts +25 -0
  120. package/node_modules/@codor/cli/dist/attach.d.ts.map +1 -0
  121. package/node_modules/@codor/cli/dist/attach.js +133 -0
  122. package/node_modules/@codor/cli/dist/attach.js.map +1 -0
  123. package/node_modules/@codor/cli/dist/connection.d.ts +21 -0
  124. package/node_modules/@codor/cli/dist/connection.d.ts.map +1 -0
  125. package/node_modules/@codor/cli/dist/connection.js +130 -0
  126. package/node_modules/@codor/cli/dist/connection.js.map +1 -0
  127. package/node_modules/@codor/cli/dist/detect.d.ts +14 -0
  128. package/node_modules/@codor/cli/dist/detect.d.ts.map +1 -0
  129. package/node_modules/@codor/cli/dist/detect.js +99 -0
  130. package/node_modules/@codor/cli/dist/detect.js.map +1 -0
  131. package/node_modules/@codor/cli/dist/index.d.ts +17 -0
  132. package/node_modules/@codor/cli/dist/index.d.ts.map +1 -0
  133. package/node_modules/@codor/cli/dist/index.js +24 -0
  134. package/node_modules/@codor/cli/dist/index.js.map +1 -0
  135. package/node_modules/@codor/cli/dist/mirror.d.ts +4 -0
  136. package/node_modules/@codor/cli/dist/mirror.d.ts.map +1 -0
  137. package/node_modules/@codor/cli/dist/mirror.js +93 -0
  138. package/node_modules/@codor/cli/dist/mirror.js.map +1 -0
  139. package/node_modules/@codor/cli/dist/program.d.ts +17 -0
  140. package/node_modules/@codor/cli/dist/program.d.ts.map +1 -0
  141. package/node_modules/@codor/cli/dist/program.js +1068 -0
  142. package/node_modules/@codor/cli/dist/program.js.map +1 -0
  143. package/node_modules/@codor/cli/dist/runtime-install.d.ts +61 -0
  144. package/node_modules/@codor/cli/dist/runtime-install.d.ts.map +1 -0
  145. package/node_modules/@codor/cli/dist/runtime-install.js +122 -0
  146. package/node_modules/@codor/cli/dist/runtime-install.js.map +1 -0
  147. package/node_modules/@codor/cli/dist/runtime-paths.d.ts +24 -0
  148. package/node_modules/@codor/cli/dist/runtime-paths.d.ts.map +1 -0
  149. package/node_modules/@codor/cli/dist/runtime-paths.js +69 -0
  150. package/node_modules/@codor/cli/dist/runtime-paths.js.map +1 -0
  151. package/node_modules/@codor/cli/dist/setup-flow.d.ts +69 -0
  152. package/node_modules/@codor/cli/dist/setup-flow.d.ts.map +1 -0
  153. package/node_modules/@codor/cli/dist/setup-flow.js +110 -0
  154. package/node_modules/@codor/cli/dist/setup-flow.js.map +1 -0
  155. package/node_modules/@codor/cli/dist/setup-session.d.ts +105 -0
  156. package/node_modules/@codor/cli/dist/setup-session.d.ts.map +1 -0
  157. package/node_modules/@codor/cli/dist/setup-session.js +346 -0
  158. package/node_modules/@codor/cli/dist/setup-session.js.map +1 -0
  159. package/node_modules/@codor/cli/dist/setup-ui.d.ts +93 -0
  160. package/node_modules/@codor/cli/dist/setup-ui.d.ts.map +1 -0
  161. package/node_modules/@codor/cli/dist/setup-ui.js +249 -0
  162. package/node_modules/@codor/cli/dist/setup-ui.js.map +1 -0
  163. package/node_modules/@codor/cli/dist/setup.d.ts +108 -0
  164. package/node_modules/@codor/cli/dist/setup.d.ts.map +1 -0
  165. package/node_modules/@codor/cli/dist/setup.js +878 -0
  166. package/node_modules/@codor/cli/dist/setup.js.map +1 -0
  167. package/node_modules/@codor/cli/dist/terminal-keys.d.ts +26 -0
  168. package/node_modules/@codor/cli/dist/terminal-keys.d.ts.map +1 -0
  169. package/node_modules/@codor/cli/dist/terminal-keys.js +70 -0
  170. package/node_modules/@codor/cli/dist/terminal-keys.js.map +1 -0
  171. package/node_modules/@codor/cli/dist/terminal-qr.d.ts +2 -0
  172. package/node_modules/@codor/cli/dist/terminal-qr.d.ts.map +1 -0
  173. package/node_modules/@codor/cli/dist/terminal-qr.js +30 -0
  174. package/node_modules/@codor/cli/dist/terminal-qr.js.map +1 -0
  175. package/node_modules/@codor/cli/dist/up.d.ts +52 -0
  176. package/node_modules/@codor/cli/dist/up.d.ts.map +1 -0
  177. package/node_modules/@codor/cli/dist/up.js +178 -0
  178. package/node_modules/@codor/cli/dist/up.js.map +1 -0
  179. package/node_modules/@codor/cli/package.json +24 -0
  180. package/node_modules/@codor/cli/packaging/systemd/codor.service +21 -0
  181. package/node_modules/@codor/cli/runtime/web/assets/LandingPage-BOmG5kSw.js +31 -0
  182. package/node_modules/@codor/cli/runtime/web/assets/LedgerPage-CecuTS8-.js +1 -0
  183. package/node_modules/@codor/cli/runtime/web/assets/NoChannels-CYiBXGQd.js +11 -0
  184. package/node_modules/@codor/cli/runtime/web/assets/PairingCodeInput-Cr6XDWx-.js +1 -0
  185. package/node_modules/@codor/cli/runtime/web/assets/PairingPage-CQBWNA2L.js +6 -0
  186. package/node_modules/@codor/cli/runtime/web/assets/SettingsPage-DGLbSXE7.js +16 -0
  187. package/node_modules/@codor/cli/runtime/web/assets/StartupUnavailable-DdQBHip_.js +1 -0
  188. package/node_modules/@codor/cli/runtime/web/assets/arrow-left-BOpjMuRi.js +6 -0
  189. package/node_modules/@codor/cli/runtime/web/assets/browser-BWQYNOsD.js +6 -0
  190. package/node_modules/@codor/cli/runtime/web/assets/graph-toBZHlC0.js +1 -0
  191. package/node_modules/@codor/cli/runtime/web/assets/index-Cxi54Xim.js +408 -0
  192. package/node_modules/@codor/cli/runtime/web/assets/index-DjwJakJC.css +1 -0
  193. package/node_modules/@codor/cli/runtime/web/assets/qr-DpynCwP9.js +8 -0
  194. package/node_modules/@codor/cli/runtime/web/assets/react-C8w-UNLI.js +32 -0
  195. package/node_modules/@codor/cli/runtime/web/assets/sodium-DtsvMzX9.js +1 -0
  196. package/node_modules/@codor/cli/runtime/web/codor-192.png +0 -0
  197. package/node_modules/@codor/cli/runtime/web/codor-512.png +0 -0
  198. package/node_modules/@codor/cli/runtime/web/codor-apple-touch-180.png +0 -0
  199. package/node_modules/@codor/cli/runtime/web/codor-favicon.svg +86 -0
  200. package/node_modules/@codor/cli/runtime/web/codor-mark.svg +86 -0
  201. package/node_modules/@codor/cli/runtime/web/codor-maskable-512.png +0 -0
  202. package/node_modules/@codor/cli/runtime/web/codor-og.png +0 -0
  203. package/node_modules/@codor/cli/runtime/web/fonts/BitcountPropSingle-latin.woff2 +0 -0
  204. package/node_modules/@codor/cli/runtime/web/fonts/Geist-Variable.woff2 +0 -0
  205. package/node_modules/@codor/cli/runtime/web/fonts/GeistMono-Variable.woff2 +0 -0
  206. package/node_modules/@codor/cli/runtime/web/fonts/OFL.txt +93 -0
  207. package/node_modules/@codor/cli/runtime/web/index.html +53 -0
  208. package/node_modules/@codor/cli/runtime/web/manifest.webmanifest +1 -0
  209. package/node_modules/@codor/cli/runtime/web/sw.js +2 -0
  210. package/node_modules/@codor/protocol/dist/adapter.d.ts +118 -0
  211. package/node_modules/@codor/protocol/dist/adapter.d.ts.map +1 -0
  212. package/node_modules/@codor/protocol/dist/adapter.js +15 -0
  213. package/node_modules/@codor/protocol/dist/adapter.js.map +1 -0
  214. package/node_modules/@codor/protocol/dist/body.d.ts +14 -0
  215. package/node_modules/@codor/protocol/dist/body.d.ts.map +1 -0
  216. package/node_modules/@codor/protocol/dist/body.js +50 -0
  217. package/node_modules/@codor/protocol/dist/body.js.map +1 -0
  218. package/node_modules/@codor/protocol/dist/changelog.d.ts +30 -0
  219. package/node_modules/@codor/protocol/dist/changelog.d.ts.map +1 -0
  220. package/node_modules/@codor/protocol/dist/changelog.js +19 -0
  221. package/node_modules/@codor/protocol/dist/changelog.js.map +1 -0
  222. package/node_modules/@codor/protocol/dist/default-recipient.d.ts +8 -0
  223. package/node_modules/@codor/protocol/dist/default-recipient.d.ts.map +1 -0
  224. package/node_modules/@codor/protocol/dist/default-recipient.js +19 -0
  225. package/node_modules/@codor/protocol/dist/default-recipient.js.map +1 -0
  226. package/node_modules/@codor/protocol/dist/delivery.d.ts +42 -0
  227. package/node_modules/@codor/protocol/dist/delivery.d.ts.map +1 -0
  228. package/node_modules/@codor/protocol/dist/delivery.js +44 -0
  229. package/node_modules/@codor/protocol/dist/delivery.js.map +1 -0
  230. package/node_modules/@codor/protocol/dist/events.d.ts +284 -0
  231. package/node_modules/@codor/protocol/dist/events.d.ts.map +1 -0
  232. package/node_modules/@codor/protocol/dist/events.js +150 -0
  233. package/node_modules/@codor/protocol/dist/events.js.map +1 -0
  234. package/node_modules/@codor/protocol/dist/ids.d.ts +19 -0
  235. package/node_modules/@codor/protocol/dist/ids.d.ts.map +1 -0
  236. package/node_modules/@codor/protocol/dist/ids.js +27 -0
  237. package/node_modules/@codor/protocol/dist/ids.js.map +1 -0
  238. package/node_modules/@codor/protocol/dist/index.d.ts +14 -0
  239. package/node_modules/@codor/protocol/dist/index.d.ts.map +1 -0
  240. package/node_modules/@codor/protocol/dist/index.js +14 -0
  241. package/node_modules/@codor/protocol/dist/index.js.map +1 -0
  242. package/node_modules/@codor/protocol/dist/interaction.d.ts +45 -0
  243. package/node_modules/@codor/protocol/dist/interaction.d.ts.map +1 -0
  244. package/node_modules/@codor/protocol/dist/interaction.js +33 -0
  245. package/node_modules/@codor/protocol/dist/interaction.js.map +1 -0
  246. package/node_modules/@codor/protocol/dist/member.d.ts +146 -0
  247. package/node_modules/@codor/protocol/dist/member.d.ts.map +1 -0
  248. package/node_modules/@codor/protocol/dist/member.js +169 -0
  249. package/node_modules/@codor/protocol/dist/member.js.map +1 -0
  250. package/node_modules/@codor/protocol/dist/message.d.ts +166 -0
  251. package/node_modules/@codor/protocol/dist/message.d.ts.map +1 -0
  252. package/node_modules/@codor/protocol/dist/message.js +95 -0
  253. package/node_modules/@codor/protocol/dist/message.js.map +1 -0
  254. package/node_modules/@codor/protocol/dist/observability.d.ts +80 -0
  255. package/node_modules/@codor/protocol/dist/observability.d.ts.map +1 -0
  256. package/node_modules/@codor/protocol/dist/observability.js +41 -0
  257. package/node_modules/@codor/protocol/dist/observability.js.map +1 -0
  258. package/node_modules/@codor/protocol/dist/room.d.ts +430 -0
  259. package/node_modules/@codor/protocol/dist/room.d.ts.map +1 -0
  260. package/node_modules/@codor/protocol/dist/room.js +142 -0
  261. package/node_modules/@codor/protocol/dist/room.js.map +1 -0
  262. package/node_modules/@codor/protocol/dist/ws.d.ts +1348 -0
  263. package/node_modules/@codor/protocol/dist/ws.d.ts.map +1 -0
  264. package/node_modules/@codor/protocol/dist/ws.js +282 -0
  265. package/node_modules/@codor/protocol/dist/ws.js.map +1 -0
  266. package/node_modules/@codor/protocol/package.json +17 -0
  267. package/node_modules/@codor/switchboard/dist/adapter-registry.d.ts +14 -0
  268. package/node_modules/@codor/switchboard/dist/adapter-registry.d.ts.map +1 -0
  269. package/node_modules/@codor/switchboard/dist/adapter-registry.js +175 -0
  270. package/node_modules/@codor/switchboard/dist/adapter-registry.js.map +1 -0
  271. package/node_modules/@codor/switchboard/dist/authorization.d.ts +13 -0
  272. package/node_modules/@codor/switchboard/dist/authorization.d.ts.map +1 -0
  273. package/node_modules/@codor/switchboard/dist/authorization.js +96 -0
  274. package/node_modules/@codor/switchboard/dist/authorization.js.map +1 -0
  275. package/node_modules/@codor/switchboard/dist/blobs.d.ts +17 -0
  276. package/node_modules/@codor/switchboard/dist/blobs.d.ts.map +1 -0
  277. package/node_modules/@codor/switchboard/dist/blobs.js +54 -0
  278. package/node_modules/@codor/switchboard/dist/blobs.js.map +1 -0
  279. package/node_modules/@codor/switchboard/dist/collaboration.d.ts +115 -0
  280. package/node_modules/@codor/switchboard/dist/collaboration.d.ts.map +1 -0
  281. package/node_modules/@codor/switchboard/dist/collaboration.js +123 -0
  282. package/node_modules/@codor/switchboard/dist/collaboration.js.map +1 -0
  283. package/node_modules/@codor/switchboard/dist/continuation.d.ts +33 -0
  284. package/node_modules/@codor/switchboard/dist/continuation.d.ts.map +1 -0
  285. package/node_modules/@codor/switchboard/dist/continuation.js +177 -0
  286. package/node_modules/@codor/switchboard/dist/continuation.js.map +1 -0
  287. package/node_modules/@codor/switchboard/dist/crypto/browser-sessions.d.ts +22 -0
  288. package/node_modules/@codor/switchboard/dist/crypto/browser-sessions.d.ts.map +1 -0
  289. package/node_modules/@codor/switchboard/dist/crypto/browser-sessions.js +92 -0
  290. package/node_modules/@codor/switchboard/dist/crypto/browser-sessions.js.map +1 -0
  291. package/node_modules/@codor/switchboard/dist/crypto/challenge.d.ts +37 -0
  292. package/node_modules/@codor/switchboard/dist/crypto/challenge.d.ts.map +1 -0
  293. package/node_modules/@codor/switchboard/dist/crypto/challenge.js +132 -0
  294. package/node_modules/@codor/switchboard/dist/crypto/challenge.js.map +1 -0
  295. package/node_modules/@codor/switchboard/dist/crypto/keys.d.ts +41 -0
  296. package/node_modules/@codor/switchboard/dist/crypto/keys.d.ts.map +1 -0
  297. package/node_modules/@codor/switchboard/dist/crypto/keys.js +145 -0
  298. package/node_modules/@codor/switchboard/dist/crypto/keys.js.map +1 -0
  299. package/node_modules/@codor/switchboard/dist/crypto/pairing.d.ts +53 -0
  300. package/node_modules/@codor/switchboard/dist/crypto/pairing.d.ts.map +1 -0
  301. package/node_modules/@codor/switchboard/dist/crypto/pairing.js +182 -0
  302. package/node_modules/@codor/switchboard/dist/crypto/pairing.js.map +1 -0
  303. package/node_modules/@codor/switchboard/dist/crypto/roomkeys.d.ts +30 -0
  304. package/node_modules/@codor/switchboard/dist/crypto/roomkeys.d.ts.map +1 -0
  305. package/node_modules/@codor/switchboard/dist/crypto/roomkeys.js +101 -0
  306. package/node_modules/@codor/switchboard/dist/crypto/roomkeys.js.map +1 -0
  307. package/node_modules/@codor/switchboard/dist/daemon.d.ts +545 -0
  308. package/node_modules/@codor/switchboard/dist/daemon.d.ts.map +1 -0
  309. package/node_modules/@codor/switchboard/dist/daemon.js +3907 -0
  310. package/node_modules/@codor/switchboard/dist/daemon.js.map +1 -0
  311. package/node_modules/@codor/switchboard/dist/fake-adapter.d.ts +103 -0
  312. package/node_modules/@codor/switchboard/dist/fake-adapter.d.ts.map +1 -0
  313. package/node_modules/@codor/switchboard/dist/fake-adapter.js +228 -0
  314. package/node_modules/@codor/switchboard/dist/fake-adapter.js.map +1 -0
  315. package/node_modules/@codor/switchboard/dist/index.d.ts +44 -0
  316. package/node_modules/@codor/switchboard/dist/index.d.ts.map +1 -0
  317. package/node_modules/@codor/switchboard/dist/index.js +24 -0
  318. package/node_modules/@codor/switchboard/dist/index.js.map +1 -0
  319. package/node_modules/@codor/switchboard/dist/ledger/resolve.d.ts +12 -0
  320. package/node_modules/@codor/switchboard/dist/ledger/resolve.d.ts.map +1 -0
  321. package/node_modules/@codor/switchboard/dist/ledger/resolve.js +17 -0
  322. package/node_modules/@codor/switchboard/dist/ledger/resolve.js.map +1 -0
  323. package/node_modules/@codor/switchboard/dist/ledger/vault.d.ts +47 -0
  324. package/node_modules/@codor/switchboard/dist/ledger/vault.d.ts.map +1 -0
  325. package/node_modules/@codor/switchboard/dist/ledger/vault.js +175 -0
  326. package/node_modules/@codor/switchboard/dist/ledger/vault.js.map +1 -0
  327. package/node_modules/@codor/switchboard/dist/ledger/watch.d.ts +73 -0
  328. package/node_modules/@codor/switchboard/dist/ledger/watch.d.ts.map +1 -0
  329. package/node_modules/@codor/switchboard/dist/ledger/watch.js +232 -0
  330. package/node_modules/@codor/switchboard/dist/ledger/watch.js.map +1 -0
  331. package/node_modules/@codor/switchboard/dist/local-dirs.d.ts +14 -0
  332. package/node_modules/@codor/switchboard/dist/local-dirs.d.ts.map +1 -0
  333. package/node_modules/@codor/switchboard/dist/local-dirs.js +40 -0
  334. package/node_modules/@codor/switchboard/dist/local-dirs.js.map +1 -0
  335. package/node_modules/@codor/switchboard/dist/local-socket.d.ts +3 -0
  336. package/node_modules/@codor/switchboard/dist/local-socket.d.ts.map +1 -0
  337. package/node_modules/@codor/switchboard/dist/local-socket.js +16 -0
  338. package/node_modules/@codor/switchboard/dist/local-socket.js.map +1 -0
  339. package/node_modules/@codor/switchboard/dist/pricing.d.ts +32 -0
  340. package/node_modules/@codor/switchboard/dist/pricing.d.ts.map +1 -0
  341. package/node_modules/@codor/switchboard/dist/pricing.js +64 -0
  342. package/node_modules/@codor/switchboard/dist/pricing.js.map +1 -0
  343. package/node_modules/@codor/switchboard/dist/process-liveness.d.ts +2 -0
  344. package/node_modules/@codor/switchboard/dist/process-liveness.d.ts.map +1 -0
  345. package/node_modules/@codor/switchboard/dist/process-liveness.js +9 -0
  346. package/node_modules/@codor/switchboard/dist/process-liveness.js.map +1 -0
  347. package/node_modules/@codor/switchboard/dist/push/producer.d.ts +54 -0
  348. package/node_modules/@codor/switchboard/dist/push/producer.d.ts.map +1 -0
  349. package/node_modules/@codor/switchboard/dist/push/producer.js +168 -0
  350. package/node_modules/@codor/switchboard/dist/push/producer.js.map +1 -0
  351. package/node_modules/@codor/switchboard/dist/push/subscriptions.d.ts +29 -0
  352. package/node_modules/@codor/switchboard/dist/push/subscriptions.d.ts.map +1 -0
  353. package/node_modules/@codor/switchboard/dist/push/subscriptions.js +83 -0
  354. package/node_modules/@codor/switchboard/dist/push/subscriptions.js.map +1 -0
  355. package/node_modules/@codor/switchboard/dist/redact.d.ts +11 -0
  356. package/node_modules/@codor/switchboard/dist/redact.d.ts.map +1 -0
  357. package/node_modules/@codor/switchboard/dist/redact.js +65 -0
  358. package/node_modules/@codor/switchboard/dist/redact.js.map +1 -0
  359. package/node_modules/@codor/switchboard/dist/residency.d.ts +110 -0
  360. package/node_modules/@codor/switchboard/dist/residency.d.ts.map +1 -0
  361. package/node_modules/@codor/switchboard/dist/residency.js +587 -0
  362. package/node_modules/@codor/switchboard/dist/residency.js.map +1 -0
  363. package/node_modules/@codor/switchboard/dist/router.d.ts +120 -0
  364. package/node_modules/@codor/switchboard/dist/router.d.ts.map +1 -0
  365. package/node_modules/@codor/switchboard/dist/router.js +198 -0
  366. package/node_modules/@codor/switchboard/dist/router.js.map +1 -0
  367. package/node_modules/@codor/switchboard/dist/server.d.ts +50 -0
  368. package/node_modules/@codor/switchboard/dist/server.d.ts.map +1 -0
  369. package/node_modules/@codor/switchboard/dist/server.js +1425 -0
  370. package/node_modules/@codor/switchboard/dist/server.js.map +1 -0
  371. package/node_modules/@codor/switchboard/dist/store.d.ts +534 -0
  372. package/node_modules/@codor/switchboard/dist/store.d.ts.map +1 -0
  373. package/node_modules/@codor/switchboard/dist/store.js +2625 -0
  374. package/node_modules/@codor/switchboard/dist/store.js.map +1 -0
  375. package/node_modules/@codor/switchboard/dist/transport/hyperswarm.d.ts +59 -0
  376. package/node_modules/@codor/switchboard/dist/transport/hyperswarm.d.ts.map +1 -0
  377. package/node_modules/@codor/switchboard/dist/transport/hyperswarm.js +183 -0
  378. package/node_modules/@codor/switchboard/dist/transport/hyperswarm.js.map +1 -0
  379. package/node_modules/@codor/switchboard/dist/transport/peer.d.ts +87 -0
  380. package/node_modules/@codor/switchboard/dist/transport/peer.d.ts.map +1 -0
  381. package/node_modules/@codor/switchboard/dist/transport/peer.js +316 -0
  382. package/node_modules/@codor/switchboard/dist/transport/peer.js.map +1 -0
  383. package/node_modules/@codor/switchboard/dist/working-directory.d.ts +2 -0
  384. package/node_modules/@codor/switchboard/dist/working-directory.d.ts.map +1 -0
  385. package/node_modules/@codor/switchboard/dist/working-directory.js +26 -0
  386. package/node_modules/@codor/switchboard/dist/working-directory.js.map +1 -0
  387. package/node_modules/@codor/switchboard/package.json +33 -0
  388. package/package.json +58 -0
@@ -0,0 +1,1068 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { MemberStatusResponseSchema, MessageSchema, RunSearchHitSchema, } from '@codor/protocol';
4
+ import { Command, Option } from 'commander';
5
+ import { addRemoteLedgerNote, CryptoVault, HyperswarmTransport, LedgerVault, pairingUrl, } from '@codor/switchboard';
6
+ import { nativeResumeCommand, superviseInteractiveAttach, } from './attach.js';
7
+ import { ProtocolClient } from './connection.js';
8
+ import { detectSession } from './detect.js';
9
+ import { parseMirrorHook } from './mirror.js';
10
+ import { runSetup } from './setup.js';
11
+ import { renderTerminalQr } from './terminal-qr.js';
12
+ import { parseLine, startOutpost, startCodor, waitForShutdown } from './up.js';
13
+ // harn:assume adapter-registry-sole-harness-source ref=registry-cli-composition
14
+ function collectAdapter(value, previous) {
15
+ return [...previous, value];
16
+ }
17
+ export function parseAdapterModules(values) {
18
+ const adapters = [];
19
+ const ids = new Set();
20
+ for (const value of values) {
21
+ const separator = value.indexOf('=');
22
+ if (separator < 1 || separator === value.length - 1) {
23
+ throw new Error('--adapter must be name=module');
24
+ }
25
+ const id = value.slice(0, separator).trim();
26
+ const module = value.slice(separator + 1).trim();
27
+ if (id === '' || module === '')
28
+ throw new Error('--adapter must be name=module');
29
+ if (ids.has(id))
30
+ throw new Error(`duplicate --adapter id '${id}'`);
31
+ ids.add(id);
32
+ adapters.push([id, module]);
33
+ }
34
+ return Object.fromEntries(adapters);
35
+ }
36
+ // harn:assume continuation-writer-follows-journaled-output-ownership ref=continuation-cli-format
37
+ /**
38
+ * A continuation is deliberately kind=run WITHOUT a lifecycle summary — the
39
+ * status, usage and cost belong to its root, not to it. Reading `message.run!`
40
+ * for one would throw and take down every tail subscriber the moment the writer
41
+ * starts emitting them, so identity comes from `run_parent_id` instead.
42
+ *
43
+ * It says only what is true of the row itself: its own permanent id, its
44
+ * author, and which run it continues. No status, no totals, no synthesized id —
45
+ * borrowing the root's would be a claim this row cannot make.
46
+ */
47
+ const formatRunHeader = (message, author) => {
48
+ if (message.run === undefined && message.run_parent_id !== undefined) {
49
+ return `#${message.id} @${author} run continuation of #${message.run_parent_id}`;
50
+ }
51
+ const run = message.run;
52
+ const usage = run.usage;
53
+ const tokens = usage ? usage.input_tokens + usage.output_tokens : undefined;
54
+ return [
55
+ `#${message.id}`,
56
+ `@${author}`,
57
+ 'run',
58
+ run.status,
59
+ tokens === undefined ? undefined : `${tokens}tk`,
60
+ usage?.cost_usd === undefined ? undefined : `$${usage.cost_usd.toFixed(2)}`,
61
+ ].filter((part) => part !== undefined).join(' ');
62
+ };
63
+ // harn:end continuation-writer-follows-journaled-output-ownership
64
+ async function readStandardInput() {
65
+ const chunks = [];
66
+ for await (const chunk of process.stdin) {
67
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
68
+ }
69
+ return Buffer.concat(chunks).toString('utf8');
70
+ }
71
+ const parsePositiveNumber = (value, label) => {
72
+ const parsed = Number(value);
73
+ if (!Number.isFinite(parsed) || parsed <= 0)
74
+ throw new Error(`${label} must be greater than zero`);
75
+ return parsed;
76
+ };
77
+ const parsePositiveInteger = (value, label) => {
78
+ const parsed = Number(value);
79
+ if (!Number.isSafeInteger(parsed) || parsed < 1)
80
+ throw new Error(`${label} must be a positive integer`);
81
+ return parsed;
82
+ };
83
+ const formatElapsed = (milliseconds) => {
84
+ const seconds = Math.max(0, Math.floor(milliseconds / 1_000));
85
+ const minutes = Math.floor(seconds / 60);
86
+ const remainder = seconds % 60;
87
+ return minutes > 0 ? `${minutes}m${String(remainder).padStart(2, '0')}s` : `${remainder}s`;
88
+ };
89
+ const formatDuration = (milliseconds) => {
90
+ if (milliseconds === undefined)
91
+ return '-';
92
+ return milliseconds >= 1_000 ? `${(milliseconds / 1_000).toFixed(1)}s` : `${Math.round(milliseconds)}ms`;
93
+ };
94
+ // harn:assume cli-waits-consume-only-matching-deliveries ref=collaboration-room-sync
95
+ async function syncRoom(client, room) {
96
+ let self;
97
+ const members = new Map();
98
+ const messages = new Map();
99
+ const deliveries = new Map();
100
+ client.send({ type: 'subscribe', room, since_seq: 0 });
101
+ for (;;) {
102
+ const frame = await client.next();
103
+ if (frame.type === 'error')
104
+ throw new Error(frame.message);
105
+ if (frame.type === 'self')
106
+ self = frame.member_id;
107
+ else if (frame.type === 'member')
108
+ members.set(frame.member.id, frame.member);
109
+ else if (frame.type === 'message')
110
+ messages.set(frame.message.id, frame.message);
111
+ else if (frame.type === 'inbox')
112
+ deliveries.set(frame.delivery.id, frame.delivery);
113
+ else if (frame.type === 'sync_complete') {
114
+ if (!self)
115
+ throw new Error('channel subscription did not identify the caller');
116
+ return { self, members, messages, deliveries };
117
+ }
118
+ }
119
+ }
120
+ const ownQueuedDeliveries = (snapshot) => [...snapshot.deliveries.values()]
121
+ .filter((delivery) => delivery.recipient === snapshot.self && delivery.state === 'queued')
122
+ .sort((left, right) => left.ts.localeCompare(right.ts));
123
+ async function consumeDelivery(client, room, delivery) {
124
+ client.send({
125
+ type: 'act',
126
+ room,
127
+ act: { act: 'consume_delivery', delivery_id: delivery.id },
128
+ });
129
+ for (;;) {
130
+ const frame = await client.next();
131
+ if (frame.type === 'error')
132
+ throw new Error(frame.message);
133
+ if (frame.type === 'consume_result' && frame.delivery.id === delivery.id)
134
+ return frame.message;
135
+ }
136
+ }
137
+ async function setWait(client, room, self, reason, peers, untilTs) {
138
+ client.send({ type: 'act', room, act: { act: 'wait_begin', reason, peers, until_ts: untilTs } });
139
+ for (;;) {
140
+ const frame = await client.next();
141
+ if (frame.type === 'error')
142
+ throw new Error(frame.message);
143
+ if (frame.type === 'member' && frame.member.id === self && frame.member.waiting)
144
+ return;
145
+ }
146
+ }
147
+ async function clearWait(client, room, self) {
148
+ client.send({ type: 'act', room, act: { act: 'wait_end' } });
149
+ for (;;) {
150
+ const frame = await client.next();
151
+ if (frame.type === 'error')
152
+ throw new Error(frame.message);
153
+ if (frame.type === 'member' && frame.member.id === self && !frame.member.waiting)
154
+ return;
155
+ }
156
+ }
157
+ async function waitForOwnDelivery(client, room, initial, deadline, matches, peerFinishedSelf) {
158
+ let snapshot = initial;
159
+ const find = () => {
160
+ for (const delivery of ownQueuedDeliveries(snapshot)) {
161
+ const message = snapshot.messages.get(delivery.message_id);
162
+ if (message && matches(message))
163
+ return { kind: 'delivery', delivery, message };
164
+ }
165
+ return undefined;
166
+ };
167
+ for (;;) {
168
+ const existing = find();
169
+ if (existing)
170
+ return existing;
171
+ const remaining = deadline - Date.now();
172
+ if (remaining <= 0)
173
+ return undefined;
174
+ let frame;
175
+ try {
176
+ frame = await client.next(remaining);
177
+ }
178
+ catch (error) {
179
+ if (error instanceof Error && error.message.includes('timed out waiting for server frame')) {
180
+ return undefined;
181
+ }
182
+ throw error;
183
+ }
184
+ if (frame.type === 'error')
185
+ throw new Error(frame.message);
186
+ if (frame.type === 'message') {
187
+ snapshot.messages.set(frame.message.id, frame.message);
188
+ if (matches(frame.message))
189
+ snapshot = await syncRoom(client, room);
190
+ }
191
+ else if (frame.type === 'inbox') {
192
+ snapshot.deliveries.set(frame.delivery.id, frame.delivery);
193
+ }
194
+ else if (frame.type === 'member') {
195
+ snapshot.members.set(frame.member.id, frame.member);
196
+ if (frame.member.id === peerFinishedSelf && frame.member.waiting === undefined) {
197
+ return { kind: 'peer_finished' };
198
+ }
199
+ }
200
+ }
201
+ }
202
+ // harn:end same-round-terminal-peers-end-live-waits
203
+ // harn:end cli-waits-consume-only-matching-deliveries
204
+ // harn:assume cli-hook-inbox-is-silent-when-empty ref=hook-inbox-renderer
205
+ const formatInboxMessage = (message, author) => `#${message.id} from @${author}\n${message.body}`;
206
+ function renderHookInbox(messages) {
207
+ if (messages.length === 0)
208
+ return undefined;
209
+ return JSON.stringify({
210
+ hookSpecificOutput: {
211
+ hookEventName: 'PostToolUse',
212
+ additionalContext: `Codor inbox:\n${messages
213
+ .map(({ message, author }) => formatInboxMessage(message, author))
214
+ .join('\n\n')}`,
215
+ },
216
+ });
217
+ }
218
+ // harn:end cli-hook-inbox-is-silent-when-empty
219
+ export function createProgram(context = {}) {
220
+ const env = context.env ?? process.env;
221
+ const out = context.stdout ?? ((line) => process.stdout.write(`${line}\n`));
222
+ const err = context.stderr ?? ((line) => process.stderr.write(`${line}\n`));
223
+ const program = new Command();
224
+ // harn:assume human-facing-surfaces-call-rooms-channels ref=cli-channel-terminology
225
+ // harn:assume codor-runtime-identity-is-a-clean-break ref=cli-runtime-identity
226
+ program
227
+ .name('codor')
228
+ .description('Operate local-first multi-agent channels')
229
+ .option('--data-dir <path>', 'switchboard data directory', env.CODOR_DATA_DIR ?? join(homedir(), '.codor'))
230
+ .option('--url <url>', 'remote switchboard URL');
231
+ // harn:assume cli-help-never-renders-selected-bearer ref=redacted-token-option-default
232
+ program.addOption(new Option('--token <token>', 'remote bearer token')
233
+ .default(env.CODOR_MEMBER_TOKEN ?? env.CODOR_TOKEN, '<redacted>'));
234
+ // harn:end cli-help-never-renders-selected-bearer
235
+ // harn:end codor-runtime-identity-is-a-clean-break
236
+ const connectionOptions = () => {
237
+ const options = program.opts();
238
+ // harn:assume member-env-selects-narrow-cli-identity ref=member-connection-options
239
+ return {
240
+ dataDir: options.dataDir,
241
+ remoteUrl: options.url,
242
+ socketPath: options.url === undefined ? env.CODOR_SOCKET : undefined,
243
+ token: options.token,
244
+ };
245
+ // harn:end member-env-selects-narrow-cli-identity
246
+ };
247
+ const withClient = async (fn) => {
248
+ const client = await ProtocolClient.connect(connectionOptions());
249
+ try {
250
+ return await fn(client);
251
+ }
252
+ finally {
253
+ await client.close();
254
+ }
255
+ };
256
+ const channel = (options) => {
257
+ const room = options.channel ?? env.CODOR_CHANNEL;
258
+ if (!room)
259
+ throw new Error('--channel or CODOR_CHANNEL is required');
260
+ return room;
261
+ };
262
+ // harn:assume cli-observability-uses-scoped-rest ref=scoped-rest-client
263
+ const restUrl = (path) => {
264
+ const globals = program.opts();
265
+ const raw = globals.url ?? env.CODOR_URL ?? 'http://127.0.0.1:8137';
266
+ const base = new URL(raw);
267
+ if (base.protocol === 'ws:')
268
+ base.protocol = 'http:';
269
+ else if (base.protocol === 'wss:')
270
+ base.protocol = 'https:';
271
+ if (base.protocol !== 'http:' && base.protocol !== 'https:') {
272
+ throw new Error('--url must use http(s) or ws(s)');
273
+ }
274
+ return new URL(path, `${base.origin}/`);
275
+ };
276
+ const fetchJson = async (url) => {
277
+ const token = program.opts().token;
278
+ if (!token)
279
+ throw new Error('--token, CODOR_TOKEN, or CODOR_MEMBER_TOKEN is required');
280
+ const response = await fetch(url, { headers: { authorization: `Bearer ${token}` } });
281
+ const value = await response.json();
282
+ if (!response.ok) {
283
+ const detail = typeof value === 'object' && value !== null && 'error' in value
284
+ ? String(value.error)
285
+ : `${response.status} ${response.statusText}`;
286
+ throw new Error(detail);
287
+ }
288
+ return value;
289
+ };
290
+ // harn:end cli-observability-uses-scoped-rest
291
+ const withCrypto = (fn) => {
292
+ const crypto = new CryptoVault(program.opts().dataDir);
293
+ try {
294
+ return fn(crypto);
295
+ }
296
+ finally {
297
+ crypto.close();
298
+ }
299
+ };
300
+ program
301
+ .command('up')
302
+ .description('start the switchboard in the foreground')
303
+ .option('--host <host>', 'HTTP bind host', '127.0.0.1')
304
+ .option('--port <port>', 'HTTP bind port', (value) => Number(value), 8137)
305
+ .option('--static-root <path>', 'built web client directory')
306
+ .option('--channel <id>', 'initial channel id', 'default')
307
+ .option('--channel-name <name>', 'initial channel name', 'Default')
308
+ .option('--owner <handle>', 'initial owner handle')
309
+ .option('--relay-url <url>', 'optional sealed push relay URL', env.CODOR_RELAY_URL)
310
+ .option('--push-vapid-public-key <key>', 'Web Push VAPID public key', env.CODOR_VAPID_PUBLIC_KEY)
311
+ .option('--join <line>', 'join a private home/outpost line as name:secret')
312
+ // harn:assume tailnet-auto-pairing-explicit-trust ref=trusted-tailnet-up-option
313
+ .option('--trust-tailscale-serve', 'trust Tailscale Serve identity headers for browser enrollment', env.CODOR_TRUST_TAILSCALE_SERVE === '1')
314
+ // harn:end tailnet-auto-pairing-explicit-trust
315
+ .option('--adapter <name=module>', 'trusted adapter module (repeatable)', collectAdapter, [])
316
+ .action(async (options) => {
317
+ const globals = program.opts();
318
+ const running = await startCodor({
319
+ dataDir: globals.dataDir,
320
+ token: globals.token ?? '',
321
+ host: options.host,
322
+ port: options.port,
323
+ staticRoot: options.staticRoot,
324
+ room: options.channel,
325
+ roomName: options.channelName,
326
+ owner: options.owner,
327
+ relayUrl: options.relayUrl,
328
+ pushVapidPublicKey: options.pushVapidPublicKey,
329
+ line: options.join ? parseLine(options.join) : undefined,
330
+ trustTailscaleServe: options.trustTailscaleServe,
331
+ adapters: parseAdapterModules(options.adapter),
332
+ });
333
+ out(`codor http://localhost:${running.server.port}`);
334
+ out(`socket ${running.server.socketPath}`);
335
+ await waitForShutdown(running.close);
336
+ });
337
+ program.command('channels').description('list channels').action(async () => {
338
+ await withClient(async (client) => {
339
+ client.send({ type: 'list_rooms' });
340
+ for (;;) {
341
+ const frame = await client.next();
342
+ if (frame.type === 'error')
343
+ throw new Error(frame.message);
344
+ if (frame.type !== 'rooms')
345
+ continue;
346
+ for (const room of frame.rooms)
347
+ out(`${room.id}\t${room.name}`);
348
+ return;
349
+ }
350
+ });
351
+ });
352
+ program
353
+ .command('serve')
354
+ .description('host resident members for a remote channel home')
355
+ .requiredOption('--join <line>', 'line name and secret as name:secret')
356
+ .option('--adapter <name=module>', 'trusted adapter module (repeatable)', collectAdapter, [])
357
+ .action(async (options) => {
358
+ const running = await startOutpost({
359
+ dataDir: program.opts().dataDir,
360
+ line: parseLine(options.join),
361
+ adapters: parseAdapterModules(options.adapter),
362
+ });
363
+ out(`codor outpost ${running.crypto.keys.identity.device_id}`);
364
+ await waitForShutdown(running.close);
365
+ });
366
+ // harn:end adapter-registry-sole-harness-source
367
+ // harn:assume setup-unattended-mutation-requires-explicit-intent ref=setup-command-surface
368
+ // harn:assume public-install-is-the-primary-command-with-setup-alias ref=install-command-alias
369
+ program
370
+ .command('install')
371
+ .alias('setup')
372
+ .description('install and start the local switchboard service, then pair your first browser')
373
+ .option('--dry-run', 'print every action and generated service content without changing the host')
374
+ .option('--yes', 'approve every setup mutation for unattended use')
375
+ .addOption(new Option('--access <method>', 'browser access method').choices(['localhost', 'tailscale']))
376
+ .action(async (options) => {
377
+ await runSetup({
378
+ access: options.access,
379
+ dryRun: options.dryRun === true,
380
+ env,
381
+ out,
382
+ overrides: {
383
+ ...context.setup,
384
+ renderQr: context.renderQr ?? context.setup?.renderQr,
385
+ },
386
+ yes: options.yes === true,
387
+ });
388
+ });
389
+ // harn:end public-install-is-the-primary-command-with-setup-alias
390
+ // harn:end setup-unattended-mutation-requires-explicit-intent
391
+ program
392
+ .command('spawn')
393
+ .requiredOption('-r, --channel <channel>', 'channel id')
394
+ .requiredOption('--harness <harness>', 'registered adapter id')
395
+ .requiredOption('--as <handle>', 'member handle')
396
+ .requiredOption('--cwd <path>', 'working directory')
397
+ .option('--policy <policy>', 'sandbox or permission policy')
398
+ .option('--model <model>', 'model override')
399
+ .action(async (options) => {
400
+ await withClient(async (client) => {
401
+ const existing = new Set();
402
+ client.send({ type: 'subscribe', room: options.channel, since_seq: 0 });
403
+ for (;;) {
404
+ const frame = await client.next();
405
+ if (frame.type === 'member')
406
+ existing.add(frame.member.id);
407
+ if (frame.type === 'error')
408
+ throw new Error(frame.message);
409
+ if (frame.type === 'sync_complete')
410
+ break;
411
+ }
412
+ client.send({
413
+ type: 'act',
414
+ room: options.channel,
415
+ act: {
416
+ act: 'spawn',
417
+ harness: options.harness,
418
+ handle: options.as,
419
+ cwd: options.cwd,
420
+ policy: options.policy,
421
+ model: options.model,
422
+ },
423
+ });
424
+ for (;;) {
425
+ const frame = await client.next();
426
+ if (frame.type === 'error')
427
+ throw new Error(frame.message);
428
+ if (frame.type === 'member' && !existing.has(frame.member.id) && frame.member.handle === options.as) {
429
+ out(`spawned @${frame.member.handle} ${frame.member.id}`);
430
+ return;
431
+ }
432
+ }
433
+ });
434
+ });
435
+ program
436
+ .command('post')
437
+ .option('-r, --channel <channel>', 'channel id; defaults to CODOR_CHANNEL')
438
+ .option('--wait', 'wait for the first direct reply from an addressed member')
439
+ .option('--timeout <seconds>', 'wait timeout in seconds', (value) => parsePositiveNumber(value, '--timeout'), 300)
440
+ .argument('<message>')
441
+ // harn:assume cli-waits-consume-only-matching-deliveries ref=post-wait-command
442
+ .action(async (message, options) => {
443
+ await withClient(async (client) => {
444
+ const room = channel(options);
445
+ const initial = await syncRoom(client, room);
446
+ const lastMessageId = Math.max(0, ...initial.messages.keys());
447
+ client.send({
448
+ type: 'post',
449
+ room,
450
+ body: message,
451
+ ...(options.wait && { awaiting_reply: true }),
452
+ });
453
+ let posted;
454
+ for (;;) {
455
+ const frame = await client.next();
456
+ if (frame.type === 'error')
457
+ throw new Error(frame.message);
458
+ if (frame.type === 'message' &&
459
+ frame.message.id > lastMessageId &&
460
+ frame.message.author === initial.self &&
461
+ frame.message.body === message) {
462
+ posted = frame.message;
463
+ break;
464
+ }
465
+ }
466
+ out(`posted #${posted.id}`);
467
+ if (!options.wait)
468
+ return;
469
+ if (!env.CODOR_MEMBER_TOKEN)
470
+ throw new Error('post --wait requires CODOR_MEMBER_TOKEN');
471
+ const peers = [...new Set(posted.mentions.map((mention) => mention.member_id))]
472
+ .filter((id) => id !== initial.self && initial.members.get(id)?.removed_ts === undefined);
473
+ if (peers.length === 0)
474
+ throw new Error('post --wait requires at least one addressed member');
475
+ const deadline = Date.now() + options.timeout * 1_000;
476
+ let registered = false;
477
+ try {
478
+ await setWait(client, room, initial.self, 'reply', peers, new Date(deadline).toISOString());
479
+ registered = true;
480
+ const reply = await waitForOwnDelivery(client, room, await syncRoom(client, room), deadline, (candidate) => candidate.id > posted.id &&
481
+ peers.includes(candidate.author) &&
482
+ candidate.mentions.some((mention) => mention.member_id === initial.self), initial.self);
483
+ if (!reply) {
484
+ out(`TIMEOUT after ${String(options.timeout)}s`);
485
+ return;
486
+ }
487
+ if (reply.kind === 'peer_finished') {
488
+ registered = false;
489
+ out('peer finished; no direct reply');
490
+ return;
491
+ }
492
+ const consumed = await consumeDelivery(client, room, reply.delivery);
493
+ out(consumed.body);
494
+ }
495
+ finally {
496
+ if (registered)
497
+ await clearWait(client, room, initial.self);
498
+ }
499
+ });
500
+ });
501
+ // harn:end cli-waits-consume-only-matching-deliveries
502
+ program
503
+ .command('tail')
504
+ .option('-r, --channel <channel>', 'channel id; defaults to CODOR_CHANNEL')
505
+ .option('--once', 'print current history and exit')
506
+ .option('--follow', 'follow new channel messages')
507
+ .option('--until-mention <handle>', 'stop after consuming an own delivery directly mentioning handle')
508
+ .option('--until-any', 'stop after consuming any queued own delivery')
509
+ .option('--timeout <seconds>', 'until timeout in seconds', (value) => parsePositiveNumber(value, '--timeout'), 300)
510
+ // harn:assume cli-waits-consume-only-matching-deliveries ref=tail-wait-command
511
+ .action(async (options) => {
512
+ await withClient(async (client) => {
513
+ const room = channel(options);
514
+ const members = new Map();
515
+ const print = (frame) => {
516
+ if (frame.type === 'member')
517
+ members.set(frame.member.id, frame.member);
518
+ if (frame.type !== 'message')
519
+ return;
520
+ const author = members.get(frame.message.author)?.handle ?? frame.message.author;
521
+ // harn:assume continuation-writer-follows-journaled-output-ownership ref=continuation-cli-tail
522
+ if (frame.message.kind === 'run') {
523
+ // Roots and continuations both print here, each carrying only its
524
+ // own id and body. Nothing is aggregated or hidden: a continuation
525
+ // is a row a reader can scroll to, not a fragment of another one.
526
+ out(formatRunHeader(frame.message, author));
527
+ if (frame.message.body)
528
+ out(frame.message.body);
529
+ // The evidence line below reads `run?.error`, which is undefined for
530
+ // a continuation by construction — so a root's failure can never be
531
+ // reattributed to a row that merely continues it.
532
+ // harn:assume run-failure-evidence-is-surfaced ref=cli-run-error-evidence
533
+ if (frame.message.run?.error)
534
+ out(`error: ${frame.message.run.error}`);
535
+ // harn:end run-failure-evidence-is-surfaced
536
+ // harn:end continuation-writer-follows-journaled-output-ownership
537
+ }
538
+ else {
539
+ out(`#${frame.message.id} @${author} ${frame.message.kind}`);
540
+ if (frame.message.body)
541
+ out(frame.message.body);
542
+ }
543
+ };
544
+ const until = options.untilMention !== undefined || options.untilAny === true;
545
+ if (options.untilMention !== undefined && options.untilAny) {
546
+ throw new Error('--until-mention and --until-any are mutually exclusive');
547
+ }
548
+ if (until && !options.follow)
549
+ throw new Error('--until-* requires --follow');
550
+ if (until && options.once)
551
+ throw new Error('--once cannot be combined with --until-*');
552
+ if (until) {
553
+ if (!env.CODOR_MEMBER_TOKEN)
554
+ throw new Error('tail --until-* requires CODOR_MEMBER_TOKEN');
555
+ const snapshot = await syncRoom(client, room);
556
+ const self = snapshot.members.get(snapshot.self);
557
+ if (!self)
558
+ throw new Error('authenticated member is absent from the channel');
559
+ let mentionedId;
560
+ if (options.untilMention !== undefined) {
561
+ const wanted = options.untilMention.replace(/^@/, '');
562
+ const mentioned = [...snapshot.members.values()].find((member) => member.id === options.untilMention || member.handle === wanted);
563
+ if (!mentioned)
564
+ throw new Error(`no such member ${options.untilMention}`);
565
+ if (mentioned.id !== snapshot.self) {
566
+ throw new Error('--until-mention must name the authenticated member');
567
+ }
568
+ mentionedId = mentioned.id;
569
+ }
570
+ const peers = [...snapshot.members.values()]
571
+ .filter((member) => member.id !== snapshot.self && member.removed_ts === undefined && member.state !== 'dead')
572
+ .map((member) => member.id);
573
+ if (peers.length === 0)
574
+ throw new Error('tail --until-* requires at least one active peer');
575
+ const deadline = Date.now() + options.timeout * 1_000;
576
+ let registered = false;
577
+ try {
578
+ await setWait(client, room, snapshot.self, options.untilAny ? 'any' : 'mention', peers, new Date(deadline).toISOString());
579
+ registered = true;
580
+ const match = await waitForOwnDelivery(client, room, await syncRoom(client, room), deadline, (message) => mentionedId === undefined ||
581
+ message.mentions.some((mention) => mention.member_id === mentionedId));
582
+ if (!match) {
583
+ out(`TIMEOUT after ${String(options.timeout)}s`);
584
+ return;
585
+ }
586
+ const consumed = await consumeDelivery(client, room, match.delivery);
587
+ out(consumed.body);
588
+ return;
589
+ }
590
+ finally {
591
+ if (registered)
592
+ await clearWait(client, room, snapshot.self);
593
+ }
594
+ }
595
+ client.send({ type: 'subscribe', room, since_seq: 0 });
596
+ for (;;) {
597
+ const frame = await client.next(24 * 60 * 60 * 1_000);
598
+ if (frame.type === 'error')
599
+ throw new Error(frame.message);
600
+ print(frame);
601
+ if (options.once && frame.type === 'sync_complete')
602
+ return;
603
+ }
604
+ });
605
+ });
606
+ // harn:end cli-waits-consume-only-matching-deliveries
607
+ // harn:assume cli-hook-inbox-is-silent-when-empty ref=inbox-command
608
+ program
609
+ .command('inbox')
610
+ .option('-r, --channel <channel>', 'channel id; defaults to CODOR_CHANNEL')
611
+ .option('--new', 'show queued deliveries not yet consumed')
612
+ .option('--consume', 'consume every printed delivery')
613
+ .option('--format <format>', 'text or hook', 'text')
614
+ .action(async (options) => {
615
+ if (!options.new)
616
+ throw new Error('inbox currently requires --new');
617
+ if (!env.CODOR_MEMBER_TOKEN)
618
+ throw new Error('inbox requires CODOR_MEMBER_TOKEN');
619
+ if (options.format !== 'text' && options.format !== 'hook') {
620
+ throw new Error('--format must be text or hook');
621
+ }
622
+ await withClient(async (client) => {
623
+ const room = channel(options);
624
+ const snapshot = await syncRoom(client, room);
625
+ const rendered = [];
626
+ for (const delivery of ownQueuedDeliveries(snapshot)) {
627
+ const message = options.consume
628
+ ? await consumeDelivery(client, room, delivery)
629
+ : snapshot.messages.get(delivery.message_id);
630
+ if (!message)
631
+ continue;
632
+ rendered.push({
633
+ message,
634
+ author: snapshot.members.get(message.author)?.handle ?? message.author,
635
+ });
636
+ }
637
+ if (options.format === 'hook') {
638
+ const hook = renderHookInbox(rendered);
639
+ if (hook !== undefined)
640
+ out(hook);
641
+ return;
642
+ }
643
+ for (const item of rendered)
644
+ out(formatInboxMessage(item.message, item.author));
645
+ });
646
+ });
647
+ // harn:end cli-hook-inbox-is-silent-when-empty
648
+ // harn:assume cli-observability-uses-scoped-rest ref=status-command
649
+ program
650
+ .command('status')
651
+ .argument('<member>')
652
+ .option('-r, --channel <channel>', 'channel id; defaults to CODOR_CHANNEL')
653
+ .action(async (memberRef, options) => {
654
+ await withClient(async (client) => {
655
+ const room = channel(options);
656
+ const snapshot = await syncRoom(client, room);
657
+ const wanted = memberRef.replace(/^@/, '');
658
+ const member = [...snapshot.members.values()].find((candidate) => candidate.id === memberRef || candidate.handle === wanted);
659
+ if (!member)
660
+ throw new Error(`no such member ${memberRef}`);
661
+ const url = restUrl(`/api/rooms/${encodeURIComponent(room)}/members/${encodeURIComponent(member.id)}/status`);
662
+ const status = MemberStatusResponseSchema.parse(await fetchJson(url));
663
+ const running = status.current_run ? ` (${formatElapsed(status.current_run.elapsed_ms)})` : '';
664
+ const waiting = status.member.waiting
665
+ ? `waiting for ${status.member.waiting.peers.map((peer) => `@${peer}`).join(', ')}`
666
+ : 'not waiting';
667
+ out(`@${status.member.handle} - ${status.member.state}${running}, ${waiting}`);
668
+ status.recent.forEach((item, index) => {
669
+ const clock = new Date(item.ts).toISOString().slice(11, 19);
670
+ out(` ${String(index + 1)}. ${item.kind} ${item.title} ${item.status ?? '-'} ` +
671
+ `${formatDuration(item.duration_ms)} ${clock}`);
672
+ });
673
+ });
674
+ });
675
+ // harn:end cli-observability-uses-scoped-rest
676
+ // harn:assume cli-observability-uses-scoped-rest ref=search-command
677
+ program
678
+ .command('search')
679
+ .argument('<query>')
680
+ .option('-r, --channel <channel>', 'channel id; defaults to CODOR_CHANNEL')
681
+ .option('--runs', 'include bounded projected run evidence')
682
+ .option('--limit <count>', 'result/run scan limit', (value) => parsePositiveInteger(value, '--limit'))
683
+ .action(async (query, options) => {
684
+ await withClient(async (client) => {
685
+ const room = channel(options);
686
+ const snapshot = await syncRoom(client, room);
687
+ const url = restUrl(`/api/rooms/${encodeURIComponent(room)}/search`);
688
+ url.searchParams.set('q', query);
689
+ if (options.runs)
690
+ url.searchParams.set('include', 'runs');
691
+ if (options.limit !== undefined)
692
+ url.searchParams.set('limit', String(options.limit));
693
+ const raw = await fetchJson(url);
694
+ if (typeof raw !== 'object' || raw === null || !('messages' in raw) || !Array.isArray(raw.messages)) {
695
+ throw new Error('invalid search response');
696
+ }
697
+ const messages = raw.messages.map((message) => MessageSchema.parse(message));
698
+ const runs = 'runs' in raw && Array.isArray(raw.runs)
699
+ ? raw.runs.map((hit) => RunSearchHitSchema.parse(hit))
700
+ : [];
701
+ for (const message of messages) {
702
+ const author = snapshot.members.get(message.author)?.handle ?? message.author;
703
+ out(`#${message.id} @${author} ${message.kind} ${message.body}`);
704
+ }
705
+ for (const hit of runs) {
706
+ out(`#${hit.message_id}:${hit.item_index} ${hit.kind} ${hit.excerpt}`);
707
+ }
708
+ });
709
+ });
710
+ // harn:end cli-observability-uses-scoped-rest
711
+ program
712
+ .command('members')
713
+ .requiredOption('-r, --channel <channel>', 'channel id')
714
+ .action(async (options) => {
715
+ await withClient(async (client) => {
716
+ const members = [];
717
+ client.send({ type: 'subscribe', room: options.channel, since_seq: 0 });
718
+ for (;;) {
719
+ const frame = await client.next();
720
+ if (frame.type === 'member')
721
+ members.push(frame.member);
722
+ if (frame.type === 'error')
723
+ throw new Error(frame.message);
724
+ if (frame.type !== 'sync_complete')
725
+ continue;
726
+ for (const member of members) {
727
+ out(`@${member.handle}\t${member.state ?? member.kind}\t${member.harness ?? '-'}`);
728
+ }
729
+ return;
730
+ }
731
+ });
732
+ });
733
+ program
734
+ .command('join')
735
+ .argument('<channel>')
736
+ .requiredOption('--as <handle>', 'channel member handle')
737
+ .option('--harness <harness>', 'claude-code or codex')
738
+ .option('--session <id>', 'native session id')
739
+ .option('--cwd <path>', 'session working directory')
740
+ .option('--policy <policy>', 'session policy label')
741
+ .action(async (channel, options) => {
742
+ const detected = detectSession({
743
+ harness: options.harness,
744
+ session: options.session,
745
+ cwd: options.cwd,
746
+ env,
747
+ });
748
+ await withClient(async (client) => {
749
+ const existing = new Set();
750
+ client.send({ type: 'subscribe', room: channel, since_seq: 0 });
751
+ for (;;) {
752
+ const frame = await client.next();
753
+ if (frame.type === 'member')
754
+ existing.add(frame.member.id);
755
+ if (frame.type === 'error')
756
+ throw new Error(frame.message);
757
+ if (frame.type === 'sync_complete')
758
+ break;
759
+ }
760
+ client.send({
761
+ type: 'act',
762
+ room: channel,
763
+ act: {
764
+ act: 'join',
765
+ harness: detected.harness,
766
+ handle: options.as,
767
+ session_ref: detected.session_ref,
768
+ cwd: detected.cwd,
769
+ policy: options.policy,
770
+ },
771
+ });
772
+ for (;;) {
773
+ const frame = await client.next();
774
+ if (frame.type === 'error')
775
+ throw new Error(frame.message);
776
+ if (frame.type === 'member' &&
777
+ !existing.has(frame.member.id) &&
778
+ frame.member.handle === options.as &&
779
+ frame.member.custody === 'mirrored') {
780
+ out(`joined @${frame.member.handle} ${frame.member.id} (${detected.harness})`);
781
+ return;
782
+ }
783
+ }
784
+ });
785
+ });
786
+ program
787
+ .command('adopt')
788
+ .argument('<member>')
789
+ .requiredOption('-r, --channel <channel>', 'channel id')
790
+ .action(async (memberRef, options) => {
791
+ await withClient(async (client) => {
792
+ let member;
793
+ client.send({ type: 'subscribe', room: options.channel, since_seq: 0 });
794
+ for (;;) {
795
+ const frame = await client.next();
796
+ if (frame.type === 'member' &&
797
+ (frame.member.id === memberRef || frame.member.handle === memberRef.replace(/^@/, ''))) {
798
+ member = frame.member;
799
+ }
800
+ if (frame.type === 'error')
801
+ throw new Error(frame.message);
802
+ if (frame.type === 'sync_complete')
803
+ break;
804
+ }
805
+ if (!member)
806
+ throw new Error(`no such member ${memberRef}`);
807
+ client.send({ type: 'act', room: options.channel, act: { act: 'adopt', member_id: member.id } });
808
+ for (;;) {
809
+ const frame = await client.next();
810
+ if (frame.type === 'error')
811
+ throw new Error(frame.message);
812
+ if (frame.type === 'member' &&
813
+ frame.member.id === member.id &&
814
+ frame.member.custody === 'owned') {
815
+ out(`adopted @${frame.member.handle}`);
816
+ return;
817
+ }
818
+ }
819
+ });
820
+ });
821
+ program
822
+ .command('mirror-hook', { hidden: true })
823
+ .argument('<source>', 'claude or codex')
824
+ .argument('[payload]', 'hook JSON; Claude hooks default to stdin')
825
+ .action(async (source, payload) => {
826
+ if (source !== 'claude' && source !== 'codex')
827
+ throw new Error(`unsupported mirror source '${source}'`);
828
+ const raw = payload ?? (await readStandardInput());
829
+ const frame = parseMirrorHook(source, raw, env);
830
+ await withClient(async (client) => {
831
+ client.send(frame);
832
+ for (;;) {
833
+ const response = await client.next();
834
+ if (response.type === 'error')
835
+ throw new Error(response.message);
836
+ if (response.type === 'mirror_ack')
837
+ return;
838
+ }
839
+ });
840
+ });
841
+ // harn:assume cli-member-recovery-is-actionable ref=cli-revive-and-attach-surface
842
+ program
843
+ .command('attach')
844
+ .argument('<member>')
845
+ .option('-r, --channel <channel>', 'channel id; omitted searches all channels')
846
+ .action(async (memberRef, options) => {
847
+ await withClient(async (client) => {
848
+ const wanted = memberRef.replace(/^@/, '');
849
+ let rooms = options.channel ? [options.channel] : undefined;
850
+ if (!rooms) {
851
+ client.send({ type: 'list_rooms' });
852
+ for (;;) {
853
+ const frame = await client.next();
854
+ if (frame.type === 'error')
855
+ throw new Error(frame.message);
856
+ if (frame.type === 'rooms') {
857
+ rooms = frame.rooms.map((room) => room.id);
858
+ break;
859
+ }
860
+ }
861
+ }
862
+ const matches = [];
863
+ for (const room of rooms) {
864
+ client.send({ type: 'subscribe', room, since_seq: 0 });
865
+ for (;;) {
866
+ const frame = await client.next();
867
+ if (frame.type === 'error')
868
+ throw new Error(frame.message);
869
+ if (frame.type === 'member' &&
870
+ frame.member.removed_ts === undefined &&
871
+ (frame.member.id === memberRef || frame.member.handle === wanted)) {
872
+ matches.push({ room, member: frame.member });
873
+ }
874
+ if (frame.type === 'sync_complete')
875
+ break;
876
+ }
877
+ }
878
+ if (matches.length === 0)
879
+ throw new Error(`no such member ${memberRef}`);
880
+ if (matches.length > 1) {
881
+ const candidates = matches
882
+ .map(({ room, member }) => `${room} (${member.state ?? member.kind})`)
883
+ .sort()
884
+ .join(', ');
885
+ throw new Error(`member ${memberRef} is ambiguous: ${candidates}; pass --channel <channel-id>`);
886
+ }
887
+ const match = matches[0];
888
+ client.send({
889
+ type: 'act',
890
+ room: match.room,
891
+ act: { act: 'attach_acquire', member_id: match.member.id, cli_pid: process.pid },
892
+ });
893
+ let acquired;
894
+ for (;;) {
895
+ const frame = await client.next(24 * 60 * 60 * 1_000);
896
+ if (frame.type === 'error')
897
+ throw new Error(frame.message);
898
+ if (frame.type === 'attach_lease' &&
899
+ frame.status === 'acquired' &&
900
+ frame.member.id === match.member.id &&
901
+ frame.lease) {
902
+ acquired = { member: frame.member, lease: frame.lease };
903
+ break;
904
+ }
905
+ }
906
+ out(`attaching @${acquired.member.handle} (${acquired.member.harness})`);
907
+ const result = await superviseInteractiveAttach({
908
+ client,
909
+ room: match.room,
910
+ member: acquired.member,
911
+ lease: acquired.lease,
912
+ env,
913
+ commandResolver: context.interactiveCommand ?? nativeResumeCommand,
914
+ spawnChild: context.spawnInteractive,
915
+ heartbeatMs: context.attachHeartbeatMs,
916
+ });
917
+ if (result.status === 'completed')
918
+ out(`re-adopted @${acquired.member.handle}`);
919
+ else
920
+ out(`@${acquired.member.handle} custody remains uncertain until its process group exits`);
921
+ });
922
+ });
923
+ program
924
+ .command('revive')
925
+ .description('revive a dead agent from its persisted native session')
926
+ .argument('<member>')
927
+ .requiredOption('-r, --channel <channel>', 'channel id')
928
+ .action(async (memberRef, options) => {
929
+ await withClient(async (client) => {
930
+ const wanted = memberRef.replace(/^@/, '');
931
+ let member;
932
+ client.send({ type: 'subscribe', room: options.channel, since_seq: 0 });
933
+ for (;;) {
934
+ const frame = await client.next();
935
+ if (frame.type === 'member' &&
936
+ frame.member.removed_ts === undefined &&
937
+ (frame.member.id === memberRef || frame.member.handle === wanted)) {
938
+ member = frame.member;
939
+ }
940
+ if (frame.type === 'error')
941
+ throw new Error(frame.message);
942
+ if (frame.type === 'sync_complete')
943
+ break;
944
+ }
945
+ if (!member)
946
+ throw new Error(`no such member ${memberRef}`);
947
+ client.send({ type: 'act', room: options.channel, act: { act: 'revive', member_id: member.id } });
948
+ for (;;) {
949
+ const frame = await client.next();
950
+ if (frame.type === 'error')
951
+ throw new Error(frame.message);
952
+ if (frame.type === 'member' && frame.member.id === member.id && frame.member.state !== 'dead') {
953
+ out(`revived @${frame.member.handle}`);
954
+ return;
955
+ }
956
+ }
957
+ });
958
+ });
959
+ // harn:end cli-member-recovery-is-actionable
960
+ // harn:assume terminal-pairing-qr-matches-plain-url ref=pair-qr-command
961
+ program
962
+ .command('pair')
963
+ .description('create a ten-minute browser or peer pairing link')
964
+ .option('--endpoint <url>', 'switchboard browser endpoint', 'http://127.0.0.1:8137')
965
+ .option('--no-qr', 'print the plain pairing URL without a terminal QR')
966
+ .action((options) => {
967
+ withCrypto((crypto) => {
968
+ const offer = crypto.pairing.issue(options.endpoint);
969
+ const url = pairingUrl(offer);
970
+ if (options.qr)
971
+ out((context.renderQr ?? renderTerminalQr)(url));
972
+ out(url);
973
+ // harn:assume pairing-code-enrollment-surfaces ref=pair-code-command
974
+ out(`code: ${offer.pairing_code}`);
975
+ // harn:end pairing-code-enrollment-surfaces
976
+ out(`expires ${offer.expires_at}`);
977
+ });
978
+ });
979
+ // harn:end terminal-pairing-qr-matches-plain-url
980
+ program.command('peers').description('list enrolled devices and switchboards').action(() => {
981
+ withCrypto((crypto) => {
982
+ for (const peer of crypto.keys.listPeers()) {
983
+ out(`${peer.device_id}\t${peer.kind}\t${peer.label ?? '-'}`);
984
+ }
985
+ });
986
+ });
987
+ program
988
+ .command('revoke')
989
+ .description('revoke a device or switchboard and rotate channel keys')
990
+ .argument('<peer>', 'device id or label')
991
+ .action((peer) => {
992
+ withCrypto((crypto) => {
993
+ const revoked = crypto.revokePeer(peer);
994
+ out(`revoked ${revoked.device_id}`);
995
+ });
996
+ });
997
+ const ledger = program.command('ledger').description('manage channel shared-memory notes');
998
+ ledger
999
+ .command('init')
1000
+ .requiredOption('-r, --channel <channel>', 'channel id')
1001
+ .action((options) => {
1002
+ const vault = new LedgerVault(program.opts().dataDir, options.channel);
1003
+ vault.bootstrap();
1004
+ out(vault.root);
1005
+ });
1006
+ ledger
1007
+ .command('add')
1008
+ .argument('<name>', 'lowercase note slug')
1009
+ .argument('<body>', 'markdown note body')
1010
+ .requiredOption('-r, --channel <channel>', 'channel id')
1011
+ .requiredOption('--type <type>', 'decision, constraint, or contract')
1012
+ .requiredOption('--as <handle>', 'channel member attribution')
1013
+ .option('--join <line>', 'route the write to the home using name:secret')
1014
+ .option('--home <peer>', 'home switchboard device id')
1015
+ .action(async (name, body, options) => {
1016
+ if (!['decision', 'constraint', 'contract'].includes(options.type)) {
1017
+ throw new Error('--type must be decision, constraint, or contract');
1018
+ }
1019
+ const write = {
1020
+ name,
1021
+ body,
1022
+ type: options.type,
1023
+ author: options.as,
1024
+ };
1025
+ if (options.join || options.home) {
1026
+ if (!options.join || !options.home)
1027
+ throw new Error('--join and --home must be used together');
1028
+ const crypto = new CryptoVault(program.opts().dataDir);
1029
+ const transport = new HyperswarmTransport({ lines: [parseLine(options.join)], crypto });
1030
+ try {
1031
+ await transport.start();
1032
+ await transport.waitForPeer(options.home);
1033
+ const note = await addRemoteLedgerNote(transport, options.home, options.channel, write);
1034
+ out(`${note.relative_path}\t[[${note.name}]]`);
1035
+ }
1036
+ finally {
1037
+ await transport.close();
1038
+ crypto.close();
1039
+ }
1040
+ return;
1041
+ }
1042
+ const note = new LedgerVault(program.opts().dataDir, options.channel).add(write);
1043
+ out(`${note.relative_path}\t[[${note.name}]]`);
1044
+ });
1045
+ ledger
1046
+ .command('show')
1047
+ .argument('<name>', 'note slug')
1048
+ .requiredOption('-r, --channel <channel>', 'channel id')
1049
+ .action((name, options) => {
1050
+ const note = new LedgerVault(program.opts().dataDir, options.channel).note(name);
1051
+ if (!note)
1052
+ throw new Error(`no such ledger note ${name}`);
1053
+ out(note.content.trimEnd());
1054
+ });
1055
+ ledger
1056
+ .command('pull')
1057
+ .requiredOption('-r, --channel <channel>', 'channel id')
1058
+ .option('-d, --destination <path>', 'snapshot parent directory', process.cwd())
1059
+ .action((options) => {
1060
+ out(new LedgerVault(program.opts().dataDir, options.channel).pull(options.destination));
1061
+ });
1062
+ // harn:end human-facing-surfaces-call-rooms-channels
1063
+ return program;
1064
+ }
1065
+ export async function runCli(argv = process.argv, context = {}) {
1066
+ await createProgram(context).parseAsync(argv);
1067
+ }
1068
+ //# sourceMappingURL=program.js.map