@qvac/core 0.0.0 → 0.1.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 (586) hide show
  1. package/LICENSE.md +198 -0
  2. package/NOTICE.md +13 -0
  3. package/README.md +694 -0
  4. package/SECURITY.md +6 -0
  5. package/dist/assistant.bundle +47256 -0
  6. package/dist/assistant.cjs +18 -0
  7. package/dist/assistant.d.ts +8 -0
  8. package/dist/prebuilds-manifest.json +380 -0
  9. package/dist-lib/client.d.ts +2 -0
  10. package/dist-lib/client.js +1 -0
  11. package/dist-lib/index.d.ts +13 -0
  12. package/dist-lib/index.js +10 -0
  13. package/dist-lib/lib/agent-icons.d.ts +3 -0
  14. package/dist-lib/lib/agent-icons.js +1 -0
  15. package/dist-lib/lib/api/agents.d.ts +5 -0
  16. package/dist-lib/lib/api/agents.js +38 -0
  17. package/dist-lib/lib/api/app-config.d.ts +5 -0
  18. package/dist-lib/lib/api/app-config.js +108 -0
  19. package/dist-lib/lib/api/approval-rules.d.ts +3 -0
  20. package/dist-lib/lib/api/approval-rules.js +9 -0
  21. package/dist-lib/lib/api/attachments.d.ts +8 -0
  22. package/dist-lib/lib/api/attachments.js +15 -0
  23. package/dist-lib/lib/api/chat-groups.d.ts +5 -0
  24. package/dist-lib/lib/api/chat-groups.js +12 -0
  25. package/dist-lib/lib/api/chat.d.ts +5 -0
  26. package/dist-lib/lib/api/chat.js +38 -0
  27. package/dist-lib/lib/api/chunks.d.ts +5 -0
  28. package/dist-lib/lib/api/chunks.js +61 -0
  29. package/dist-lib/lib/api/config.d.ts +5 -0
  30. package/dist-lib/lib/api/config.js +15 -0
  31. package/dist-lib/lib/api/current-mesh.d.ts +5 -0
  32. package/dist-lib/lib/api/current-mesh.js +12 -0
  33. package/dist-lib/lib/api/custom-models.d.ts +5 -0
  34. package/dist-lib/lib/api/custom-models.js +45 -0
  35. package/dist-lib/lib/api/devices.d.ts +8 -0
  36. package/dist-lib/lib/api/devices.js +125 -0
  37. package/dist-lib/lib/api/diagnostics.d.ts +7 -0
  38. package/dist-lib/lib/api/diagnostics.js +7 -0
  39. package/dist-lib/lib/api/effective-ctx-size.d.ts +2 -0
  40. package/dist-lib/lib/api/effective-ctx-size.js +10 -0
  41. package/dist-lib/lib/api/execution.d.ts +3 -0
  42. package/dist-lib/lib/api/execution.js +45 -0
  43. package/dist-lib/lib/api/files.d.ts +3 -0
  44. package/dist-lib/lib/api/files.js +48 -0
  45. package/dist-lib/lib/api/index.d.ts +62 -0
  46. package/dist-lib/lib/api/index.js +172 -0
  47. package/dist-lib/lib/api/instrument.d.ts +2 -0
  48. package/dist-lib/lib/api/instrument.js +86 -0
  49. package/dist-lib/lib/api/knowledge.d.ts +8 -0
  50. package/dist-lib/lib/api/knowledge.js +26 -0
  51. package/dist-lib/lib/api/logs.d.ts +14 -0
  52. package/dist-lib/lib/api/logs.js +116 -0
  53. package/dist-lib/lib/api/mesh.d.ts +13 -0
  54. package/dist-lib/lib/api/mesh.js +25 -0
  55. package/dist-lib/lib/api/model-download.d.ts +5 -0
  56. package/dist-lib/lib/api/model-download.js +47 -0
  57. package/dist-lib/lib/api/network.d.ts +8 -0
  58. package/dist-lib/lib/api/network.js +6 -0
  59. package/dist-lib/lib/api/notifications.d.ts +21 -0
  60. package/dist-lib/lib/api/notifications.js +108 -0
  61. package/dist-lib/lib/api/rag.d.ts +7 -0
  62. package/dist-lib/lib/api/rag.js +216 -0
  63. package/dist-lib/lib/api/sync.d.ts +3 -0
  64. package/dist-lib/lib/api/sync.js +6 -0
  65. package/dist-lib/lib/api/tool-activity.d.ts +5 -0
  66. package/dist-lib/lib/api/tool-activity.js +53 -0
  67. package/dist-lib/lib/api/tool-configs.d.ts +6 -0
  68. package/dist-lib/lib/api/tool-configs.js +27 -0
  69. package/dist-lib/lib/api/watchable.d.ts +12 -0
  70. package/dist-lib/lib/api/watchable.js +121 -0
  71. package/dist-lib/lib/assistant-client.d.ts +21 -0
  72. package/dist-lib/lib/assistant-client.js +52 -0
  73. package/dist-lib/lib/assistant-tree.d.ts +50 -0
  74. package/dist-lib/lib/assistant-tree.js +184 -0
  75. package/dist-lib/lib/assistant.d.ts +425 -0
  76. package/dist-lib/lib/assistant.js +2706 -0
  77. package/dist-lib/lib/audio-format.d.ts +4 -0
  78. package/dist-lib/lib/audio-format.js +4 -0
  79. package/dist-lib/lib/chat-title.d.ts +5 -0
  80. package/dist-lib/lib/chat-title.js +58 -0
  81. package/dist-lib/lib/client.d.ts +25 -0
  82. package/dist-lib/lib/client.js +53 -0
  83. package/dist-lib/lib/collabora/convert.d.ts +9 -0
  84. package/dist-lib/lib/collabora/convert.js +62 -0
  85. package/dist-lib/lib/collabora/entry.d.ts +1 -0
  86. package/dist-lib/lib/collabora/entry.js +44 -0
  87. package/dist-lib/lib/collabora/protocol.d.ts +15 -0
  88. package/dist-lib/lib/collabora/protocol.js +24 -0
  89. package/dist-lib/lib/collabora/worker.d.ts +5 -0
  90. package/dist-lib/lib/collabora/worker.js +111 -0
  91. package/dist-lib/lib/compaction.d.ts +30 -0
  92. package/dist-lib/lib/compaction.js +95 -0
  93. package/dist-lib/lib/constants.d.ts +4 -0
  94. package/dist-lib/lib/constants.js +4 -0
  95. package/dist-lib/lib/core/agent.d.ts +15 -0
  96. package/dist-lib/lib/core/agent.js +149 -0
  97. package/dist-lib/lib/core/app-build.d.ts +7 -0
  98. package/dist-lib/lib/core/app-build.js +1 -0
  99. package/dist-lib/lib/core/approval-rules.d.ts +15 -0
  100. package/dist-lib/lib/core/approval-rules.js +41 -0
  101. package/dist-lib/lib/core/async-iterable.d.ts +13 -0
  102. package/dist-lib/lib/core/async-iterable.js +65 -0
  103. package/dist-lib/lib/core/attachment-link.d.ts +7 -0
  104. package/dist-lib/lib/core/attachment-link.js +6 -0
  105. package/dist-lib/lib/core/audio-attachment.d.ts +1 -0
  106. package/dist-lib/lib/core/audio-attachment.js +4 -0
  107. package/dist-lib/lib/core/blind-peers.d.ts +6 -0
  108. package/dist-lib/lib/core/blind-peers.js +13 -0
  109. package/dist-lib/lib/core/chat-activity.d.ts +7 -0
  110. package/dist-lib/lib/core/chat-activity.js +244 -0
  111. package/dist-lib/lib/core/chat-group.d.ts +14 -0
  112. package/dist-lib/lib/core/chat-group.js +79 -0
  113. package/dist-lib/lib/core/chat-search.d.ts +17 -0
  114. package/dist-lib/lib/core/chat-search.js +199 -0
  115. package/dist-lib/lib/core/chat.d.ts +37 -0
  116. package/dist-lib/lib/core/chat.js +196 -0
  117. package/dist-lib/lib/core/chunk.d.ts +61 -0
  118. package/dist-lib/lib/core/chunk.js +212 -0
  119. package/dist-lib/lib/core/contract/activity.d.ts +11 -0
  120. package/dist-lib/lib/core/contract/activity.js +45 -0
  121. package/dist-lib/lib/core/contract/agents.d.ts +2 -0
  122. package/dist-lib/lib/core/contract/agents.js +29 -0
  123. package/dist-lib/lib/core/contract/approval-rules.d.ts +2 -0
  124. package/dist-lib/lib/core/contract/approval-rules.js +14 -0
  125. package/dist-lib/lib/core/contract/attestations.d.ts +2 -0
  126. package/dist-lib/lib/core/contract/attestations.js +14 -0
  127. package/dist-lib/lib/core/contract/chat-group.d.ts +2 -0
  128. package/dist-lib/lib/core/contract/chat-group.js +20 -0
  129. package/dist-lib/lib/core/contract/chat.d.ts +2 -0
  130. package/dist-lib/lib/core/contract/chat.js +18 -0
  131. package/dist-lib/lib/core/contract/chunks.d.ts +2 -0
  132. package/dist-lib/lib/core/contract/chunks.js +156 -0
  133. package/dist-lib/lib/core/contract/devices.d.ts +2 -0
  134. package/dist-lib/lib/core/contract/devices.js +110 -0
  135. package/dist-lib/lib/core/contract/index.d.ts +2 -0
  136. package/dist-lib/lib/core/contract/index.js +30 -0
  137. package/dist-lib/lib/core/contract/indexing.d.ts +4 -0
  138. package/dist-lib/lib/core/contract/indexing.js +82 -0
  139. package/dist-lib/lib/core/contract/knowledge.d.ts +2 -0
  140. package/dist-lib/lib/core/contract/knowledge.js +55 -0
  141. package/dist-lib/lib/core/contract/members.d.ts +2 -0
  142. package/dist-lib/lib/core/contract/members.js +96 -0
  143. package/dist-lib/lib/core/contract/seed-defaults.d.ts +2 -0
  144. package/dist-lib/lib/core/contract/seed-defaults.js +29 -0
  145. package/dist-lib/lib/core/contract/tool-activity.d.ts +2 -0
  146. package/dist-lib/lib/core/contract/tool-activity.js +25 -0
  147. package/dist-lib/lib/core/contract/tool-configs.d.ts +2 -0
  148. package/dist-lib/lib/core/contract/tool-configs.js +50 -0
  149. package/dist-lib/lib/core/contract/types.d.ts +11 -0
  150. package/dist-lib/lib/core/contract/types.js +1 -0
  151. package/dist-lib/lib/core/contract/writers.d.ts +2 -0
  152. package/dist-lib/lib/core/contract/writers.js +112 -0
  153. package/dist-lib/lib/core/cpu-info-node.d.ts +3 -0
  154. package/dist-lib/lib/core/cpu-info-node.js +2 -0
  155. package/dist-lib/lib/core/departures.d.ts +41 -0
  156. package/dist-lib/lib/core/departures.js +145 -0
  157. package/dist-lib/lib/core/device-attestation.d.ts +6 -0
  158. package/dist-lib/lib/core/device-attestation.js +12 -0
  159. package/dist-lib/lib/core/devices.d.ts +14 -0
  160. package/dist-lib/lib/core/devices.js +11 -0
  161. package/dist-lib/lib/core/document-attachment.d.ts +22 -0
  162. package/dist-lib/lib/core/document-attachment.js +35 -0
  163. package/dist-lib/lib/core/files/attachments.d.ts +8 -0
  164. package/dist-lib/lib/core/files/attachments.js +50 -0
  165. package/dist-lib/lib/core/files/index.d.ts +133 -0
  166. package/dist-lib/lib/core/files/index.js +585 -0
  167. package/dist-lib/lib/core/files/knowledge.d.ts +9 -0
  168. package/dist-lib/lib/core/files/knowledge.js +31 -0
  169. package/dist-lib/lib/core/files/preview/image.d.ts +4 -0
  170. package/dist-lib/lib/core/files/preview/image.js +42 -0
  171. package/dist-lib/lib/core/files/preview/index.d.ts +33 -0
  172. package/dist-lib/lib/core/files/preview/index.js +161 -0
  173. package/dist-lib/lib/core/files/processing/claims.d.ts +26 -0
  174. package/dist-lib/lib/core/files/processing/claims.js +89 -0
  175. package/dist-lib/lib/core/files/processing/document.d.ts +100 -0
  176. package/dist-lib/lib/core/files/processing/document.js +101 -0
  177. package/dist-lib/lib/core/files/processing/index.d.ts +75 -0
  178. package/dist-lib/lib/core/files/processing/index.js +295 -0
  179. package/dist-lib/lib/core/files/processing/ownership.d.ts +11 -0
  180. package/dist-lib/lib/core/files/processing/ownership.js +41 -0
  181. package/dist-lib/lib/core/files/processing/protocol.d.ts +29 -0
  182. package/dist-lib/lib/core/files/processing/protocol.js +70 -0
  183. package/dist-lib/lib/core/files/processing/settle.d.ts +10 -0
  184. package/dist-lib/lib/core/files/processing/settle.js +75 -0
  185. package/dist-lib/lib/core/files/processing/source.d.ts +36 -0
  186. package/dist-lib/lib/core/files/processing/source.js +96 -0
  187. package/dist-lib/lib/core/files/processing/state.d.ts +64 -0
  188. package/dist-lib/lib/core/files/processing/state.js +118 -0
  189. package/dist-lib/lib/core/files/rag/artifact/codec.d.ts +3 -0
  190. package/dist-lib/lib/core/files/rag/artifact/codec.js +172 -0
  191. package/dist-lib/lib/core/files/rag/artifact/id.d.ts +10 -0
  192. package/dist-lib/lib/core/files/rag/artifact/id.js +39 -0
  193. package/dist-lib/lib/core/files/rag/artifact/types.d.ts +24 -0
  194. package/dist-lib/lib/core/files/rag/artifact/types.js +41 -0
  195. package/dist-lib/lib/core/files/rag/build.d.ts +25 -0
  196. package/dist-lib/lib/core/files/rag/build.js +60 -0
  197. package/dist-lib/lib/core/files/rag/chunk/chunking.d.ts +12 -0
  198. package/dist-lib/lib/core/files/rag/chunk/chunking.js +117 -0
  199. package/dist-lib/lib/core/files/rag/chunk/metadata.d.ts +30 -0
  200. package/dist-lib/lib/core/files/rag/chunk/metadata.js +89 -0
  201. package/dist-lib/lib/core/files/rag/chunk/tokenizer.d.ts +7 -0
  202. package/dist-lib/lib/core/files/rag/chunk/tokenizer.js +18 -0
  203. package/dist-lib/lib/core/files/rag/document-types.d.ts +11 -0
  204. package/dist-lib/lib/core/files/rag/document-types.js +94 -0
  205. package/dist-lib/lib/core/files/rag/extract/csv-text.d.ts +1 -0
  206. package/dist-lib/lib/core/files/rag/extract/csv-text.js +117 -0
  207. package/dist-lib/lib/core/files/rag/extract/document-types.d.ts +22 -0
  208. package/dist-lib/lib/core/files/rag/extract/document-types.js +152 -0
  209. package/dist-lib/lib/core/files/rag/extract/extract.d.ts +17 -0
  210. package/dist-lib/lib/core/files/rag/extract/extract.js +81 -0
  211. package/dist-lib/lib/core/files/rag/extract/html-table-text.d.ts +1 -0
  212. package/dist-lib/lib/core/files/rag/extract/html-table-text.js +125 -0
  213. package/dist-lib/lib/core/files/rag/extract/html-text.d.ts +1 -0
  214. package/dist-lib/lib/core/files/rag/extract/html-text.js +132 -0
  215. package/dist-lib/lib/core/files/rag/extract/office-collabora.d.ts +2 -0
  216. package/dist-lib/lib/core/files/rag/extract/office-collabora.js +8 -0
  217. package/dist-lib/lib/core/files/rag/extract/pdf-platform.d.ts +17 -0
  218. package/dist-lib/lib/core/files/rag/extract/pdf-platform.js +141 -0
  219. package/dist-lib/lib/core/files/rag/extract/pdf-text.d.ts +12 -0
  220. package/dist-lib/lib/core/files/rag/extract/pdf-text.js +43 -0
  221. package/dist-lib/lib/core/files/rag/extract/rtf-text.d.ts +1 -0
  222. package/dist-lib/lib/core/files/rag/extract/rtf-text.js +15 -0
  223. package/dist-lib/lib/core/files/rag/extract/text-decoding.d.ts +1 -0
  224. package/dist-lib/lib/core/files/rag/extract/text-decoding.js +91 -0
  225. package/dist-lib/lib/core/files/rag/extract/types.d.ts +36 -0
  226. package/dist-lib/lib/core/files/rag/extract/types.js +12 -0
  227. package/dist-lib/lib/core/files/rag/extract/utf.d.ts +2 -0
  228. package/dist-lib/lib/core/files/rag/extract/utf.js +18 -0
  229. package/dist-lib/lib/core/files/rag/index.d.ts +54 -0
  230. package/dist-lib/lib/core/files/rag/index.js +79 -0
  231. package/dist-lib/lib/core/files/rag/limits.d.ts +2 -0
  232. package/dist-lib/lib/core/files/rag/limits.js +2 -0
  233. package/dist-lib/lib/core/files/rag/load.d.ts +28 -0
  234. package/dist-lib/lib/core/files/rag/load.js +250 -0
  235. package/dist-lib/lib/core/files/rag/models.d.ts +1 -0
  236. package/dist-lib/lib/core/files/rag/models.js +1 -0
  237. package/dist-lib/lib/core/files/rag/policy.d.ts +2 -0
  238. package/dist-lib/lib/core/files/rag/policy.js +23 -0
  239. package/dist-lib/lib/core/files/rag/produce.d.ts +21 -0
  240. package/dist-lib/lib/core/files/rag/produce.js +214 -0
  241. package/dist-lib/lib/core/files/rag/retrieval/citation-match.d.ts +2 -0
  242. package/dist-lib/lib/core/files/rag/retrieval/citation-match.js +16 -0
  243. package/dist-lib/lib/core/files/rag/retrieval/coverage.d.ts +4 -0
  244. package/dist-lib/lib/core/files/rag/retrieval/coverage.js +48 -0
  245. package/dist-lib/lib/core/files/rag/retrieval/diversity.d.ts +10 -0
  246. package/dist-lib/lib/core/files/rag/retrieval/diversity.js +37 -0
  247. package/dist-lib/lib/core/files/rag/retrieval/floor.d.ts +5 -0
  248. package/dist-lib/lib/core/files/rag/retrieval/floor.js +21 -0
  249. package/dist-lib/lib/core/files/rag/retrieval/format.d.ts +6 -0
  250. package/dist-lib/lib/core/files/rag/retrieval/format.js +21 -0
  251. package/dist-lib/lib/core/files/rag/retrieval/full-text.d.ts +22 -0
  252. package/dist-lib/lib/core/files/rag/retrieval/full-text.js +137 -0
  253. package/dist-lib/lib/core/files/rag/retrieval/knowledge.d.ts +2 -0
  254. package/dist-lib/lib/core/files/rag/retrieval/knowledge.js +53 -0
  255. package/dist-lib/lib/core/files/rag/retrieval/notices.d.ts +16 -0
  256. package/dist-lib/lib/core/files/rag/retrieval/notices.js +27 -0
  257. package/dist-lib/lib/core/files/rag/retrieval/scoring.d.ts +8 -0
  258. package/dist-lib/lib/core/files/rag/retrieval/scoring.js +82 -0
  259. package/dist-lib/lib/core/files/rag/retrieval/search.d.ts +3 -0
  260. package/dist-lib/lib/core/files/rag/retrieval/search.js +46 -0
  261. package/dist-lib/lib/core/files/rag/retrieval/selection.d.ts +10 -0
  262. package/dist-lib/lib/core/files/rag/retrieval/selection.js +63 -0
  263. package/dist-lib/lib/core/files/rag/retrieval/source-tag-filter.d.ts +6 -0
  264. package/dist-lib/lib/core/files/rag/retrieval/source-tag-filter.js +79 -0
  265. package/dist-lib/lib/core/files/rag/retrieval/sources.d.ts +13 -0
  266. package/dist-lib/lib/core/files/rag/retrieval/sources.js +20 -0
  267. package/dist-lib/lib/core/files/rag/retrieval/target.d.ts +13 -0
  268. package/dist-lib/lib/core/files/rag/retrieval/target.js +89 -0
  269. package/dist-lib/lib/core/files/rag/retrieval/terms.d.ts +8 -0
  270. package/dist-lib/lib/core/files/rag/retrieval/terms.js +70 -0
  271. package/dist-lib/lib/core/files/rag/retrieval/types.d.ts +28 -0
  272. package/dist-lib/lib/core/files/rag/retrieval/types.js +1 -0
  273. package/dist-lib/lib/core/files/rag/retrieval/web-sources.d.ts +8 -0
  274. package/dist-lib/lib/core/files/rag/retrieval/web-sources.js +41 -0
  275. package/dist-lib/lib/core/files/rag/retrieval/whole-document-query.d.ts +1 -0
  276. package/dist-lib/lib/core/files/rag/retrieval/whole-document-query.js +96 -0
  277. package/dist-lib/lib/core/files/rag/vector/memory.d.ts +15 -0
  278. package/dist-lib/lib/core/files/rag/vector/memory.js +135 -0
  279. package/dist-lib/lib/core/files/rag/vector/types.d.ts +28 -0
  280. package/dist-lib/lib/core/files/rag/vector/types.js +1 -0
  281. package/dist-lib/lib/core/files/records/chunks.d.ts +3 -0
  282. package/dist-lib/lib/core/files/records/chunks.js +12 -0
  283. package/dist-lib/lib/core/files/records/index.d.ts +10 -0
  284. package/dist-lib/lib/core/files/records/index.js +8 -0
  285. package/dist-lib/lib/core/files/records/knowledge.d.ts +22 -0
  286. package/dist-lib/lib/core/files/records/knowledge.js +105 -0
  287. package/dist-lib/lib/core/files/records/linkage.d.ts +11 -0
  288. package/dist-lib/lib/core/files/records/linkage.js +27 -0
  289. package/dist-lib/lib/core/files/records/output.d.ts +8 -0
  290. package/dist-lib/lib/core/files/records/output.js +38 -0
  291. package/dist-lib/lib/core/files/records/reclaim.d.ts +5 -0
  292. package/dist-lib/lib/core/files/records/reclaim.js +73 -0
  293. package/dist-lib/lib/core/files/records/routing.d.ts +23 -0
  294. package/dist-lib/lib/core/files/records/routing.js +62 -0
  295. package/dist-lib/lib/core/files/records/source.d.ts +16 -0
  296. package/dist-lib/lib/core/files/records/source.js +70 -0
  297. package/dist-lib/lib/core/files/records/sweep.d.ts +2 -0
  298. package/dist-lib/lib/core/files/records/sweep.js +30 -0
  299. package/dist-lib/lib/core/files/store/blob.d.ts +29 -0
  300. package/dist-lib/lib/core/files/store/blob.js +98 -0
  301. package/dist-lib/lib/core/files/store/index.d.ts +36 -0
  302. package/dist-lib/lib/core/files/store/index.js +89 -0
  303. package/dist-lib/lib/core/files/store/inline.d.ts +8 -0
  304. package/dist-lib/lib/core/files/store/inline.js +38 -0
  305. package/dist-lib/lib/core/files/store/reference.d.ts +27 -0
  306. package/dist-lib/lib/core/files/store/reference.js +168 -0
  307. package/dist-lib/lib/core/files/store/server.d.ts +27 -0
  308. package/dist-lib/lib/core/files/store/server.js +114 -0
  309. package/dist-lib/lib/core/files/store/sweep.d.ts +2 -0
  310. package/dist-lib/lib/core/files/store/sweep.js +45 -0
  311. package/dist-lib/lib/core/files/upload-input.d.ts +27 -0
  312. package/dist-lib/lib/core/files/upload-input.js +52 -0
  313. package/dist-lib/lib/core/files/upload.d.ts +32 -0
  314. package/dist-lib/lib/core/files/upload.js +201 -0
  315. package/dist-lib/lib/core/fs-drives.d.ts +18 -0
  316. package/dist-lib/lib/core/fs-drives.js +58 -0
  317. package/dist-lib/lib/core/gpu-info-node.d.ts +3 -0
  318. package/dist-lib/lib/core/gpu-info-node.js +2 -0
  319. package/dist-lib/lib/core/handoff-channel.d.ts +46 -0
  320. package/dist-lib/lib/core/handoff-channel.js +102 -0
  321. package/dist-lib/lib/core/health-assistant.d.ts +7 -0
  322. package/dist-lib/lib/core/health-assistant.js +24 -0
  323. package/dist-lib/lib/core/helpers/index.d.ts +5 -0
  324. package/dist-lib/lib/core/helpers/index.js +74 -0
  325. package/dist-lib/lib/core/hosted-agents.d.ts +36 -0
  326. package/dist-lib/lib/core/hosted-agents.js +127 -0
  327. package/dist-lib/lib/core/id.d.ts +1 -0
  328. package/dist-lib/lib/core/id.js +5 -0
  329. package/dist-lib/lib/core/identity.d.ts +14 -0
  330. package/dist-lib/lib/core/identity.js +45 -0
  331. package/dist-lib/lib/core/image/cache-sweep.d.ts +12 -0
  332. package/dist-lib/lib/core/image/cache-sweep.js +67 -0
  333. package/dist-lib/lib/core/image/normalize.d.ts +3 -0
  334. package/dist-lib/lib/core/image/normalize.js +49 -0
  335. package/dist-lib/lib/core/image/sniff.d.ts +3 -0
  336. package/dist-lib/lib/core/image/sniff.js +149 -0
  337. package/dist-lib/lib/core/invite.d.ts +14 -0
  338. package/dist-lib/lib/core/invite.js +36 -0
  339. package/dist-lib/lib/core/local/index.d.ts +71 -0
  340. package/dist-lib/lib/core/local/index.js +391 -0
  341. package/dist-lib/lib/core/membership.d.ts +15 -0
  342. package/dist-lib/lib/core/membership.js +40 -0
  343. package/dist-lib/lib/core/mesh.d.ts +153 -0
  344. package/dist-lib/lib/core/mesh.js +509 -0
  345. package/dist-lib/lib/core/migrations/agent-catalog.d.ts +6 -0
  346. package/dist-lib/lib/core/migrations/agent-catalog.js +17 -0
  347. package/dist-lib/lib/core/migrations/index.d.ts +5 -0
  348. package/dist-lib/lib/core/migrations/index.js +7 -0
  349. package/dist-lib/lib/core/migrations/membership.d.ts +11 -0
  350. package/dist-lib/lib/core/migrations/membership.js +26 -0
  351. package/dist-lib/lib/core/min-version.d.ts +6 -0
  352. package/dist-lib/lib/core/min-version.js +31 -0
  353. package/dist-lib/lib/core/next-frame.d.ts +6 -0
  354. package/dist-lib/lib/core/next-frame.js +27 -0
  355. package/dist-lib/lib/core/notification.d.ts +6 -0
  356. package/dist-lib/lib/core/notification.js +162 -0
  357. package/dist-lib/lib/core/ota-config.d.ts +19 -0
  358. package/dist-lib/lib/core/ota-config.js +44 -0
  359. package/dist-lib/lib/core/prompt-history.d.ts +12 -0
  360. package/dist-lib/lib/core/prompt-history.js +40 -0
  361. package/dist-lib/lib/core/search-fold.d.ts +1 -0
  362. package/dist-lib/lib/core/search-fold.js +4 -0
  363. package/dist-lib/lib/core/secret-handoff.d.ts +17 -0
  364. package/dist-lib/lib/core/secret-handoff.js +29 -0
  365. package/dist-lib/lib/core/send.d.ts +18 -0
  366. package/dist-lib/lib/core/send.js +46 -0
  367. package/dist-lib/lib/core/skill-overlay-handoff.d.ts +25 -0
  368. package/dist-lib/lib/core/skill-overlay-handoff.js +50 -0
  369. package/dist-lib/lib/core/skill-overlay-receiver.d.ts +8 -0
  370. package/dist-lib/lib/core/skill-overlay-receiver.js +20 -0
  371. package/dist-lib/lib/core/skill-secrets.d.ts +25 -0
  372. package/dist-lib/lib/core/skill-secrets.js +79 -0
  373. package/dist-lib/lib/core/sync/chats.d.ts +3 -0
  374. package/dist-lib/lib/core/sync/chats.js +5 -0
  375. package/dist-lib/lib/core/sync/chunks.d.ts +9 -0
  376. package/dist-lib/lib/core/sync/chunks.js +16 -0
  377. package/dist-lib/lib/core/sync/devices.d.ts +4 -0
  378. package/dist-lib/lib/core/sync/devices.js +12 -0
  379. package/dist-lib/lib/core/sync/files.d.ts +16 -0
  380. package/dist-lib/lib/core/sync/files.js +109 -0
  381. package/dist-lib/lib/core/sync/index.d.ts +5 -0
  382. package/dist-lib/lib/core/sync/index.js +63 -0
  383. package/dist-lib/lib/core/sync-status.d.ts +17 -0
  384. package/dist-lib/lib/core/sync-status.js +129 -0
  385. package/dist-lib/lib/core/system-info.d.ts +24 -0
  386. package/dist-lib/lib/core/system-info.js +66 -0
  387. package/dist-lib/lib/core/tool-activity.d.ts +22 -0
  388. package/dist-lib/lib/core/tool-activity.js +39 -0
  389. package/dist-lib/lib/core/tool-configs.d.ts +13 -0
  390. package/dist-lib/lib/core/tool-configs.js +141 -0
  391. package/dist-lib/lib/core.d.ts +291 -0
  392. package/dist-lib/lib/core.js +2126 -0
  393. package/dist-lib/lib/credential-pusher.d.ts +67 -0
  394. package/dist-lib/lib/credential-pusher.js +290 -0
  395. package/dist-lib/lib/custom-model-pusher.d.ts +9 -0
  396. package/dist-lib/lib/custom-model-pusher.js +42 -0
  397. package/dist-lib/lib/custom-model-source.d.ts +15 -0
  398. package/dist-lib/lib/custom-model-source.js +46 -0
  399. package/dist-lib/lib/deadline.d.ts +9 -0
  400. package/dist-lib/lib/deadline.js +31 -0
  401. package/dist-lib/lib/diagnostics.d.ts +35 -0
  402. package/dist-lib/lib/diagnostics.js +14 -0
  403. package/dist-lib/lib/fetch-node.d.ts +1 -0
  404. package/dist-lib/lib/fetch-node.js +1 -0
  405. package/dist-lib/lib/fs-drive-bridge.d.ts +12 -0
  406. package/dist-lib/lib/fs-drive-bridge.js +186 -0
  407. package/dist-lib/lib/fs-grant-keys.d.ts +2 -0
  408. package/dist-lib/lib/fs-grant-keys.js +6 -0
  409. package/dist-lib/lib/fs-grants.d.ts +10 -0
  410. package/dist-lib/lib/fs-grants.js +44 -0
  411. package/dist-lib/lib/image-cache-dir.d.ts +1 -0
  412. package/dist-lib/lib/image-cache-dir.js +5 -0
  413. package/dist-lib/lib/integrations/index.d.ts +4 -0
  414. package/dist-lib/lib/integrations/index.js +3 -0
  415. package/dist-lib/lib/integrations/mcp-providers.d.ts +12 -0
  416. package/dist-lib/lib/integrations/mcp-providers.js +22 -0
  417. package/dist-lib/lib/integrations/oauth-providers.d.ts +14 -0
  418. package/dist-lib/lib/integrations/oauth-providers.js +116 -0
  419. package/dist-lib/lib/integrations/setup-routes.d.ts +12 -0
  420. package/dist-lib/lib/integrations/setup-routes.js +114 -0
  421. package/dist-lib/lib/knowledge-search.d.ts +7 -0
  422. package/dist-lib/lib/knowledge-search.js +53 -0
  423. package/dist-lib/lib/kv-cache-reclaim.d.ts +5 -0
  424. package/dist-lib/lib/kv-cache-reclaim.js +29 -0
  425. package/dist-lib/lib/kv-cache.d.ts +18 -0
  426. package/dist-lib/lib/kv-cache.js +33 -0
  427. package/dist-lib/lib/legacy-core-domain.d.ts +258 -0
  428. package/dist-lib/lib/legacy-core-domain.js +1 -0
  429. package/dist-lib/lib/llm-model-names.d.ts +1 -0
  430. package/dist-lib/lib/llm-model-names.js +1 -0
  431. package/dist-lib/lib/log-buffer.d.ts +7 -0
  432. package/dist-lib/lib/log-buffer.js +16 -0
  433. package/dist-lib/lib/log-levels.d.ts +7 -0
  434. package/dist-lib/lib/log-levels.js +1 -0
  435. package/dist-lib/lib/log.d.ts +60 -0
  436. package/dist-lib/lib/log.js +149 -0
  437. package/dist-lib/lib/logger-type.d.ts +13 -0
  438. package/dist-lib/lib/logger-type.js +1 -0
  439. package/dist-lib/lib/logger.d.ts +5 -0
  440. package/dist-lib/lib/logger.js +18 -0
  441. package/dist-lib/lib/model-catalog-revision.d.ts +9 -0
  442. package/dist-lib/lib/model-catalog-revision.js +65 -0
  443. package/dist-lib/lib/model-clamp.d.ts +6 -0
  444. package/dist-lib/lib/model-clamp.js +20 -0
  445. package/dist-lib/lib/model-context.d.ts +13 -0
  446. package/dist-lib/lib/model-context.js +71 -0
  447. package/dist-lib/lib/model-download-status.d.ts +29 -0
  448. package/dist-lib/lib/model-download-status.js +56 -0
  449. package/dist-lib/lib/model-download.d.ts +191 -0
  450. package/dist-lib/lib/model-download.js +787 -0
  451. package/dist-lib/lib/oauth/asana.d.ts +35 -0
  452. package/dist-lib/lib/oauth/asana.js +71 -0
  453. package/dist-lib/lib/oauth/browser-connect.d.ts +22 -0
  454. package/dist-lib/lib/oauth/browser-connect.js +83 -0
  455. package/dist-lib/lib/oauth/client.d.ts +9 -0
  456. package/dist-lib/lib/oauth/client.js +9 -0
  457. package/dist-lib/lib/oauth/common.d.ts +38 -0
  458. package/dist-lib/lib/oauth/common.js +36 -0
  459. package/dist-lib/lib/oauth/crypto.d.ts +3 -0
  460. package/dist-lib/lib/oauth/crypto.js +25 -0
  461. package/dist-lib/lib/oauth/fetch-platform.d.ts +1 -0
  462. package/dist-lib/lib/oauth/fetch-platform.js +1 -0
  463. package/dist-lib/lib/oauth/flow-core.d.ts +6 -0
  464. package/dist-lib/lib/oauth/flow-core.js +37 -0
  465. package/dist-lib/lib/oauth/flow.d.ts +3 -0
  466. package/dist-lib/lib/oauth/flow.js +24 -0
  467. package/dist-lib/lib/oauth/google.d.ts +37 -0
  468. package/dist-lib/lib/oauth/google.js +77 -0
  469. package/dist-lib/lib/oauth/host.d.ts +5 -0
  470. package/dist-lib/lib/oauth/host.js +3 -0
  471. package/dist-lib/lib/oauth/keys.d.ts +25 -0
  472. package/dist-lib/lib/oauth/keys.js +93 -0
  473. package/dist-lib/lib/oauth/loopback.d.ts +3 -0
  474. package/dist-lib/lib/oauth/loopback.js +119 -0
  475. package/dist-lib/lib/oauth/loopback.stub.d.ts +3 -0
  476. package/dist-lib/lib/oauth/loopback.stub.js +6 -0
  477. package/dist-lib/lib/oauth/notion.d.ts +34 -0
  478. package/dist-lib/lib/oauth/notion.js +82 -0
  479. package/dist-lib/lib/oauth/pkce-runtime.d.ts +3 -0
  480. package/dist-lib/lib/oauth/pkce-runtime.js +5 -0
  481. package/dist-lib/lib/oauth/pkce.d.ts +8 -0
  482. package/dist-lib/lib/oauth/pkce.js +6 -0
  483. package/dist-lib/lib/oauth/providers.d.ts +5 -0
  484. package/dist-lib/lib/oauth/providers.js +73 -0
  485. package/dist-lib/lib/oauth/redirect-types.d.ts +19 -0
  486. package/dist-lib/lib/oauth/redirect-types.js +1 -0
  487. package/dist-lib/lib/oauth/register.d.ts +3 -0
  488. package/dist-lib/lib/oauth/register.js +34 -0
  489. package/dist-lib/lib/oauth/resolve.d.ts +17 -0
  490. package/dist-lib/lib/oauth/resolve.js +57 -0
  491. package/dist-lib/lib/oauth/spotify.d.ts +32 -0
  492. package/dist-lib/lib/oauth/spotify.js +73 -0
  493. package/dist-lib/lib/oauth/token-exchange-core.d.ts +6 -0
  494. package/dist-lib/lib/oauth/token-exchange-core.js +97 -0
  495. package/dist-lib/lib/oauth/token-exchange.d.ts +5 -0
  496. package/dist-lib/lib/oauth/token-exchange.js +9 -0
  497. package/dist-lib/lib/oauth/types.d.ts +54 -0
  498. package/dist-lib/lib/oauth/types.js +1 -0
  499. package/dist-lib/lib/oauth.client.d.ts +5 -0
  500. package/dist-lib/lib/oauth.client.js +2 -0
  501. package/dist-lib/lib/oauth.d.ts +14 -0
  502. package/dist-lib/lib/oauth.js +12 -0
  503. package/dist-lib/lib/obsidian-key.d.ts +1 -0
  504. package/dist-lib/lib/obsidian-key.js +1 -0
  505. package/dist-lib/lib/race-resource.d.ts +5 -0
  506. package/dist-lib/lib/race-resource.js +25 -0
  507. package/dist-lib/lib/reconnecting-watch.d.ts +2 -0
  508. package/dist-lib/lib/reconnecting-watch.js +78 -0
  509. package/dist-lib/lib/retry-budget.d.ts +14 -0
  510. package/dist-lib/lib/retry-budget.js +39 -0
  511. package/dist-lib/lib/run-notices.d.ts +23 -0
  512. package/dist-lib/lib/run-notices.js +33 -0
  513. package/dist-lib/lib/run-transcript.d.ts +35 -0
  514. package/dist-lib/lib/run-transcript.js +106 -0
  515. package/dist-lib/lib/skill-readiness.d.ts +2 -0
  516. package/dist-lib/lib/skill-readiness.js +21 -0
  517. package/dist-lib/lib/skill-types.d.ts +70 -0
  518. package/dist-lib/lib/skill-types.js +1 -0
  519. package/dist-lib/lib/spec-loader.d.ts +14 -0
  520. package/dist-lib/lib/spec-loader.js +9 -0
  521. package/dist-lib/lib/suspend-lifecycle.d.ts +17 -0
  522. package/dist-lib/lib/suspend-lifecycle.js +33 -0
  523. package/dist-lib/lib/task.d.ts +26 -0
  524. package/dist-lib/lib/task.js +69 -0
  525. package/dist-lib/lib/unref.d.ts +3 -0
  526. package/dist-lib/lib/unref.js +4 -0
  527. package/dist-lib/lib/wav-duration.d.ts +1 -0
  528. package/dist-lib/lib/wav-duration.js +53 -0
  529. package/dist-lib/lib/write-queue.d.ts +22 -0
  530. package/dist-lib/lib/write-queue.js +39 -0
  531. package/dist-lib/schema/build.d.ts +1 -0
  532. package/dist-lib/schema/build.js +120 -0
  533. package/dist-lib/schema/config.d.ts +4 -0
  534. package/dist-lib/schema/config.js +7 -0
  535. package/dist-lib/schema/content.d.ts +20 -0
  536. package/dist-lib/schema/content.js +122 -0
  537. package/dist-lib/schema/engine.d.ts +2 -0
  538. package/dist-lib/schema/engine.js +2013 -0
  539. package/dist-lib/schema/field-order.d.ts +1 -0
  540. package/dist-lib/schema/field-order.js +95 -0
  541. package/dist-lib/schema/local.d.ts +2 -0
  542. package/dist-lib/schema/local.js +133 -0
  543. package/dist-lib/schema/qvac.d.ts +22 -0
  544. package/dist-lib/schema/qvac.js +722 -0
  545. package/dist-lib/spec/bind.d.ts +2 -0
  546. package/dist-lib/spec/bind.js +520 -0
  547. package/dist-lib/spec/calls.d.ts +3 -0
  548. package/dist-lib/spec/calls.js +129 -0
  549. package/dist-lib/spec/capabilities.d.ts +263 -0
  550. package/dist-lib/spec/config/hyperconf/index.d.ts +15 -0
  551. package/dist-lib/spec/config/hyperconf/index.js +24 -0
  552. package/dist-lib/spec/config/hyperconf/package.json +3 -0
  553. package/dist-lib/spec/config/hyperschema/index.js +81 -0
  554. package/dist-lib/spec/config/hyperschema/schema.json +19 -0
  555. package/dist-lib/spec/hrpc/hrpc.json +1500 -0
  556. package/dist-lib/spec/hrpc/index.d.ts +3 -0
  557. package/dist-lib/spec/hrpc/index.js +1545 -0
  558. package/dist-lib/spec/hrpc/messages.d.ts +4 -0
  559. package/dist-lib/spec/hrpc/messages.js +8373 -0
  560. package/dist-lib/spec/hyperschema/index.d.ts +20 -0
  561. package/dist-lib/spec/hyperschema/index.js +8373 -0
  562. package/dist-lib/spec/hyperschema/schema.json +6202 -0
  563. package/dist-lib/spec/hyperschema/types.d.ts +1545 -0
  564. package/dist-lib/spec/index.d.ts +36 -0
  565. package/dist-lib/spec/index.js +6 -0
  566. package/dist-lib/spec/local/hyperdb/db.json +186 -0
  567. package/dist-lib/spec/local/hyperdb/index.d.ts +9 -0
  568. package/dist-lib/spec/local/hyperdb/index.js +855 -0
  569. package/dist-lib/spec/local/hyperdb/messages.js +2189 -0
  570. package/dist-lib/spec/local/hyperschema/index.js +1208 -0
  571. package/dist-lib/spec/local/hyperschema/schema.json +639 -0
  572. package/dist-lib/spec/local/hyperschema/types.d.ts +159 -0
  573. package/dist-lib/spec/mesh/hyperdb/db.json +702 -0
  574. package/dist-lib/spec/mesh/hyperdb/index.d.ts +9 -0
  575. package/dist-lib/spec/mesh/hyperdb/index.js +2260 -0
  576. package/dist-lib/spec/mesh/hyperdb/messages.js +7453 -0
  577. package/dist-lib/spec/mesh/hyperdispatch/dispatch.json +174 -0
  578. package/dist-lib/spec/mesh/hyperdispatch/index.d.ts +13 -0
  579. package/dist-lib/spec/mesh/hyperdispatch/index.js +566 -0
  580. package/dist-lib/spec/mesh/hyperdispatch/messages.js +5713 -0
  581. package/dist-lib/spec/mesh/hyperschema/index.d.ts +14 -0
  582. package/dist-lib/spec/mesh/hyperschema/index.js +5713 -0
  583. package/dist-lib/spec/mesh/hyperschema/schema.json +3142 -0
  584. package/dist-lib/spec/mesh/hyperschema/types.d.ts +754 -0
  585. package/ducks.png +0 -0
  586. package/package.json +332 -1
