@remnic/core 9.63.0 → 9.63.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/dist/access-admin-ops-surface.d.ts +1 -1
  2. package/dist/access-admin-ops-surface.js +34 -33
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +1 -1
  5. package/dist/access-authorization-probe.js +35 -34
  6. package/dist/access-boundary.d.ts +1 -1
  7. package/dist/access-boundary.js +34 -33
  8. package/dist/access-cli.js +99 -97
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +1 -1
  11. package/dist/access-extraction-force-flush.js +34 -33
  12. package/dist/access-http-lcm-compaction.d.ts +1 -1
  13. package/dist/access-http-lifecycle-flush.d.ts +1 -1
  14. package/dist/access-http-offline-stream.d.ts +1 -1
  15. package/dist/access-http-query.js +34 -33
  16. package/dist/access-http.d.ts +2 -2
  17. package/dist/access-http.js +47 -46
  18. package/dist/access-identity-continuity-surface.js +34 -33
  19. package/dist/access-lcm-surface.d.ts +1 -1
  20. package/dist/access-lcm-surface.js +34 -33
  21. package/dist/access-mcp.d.ts +1 -1
  22. package/dist/access-mcp.js +40 -39
  23. package/dist/access-namespace-preflight.js +34 -33
  24. package/dist/access-observe-write-surface.d.ts +1 -1
  25. package/dist/access-observe-write-surface.js +34 -33
  26. package/dist/access-operations-batch.js +35 -34
  27. package/dist/access-operations.d.ts +4 -4
  28. package/dist/access-operations.js +39 -38
  29. package/dist/access-recall-concurrency.d.ts +1 -1
  30. package/dist/access-recall-concurrency.js +34 -33
  31. package/dist/access-recall-response.d.ts +1 -1
  32. package/dist/access-recall-response.js +34 -33
  33. package/dist/access-recall-surface.d.ts +1 -1
  34. package/dist/access-recall-surface.js +34 -33
  35. package/dist/access-schema.d.ts +88 -88
  36. package/dist/access-schema.js +3 -3
  37. package/dist/access-service-helpers.d.ts +1 -1
  38. package/dist/access-service.d.ts +1 -1
  39. package/dist/access-service.js +34 -33
  40. package/dist/access-surface-catalog.d.ts +1 -1
  41. package/dist/access-surface-catalog.js +36 -35
  42. package/dist/access-surface-catalog.js.map +1 -1
  43. package/dist/adapters/index.js +7 -7
  44. package/dist/adapters/registry.js +3 -3
  45. package/dist/{auto-sync-Z52VWMNC.js → auto-sync-BKRJDMKX.js} +3 -3
  46. package/dist/behavior-learner.js +2 -2
  47. package/dist/briefing.js +15 -15
  48. package/dist/buffer.js +5 -4
  49. package/dist/causal-behavior.js +3 -3
  50. package/dist/causal-chain.js +3 -3
  51. package/dist/causal-consolidation.js +18 -18
  52. package/dist/causal-retrieval.js +3 -3
  53. package/dist/causal-trajectory.js +2 -2
  54. package/dist/{chunk-5F6HMNMZ.js → chunk-2LA3H54D.js} +2 -2
  55. package/dist/{chunk-IRLH4NM2.js → chunk-2PSX5BJU.js} +3 -3
  56. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  57. package/dist/{chunk-IZRNVNPV.js → chunk-3LJ2L3T3.js} +2 -2
  58. package/dist/{chunk-CLJ5QS6J.js → chunk-44KHFMCM.js} +72 -64
  59. package/dist/{chunk-CLJ5QS6J.js.map → chunk-44KHFMCM.js.map} +1 -1
  60. package/dist/{chunk-JDI7G6EA.js → chunk-4NMVX5U7.js} +2 -2
  61. package/dist/{chunk-WFLBP5GC.js → chunk-4NZHHGVL.js} +25 -6
  62. package/dist/chunk-4NZHHGVL.js.map +1 -0
  63. package/dist/{chunk-ANMIOQPU.js → chunk-4XN35YQD.js} +478 -164
  64. package/dist/chunk-4XN35YQD.js.map +1 -0
  65. package/dist/{chunk-LJOIZPJH.js → chunk-5QZR2RA3.js} +2 -2
  66. package/dist/{chunk-FF6E6HOT.js → chunk-5UFQCU6M.js} +32 -32
  67. package/dist/{chunk-4HO3542O.js → chunk-5W5N7XJZ.js} +2 -2
  68. package/dist/{chunk-4Y2RHVCV.js → chunk-5W62VEFH.js} +4 -4
  69. package/dist/{chunk-DEOYTFA6.js → chunk-645WOU5I.js} +4 -52
  70. package/dist/chunk-645WOU5I.js.map +1 -0
  71. package/dist/{chunk-LTJTP5YQ.js → chunk-6D7PZKCJ.js} +10 -10
  72. package/dist/{chunk-BBHFAVMP.js → chunk-6F2UMP4H.js} +7 -7
  73. package/dist/{chunk-IIPJKCZB.js → chunk-6NAPOLRO.js} +3 -3
  74. package/dist/{chunk-CK3NQUSQ.js → chunk-6UZR7KEK.js} +2 -2
  75. package/dist/{chunk-2TYIAKU5.js → chunk-6YMEU6OQ.js} +2 -2
  76. package/dist/{chunk-H23GIXJC.js → chunk-A73QHOZP.js} +2 -2
  77. package/dist/{chunk-LLGDVG52.js → chunk-AJSZ2EK6.js} +3 -3
  78. package/dist/{chunk-HVKMJAEF.js → chunk-B2OOJCUX.js} +2 -2
  79. package/dist/chunk-BUYVPUEM.js +66 -0
  80. package/dist/chunk-BUYVPUEM.js.map +1 -0
  81. package/dist/{chunk-YTHQHH5U.js → chunk-C6WMSXCJ.js} +2 -2
  82. package/dist/{chunk-JKW663ZN.js → chunk-CIAI24TQ.js} +2 -2
  83. package/dist/{chunk-PD6O7AXF.js → chunk-CSAKJVXW.js} +14 -17
  84. package/dist/chunk-CSAKJVXW.js.map +1 -0
  85. package/dist/{chunk-EFWHCTYJ.js → chunk-DNRTKO2U.js} +2 -2
  86. package/dist/{chunk-QCECHYZL.js → chunk-E2GYBTSP.js} +24 -4
  87. package/dist/chunk-E2GYBTSP.js.map +1 -0
  88. package/dist/{chunk-4IZ2IT7D.js → chunk-EJLTNPRY.js} +3 -3
  89. package/dist/{chunk-JCJGYNIS.js → chunk-EJQXDKYK.js} +4 -4
  90. package/dist/{chunk-347ZR6D4.js → chunk-FKJVEW6O.js} +2 -2
  91. package/dist/{chunk-DROAPP6N.js → chunk-GFNS3BHV.js} +3 -3
  92. package/dist/{chunk-ALNZEWGN.js → chunk-GPFZFCRN.js} +2 -2
  93. package/dist/{chunk-KPML4Q3M.js → chunk-GTRGH4ZT.js} +3 -3
  94. package/dist/{chunk-TIRJV2LW.js → chunk-I6OQCT3Y.js} +2 -2
  95. package/dist/{chunk-CH627RRV.js → chunk-IKXUG6KC.js} +8 -8
  96. package/dist/{chunk-HSBQJRV2.js → chunk-IM56VPKO.js} +3 -3
  97. package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
  98. package/dist/{chunk-BP6WMYLP.js → chunk-ITYAXU4S.js} +3 -3
  99. package/dist/{chunk-4FFROSFG.js → chunk-JJ7JW62R.js} +23 -23
  100. package/dist/{chunk-RFH7U5LT.js → chunk-JJX5XEIG.js} +2 -2
  101. package/dist/{chunk-CALURYWR.js → chunk-JWPG65LH.js} +14 -14
  102. package/dist/chunk-K2XUWZBM.js +417 -0
  103. package/dist/chunk-K2XUWZBM.js.map +1 -0
  104. package/dist/{chunk-G2FCSILA.js → chunk-KWIGDKM2.js} +2 -2
  105. package/dist/{chunk-WR2YKUIW.js → chunk-KWN6NOHQ.js} +2 -2
  106. package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
  107. package/dist/{chunk-WMOJIOIG.js → chunk-LZCSOUJ7.js} +2 -2
  108. package/dist/{chunk-256FBCVX.js → chunk-M4AHBM72.js} +7 -7
  109. package/dist/{chunk-5PFGMO33.js → chunk-MEW53VQJ.js} +2 -2
  110. package/dist/{chunk-DCUMFQYM.js → chunk-ML3U4KPR.js} +2 -2
  111. package/dist/{chunk-X6E7TT3A.js → chunk-MR5HWQHS.js} +2 -2
  112. package/dist/{chunk-H7PRHUBD.js → chunk-NRLELHAY.js} +2 -2
  113. package/dist/{chunk-ZS4JADYY.js → chunk-OW7NVMGQ.js} +2 -2
  114. package/dist/{chunk-TGSMU3F2.js → chunk-PADG72LJ.js} +3 -3
  115. package/dist/{chunk-6GGTATZF.js → chunk-PYIR4SSB.js} +4 -4
  116. package/dist/chunk-PYIR4SSB.js.map +1 -0
  117. package/dist/{chunk-UDTME32W.js → chunk-Q35XGIEM.js} +2 -2
  118. package/dist/{chunk-XPRJSHNI.js → chunk-QJ622LTI.js} +6 -3
  119. package/dist/chunk-QJ622LTI.js.map +1 -0
  120. package/dist/{chunk-AYIHDC5S.js → chunk-QSIQVC32.js} +2 -2
  121. package/dist/{chunk-3MA7JVXN.js → chunk-R74NCKEY.js} +4 -4
  122. package/dist/{chunk-QCI73Z7C.js → chunk-RYGJGXL6.js} +2 -2
  123. package/dist/{chunk-4OW2T32G.js → chunk-SQ3EGGII.js} +2 -2
  124. package/dist/{chunk-ZPGHA7EO.js → chunk-TRPX6F2G.js} +10 -10
  125. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  126. package/dist/{chunk-7BJYTX6Q.js → chunk-VAMQU4W7.js} +2 -2
  127. package/dist/{chunk-YSR3DXGC.js → chunk-VN7IIQGS.js} +2 -2
  128. package/dist/{chunk-DTLF2SLZ.js → chunk-WDUG2CH3.js} +2 -2
  129. package/dist/{chunk-YIIC5IDU.js → chunk-X4MGNVOO.js} +2 -2
  130. package/dist/{chunk-BHO6RHE5.js → chunk-XFCQIQQU.js} +3 -3
  131. package/dist/{chunk-PSNN25DW.js → chunk-XZPSBGHA.js} +2 -2
  132. package/dist/{chunk-PMRUMGK6.js → chunk-Y7COCXY2.js} +2 -2
  133. package/dist/{chunk-DJ7HMNSL.js → chunk-YCVB7X56.js} +4 -2
  134. package/dist/chunk-YCVB7X56.js.map +1 -0
  135. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  136. package/dist/{chunk-JFLKSD5V.js → chunk-Z334TJRB.js} +2 -2
  137. package/dist/{cli-Bw9z-KqX.d.ts → cli-DJwNNDL1.d.ts} +1 -1
  138. package/dist/cli.d.ts +2 -2
  139. package/dist/cli.js +68 -67
  140. package/dist/coding/pre-action-gate.js +3 -3
  141. package/dist/compounding/engine.js +15 -15
  142. package/dist/connectors/codex-materialize-runner.js +15 -15
  143. package/dist/connectors/index.d.ts +45 -1
  144. package/dist/connectors/index.js +24 -16
  145. package/dist/convergence-refresh.js +17 -17
  146. package/dist/conversation-index/backend.js +2 -2
  147. package/dist/corpus-watermark.js +17 -17
  148. package/dist/dashboard-runtime.js +2 -2
  149. package/dist/direct-answer-wiring.js +3 -3
  150. package/dist/direct-answer.js +2 -2
  151. package/dist/entity-retrieval.js +15 -15
  152. package/dist/event-order-query.d.ts +3 -0
  153. package/dist/event-order-query.js +9 -0
  154. package/dist/event-order-query.js.map +1 -0
  155. package/dist/event-order-recall.d.ts +2 -2
  156. package/dist/event-order-recall.js +5 -2
  157. package/dist/external-wiki-access.d.ts +1 -1
  158. package/dist/external-wiki-access.js +35 -34
  159. package/dist/external-wiki-mcp-tools.d.ts +1 -1
  160. package/dist/extraction-normalization.js +2 -2
  161. package/dist/extraction.js +25 -24
  162. package/dist/harmonic-construction.js +2 -2
  163. package/dist/harmonic-retrieval.js +2 -2
  164. package/dist/index.d.ts +683 -682
  165. package/dist/index.js +108 -105
  166. package/dist/intent.js +2 -1
  167. package/dist/lcm/engine.js +3 -3
  168. package/dist/lcm/index.js +6 -6
  169. package/dist/maintenance/memory-governance.js +15 -15
  170. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +15 -15
  171. package/dist/maintenance/rebuild-memory-projection.js +16 -16
  172. package/dist/mcp-memory-inspector-app.d.ts +1 -1
  173. package/dist/namespaces/migrate.js +16 -16
  174. package/dist/namespaces/search.js +10 -10
  175. package/dist/namespaces/storage.js +15 -15
  176. package/dist/operator-doctor-corpus.js +18 -18
  177. package/dist/operator-toolkit.js +22 -22
  178. package/dist/orchestration/maintenance.js +20 -20
  179. package/dist/orchestrator.js +101 -99
  180. package/dist/policy-runtime.js +3 -3
  181. package/dist/{public-http-DK-QwaBu.d.ts → public-http-43z1YT-k.d.ts} +1 -1
  182. package/dist/{qmd-D_62bYNl.d.ts → qmd-CBSxevyb.d.ts} +12 -1
  183. package/dist/qmd-preflight.d.ts +1 -1
  184. package/dist/qmd.d.ts +1 -1
  185. package/dist/qmd.js +3 -1
  186. package/dist/recall-planner-i18n.d.ts +31 -0
  187. package/dist/recall-planner-i18n.js +30 -0
  188. package/dist/recall-planner-i18n.js.map +1 -0
  189. package/dist/recall-planner-llm.js +2 -1
  190. package/dist/recall-planner-llm.js.map +1 -1
  191. package/dist/recall-query-policy.js +2 -2
  192. package/dist/recall-tokenization.js +1 -1
  193. package/dist/resume-bundles.js +3 -3
  194. package/dist/retrieval-agents.d.ts +1 -1
  195. package/dist/retrieval-agents.js +2 -1
  196. package/dist/schemas.d.ts +117 -434
  197. package/dist/schemas.js +1 -1
  198. package/dist/search/factory.js +9 -9
  199. package/dist/search/index.js +15 -15
  200. package/dist/search/orama-backend.js +2 -2
  201. package/dist/semantic-consolidation.js +16 -16
  202. package/dist/semantic-rule-promotion.js +15 -15
  203. package/dist/semantic-rule-verifier.js +15 -15
  204. package/dist/shared-context/manager.d.ts +8 -8
  205. package/dist/source-agent-qualifier.js +21 -20
  206. package/dist/storage.js +14 -14
  207. package/dist/support-passport/index.d.ts +4 -4
  208. package/dist/support-passport/index.js +37 -36
  209. package/dist/transfer/autodetect.js +1 -1
  210. package/dist/transfer/backup.js +1 -1
  211. package/dist/transfer/capsule-export.js +2 -2
  212. package/dist/transfer/types.d.ts +66 -66
  213. package/dist/trust-zones.js +2 -2
  214. package/dist/verified-recall.js +15 -15
  215. package/dist/work-product-ledger.js +2 -2
  216. package/package.json +2 -2
  217. package/src/connectors/droid-mcp.ts +434 -0
  218. package/src/connectors/index.ts +70 -0
  219. package/src/direct-answer.ts +6 -3
  220. package/src/event-order-query.ts +78 -0
  221. package/src/event-order-recall.ts +4 -90
  222. package/src/intent.ts +19 -19
  223. package/src/orchestration/turn-ingestion.ts +24 -1
  224. package/src/orchestrator-flush.test.ts +142 -1
  225. package/src/qmd-process-group.test.ts +125 -0
  226. package/src/qmd.ts +30 -2
  227. package/src/recall-planner-i18n.ts +193 -0
  228. package/src/recall-tokenization.ts +3 -1
  229. package/src/retrieval-agents.ts +6 -10
  230. package/src/schemas.test.ts +158 -0
  231. package/src/schemas.ts +45 -22
  232. package/dist/chunk-6GGTATZF.js.map +0 -1
  233. package/dist/chunk-ANMIOQPU.js.map +0 -1
  234. package/dist/chunk-DEOYTFA6.js.map +0 -1
  235. package/dist/chunk-DJ7HMNSL.js.map +0 -1
  236. package/dist/chunk-PD6O7AXF.js.map +0 -1
  237. package/dist/chunk-QCECHYZL.js.map +0 -1
  238. package/dist/chunk-WFLBP5GC.js.map +0 -1
  239. package/dist/chunk-XPRJSHNI.js.map +0 -1
  240. package/dist/{access-service-M4LgO141.d.ts → access-service-DBpEnlzA.d.ts} +64 -64
  241. /package/dist/{auto-sync-Z52VWMNC.js.map → auto-sync-BKRJDMKX.js.map} +0 -0
  242. /package/dist/{chunk-5F6HMNMZ.js.map → chunk-2LA3H54D.js.map} +0 -0
  243. /package/dist/{chunk-IRLH4NM2.js.map → chunk-2PSX5BJU.js.map} +0 -0
  244. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  245. /package/dist/{chunk-IZRNVNPV.js.map → chunk-3LJ2L3T3.js.map} +0 -0
  246. /package/dist/{chunk-JDI7G6EA.js.map → chunk-4NMVX5U7.js.map} +0 -0
  247. /package/dist/{chunk-LJOIZPJH.js.map → chunk-5QZR2RA3.js.map} +0 -0
  248. /package/dist/{chunk-FF6E6HOT.js.map → chunk-5UFQCU6M.js.map} +0 -0
  249. /package/dist/{chunk-4HO3542O.js.map → chunk-5W5N7XJZ.js.map} +0 -0
  250. /package/dist/{chunk-4Y2RHVCV.js.map → chunk-5W62VEFH.js.map} +0 -0
  251. /package/dist/{chunk-LTJTP5YQ.js.map → chunk-6D7PZKCJ.js.map} +0 -0
  252. /package/dist/{chunk-BBHFAVMP.js.map → chunk-6F2UMP4H.js.map} +0 -0
  253. /package/dist/{chunk-IIPJKCZB.js.map → chunk-6NAPOLRO.js.map} +0 -0
  254. /package/dist/{chunk-CK3NQUSQ.js.map → chunk-6UZR7KEK.js.map} +0 -0
  255. /package/dist/{chunk-2TYIAKU5.js.map → chunk-6YMEU6OQ.js.map} +0 -0
  256. /package/dist/{chunk-H23GIXJC.js.map → chunk-A73QHOZP.js.map} +0 -0
  257. /package/dist/{chunk-LLGDVG52.js.map → chunk-AJSZ2EK6.js.map} +0 -0
  258. /package/dist/{chunk-HVKMJAEF.js.map → chunk-B2OOJCUX.js.map} +0 -0
  259. /package/dist/{chunk-YTHQHH5U.js.map → chunk-C6WMSXCJ.js.map} +0 -0
  260. /package/dist/{chunk-JKW663ZN.js.map → chunk-CIAI24TQ.js.map} +0 -0
  261. /package/dist/{chunk-EFWHCTYJ.js.map → chunk-DNRTKO2U.js.map} +0 -0
  262. /package/dist/{chunk-4IZ2IT7D.js.map → chunk-EJLTNPRY.js.map} +0 -0
  263. /package/dist/{chunk-JCJGYNIS.js.map → chunk-EJQXDKYK.js.map} +0 -0
  264. /package/dist/{chunk-347ZR6D4.js.map → chunk-FKJVEW6O.js.map} +0 -0
  265. /package/dist/{chunk-DROAPP6N.js.map → chunk-GFNS3BHV.js.map} +0 -0
  266. /package/dist/{chunk-ALNZEWGN.js.map → chunk-GPFZFCRN.js.map} +0 -0
  267. /package/dist/{chunk-KPML4Q3M.js.map → chunk-GTRGH4ZT.js.map} +0 -0
  268. /package/dist/{chunk-TIRJV2LW.js.map → chunk-I6OQCT3Y.js.map} +0 -0
  269. /package/dist/{chunk-CH627RRV.js.map → chunk-IKXUG6KC.js.map} +0 -0
  270. /package/dist/{chunk-HSBQJRV2.js.map → chunk-IM56VPKO.js.map} +0 -0
  271. /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
  272. /package/dist/{chunk-BP6WMYLP.js.map → chunk-ITYAXU4S.js.map} +0 -0
  273. /package/dist/{chunk-4FFROSFG.js.map → chunk-JJ7JW62R.js.map} +0 -0
  274. /package/dist/{chunk-RFH7U5LT.js.map → chunk-JJX5XEIG.js.map} +0 -0
  275. /package/dist/{chunk-CALURYWR.js.map → chunk-JWPG65LH.js.map} +0 -0
  276. /package/dist/{chunk-G2FCSILA.js.map → chunk-KWIGDKM2.js.map} +0 -0
  277. /package/dist/{chunk-WR2YKUIW.js.map → chunk-KWN6NOHQ.js.map} +0 -0
  278. /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
  279. /package/dist/{chunk-WMOJIOIG.js.map → chunk-LZCSOUJ7.js.map} +0 -0
  280. /package/dist/{chunk-256FBCVX.js.map → chunk-M4AHBM72.js.map} +0 -0
  281. /package/dist/{chunk-5PFGMO33.js.map → chunk-MEW53VQJ.js.map} +0 -0
  282. /package/dist/{chunk-DCUMFQYM.js.map → chunk-ML3U4KPR.js.map} +0 -0
  283. /package/dist/{chunk-X6E7TT3A.js.map → chunk-MR5HWQHS.js.map} +0 -0
  284. /package/dist/{chunk-H7PRHUBD.js.map → chunk-NRLELHAY.js.map} +0 -0
  285. /package/dist/{chunk-ZS4JADYY.js.map → chunk-OW7NVMGQ.js.map} +0 -0
  286. /package/dist/{chunk-TGSMU3F2.js.map → chunk-PADG72LJ.js.map} +0 -0
  287. /package/dist/{chunk-UDTME32W.js.map → chunk-Q35XGIEM.js.map} +0 -0
  288. /package/dist/{chunk-AYIHDC5S.js.map → chunk-QSIQVC32.js.map} +0 -0
  289. /package/dist/{chunk-3MA7JVXN.js.map → chunk-R74NCKEY.js.map} +0 -0
  290. /package/dist/{chunk-QCI73Z7C.js.map → chunk-RYGJGXL6.js.map} +0 -0
  291. /package/dist/{chunk-4OW2T32G.js.map → chunk-SQ3EGGII.js.map} +0 -0
  292. /package/dist/{chunk-ZPGHA7EO.js.map → chunk-TRPX6F2G.js.map} +0 -0
  293. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  294. /package/dist/{chunk-7BJYTX6Q.js.map → chunk-VAMQU4W7.js.map} +0 -0
  295. /package/dist/{chunk-YSR3DXGC.js.map → chunk-VN7IIQGS.js.map} +0 -0
  296. /package/dist/{chunk-DTLF2SLZ.js.map → chunk-WDUG2CH3.js.map} +0 -0
  297. /package/dist/{chunk-YIIC5IDU.js.map → chunk-X4MGNVOO.js.map} +0 -0
  298. /package/dist/{chunk-BHO6RHE5.js.map → chunk-XFCQIQQU.js.map} +0 -0
  299. /package/dist/{chunk-PSNN25DW.js.map → chunk-XZPSBGHA.js.map} +0 -0
  300. /package/dist/{chunk-PMRUMGK6.js.map → chunk-Y7COCXY2.js.map} +0 -0
  301. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  302. /package/dist/{chunk-JFLKSD5V.js.map → chunk-Z334TJRB.js.map} +0 -0
