bantou 0.1.0 → 0.2.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 (515) hide show
  1. package/.output/nitro.json +13 -0
  2. package/.output/public/_nuxt/BmGsA4i2.js +1 -0
  3. package/.output/public/_nuxt/D_G6gzEa.js +1 -0
  4. package/.output/public/_nuxt/builds/latest.json +1 -0
  5. package/.output/public/_nuxt/builds/meta/1a8fc623-6671-445b-bdd3-c3d073520a3a.json +1 -0
  6. package/.output/public/_nuxt/entry.CZSvzYhH.css +1 -0
  7. package/.output/public/_nuxt/error-404.C3wqHTJz.css +1 -0
  8. package/.output/public/_nuxt/error-500.D6rBzoDj.css +1 -0
  9. package/.output/public/_nuxt/pdFQkwM_.js +4 -0
  10. package/.output/server/chunks/_/error-500.mjs +20 -0
  11. package/.output/server/chunks/_/error-500.mjs.map +1 -0
  12. package/.output/server/chunks/nitro/nitro.mjs +5870 -0
  13. package/.output/server/chunks/nitro/nitro.mjs.map +1 -0
  14. package/.output/server/chunks/routes/mcp.mjs +22 -0
  15. package/.output/server/chunks/routes/mcp.mjs.map +1 -0
  16. package/.output/server/chunks/routes/renderer.mjs +462 -0
  17. package/.output/server/chunks/routes/renderer.mjs.map +1 -0
  18. package/.output/server/chunks/virtual/_virtual_spa-template.mjs +4 -0
  19. package/.output/server/chunks/virtual/_virtual_spa-template.mjs.map +1 -0
  20. package/.output/server/chunks/virtual/precomputed.mjs +4 -0
  21. package/.output/server/chunks/virtual/precomputed.mjs.map +1 -0
  22. package/.output/server/index.mjs +18 -0
  23. package/.output/server/index.mjs.map +1 -0
  24. package/.output/server/node_modules/@babel/parser/lib/index.js +14657 -0
  25. package/.output/server/node_modules/@babel/parser/package.json +50 -0
  26. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js +64 -0
  27. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js +16 -0
  28. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js +32 -0
  29. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js +246 -0
  30. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/package.json +1 -0
  31. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js +41 -0
  32. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js +429 -0
  33. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js +971 -0
  34. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/requestBody.js +58 -0
  35. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js +13 -0
  36. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js +961 -0
  37. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js +228 -0
  38. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js +51 -0
  39. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js +57 -0
  40. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js +1137 -0
  41. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js +92 -0
  42. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js +239 -0
  43. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js +2065 -0
  44. package/.output/server/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js +87 -0
  45. package/.output/server/node_modules/@modelcontextprotocol/sdk/package.json +165 -0
  46. package/.output/server/node_modules/@parcel/watcher-wasm/index.mjs +349 -0
  47. package/.output/server/node_modules/@parcel/watcher-wasm/package.json +44 -0
  48. package/.output/server/node_modules/@parcel/watcher-wasm/watcher.wasm +0 -0
  49. package/.output/server/node_modules/@parcel/watcher-wasm/wrapper.js +88 -0
  50. package/.output/server/node_modules/@unagents/messenger-broker/dist/index.mjs +12 -0
  51. package/.output/server/node_modules/@unagents/messenger-broker/dist/shared/messenger-broker.B8W77sqB.mjs +1177 -0
  52. package/.output/server/node_modules/@unagents/messenger-broker/package.json +37 -0
  53. package/.output/server/node_modules/@unagents/messenger-client/dist/index.mjs +9 -0
  54. package/.output/server/node_modules/@unagents/messenger-client/dist/shared/messenger-client.CfQVmH_Z.mjs +975 -0
  55. package/.output/server/node_modules/@unagents/messenger-client/dist/shared/messenger-client.CoDKzubj.mjs +1000 -0
  56. package/.output/server/node_modules/@unagents/messenger-client/package.json +37 -0
  57. package/.output/server/node_modules/@unagents/messenger-protocol/dist/index.mjs +103 -0
  58. package/.output/server/node_modules/@unagents/messenger-protocol/package.json +29 -0
  59. package/.output/server/node_modules/@vue/compiler-core/dist/compiler-core.cjs.prod.js +6802 -0
  60. package/.output/server/node_modules/@vue/compiler-core/package.json +58 -0
  61. package/.output/server/node_modules/@vue/compiler-dom/dist/compiler-dom.cjs.prod.js +729 -0
  62. package/.output/server/node_modules/@vue/compiler-dom/package.json +57 -0
  63. package/.output/server/node_modules/@vue/compiler-ssr/dist/compiler-ssr.cjs.js +1420 -0
  64. package/.output/server/node_modules/@vue/compiler-ssr/package.json +34 -0
  65. package/.output/server/node_modules/@vue/reactivity/dist/reactivity.cjs.prod.js +1933 -0
  66. package/.output/server/node_modules/@vue/reactivity/package.json +55 -0
  67. package/.output/server/node_modules/@vue/runtime-core/dist/runtime-core.cjs.prod.js +7085 -0
  68. package/.output/server/node_modules/@vue/runtime-core/package.json +52 -0
  69. package/.output/server/node_modules/@vue/runtime-dom/dist/runtime-dom.cjs.prod.js +1917 -0
  70. package/.output/server/node_modules/@vue/runtime-dom/package.json +60 -0
  71. package/.output/server/node_modules/@vue/server-renderer/dist/server-renderer.cjs.prod.js +951 -0
  72. package/.output/server/node_modules/@vue/server-renderer/package.json +53 -0
  73. package/.output/server/node_modules/@vue/shared/dist/shared.cjs.prod.js +655 -0
  74. package/.output/server/node_modules/@vue/shared/package.json +47 -0
  75. package/.output/server/node_modules/ajv/dist/ajv.js +50 -0
  76. package/.output/server/node_modules/ajv/dist/compile/codegen/code.js +156 -0
  77. package/.output/server/node_modules/ajv/dist/compile/codegen/index.js +697 -0
  78. package/.output/server/node_modules/ajv/dist/compile/codegen/scope.js +143 -0
  79. package/.output/server/node_modules/ajv/dist/compile/errors.js +123 -0
  80. package/.output/server/node_modules/ajv/dist/compile/index.js +242 -0
  81. package/.output/server/node_modules/ajv/dist/compile/names.js +28 -0
  82. package/.output/server/node_modules/ajv/dist/compile/ref_error.js +12 -0
  83. package/.output/server/node_modules/ajv/dist/compile/resolve.js +155 -0
  84. package/.output/server/node_modules/ajv/dist/compile/rules.js +26 -0
  85. package/.output/server/node_modules/ajv/dist/compile/util.js +178 -0
  86. package/.output/server/node_modules/ajv/dist/compile/validate/applicability.js +19 -0
  87. package/.output/server/node_modules/ajv/dist/compile/validate/boolSchema.js +50 -0
  88. package/.output/server/node_modules/ajv/dist/compile/validate/dataType.js +203 -0
  89. package/.output/server/node_modules/ajv/dist/compile/validate/defaults.js +35 -0
  90. package/.output/server/node_modules/ajv/dist/compile/validate/index.js +520 -0
  91. package/.output/server/node_modules/ajv/dist/compile/validate/keyword.js +124 -0
  92. package/.output/server/node_modules/ajv/dist/compile/validate/subschema.js +81 -0
  93. package/.output/server/node_modules/ajv/dist/core.js +618 -0
  94. package/.output/server/node_modules/ajv/dist/refs/data.json +13 -0
  95. package/.output/server/node_modules/ajv/dist/refs/json-schema-draft-07.json +151 -0
  96. package/.output/server/node_modules/ajv/dist/runtime/equal.js +7 -0
  97. package/.output/server/node_modules/ajv/dist/runtime/ucs2length.js +24 -0
  98. package/.output/server/node_modules/ajv/dist/runtime/uri.js +6 -0
  99. package/.output/server/node_modules/ajv/dist/runtime/validation_error.js +11 -0
  100. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/additionalItems.js +49 -0
  101. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js +106 -0
  102. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/allOf.js +23 -0
  103. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/anyOf.js +12 -0
  104. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/contains.js +95 -0
  105. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/dependencies.js +85 -0
  106. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/if.js +66 -0
  107. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/index.js +44 -0
  108. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/items.js +52 -0
  109. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/items2020.js +30 -0
  110. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/not.js +26 -0
  111. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/oneOf.js +60 -0
  112. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/patternProperties.js +75 -0
  113. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/prefixItems.js +12 -0
  114. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/properties.js +54 -0
  115. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/propertyNames.js +38 -0
  116. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/thenElse.js +13 -0
  117. package/.output/server/node_modules/ajv/dist/vocabularies/code.js +131 -0
  118. package/.output/server/node_modules/ajv/dist/vocabularies/core/id.js +10 -0
  119. package/.output/server/node_modules/ajv/dist/vocabularies/core/index.js +16 -0
  120. package/.output/server/node_modules/ajv/dist/vocabularies/core/ref.js +122 -0
  121. package/.output/server/node_modules/ajv/dist/vocabularies/discriminator/index.js +104 -0
  122. package/.output/server/node_modules/ajv/dist/vocabularies/discriminator/types.js +9 -0
  123. package/.output/server/node_modules/ajv/dist/vocabularies/draft7.js +17 -0
  124. package/.output/server/node_modules/ajv/dist/vocabularies/format/format.js +92 -0
  125. package/.output/server/node_modules/ajv/dist/vocabularies/format/index.js +6 -0
  126. package/.output/server/node_modules/ajv/dist/vocabularies/metadata.js +18 -0
  127. package/.output/server/node_modules/ajv/dist/vocabularies/validation/const.js +25 -0
  128. package/.output/server/node_modules/ajv/dist/vocabularies/validation/enum.js +48 -0
  129. package/.output/server/node_modules/ajv/dist/vocabularies/validation/index.js +33 -0
  130. package/.output/server/node_modules/ajv/dist/vocabularies/validation/limitItems.js +24 -0
  131. package/.output/server/node_modules/ajv/dist/vocabularies/validation/limitLength.js +27 -0
  132. package/.output/server/node_modules/ajv/dist/vocabularies/validation/limitNumber.js +27 -0
  133. package/.output/server/node_modules/ajv/dist/vocabularies/validation/limitProperties.js +24 -0
  134. package/.output/server/node_modules/ajv/dist/vocabularies/validation/multipleOf.js +26 -0
  135. package/.output/server/node_modules/ajv/dist/vocabularies/validation/pattern.js +33 -0
  136. package/.output/server/node_modules/ajv/dist/vocabularies/validation/required.js +79 -0
  137. package/.output/server/node_modules/ajv/dist/vocabularies/validation/uniqueItems.js +64 -0
  138. package/.output/server/node_modules/ajv/package.json +126 -0
  139. package/.output/server/node_modules/ajv-formats/dist/formats.js +208 -0
  140. package/.output/server/node_modules/ajv-formats/dist/index.js +37 -0
  141. package/.output/server/node_modules/ajv-formats/dist/limit.js +69 -0
  142. package/.output/server/node_modules/ajv-formats/package.json +74 -0
  143. package/.output/server/node_modules/consola/dist/chunks/prompt.mjs +280 -0
  144. package/.output/server/node_modules/consola/dist/core.mjs +512 -0
  145. package/.output/server/node_modules/consola/dist/index.mjs +651 -0
  146. package/.output/server/node_modules/consola/dist/shared/consola.DRwqZj3T.mjs +72 -0
  147. package/.output/server/node_modules/consola/dist/shared/consola.DXBYu-KD.mjs +288 -0
  148. package/.output/server/node_modules/consola/dist/utils.mjs +54 -0
  149. package/.output/server/node_modules/consola/package.json +136 -0
  150. package/.output/server/node_modules/content-type/index.js +225 -0
  151. package/.output/server/node_modules/content-type/package.json +42 -0
  152. package/.output/server/node_modules/cookie-es/dist/index.mjs +268 -0
  153. package/.output/server/node_modules/cookie-es/package.json +46 -0
  154. package/.output/server/node_modules/crossws/dist/_chunks/_request.mjs +83 -0
  155. package/.output/server/node_modules/crossws/dist/_chunks/adapter.mjs +234 -0
  156. package/.output/server/node_modules/crossws/dist/_chunks/error.mjs +7 -0
  157. package/.output/server/node_modules/crossws/dist/_chunks/libs/ws.mjs +6 -0
  158. package/.output/server/node_modules/crossws/dist/_chunks/node.mjs +220 -0
  159. package/.output/server/node_modules/crossws/dist/_chunks/peer.mjs +208 -0
  160. package/.output/server/node_modules/crossws/dist/adapters/node.mjs +1 -0
  161. package/.output/server/node_modules/crossws/package.json +115 -0
  162. package/.output/server/node_modules/defu/dist/defu.mjs +69 -0
  163. package/.output/server/node_modules/defu/package.json +48 -0
  164. package/.output/server/node_modules/destr/dist/index.mjs +72 -0
  165. package/.output/server/node_modules/destr/package.json +47 -0
  166. package/.output/server/node_modules/devalue/index.js +17 -0
  167. package/.output/server/node_modules/devalue/package.json +39 -0
  168. package/.output/server/node_modules/devalue/src/base64.js +60 -0
  169. package/.output/server/node_modules/devalue/src/constants.js +12 -0
  170. package/.output/server/node_modules/devalue/src/operations.js +221 -0
  171. package/.output/server/node_modules/devalue/src/parse.js +279 -0
  172. package/.output/server/node_modules/devalue/src/stringify.js +433 -0
  173. package/.output/server/node_modules/devalue/src/uneval.js +698 -0
  174. package/.output/server/node_modules/devalue/src/utils.js +190 -0
  175. package/.output/server/node_modules/entities/dist/commonjs/decode-codepoint.js +77 -0
  176. package/.output/server/node_modules/entities/dist/commonjs/decode.js +568 -0
  177. package/.output/server/node_modules/entities/dist/commonjs/generated/decode-data-html.js +7 -0
  178. package/.output/server/node_modules/entities/dist/commonjs/generated/decode-data-xml.js +7 -0
  179. package/.output/server/node_modules/entities/dist/commonjs/internal/bin-trie-flags.js +21 -0
  180. package/.output/server/node_modules/entities/dist/commonjs/internal/decode-shared.js +31 -0
  181. package/.output/server/node_modules/entities/dist/commonjs/package.json +3 -0
  182. package/.output/server/node_modules/entities/package.json +120 -0
  183. package/.output/server/node_modules/estree-walker/dist/umd/estree-walker.js +344 -0
  184. package/.output/server/node_modules/estree-walker/package.json +37 -0
  185. package/.output/server/node_modules/fast-deep-equal/index.js +46 -0
  186. package/.output/server/node_modules/fast-deep-equal/package.json +61 -0
  187. package/.output/server/node_modules/fast-uri/index.js +711 -0
  188. package/.output/server/node_modules/fast-uri/lib/schemes.js +272 -0
  189. package/.output/server/node_modules/fast-uri/lib/utils.js +799 -0
  190. package/.output/server/node_modules/fast-uri/package.json +68 -0
  191. package/.output/server/node_modules/get-port-please/dist/index.mjs +430 -0
  192. package/.output/server/node_modules/get-port-please/package.json +39 -0
  193. package/.output/server/node_modules/h3/dist/index.mjs +2498 -0
  194. package/.output/server/node_modules/h3/package.json +75 -0
  195. package/.output/server/node_modules/hookable/dist/index.mjs +257 -0
  196. package/.output/server/node_modules/hookable/package.json +54 -0
  197. package/.output/server/node_modules/http-shutdown/index.js +85 -0
  198. package/.output/server/node_modules/http-shutdown/package.json +32 -0
  199. package/.output/server/node_modules/iron-webcrypto/dist/index.js +298 -0
  200. package/.output/server/node_modules/iron-webcrypto/package.json +72 -0
  201. package/.output/server/node_modules/is-extglob/index.js +20 -0
  202. package/.output/server/node_modules/is-extglob/package.json +69 -0
  203. package/.output/server/node_modules/is-glob/index.js +150 -0
  204. package/.output/server/node_modules/is-glob/package.json +81 -0
  205. package/.output/server/node_modules/jiti/dist/jiti.cjs +1 -0
  206. package/.output/server/node_modules/jiti/lib/jiti.mjs +29 -0
  207. package/.output/server/node_modules/jiti/package.json +146 -0
  208. package/.output/server/node_modules/json-schema-traverse/index.js +93 -0
  209. package/.output/server/node_modules/json-schema-traverse/package.json +43 -0
  210. package/.output/server/node_modules/listhen/dist/chunks/xdg-open.mjs +1069 -0
  211. package/.output/server/node_modules/listhen/dist/index.mjs +19 -0
  212. package/.output/server/node_modules/listhen/dist/shared/listhen.tqe5I1Rl.mjs +1040 -0
  213. package/.output/server/node_modules/listhen/package.json +84 -0
  214. package/.output/server/node_modules/napi-wasm/index.mjs +1371 -0
  215. package/.output/server/node_modules/napi-wasm/package.json +33 -0
  216. package/.output/server/node_modules/node-forge/lib/aes.js +1091 -0
  217. package/.output/server/node_modules/node-forge/lib/aesCipherSuites.js +282 -0
  218. package/.output/server/node_modules/node-forge/lib/asn1-validator.js +91 -0
  219. package/.output/server/node_modules/node-forge/lib/asn1.js +1522 -0
  220. package/.output/server/node_modules/node-forge/lib/baseN.js +186 -0
  221. package/.output/server/node_modules/node-forge/lib/cipher.js +230 -0
  222. package/.output/server/node_modules/node-forge/lib/cipherModes.js +1027 -0
  223. package/.output/server/node_modules/node-forge/lib/des.js +496 -0
  224. package/.output/server/node_modules/node-forge/lib/ed25519.js +1091 -0
  225. package/.output/server/node_modules/node-forge/lib/forge.js +13 -0
  226. package/.output/server/node_modules/node-forge/lib/hmac.js +146 -0
  227. package/.output/server/node_modules/node-forge/lib/index.js +33 -0
  228. package/.output/server/node_modules/node-forge/lib/jsbn.js +1294 -0
  229. package/.output/server/node_modules/node-forge/lib/kem.js +168 -0
  230. package/.output/server/node_modules/node-forge/lib/log.js +319 -0
  231. package/.output/server/node_modules/node-forge/lib/md.all.js +13 -0
  232. package/.output/server/node_modules/node-forge/lib/md.js +11 -0
  233. package/.output/server/node_modules/node-forge/lib/md5.js +289 -0
  234. package/.output/server/node_modules/node-forge/lib/mgf.js +12 -0
  235. package/.output/server/node_modules/node-forge/lib/mgf1.js +57 -0
  236. package/.output/server/node_modules/node-forge/lib/oids.js +180 -0
  237. package/.output/server/node_modules/node-forge/lib/pbe.js +1029 -0
  238. package/.output/server/node_modules/node-forge/lib/pbkdf2.js +211 -0
  239. package/.output/server/node_modules/node-forge/lib/pem.js +413 -0
  240. package/.output/server/node_modules/node-forge/lib/pkcs1.js +276 -0
  241. package/.output/server/node_modules/node-forge/lib/pkcs12.js +1081 -0
  242. package/.output/server/node_modules/node-forge/lib/pkcs7.js +1260 -0
  243. package/.output/server/node_modules/node-forge/lib/pkcs7asn1.js +410 -0
  244. package/.output/server/node_modules/node-forge/lib/pki.js +102 -0
  245. package/.output/server/node_modules/node-forge/lib/prime.js +297 -0
  246. package/.output/server/node_modules/node-forge/lib/prng.js +419 -0
  247. package/.output/server/node_modules/node-forge/lib/pss.js +241 -0
  248. package/.output/server/node_modules/node-forge/lib/random.js +191 -0
  249. package/.output/server/node_modules/node-forge/lib/rc2.js +410 -0
  250. package/.output/server/node_modules/node-forge/lib/rsa.js +2014 -0
  251. package/.output/server/node_modules/node-forge/lib/sha1.js +319 -0
  252. package/.output/server/node_modules/node-forge/lib/sha256.js +327 -0
  253. package/.output/server/node_modules/node-forge/lib/sha512.js +561 -0
  254. package/.output/server/node_modules/node-forge/lib/ssh.js +236 -0
  255. package/.output/server/node_modules/node-forge/lib/tls.js +4334 -0
  256. package/.output/server/node_modules/node-forge/lib/util.js +2652 -0
  257. package/.output/server/node_modules/node-forge/lib/x509.js +3257 -0
  258. package/.output/server/node_modules/node-forge/package.json +123 -0
  259. package/.output/server/node_modules/node-mock-http/dist/_polyfill/buffer/node.mjs +1 -0
  260. package/.output/server/node_modules/node-mock-http/dist/_polyfill/events/node.mjs +1 -0
  261. package/.output/server/node_modules/node-mock-http/dist/index.mjs +1 -0
  262. package/.output/server/node_modules/node-mock-http/package.json +63 -0
  263. package/.output/server/node_modules/nostics/dist/formatters/ansi.mjs +19 -0
  264. package/.output/server/node_modules/nostics/dist/index.mjs +194 -0
  265. package/.output/server/node_modules/nostics/package.json +126 -0
  266. package/.output/server/node_modules/pathe/dist/index.mjs +19 -0
  267. package/.output/server/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs +249 -0
  268. package/.output/server/node_modules/pathe/package.json +61 -0
  269. package/.output/server/node_modules/picomatch/index.js +17 -0
  270. package/.output/server/node_modules/picomatch/lib/constants.js +184 -0
  271. package/.output/server/node_modules/picomatch/lib/parse.js +1425 -0
  272. package/.output/server/node_modules/picomatch/lib/picomatch.js +361 -0
  273. package/.output/server/node_modules/picomatch/lib/scan.js +403 -0
  274. package/.output/server/node_modules/picomatch/lib/utils.js +72 -0
  275. package/.output/server/node_modules/picomatch/package.json +83 -0
  276. package/.output/server/node_modules/radix3/dist/index.mjs +262 -0
  277. package/.output/server/node_modules/radix3/package.json +52 -0
  278. package/.output/server/node_modules/source-map-js/lib/array-set.js +121 -0
  279. package/.output/server/node_modules/source-map-js/lib/base64-vlq.js +140 -0
  280. package/.output/server/node_modules/source-map-js/lib/base64.js +67 -0
  281. package/.output/server/node_modules/source-map-js/lib/binary-search.js +111 -0
  282. package/.output/server/node_modules/source-map-js/lib/mapping-list.js +79 -0
  283. package/.output/server/node_modules/source-map-js/lib/quick-sort.js +141 -0
  284. package/.output/server/node_modules/source-map-js/lib/source-map-consumer.js +1236 -0
  285. package/.output/server/node_modules/source-map-js/lib/source-map-generator.js +446 -0
  286. package/.output/server/node_modules/source-map-js/lib/source-node.js +420 -0
  287. package/.output/server/node_modules/source-map-js/lib/util.js +594 -0
  288. package/.output/server/node_modules/source-map-js/package.json +71 -0
  289. package/.output/server/node_modules/source-map-js/source-map.js +8 -0
  290. package/.output/server/node_modules/std-env/dist/index.mjs +1 -0
  291. package/.output/server/node_modules/std-env/package.json +43 -0
  292. package/.output/server/node_modules/tinyclip/dist/index.js +143 -0
  293. package/.output/server/node_modules/tinyclip/package.json +48 -0
  294. package/.output/server/node_modules/ufo/dist/index.mjs +645 -0
  295. package/.output/server/node_modules/ufo/package.json +48 -0
  296. package/.output/server/node_modules/uncrypto/dist/crypto.node.mjs +16 -0
  297. package/.output/server/node_modules/uncrypto/package.json +60 -0
  298. package/.output/server/node_modules/unhead/dist/client.mjs +22 -0
  299. package/.output/server/node_modules/unhead/dist/legacy.mjs +33 -0
  300. package/.output/server/node_modules/unhead/dist/minify.mjs +183 -0
  301. package/.output/server/node_modules/unhead/dist/parser.mjs +518 -0
  302. package/.output/server/node_modules/unhead/dist/plugins.mjs +782 -0
  303. package/.output/server/node_modules/unhead/dist/server.mjs +99 -0
  304. package/.output/server/node_modules/unhead/dist/shared/unhead.BEmVMkeA.mjs +673 -0
  305. package/.output/server/node_modules/unhead/dist/shared/unhead.Bf_fPVYA.mjs +6 -0
  306. package/.output/server/node_modules/unhead/dist/shared/unhead.Bm4Y6XQI.mjs +17 -0
  307. package/.output/server/node_modules/unhead/dist/shared/unhead.C5Bksi2B.mjs +49 -0
  308. package/.output/server/node_modules/unhead/dist/shared/unhead.CGPOfp5O.mjs +32 -0
  309. package/.output/server/node_modules/unhead/dist/shared/unhead.CHEy9ana.mjs +7 -0
  310. package/.output/server/node_modules/unhead/dist/shared/unhead.C_7zwq8E.mjs +11 -0
  311. package/.output/server/node_modules/unhead/dist/shared/unhead.CaeaMM5q.mjs +19 -0
  312. package/.output/server/node_modules/unhead/dist/shared/unhead.D7HkBzZn.mjs +59 -0
  313. package/.output/server/node_modules/unhead/dist/shared/unhead.D9VfQWNo.mjs +240 -0
  314. package/.output/server/node_modules/unhead/dist/shared/unhead.DD4N5B4k.mjs +224 -0
  315. package/.output/server/node_modules/unhead/dist/shared/unhead.DGl9jcjg.mjs +196 -0
  316. package/.output/server/node_modules/unhead/dist/shared/unhead.DJuZwX9c.mjs +400 -0
  317. package/.output/server/node_modules/unhead/dist/shared/unhead.DkxnqlHC.mjs +264 -0
  318. package/.output/server/node_modules/unhead/dist/shared/unhead.DspMpm6y.mjs +48 -0
  319. package/.output/server/node_modules/unhead/dist/shared/unhead.o8j9utSy.mjs +208 -0
  320. package/.output/server/node_modules/unhead/dist/stream/client.mjs +33 -0
  321. package/.output/server/node_modules/unhead/dist/stream/iife.mjs +2 -0
  322. package/.output/server/node_modules/unhead/dist/stream/server.mjs +446 -0
  323. package/.output/server/node_modules/unhead/dist/utils.mjs +7 -0
  324. package/.output/server/node_modules/unhead/package.json +179 -0
  325. package/.output/server/node_modules/untun/dist/_chunks/cloudflared.mjs +179 -0
  326. package/.output/server/node_modules/untun/dist/_chunks/log.mjs +27 -0
  327. package/.output/server/node_modules/untun/dist/index.mjs +47 -0
  328. package/.output/server/node_modules/untun/package.json +44 -0
  329. package/.output/server/node_modules/uqr/dist/index.mjs +739 -0
  330. package/.output/server/node_modules/uqr/package.json +69 -0
  331. package/.output/server/node_modules/vue/dist/vue.cjs.js +80 -0
  332. package/.output/server/node_modules/vue/dist/vue.cjs.prod.js +66 -0
  333. package/.output/server/node_modules/vue/index.js +7 -0
  334. package/.output/server/node_modules/vue/index.mjs +1 -0
  335. package/.output/server/node_modules/vue/package.json +112 -0
  336. package/.output/server/node_modules/vue/server-renderer/index.mjs +1 -0
  337. package/.output/server/node_modules/vue-bundle-renderer/dist/runtime.mjs +687 -0
  338. package/.output/server/node_modules/vue-bundle-renderer/package.json +66 -0
  339. package/.output/server/node_modules/zod/index.js +7 -0
  340. package/.output/server/node_modules/zod/package.json +147 -0
  341. package/.output/server/node_modules/zod/v3/ZodError.js +143 -0
  342. package/.output/server/node_modules/zod/v3/errors.js +9 -0
  343. package/.output/server/node_modules/zod/v3/external.js +6 -0
  344. package/.output/server/node_modules/zod/v3/helpers/errorUtil.js +6 -0
  345. package/.output/server/node_modules/zod/v3/helpers/parseUtil.js +109 -0
  346. package/.output/server/node_modules/zod/v3/helpers/typeAliases.js +1 -0
  347. package/.output/server/node_modules/zod/v3/helpers/util.js +133 -0
  348. package/.output/server/node_modules/zod/v3/index.js +4 -0
  349. package/.output/server/node_modules/zod/v3/locales/en.js +109 -0
  350. package/.output/server/node_modules/zod/v3/package.json +7 -0
  351. package/.output/server/node_modules/zod/v3/types.js +3697 -0
  352. package/.output/server/node_modules/zod/v4/classic/checks.js +1 -0
  353. package/.output/server/node_modules/zod/v4/classic/coerce.js +17 -0
  354. package/.output/server/node_modules/zod/v4/classic/compat.js +31 -0
  355. package/.output/server/node_modules/zod/v4/classic/deep-partial.js +13 -0
  356. package/.output/server/node_modules/zod/v4/classic/errors.js +57 -0
  357. package/.output/server/node_modules/zod/v4/classic/external.js +17 -0
  358. package/.output/server/node_modules/zod/v4/classic/from-json-schema.js +881 -0
  359. package/.output/server/node_modules/zod/v4/classic/in-out.js +36 -0
  360. package/.output/server/node_modules/zod/v4/classic/index.js +4 -0
  361. package/.output/server/node_modules/zod/v4/classic/iso.js +15 -0
  362. package/.output/server/node_modules/zod/v4/classic/package.json +7 -0
  363. package/.output/server/node_modules/zod/v4/classic/parse.js +16 -0
  364. package/.output/server/node_modules/zod/v4/classic/schemas.js +1535 -0
  365. package/.output/server/node_modules/zod/v4/core/api.js +1107 -0
  366. package/.output/server/node_modules/zod/v4/core/checks.js +516 -0
  367. package/.output/server/node_modules/zod/v4/core/compile.js +1866 -0
  368. package/.output/server/node_modules/zod/v4/core/core.js +141 -0
  369. package/.output/server/node_modules/zod/v4/core/doc.js +38 -0
  370. package/.output/server/node_modules/zod/v4/core/errors.js +267 -0
  371. package/.output/server/node_modules/zod/v4/core/index.js +19 -0
  372. package/.output/server/node_modules/zod/v4/core/json-schema-generator.js +99 -0
  373. package/.output/server/node_modules/zod/v4/core/json-schema-processors.js +843 -0
  374. package/.output/server/node_modules/zod/v4/core/json-schema.js +1 -0
  375. package/.output/server/node_modules/zod/v4/core/memoizer.js +311 -0
  376. package/.output/server/node_modules/zod/v4/core/package.json +7 -0
  377. package/.output/server/node_modules/zod/v4/core/parse.js +175 -0
  378. package/.output/server/node_modules/zod/v4/core/regexes.js +156 -0
  379. package/.output/server/node_modules/zod/v4/core/registries.js +51 -0
  380. package/.output/server/node_modules/zod/v4/core/schemas.js +2636 -0
  381. package/.output/server/node_modules/zod/v4/core/to-json-schema.js +651 -0
  382. package/.output/server/node_modules/zod/v4/core/util.js +873 -0
  383. package/.output/server/node_modules/zod/v4/core/versions.js +5 -0
  384. package/.output/server/node_modules/zod/v4/core/visit.js +169 -0
  385. package/.output/server/node_modules/zod/v4/index.js +4 -0
  386. package/.output/server/node_modules/zod/v4/locales/ar.js +111 -0
  387. package/.output/server/node_modules/zod/v4/locales/az.js +110 -0
  388. package/.output/server/node_modules/zod/v4/locales/be.js +168 -0
  389. package/.output/server/node_modules/zod/v4/locales/bg.js +125 -0
  390. package/.output/server/node_modules/zod/v4/locales/bn.js +113 -0
  391. package/.output/server/node_modules/zod/v4/locales/ca.js +112 -0
  392. package/.output/server/node_modules/zod/v4/locales/ckb.js +133 -0
  393. package/.output/server/node_modules/zod/v4/locales/cs.js +116 -0
  394. package/.output/server/node_modules/zod/v4/locales/da.js +120 -0
  395. package/.output/server/node_modules/zod/v4/locales/de.js +113 -0
  396. package/.output/server/node_modules/zod/v4/locales/el.js +112 -0
  397. package/.output/server/node_modules/zod/v4/locales/en.js +125 -0
  398. package/.output/server/node_modules/zod/v4/locales/eo.js +114 -0
  399. package/.output/server/node_modules/zod/v4/locales/es.js +136 -0
  400. package/.output/server/node_modules/zod/v4/locales/fa.js +119 -0
  401. package/.output/server/node_modules/zod/v4/locales/fi.js +117 -0
  402. package/.output/server/node_modules/zod/v4/locales/fr-CA.js +112 -0
  403. package/.output/server/node_modules/zod/v4/locales/fr.js +129 -0
  404. package/.output/server/node_modules/zod/v4/locales/gu.js +113 -0
  405. package/.output/server/node_modules/zod/v4/locales/he.js +221 -0
  406. package/.output/server/node_modules/zod/v4/locales/hi.js +111 -0
  407. package/.output/server/node_modules/zod/v4/locales/hr.js +126 -0
  408. package/.output/server/node_modules/zod/v4/locales/hu.js +113 -0
  409. package/.output/server/node_modules/zod/v4/locales/hy.js +158 -0
  410. package/.output/server/node_modules/zod/v4/locales/id.js +111 -0
  411. package/.output/server/node_modules/zod/v4/locales/index.js +63 -0
  412. package/.output/server/node_modules/zod/v4/locales/is.js +114 -0
  413. package/.output/server/node_modules/zod/v4/locales/it.js +113 -0
  414. package/.output/server/node_modules/zod/v4/locales/ja.js +112 -0
  415. package/.output/server/node_modules/zod/v4/locales/ka.js +117 -0
  416. package/.output/server/node_modules/zod/v4/locales/kh.js +5 -0
  417. package/.output/server/node_modules/zod/v4/locales/km.js +115 -0
  418. package/.output/server/node_modules/zod/v4/locales/kn.js +116 -0
  419. package/.output/server/node_modules/zod/v4/locales/ko.js +116 -0
  420. package/.output/server/node_modules/zod/v4/locales/lt.js +207 -0
  421. package/.output/server/node_modules/zod/v4/locales/mk.js +114 -0
  422. package/.output/server/node_modules/zod/v4/locales/ms.js +112 -0
  423. package/.output/server/node_modules/zod/v4/locales/ne.js +111 -0
  424. package/.output/server/node_modules/zod/v4/locales/nl.js +115 -0
  425. package/.output/server/node_modules/zod/v4/locales/nn.js +113 -0
  426. package/.output/server/node_modules/zod/v4/locales/no.js +113 -0
  427. package/.output/server/node_modules/zod/v4/locales/ota.js +114 -0
  428. package/.output/server/node_modules/zod/v4/locales/package.json +7 -0
  429. package/.output/server/node_modules/zod/v4/locales/pl.js +114 -0
  430. package/.output/server/node_modules/zod/v4/locales/ps.js +119 -0
  431. package/.output/server/node_modules/zod/v4/locales/pt-BR.js +143 -0
  432. package/.output/server/node_modules/zod/v4/locales/pt.js +142 -0
  433. package/.output/server/node_modules/zod/v4/locales/ro.js +122 -0
  434. package/.output/server/node_modules/zod/v4/locales/ru.js +168 -0
  435. package/.output/server/node_modules/zod/v4/locales/sk.js +116 -0
  436. package/.output/server/node_modules/zod/v4/locales/sl.js +114 -0
  437. package/.output/server/node_modules/zod/v4/locales/sv.js +115 -0
  438. package/.output/server/node_modules/zod/v4/locales/ta.js +115 -0
  439. package/.output/server/node_modules/zod/v4/locales/tg.js +117 -0
  440. package/.output/server/node_modules/zod/v4/locales/th.js +115 -0
  441. package/.output/server/node_modules/zod/v4/locales/tk.js +107 -0
  442. package/.output/server/node_modules/zod/v4/locales/tr.js +110 -0
  443. package/.output/server/node_modules/zod/v4/locales/ua.js +5 -0
  444. package/.output/server/node_modules/zod/v4/locales/uk.js +113 -0
  445. package/.output/server/node_modules/zod/v4/locales/ur.js +115 -0
  446. package/.output/server/node_modules/zod/v4/locales/uz.js +113 -0
  447. package/.output/server/node_modules/zod/v4/locales/vi.js +113 -0
  448. package/.output/server/node_modules/zod/v4/locales/yo.js +112 -0
  449. package/.output/server/node_modules/zod/v4/locales/zh-CN.js +114 -0
  450. package/.output/server/node_modules/zod/v4/locales/zh-TW.js +112 -0
  451. package/.output/server/node_modules/zod/v4/mini/checks.js +1 -0
  452. package/.output/server/node_modules/zod/v4/mini/coerce.js +22 -0
  453. package/.output/server/node_modules/zod/v4/mini/deep-partial.js +13 -0
  454. package/.output/server/node_modules/zod/v4/mini/external.js +16 -0
  455. package/.output/server/node_modules/zod/v4/mini/in-out.js +36 -0
  456. package/.output/server/node_modules/zod/v4/mini/iso.js +34 -0
  457. package/.output/server/node_modules/zod/v4/mini/package.json +7 -0
  458. package/.output/server/node_modules/zod/v4/mini/parse.js +1 -0
  459. package/.output/server/node_modules/zod/v4/mini/schemas.js +1002 -0
  460. package/.output/server/node_modules/zod/v4/package.json +7 -0
  461. package/.output/server/node_modules/zod/v4-mini/index.js +3 -0
  462. package/.output/server/node_modules/zod/v4-mini/package.json +7 -0
  463. package/.output/server/node_modules/zod-to-json-schema/dist/esm/Options.js +46 -0
  464. package/.output/server/node_modules/zod-to-json-schema/dist/esm/Refs.js +22 -0
  465. package/.output/server/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +14 -0
  466. package/.output/server/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +8 -0
  467. package/.output/server/node_modules/zod-to-json-schema/dist/esm/index.js +40 -0
  468. package/.output/server/node_modules/zod-to-json-schema/dist/esm/package.json +1 -0
  469. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parseDef.js +62 -0
  470. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parseTypes.js +1 -0
  471. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +17 -0
  472. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +26 -0
  473. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +49 -0
  474. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +5 -0
  475. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +4 -0
  476. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +4 -0
  477. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +46 -0
  478. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +7 -0
  479. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +7 -0
  480. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +6 -0
  481. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +52 -0
  482. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +21 -0
  483. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +26 -0
  484. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +16 -0
  485. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +11 -0
  486. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +10 -0
  487. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +33 -0
  488. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +52 -0
  489. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +72 -0
  490. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +21 -0
  491. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +20 -0
  492. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +4 -0
  493. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +4 -0
  494. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +61 -0
  495. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +20 -0
  496. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +352 -0
  497. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +32 -0
  498. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +6 -0
  499. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +80 -0
  500. package/.output/server/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +4 -0
  501. package/.output/server/node_modules/zod-to-json-schema/dist/esm/selectParser.js +105 -0
  502. package/.output/server/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +87 -0
  503. package/.output/server/node_modules/zod-to-json-schema/package.json +85 -0
  504. package/.output/server/package.json +64 -0
  505. package/README.md +227 -24
  506. package/bin/bantou.mjs +33 -0
  507. package/package.json +18 -8
  508. package/protocol/PROTOCOL.md +26 -0
  509. package/protocol/protocol.json +92 -0
  510. package/dist/cap.js +0 -7
  511. package/dist/cli.js +0 -27
  512. package/dist/config.js +0 -23
  513. package/dist/daemon.js +0 -23
  514. package/dist/session.js +0 -7
  515. package/dist/workspace.js +0 -8