@@ -0,0 +1,2126 @@
1
+ import BlindPeering from 'blind-peering';
2
+ import Corestore from 'corestore';
3
+ import CorestoreStorage from 'hypercore-storage';
4
+ import { constants as RocksConstants } from 'rocksdb-native';
5
+ import Rache from 'rache';
6
+ import Hyperswarm from 'hyperswarm';
7
+ import Wakeup from 'protomux-wakeup';
8
+ import Top from 'process-top';
9
+ import ReadyGuard from 'ready-guard';
10
+ import ReadyResource from 'ready-resource';
11
+ import ScopeLock from 'scope-lock';
12
+ import { createApi } from "./api/index.js";
13
+ import { BLIND_PEER_KEYS, BLIND_RELAY_KEYS } from "./core/blind-peers.js";
14
+ import { CoreBlobServer, MemoryVectorIndex } from "./core/files/index.js";
15
+ import { removeChatAttachments, removeChatKnowledge } from "./core/chat.js";
16
+ import { createFsDriveHost } from "./core/fs-drives.js";
17
+ import { sweepDriveStaging } from "./fs-drive-bridge.js";
18
+ import { closeCollaboraWorker } from "./collabora/worker.js";
19
+ import { decodeMeshInvite, encodeMeshInvite } from "./core/invite.js";
20
+ import { openLocalStore } from "./core/local/index.js";
21
+ import { getAgent } from "./core/agent.js";
22
+ import { HostedAgents } from "./core/hosted-agents.js";
23
+ import { SecretHandoff } from "./core/secret-handoff.js";
24
+ import { SkillOverlayHandoff } from "./core/skill-overlay-handoff.js";
25
+ import { createSkillOverlayReceiver } from "./core/skill-overlay-receiver.js";
26
+ import { createSkillSecretReceiver, HOST_REVOKED, NO_SUCH_AGENT, NOT_THE_HOST } from "./core/skill-secrets.js";
27
+ import { attestUnattestedDevices } from "./core/membership.js";
28
+ import { runMigrations } from "./core/migrations/index.js";
29
+ import { advertiseDeviceVersion } from "./core/devices.js";
30
+ import { OtaConfigReader, configCoreFor, resolveConfigChannel, vendoredMinSupportedVersion } from "./core/ota-config.js";
31
+ import { updateRequired } from "./core/min-version.js";
32
+ import { PendingDepartures } from "./core/departures.js";
33
+ import { Mesh } from "./core/mesh.js";
34
+ import { raceResource } from "./race-resource.js";
35
+ import { createSystemInfoSampler } from "./core/system-info.js";
36
+ import { oauthStateKeyFor } from "./credential-pusher.js";
37
+ import { setLogger } from "./logger.js";
38
+ import { settleOnClose } from '@qvac/harness/rpc';
39
+ import { openLocalSpec } from "./spec-loader.js";
40
+ import { unref } from "./unref.js";
41
+ import { local } from '../spec/index.js';
42
+ const QvacState = local.getEnum('@local/qvac-state');
43
+ const top = new Top();
44
+ const SWARM_KEYPAIR_NAME = 'qvac-swarm-keypair';
45
+ const QVAC_CORE_NAMESPACE = 'qvac-core';
46
+ const MESH_JOIN_CANCELED = 'Mesh join canceled';
47
+ const MESH_BELOW_FLOOR = 'Build is below the mesh floor';
48
+ const INVITE_DHT_NODES_LIMIT = 3;
49
+ const INVITE_BLIND_PEERS_LIMIT = 3;
50
+ const DIAGNOSTICS_SAMPLE_MS = 2000;
51
+ export class Core extends ReadyResource {
52
+ _storagePath;
53
+ store;
54
+ rootCorestore;
55
+ storage;
56
+ local;
57
+ state;
58
+ _transport;
59
+ _apiLifecycle;
60
+ _log;
61
+ _spec;
62
+ _bootstrapNodes;
63
+ _device;
64
+ _app;
65
+ _minSupportedVersion;
66
+ _otaConfigCore;
67
+ _otaConfig = null;
68
+ _configPeering = null;
69
+ _localDevice;
70
+ _blindPeerKeys;
71
+ _blindPeeringOpts;
72
+ _meshSeed;
73
+ _meshKey;
74
+ _additionalNodes;
75
+ _listModels;
76
+ _deleteModel;
77
+ _clearKvCache;
78
+ _deleteChatKvCache;
79
+ _compactChat;
80
+ _modelCatalogWatch;
81
+ _modelCatalogWatchSource = new ReadyGuard();
82
+ _retryModelDownload;
83
+ _transcribe;
84
+ _speak;
85
+ _speakStream;
86
+ _embedder;
87
+ _ragExtractors;
88
+ _indexedEmbedder = null;
89
+ _indexingLock = new ScopeLock();
90
+ _meshTransitionLock = new ScopeLock();
91
+ _processingFiles;
92
+ _skills;
93
+ _skillCatalog;
94
+ _skillManagement;
95
+ _catalogHooks = new ReadyGuard();
96
+ _tools;
97
+ _hostsModelSource;
98
+ _vectorIndex;
99
+ _closeSignal;
100
+ _signalClose;
101
+ _closeListeners;
102
+ _closeSignaled;
103
+ _mesh;
104
+ _offlineBoot = new ReadyGuard();
105
+ onlineBoot = new ReadyGuard();
106
+ _candidateMesh;
107
+ _cancelCandidateJoin;
108
+ _joinCancellation;
109
+ _meshSecretSeed;
110
+ _rpcs = new Set();
111
+ _stream;
112
+ _api;
113
+ _clients;
114
+ _deviceKeyPair;
115
+ _memberLock = new ScopeLock({ debounce: true });
116
+ _identityPhrase = null;
117
+ _identityPublicKey = null;
118
+ _swarm;
119
+ _departures = null;
120
+ _fsDrives = null;
121
+ _blobServer = null;
122
+ _attachmentUrl = (attachment) => this._blobServer?.link(attachment) ?? null;
123
+ _wakeup;
124
+ _secretHandoff;
125
+ _skillOverlayHandoff;
126
+ _hostedAgents;
127
+ _minting;
128
+ _leaving;
129
+ _kicked;
130
+ _kickedPending;
131
+ _peers;
132
+ _statusListeners;
133
+ _diagnosticsProviders;
134
+ _systemInfo;
135
+ _onMeshWritable;
136
+ _onMeshDead;
137
+ _onMeshStalled;
138
+ _statusError;
139
+ _upgradeRequired;
140
+ constructor(transport, { storagePath, logger = null, spec = openLocalSpec, bootstrapNodes = undefined, device = undefined, app = undefined, minSupportedVersion = undefined, otaConfigCore = undefined, blindPeerKeys = undefined, blindPeeringOpts = undefined, meshSeed = undefined, meshKey = undefined, additionalNodes = undefined, listModels = undefined, deleteModel = undefined, clearKvCache = undefined, deleteChatKvCache = undefined, compactChat = undefined, modelCatalogWatch = undefined, retryModelDownload = undefined, transcribe = undefined, speak = undefined, speakStream = undefined, embedder = undefined, extractors = undefined, skills = undefined, skillCatalog = undefined, tools = undefined, hostsModelSource = false, vectorIndex = undefined, apiLifecycle = undefined }) {
141
+ super();
142
+ this._transport = transport;
143
+ this._apiLifecycle = apiLifecycle ?? {
144
+ suspend: () => this.suspend(),
145
+ resume: () => this.resume()
146
+ };
147
+ this._log = logger;
148
+ if (logger)
149
+ setLogger(logger);
150
+ this._storagePath = storagePath;
151
+ this.storage = new CorestoreStorage(this._storagePath, {
152
+ blobGarbageCollectionAgeCutOff: 1.0,
153
+ blobGarbageCollectionForceThreshold: 0.5,
154
+ blobFileSize: 64 * 1024 * 1024
155
+ });
156
+ this.rootCorestore = new Corestore(this.storage, {
157
+ globalCache: new Rache()
158
+ });
159
+ this.store = this.rootCorestore.namespace(QVAC_CORE_NAMESPACE);
160
+ this.local = openLocalStore(this.storage);
161
+ this.state = QvacState.RESUME;
162
+ this._spec = spec;
163
+ this._bootstrapNodes = bootstrapNodes;
164
+ this._device = device;
165
+ this._app = app;
166
+ this._minSupportedVersion = minSupportedVersion;
167
+ const channel = resolveConfigChannel(app?.channel);
168
+ const lane = channel ? configCoreFor(channel) : null;
169
+ this._otaConfigCore = minSupportedVersion ? null : (otaConfigCore ?? lane);
170
+ if (!minSupportedVersion)
171
+ this._minSupportedVersion = vendoredMinSupportedVersion();
172
+ this._localDevice = null;
173
+ this._blindPeerKeys = blindPeerKeys;
174
+ this._blindPeeringOpts = blindPeeringOpts;
175
+ this._meshSeed = meshSeed;
176
+ this._meshKey = meshKey;
177
+ this._additionalNodes = additionalNodes;
178
+ this._listModels = listModels ?? null;
179
+ this._deleteModel = deleteModel ?? null;
180
+ this._clearKvCache = clearKvCache ?? null;
181
+ this._deleteChatKvCache = deleteChatKvCache ?? null;
182
+ this._compactChat = compactChat ?? null;
183
+ this._modelCatalogWatch = modelCatalogWatch ?? null;
184
+ this._openModelCatalogWatchSource();
185
+ void this._modelCatalogWatchSource.ready().catch(noop);
186
+ this._retryModelDownload = retryModelDownload ?? null;
187
+ this._transcribe = transcribe ?? null;
188
+ this._speak = speak ?? null;
189
+ this._speakStream = speakStream ?? null;
190
+ this._embedder = embedder ?? null;
191
+ this._ragExtractors = extractors;
192
+ this._processingFiles = null;
193
+ this._skills = skills ?? null;
194
+ this._skillCatalog = skillCatalog ?? null;
195
+ this._skillManagement = null;
196
+ this._tools = tools ?? null;
197
+ this._hostsModelSource = hostsModelSource;
198
+ this._openCatalogHooks();
199
+ void this._catalogHooks.ready().catch(noop);
200
+ this._vectorIndex = vectorIndex ?? (embedder ? new MemoryVectorIndex() : null);
201
+ this._closeSignal = new Promise((resolve) => {
202
+ this._signalClose = resolve;
203
+ });
204
+ this._closeListeners = new Set();
205
+ this._closeSignaled = false;
206
+ void this._closeSignal.then(() => {
207
+ this._closeSignaled = true;
208
+ const listeners = [...this._closeListeners];
209
+ this._closeListeners.clear();
210
+ for (const listener of listeners)
211
+ listener();
212
+ });
213
+ this._mesh = null;
214
+ this._candidateMesh = null;
215
+ this._cancelCandidateJoin = null;
216
+ this._joinCancellation = null;
217
+ this._meshSecretSeed = null;
218
+ this._rpcs.clear();
219
+ this._stream = null;
220
+ this._api = null;
221
+ this._clients = new Set();
222
+ this._deviceKeyPair = null;
223
+ this._swarm = null;
224
+ this._wakeup = new Wakeup();
225
+ this._secretHandoff = new SecretHandoff({
226
+ onrequest: (request, from) => this._storeHandedOffSecret(request, from)
227
+ });
228
+ this._skillOverlayHandoff = new SkillOverlayHandoff({
229
+ onrequest: (op, from) => this._serveSkillOverlayOp(op, from)
230
+ });
231
+ this._hostedAgents = null;
232
+ this._minting = false;
233
+ this._leaving = false;
234
+ this._kicked = false;
235
+ this._kickedPending = false;
236
+ this._peers = new Set();
237
+ this._statusListeners = new Set();
238
+ this._diagnosticsProviders = new Set();
239
+ this._systemInfo = null;
240
+ this._onMeshWritable = () => {
241
+ this._kicked = false;
242
+ this._notifyStatus();
243
+ };
244
+ this._onMeshDead = (err) => {
245
+ const mesh = this._mesh;
246
+ if (this.closing || !mesh)
247
+ return;
248
+ this._log?.error(['p2p', 'mesh'], 'mesh autobee died — retiring it', err);
249
+ this._mesh = null;
250
+ this._statusError = statusErrorMessage('the local database died', err);
251
+ this._notifyStatus();
252
+ this._retireMesh(mesh).catch((retireErr) => {
253
+ this._log?.warn(['p2p', 'mesh'], 'retiring the dead mesh failed', retireErr);
254
+ });
255
+ };
256
+ this._onMeshStalled = (err) => {
257
+ if (this._mesh)
258
+ this._withdrawFromMesh(this._mesh, err);
259
+ };
260
+ this._statusError = null;
261
+ this._upgradeRequired = null;
262
+ }
263
+ get devicePublicKey() {
264
+ return this._deviceKeyPair?.publicKey ?? null;
265
+ }
266
+ get fsDrives() {
267
+ return this._fsDrives;
268
+ }
269
+ get suspended() {
270
+ return this.state === QvacState.SUSPEND;
271
+ }
272
+ get mesh() {
273
+ return this._mesh;
274
+ }
275
+ async meshReady() {
276
+ await this._awaitMesh();
277
+ }
278
+ get peerCount() {
279
+ return this._peers.size;
280
+ }
281
+ get peerDeviceIds() {
282
+ const ids = [...this._peers].map((conn) => conn.remotePublicKey.toString('hex'));
283
+ return [...new Set(ids)].sort();
284
+ }
285
+ async _open() {
286
+ this._runBootOffline().catch(noop);
287
+ this._runBootOnline().catch(noop);
288
+ await this._offlineBoot.ready();
289
+ this._log?.info('lifecycle', 'core open');
290
+ }
291
+ async _runBootOffline() {
292
+ try {
293
+ this._deviceKeyPair = await this.store.createKeyPair(SWARM_KEYPAIR_NAME);
294
+ this._identityPublicKey = (await this.local.readIdentity())?.publicKey.toString('hex') ?? null;
295
+ this._localDevice = await this.local.ensureDevice(this.devicePublicKey, this._device);
296
+ this._openSwarm(this._deviceKeyPair);
297
+ this._departures = new PendingDepartures(this.store, this.local, {
298
+ swarm: this._swarm,
299
+ logger: this._log,
300
+ blindPeerKeys: this._resolveBlindPeerKeys(),
301
+ blindPeeringOpts: this._blindPeeringOpts,
302
+ wakeup: this._wakeup
303
+ });
304
+ this._fsDrives = createFsDriveHost(this.store, {
305
+ swarm: this._swarm,
306
+ blindPeerKeys: this._resolveBlindPeerKeys(),
307
+ blindPeeringOpts: this._blindPeeringOpts
308
+ });
309
+ void sweepDriveStaging();
310
+ this._blobServer = new CoreBlobServer(this.store, () => this._currentMesh());
311
+ this._blobServer.on('rebound', (port) => {
312
+ logger.warn('core', 'blob server rebound, links minted before now are stale', { port });
313
+ });
314
+ await this._blobServer.ready();
315
+ await this._openOtaConfig();
316
+ await this._openBootMesh();
317
+ this._systemInfo = createSystemInfoSampler();
318
+ this._api = createApi({
319
+ state: this.local,
320
+ notificationLifetime: this,
321
+ mesh: () => this._currentMesh(),
322
+ meshStatus: this._meshStatusSource(),
323
+ network: this._networkStatusSource(),
324
+ diagnostics: this._diagnosticsSource(),
325
+ logs: this._logSource(),
326
+ deviceId: this.devicePublicKey,
327
+ lifecycle: this._apiLifecycle,
328
+ ragIndex: () => this._vectorIndex,
329
+ ragEmbed: () => this._indexedEmbedder,
330
+ platform: () => this._localDevice?.platform ?? null,
331
+ pushSkillSecret: (request) => this.pushSkillSecret(request),
332
+ listModels: this._hostsModelSource || this._listModels
333
+ ? (options) => this._listModels?.(options) ?? Promise.resolve({ models: [] })
334
+ : null,
335
+ deleteModel: this._hostsModelSource || this._deleteModel
336
+ ? (options) => this._deleteModel?.(options) ??
337
+ Promise.resolve({ name: options.name, removed: 0, freedBytes: 0 })
338
+ : null,
339
+ clearKvCache: () => this._clearKvCache?.() ??
340
+ Promise.resolve({
341
+ status: 'unsupported',
342
+ error: 'No harness KV cache deletion source is bound'
343
+ }),
344
+ deleteChatKvCache: (chatId) => this._deleteChatKvCache?.(chatId) ??
345
+ Promise.resolve({
346
+ status: 'unsupported',
347
+ error: 'No harness KV cache deletion source is bound'
348
+ }),
349
+ compactChat: (chatId) => this._compactChat?.(chatId) ??
350
+ Promise.resolve({ compacted: false, reason: 'unsupported' }),
351
+ modelCatalogWatch: this._hostsModelSource || this._modelCatalogWatch
352
+ ? () => this._watchModelCatalog()
353
+ : null,
354
+ retryModelDownload: this._hostsModelSource || this._retryModelDownload
355
+ ? ({ name }) => this._retryModelDownload?.(name) ??
356
+ Promise.reject(new Error('no model download source bound'))
357
+ : null,
358
+ transcribe: this._hostsModelSource || this._transcribe
359
+ ? (request) => this._transcribe?.(request) ??
360
+ Promise.reject(new Error('no transcription source bound'))
361
+ : null,
362
+ speak: this._hostsModelSource || this._speak
363
+ ? (request) => this._speak?.(request) ?? Promise.reject(new Error('no tts source bound'))
364
+ : null,
365
+ speakStream: this._hostsModelSource || this._speakStream
366
+ ? (text) => {
367
+ if (!this._speakStream)
368
+ throw new Error('no tts source bound');
369
+ return this._speakStream(text);
370
+ }
371
+ : null,
372
+ deviceHost: {
373
+ removeWriter: (writerKey, deviceId) => this.removeDeviceWriter(writerKey, deviceId),
374
+ renameLocal: (name) => this.renameLocalDevice(name),
375
+ saveProfileLocal: (capabilityProfile, recommendedModelName, platform) => this.saveDeviceProfileLocal(capabilityProfile, recommendedModelName, platform),
376
+ readLocalProfile: () => this._localDevice
377
+ ? {
378
+ capabilityProfile: this._localDevice.capabilityProfile,
379
+ recommendedModelName: this._localDevice.recommendedModelName,
380
+ platform: this._localDevice.platform
381
+ }
382
+ : null
383
+ },
384
+ skills: this._hostsModelSource || this._skills
385
+ ? (agentId, modelName, options) => this._skills?.(agentId, modelName, options) ?? Promise.resolve([])
386
+ : null,
387
+ skillCatalog: this._hostsModelSource || this._skillCatalog
388
+ ? async (agentId, modelName, options) => {
389
+ await this._waitForCatalogHooks();
390
+ return (this._skillCatalog?.(agentId, modelName, options) ??
391
+ Promise.resolve({ skills: [] }));
392
+ }
393
+ : null,
394
+ tools: this._hostsModelSource || this._tools
395
+ ? async () => {
396
+ await this._waitForCatalogHooks();
397
+ return this._tools?.() ?? Promise.resolve({ tools: [] });
398
+ }
399
+ : null,
400
+ listManagedSkills: this._hostsModelSource || this._skillManagement
401
+ ? async (agentId) => ({
402
+ skills: [...((await this._skillOverlayOp(agentId, { op: 'list' })).skills ?? [])]
403
+ })
404
+ : null,
405
+ readSkillFile: this._hostsModelSource || this._skillManagement
406
+ ? async (name, agentId) => {
407
+ const res = await this._skillOverlayOp(agentId, { op: 'read', name });
408
+ return { found: res.found ?? false, content: res.content, origin: res.origin };
409
+ }
410
+ : null,
411
+ writeSkillFile: this._hostsModelSource || this._skillManagement
412
+ ? async (name, content, agentId) => ({
413
+ ok: (await this._skillOverlayOp(agentId, { op: 'write', name, content })).ok ?? false
414
+ })
415
+ : null,
416
+ copySkillForEdit: this._hostsModelSource || this._skillManagement
417
+ ? async (name, agentId) => ({
418
+ copied: (await this._skillOverlayOp(agentId, { op: 'copy', name })).copied ?? false
419
+ })
420
+ : null,
421
+ deleteOverlaySkill: this._hostsModelSource || this._skillManagement
422
+ ? async (name, agentId) => ({
423
+ removed: (await this._skillOverlayOp(agentId, { op: 'delete', name })).removed ?? false
424
+ })
425
+ : null
426
+ });
427
+ this._stream = await this._transport();
428
+ const { bindApi, HRPC } = await this._spec();
429
+ const rpc = settleOnClose(new HRPC(this._stream));
430
+ bindApi(rpc, this._api);
431
+ this._rpcs.add(rpc);
432
+ this._offlineBoot.exit();
433
+ void this._pushIdentityPhrase();
434
+ return;
435
+ }
436
+ catch (err) {
437
+ try {
438
+ this._systemInfo?.destroy();
439
+ this._systemInfo = null;
440
+ await this._stopIndexing();
441
+ await this._closeOtaConfig();
442
+ await this._fsDrives?.close();
443
+ this._fsDrives = null;
444
+ await this._blobServer?.close();
445
+ this._blobServer = null;
446
+ await this._departures?.close();
447
+ this._departures = null;
448
+ logger.info('core', 'closing swarm');
449
+ await this._closeSwarm();
450
+ logger.info('core', 'closing local');
451
+ await this.local?.close();
452
+ logger.info('core', 'closing mesh');
453
+ await this._mesh?.close();
454
+ logger.info('core', 'closing storage');
455
+ await this.store?.close();
456
+ await this.rootCorestore?.close();
457
+ }
458
+ finally {
459
+ this._offlineBoot.destroy(err instanceof Error ? err : new Error(String(err)));
460
+ }
461
+ }
462
+ }
463
+ async _openBootMesh() {
464
+ if (this._blockedByMinVersion() || this._mesh || this._minting)
465
+ return;
466
+ try {
467
+ await this._openMesh({ seed: this._meshSeed, baseKey: this._meshKey });
468
+ }
469
+ catch (err) {
470
+ if (this.closing)
471
+ return;
472
+ if (!this._upgradeRequired) {
473
+ this._statusError = statusErrorMessage('opening the local database failed', err);
474
+ }
475
+ this._notifyStatus();
476
+ this._log?.error(['p2p', 'mesh'], 'mesh open failed', err);
477
+ }
478
+ }
479
+ async _runBootOnline() {
480
+ void this.onlineBoot.ready().catch(noop);
481
+ try {
482
+ await this._offlineBoot.ready();
483
+ if (this.closing)
484
+ return;
485
+ if (this._mesh)
486
+ this._bringMeshOnline(this._mesh);
487
+ }
488
+ catch (err) {
489
+ if (this.closing)
490
+ return;
491
+ this._log?.error(['p2p', 'mesh'], 'online boot failed', err);
492
+ }
493
+ finally {
494
+ if (!this.closing && !this._offlineBoot.destroyed)
495
+ this._peerConfigCore();
496
+ if (!this.closing)
497
+ this._departures?.flush(this._mesh?.key);
498
+ this.onlineBoot.exit();
499
+ }
500
+ }
501
+ async _reopenMesh() {
502
+ try {
503
+ if (this.closing || this._mesh || this._minting)
504
+ return;
505
+ await this._startMesh({ seed: this._meshSeed, baseKey: this._meshKey });
506
+ }
507
+ catch (err) {
508
+ if (this.closing)
509
+ return;
510
+ if (!this._upgradeRequired) {
511
+ this._statusError = statusErrorMessage('reopening the local database failed', err);
512
+ }
513
+ this._notifyStatus();
514
+ this._log?.error(['p2p', 'mesh'], 'reopening the mesh failed', err);
515
+ }
516
+ }
517
+ get otaConfigCore() {
518
+ return this._otaConfigCore;
519
+ }
520
+ async _openOtaConfig() {
521
+ const core = this._otaConfigCore;
522
+ if (!core) {
523
+ this._log?.warn(['p2p', 'config'], 'no release lane: the version floor is inert', {
524
+ lane: this._app?.channel ?? null,
525
+ appVersion: this._app?.version ?? null
526
+ });
527
+ return;
528
+ }
529
+ if (this._otaConfig || this.closing)
530
+ return;
531
+ const config = new OtaConfigReader(this.store, core);
532
+ this._otaConfig = config;
533
+ try {
534
+ if (!(await recordedBlockIsLocal(config.core))) {
535
+ this._log?.warn(['p2p', 'config'], 'lane core records a block it does not hold: the baked floor stands');
536
+ await this._closeOtaConfig();
537
+ return;
538
+ }
539
+ await config.ready();
540
+ if (this.closing)
541
+ return;
542
+ config.on('update', () => {
543
+ this._logFloor(config, 'updated');
544
+ this.setMinSupportedVersion(config.minSupportedVersion);
545
+ });
546
+ this._logFloor(config, 'opened');
547
+ this.setMinSupportedVersion(config.minSupportedVersion);
548
+ }
549
+ catch (err) {
550
+ this._log?.warn(['p2p', 'config'], 'ota config unavailable', err);
551
+ }
552
+ }
553
+ _logFloor(config, event) {
554
+ const floor = config.minSupportedVersion;
555
+ const appVersion = this._app?.version;
556
+ const length = config.core.length;
557
+ this._log?.info(['p2p', 'config'], `ota config ${event}`, {
558
+ lane: this._app?.channel ?? null,
559
+ discoveryKey: config.core.discoveryKey.toString('hex').slice(0, 8),
560
+ length,
561
+ floor,
562
+ source: length > 0 && length >= (this._otaConfigCore?.minLength ?? 1) ? 'published' : 'vendored',
563
+ appVersion: appVersion ?? null,
564
+ withheld: updateRequired({ range: floor, appVersion })
565
+ });
566
+ }
567
+ _peerConfigCore() {
568
+ const config = this._otaConfig;
569
+ if (!config || this._configPeering || this._mesh || !this._swarm)
570
+ return;
571
+ const keys = this._resolveBlindPeerKeys();
572
+ if (keys.length === 0)
573
+ return;
574
+ this._configPeering = new BlindPeering(this._swarm.dht, this.store, {
575
+ pick: keys.length,
576
+ ...this._blindPeeringOpts
577
+ });
578
+ this._configPeering.addCoreBackground(config.core, { keys });
579
+ this._log?.info(['p2p', 'config'], 'blind peering the config core: no mesh to carry it');
580
+ }
581
+ async _closeConfigPeering() {
582
+ const peering = this._configPeering;
583
+ if (!peering)
584
+ return;
585
+ this._configPeering = null;
586
+ await peering.close();
587
+ }
588
+ async _closeOtaConfig() {
589
+ const config = this._otaConfig;
590
+ this._otaConfig = null;
591
+ await closeConfigReader(config);
592
+ }
593
+ _blockedByMinVersion() {
594
+ const range = this._minSupportedVersion;
595
+ const appVersion = this._app?.version;
596
+ if (!updateRequired({ range, appVersion })) {
597
+ if (this._upgradeRequired === 'floor')
598
+ this._setUpgradeRequired(null);
599
+ return false;
600
+ }
601
+ if (this._upgradeRequired)
602
+ return true;
603
+ this._log?.error(['p2p', 'mesh'], 'mesh requires a newer build — not opening', {
604
+ range,
605
+ appVersion
606
+ });
607
+ this._setUpgradeRequired('floor');
608
+ return true;
609
+ }
610
+ _setUpgradeRequired(reason) {
611
+ if (this._upgradeRequired === reason)
612
+ return;
613
+ this._upgradeRequired = reason;
614
+ this._notifyStatus();
615
+ }
616
+ setMinSupportedVersion(required) {
617
+ const next = required || undefined;
618
+ if (this._minSupportedVersion === next)
619
+ return;
620
+ this._minSupportedVersion = next;
621
+ if (this.closing)
622
+ return;
623
+ const withheld = this._upgradeRequired === 'floor';
624
+ if (!this._blockedByMinVersion()) {
625
+ if (withheld)
626
+ void this._reopenMesh();
627
+ return;
628
+ }
629
+ const mesh = this._mesh;
630
+ if (!mesh)
631
+ return;
632
+ this._mesh = null;
633
+ this._notifyStatus();
634
+ this._retireMesh(mesh).catch((err) => {
635
+ this._log?.warn(['p2p', 'mesh'], 'retiring a mesh above our floor failed', err);
636
+ });
637
+ }
638
+ async connect(stream) {
639
+ if (!this.opened)
640
+ await this.ready();
641
+ if (this.closing || !this._api)
642
+ throw new Error('core is closing');
643
+ const { bindApi, HRPC } = await this._spec();
644
+ const rpc = settleOnClose(new HRPC(stream));
645
+ bindApi(rpc, this._api);
646
+ this._rpcs.add(rpc);
647
+ this._clients.add(stream);
648
+ void this._pushIdentityPhrase();
649
+ stream.on('close', () => {
650
+ this._clients.delete(stream);
651
+ this._rpcs.delete(rpc);
652
+ });
653
+ }
654
+ async wakeup() {
655
+ if (this.closing)
656
+ return;
657
+ this.state = QvacState.WAKEUP;
658
+ logger.info('core', 'wakeup');
659
+ if (!this.opened)
660
+ await this.ready();
661
+ await this.resume();
662
+ }
663
+ async presuspend() {
664
+ if (this.closing)
665
+ return;
666
+ this.state = QvacState.PRESUSPEND;
667
+ logger.info('core', 'presuspend');
668
+ if (!this.opened)
669
+ await this.ready();
670
+ }
671
+ async suspend() {
672
+ logger.info('core', 'suspend called');
673
+ if (this.state === QvacState.SUSPEND)
674
+ return;
675
+ if (this.closing)
676
+ return;
677
+ this.state = QvacState.SUSPEND;
678
+ if (!this.opened)
679
+ await this.ready();
680
+ logger.info('core', 'suspending');
681
+ if (this._mesh)
682
+ await this._mesh.suspend();
683
+ if (this._departures)
684
+ await this._departures.suspend();
685
+ if (this._configPeering)
686
+ await this._configPeering.suspend();
687
+ if (this._swarm)
688
+ await this._swarm.suspend();
689
+ if (this._blobServer)
690
+ await this._blobServer.suspend();
691
+ await this.store.suspend();
692
+ this._log?.info('lifecycle', 'core suspend');
693
+ }
694
+ async resume() {
695
+ logger.info('core', 'resume called');
696
+ if (this.state === QvacState.RESUME)
697
+ return;
698
+ if (this.closing)
699
+ return;
700
+ if (this.state === QvacState.PRESUSPEND) {
701
+ this.state = QvacState.RESUME;
702
+ return;
703
+ }
704
+ this.state = QvacState.RESUME;
705
+ if (!this.opened)
706
+ await this.ready();
707
+ logger.info('core', 'resuming');
708
+ await this.store.resume();
709
+ if (this._blobServer)
710
+ await this._blobServer.resume();
711
+ if (this._swarm)
712
+ await this._swarm.resume();
713
+ if (this._configPeering)
714
+ await this._configPeering.resume();
715
+ if (this._mesh)
716
+ await this._mesh.resume();
717
+ if (this._departures)
718
+ await this._departures.resume();
719
+ this._departures?.flush(this._mesh?.key);
720
+ if (this._swarm)
721
+ void this._refreshTopics(this._swarm).catch(noop);
722
+ void this._pushIdentityPhrase();
723
+ this._log?.info('lifecycle', 'core resume');
724
+ }
725
+ async _refreshTopics(swarm) {
726
+ for (const discovery of swarm.topics()) {
727
+ await discovery.flushed();
728
+ await discovery.refresh();
729
+ }
730
+ }
731
+ async _close() {
732
+ logger.info('core', 'closing');
733
+ if (this.state === QvacState.SUSPEND)
734
+ await this.store.resume();
735
+ this._catalogHooks.destroy(new Error('core is closing'));
736
+ this._modelCatalogWatchSource.destroy(new Error('core is closing'));
737
+ this._offlineBoot.destroy(new Error('core is closing'));
738
+ this.onlineBoot.destroy(new Error('core is closing'));
739
+ this._signalClose();
740
+ this._notifyStatus();
741
+ if (this._stream)
742
+ this._stream.destroy();
743
+ for (const client of this._clients)
744
+ client.destroy();
745
+ this._clients.clear();
746
+ await this._stopHostedAgents();
747
+ await this._stopIndexing();
748
+ closeCollaboraWorker();
749
+ await this._blobServer?.close();
750
+ this._blobServer = null;
751
+ if (this._mesh) {
752
+ this._mesh.autobee.off('writable', this._onMeshWritable);
753
+ this._mesh.autobee.off('error', this._onMeshDead);
754
+ this._mesh.autobee.off('close', this._onMeshDead);
755
+ this._mesh.autobee.off('interrupt', this._onMeshStalled);
756
+ await this._mesh.close();
757
+ }
758
+ await this._discardCandidateMesh();
759
+ await this._departures?.close();
760
+ this._departures = null;
761
+ await this._closeConfigPeering();
762
+ await this._closeOtaConfig();
763
+ await this._fsDrives?.close();
764
+ this._fsDrives = null;
765
+ logger.info('core', 'closing swarm');
766
+ await this._closeSwarm();
767
+ this._mesh = null;
768
+ this._meshSecretSeed = null;
769
+ logger.info('core', 'closing local');
770
+ await this.local?.close();
771
+ this._systemInfo?.destroy();
772
+ this._systemInfo = null;
773
+ logger.info('core', 'closing storage');
774
+ await this.store?.close();
775
+ await this.rootCorestore?.close();
776
+ this._log?.info('lifecycle', 'core closed');
777
+ }
778
+ _openSwarm(keyPair) {
779
+ this._swarm = new Hyperswarm({
780
+ keyPair,
781
+ bootstrap: this._bootstrapNodes,
782
+ relayThrough: this._bootstrapNodes ? undefined : () => BLIND_RELAY_KEYS
783
+ });
784
+ this._swarm.on('connection', (conn) => this._onConnection(conn));
785
+ this._log?.info(['p2p', 'swarm'], 'swarm created', {
786
+ deviceKey: keyPair.publicKey.toString('hex').slice(0, 8)
787
+ });
788
+ for (const node of this._additionalNodes ?? [])
789
+ this._swarm.dht.addNode(node);
790
+ }
791
+ _resolveBlindPeerKeys(extra = []) {
792
+ const defaults = this._bootstrapNodes ? [] : BLIND_PEER_KEYS;
793
+ const merged = new Map(defaults.map((key) => [key.toString('hex'), key]));
794
+ for (const key of this._blindPeerKeys ?? [])
795
+ merged.set(key.toString('hex'), key);
796
+ for (const key of extra)
797
+ merged.set(key.toString('hex'), key);
798
+ return [...merged.values()];
799
+ }
800
+ async _startMesh(opts = {}) {
801
+ const mesh = await this._openMesh(opts);
802
+ this._bringMeshOnline(mesh, opts);
803
+ return mesh;
804
+ }
805
+ async _openMesh(opts = {}) {
806
+ if (this.closing)
807
+ throw new Error('core is closing');
808
+ if (this._blockedByMinVersion())
809
+ throw new Error(MESH_BELOW_FLOOR);
810
+ if (this._mesh) {
811
+ await this._retireMesh(this._mesh);
812
+ }
813
+ const deviceId = this._deviceKeyPair.publicKey;
814
+ const session = await this.local.resolveSession(deviceId, opts);
815
+ const mesh = new Mesh(this.store, {
816
+ seed: session.seed,
817
+ key: session.baseKey ?? null,
818
+ deviceId,
819
+ writerSeed: session.writerSeed,
820
+ logger: this._log,
821
+ blindPeerKeys: this._resolveBlindPeerKeys(opts.blindPeerKeys),
822
+ blindPeeringOpts: this._blindPeeringOpts,
823
+ wakeup: this._wakeup,
824
+ attachmentUrl: this._attachmentUrl
825
+ });
826
+ try {
827
+ await mesh.ready();
828
+ await raceResource(mesh.autobee, (async () => {
829
+ await mesh.appendBirthOp(deviceId, this._localDevice ?? undefined, await this._mintBirthMember(mesh, deviceId, session));
830
+ await this.local.recordMesh(deviceId, mesh.key, session.seed, session.creator, session.writerSeed);
831
+ })(), 'mesh');
832
+ }
833
+ catch (err) {
834
+ await mesh.close().catch(noop);
835
+ throw err;
836
+ }
837
+ if (this.closing) {
838
+ await mesh.close();
839
+ throw new Error('core is closing');
840
+ }
841
+ const halted = mesh.interrupted;
842
+ if (halted) {
843
+ this._withdrawFromMesh(mesh, halted);
844
+ throw halted;
845
+ }
846
+ this._activateMesh(mesh, session);
847
+ return mesh;
848
+ }
849
+ async _mintBirthMember(mesh, deviceId, session) {
850
+ const local = this._localDevice;
851
+ if (!local || session.baseKey || mesh.localLength > 0)
852
+ return undefined;
853
+ const now = Date.now();
854
+ const { identity, mnemonic } = await this.local.ensureIdentity(deviceId, now);
855
+ this._identityPublicKey = identity.publicKey.toString('hex');
856
+ this._holdIdentityPhrase(mnemonic);
857
+ return {
858
+ member: { id: identity.publicKey, name: local.name, joinedAt: now, updatedAt: now },
859
+ proof: identity.proof
860
+ };
861
+ }
862
+ _holdIdentityPhrase(mnemonic) {
863
+ if (!mnemonic)
864
+ return;
865
+ this._identityPhrase = mnemonic;
866
+ void this._pushIdentityPhrase();
867
+ }
868
+ async _pushIdentityPhrase() {
869
+ const phrase = this._identityPhrase;
870
+ if (!phrase || this._rpcs.size === 0 || this.closing)
871
+ return;
872
+ this._identityPhrase = null;
873
+ for (const rpc of this._rpcs) {
874
+ if (await this._offerIdentityPhrase(rpc, phrase))
875
+ return;
876
+ }
877
+ this._identityPhrase = phrase;
878
+ this._log?.warn(['api'], 'the host stored no recovery phrase');
879
+ }
880
+ async _offerIdentityPhrase(rpc, phrase) {
881
+ try {
882
+ return (await rpc.storeIdentityPhrase({ phrase })).ok;
883
+ }
884
+ catch {
885
+ return false;
886
+ }
887
+ }
888
+ _bringMeshOnline(mesh, opts = {}) {
889
+ if (this.closing || mesh.closing || this._mesh !== mesh)
890
+ return;
891
+ if (this._swarm) {
892
+ this._swarm.join(mesh.discoveryKey, { server: true, client: true });
893
+ mesh.startBlindPeering(this._swarm.dht);
894
+ if (this.suspended)
895
+ void mesh.suspend().catch(noop);
896
+ this._log?.info(['p2p', 'swarm'], 'announced and peering the mesh');
897
+ }
898
+ if (!opts.new)
899
+ void this._ensureNotRevoked(mesh);
900
+ this._departures?.flush(mesh.key);
901
+ void this._advertiseAppVersion(mesh, this._deviceKeyPair.publicKey);
902
+ void this._advertiseDeviceProfile(mesh, this._deviceKeyPair.publicKey);
903
+ void this._settleMembership(mesh, { migrate: true });
904
+ }
905
+ async _advertiseDeviceProfile(mesh, deviceId) {
906
+ const local = this._localDevice;
907
+ if (!local?.platform)
908
+ return;
909
+ try {
910
+ await mesh.waitForWritable();
911
+ if (mesh.closing || this._mesh !== mesh)
912
+ return;
913
+ const snap = mesh.view.snapshot();
914
+ let existing;
915
+ try {
916
+ existing = await snap.get('@qvac/devices', { id: deviceId });
917
+ }
918
+ finally {
919
+ await snap.close();
920
+ }
921
+ if (existing?.platform === local.platform &&
922
+ existing.capabilityProfile === local.capabilityProfile &&
923
+ existing.recommendedModelName === local.recommendedModelName) {
924
+ return;
925
+ }
926
+ await mesh.dispatch('update-device-profile', {
927
+ deviceId,
928
+ capabilityProfile: local.capabilityProfile,
929
+ recommendedModelName: local.recommendedModelName,
930
+ platform: local.platform
931
+ });
932
+ }
933
+ catch (err) {
934
+ this._log?.warn(['p2p', 'mesh'], 'advertising the device profile failed', err);
935
+ }
936
+ }
937
+ async _advertiseAppVersion(mesh, deviceId) {
938
+ const app = this._app;
939
+ if (!app)
940
+ return;
941
+ try {
942
+ await mesh.waitForWritable();
943
+ if (mesh.closing || this._mesh !== mesh)
944
+ return;
945
+ const snap = mesh.view.snapshot();
946
+ let existing;
947
+ try {
948
+ existing = await snap.get('@qvac/devices', { id: deviceId });
949
+ }
950
+ finally {
951
+ await snap.close();
952
+ }
953
+ if (existing?.appVersion === app.version &&
954
+ (existing.appBuild || undefined) === app.build &&
955
+ existing.appChannel === app.channel) {
956
+ return;
957
+ }
958
+ await advertiseDeviceVersion(mesh, deviceId, app);
959
+ }
960
+ catch (err) {
961
+ this._log?.warn(['p2p', 'mesh'], 'advertising app version failed', err);
962
+ }
963
+ }
964
+ async _settleMembership(mesh, { migrate = false } = {}) {
965
+ if (!this._localDevice)
966
+ return;
967
+ if (!(await this._memberLock.lock()))
968
+ return;
969
+ try {
970
+ await mesh.waitForWritable();
971
+ if (mesh.closing || this._mesh !== mesh)
972
+ return;
973
+ await mesh.autobee.update();
974
+ if (mesh.closing || this._mesh !== mesh)
975
+ return;
976
+ const context = { deviceKeyPair: this._deviceKeyPair, log: this._log };
977
+ if (migrate)
978
+ await runMigrations(mesh, { ...context, ...this._migrationContext() });
979
+ await attestUnattestedDevices(mesh, context);
980
+ }
981
+ catch (err) {
982
+ this._log?.warn(['p2p', 'mesh'], 'settling membership failed', err);
983
+ }
984
+ finally {
985
+ this._memberLock.unlock();
986
+ }
987
+ }
988
+ _migrationContext() {
989
+ return {
990
+ device: {
991
+ id: this._deviceKeyPair.publicKey,
992
+ platform: this._device?.platform ?? this._localDevice.platform
993
+ },
994
+ deviceName: this._localDevice.name,
995
+ mintRoot: async (deviceId, at) => {
996
+ const { identity, mnemonic } = await this.local.ensureIdentity(deviceId, at);
997
+ this._identityPublicKey = identity.publicKey.toString('hex');
998
+ this._holdIdentityPhrase(mnemonic);
999
+ return { publicKey: identity.publicKey, proof: identity.proof };
1000
+ }
1001
+ };
1002
+ }
1003
+ async _recordMembership(own) {
1004
+ try {
1005
+ await this.local.recordMembership({
1006
+ memberId: own.memberId,
1007
+ proof: own.memberProof,
1008
+ attestedAt: own.attestedAt || 0
1009
+ });
1010
+ }
1011
+ catch (err) {
1012
+ this._log?.warn(['p2p', 'mesh'], 'keeping our membership proof failed', err);
1013
+ }
1014
+ }
1015
+ async _ensureNotRevoked(mesh) {
1016
+ try {
1017
+ const revocation = await mesh.checkResumedRevocation();
1018
+ if (!revocation || this._mesh !== mesh)
1019
+ return;
1020
+ this._log?.info(['p2p', 'mesh'], `resumed already revoked (${revocation} while offline) — minting a fresh mesh`);
1021
+ if (revocation === 'kicked')
1022
+ this._kickedPending = true;
1023
+ await this._requestFreshMesh();
1024
+ }
1025
+ catch (err) {
1026
+ this._log?.warn(['p2p', 'mesh'], 'resumed revocation check failed', err);
1027
+ }
1028
+ }
1029
+ async _retireMesh(mesh) {
1030
+ if (this._mesh === mesh) {
1031
+ this._mesh = null;
1032
+ this._notifyStatus();
1033
+ }
1034
+ if (this._candidateMesh === mesh)
1035
+ this._candidateMesh = null;
1036
+ mesh.autobee.off('writable', this._onMeshWritable);
1037
+ mesh.autobee.off('error', this._onMeshDead);
1038
+ mesh.autobee.off('close', this._onMeshDead);
1039
+ mesh.autobee.off('interrupt', this._onMeshStalled);
1040
+ await this._stopHostedAgents();
1041
+ try {
1042
+ await this._stopIndexing();
1043
+ }
1044
+ finally {
1045
+ if (this._swarm)
1046
+ await this._swarm.leave(mesh.discoveryKey).catch(() => { });
1047
+ await mesh.close();
1048
+ }
1049
+ }
1050
+ _withdrawFromMesh(mesh, err) {
1051
+ if (this.closing || this._upgradeRequired)
1052
+ return;
1053
+ this._log?.error(['p2p', 'mesh'], 'mesh needs a newer build — withdrawing from it', err);
1054
+ this._setUpgradeRequired('halt');
1055
+ this._retireMesh(mesh).catch((retireErr) => {
1056
+ this._log?.warn(['p2p', 'mesh'], 'retiring the stalled mesh failed', retireErr);
1057
+ });
1058
+ }
1059
+ _onKicked() {
1060
+ if (this.closing || this._leaving)
1061
+ return;
1062
+ this._log?.info(['p2p', 'mesh'], 'our writer was revoked (kicked) — minting a fresh mesh');
1063
+ this._kicked = true;
1064
+ this._kickedPending = true;
1065
+ this._requestFreshMesh().catch((err) => {
1066
+ this._log?.error(['p2p', 'mesh'], 'kick-driven re-mint failed', err);
1067
+ });
1068
+ }
1069
+ async _requestFreshMesh() {
1070
+ if (this.closing || this._minting)
1071
+ return;
1072
+ this._minting = true;
1073
+ this._notifyStatus();
1074
+ try {
1075
+ this.emit('mesh-changed', await this._startMesh({ new: true }));
1076
+ }
1077
+ catch (err) {
1078
+ if (this.closing)
1079
+ return;
1080
+ if (!this._upgradeRequired) {
1081
+ this._statusError = statusErrorMessage('creating a new mesh failed', err);
1082
+ }
1083
+ if (!this.emit('mesh-error', err))
1084
+ throw err;
1085
+ }
1086
+ finally {
1087
+ this._minting = false;
1088
+ this._notifyStatus();
1089
+ }
1090
+ }
1091
+ _onClose(listener) {
1092
+ if (this._closeSignaled) {
1093
+ listener();
1094
+ return noop;
1095
+ }
1096
+ this._closeListeners.add(listener);
1097
+ return () => void this._closeListeners.delete(listener);
1098
+ }
1099
+ _waitForMeshChange() {
1100
+ return new Promise((resolve) => {
1101
+ let offClose = noop;
1102
+ const settle = (error) => {
1103
+ this.off('mesh-changed', onChanged);
1104
+ this.off('mesh-error', onError);
1105
+ offClose();
1106
+ resolve(error);
1107
+ };
1108
+ const onChanged = () => settle(null);
1109
+ const onError = (error) => settle(error);
1110
+ this.on('mesh-changed', onChanged);
1111
+ this.on('mesh-error', onError);
1112
+ offClose = this._onClose(onChanged);
1113
+ });
1114
+ }
1115
+ async joinMesh(rawInvite) {
1116
+ const invite = decodeMeshInvite(rawInvite);
1117
+ if (!invite)
1118
+ throw new Error('Invalid mesh invite');
1119
+ await this._awaitMesh();
1120
+ await this._meshTransitionLock.lock();
1121
+ let ownsTransition = false;
1122
+ try {
1123
+ if (this.closing)
1124
+ throw new Error('Core is closing');
1125
+ if (this._leaving || this._minting)
1126
+ throw new Error('Mesh transition already in progress');
1127
+ if (this._mesh?.key.equals(invite.baseKey) && this._mesh.writable)
1128
+ return;
1129
+ ownsTransition = true;
1130
+ this._minting = true;
1131
+ this._notifyStatus();
1132
+ await this._joinMesh(invite);
1133
+ }
1134
+ finally {
1135
+ if (ownsTransition)
1136
+ this._minting = false;
1137
+ this._meshTransitionLock.unlock();
1138
+ this._notifyStatus();
1139
+ this._departures?.flush(this._mesh?.key);
1140
+ }
1141
+ }
1142
+ cancelMeshJoin() {
1143
+ if (this._joinCancellation?.accepting)
1144
+ this._joinCancellation.canceled = true;
1145
+ this._cancelCandidateJoin?.();
1146
+ }
1147
+ _throwIfJoinCanceled() {
1148
+ if (this._joinCancellation?.canceled)
1149
+ throw new Error(MESH_JOIN_CANCELED);
1150
+ }
1151
+ async _joinMesh(invite) {
1152
+ const cancellation = { canceled: false, accepting: true };
1153
+ this._joinCancellation = cancellation;
1154
+ try {
1155
+ await this._runJoinMesh(invite);
1156
+ }
1157
+ finally {
1158
+ if (this._joinCancellation === cancellation)
1159
+ this._joinCancellation = null;
1160
+ }
1161
+ }
1162
+ async _runJoinMesh(invite) {
1163
+ const deviceId = this._deviceKeyPair.publicKey;
1164
+ const source = this._mesh;
1165
+ for (const node of invite.additionalNodes ?? [])
1166
+ this._swarm?.dht.addNode(node);
1167
+ await this._departures?.park(invite.baseKey);
1168
+ try {
1169
+ await this._joinParkedMesh(invite, source, deviceId);
1170
+ }
1171
+ finally {
1172
+ this._departures?.unpark(invite.baseKey);
1173
+ }
1174
+ }
1175
+ async _joinParkedMesh(invite, source, deviceId) {
1176
+ const session = this.local.createCandidateSession(invite.seed, invite.baseKey);
1177
+ let candidate;
1178
+ try {
1179
+ candidate = await this._openCandidateMesh(invite, session);
1180
+ }
1181
+ catch (error) {
1182
+ await this._discardCandidateMesh();
1183
+ throw error;
1184
+ }
1185
+ this._throwIfJoinCanceled();
1186
+ if (this._joinCancellation)
1187
+ this._joinCancellation.accepting = false;
1188
+ try {
1189
+ if (source && (await this._departureHasAudience(source))) {
1190
+ await this.local.recordDeparture(source.key);
1191
+ }
1192
+ await this.local.recordMesh(deviceId, candidate.key, session.seed, session.creator, session.writerSeed);
1193
+ }
1194
+ catch (error) {
1195
+ await this._discardCandidateMesh();
1196
+ throw error;
1197
+ }
1198
+ if (source) {
1199
+ await this._announceDeparture(source);
1200
+ await this._retireMesh(source).catch((error) => this._log?.warn(['p2p', 'mesh'], 'source mesh retirement failed', error));
1201
+ }
1202
+ if (this._blockedByMinVersion()) {
1203
+ await this._retireMesh(candidate).catch((err) => this._log?.warn(['p2p', 'mesh'], 'withholding the joined mesh failed', err));
1204
+ return;
1205
+ }
1206
+ this._activateMesh(candidate, session);
1207
+ void this._departures?.drop(candidate.key).catch(noop);
1208
+ void this._advertiseDeviceProfile(candidate, deviceId);
1209
+ void this._settleMembership(candidate, { migrate: true });
1210
+ this.emit('mesh-changed', candidate);
1211
+ }
1212
+ async _openCandidateMesh(invite, session) {
1213
+ this._throwIfJoinCanceled();
1214
+ const candidate = new Mesh(this.store, {
1215
+ seed: session.seed,
1216
+ key: session.baseKey ?? null,
1217
+ deviceId: this._deviceKeyPair.publicKey,
1218
+ writerSeed: session.writerSeed,
1219
+ logger: this._log,
1220
+ blindPeerKeys: this._resolveBlindPeerKeys(invite.blindPeers),
1221
+ blindPeeringOpts: this._blindPeeringOpts,
1222
+ bootFrom: invite.fastForward,
1223
+ wakeup: this._wakeup,
1224
+ attachmentUrl: this._attachmentUrl
1225
+ });
1226
+ this._candidateMesh = candidate;
1227
+ if (this._swarm)
1228
+ this._swarm.join(candidate.discoveryKey, { server: true, client: true });
1229
+ const onOpenCanceled = () => candidate.interruptBoot();
1230
+ this._cancelCandidateJoin = onOpenCanceled;
1231
+ const disarm = () => {
1232
+ if (this._cancelCandidateJoin === onOpenCanceled)
1233
+ this._cancelCandidateJoin = null;
1234
+ };
1235
+ try {
1236
+ await candidate.ready();
1237
+ }
1238
+ catch (error) {
1239
+ disarm();
1240
+ this._candidateMesh = null;
1241
+ if (this._swarm)
1242
+ await this._swarm.leave(candidate.discoveryKey).catch(noop);
1243
+ await candidate.close().catch(noop);
1244
+ throw this._joinCancellation?.canceled ? new Error(MESH_JOIN_CANCELED) : error;
1245
+ }
1246
+ if (this._swarm)
1247
+ candidate.startBlindPeering(this._swarm.dht);
1248
+ try {
1249
+ this._throwIfJoinCanceled();
1250
+ await candidate.appendBirthOp(this._deviceKeyPair.publicKey, this._localDevice ?? undefined);
1251
+ this._throwIfJoinCanceled();
1252
+ if (!candidate.key.equals(invite.baseKey)) {
1253
+ throw new Error('Device is not permitted to join the invited mesh');
1254
+ }
1255
+ if ((await candidate.checkResumedRevocation()) === 'kicked') {
1256
+ throw new Error('Device is not permitted to join the invited mesh');
1257
+ }
1258
+ this._throwIfJoinCanceled();
1259
+ disarm();
1260
+ await this._waitForCandidateWritable(candidate);
1261
+ if (!candidate.writable)
1262
+ throw new Error('Device is not permitted to join the invited mesh');
1263
+ this._throwIfJoinCanceled();
1264
+ return candidate;
1265
+ }
1266
+ catch (error) {
1267
+ await this._discardCandidateMesh();
1268
+ throw this._joinCancellation?.canceled ? new Error(MESH_JOIN_CANCELED) : error;
1269
+ }
1270
+ finally {
1271
+ disarm();
1272
+ }
1273
+ }
1274
+ async _waitForCandidateWritable(candidate) {
1275
+ if (candidate.writable)
1276
+ return;
1277
+ await new Promise((resolve, reject) => {
1278
+ let offClose = noop;
1279
+ const cleanup = () => {
1280
+ candidate.autobee.off('writable', onWritable);
1281
+ candidate.autobee.off('interrupt', onInterrupt);
1282
+ candidate.off('kicked', onKicked);
1283
+ offClose();
1284
+ if (this._cancelCandidateJoin === onCanceled)
1285
+ this._cancelCandidateJoin = null;
1286
+ };
1287
+ const onWritable = () => {
1288
+ cleanup();
1289
+ resolve();
1290
+ };
1291
+ const onKicked = () => {
1292
+ cleanup();
1293
+ reject(new Error('Device is not permitted to join the invited mesh'));
1294
+ };
1295
+ const onInterrupt = (reason) => {
1296
+ cleanup();
1297
+ reject(reason instanceof Error ? reason : new Error('Apply interrupted'));
1298
+ };
1299
+ const onCanceled = () => {
1300
+ cleanup();
1301
+ reject(new Error(MESH_JOIN_CANCELED));
1302
+ };
1303
+ this._cancelCandidateJoin = onCanceled;
1304
+ candidate.autobee.on('writable', onWritable);
1305
+ candidate.autobee.on('interrupt', onInterrupt);
1306
+ candidate.on('kicked', onKicked);
1307
+ offClose = this._onClose(onCanceled);
1308
+ });
1309
+ }
1310
+ _activateMesh(mesh, session) {
1311
+ if (this._candidateMesh === mesh)
1312
+ this._candidateMesh = null;
1313
+ this._mesh = mesh;
1314
+ this._meshSecretSeed = session.seed;
1315
+ this._statusError = null;
1316
+ this._upgradeRequired = null;
1317
+ void this._closeConfigPeering().catch(noop);
1318
+ if (mesh.writable)
1319
+ this._kicked = false;
1320
+ mesh.on('kicked', () => this._onKicked());
1321
+ mesh.on('unattested-device', () => void this._settleMembership(mesh));
1322
+ mesh.on('membership', (own) => void this._recordMembership(own));
1323
+ mesh.autobee.on('writable', this._onMeshWritable);
1324
+ mesh.autobee.on('error', this._onMeshDead);
1325
+ mesh.autobee.on('close', this._onMeshDead);
1326
+ mesh.autobee.on('interrupt', this._onMeshStalled);
1327
+ this._startMeshServices(mesh);
1328
+ this._notifyStatus();
1329
+ }
1330
+ _currentMesh() {
1331
+ return this._mesh;
1332
+ }
1333
+ async _awaitMesh() {
1334
+ if (this.closing)
1335
+ return null;
1336
+ if (!this.opened)
1337
+ await this.ready();
1338
+ return this._currentMesh();
1339
+ }
1340
+ _startMeshServices(mesh) {
1341
+ const deviceId = this._deviceKeyPair.publicKey;
1342
+ mesh.on('notification', (event) => this.emit('notification', event));
1343
+ void mesh.refreshMembership().catch((error) => {
1344
+ this._log?.warn(['p2p', 'mesh'], 'tallying membership failed', error);
1345
+ });
1346
+ mesh.on('chat-tombstone', (chatId, deletedAt) => {
1347
+ void this.local
1348
+ .clearChatNotify(chatId)
1349
+ .catch((error) => this._log?.warn(['p2p', 'mesh'], 'chat-tombstone notification reclaim failed', error));
1350
+ void removeChatAttachments(mesh, deviceId, chatId, deletedAt).catch((error) => this._log?.warn(['p2p', 'mesh'], 'chat-tombstone attachment reclaim failed', error));
1351
+ void removeChatKnowledge(mesh, chatId, deletedAt).catch((error) => this._log?.warn(['p2p', 'mesh'], 'chat-tombstone knowledge reclaim failed', error));
1352
+ });
1353
+ const sweepLock = new ScopeLock({ debounce: true });
1354
+ const sweep = async () => {
1355
+ if (!(await sweepLock.lock()))
1356
+ return;
1357
+ try {
1358
+ if (!mesh.closing)
1359
+ await mesh.files.sweepTombstones(deviceId);
1360
+ }
1361
+ catch (error) {
1362
+ this._log?.warn(['p2p', 'mesh'], 'blob sweep failed', error);
1363
+ }
1364
+ finally {
1365
+ sweepLock.unlock();
1366
+ }
1367
+ };
1368
+ void sweep();
1369
+ mesh.autobee.on('move-to', () => void sweep());
1370
+ this._startIndexing();
1371
+ this._hostedAgents = new HostedAgents({
1372
+ mesh,
1373
+ local: this.local,
1374
+ deviceId,
1375
+ catalog: () => this._hostSkills(),
1376
+ send: (host, request) => this._secretHandoff.send(host, request),
1377
+ onmoved: () => this._skillCatalog?.(null, null, { refresh: true }) ?? Promise.resolve(),
1378
+ log: this._log
1379
+ });
1380
+ this._hostedAgents.start();
1381
+ }
1382
+ async _stopHostedAgents() {
1383
+ const hosted = this._hostedAgents;
1384
+ this._hostedAgents = null;
1385
+ await hosted?.close();
1386
+ }
1387
+ async _discardCandidateMesh() {
1388
+ const candidate = this._candidateMesh;
1389
+ if (!candidate)
1390
+ return;
1391
+ this._candidateMesh = null;
1392
+ if (this._swarm)
1393
+ await this._swarm.leave(candidate.discoveryKey).catch(noop);
1394
+ await candidate.close().catch(noop);
1395
+ }
1396
+ async _departureHasAudience(mesh) {
1397
+ if (!mesh.writable)
1398
+ return false;
1399
+ const deviceId = this._deviceKeyPair.publicKey;
1400
+ const snap = mesh.view.snapshot();
1401
+ try {
1402
+ for await (const device of snap.find('@qvac/devices')) {
1403
+ if (!device.revoked && !device.id.equals(deviceId))
1404
+ return true;
1405
+ }
1406
+ return false;
1407
+ }
1408
+ finally {
1409
+ await snap.close();
1410
+ }
1411
+ }
1412
+ async _announceDeparture(mesh = this._mesh, strict = false) {
1413
+ if (!mesh?.writable) {
1414
+ if (strict)
1415
+ throw new Error('Mesh departure requires a writable source');
1416
+ return;
1417
+ }
1418
+ try {
1419
+ await mesh.dispatch('remove-writer', {
1420
+ writerKey: mesh.localWriterKey,
1421
+ deviceId: this._deviceKeyPair.publicKey,
1422
+ revokedAt: Date.now()
1423
+ });
1424
+ await mesh.autobee.update();
1425
+ }
1426
+ catch (error) {
1427
+ this._log?.warn(['p2p', 'mesh'], 'writer departure announcement failed', error);
1428
+ if (strict)
1429
+ throw error;
1430
+ }
1431
+ }
1432
+ async leaveMesh() {
1433
+ if (this.closing)
1434
+ return;
1435
+ const mesh = await this._awaitMesh();
1436
+ if (!mesh)
1437
+ return;
1438
+ if (this._leaving)
1439
+ return;
1440
+ if (this._minting)
1441
+ throw new Error('Mesh transition already in progress');
1442
+ this._leaving = true;
1443
+ this._notifyStatus();
1444
+ const landed = this._waitForMeshChange();
1445
+ try {
1446
+ if (await this._departureHasAudience(mesh))
1447
+ await this.local.recordDeparture(mesh.key);
1448
+ await this._announceDeparture();
1449
+ this._requestFreshMesh().catch(() => { });
1450
+ const error = await landed;
1451
+ if (error)
1452
+ throw error;
1453
+ }
1454
+ finally {
1455
+ this._leaving = false;
1456
+ this._notifyStatus();
1457
+ }
1458
+ }
1459
+ async removeDeviceWriter(writerKey, deviceId) {
1460
+ const mesh = await this._awaitMesh();
1461
+ if (!mesh)
1462
+ throw new Error('No active mesh');
1463
+ await mesh.dispatch('remove-writer', { writerKey, deviceId, revokedAt: Date.now() });
1464
+ }
1465
+ async renameLocalDevice(name) {
1466
+ const publicKey = this.devicePublicKey;
1467
+ if (publicKey)
1468
+ await this.local.renameDevice(publicKey, name);
1469
+ if (this._localDevice)
1470
+ this._localDevice = { ...this._localDevice, name };
1471
+ }
1472
+ async saveDeviceProfileLocal(capabilityProfile, recommendedModelName, platform) {
1473
+ const publicKey = this.devicePublicKey;
1474
+ if (publicKey) {
1475
+ await this.local.saveDeviceProfile(publicKey, capabilityProfile, recommendedModelName, platform);
1476
+ }
1477
+ if (this._localDevice) {
1478
+ this._localDevice = {
1479
+ ...this._localDevice,
1480
+ capabilityProfile,
1481
+ recommendedModelName,
1482
+ platform: platform ?? this._localDevice.platform
1483
+ };
1484
+ }
1485
+ }
1486
+ async waitForWritable() {
1487
+ if (this.closing)
1488
+ return;
1489
+ await this.ready();
1490
+ const mesh = await this._awaitMesh();
1491
+ if (this.closing || !mesh)
1492
+ return;
1493
+ await Promise.race([mesh.waitForWritable(), this._closeSignal]);
1494
+ }
1495
+ async getMeshInvite() {
1496
+ const mesh = await this._awaitMesh();
1497
+ if (!mesh || !this._meshSecretSeed)
1498
+ return null;
1499
+ const auto = mesh.autobee;
1500
+ const info = await auto.system.getInfo();
1501
+ const head = info && info.view.length > 0 ? await auto.trusted.mostRecentTrusted(auto.view, null) : null;
1502
+ const additionalNodes = this._swarm
1503
+ ? this._swarm.dht.toArray({ limit: INVITE_DHT_NODES_LIMIT })
1504
+ : [];
1505
+ const snap = mesh.view.snapshot();
1506
+ let blindPeerRows;
1507
+ try {
1508
+ blindPeerRows = await snap
1509
+ .find('@qvac/mesh-blind-peers', { limit: INVITE_BLIND_PEERS_LIMIT })
1510
+ .toArray();
1511
+ }
1512
+ finally {
1513
+ await snap.close();
1514
+ }
1515
+ return {
1516
+ baseKey: mesh.key,
1517
+ seed: this._meshSecretSeed,
1518
+ fastForward: head ? { key: head.key, length: head.length } : null,
1519
+ additionalNodes,
1520
+ blindPeers: blindPeerRows.map((row) => row.key)
1521
+ };
1522
+ }
1523
+ async _closeSwarm() {
1524
+ this._wakeup.destroy();
1525
+ this._secretHandoff.destroy();
1526
+ this._skillOverlayHandoff.destroy();
1527
+ if (!this._swarm)
1528
+ return;
1529
+ const swarm = this._swarm;
1530
+ this._swarm = null;
1531
+ for (const conn of swarm.connections)
1532
+ conn.destroy?.();
1533
+ await swarm.destroy();
1534
+ }
1535
+ async pushSkillSecret(request) {
1536
+ if (!this.opened)
1537
+ await this.ready();
1538
+ const mesh = this._mesh;
1539
+ const deviceId = this.devicePublicKey;
1540
+ if (!mesh || !deviceId)
1541
+ throw new Error(NOT_THE_HOST);
1542
+ const agent = await getAgent(mesh, request.agentId);
1543
+ if (!agent)
1544
+ throw new Error(NO_SUCH_AGENT);
1545
+ if (!agent.providerDeviceId)
1546
+ throw new Error(NOT_THE_HOST);
1547
+ if (agent.providerDeviceId.equals(deviceId)) {
1548
+ return this._storeHandedOffSecret(request, deviceId);
1549
+ }
1550
+ const host = await mesh.view.get('@qvac/devices', { id: agent.providerDeviceId });
1551
+ if (!host || host.revoked)
1552
+ throw new Error(HOST_REVOKED);
1553
+ return this._secretHandoff.send(agent.providerDeviceId, request);
1554
+ }
1555
+ async _storeHandedOffSecret(request, fromDeviceId) {
1556
+ const mesh = this._mesh;
1557
+ const deviceId = this.devicePublicKey;
1558
+ if (!mesh || !deviceId)
1559
+ throw new Error(NOT_THE_HOST);
1560
+ const receive = createSkillSecretReceiver({
1561
+ mesh,
1562
+ local: this.local,
1563
+ deviceId,
1564
+ setupFields: (skillName) => this._setupFields(skillName),
1565
+ onstored: () => this._skillCatalog?.(null, null, { refresh: true }) ?? Promise.resolve()
1566
+ });
1567
+ return receive(request, fromDeviceId);
1568
+ }
1569
+ async _skillOverlayOp(agentId, op) {
1570
+ const host = await this._resolveSkillOverlayHost(agentId);
1571
+ if (!host)
1572
+ return this._runLocalSkillOverlayOp(op);
1573
+ return this._skillOverlayHandoff.send(host, { ...op, agentId });
1574
+ }
1575
+ async _resolveSkillOverlayHost(agentId) {
1576
+ if (!agentId)
1577
+ return null;
1578
+ if (!this.opened)
1579
+ await this.ready();
1580
+ const mesh = this._mesh;
1581
+ const deviceId = this.devicePublicKey;
1582
+ if (!mesh || !deviceId)
1583
+ throw new Error(NOT_THE_HOST);
1584
+ const agent = await getAgent(mesh, agentId);
1585
+ if (!agent)
1586
+ throw new Error(NO_SUCH_AGENT);
1587
+ if (!agent.providerDeviceId)
1588
+ throw new Error(NOT_THE_HOST);
1589
+ if (agent.providerDeviceId.equals(deviceId))
1590
+ return null;
1591
+ const host = await mesh.view.get('@qvac/devices', { id: agent.providerDeviceId });
1592
+ if (!host || host.revoked)
1593
+ throw new Error(HOST_REVOKED);
1594
+ return agent.providerDeviceId;
1595
+ }
1596
+ async _serveSkillOverlayOp(op, fromDeviceId) {
1597
+ const mesh = this._mesh;
1598
+ const deviceId = this.devicePublicKey;
1599
+ if (!mesh || !deviceId)
1600
+ throw new Error(NOT_THE_HOST);
1601
+ const receive = createSkillOverlayReceiver({
1602
+ mesh,
1603
+ deviceId,
1604
+ runLocal: (op) => this._runLocalSkillOverlayOp(op)
1605
+ });
1606
+ return receive(op, fromDeviceId);
1607
+ }
1608
+ async _runLocalSkillOverlayOp(op) {
1609
+ const mgmt = this._skillManagement;
1610
+ switch (op.op) {
1611
+ case 'list':
1612
+ return { skills: ((await mgmt?.listManagedSkills()) ?? { skills: [] }).skills };
1613
+ case 'read': {
1614
+ const res = (await mgmt?.readSkillFile(op.name ?? '')) ?? { found: false };
1615
+ return { found: res.found ?? false, content: res.content, origin: res.origin };
1616
+ }
1617
+ case 'write':
1618
+ return {
1619
+ ok: ((await mgmt?.writeSkillFile(op.name ?? '', op.content ?? '')) ?? { ok: false }).ok
1620
+ };
1621
+ case 'copy':
1622
+ return {
1623
+ copied: ((await mgmt?.copySkillForEdit(op.name ?? '')) ?? { copied: false }).copied
1624
+ };
1625
+ case 'delete':
1626
+ return {
1627
+ removed: ((await mgmt?.deleteOverlaySkill(op.name ?? '')) ?? { removed: false }).removed
1628
+ };
1629
+ default:
1630
+ throw new Error(`unknown skill overlay op: ${op.op}`);
1631
+ }
1632
+ }
1633
+ async _setupFields(skillName) {
1634
+ const skills = await this._hostSkills();
1635
+ if (skills.length === 0)
1636
+ return null;
1637
+ const skill = skills.find((entry) => entry.name === skillName);
1638
+ if (!skill)
1639
+ return new Map();
1640
+ const fields = new Map();
1641
+ for (const slot of skill.credentials ?? []) {
1642
+ for (const key of slot.split('|')) {
1643
+ fields.set(key, true);
1644
+ const stateKey = oauthStateKeyFor(key);
1645
+ if (stateKey)
1646
+ fields.set(stateKey, true);
1647
+ }
1648
+ }
1649
+ for (const route of skill.setup?.routes ?? []) {
1650
+ if (route.credentialKey)
1651
+ fields.set(route.credentialKey, true);
1652
+ for (const field of route.fields ?? [])
1653
+ fields.set(field.key, field.secret === true);
1654
+ }
1655
+ return fields;
1656
+ }
1657
+ async _hostSkills() {
1658
+ await this._waitForCatalogHooks();
1659
+ const catalog = await this._skillCatalog?.(null, null, { skipCredentialProbe: true });
1660
+ return catalog?.skills ?? [];
1661
+ }
1662
+ _onConnection(conn) {
1663
+ if (this.closing) {
1664
+ conn.on('error', noop);
1665
+ return;
1666
+ }
1667
+ this._trackPeerConnection(conn);
1668
+ const remoteId = conn.remotePublicKey.toString('hex').slice(0, 8);
1669
+ const start = Date.now();
1670
+ let bytes = 0;
1671
+ let connErr = null;
1672
+ this._log?.info(['p2p', 'peer'], `got ${conn.isInitiator ? 'client' : 'server'} connection to ${remoteId}`);
1673
+ conn.once('error', (err) => {
1674
+ connErr = err;
1675
+ });
1676
+ conn.once('close', () => {
1677
+ this._log?.info(['p2p', 'peer'], `connection closed to ${remoteId}, with err: ${connErr} (${Date.now() - start} ms ${bytes} bytes recv)`);
1678
+ });
1679
+ conn.on('data', (data) => {
1680
+ bytes += data.byteLength;
1681
+ });
1682
+ this._wakeup.addStream(conn);
1683
+ this._secretHandoff.addStream(conn);
1684
+ this._skillOverlayHandoff.addStream(conn);
1685
+ this._hostedAgents?.kick();
1686
+ this.rootCorestore.replicate(conn);
1687
+ this._mesh?.files.reconnect();
1688
+ }
1689
+ _trackPeerConnection(conn) {
1690
+ this._peers.add(conn);
1691
+ this._onPeerChange();
1692
+ let removed = false;
1693
+ const remove = () => {
1694
+ if (removed)
1695
+ return;
1696
+ removed = true;
1697
+ this._peers.delete(conn);
1698
+ this._onPeerChange();
1699
+ };
1700
+ conn.once('close', remove);
1701
+ conn.once('error', remove);
1702
+ }
1703
+ _onPeerChange() {
1704
+ this._log?.info(['p2p', 'peer'], 'peer connections changed', {
1705
+ connections: this._peers.size,
1706
+ peers: this.peerDeviceIds.length
1707
+ });
1708
+ this._notifyStatus();
1709
+ }
1710
+ _meshStatusSource() {
1711
+ return {
1712
+ watch: (listener) => void this._statusListeners.add(listener),
1713
+ unwatch: (listener) => void this._statusListeners.delete(listener),
1714
+ snapshot: () => this._statusSnapshot(),
1715
+ leave: () => this.leaveMesh(),
1716
+ acknowledgeKicked: () => this.acknowledgeKicked(),
1717
+ join: (invite) => this.joinMesh(invite),
1718
+ cancelJoin: () => this.cancelMeshJoin(),
1719
+ invite: async () => {
1720
+ const invite = await this.getMeshInvite();
1721
+ return invite ? encodeMeshInvite(invite) : null;
1722
+ }
1723
+ };
1724
+ }
1725
+ _networkStatusSource() {
1726
+ const listeners = new Set();
1727
+ let timer = null;
1728
+ return {
1729
+ watch: (listener) => {
1730
+ listeners.add(listener);
1731
+ if (timer)
1732
+ return;
1733
+ timer = setInterval(() => {
1734
+ for (const fn of listeners)
1735
+ fn();
1736
+ }, DIAGNOSTICS_SAMPLE_MS);
1737
+ unref(timer);
1738
+ },
1739
+ unwatch: (listener) => {
1740
+ listeners.delete(listener);
1741
+ if (listeners.size === 0 && timer) {
1742
+ clearInterval(timer);
1743
+ timer = null;
1744
+ }
1745
+ },
1746
+ snapshot: () => this._networkSnapshot()
1747
+ };
1748
+ }
1749
+ _networkSnapshot() {
1750
+ const dht = this._swarm ? this._swarm.dht : null;
1751
+ return {
1752
+ state: this._networkState(dht),
1753
+ peerCount: this.peerDeviceIds.length
1754
+ };
1755
+ }
1756
+ _networkState(dht) {
1757
+ if (!dht?.online)
1758
+ return 'offline';
1759
+ if (dht.degraded)
1760
+ return 'degraded';
1761
+ return 'online';
1762
+ }
1763
+ _logSource() {
1764
+ const log = this._log;
1765
+ if (!log)
1766
+ return null;
1767
+ return {
1768
+ backfill: () => log.backfill(),
1769
+ subscribe: (listener) => log.subscribe(listener),
1770
+ unsubscribe: (listener) => log.unsubscribe(listener),
1771
+ write: (input) => log.appendClient({ ...input, originDeviceId: this.devicePublicKey ?? undefined })
1772
+ };
1773
+ }
1774
+ compact(force = false) {
1775
+ if (!force) {
1776
+ return this.storage.compact();
1777
+ }
1778
+ return this.storage.compact({
1779
+ blobGarbageCollectionPolicy: RocksConstants.garbageCollectionPolicy.FORCE,
1780
+ blobGarbageCollectionAgeCutoff: 1.0,
1781
+ bottommostLevelCompaction: RocksConstants.bottommostLevelCompaction.FORCE
1782
+ });
1783
+ }
1784
+ registerDiagnostics(provider) {
1785
+ this._diagnosticsProviders.add(provider);
1786
+ return () => void this._diagnosticsProviders.delete(provider);
1787
+ }
1788
+ registerListModels(hook) {
1789
+ this._listModels = hook;
1790
+ return () => {
1791
+ if (this._listModels === hook)
1792
+ this._listModels = null;
1793
+ };
1794
+ }
1795
+ registerDeleteModel(hook) {
1796
+ this._deleteModel = hook;
1797
+ return () => {
1798
+ if (this._deleteModel === hook)
1799
+ this._deleteModel = null;
1800
+ };
1801
+ }
1802
+ registerClearKvCache(hook) {
1803
+ this._clearKvCache = hook;
1804
+ return () => {
1805
+ if (this._clearKvCache === hook)
1806
+ this._clearKvCache = null;
1807
+ };
1808
+ }
1809
+ registerDeleteChatKvCache(hook) {
1810
+ this._deleteChatKvCache = hook;
1811
+ return () => {
1812
+ if (this._deleteChatKvCache === hook)
1813
+ this._deleteChatKvCache = null;
1814
+ };
1815
+ }
1816
+ registerCompactChat(hook) {
1817
+ this._compactChat = hook;
1818
+ return () => {
1819
+ if (this._compactChat === hook)
1820
+ this._compactChat = null;
1821
+ };
1822
+ }
1823
+ registerModelCatalogWatch(hook) {
1824
+ this._modelCatalogWatch = hook;
1825
+ this._openModelCatalogWatchSource();
1826
+ return () => {
1827
+ if (this._modelCatalogWatch !== hook)
1828
+ return;
1829
+ this._modelCatalogWatch = null;
1830
+ if (!this.closing)
1831
+ this._resetModelCatalogWatchSource();
1832
+ };
1833
+ }
1834
+ async *_watchModelCatalog() {
1835
+ while (!this.closing) {
1836
+ const source = this._modelCatalogWatchSource;
1837
+ try {
1838
+ await source.ready();
1839
+ }
1840
+ catch {
1841
+ return;
1842
+ }
1843
+ const watch = this._modelCatalogWatch;
1844
+ if (!watch)
1845
+ continue;
1846
+ yield* watch();
1847
+ return;
1848
+ }
1849
+ }
1850
+ _openModelCatalogWatchSource() {
1851
+ if (!this._modelCatalogWatch || !this._modelCatalogWatchSource.enter())
1852
+ return;
1853
+ this._modelCatalogWatchSource.exit();
1854
+ }
1855
+ _resetModelCatalogWatchSource() {
1856
+ this._modelCatalogWatchSource = new ReadyGuard();
1857
+ void this._modelCatalogWatchSource.ready().catch(noop);
1858
+ }
1859
+ registerRetryModelDownload(hook) {
1860
+ this._retryModelDownload = hook;
1861
+ return () => {
1862
+ if (this._retryModelDownload === hook)
1863
+ this._retryModelDownload = null;
1864
+ };
1865
+ }
1866
+ registerSkills(hook) {
1867
+ this._skills = hook;
1868
+ return () => {
1869
+ if (this._skills === hook)
1870
+ this._skills = null;
1871
+ };
1872
+ }
1873
+ registerSkillCatalog(hook) {
1874
+ this._skillCatalog = hook;
1875
+ this._openCatalogHooks();
1876
+ return () => {
1877
+ if (this._skillCatalog === hook)
1878
+ this._skillCatalog = null;
1879
+ };
1880
+ }
1881
+ registerSkillManagement(hooks) {
1882
+ this._skillManagement = hooks;
1883
+ return () => {
1884
+ if (this._skillManagement === hooks)
1885
+ this._skillManagement = null;
1886
+ };
1887
+ }
1888
+ async _waitForCatalogHooks() {
1889
+ if (!this._hostsModelSource)
1890
+ return;
1891
+ await this._catalogHooks.ready();
1892
+ }
1893
+ _catalogHooksReady() {
1894
+ if (!this._hostsModelSource)
1895
+ return true;
1896
+ return this._skillCatalog !== null && this._tools !== null;
1897
+ }
1898
+ _openCatalogHooks() {
1899
+ if (!this._catalogHooksReady() || !this._catalogHooks.enter())
1900
+ return;
1901
+ this._catalogHooks.exit();
1902
+ }
1903
+ registerTools(hook) {
1904
+ this._tools = hook;
1905
+ this._openCatalogHooks();
1906
+ return () => {
1907
+ if (this._tools === hook)
1908
+ this._tools = null;
1909
+ };
1910
+ }
1911
+ registerEmbedder(embedder, extractors) {
1912
+ this._embedder = embedder;
1913
+ this._ragExtractors = extractors ?? this._ragExtractors;
1914
+ this._vectorIndex = this._vectorIndex ?? new MemoryVectorIndex();
1915
+ const settled = this._reconcileIndexing();
1916
+ settled.catch((err) => this._log?.warn(['indexing'], 'reconcile failed', err));
1917
+ return () => {
1918
+ if (this._embedder !== embedder)
1919
+ return settled;
1920
+ this._embedder = null;
1921
+ return this._reconcileIndexing();
1922
+ };
1923
+ }
1924
+ async _reconcileIndexing() {
1925
+ await this._indexingLock.lock();
1926
+ try {
1927
+ if (this.closing)
1928
+ return;
1929
+ if (this._indexedEmbedder && this._indexedEmbedder !== this._embedder) {
1930
+ await this._stopIndexing();
1931
+ }
1932
+ this._startIndexing();
1933
+ }
1934
+ finally {
1935
+ this._indexingLock.unlock();
1936
+ }
1937
+ }
1938
+ _startIndexing() {
1939
+ if (!this._mesh || !this._embedder || this._processingFiles)
1940
+ return;
1941
+ this._vectorIndex ??= new MemoryVectorIndex();
1942
+ this._processingFiles = this._mesh.files;
1943
+ this._processingFiles.startProcessing({
1944
+ embedder: this._embedder,
1945
+ index: this._vectorIndex,
1946
+ deviceId: this.devicePublicKey,
1947
+ extractors: this._ragExtractors
1948
+ });
1949
+ this._indexedEmbedder = this._embedder;
1950
+ }
1951
+ async _stopIndexing() {
1952
+ this._indexedEmbedder = null;
1953
+ if (this._processingFiles && !(await this._processingFiles.stopProcessing())) {
1954
+ this._vectorIndex = null;
1955
+ }
1956
+ this._processingFiles = null;
1957
+ }
1958
+ registerTranscribe(hook) {
1959
+ this._transcribe = hook;
1960
+ return () => {
1961
+ if (this._transcribe === hook)
1962
+ this._transcribe = null;
1963
+ };
1964
+ }
1965
+ registerSpeak(hook) {
1966
+ this._speak = hook;
1967
+ return () => {
1968
+ if (this._speak === hook)
1969
+ this._speak = null;
1970
+ };
1971
+ }
1972
+ registerSpeakStream(hook) {
1973
+ this._speakStream = hook;
1974
+ return () => {
1975
+ if (this._speakStream === hook)
1976
+ this._speakStream = null;
1977
+ };
1978
+ }
1979
+ _diagnosticsSource() {
1980
+ const listeners = new Set();
1981
+ let timer = null;
1982
+ return {
1983
+ watch: (listener) => {
1984
+ listeners.add(listener);
1985
+ if (timer)
1986
+ return;
1987
+ timer = setInterval(() => {
1988
+ for (const fn of listeners)
1989
+ fn();
1990
+ }, DIAGNOSTICS_SAMPLE_MS);
1991
+ unref(timer);
1992
+ },
1993
+ unwatch: (listener) => {
1994
+ listeners.delete(listener);
1995
+ if (listeners.size === 0 && timer) {
1996
+ clearInterval(timer);
1997
+ timer = null;
1998
+ }
1999
+ },
2000
+ snapshot: () => {
2001
+ const merged = { ...this._diagnostics() };
2002
+ for (const provider of this._diagnosticsProviders)
2003
+ Object.assign(merged, provider());
2004
+ return merged;
2005
+ }
2006
+ };
2007
+ }
2008
+ _memberDiagnostics(mesh) {
2009
+ const memberId = mesh.ourMemberId?.toString('hex') ?? null;
2010
+ return {
2011
+ ...mesh.membership,
2012
+ memberId,
2013
+ mintedOurRoot: memberId !== null && memberId === this._identityPublicKey
2014
+ };
2015
+ }
2016
+ _diagnostics() {
2017
+ const mesh = this._mesh;
2018
+ const swarm = this._swarm;
2019
+ const dht = swarm ? swarm.dht : null;
2020
+ const system = this._systemInfo?.snapshot() ?? { cpu: null, gpu: null };
2021
+ const publicKey = this.devicePublicKey?.toString('hex');
2022
+ const device = this._localDevice;
2023
+ return {
2024
+ device: publicKey,
2025
+ deviceInfo: device && publicKey
2026
+ ? {
2027
+ publicKey,
2028
+ name: device.name,
2029
+ capabilityProfile: device.capabilityProfile,
2030
+ recommendedModelName: device.recommendedModelName
2031
+ }
2032
+ : null,
2033
+ state: this._statusState(),
2034
+ mesh: mesh
2035
+ ? {
2036
+ key: mesh.key.toString('hex'),
2037
+ discoveryKey: mesh.discoveryKey.toString('hex'),
2038
+ writable: mesh.writable,
2039
+ localLength: mesh.localLength,
2040
+ systemLength: mesh.autobee.system.bee.head()?.length ?? 0,
2041
+ viewLength: mesh.view.db.head()?.length ?? 0,
2042
+ flushes: mesh.autobee.system.flushes,
2043
+ fastForwards: mesh.autobee.stats.fastForwards,
2044
+ member: this._memberDiagnostics(mesh),
2045
+ orphanedBlobSweep: mesh.orphanedBlobSweepStatus,
2046
+ blindPeerCount: mesh.blindPeerKeys.length,
2047
+ blindPeers: mesh.blindPeerStats()
2048
+ }
2049
+ : null,
2050
+ network: dht
2051
+ ? {
2052
+ online: dht.online ?? null,
2053
+ degraded: dht.degraded ?? null,
2054
+ nodes: dht.nodes?.length ?? 0,
2055
+ host: dht.host,
2056
+ port: dht.port,
2057
+ connections: this._peers.size,
2058
+ peers: this.peerDeviceIds.length,
2059
+ stats: dht.stats,
2060
+ health: dht.health?.stats ?? null,
2061
+ config: dht.config ?? null
2062
+ }
2063
+ : null,
2064
+ process: top.toJSON(),
2065
+ cpu: system.cpu,
2066
+ gpu: system.gpu
2067
+ };
2068
+ }
2069
+ _statusSnapshot() {
2070
+ const peerDeviceIds = [...this.peerDeviceIds];
2071
+ const mesh = this._mesh;
2072
+ return {
2073
+ state: this._statusState(),
2074
+ writable: mesh?.writable ?? false,
2075
+ peerCount: peerDeviceIds.length,
2076
+ peerDeviceIds,
2077
+ meshKey: mesh?.key,
2078
+ discoveryKey: mesh?.discoveryKey,
2079
+ kickedPending: this._kickedPending,
2080
+ error: this._statusError ?? undefined
2081
+ };
2082
+ }
2083
+ acknowledgeKicked() {
2084
+ if (!this._kickedPending)
2085
+ return;
2086
+ this._kickedPending = false;
2087
+ this._notifyStatus();
2088
+ }
2089
+ _statusState() {
2090
+ if (this._statusError)
2091
+ return 'error';
2092
+ if (this.closing || this._leaving)
2093
+ return 'leaving';
2094
+ if (this._kicked)
2095
+ return 'kicked';
2096
+ if (this._upgradeRequired)
2097
+ return 'needs-upgrade';
2098
+ if (this._minting)
2099
+ return 'joining';
2100
+ if (this._mesh)
2101
+ return this._mesh.writable ? 'joined' : 'joining';
2102
+ return 'idle';
2103
+ }
2104
+ _notifyStatus() {
2105
+ for (const listener of [...this._statusListeners])
2106
+ listener();
2107
+ }
2108
+ }
2109
+ function noop() { }
2110
+ async function closeConfigReader(reader) {
2111
+ if (!reader)
2112
+ return;
2113
+ await reader.core.close().catch(noop);
2114
+ await reader.close().catch(noop);
2115
+ }
2116
+ async function recordedBlockIsLocal(core) {
2117
+ await raceResource(core, core.ready(), 'config core');
2118
+ const length = Number((await raceResource(core, core.getUserData('hyperconf'), 'config core')) || '0');
2119
+ if (length <= 0)
2120
+ return true;
2121
+ return raceResource(core, core.has(length - 1), 'config core');
2122
+ }
2123
+ function statusErrorMessage(context, err) {
2124
+ const detail = err instanceof Error ? err.message : err ? String(err) : '';
2125
+ return detail ? `${context}: ${detail}` : context;
2126
+ }