@@ -1,33 +1,33 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-BHO6RHE5.js";
4
+ } from "./chunk-XFCQIQQU.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-CALURYWR.js";
7
- import "./chunk-UHVXE24Y.js";
6
+ import "./chunk-JWPG65LH.js";
8
7
  import "./chunk-46WM6JX2.js";
8
+ import "./chunk-UHVXE24Y.js";
9
9
  import "./chunk-SXIMQLGV.js";
10
- import "./chunk-JFLKSD5V.js";
11
- import "./chunk-LTJTP5YQ.js";
12
- import "./chunk-CYEPCZN5.js";
13
- import "./chunk-DCUMFQYM.js";
14
- import "./chunk-VYISFWVX.js";
15
- import "./chunk-6KTXE6A3.js";
10
+ import "./chunk-Z334TJRB.js";
11
+ import "./chunk-6D7PZKCJ.js";
16
12
  import "./chunk-OQIRBGUU.js";
17
13
  import "./chunk-VANZKHTN.js";
14
+ import "./chunk-CYEPCZN5.js";
15
+ import "./chunk-ML3U4KPR.js";
16
+ import "./chunk-VYISFWVX.js";
18
17
  import "./chunk-W7IGLX4G.js";
18
+ import "./chunk-6KTXE6A3.js";
19
19
  import "./chunk-GUMZC2BO.js";