@@ -0,0 +1,1177 @@
1
+ import { listen } from 'listhen';
2
+ import { createRouter, defineEventHandler, createApp, send, setResponseStatus, getRequestHeader, readRawBody, toNodeListener } from 'h3';
3
+ import { DEFAULT_BIND, ENV, DEFAULT_DISCOVERY_PORT, DEFAULT_HTTP_PORT, PROTOCOL_NAME_PATTERN, PROTOCOL_META_MAX_LENGTH, PROTOCOL_MANIFEST_MAX_BYTES, PROTOCOL_DOC_MAX_BYTES, PROTOCOL_TOTAL_MAX_BYTES, canonicalJSON, HEARTBEAT_TIMEOUT_MS, PROTOCOL_MAX_STORED, MESH_SYNC_ROUTE, HEALTH_ROUTE, BROKER_POST_ROUTES, PROTOCOL_ROUTES, RELAY_ROUTE, DISCOVERY_KEY, DISCOVERY_PROBE_VALUE, DISCOVERY_REPLY_VALUE } from '@unagents/messenger-protocol';
4
+ import { homedir, hostname, networkInterfaces } from 'node:os';
5
+ import { join, dirname } from 'node:path';
6
+ import { defu } from 'defu';
7
+ import { readFileSync, mkdirSync, writeFileSync, renameSync } from 'node:fs';
8
+ import { createConsola } from 'consola';
9
+ import { createHash } from 'node:crypto';
10
+ import { request } from 'node:http';
11
+ import { createSocket } from 'node:dgram';
12
+
13
+ const FALLBACK_ENV = "AGENT_MESSENGER_FALLBACK";
14
+ const FALLBACK_INTERVAL_ENV = "AGENT_MESSENGER_FALLBACK_INTERVAL_MS";
15
+ const DEFAULT_FALLBACK_INTERVAL_MS = 1e4;
16
+ const STATE_DIR = join(homedir(), ".agent-messenger");
17
+ const DEFAULT_STATE_FILE = join(STATE_DIR, "broker.json");
18
+ const MESH_ENV = {
19
+ MESH: "AGENT_MESSENGER_MESH",
20
+ INTERVAL_MS: "AGENT_MESSENGER_MESH_INTERVAL_MS",
21
+ PEER_TTL_MS: "AGENT_MESSENGER_MESH_PEER_TTL_MS"
22
+ };
23
+ function configFromEnv(env = process.env) {
24
+ return {
25
+ port: parseInt(env[ENV.PORT] ?? String(DEFAULT_HTTP_PORT), 10),
26
+ bind: env[ENV.BIND] ?? DEFAULT_BIND,
27
+ token: env[ENV.TOKEN] ?? "",
28
+ id: env[ENV.BROKER_ID] ?? hostname(),
29
+ stateFile: env[ENV.STATE] ?? DEFAULT_STATE_FILE,
30
+ discovery: (env[ENV.DISCOVERY] ?? "on").toLowerCase() !== "off",
31
+ discoveryPort: parseInt(env[ENV.DISCOVERY_PORT] ?? String(DEFAULT_DISCOVERY_PORT), 10),
32
+ discoveryAddr: env[ENV.DISCOVERY_ADDR] ?? "",
33
+ fallback: ["1", "true", "on", "yes"].includes((env[FALLBACK_ENV] ?? "").toLowerCase()),
34
+ fallbackIntervalMs: parseInt(env[FALLBACK_INTERVAL_ENV] ?? String(DEFAULT_FALLBACK_INTERVAL_MS), 10),
35
+ mesh: (env[MESH_ENV.MESH] ?? "off").toLowerCase() === "on",
36
+ meshBrokers: [],
37
+ meshIntervalMs: parseInt(env[MESH_ENV.INTERVAL_MS] ?? "5000", 10),
38
+ meshPeerTtlMs: parseInt(env[MESH_ENV.PEER_TTL_MS] ?? "300000", 10),
39
+ configFile: env[ENV.CONFIG] ?? join(STATE_DIR, "config.json")
40
+ };
41
+ }
42
+ function resolveConfig(options = {}) {
43
+ return defu(options, configFromEnv());
44
+ }
45
+
46
+ const log = createConsola({ stdout: process.stderr, stderr: process.stderr }).withTag(
47
+ "agent-messenger broker"
48
+ );
49
+
50
+ class BrokerState {
51
+ constructor(file) {
52
+ this.file = file;
53
+ }
54
+ peers = /* @__PURE__ */ new Map();
55
+ messages = [];
56
+ nextMsgId = 1;
57
+ pending = [];
58
+ /** Protocol definitions by `"name@version"`. Kept while at least one alive peer declares them (see `BrokerHandlers.gcProtocols`). */
59
+ protocols = /* @__PURE__ */ new Map();
60
+ /** Mesh: when each origin broker last synced with us (ms epoch, memory only). Replicated peers live as long as this is fresh. */
61
+ originSeen = /* @__PURE__ */ new Map();
62
+ saveTimer = null;
63
+ /** Read the snapshot if present. A missing or unreadable file starts empty. */
64
+ load() {
65
+ try {
66
+ const raw = JSON.parse(readFileSync(this.file, "utf8"));
67
+ for (const p of raw.peers ?? []) {
68
+ this.peers.set(p.id, p);
69
+ if (p.origin) this.originSeen.set(p.origin, Date.now());
70
+ }
71
+ this.messages = raw.messages ?? [];
72
+ this.nextMsgId = raw.nextMsgId ?? 1;
73
+ this.pending = raw.pending ?? [];
74
+ for (const sp of raw.protocols ?? []) {
75
+ if (sp && typeof sp.name === "string" && typeof sp.version === "string") this.protocols.set(`${sp.name}@${sp.version}`, sp);
76
+ }
77
+ log.info(
78
+ `Loaded state from ${this.file} (${this.peers.size} peer(s), ${this.messages.length} message(s)${this.protocols.size ? `, ${this.protocols.size} protocol(s)` : ""})`
79
+ );
80
+ } catch {
81
+ }
82
+ }
83
+ /** Snapshot to disk after 200 ms; repeated calls inside the window coalesce. */
84
+ scheduleSave() {
85
+ if (this.saveTimer) return;
86
+ this.saveTimer = setTimeout(() => {
87
+ this.saveTimer = null;
88
+ this.saveNow();
89
+ }, 200);
90
+ }
91
+ /** Write the snapshot immediately (also cancels a pending debounced save). */
92
+ saveNow() {
93
+ if (this.saveTimer) {
94
+ clearTimeout(this.saveTimer);
95
+ this.saveTimer = null;
96
+ }
97
+ try {
98
+ mkdirSync(dirname(this.file), { recursive: true });
99
+ const tmp = `${this.file}.tmp`;
100
+ const snapshot = {
101
+ peers: [...this.peers.values()],
102
+ messages: this.messages,
103
+ nextMsgId: this.nextMsgId,
104
+ ...this.pending.length ? { pending: this.pending } : {},
105
+ ...this.protocols.size ? { protocols: [...this.protocols.values()] } : {}
106
+ };
107
+ writeFileSync(tmp, JSON.stringify(snapshot, null, 1));
108
+ renameSync(tmp, this.file);
109
+ } catch (e) {
110
+ log.warn(`Save failed: ${e.message}`);
111
+ }
112
+ }
113
+ /** True when a debounced save is still pending. */
114
+ get savePending() {
115
+ return this.saveTimer !== null;
116
+ }
117
+ }
118
+
119
+ const VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
120
+ const HASH_PATTERN = /^[0-9a-f]{64}$/;
121
+ const MAX_FIELD_LENGTH = 1024;
122
+ function protocolHash(manifest, doc) {
123
+ return createHash("sha256").update(canonicalJSON({ manifest, doc })).digest("hex");
124
+ }
125
+ function isPlainObject(v) {
126
+ return typeof v === "object" && v !== null && !Array.isArray(v);
127
+ }
128
+ function checkDefinition(name, version, def) {
129
+ const bad = (error) => ({ ok: false, code: "INVALID_DEFINITION", error });
130
+ if (typeof name !== "string" || !PROTOCOL_NAME_PATTERN.test(name)) {
131
+ return bad(`invalid protocol name (expected ${String(PROTOCOL_NAME_PATTERN)})`);
132
+ }
133
+ if (typeof version !== "string" || version.length > MAX_FIELD_LENGTH || !VERSION_PATTERN.test(version)) {
134
+ return bad("invalid version (expected semver, e.g. 1.2.0 or 0.0.0+abc1234)");
135
+ }
136
+ if (!isPlainObject(def)) return bad("missing definition");
137
+ const { manifest, doc, source, ref } = def;
138
+ if (!isPlainObject(manifest)) return bad("definition.manifest must be an object");
139
+ if (typeof doc !== "string") return bad("definition.doc must be a string");
140
+ if (typeof source !== "string" || !source || source.length > MAX_FIELD_LENGTH) return bad("definition.source must be a non-empty string");
141
+ if (typeof ref !== "string" || !ref || ref.length > MAX_FIELD_LENGTH) return bad("definition.ref must be a non-empty string");
142
+ if (manifest.name !== name) return bad(`protocol.json "name" must equal "${name}"`);
143
+ if (manifest.description !== void 0 && typeof manifest.description !== "string") return bad('protocol.json "description" must be a string');
144
+ if (manifest.messages !== void 0) {
145
+ if (!isPlainObject(manifest.messages)) return bad('protocol.json "messages" must be an object');
146
+ for (const [k, schema] of Object.entries(manifest.messages)) {
147
+ if (!isPlainObject(schema)) return bad(`protocol.json messages.${k} must be an object (JSON Schema)`);
148
+ }
149
+ }
150
+ const manifestBytes = Buffer.byteLength(JSON.stringify(manifest));
151
+ const docBytes = Buffer.byteLength(doc);
152
+ if (manifestBytes > PROTOCOL_MANIFEST_MAX_BYTES) {
153
+ return { ok: false, code: "TOO_LARGE", error: `protocol.json is ${manifestBytes} bytes (limit ${PROTOCOL_MANIFEST_MAX_BYTES})` };
154
+ }
155
+ if (docBytes > PROTOCOL_DOC_MAX_BYTES) {
156
+ return { ok: false, code: "TOO_LARGE", error: `PROTOCOL.md is ${docBytes} bytes (limit ${PROTOCOL_DOC_MAX_BYTES})` };
157
+ }
158
+ if (manifestBytes + docBytes > PROTOCOL_TOTAL_MAX_BYTES) {
159
+ return { ok: false, code: "TOO_LARGE", error: `definition is ${manifestBytes + docBytes} bytes (limit ${PROTOCOL_TOTAL_MAX_BYTES})` };
160
+ }
161
+ return { ok: true };
162
+ }
163
+ function sanitizeDecls(list) {
164
+ if (!Array.isArray(list)) return [];
165
+ const out = [];
166
+ for (const d of list) {
167
+ if (!isPlainObject(d)) continue;
168
+ const { name, version, hash } = d;
169
+ if (typeof name !== "string" || !PROTOCOL_NAME_PATTERN.test(name)) continue;
170
+ if (typeof version !== "string" || version.length > MAX_FIELD_LENGTH || !VERSION_PATTERN.test(version)) continue;
171
+ if (typeof hash !== "string" || !HASH_PATTERN.test(hash)) continue;
172
+ if (out.some((o) => o.name === name)) continue;
173
+ out.push({ name, version, hash });
174
+ }
175
+ return out;
176
+ }
177
+ function checkMeta(meta) {
178
+ if (!isPlainObject(meta)) return null;
179
+ const { protocol, version } = meta;
180
+ if (typeof protocol !== "string" || typeof version !== "string") return null;
181
+ if (protocol.length > PROTOCOL_META_MAX_LENGTH || version.length > PROTOCOL_META_MAX_LENGTH) return null;
182
+ return { protocol, version };
183
+ }
184
+ function isTagless(v) {
185
+ return v.startsWith("0.0.0+");
186
+ }
187
+ const SEMVER = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$/;
188
+ function compareVersions(a, b) {
189
+ const ta = isTagless(a);
190
+ const tb = isTagless(b);
191
+ if (ta || tb) return ta && tb ? 0 : ta ? -1 : 1;
192
+ const ma = SEMVER.exec(a);
193
+ const mb = SEMVER.exec(b);
194
+ if (!ma || !mb) return a < b ? -1 : a > b ? 1 : 0;
195
+ for (let i = 1; i <= 3; i++) {
196
+ const x = BigInt(ma[i]);
197
+ const y = BigInt(mb[i]);
198
+ if (x !== y) return x < y ? -1 : 1;
199
+ }
200
+ const pa = ma[4];
201
+ const pb = mb[4];
202
+ if (pa === void 0 && pb === void 0) return 0;
203
+ if (pa === void 0) return 1;
204
+ if (pb === void 0) return -1;
205
+ const ia = pa.split(".");
206
+ const ib = pb.split(".");
207
+ for (let i = 0; i < Math.min(ia.length, ib.length); i++) {
208
+ const x = ia[i];
209
+ const y = ib[i];
210
+ const nx = /^\d+$/.test(x);
211
+ const ny = /^\d+$/.test(y);
212
+ if (nx && ny) {
213
+ const dx = BigInt(x);
214
+ const dy = BigInt(y);
215
+ if (dx !== dy) return dx < dy ? -1 : 1;
216
+ } else if (nx !== ny) {
217
+ return nx ? -1 : 1;
218
+ } else if (x !== y) {
219
+ return x < y ? -1 : 1;
220
+ }
221
+ }
222
+ return ia.length === ib.length ? 0 : ia.length < ib.length ? -1 : 1;
223
+ }
224
+
225
+ const PENDING_RELAY_TTL_MS = 60 * 60 * 1e3;
226
+ const DEFAULT_MESH_PEER_TTL_MS = 3e5;
227
+ const MESH_KEY_MEMORY = 2e3;
228
+ class BrokerHandlers {
229
+ constructor(state, opts = {}) {
230
+ this.state = state;
231
+ this.opts = opts;
232
+ }
233
+ recentMeshKeys = /* @__PURE__ */ new Set();
234
+ /** Mesh protocol conflicts already logged (`name@version:hash`), so a standing conflict warns once, not every round. */
235
+ warnedProtocolConflicts = /* @__PURE__ */ new Set();
236
+ // --- peer bookkeeping ---
237
+ /** Cutoff `last_seen` (ISO) below which a peer counts as stale. */
238
+ static cutoff() {
239
+ return new Date(Date.now() - HEARTBEAT_TIMEOUT_MS).toISOString();
240
+ }
241
+ /**
242
+ * Direct peers: `last_seen` within the heartbeat timeout. Replicated peers
243
+ * (mesh): their origin broker synced within `meshPeerTtlMs`; `last_seen` is
244
+ * the origin's clock and is not compared.
245
+ */
246
+ isAlive(p, cutoff) {
247
+ if (p.origin) {
248
+ const seen = this.state.originSeen.get(p.origin) ?? 0;
249
+ return Date.now() - seen < (this.opts.meshPeerTtlMs ?? DEFAULT_MESH_PEER_TTL_MS);
250
+ }
251
+ return p.last_seen >= cutoff;
252
+ }
253
+ /** Number of peers seen within `HEARTBEAT_TIMEOUT_MS` (for `/health`). */
254
+ alivePeerCount() {
255
+ const cutoff = BrokerHandlers.cutoff();
256
+ return [...this.state.peers.values()].filter((p) => this.isAlive(p, cutoff)).length;
257
+ }
258
+ cleanStalePeers() {
259
+ const cutoff = BrokerHandlers.cutoff();
260
+ let removed = 0;
261
+ for (const p of [...this.state.peers.values()]) {
262
+ if (!this.isAlive(p, cutoff)) {
263
+ this.removePeer(p.id);
264
+ removed++;
265
+ }
266
+ }
267
+ if (removed) {
268
+ log.info(`Cleaned ${removed} stale peer(s)`);
269
+ this.state.scheduleSave();
270
+ }
271
+ const expiry = new Date(Date.now() - PENDING_RELAY_TTL_MS).toISOString();
272
+ const kept = this.state.pending.filter((r) => r.queued_at >= expiry);
273
+ if (kept.length !== this.state.pending.length) {
274
+ log.info(`Dropped ${this.state.pending.length - kept.length} expired relayed message(s)`);
275
+ this.state.pending = kept;
276
+ this.state.scheduleSave();
277
+ }
278
+ this.gcProtocols();
279
+ }
280
+ // --- protocol store ---
281
+ /** Alive peers (replicas included) that declare `name@version`. */
282
+ serversOf(name, version) {
283
+ const cutoff = BrokerHandlers.cutoff();
284
+ return [...this.state.peers.values()].filter(
285
+ (p) => this.isAlive(p, cutoff) && p.protocols?.some((d) => d.name === name && d.version === version)
286
+ );
287
+ }
288
+ /**
289
+ * Drop stored definitions that no alive peer (replicas included) declares by `(name, version)` any more.
290
+ * Runs after `cleanStalePeers`, `register`, `unregister`, `/set-protocol`, `/unset-protocol`, `meshApplyPeers`
291
+ * and before `/get-protocol` answers.
292
+ */
293
+ gcProtocols() {
294
+ if (this.state.protocols.size === 0) return;
295
+ const cutoff = BrokerHandlers.cutoff();
296
+ const live = /* @__PURE__ */ new Set();
297
+ for (const p of this.state.peers.values()) {
298
+ if (!this.isAlive(p, cutoff)) continue;
299
+ for (const d of p.protocols ?? []) live.add(`${d.name}@${d.version}`);
300
+ }
301
+ let removed = 0;
302
+ for (const key of [...this.state.protocols.keys()]) {
303
+ if (!live.has(key)) {
304
+ this.state.protocols.delete(key);
305
+ removed++;
306
+ }
307
+ }
308
+ if (removed) {
309
+ log.info(`Dropped ${removed} protocol definition(s) without a declaring peer`);
310
+ this.state.scheduleSave();
311
+ }
312
+ }
313
+ /**
314
+ * Record `decls` on `peer` (hash only). A name the peer already declares is left alone (only `/set-protocol`
315
+ * changes a declaration, so a heartbeat that raced a change cannot undo it), and so is a declaration whose hash
316
+ * differs from the definition stored for the same `(name, version)`.
317
+ */
318
+ mergeDecls(peer, decls) {
319
+ let changed = false;
320
+ for (const d of decls) {
321
+ if (peer.protocols?.some((x) => x.name === d.name)) continue;
322
+ const stored = this.state.protocols.get(`${d.name}@${d.version}`);
323
+ if (stored && stored.hash !== d.hash) continue;
324
+ peer.protocols = [...peer.protocols ?? [], d];
325
+ changed = true;
326
+ }
327
+ return changed;
328
+ }
329
+ /** A peer that registered here (not a mesh replica). Only those can heartbeat / rename. */
330
+ localPeer(id) {
331
+ const p = this.state.peers.get(id);
332
+ return p && !p.origin ? p : void 0;
333
+ }
334
+ removePeer(id) {
335
+ this.state.peers.delete(id);
336
+ this.state.messages = this.state.messages.filter((m) => !(m.to_id === id && m.delivered === 0));
337
+ }
338
+ /** Resolve a peer by id or unique name. */
339
+ resolvePeer(to) {
340
+ const byId = this.state.peers.get(to);
341
+ if (byId) return { peer: byId };
342
+ const byName = [...this.state.peers.values()].filter((p) => p.name && p.name === to);
343
+ if (byName.length === 1) return { peer: byName[0] };
344
+ if (byName.length > 1) {
345
+ return {
346
+ error: `Name "${to}" is ambiguous: ${byName.map((p) => `${p.id}@${p.hostname}`).join(", ")}`
347
+ };
348
+ }
349
+ return { error: `Peer "${to}" not found (no id or name matches)` };
350
+ }
351
+ static generateId() {
352
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
353
+ let id = "";
354
+ for (let i = 0; i < 8; i++) id += chars[Math.floor(Math.random() * chars.length)];
355
+ return id;
356
+ }
357
+ // --- routes ---
358
+ register(body) {
359
+ for (const p of [...this.state.peers.values()]) {
360
+ if (p.pid === body.pid && p.hostname === body.hostname) this.removePeer(p.id);
361
+ }
362
+ const id = BrokerHandlers.generateId();
363
+ const now = (/* @__PURE__ */ new Date()).toISOString();
364
+ this.state.peers.set(id, {
365
+ id,
366
+ name: body.name ?? "",
367
+ pid: body.pid,
368
+ hostname: body.hostname ?? "",
369
+ cwd: body.cwd ?? "",
370
+ git_root: body.git_root ?? null,
371
+ tty: body.tty ?? null,
372
+ summary: body.summary ?? "",
373
+ registered_at: now,
374
+ last_seen: now
375
+ });
376
+ const peer = this.state.peers.get(id);
377
+ if (body.protocols !== void 0) this.mergeDecls(peer, sanitizeDecls(body.protocols));
378
+ this.deliverPending(peer);
379
+ this.gcProtocols();
380
+ this.state.scheduleSave();
381
+ return { id };
382
+ }
383
+ heartbeat(body) {
384
+ const p = this.localPeer(body.id);
385
+ if (!p) return { ok: false, error: "unknown peer (re-register)" };
386
+ p.last_seen = (/* @__PURE__ */ new Date()).toISOString();
387
+ if (body.protocols !== void 0) this.mergeDecls(p, sanitizeDecls(body.protocols));
388
+ this.state.scheduleSave();
389
+ const resend = (p.protocols ?? []).filter((d) => !this.state.protocols.has(`${d.name}@${d.version}`)).map((d) => `${d.name}@${d.version}`);
390
+ return resend.length ? { ok: true, resend } : { ok: true };
391
+ }
392
+ setSummary(body) {
393
+ const p = this.localPeer(body.id);
394
+ if (!p) return { ok: false, error: "unknown peer" };
395
+ p.summary = body.summary ?? "";
396
+ this.state.scheduleSave();
397
+ return { ok: true };
398
+ }
399
+ setName(body) {
400
+ const p = this.localPeer(body.id);
401
+ if (!p) return { ok: false, error: "unknown peer" };
402
+ p.name = body.name ?? "";
403
+ this.deliverPending(p);
404
+ this.state.scheduleSave();
405
+ return { ok: true };
406
+ }
407
+ listPeers(body) {
408
+ const cutoff = BrokerHandlers.cutoff();
409
+ let list = [...this.state.peers.values()].filter((p) => this.isAlive(p, cutoff));
410
+ switch (body.scope) {
411
+ case "host":
412
+ if (body.hostname) list = list.filter((p) => p.hostname === body.hostname);
413
+ break;
414
+ case "directory":
415
+ list = list.filter((p) => p.cwd === body.cwd);
416
+ break;
417
+ case "repo":
418
+ list = body.git_root ? list.filter((p) => p.git_root === body.git_root) : list.filter((p) => p.cwd === body.cwd);
419
+ break;
420
+ }
421
+ if (body.exclude_id) list = list.filter((p) => p.id !== body.exclude_id);
422
+ if (body.protocol) {
423
+ const { protocol, version } = body;
424
+ list = list.filter((p) => p.protocols?.some((d) => d.name === protocol && (!version || d.version === version)));
425
+ }
426
+ return list.map(({ origin: _origin, ...p }) => p);
427
+ }
428
+ sendMessage(body) {
429
+ const resolved = this.resolvePeer(body.to);
430
+ if (resolved.error !== void 0) return { ok: false, error: resolved.error };
431
+ const { peer } = resolved;
432
+ const mode = body.mode ?? "pull";
433
+ if (mode !== "pull" && mode !== "push" && mode !== "ping") return { ok: false, error: `invalid mode: ${String(mode)}` };
434
+ let meta;
435
+ if (body.meta !== void 0) {
436
+ const checked = checkMeta(body.meta);
437
+ if (!checked) return { ok: false, error: "invalid meta: expected {protocol: string, version: string}, each at most 128 characters" };
438
+ meta = checked;
439
+ }
440
+ const msg = {
441
+ id: this.state.nextMsgId++,
442
+ from_id: body.from_id ?? "cli",
443
+ from_name: body.from_name ?? "",
444
+ to_id: peer.id,
445
+ text: body.text ?? "",
446
+ mode,
447
+ sent_at: (/* @__PURE__ */ new Date()).toISOString(),
448
+ delivered: 0,
449
+ acknowledged: 0,
450
+ ...meta ? { meta } : {}
451
+ };
452
+ this.state.messages.push(msg);
453
+ this.state.scheduleSave();
454
+ if (peer.origin) this.opts.onRemoteMessage?.();
455
+ return { ok: true, to_id: peer.id, to_name: peer.name, message_id: msg.id };
456
+ }
457
+ pollMessages(body) {
458
+ const out = this.state.messages.filter((m) => m.to_id === body.id && m.delivered === 0);
459
+ for (const m of out) m.delivered = 1;
460
+ if (out.length) this.state.scheduleSave();
461
+ return { messages: out };
462
+ }
463
+ acknowledgeMessages(body) {
464
+ const ids = new Set(body.message_ids ?? []);
465
+ const before = this.state.messages.length;
466
+ this.state.messages = this.state.messages.filter((m) => !(m.to_id === body.id && ids.has(m.id)));
467
+ if (this.state.messages.length !== before) this.state.scheduleSave();
468
+ return { ok: true };
469
+ }
470
+ getBufferedMessages(body) {
471
+ return {
472
+ messages: this.state.messages.filter(
473
+ (m) => m.to_id === body.id && m.delivered === 1 && m.acknowledged === 0
474
+ )
475
+ };
476
+ }
477
+ unregister(body) {
478
+ this.removePeer(body.id);
479
+ this.gcProtocols();
480
+ this.state.scheduleSave();
481
+ return { ok: true };
482
+ }
483
+ // --- protocol registry ---
484
+ protocolError(code, error, extra = {}) {
485
+ return { ok: false, error, code, ...extra };
486
+ }
487
+ /**
488
+ * `/set-protocol`. Order: unknown peer, definition shape / size (INVALID_DEFINITION, TOO_LARGE), hash
489
+ * re-computation (HASH_MISMATCH), different hash for the same `(name, version)` (PROTOCOL_CONFLICT), held
490
+ * definitions limit (LIMIT). The same hash again is a no-op success, so a client may re-send at will.
491
+ */
492
+ setProtocol(body) {
493
+ const peer = this.localPeer(body.id);
494
+ if (!peer) return { ok: false, error: "unknown peer" };
495
+ const checked = checkDefinition(body.name, body.version, body.definition);
496
+ if (!checked.ok) return this.protocolError(checked.code, checked.error);
497
+ const { name, version, definition } = body;
498
+ const hash = protocolHash(definition.manifest, definition.doc);
499
+ if (body.hash !== hash) {
500
+ return this.protocolError("HASH_MISMATCH", `hash mismatch for ${name}@${version}: sent ${String(body.hash)}, computed ${hash}`);
501
+ }
502
+ this.gcProtocols();
503
+ const key = `${name}@${version}`;
504
+ const existing = this.state.protocols.get(key);
505
+ if (existing && existing.hash !== hash) {
506
+ const servers = this.serversOf(name, version).map((p) => `${p.name || p.id}@${p.hostname}`);
507
+ return this.protocolError(
508
+ "PROTOCOL_CONFLICT",
509
+ `${key} is already registered with a different definition (hash ${existing.hash}, held by ${servers.join(", ") || "no server"}); every server of it must unset_protocol first`,
510
+ { existing_hash: existing.hash, servers }
511
+ );
512
+ }
513
+ if (!existing) {
514
+ if (this.state.protocols.size >= PROTOCOL_MAX_STORED) {
515
+ return this.protocolError("LIMIT", `this broker already holds ${PROTOCOL_MAX_STORED} protocol definitions (limit)`);
516
+ }
517
+ this.state.protocols.set(key, {
518
+ name,
519
+ version,
520
+ hash,
521
+ definition: { manifest: definition.manifest, doc: definition.doc, source: definition.source, ref: definition.ref },
522
+ registered_at: (/* @__PURE__ */ new Date()).toISOString()
523
+ });
524
+ }
525
+ peer.protocols = [...(peer.protocols ?? []).filter((d) => d.name !== name), { name, version, hash }];
526
+ this.gcProtocols();
527
+ this.state.scheduleSave();
528
+ return { ok: true };
529
+ }
530
+ /** `/unset-protocol`: drop one declaration by `name`, or all of the peer's. Succeeds with `removed: 0` when there was none. */
531
+ unsetProtocol(body) {
532
+ const peer = this.localPeer(body.id);
533
+ if (!peer) return { ok: false, error: "unknown peer" };
534
+ if (body.name !== void 0 && typeof body.name !== "string") return { ok: false, error: "invalid name" };
535
+ const before = peer.protocols ?? [];
536
+ const kept = body.name === void 0 ? [] : before.filter((d) => d.name !== body.name);
537
+ const removed = before.length - kept.length;
538
+ if (kept.length) peer.protocols = kept;
539
+ else delete peer.protocols;
540
+ if (removed) {
541
+ this.gcProtocols();
542
+ this.state.scheduleSave();
543
+ }
544
+ return { ok: true, removed };
545
+ }
546
+ /** `/get-protocol`: the stored definition of `name` at `version`, or at the highest held version. No round trip to any server. */
547
+ getProtocol(body) {
548
+ if (typeof body.name !== "string" || !body.name) return this.protocolError("PROTOCOL_NOT_FOUND", "protocol name is required", { versions: [] });
549
+ this.gcProtocols();
550
+ const held = [...this.state.protocols.values()].filter((sp) => sp.name === body.name);
551
+ held.sort((a, b) => compareVersions(b.version, a.version) || (a.registered_at < b.registered_at ? 1 : -1));
552
+ const versions = held.map((sp) => sp.version);
553
+ const found = body.version === void 0 ? held[0] : held.find((sp) => sp.version === body.version);
554
+ if (!found) {
555
+ const what = body.version === void 0 ? `"${body.name}"` : `"${body.name}" version "${body.version}"`;
556
+ return this.protocolError("PROTOCOL_NOT_FOUND", `Protocol ${what} not found (registered versions: ${versions.join(", ") || "none"})`, { versions });
557
+ }
558
+ return { ok: true, protocol: found, servers: this.serversOf(found.name, found.version).length };
559
+ }
560
+ /** Route table of the protocol registry in `PROTOCOL_ROUTES` order. */
561
+ protocolRoutes() {
562
+ return {
563
+ "/set-protocol": (b) => this.setProtocol(b),
564
+ "/unset-protocol": (b) => this.unsetProtocol(b),
565
+ "/get-protocol": (b) => this.getProtocol(b)
566
+ };
567
+ }
568
+ // --- relay from a fallback broker ---
569
+ /** Queue a message for `peerId` exactly like `sendMessage` does. */
570
+ enqueue(peerId, m) {
571
+ const meta = m.meta === void 0 ? null : checkMeta(m.meta);
572
+ this.state.messages.push({
573
+ id: this.state.nextMsgId++,
574
+ from_id: m.from_id,
575
+ from_name: m.from_name,
576
+ to_id: peerId,
577
+ text: m.text,
578
+ mode: m.mode ?? "pull",
579
+ sent_at: m.sent_at,
580
+ delivered: 0,
581
+ acknowledged: 0,
582
+ ...meta ? { meta } : {}
583
+ });
584
+ }
585
+ /** Give `peer` the relayed messages that were waiting for its name. */
586
+ deliverPending(peer) {
587
+ if (!peer.name || this.state.pending.length === 0) return;
588
+ const mine = (r) => r.to_name === peer.name && (!r.to_hostname || r.to_hostname === peer.hostname);
589
+ const hits = this.state.pending.filter(mine);
590
+ if (hits.length === 0) return;
591
+ for (const r of hits) this.enqueue(peer.id, r);
592
+ this.state.pending = this.state.pending.filter((r) => !mine(r));
593
+ log.info(`Delivered ${hits.length} relayed message(s) to ${peer.name} (${peer.id})`);
594
+ }
595
+ /**
596
+ * `/relay-messages`: undelivered messages of a fallback broker. Peer ids are broker-local, so the
597
+ * recipient is addressed by name (and hostname). A recipient that is not registered yet (its client
598
+ * moves over only after the fallback exits) gets the message when it registers.
599
+ */
600
+ relayMessages(body) {
601
+ const res = { ok: true, delivered: 0, queued: 0, dropped: 0 };
602
+ const cutoff = BrokerHandlers.cutoff();
603
+ for (const m of body.messages ?? []) {
604
+ if (!m.to_name) {
605
+ res.dropped++;
606
+ continue;
607
+ }
608
+ let cands = [...this.state.peers.values()].filter((p) => p.name === m.to_name && this.isAlive(p, cutoff));
609
+ if (m.to_hostname && cands.some((p) => p.hostname === m.to_hostname)) cands = cands.filter((p) => p.hostname === m.to_hostname);
610
+ if (cands.length === 1) {
611
+ this.enqueue(cands[0].id, m);
612
+ res.delivered++;
613
+ } else {
614
+ this.state.pending.push({ ...m, queued_at: (/* @__PURE__ */ new Date()).toISOString() });
615
+ res.queued++;
616
+ }
617
+ }
618
+ this.state.scheduleSave();
619
+ log.info(`Relay: ${res.delivered} delivered, ${res.queued} queued, ${res.dropped} dropped`);
620
+ return res;
621
+ }
622
+ // --- mesh (permanent broker sync) ---
623
+ /** Live peers that registered with this broker directly. */
624
+ meshLocalPeers() {
625
+ const cutoff = BrokerHandlers.cutoff();
626
+ return [...this.state.peers.values()].filter((p) => !p.origin && this.isAlive(p, cutoff));
627
+ }
628
+ /** Undelivered messages addressed to peers replicated from `origin` (to be forwarded there). */
629
+ meshOutbox(origin) {
630
+ return this.state.messages.filter((m) => {
631
+ if (m.delivered !== 0) return false;
632
+ return this.state.peers.get(m.to_id)?.origin === origin;
633
+ });
634
+ }
635
+ /** Drop messages the other broker took over. */
636
+ meshDrop(ids) {
637
+ if (!ids.length) return;
638
+ const gone = new Set(ids);
639
+ this.state.messages = this.state.messages.filter((m) => !gone.has(m.id));
640
+ this.state.scheduleSave();
641
+ }
642
+ /** Replace everything held for `origin` by `peers` and note that `origin` is alive. */
643
+ meshApplyPeers(origin, peers) {
644
+ const now = (/* @__PURE__ */ new Date()).toISOString();
645
+ this.state.originSeen.set(origin, Date.now());
646
+ const incoming = /* @__PURE__ */ new Set();
647
+ for (const p of peers) {
648
+ const local = this.state.peers.get(p.id);
649
+ if (local && !local.origin) continue;
650
+ const moved = [...this.state.peers.values()].some((q) => !q.origin && q.pid === p.pid && q.hostname === p.hostname);
651
+ if (moved) continue;
652
+ incoming.add(p.id);
653
+ this.state.peers.set(p.id, { ...p, origin, last_seen: now });
654
+ }
655
+ for (const p of [...this.state.peers.values()]) {
656
+ if (p.origin === origin && !incoming.has(p.id)) this.removePeer(p.id);
657
+ }
658
+ this.gcProtocols();
659
+ this.state.scheduleSave();
660
+ }
661
+ /** Definitions declared by this broker's direct, alive peers (what a mesh sync sends). */
662
+ meshLocalProtocols() {
663
+ const out = /* @__PURE__ */ new Map();
664
+ for (const p of this.meshLocalPeers()) {
665
+ for (const d of p.protocols ?? []) {
666
+ const key = `${d.name}@${d.version}`;
667
+ const sp = this.state.protocols.get(key);
668
+ if (sp && sp.hash === d.hash) out.set(key, sp);
669
+ }
670
+ }
671
+ return [...out.values()];
672
+ }
673
+ /**
674
+ * Take over definitions another broker's direct peers declare. Only a definition that a peer we now hold
675
+ * declares with the same hash is stored (the rest would be collected at once). A `(name, version)` we already
676
+ * hold with another hash stays as it is (ours wins) and the received one is dropped with a warning.
677
+ */
678
+ meshApplyProtocols(from, protocols) {
679
+ let added = false;
680
+ for (const sp of protocols) {
681
+ const checked = checkDefinition(sp?.name, sp?.version, sp?.definition);
682
+ if (!checked.ok) {
683
+ log.warn(`mesh: dropped protocol from ${from}: ${checked.error}`);
684
+ continue;
685
+ }
686
+ const hash = protocolHash(sp.definition.manifest, sp.definition.doc);
687
+ if (hash !== sp.hash) {
688
+ log.warn(`mesh: dropped protocol ${sp.name}@${sp.version} from ${from}: hash mismatch`);
689
+ continue;
690
+ }
691
+ const key = `${sp.name}@${sp.version}`;
692
+ const mine = this.state.protocols.get(key);
693
+ if (mine) {
694
+ if (mine.hash !== hash && !this.warnedProtocolConflicts.has(`${key}:${hash}`)) {
695
+ this.warnedProtocolConflicts.add(`${key}:${hash}`);
696
+ log.warn(`mesh: protocol ${key} from ${from} differs from the one held here (${hash} vs ${mine.hash}); keeping ours`);
697
+ }
698
+ continue;
699
+ }
700
+ if (this.state.protocols.size >= PROTOCOL_MAX_STORED) {
701
+ log.warn(`mesh: dropped protocol ${key} from ${from}: ${PROTOCOL_MAX_STORED} definitions held (limit)`);
702
+ continue;
703
+ }
704
+ if (!this.serversOf(sp.name, sp.version).some((p) => p.protocols?.some((d) => d.name === sp.name && d.version === sp.version && d.hash === hash))) continue;
705
+ this.state.protocols.set(key, {
706
+ name: sp.name,
707
+ version: sp.version,
708
+ hash,
709
+ definition: { manifest: sp.definition.manifest, doc: sp.definition.doc, source: sp.definition.source, ref: sp.definition.ref },
710
+ registered_at: typeof sp.registered_at === "string" ? sp.registered_at : (/* @__PURE__ */ new Date()).toISOString()
711
+ });
712
+ added = true;
713
+ }
714
+ if (added) this.state.scheduleSave();
715
+ }
716
+ /** Take over messages forwarded by broker `from`; returns the sender-side ids to drop (duplicates count as taken). */
717
+ meshAccept(from, messages) {
718
+ const accepted = [];
719
+ for (const m of messages) {
720
+ const target = this.state.peers.get(m.to_id);
721
+ if (!target || target.origin) continue;
722
+ const key = `${from}:${m.id}`;
723
+ const dup = this.recentMeshKeys.has(key) || this.state.messages.some((x) => x.mesh_key === key);
724
+ if (!dup) {
725
+ this.state.messages.push({ ...m, id: this.state.nextMsgId++, delivered: 0, acknowledged: 0, mesh_key: key });
726
+ this.recentMeshKeys.add(key);
727
+ if (this.recentMeshKeys.size > MESH_KEY_MEMORY) this.recentMeshKeys.delete(this.recentMeshKeys.values().next().value);
728
+ }
729
+ accepted.push(m.id);
730
+ }
731
+ if (accepted.length) this.state.scheduleSave();
732
+ return accepted;
733
+ }
734
+ /** Inbound `/mesh/sync`. */
735
+ meshSync(body) {
736
+ if (!body.from) throw new Error("mesh sync: missing from");
737
+ if (body.from === this.opts.id) return { id: body.from, peers: [], accepted: [] };
738
+ this.meshApplyPeers(body.from, body.peers ?? []);
739
+ this.meshApplyProtocols(body.from, body.protocols ?? []);
740
+ const accepted = this.meshAccept(body.from, body.messages ?? []);
741
+ const protocols = this.meshLocalProtocols();
742
+ return { id: this.opts.id ?? "", peers: this.meshLocalPeers(), accepted, ...protocols.length ? { protocols } : {} };
743
+ }
744
+ /** Route table in `BROKER_POST_ROUTES` order. */
745
+ routes() {
746
+ return {
747
+ "/register": (b) => this.register(b),
748
+ "/heartbeat": (b) => this.heartbeat(b),
749
+ "/set-summary": (b) => this.setSummary(b),
750
+ "/set-name": (b) => this.setName(b),
751
+ "/list-peers": (b) => this.listPeers(b),
752
+ "/send-message": (b) => this.sendMessage(b),
753
+ "/poll-messages": (b) => this.pollMessages(b),
754
+ "/acknowledge-messages": (b) => this.acknowledgeMessages(b),
755
+ "/get-buffered-messages": (b) => this.getBufferedMessages(b),
756
+ "/unregister": (b) => this.unregister(b)
757
+ };
758
+ }
759
+ }
760
+
761
+ class Mesh {
762
+ constructor(opts) {
763
+ this.opts = opts;
764
+ }
765
+ timer = null;
766
+ running = false;
767
+ again = false;
768
+ stopped = false;
769
+ links = /* @__PURE__ */ new Map();
770
+ /** url -> id of the broker that answered there */
771
+ origins = /* @__PURE__ */ new Map();
772
+ start() {
773
+ log.info(`mesh on (id ${this.opts.id}, every ${this.opts.intervalMs}ms)`);
774
+ this.timer = setInterval(() => void this.syncOnce(), this.opts.intervalMs);
775
+ this.timer.unref();
776
+ void this.syncOnce();
777
+ }
778
+ stop() {
779
+ this.stopped = true;
780
+ if (this.timer) clearInterval(this.timer);
781
+ this.timer = null;
782
+ }
783
+ /** Sync soon (coalesced). */
784
+ kick() {
785
+ if (this.running) this.again = true;
786
+ else setImmediate(() => void this.syncOnce());
787
+ }
788
+ /** One round against every listed broker. Never throws. */
789
+ async syncOnce() {
790
+ if (this.running) {
791
+ this.again = true;
792
+ return;
793
+ }
794
+ this.running = true;
795
+ try {
796
+ do {
797
+ this.again = false;
798
+ await Promise.all(this.opts.urls().map((url) => this.syncWith(url)));
799
+ } while (this.again && !this.stopped);
800
+ } finally {
801
+ this.running = false;
802
+ }
803
+ }
804
+ setLink(url, state, detail = "") {
805
+ const prev = this.links.get(url);
806
+ this.links.set(url, state);
807
+ if (prev === state) return;
808
+ if (state === "up") log.info(`mesh: ${url} ${prev === "down" ? "is back, synced" : "joined"}`);
809
+ else if (state === "down") log.warn(`mesh: ${url} unreachable${detail ? ` (${detail})` : ""}; will keep retrying`);
810
+ else if (state === "unsupported") log.warn(`mesh: ${url} does not take part in the mesh (${detail})`);
811
+ else if (state === "self") log.info(`mesh: ${url} is this broker, skipped`);
812
+ }
813
+ async syncWith(url) {
814
+ if (this.links.get(url) === "self" || this.stopped) return;
815
+ const { handlers, id } = this.opts;
816
+ const origin = this.origins.get(url);
817
+ const protocols = handlers.meshLocalProtocols();
818
+ const req = {
819
+ from: id,
820
+ peers: handlers.meshLocalPeers(),
821
+ messages: origin ? handlers.meshOutbox(origin) : [],
822
+ ...protocols.length ? { protocols } : {}
823
+ };
824
+ let res;
825
+ try {
826
+ const headers = { "Content-Type": "application/json" };
827
+ if (this.opts.token) headers.Authorization = `Bearer ${this.opts.token}`;
828
+ const r = await postJson(`${url}${MESH_SYNC_ROUTE}`, headers, JSON.stringify(req), this.opts.timeoutMs ?? 3e3);
829
+ if (r.status === 404) return this.setLink(url, "unsupported", "HTTP 404");
830
+ if (r.status < 200 || r.status >= 300) return this.setLink(url, "down", `HTTP ${r.status}`);
831
+ res = JSON.parse(r.body);
832
+ } catch (e) {
833
+ return this.setLink(url, "down", e.message);
834
+ }
835
+ if (!res.id) return this.setLink(url, "unsupported", "no broker id in answer");
836
+ if (res.id === id) return this.setLink(url, "self");
837
+ const learned = this.origins.get(url) !== res.id;
838
+ this.origins.set(url, res.id);
839
+ handlers.meshApplyPeers(res.id, res.peers ?? []);
840
+ handlers.meshApplyProtocols(res.id, res.protocols ?? []);
841
+ handlers.meshDrop(res.accepted ?? []);
842
+ if (learned && handlers.meshOutbox(res.id).length) this.again = true;
843
+ this.setLink(url, "up");
844
+ }
845
+ }
846
+ function readMeshBrokers(configFile) {
847
+ try {
848
+ const parsed = JSON.parse(readFileSync(configFile, "utf8"));
849
+ const list = Array.isArray(parsed.brokers) ? parsed.brokers : parsed.broker ? [parsed.broker] : [];
850
+ const out = [];
851
+ for (const s of list) {
852
+ if (typeof s !== "string" || !s.trim()) continue;
853
+ try {
854
+ out.push(normalizeBrokerUrl(s));
855
+ } catch {
856
+ log.warn(`mesh: ignoring unparsable broker entry "${s}"`);
857
+ }
858
+ }
859
+ return out;
860
+ } catch {
861
+ return [];
862
+ }
863
+ }
864
+ function normalizeBrokerUrl(s) {
865
+ s = s.trim();
866
+ if (!/^https?:\/\//.test(s)) s = `http://${s}`;
867
+ const u = new URL(s);
868
+ if (!u.port) u.port = String(DEFAULT_HTTP_PORT);
869
+ return u.origin;
870
+ }
871
+ function postJson(url, headers, body, timeoutMs) {
872
+ return new Promise((resolve, reject) => {
873
+ const req = request(url, { method: "POST", agent: false, headers: { ...headers, "Content-Length": Buffer.byteLength(body) }, timeout: timeoutMs }, (res) => {
874
+ const chunks = [];
875
+ res.on("data", (d) => chunks.push(d));
876
+ res.on("end", () => resolve({ status: res.statusCode ?? 0, body: Buffer.concat(chunks).toString("utf8") }));
877
+ res.on("error", reject);
878
+ });
879
+ req.on("timeout", () => req.destroy(new Error(`timeout after ${timeoutMs}ms`)));
880
+ req.on("error", reject);
881
+ req.end(body);
882
+ });
883
+ }
884
+
885
+ function createBrokerApp(opts) {
886
+ const routes = opts.handlers.routes();
887
+ const protocolRoutes = opts.handlers.protocolRoutes();
888
+ const router = createRouter();
889
+ router.get(HEALTH_ROUTE, defineEventHandler(() => ({
890
+ status: "ok",
891
+ version: opts.version,
892
+ id: opts.id,
893
+ port: opts.port(),
894
+ peers: opts.handlers.alivePeerCount(),
895
+ ...opts.fallback ? { fallback: true } : {}
896
+ })));
897
+ const post = (route, run) => router.post(route, defineEventHandler(async (event) => {
898
+ if (!authorized(event, opts.token)) return unauthorized(event);
899
+ try {
900
+ return run(await readJson(event));
901
+ } catch (e) {
902
+ setResponseStatus(event, 500);
903
+ return { error: e.message };
904
+ }
905
+ }));
906
+ for (const route of BROKER_POST_ROUTES) post(route, (body) => routes[route](body));
907
+ post(RELAY_ROUTE, (body) => opts.handlers.relayMessages(body));
908
+ for (const route of PROTOCOL_ROUTES) post(route, (body) => protocolRoutes[route](body));
909
+ if (opts.mesh) post(MESH_SYNC_ROUTE, (body) => opts.handlers.meshSync(body));
910
+ const app = createApp();
911
+ app.use(router);
912
+ app.use(defineEventHandler(async (event) => {
913
+ if (event.method !== "POST") {
914
+ return send(event, `agent-messenger broker ${opts.version}
915
+ `, "text/plain");
916
+ }
917
+ if (!authorized(event, opts.token)) return unauthorized(event);
918
+ setResponseStatus(event, 404);
919
+ return { error: "not found" };
920
+ }));
921
+ return app;
922
+ }
923
+ function authorized(event, token) {
924
+ return !token || getRequestHeader(event, "authorization") === `Bearer ${token}`;
925
+ }
926
+ function unauthorized(event) {
927
+ setResponseStatus(event, 401);
928
+ return { error: "unauthorized" };
929
+ }
930
+ async function readJson(event) {
931
+ const raw = await readRawBody(event, "utf8");
932
+ return raw ? JSON.parse(raw) : {};
933
+ }
934
+
935
+ function startDiscoveryResponder(opts) {
936
+ const disco = createSocket({ type: "udp4", reuseAddr: true });
937
+ disco.on("error", (e) => log.warn(`discovery responder error: ${e.message}`));
938
+ disco.on("message", (msg, rinfo) => {
939
+ try {
940
+ if (JSON.parse(msg.toString())[DISCOVERY_KEY] !== DISCOVERY_PROBE_VALUE) return;
941
+ } catch {
942
+ return;
943
+ }
944
+ const reply = Buffer.from(JSON.stringify(opts.reply()));
945
+ disco.send(reply, rinfo.port, rinfo.address, () => {
946
+ });
947
+ });
948
+ const bindAddr = opts.addr && !opts.addr.endsWith(".255") ? opts.addr : "0.0.0.0";
949
+ return new Promise((resolve) => {
950
+ disco.once("error", () => resolve(disco));
951
+ disco.bind(opts.port, bindAddr, () => {
952
+ try {
953
+ disco.setBroadcast(true);
954
+ } catch {
955
+ }
956
+ log.info(`discovery responder on udp ${bindAddr}:${opts.port} (id: ${opts.reply().id})`);
957
+ resolve(disco);
958
+ });
959
+ });
960
+ }
961
+ function probeTargets(addr) {
962
+ if (addr) return [addr];
963
+ const targets = /* @__PURE__ */ new Set(["255.255.255.255"]);
964
+ for (const list of Object.values(networkInterfaces())) {
965
+ for (const i of list ?? []) {
966
+ if (i.family !== "IPv4" || i.internal || !i.netmask) continue;
967
+ const ip = i.address.split(".").map(Number);
968
+ const mask = i.netmask.split(".").map(Number);
969
+ targets.add(ip.map((o, k) => o & mask[k] | ~mask[k] & 255).join("."));
970
+ }
971
+ }
972
+ return [...targets];
973
+ }
974
+ function localAddresses() {
975
+ const out = /* @__PURE__ */ new Set(["127.0.0.1"]);
976
+ for (const list of Object.values(networkInterfaces())) {
977
+ for (const i of list ?? []) if (i.family === "IPv4") out.add(i.address);
978
+ }
979
+ return out;
980
+ }
981
+ function probeBrokers(opts) {
982
+ return new Promise((resolve) => {
983
+ const sock = createSocket({ type: "udp4" });
984
+ const found = /* @__PURE__ */ new Map();
985
+ let settled = false;
986
+ const finish = () => {
987
+ if (settled) return;
988
+ settled = true;
989
+ clearTimeout(timer);
990
+ try {
991
+ sock.close();
992
+ } catch {
993
+ }
994
+ resolve([...found.values()]);
995
+ };
996
+ const timer = setTimeout(finish, opts.timeoutMs);
997
+ sock.on("error", finish);
998
+ sock.on("message", (msg, rinfo) => {
999
+ try {
1000
+ const m = JSON.parse(msg.toString());
1001
+ if (m[DISCOVERY_KEY] !== DISCOVERY_REPLY_VALUE || !m.port) return;
1002
+ const url = `http://${rinfo.address}:${m.port}`;
1003
+ if (!found.has(url)) {
1004
+ found.set(url, { url, host: rinfo.address, port: m.port, id: m.id ?? rinfo.address, version: m.version ?? "", fallback: m.fallback === true });
1005
+ }
1006
+ } catch {
1007
+ }
1008
+ });
1009
+ sock.bind(0, () => {
1010
+ try {
1011
+ sock.setBroadcast(true);
1012
+ } catch {
1013
+ }
1014
+ const probe = Buffer.from(JSON.stringify({ [DISCOVERY_KEY]: DISCOVERY_PROBE_VALUE }));
1015
+ for (const t of probeTargets(opts.addr)) sock.send(probe, opts.port, t, () => {
1016
+ });
1017
+ });
1018
+ });
1019
+ }
1020
+
1021
+ const TIMEOUT_MS = 5e3;
1022
+ async function post(url, path, token, body) {
1023
+ const headers = { "Content-Type": "application/json" };
1024
+ if (token) headers.Authorization = `Bearer ${token}`;
1025
+ return fetch(`${url}${path}`, { method: "POST", headers, body: JSON.stringify(body), signal: AbortSignal.timeout(TIMEOUT_MS) });
1026
+ }
1027
+ async function relayUndelivered(state, url, token) {
1028
+ const items = [];
1029
+ let dropped = 0;
1030
+ for (const m of state.messages) {
1031
+ if (m.delivered !== 0) continue;
1032
+ const peer = state.peers.get(m.to_id);
1033
+ if (!peer?.name) {
1034
+ dropped++;
1035
+ continue;
1036
+ }
1037
+ items.push({
1038
+ from_id: m.from_id,
1039
+ from_name: m.from_name,
1040
+ to_name: peer.name,
1041
+ to_hostname: peer.hostname,
1042
+ text: m.text,
1043
+ mode: m.mode ?? "pull",
1044
+ sent_at: m.sent_at,
1045
+ ...m.meta ? { meta: m.meta } : {}
1046
+ });
1047
+ }
1048
+ let sent = 0;
1049
+ if (items.length) {
1050
+ const res = await post(url, RELAY_ROUTE, token, { messages: items });
1051
+ if (res.ok) {
1052
+ const r = await res.json();
1053
+ sent = r.delivered + r.queued;
1054
+ dropped += r.dropped;
1055
+ } else if (res.status === 404) {
1056
+ for (const it of items) {
1057
+ const r = await post(url, "/send-message", token, { to: it.to_name, from_id: it.from_id, from_name: it.from_name, text: it.text, mode: it.mode, meta: it.meta });
1058
+ if (r.ok && (await r.json()).ok) sent++;
1059
+ else dropped++;
1060
+ }
1061
+ } else {
1062
+ throw new Error(`relay to ${url} failed: ${res.status} ${await res.text()}`);
1063
+ }
1064
+ }
1065
+ state.messages = state.messages.filter((m) => m.delivered !== 0);
1066
+ state.scheduleSave();
1067
+ log.info(`relayed ${sent} message(s) to ${url} (${dropped} dropped: recipient without name or refused)`);
1068
+ return { sent, dropped };
1069
+ }
1070
+
1071
+ const version = "0.10.0";
1072
+ const pkg = {
1073
+ version: version};
1074
+
1075
+ const VERSION = pkg.version;
1076
+ const CLEAN_INTERVAL_MS = 3e4;
1077
+ async function startBroker(options = {}) {
1078
+ const { onSupersede, ...rest } = options;
1079
+ const cfg = resolveConfig(rest);
1080
+ const state = new BrokerState(cfg.stateFile);
1081
+ state.load();
1082
+ let mesh = null;
1083
+ const handlers = new BrokerHandlers(state, {
1084
+ id: cfg.id,
1085
+ meshPeerTtlMs: cfg.meshPeerTtlMs,
1086
+ onRemoteMessage: () => mesh?.kick()
1087
+ });
1088
+ handlers.cleanStalePeers();
1089
+ const cleaner = setInterval(() => handlers.cleanStalePeers(), CLEAN_INTERVAL_MS);
1090
+ cleaner.unref();
1091
+ let port = cfg.port;
1092
+ const app = createBrokerApp({
1093
+ handlers,
1094
+ version: VERSION,
1095
+ id: cfg.id,
1096
+ port: () => port,
1097
+ token: cfg.token,
1098
+ fallback: cfg.fallback,
1099
+ mesh: cfg.mesh
1100
+ });
1101
+ let listener;
1102
+ try {
1103
+ listener = await listen(toNodeListener(app), {
1104
+ port: cfg.port,
1105
+ hostname: cfg.bind,
1106
+ showURL: false,
1107
+ autoClose: false,
1108
+ // `isProd` makes listhen fail on a busy port instead of silently picking another one.
1109
+ // For port 0 we need listhen's random-port path, which `isProd` would disable.
1110
+ isProd: cfg.port !== 0
1111
+ });
1112
+ } catch (e) {
1113
+ clearInterval(cleaner);
1114
+ throw e;
1115
+ }
1116
+ port = listener.address.port;
1117
+ const reply = () => ({ [DISCOVERY_KEY]: DISCOVERY_REPLY_VALUE, id: cfg.id, port, version: VERSION, ...cfg.fallback ? { fallback: true } : {} });
1118
+ let disco = null;
1119
+ if (cfg.discovery) {
1120
+ disco = await startDiscoveryResponder({ port: cfg.discoveryPort, addr: cfg.discoveryAddr, reply });
1121
+ }
1122
+ if (cfg.mesh) {
1123
+ const fixed = cfg.meshBrokers.map(normalizeBrokerUrl);
1124
+ mesh = new Mesh({
1125
+ id: cfg.id,
1126
+ token: cfg.token,
1127
+ handlers,
1128
+ urls: () => fixed.length ? fixed : readMeshBrokers(cfg.configFile),
1129
+ intervalMs: cfg.meshIntervalMs
1130
+ });
1131
+ mesh.start();
1132
+ }
1133
+ log.info(`v${VERSION} id=${cfg.id} listening on ${cfg.bind}:${port} (state: ${cfg.stateFile})`);
1134
+ if (cfg.fallback) log.info(`FALLBACK mode: looking for another broker every ${cfg.fallbackIntervalMs} ms (discovery ${cfg.discovery ? "on" : "off"})`);
1135
+ log.info(cfg.token ? "token auth enabled" : "WARNING: no AGENT_MESSENGER_TOKEN set \u2014 broker is open");
1136
+ let closed = false;
1137
+ let fallbackTimer = null;
1138
+ const close = async () => {
1139
+ if (closed) return;
1140
+ closed = true;
1141
+ clearInterval(cleaner);
1142
+ if (fallbackTimer) clearInterval(fallbackTimer);
1143
+ mesh?.stop();
1144
+ if (disco) {
1145
+ await new Promise((resolve) => disco.close(() => resolve()));
1146
+ }
1147
+ await listener.close();
1148
+ if (state.savePending) state.saveNow();
1149
+ };
1150
+ if (cfg.fallback && cfg.discovery) {
1151
+ const mine = localAddresses();
1152
+ let busy = false;
1153
+ const lookForBroker = async () => {
1154
+ if (busy || closed) return;
1155
+ busy = true;
1156
+ try {
1157
+ const found = await probeBrokers({ port: cfg.discoveryPort, addr: cfg.discoveryAddr, timeoutMs: 1e3 });
1158
+ const other = found.find((b) => !b.fallback && !(b.port === port && mine.has(b.host)));
1159
+ if (!other || closed) return;
1160
+ log.info(`fallback: found broker ${other.id} at ${other.url} \u2014 relaying messages and exiting`);
1161
+ await relayUndelivered(state, other.url, cfg.token);
1162
+ await close();
1163
+ log.info("fallback: done");
1164
+ onSupersede?.(other.url);
1165
+ } catch (e) {
1166
+ log.warn(`fallback: ${e.message} \u2014 will retry`);
1167
+ } finally {
1168
+ busy = false;
1169
+ }
1170
+ };
1171
+ fallbackTimer = setInterval(() => void lookForBroker(), cfg.fallbackIntervalMs);
1172
+ fallbackTimer.unref();
1173
+ }
1174
+ return { close, port, id: cfg.id };
1175
+ }
1176
+
1177
+ export { DEFAULT_STATE_FILE as D, FALLBACK_ENV as F, MESH_ENV as M, STATE_DIR as S, VERSION as V, FALLBACK_INTERVAL_ENV as a, configFromEnv as c, log as l, resolveConfig as r, startBroker as s };