20
- import "./chunk-227UFSEQ.js";
21
- import "./chunk-ET356KSB.js";
20
+ import "./chunk-LEPOP46W.js";
22
21
  import "./chunk-72A4L5JJ.js";
23
22
  import "./chunk-A7Q43EUZ.js";
23
+ import "./chunk-ET356KSB.js";
24
24
  import "./chunk-S2V7RUCL.js";
25
25
  import "./chunk-AR253JBM.js";
26
+ import "./chunk-PO7NXBG2.js";
26
27
  import "./chunk-S2HLHAZ4.js";
27
28
  import "./chunk-SCU65EZI.js";
28
- import "./chunk-PO7NXBG2.js";
29
- import "./chunk-LDXUBPMO.js";
30
29
  import "./chunk-DM2T26WE.js";
30
+ import "./chunk-LDXUBPMO.js";
31
31
  import "./chunk-UG6VXIOK.js";
32
32
  import "./chunk-AAD2ZS6P.js";
33
33
  import "./chunk-H6ZXNH5I.js";
@@ -43,7 +43,7 @@ import "./chunk-RBOJCG4T.js";
43
43
  import "./chunk-GSTIBXBW.js";
44
44
  import "./chunk-5WITETWU.js";
45
45
  import "./chunk-6CIAGZ6X.js";
46
- import "./chunk-QCECHYZL.js";
46
+ import "./chunk-E2GYBTSP.js";
47
47
  import "./chunk-URS5GSM7.js";
48
48
  import "./chunk-ZLQ37WJX.js";
49
49
  import "./chunk-IUM3VSHI.js";
@@ -63,7 +63,7 @@ import "./chunk-PJKTFXE2.js";
63
63
  import "./chunk-W5BIQOAJ.js";
64
64
  import "./chunk-Z7L72ZHL.js";
65
65
  import "./chunk-4O4TKIXQ.js";
66
- import "./chunk-DJ7HMNSL.js";
66
+ import "./chunk-YCVB7X56.js";
67
67
  import "./chunk-BJMBJZ2Y.js";
68
68
  import "./chunk-UKJAGEXH.js";
69
69
  import "./chunk-FP2373TW.js";
@@ -4,8 +4,8 @@ import {
4
4
  resolveWorkProductLedgerDir,
5
5
  searchWorkProductLedgerEntries,
6
6
  validateWorkProductLedgerEntry
7
- } from "./chunk-H7PRHUBD.js";
8
- import "./chunk-DJ7HMNSL.js";
7
+ } from "./chunk-NRLELHAY.js";
8
+ import "./chunk-YCVB7X56.js";
9
9
  import "./chunk-A2IYSXDQ.js";
10
10
  import "./chunk-P77QX3ID.js";
11
11
  import "./chunk-PZ5AY32C.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.63.0",
3
+ "version": "9.63.2",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3156,7 +3156,7 @@
3156
3156
  "core"
3157
3157
  ],
3158
3158
  "peerDependencies": {
3159
- "@remnic/coding-graph": "^9.63.0"
3159
+ "@remnic/coding-graph": "^9.63.2"
3160
3160
  },
3161
3161
  "peerDependenciesMeta": {
3162
3162
  "@remnic/coding-graph": {
@@ -0,0 +1,434 @@
1
+ /**
2
+ * @remnic/core — Droid connector helpers
3
+ *
4
+ * Factory Droid reads MCP server config from the user-level ~/.factory/mcp.json.
5
+ * `remnic connectors install droid` writes a "remnic" entry under mcpServers
6
+ * with HTTP transport and a bearer token so Droid can authenticate to the
7
+ * Remnic daemon. The token is NEVER written into the project-level
8
+ * .factory/mcp.json — only the user-level file at ~/.factory/mcp.json.
9
+ *
10
+ * Extracted from connectors/index.ts to keep the main file under its
11
+ * ratchet ceiling (issue #1995).
12
+ */
13
+
14
+ import fs from "node:fs";
15
+ import path from "node:path";
16
+ import os from "node:os";
17
+
18
+ import { readEnvVar } from "../runtime/env.js";
19
+ import type { ConnectorManifest } from "./index.js";
20
+
21
+ // ── Manifest ────────────────────────────────────────────────────────────────
22
+
23
+ /**
24
+ * The droid connector manifest entry. Imported into BUILTIN_CONNECTORS
25
+ * in connectors/index.ts.
26
+ */
27
+ export const DROID_CONNECTOR_MANIFEST: ConnectorManifest = {
28
+ id: "droid",
29
+ name: "Factory Droid",
30
+ version: "1.0.0",
31
+ description:
32
+ "Factory Droid — AI software engineering agent; memory via HTTP MCP with bearer auth",
33
+ capabilities: {
34
+ observe: true,
35
+ recall: true,
36
+ store: true,
37
+ search: true,
38
+ entities: true,
39
+ realtimeSync: true,
40
+ batch: true,
41
+ maxBudgetChars: 32000,
42
+ connectionType: "mcp",
43
+ },
44
+ configSchema: {
45
+ mcpServerUrl: "URL of the MCP Remnic: server (default: http://127.0.0.1:4318/mcp)",
46
+ namespace: "Optional namespace",
47
+ },
48
+ homepage: "https://factory.ai",
49
+ author: "Remnic",
50
+ tags: ["official", "ai", "droid", "factory"],
51
+ requiresToken: true,
52
+ };
53
+
54
+ // ── Provenance reading for removeConnector ─────────────────────────────────
55
+
56
+ /**
57
+ * Result of reading the droid MCP provenance from the saved connector JSON.
58
+ */
59
+ export interface DroidMcpProvenance {
60
+ /** Resolved MCP config path, or null if none found. */
61
+ mcpConfigPath: string | null;
62
+ /** True if the connector JSON was malformed (abort removal). */
63
+ registryParseFailed: boolean;
64
+ }
65
+
66
+ // ── Install step (called from installConnector) ────────────────────────────
67
+
68
+ /**
69
+ * Result of the droid install step — either success with rollback/mcpPath,
70
+ * or an error result that installConnector should return directly.
71
+ */
72
+ export type DroidInstallStepResult =
73
+ | { ok: true; rollback: (() => void) | null; mcpPath: string }
74
+ | { ok: false; errorMessage: string };
75
+
76
+ /**
77
+ * Write the remnic MCP entry to ~/.factory/mcp.json, with token rollback on failure.
78
+ *
79
+ * `saveTokenStore` is passed as a callback to avoid a circular dependency
80
+ * back into the main connectors module.
81
+ */
82
+ export function droidInstallStep(
83
+ authToken: string | undefined,
84
+ resolvedConfig: Record<string, unknown>,
85
+ requiresToken: boolean,
86
+ tokenEntry: { token: string } | null,
87
+ priorTokenStore: unknown,
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ saveTokenStoreFn: (store: any) => void,
90
+ ): DroidInstallStepResult {
91
+ try {
92
+ const result = writeDroidMcpEntry(authToken, resolvedConfig);
93
+ return { ok: true, rollback: result.rollback, mcpPath: result.mcpPath };
94
+ } catch (droidErr) {
95
+ const errMsg = droidErr instanceof Error ? droidErr.message : String(droidErr);
96
+ let tokenSuffix = "";
97
+ if (requiresToken && tokenEntry !== null && priorTokenStore !== null) {
98
+ try {
99
+ saveTokenStoreFn(priorTokenStore);
100
+ tokenSuffix = " Token has been rolled back.";
101
+ } catch (e) {
102
+ tokenSuffix = ` Token rollback FAILED (${e instanceof Error ? e.message : String(e)}) — manually inspect ~/.remnic/tokens.json and reinstall.`;
103
+ }
104
+ }
105
+ return {
106
+ ok: false,
107
+ errorMessage: `Droid install aborted: ~/.factory/mcp.json write failed — ${errMsg}.${tokenSuffix} Resolve the write permission issue on ~/.factory/, then reinstall.`,
108
+ };
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Called from `removeConnector` when `connectorId === "droid"`. Falls back to
114
+ * env resolution if the path is missing (legacy install pre-dating
115
+ * factoryMcpPath provenance).
116
+ */
117
+ export function readDroidMcpProvenance(configPath: string): DroidMcpProvenance {
118
+ let mcpConfigPath: string | null = null;
119
+ let registryParseFailed = false;
120
+ if (!fs.existsSync(configPath)) {
121
+ return { mcpConfigPath: null, registryParseFailed: false };
122
+ }
123
+ try {
124
+ const stored = JSON.parse(fs.readFileSync(configPath, "utf8")) as Record<string, unknown>;
125
+ if (typeof stored.factoryMcpPath === "string" && stored.factoryMcpPath.length > 0) {
126
+ mcpConfigPath = stored.factoryMcpPath;
127
+ }
128
+ } catch {
129
+ registryParseFailed = true;
130
+ }
131
+ if (mcpConfigPath === null && !registryParseFailed) {
132
+ try {
133
+ mcpConfigPath = resolveFactoryMcpPath();
134
+ } catch {
135
+ // Resolution failed — leave null; cleanup block skips.
136
+ }
137
+ }
138
+ return { mcpConfigPath, registryParseFailed };
139
+ }
140
+
141
+ /**
142
+ * Atomic write with owner-only (0o600) permissions. Mirrors the
143
+ * `writeSecretFileSync` in connectors/index.ts — kept local so this module
144
+ * has no dependency back into the main file.
145
+ */
146
+ function writeSecretFileSync(filePath: string, data: string): void {
147
+ const dir = path.dirname(filePath);
148
+ const base = path.basename(filePath);
149
+ const tmpPath = path.join(
150
+ dir,
151
+ `.${base}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`,
152
+ );
153
+ let wroteTemp = false;
154
+ try {
155
+ fs.writeFileSync(tmpPath, data, { mode: 0o600, flag: "wx" });
156
+ wroteTemp = true;
157
+ try { fs.chmodSync(tmpPath, 0o600); } catch { /* best-effort */ }
158
+ fs.renameSync(tmpPath, filePath);
159
+ try { fs.chmodSync(filePath, 0o600); } catch { /* best-effort */ }
160
+ } catch (err) {
161
+ if (wroteTemp) { try { fs.unlinkSync(tmpPath); } catch { /* best-effort */ } }
162
+ throw err;
163
+ }
164
+ }
165
+
166
+ // ── Install ─────────────────────────────────────────────────────────────────
167
+
168
+ /**
169
+ * Result of the droid MCP install step.
170
+ */
171
+ export interface DroidMcpInstallResult {
172
+ /** Absolute path to ~/.factory/mcp.json that was written. */
173
+ mcpPath: string;
174
+ /** Rollback closure: restores prior content (or deletes if newly created). */
175
+ rollback: () => void;
176
+ }
177
+
178
+ /**
179
+ * Write the remnic MCP server entry to ~/.factory/mcp.json.
180
+ *
181
+ * Called from `installConnector` when `connectorId === "droid"`. Upserts only
182
+ * the `remnic` key under `mcpServers`, preserving all other entries. Returns
183
+ * the resolved path and a rollback closure. Throws on write failure (after
184
+ * attempting rollback).
185
+ */
186
+ export function writeDroidMcpEntry(
187
+ authToken: string | undefined,
188
+ resolvedConfig: Record<string, unknown>,
189
+ ): DroidMcpInstallResult {
190
+ const mcpPath = resolveFactoryMcpPath();
191
+ const priorContent = readFactoryMcpIfExists(mcpPath);
192
+ const mcpConfig = upsertFactoryMcpRemnicEntry(priorContent, authToken, resolvedConfig);
193
+ fs.mkdirSync(path.dirname(mcpPath), { recursive: true });
194
+ const rollback = (): void => {
195
+ try {
196
+ if (priorContent === null) {
197
+ if (fs.existsSync(mcpPath)) fs.unlinkSync(mcpPath);
198
+ } else {
199
+ writeSecretFileSync(mcpPath, priorContent);
200
+ }
201
+ } catch { /* best-effort */ }
202
+ };
203
+ try {
204
+ writeSecretFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
205
+ } catch (writeErr) {
206
+ try { rollback(); } catch { /* best-effort */ }
207
+ throw writeErr;
208
+ }
209
+ return { mcpPath, rollback };
210
+ }
211
+
212
+ // ── Remove ──────────────────────────────────────────────────────────────────
213
+
214
+ /**
215
+ * Remove the remnic entry from ~/.factory/mcp.json at the given path.
216
+ *
217
+ * Validates the path is absolute and ends with `.factory/mcp.json` before
218
+ * modifying. Returns a note string on success, or null if no modification
219
+ * was needed. Throws on write failure or if the path fails safety validation.
220
+ */
221
+ export function removeDroidMcpEntry(mcpPath: string): string | null {
222
+ const expectedSuffix = path.join(".factory", "mcp.json");
223
+ if (!path.isAbsolute(mcpPath) || !mcpPath.endsWith(expectedSuffix)) {
224
+ throw new Error(
225
+ `MCP config path ${JSON.stringify(mcpPath)} failed safety validation ` +
226
+ `(must be absolute and end with "${expectedSuffix}"). ` +
227
+ `Refusing to modify — remove the "remnic" entry manually if it exists.`,
228
+ );
229
+ }
230
+ const priorContent = readFactoryMcpIfExists(mcpPath);
231
+ if (priorContent === null) return null;
232
+ const updated = removeFactoryMcpRemnicEntry(priorContent);
233
+ if (updated === null) return null;
234
+ writeSecretFileSync(mcpPath, JSON.stringify(updated, null, 2));
235
+ return `Removed remnic entry from Droid MCP config: ${mcpPath}`;
236
+ }
237
+
238
+ // ── Doctor ──────────────────────────────────────────────────────────────────
239
+
240
+ export interface DroidDoctorCheck {
241
+ name: string;
242
+ ok: boolean;
243
+ detail: string;
244
+ }
245
+
246
+ /**
247
+ * Check that ~/.factory/mcp.json contains a remnic entry.
248
+ *
249
+ * Called from `doctorConnector` when `connectorId === "droid"`.
250
+ */
251
+ export function droidMcpDoctorCheck(savedPath: string | undefined): DroidDoctorCheck {
252
+ const mcpPath = savedPath ?? resolveFactoryMcpPath();
253
+ // Safety gate: validate persisted path before reading (mirrors removeConnector).
254
+ if (savedPath !== undefined) {
255
+ const expectedSuffix = path.join(".factory", "mcp.json");
256
+ if (!path.isAbsolute(savedPath) || !savedPath.endsWith(expectedSuffix)) {
257
+ return { name: "Droid MCP config", ok: false, detail: `Unsafe path in droid.json: ${savedPath}` };
258
+ }
259
+ }
260
+ try {
261
+ const raw = fs.readFileSync(mcpPath, "utf8");
262
+ const parsed = JSON.parse(raw) as Record<string, unknown>;
263
+ const servers = parsed.mcpServers;
264
+ if (typeof servers !== "object" || servers === null || !("remnic" in (servers as Record<string, unknown>))) {
265
+ return { name: "Droid MCP config", ok: false, detail: `remnic entry missing in ${mcpPath} — run \`remnic connectors install droid\`` };
266
+ }
267
+ const remnic = (servers as Record<string, Record<string, unknown>>).remnic;
268
+ // Validate the entry has the expected shape (type + url + Authorization).
269
+ if (remnic.type !== "http" || typeof remnic.url !== "string") {
270
+ return { name: "Droid MCP config", ok: false, detail: `remnic entry malformed in ${mcpPath}` };
271
+ }
272
+ const headers = remnic.headers as Record<string, unknown> | undefined;
273
+ const hasAuth = headers && typeof headers["Authorization"] === "string" && (headers["Authorization"] as string).startsWith("Bearer ");
274
+ return {
275
+ name: "Droid MCP config",
276
+ ok: !!hasAuth,
277
+ detail: hasAuth ? `remnic entry present in ${mcpPath}` : `remnic entry missing Authorization header in ${mcpPath} — run \`remnic connectors install droid\``,
278
+ };
279
+ } catch {
280
+ return { name: "Droid MCP config", ok: false, detail: `Cannot read ${mcpPath} — run \`remnic connectors install droid\`` };
281
+ }
282
+ }
283
+
284
+ // ── Path resolution and low-level helpers ───────────────────────────────────
285
+
286
+ /**
287
+ * Resolve the path to ~/.factory/mcp.json. Honours the HOME env override
288
+ * so tests can point the install at a temp dir without leaking into the
289
+ * real home directory. Falls back to os.homedir() when HOME is unset.
290
+ */
291
+ export function resolveFactoryMcpPath(): string {
292
+ const envHome = readEnvVar("HOME");
293
+ const home = envHome && envHome.length > 0 ? envHome : os.homedir();
294
+ return path.resolve(home, ".factory", "mcp.json");
295
+ }
296
+
297
+ /**
298
+ * Read the existing ~/.factory/mcp.json, if any. Returns raw string contents
299
+ * so the caller can parse, modify, and restore on rollback.
300
+ */
301
+ export function readFactoryMcpIfExists(mcpPath: string): string | null {
302
+ try {
303
+ if (!fs.existsSync(mcpPath)) return null;
304
+ return fs.readFileSync(mcpPath, "utf8");
305
+ } catch {
306
+ return null;
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Default MCP server URL for the Remnic daemon.
312
+ */
313
+ const REMNIC_DEFAULT_MCP_URL = "http://127.0.0.1:4318/mcp";
314
+
315
+ /**
316
+ * Upsert the "remnic" entry in a ~/.factory/mcp.json config object.
317
+ *
318
+ * Parses the prior content (if any), preserves all existing mcpServers entries,
319
+ * and sets the "remnic" entry with HTTP transport, the bearer token, and an
320
+ * optional namespace header. Returns the full config object ready to serialize.
321
+ *
322
+ * If no token is available, the entry is still written but without the
323
+ * Authorization header — the caller will see an auth error from the daemon,
324
+ * which is more informative than a missing entry.
325
+ */
326
+ export function upsertFactoryMcpRemnicEntry(
327
+ priorContent: string | null,
328
+ authToken: string | undefined,
329
+ resolvedConfig: Record<string, unknown>,
330
+ ): Record<string, unknown> {
331
+ let config: Record<string, unknown>;
332
+ if (priorContent !== null) {
333
+ try {
334
+ const parsed = JSON.parse(priorContent);
335
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
336
+ config = parsed as Record<string, unknown>;
337
+ } else {
338
+ // Non-object JSON — start fresh but warn in console.
339
+ console.warn("[remnic/connectors] ~/.factory/mcp.json contained non-object JSON; starting fresh.");
340
+ config = {};
341
+ }
342
+ } catch {
343
+ // Malformed JSON — do NOT silently discard other MCP server entries.
344
+ // Throw so the caller can surface the error instead of overwriting the file.
345
+ throw new Error(
346
+ "~/.factory/mcp.json contains malformed JSON and cannot be parsed. " +
347
+ "Fix the file manually before reinstalling, or use --force to overwrite (this will lose existing MCP server entries).",
348
+ );
349
+ }
350
+ } else {
351
+ config = {};
352
+ }
353
+
354
+ if (typeof config.mcpServers !== "object" || config.mcpServers === null || Array.isArray(config.mcpServers)) {
355
+ config.mcpServers = {};
356
+ }
357
+ const servers = config.mcpServers as Record<string, unknown>;
358
+
359
+ const mcpUrl =
360
+ typeof resolvedConfig.mcpServerUrl === "string" && resolvedConfig.mcpServerUrl.length > 0
361
+ ? resolvedConfig.mcpServerUrl
362
+ : REMNIC_DEFAULT_MCP_URL;
363
+
364
+ const remnicEntry: Record<string, unknown> = { type: "http", url: mcpUrl };
365
+
366
+ // Preserve prior headers EXCEPT Remnic-managed ones (Authorization,
367
+ // X-Engram-Namespace). These are always replaced from the current install
368
+ // config so a reinstall that clears namespace does not leave a stale header.
369
+ const REMNIC_MANAGED_HEADERS = new Set(["Authorization", "X-Engram-Namespace"]);
370
+ const headers: Record<string, string> = {};
371
+ if (
372
+ typeof servers.remnic === "object" && servers.remnic !== null &&
373
+ typeof (servers.remnic as Record<string, unknown>).headers === "object" &&
374
+ (servers.remnic as Record<string, unknown>).headers !== null
375
+ ) {
376
+ const priorHeaders = (servers.remnic as Record<string, Record<string, unknown>>).headers as Record<string, unknown>;
377
+ for (const [key, value] of Object.entries(priorHeaders)) {
378
+ if (!REMNIC_MANAGED_HEADERS.has(key) && typeof value === "string") {
379
+ headers[key] = value;
380
+ }
381
+ }
382
+ }
383
+
384
+ if (authToken && authToken.length > 0) {
385
+ headers["Authorization"] = `Bearer ${authToken}`;
386
+ }
387
+
388
+ const namespace =
389
+ typeof resolvedConfig.namespace === "string" && resolvedConfig.namespace.length > 0
390
+ ? resolvedConfig.namespace
391
+ : undefined;
392
+ if (namespace) {
393
+ headers["X-Engram-Namespace"] = namespace;
394
+ }
395
+
396
+ if (Object.keys(headers).length > 0) {
397
+ remnicEntry.headers = headers;
398
+ }
399
+
400
+ servers.remnic = remnicEntry;
401
+ return config;
402
+ }
403
+
404
+ /**
405
+ * Remove the "remnic" entry from a ~/.factory/mcp.json config object.
406
+ *
407
+ * Returns the updated config object (with remnic removed) or null if the
408
+ * entry was not present (no modification needed).
409
+ */
410
+ export function removeFactoryMcpRemnicEntry(
411
+ priorContent: string,
412
+ ): Record<string, unknown> | null {
413
+ let config: Record<string, unknown>;
414
+ try {
415
+ const parsed = JSON.parse(priorContent);
416
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
417
+ return null;
418
+ }
419
+ config = parsed as Record<string, unknown>;
420
+ } catch {
421
+ return null;
422
+ }
423
+
424
+ if (typeof config.mcpServers !== "object" || config.mcpServers === null) {
425
+ return null;
426
+ }
427
+ const servers = config.mcpServers as Record<string, unknown>;
428
+ if (!("remnic" in servers)) {
429
+ return null;
430
+ }
431
+
432
+ delete servers.remnic;
433
+ return config;
434
+ }
@@ -29,6 +29,15 @@ import {
29
29
  } from "./hermes-shim.js";
30
30
  import { getConnectorsDir, getRegistryPath } from "./paths.js";
31
31
  export { getConnectorsDir, getRegistryPath } from "./paths.js";
32
+ export { resolveFactoryMcpPath, upsertFactoryMcpRemnicEntry, removeFactoryMcpRemnicEntry } from "./droid-mcp.js";
33
+ export { DROID_CONNECTOR_MANIFEST } from "./droid-mcp.js";
34
+ import {
35
+ DROID_CONNECTOR_MANIFEST,
36
+ droidInstallStep,
37
+ removeDroidMcpEntry as removeDroidMcpEntryImpl,
38
+ droidMcpDoctorCheck as droidMcpDoctorCheckImpl,
39
+ readDroidMcpProvenance,
40
+ } from "./droid-mcp.js";
32
41
 
33
42
  // Native memory artifact materialization for Codex CLI (#378). Surfaced here
34
43
  // so downstream callers can `import { materializeForNamespace } from "@remnic/core/connectors"`.
@@ -565,6 +574,7 @@ export const BUILTIN_CONNECTORS: ConnectorManifest[] = [
565
574
  tags: ["official", "python", "hermes"],
566
575
  requiresToken: true,
567
576
  },
577
+ DROID_CONNECTOR_MANIFEST,
568
578
  ];
569
579
 
570
580
  // ── Registry management ───────────────────────────────────────────────────
@@ -2028,6 +2038,24 @@ export function installConnector(options: InstallOptions): InstallResult {
2028
2038
  }
2029
2039
  }
2030
2040
 
2041
+ // ── Droid: write remnic MCP server entry to ~/.factory/mcp.json ──────────
2042
+ let droidMcpRollback: (() => void) | null = null;
2043
+ if (options.connectorId === "droid") {
2044
+ const stepResult = droidInstallStep(
2045
+ tokenEntry?.token,
2046
+ resolvedConfig,
2047
+ manifest.requiresToken ?? false,
2048
+ tokenEntry,
2049
+ nonHermesPriorTokenStore,
2050
+ saveTokenStore,
2051
+ );
2052
+ if (!stepResult.ok) {
2053
+ return { connectorId: options.connectorId, status: "error", message: stepResult.errorMessage };
2054
+ }
2055
+ droidMcpRollback = stepResult.rollback;
2056
+ resolvedConfig.factoryMcpPath = stepResult.mcpPath;
2057
+ }
2058
+
2031
2059
  // Finding 5: strip internal/test-only keys that must never be persisted to
2032
2060
  // the config file. These keys are used at install time only (e.g. to inject
2033
2061
  // a synthetic extension source dir in tests) and have no meaning on disk.
@@ -2095,6 +2123,14 @@ export function installConnector(options: InstallOptions): InstallResult {
2095
2123
  // Best-effort rollback.
2096
2124
  }
2097
2125
  }
2126
+ // Roll back the Droid ~/.factory/mcp.json if it was written.
2127
+ if (droidMcpRollback !== null) {
2128
+ try {
2129
+ droidMcpRollback();
2130
+ } catch {
2131
+ // Best-effort rollback.
2132
+ }
2133
+ }
2098
2134
  // Only include a token-rollback suffix for connectors that actually had a
2099
2135
  // token to roll back. Non-token connectors (requiresToken !== true) never
2100
2136
  // generated a token entry. For requiresToken connectors where generateToken
@@ -2316,6 +2352,20 @@ export function removeConnector(connectorId: string): RemoveResult {
2316
2352
  }
2317
2353
  }
2318
2354
  }
2355
+
2356
+ // For droid, read the persisted factoryMcpPath before deleting the config.
2357
+ let droidMcpConfigPath: string | null = null;
2358
+ let droidRegistryParseFailed = false;
2359
+ if (connectorId === "droid") {
2360
+ const prov = readDroidMcpProvenance(configPath);
2361
+ droidMcpConfigPath = prov.mcpConfigPath;
2362
+ droidRegistryParseFailed = prov.registryParseFailed;
2363
+ }
2364
+ if (connectorId === "droid" && droidRegistryParseFailed) {
2365
+ console.warn(`[remnic/connectors] removeConnector: droid.json malformed — aborting. Fix or delete ${configPath} manually and retry.`);
2366
+ return { connectorId, configPath, message: "Removal aborted: droid.json is malformed. Registry config left in place.", status: "skipped", reason: "config-parse-failed" };
2367
+ }
2368
+
2319
2369
  if (connectorId === "weclone" && weCloneRegistryParseFailed) {
2320
2370
  console.warn(
2321
2371
  "[remnic/connectors] removeConnector: weclone.json is malformed — " +
@@ -2564,6 +2614,21 @@ export function removeConnector(connectorId: string): RemoveResult {
2564
2614
  };
2565
2615
  }
2566
2616
 
2617
+ // Droid-specific: remove the "remnic" entry from ~/.factory/mcp.json.
2618
+ let droidMcpDeleteFailed: string | null = null;
2619
+ if (connectorId === "droid") {
2620
+ if (droidMcpConfigPath === null) {
2621
+ notes.push("Droid MCP config cleanup skipped: no persisted path found (legacy install).");
2622
+ } else {
2623
+ try { const note = removeDroidMcpEntryImpl(droidMcpConfigPath); if (note) notes.push(note); }
2624
+ catch (err) { droidMcpDeleteFailed = err instanceof Error ? err.message : String(err); }
2625
+ }
2626
+ }
2627
+ if (droidMcpDeleteFailed !== null && droidMcpConfigPath !== null) {
2628
+ const ts = tokenRevoked ? "token was revoked" : "TOKEN REVOCATION ALSO FAILED — inspect ~/.remnic/tokens.json and revoke manually";
2629
+ return { connectorId, configPath, status: "error", message: `Droid remove partially succeeded: registry config deleted, ${ts}, but the MCP config at ${droidMcpConfigPath} could not be updated (${droidMcpDeleteFailed}). Manually remove the "remnic" entry.` };
2630
+ }
2631
+
2567
2632
  // Hermes-specific: strip the remnic: block from config.yaml (the writability
2568
2633
  // preflight above already verified every remnic:-bearing target, so a
2569
2634
  // partial failure here is a rare TOCTOU race — the error branch below stays
@@ -3301,6 +3366,11 @@ export async function doctorConnector(connectorId: string): Promise<DoctorResult
3301
3366
  }
3302
3367
  }
3303
3368
 
3369
+ // Droid-specific: check ~/.factory/mcp.json has the remnic entry
3370
+ if (connectorId === "droid") {
3371
+ checks.push(droidMcpDoctorCheckImpl(instance.config.factoryMcpPath as string | undefined));
3372
+ }
3373
+
3304
3374
  const healthy = checks.every((c) => c.ok);
3305
3375
  return { connectorId, checks, healthy };
3306
3376
  }
@@ -18,7 +18,11 @@
18
18
  * Not wired into retrieval yet — see slice 3.
19
19
  */
20
20
 
21
- import { normalizeRecallTokenSet, normalizeRecallTokens } from "./recall-tokenization.js";
21
+ import {
22
+ isUnsegmentableRecallChar as isUnsegmentableRecallCodepoint,
23
+ normalizeRecallTokenSet,
24
+ normalizeRecallTokens,
25
+ } from "./recall-tokenization.js";
22
26
  import type { TrustZoneName } from "./trust-zones.js";
23
27
  import type { MemoryFile, MemoryStatus } from "./types.js";
24
28
 
@@ -154,8 +158,7 @@ interface ScoredCandidate {
154
158
  }
155
159
 
156
160
  function hasUnsegmentableRecallChar(token: string): boolean {
157
- if (token.includes("ー") || token.includes("ー")) return true;
158
- return /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(token);
161
+ return [...token].some((ch) => isUnsegmentableRecallCodepoint(ch));
159
162
  }
160
163
 
161
164
  function requiredCjkPhraseTokens(query: string): string[] {