@remnic/core 9.63.1 → 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 (254) hide show
  1. package/dist/access-admin-ops-surface.js +33 -32
  2. package/dist/access-audit.js +2 -2
  3. package/dist/access-authorization-probe.js +34 -33
  4. package/dist/access-boundary.js +33 -32
  5. package/dist/access-cli.js +97 -95
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-extraction-force-flush.js +33 -32
  8. package/dist/access-http-query.js +33 -32
  9. package/dist/access-http.js +46 -45
  10. package/dist/access-identity-continuity-surface.js +33 -32
  11. package/dist/access-lcm-surface.js +33 -32
  12. package/dist/access-mcp.js +39 -38
  13. package/dist/access-namespace-preflight.js +33 -32
  14. package/dist/access-observe-write-surface.js +33 -32
  15. package/dist/access-operations-batch.js +34 -33
  16. package/dist/access-operations.js +38 -37
  17. package/dist/access-recall-concurrency.js +33 -32
  18. package/dist/access-recall-response.js +33 -32
  19. package/dist/access-recall-surface.js +33 -32
  20. package/dist/access-schema.js +3 -3
  21. package/dist/access-service.js +33 -32
  22. package/dist/access-surface-catalog.js +35 -34
  23. package/dist/access-surface-catalog.js.map +1 -1
  24. package/dist/adapters/index.js +7 -7
  25. package/dist/adapters/registry.js +3 -3
  26. package/dist/{auto-sync-Z52VWMNC.js → auto-sync-BKRJDMKX.js} +3 -3
  27. package/dist/behavior-learner.js +2 -2
  28. package/dist/briefing.js +14 -14
  29. package/dist/buffer.js +4 -3
  30. package/dist/causal-behavior.js +3 -3
  31. package/dist/causal-chain.js +3 -3
  32. package/dist/causal-consolidation.js +17 -17
  33. package/dist/causal-retrieval.js +3 -3
  34. package/dist/causal-trajectory.js +2 -2
  35. package/dist/{chunk-5F6HMNMZ.js → chunk-2LA3H54D.js} +2 -2
  36. package/dist/{chunk-IRLH4NM2.js → chunk-2PSX5BJU.js} +3 -3
  37. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  38. package/dist/{chunk-F2FZEVDE.js → chunk-3LJ2L3T3.js} +2 -2
  39. package/dist/{chunk-RBBYKXXK.js → chunk-44KHFMCM.js} +64 -62
  40. package/dist/{chunk-RBBYKXXK.js.map → chunk-44KHFMCM.js.map} +1 -1
  41. package/dist/{chunk-AUIAHNO7.js → chunk-4NMVX5U7.js} +2 -2
  42. package/dist/{chunk-ANMIOQPU.js → chunk-4XN35YQD.js} +478 -164
  43. package/dist/chunk-4XN35YQD.js.map +1 -0
  44. package/dist/{chunk-LJOIZPJH.js → chunk-5QZR2RA3.js} +2 -2
  45. package/dist/{chunk-RBJKE5LV.js → chunk-5UFQCU6M.js} +32 -32
  46. package/dist/{chunk-S52C2DEM.js → chunk-5W5N7XJZ.js} +2 -2
  47. package/dist/{chunk-GL4RHVHX.js → chunk-5W62VEFH.js} +4 -4
  48. package/dist/{chunk-DEOYTFA6.js → chunk-645WOU5I.js} +4 -52
  49. package/dist/chunk-645WOU5I.js.map +1 -0
  50. package/dist/{chunk-4WW5FMUD.js → chunk-6D7PZKCJ.js} +9 -9
  51. package/dist/{chunk-NVSTZ2PN.js → chunk-6F2UMP4H.js} +7 -7
  52. package/dist/{chunk-IIPJKCZB.js → chunk-6NAPOLRO.js} +3 -3
  53. package/dist/{chunk-U4CCRHN6.js → chunk-6UZR7KEK.js} +2 -2
  54. package/dist/{chunk-2TYIAKU5.js → chunk-6YMEU6OQ.js} +2 -2
  55. package/dist/{chunk-LAX6S5WS.js → chunk-A73QHOZP.js} +2 -2
  56. package/dist/{chunk-ZSH6GJ2V.js → chunk-AJSZ2EK6.js} +3 -3
  57. package/dist/{chunk-GUBT77YC.js → chunk-B2OOJCUX.js} +2 -2
  58. package/dist/chunk-BUYVPUEM.js +66 -0
  59. package/dist/chunk-BUYVPUEM.js.map +1 -0
  60. package/dist/{chunk-YTHQHH5U.js → chunk-C6WMSXCJ.js} +2 -2
  61. package/dist/{chunk-JKW663ZN.js → chunk-CIAI24TQ.js} +2 -2
  62. package/dist/{chunk-PD6O7AXF.js → chunk-CSAKJVXW.js} +14 -17
  63. package/dist/chunk-CSAKJVXW.js.map +1 -0
  64. package/dist/{chunk-ALKRPLWB.js → chunk-DNRTKO2U.js} +2 -2
  65. package/dist/{chunk-J5AFG5JN.js → chunk-EJLTNPRY.js} +3 -3
  66. package/dist/{chunk-ORB56L3Y.js → chunk-EJQXDKYK.js} +4 -4
  67. package/dist/{chunk-UM7A4CPT.js → chunk-FKJVEW6O.js} +2 -2
  68. package/dist/{chunk-ZXMNT75M.js → chunk-GFNS3BHV.js} +3 -3
  69. package/dist/{chunk-ALNZEWGN.js → chunk-GPFZFCRN.js} +2 -2
  70. package/dist/{chunk-MQFFR6QB.js → chunk-GTRGH4ZT.js} +2 -2
  71. package/dist/{chunk-USKANB65.js → chunk-I6OQCT3Y.js} +2 -2
  72. package/dist/{chunk-2AZBPQLK.js → chunk-IKXUG6KC.js} +7 -7
  73. package/dist/{chunk-5LVSFKQB.js → chunk-IM56VPKO.js} +3 -3
  74. package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
  75. package/dist/{chunk-R7R4FSV2.js → chunk-ITYAXU4S.js} +3 -3
  76. package/dist/{chunk-7CJO52ET.js → chunk-JJ7JW62R.js} +23 -23
  77. package/dist/{chunk-5S7Y7AC6.js → chunk-JJX5XEIG.js} +2 -2
  78. package/dist/{chunk-OF6KQJ35.js → chunk-JWPG65LH.js} +14 -14
  79. package/dist/chunk-K2XUWZBM.js +417 -0
  80. package/dist/chunk-K2XUWZBM.js.map +1 -0
  81. package/dist/{chunk-G2FCSILA.js → chunk-KWIGDKM2.js} +2 -2
  82. package/dist/{chunk-UKBIB3FP.js → chunk-KWN6NOHQ.js} +2 -2
  83. package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
  84. package/dist/{chunk-SHSJP4D6.js → chunk-LZCSOUJ7.js} +2 -2
  85. package/dist/{chunk-256FBCVX.js → chunk-M4AHBM72.js} +7 -7
  86. package/dist/{chunk-5PFGMO33.js → chunk-MEW53VQJ.js} +2 -2
  87. package/dist/{chunk-DCUMFQYM.js → chunk-ML3U4KPR.js} +2 -2
  88. package/dist/{chunk-UDL4DNBM.js → chunk-MR5HWQHS.js} +2 -2
  89. package/dist/{chunk-H7PRHUBD.js → chunk-NRLELHAY.js} +2 -2
  90. package/dist/{chunk-ZS4JADYY.js → chunk-OW7NVMGQ.js} +2 -2
  91. package/dist/{chunk-U5LYM2NS.js → chunk-PADG72LJ.js} +3 -3
  92. package/dist/{chunk-6GGTATZF.js → chunk-PYIR4SSB.js} +4 -4
  93. package/dist/chunk-PYIR4SSB.js.map +1 -0
  94. package/dist/{chunk-UW74LP76.js → chunk-Q35XGIEM.js} +2 -2
  95. package/dist/{chunk-XPRJSHNI.js → chunk-QJ622LTI.js} +6 -3
  96. package/dist/chunk-QJ622LTI.js.map +1 -0
  97. package/dist/{chunk-FNYIMSKI.js → chunk-QSIQVC32.js} +2 -2
  98. package/dist/{chunk-EJYAE2U7.js → chunk-R74NCKEY.js} +4 -4
  99. package/dist/{chunk-KP36WQBJ.js → chunk-RYGJGXL6.js} +2 -2
  100. package/dist/{chunk-4OW2T32G.js → chunk-SQ3EGGII.js} +2 -2
  101. package/dist/{chunk-FU7OICXE.js → chunk-TRPX6F2G.js} +10 -10
  102. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  103. package/dist/{chunk-6VX2ZZH2.js → chunk-VAMQU4W7.js} +2 -2
  104. package/dist/{chunk-WLITCQAC.js → chunk-VN7IIQGS.js} +2 -2
  105. package/dist/{chunk-MMM7SDOJ.js → chunk-WDUG2CH3.js} +2 -2
  106. package/dist/{chunk-P2BT5ALE.js → chunk-X4MGNVOO.js} +2 -2
  107. package/dist/{chunk-BE5SVRFC.js → chunk-XFCQIQQU.js} +3 -3
  108. package/dist/{chunk-S4MF77NV.js → chunk-XZPSBGHA.js} +2 -2
  109. package/dist/{chunk-PMRUMGK6.js → chunk-Y7COCXY2.js} +2 -2
  110. package/dist/{chunk-DJ7HMNSL.js → chunk-YCVB7X56.js} +4 -2
  111. package/dist/chunk-YCVB7X56.js.map +1 -0
  112. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  113. package/dist/{chunk-A5BYPCDI.js → chunk-Z334TJRB.js} +2 -2
  114. package/dist/cli.js +67 -66
  115. package/dist/coding/pre-action-gate.js +3 -3
  116. package/dist/compounding/engine.js +14 -14
  117. package/dist/connectors/codex-materialize-runner.js +14 -14
  118. package/dist/connectors/index.d.ts +45 -1
  119. package/dist/connectors/index.js +23 -15
  120. package/dist/convergence-refresh.js +16 -16
  121. package/dist/conversation-index/backend.js +2 -2
  122. package/dist/corpus-watermark.js +16 -16
  123. package/dist/dashboard-runtime.js +2 -2
  124. package/dist/direct-answer-wiring.js +3 -3
  125. package/dist/direct-answer.js +2 -2
  126. package/dist/entity-retrieval.js +14 -14
  127. package/dist/event-order-query.d.ts +3 -0
  128. package/dist/event-order-query.js +9 -0
  129. package/dist/event-order-query.js.map +1 -0
  130. package/dist/event-order-recall.d.ts +2 -2
  131. package/dist/event-order-recall.js +5 -2
  132. package/dist/external-wiki-access.js +34 -33
  133. package/dist/extraction-normalization.js +2 -2
  134. package/dist/extraction.js +23 -22
  135. package/dist/harmonic-construction.js +2 -2
  136. package/dist/harmonic-retrieval.js +2 -2
  137. package/dist/index.d.ts +2 -1
  138. package/dist/index.js +106 -103
  139. package/dist/intent.js +2 -1
  140. package/dist/lcm/engine.js +3 -3
  141. package/dist/lcm/index.js +6 -6
  142. package/dist/maintenance/memory-governance.js +14 -14
  143. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
  144. package/dist/maintenance/rebuild-memory-projection.js +15 -15
  145. package/dist/namespaces/migrate.js +15 -15
  146. package/dist/namespaces/search.js +9 -9
  147. package/dist/namespaces/storage.js +14 -14
  148. package/dist/operator-doctor-corpus.js +17 -17
  149. package/dist/operator-toolkit.js +21 -21
  150. package/dist/orchestration/maintenance.js +19 -19
  151. package/dist/orchestrator.js +99 -97
  152. package/dist/policy-runtime.js +3 -3
  153. package/dist/recall-planner-i18n.d.ts +31 -0
  154. package/dist/recall-planner-i18n.js +30 -0
  155. package/dist/recall-planner-i18n.js.map +1 -0
  156. package/dist/recall-planner-llm.js +2 -1
  157. package/dist/recall-planner-llm.js.map +1 -1
  158. package/dist/recall-query-policy.js +2 -2
  159. package/dist/recall-tokenization.js +1 -1
  160. package/dist/resume-bundles.js +3 -3
  161. package/dist/retrieval-agents.js +2 -1
  162. package/dist/search/factory.js +8 -8
  163. package/dist/search/index.js +14 -14
  164. package/dist/search/orama-backend.js +2 -2
  165. package/dist/semantic-consolidation.js +15 -15
  166. package/dist/semantic-rule-promotion.js +14 -14
  167. package/dist/semantic-rule-verifier.js +14 -14
  168. package/dist/source-agent-qualifier.js +20 -19
  169. package/dist/storage.js +13 -13
  170. package/dist/support-passport/index.js +36 -35
  171. package/dist/transfer/autodetect.js +1 -1
  172. package/dist/transfer/backup.js +1 -1
  173. package/dist/transfer/capsule-export.js +2 -2
  174. package/dist/trust-zones.js +2 -2
  175. package/dist/verified-recall.js +14 -14
  176. package/dist/work-product-ledger.js +2 -2
  177. package/package.json +2 -2
  178. package/src/connectors/droid-mcp.ts +434 -0
  179. package/src/connectors/index.ts +70 -0
  180. package/src/direct-answer.ts +6 -3
  181. package/src/event-order-query.ts +78 -0
  182. package/src/event-order-recall.ts +4 -90
  183. package/src/intent.ts +19 -19
  184. package/src/recall-planner-i18n.ts +193 -0
  185. package/src/recall-tokenization.ts +3 -1
  186. package/src/retrieval-agents.ts +6 -10
  187. package/dist/chunk-6GGTATZF.js.map +0 -1
  188. package/dist/chunk-ANMIOQPU.js.map +0 -1
  189. package/dist/chunk-DEOYTFA6.js.map +0 -1
  190. package/dist/chunk-DJ7HMNSL.js.map +0 -1
  191. package/dist/chunk-PD6O7AXF.js.map +0 -1
  192. package/dist/chunk-XPRJSHNI.js.map +0 -1
  193. /package/dist/{auto-sync-Z52VWMNC.js.map → auto-sync-BKRJDMKX.js.map} +0 -0
  194. /package/dist/{chunk-5F6HMNMZ.js.map → chunk-2LA3H54D.js.map} +0 -0
  195. /package/dist/{chunk-IRLH4NM2.js.map → chunk-2PSX5BJU.js.map} +0 -0
  196. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  197. /package/dist/{chunk-F2FZEVDE.js.map → chunk-3LJ2L3T3.js.map} +0 -0
  198. /package/dist/{chunk-AUIAHNO7.js.map → chunk-4NMVX5U7.js.map} +0 -0
  199. /package/dist/{chunk-LJOIZPJH.js.map → chunk-5QZR2RA3.js.map} +0 -0
  200. /package/dist/{chunk-RBJKE5LV.js.map → chunk-5UFQCU6M.js.map} +0 -0
  201. /package/dist/{chunk-S52C2DEM.js.map → chunk-5W5N7XJZ.js.map} +0 -0
  202. /package/dist/{chunk-GL4RHVHX.js.map → chunk-5W62VEFH.js.map} +0 -0
  203. /package/dist/{chunk-4WW5FMUD.js.map → chunk-6D7PZKCJ.js.map} +0 -0
  204. /package/dist/{chunk-NVSTZ2PN.js.map → chunk-6F2UMP4H.js.map} +0 -0
  205. /package/dist/{chunk-IIPJKCZB.js.map → chunk-6NAPOLRO.js.map} +0 -0
  206. /package/dist/{chunk-U4CCRHN6.js.map → chunk-6UZR7KEK.js.map} +0 -0
  207. /package/dist/{chunk-2TYIAKU5.js.map → chunk-6YMEU6OQ.js.map} +0 -0
  208. /package/dist/{chunk-LAX6S5WS.js.map → chunk-A73QHOZP.js.map} +0 -0
  209. /package/dist/{chunk-ZSH6GJ2V.js.map → chunk-AJSZ2EK6.js.map} +0 -0
  210. /package/dist/{chunk-GUBT77YC.js.map → chunk-B2OOJCUX.js.map} +0 -0
  211. /package/dist/{chunk-YTHQHH5U.js.map → chunk-C6WMSXCJ.js.map} +0 -0
  212. /package/dist/{chunk-JKW663ZN.js.map → chunk-CIAI24TQ.js.map} +0 -0
  213. /package/dist/{chunk-ALKRPLWB.js.map → chunk-DNRTKO2U.js.map} +0 -0
  214. /package/dist/{chunk-J5AFG5JN.js.map → chunk-EJLTNPRY.js.map} +0 -0
  215. /package/dist/{chunk-ORB56L3Y.js.map → chunk-EJQXDKYK.js.map} +0 -0
  216. /package/dist/{chunk-UM7A4CPT.js.map → chunk-FKJVEW6O.js.map} +0 -0
  217. /package/dist/{chunk-ZXMNT75M.js.map → chunk-GFNS3BHV.js.map} +0 -0
  218. /package/dist/{chunk-ALNZEWGN.js.map → chunk-GPFZFCRN.js.map} +0 -0
  219. /package/dist/{chunk-MQFFR6QB.js.map → chunk-GTRGH4ZT.js.map} +0 -0
  220. /package/dist/{chunk-USKANB65.js.map → chunk-I6OQCT3Y.js.map} +0 -0
  221. /package/dist/{chunk-2AZBPQLK.js.map → chunk-IKXUG6KC.js.map} +0 -0
  222. /package/dist/{chunk-5LVSFKQB.js.map → chunk-IM56VPKO.js.map} +0 -0
  223. /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
  224. /package/dist/{chunk-R7R4FSV2.js.map → chunk-ITYAXU4S.js.map} +0 -0
  225. /package/dist/{chunk-7CJO52ET.js.map → chunk-JJ7JW62R.js.map} +0 -0
  226. /package/dist/{chunk-5S7Y7AC6.js.map → chunk-JJX5XEIG.js.map} +0 -0
  227. /package/dist/{chunk-OF6KQJ35.js.map → chunk-JWPG65LH.js.map} +0 -0
  228. /package/dist/{chunk-G2FCSILA.js.map → chunk-KWIGDKM2.js.map} +0 -0
  229. /package/dist/{chunk-UKBIB3FP.js.map → chunk-KWN6NOHQ.js.map} +0 -0
  230. /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
  231. /package/dist/{chunk-SHSJP4D6.js.map → chunk-LZCSOUJ7.js.map} +0 -0
  232. /package/dist/{chunk-256FBCVX.js.map → chunk-M4AHBM72.js.map} +0 -0
  233. /package/dist/{chunk-5PFGMO33.js.map → chunk-MEW53VQJ.js.map} +0 -0
  234. /package/dist/{chunk-DCUMFQYM.js.map → chunk-ML3U4KPR.js.map} +0 -0
  235. /package/dist/{chunk-UDL4DNBM.js.map → chunk-MR5HWQHS.js.map} +0 -0
  236. /package/dist/{chunk-H7PRHUBD.js.map → chunk-NRLELHAY.js.map} +0 -0
  237. /package/dist/{chunk-ZS4JADYY.js.map → chunk-OW7NVMGQ.js.map} +0 -0
  238. /package/dist/{chunk-U5LYM2NS.js.map → chunk-PADG72LJ.js.map} +0 -0
  239. /package/dist/{chunk-UW74LP76.js.map → chunk-Q35XGIEM.js.map} +0 -0
  240. /package/dist/{chunk-FNYIMSKI.js.map → chunk-QSIQVC32.js.map} +0 -0
  241. /package/dist/{chunk-EJYAE2U7.js.map → chunk-R74NCKEY.js.map} +0 -0
  242. /package/dist/{chunk-KP36WQBJ.js.map → chunk-RYGJGXL6.js.map} +0 -0
  243. /package/dist/{chunk-4OW2T32G.js.map → chunk-SQ3EGGII.js.map} +0 -0
  244. /package/dist/{chunk-FU7OICXE.js.map → chunk-TRPX6F2G.js.map} +0 -0
  245. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  246. /package/dist/{chunk-6VX2ZZH2.js.map → chunk-VAMQU4W7.js.map} +0 -0
  247. /package/dist/{chunk-WLITCQAC.js.map → chunk-VN7IIQGS.js.map} +0 -0
  248. /package/dist/{chunk-MMM7SDOJ.js.map → chunk-WDUG2CH3.js.map} +0 -0
  249. /package/dist/{chunk-P2BT5ALE.js.map → chunk-X4MGNVOO.js.map} +0 -0
  250. /package/dist/{chunk-BE5SVRFC.js.map → chunk-XFCQIQQU.js.map} +0 -0
  251. /package/dist/{chunk-S4MF77NV.js.map → chunk-XZPSBGHA.js.map} +0 -0
  252. /package/dist/{chunk-PMRUMGK6.js.map → chunk-Y7COCXY2.js.map} +0 -0
  253. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  254. /package/dist/{chunk-A5BYPCDI.js.map → chunk-Z334TJRB.js.map} +0 -0
@@ -33,9 +33,9 @@ import {
33
33
  } from "./chunk-3WCASNQZ.js";
34
34
 
35
35
  // src/connectors/index.ts
36
- import fs3 from "fs";
37
- import path3 from "path";
38
- import os from "os";
36
+ import fs4 from "fs";
37
+ import path4 from "path";
38
+ import os2 from "os";
39
39
  import { createRequire } from "module";
40
40
  import { fileURLToPath } from "url";
41
41
 
@@ -398,9 +398,265 @@ function assertConfigComponentsNotSymlinked(cfgPath) {
398
398
  }
399
399
  }
400
400
 
401
- // src/connectors/codex-marketplace.ts
401
+ // src/connectors/droid-mcp.ts
402
402
  import fs2 from "fs";
403
403
  import path2 from "path";
404
+ import os from "os";
405
+ var DROID_CONNECTOR_MANIFEST = {
406
+ id: "droid",
407
+ name: "Factory Droid",
408
+ version: "1.0.0",
409
+ description: "Factory Droid \u2014 AI software engineering agent; memory via HTTP MCP with bearer auth",
410
+ capabilities: {
411
+ observe: true,
412
+ recall: true,
413
+ store: true,
414
+ search: true,
415
+ entities: true,
416
+ realtimeSync: true,
417
+ batch: true,
418
+ maxBudgetChars: 32e3,
419
+ connectionType: "mcp"
420
+ },
421
+ configSchema: {
422
+ mcpServerUrl: "URL of the MCP Remnic: server (default: http://127.0.0.1:4318/mcp)",
423
+ namespace: "Optional namespace"
424
+ },
425
+ homepage: "https://factory.ai",
426
+ author: "Remnic",
427
+ tags: ["official", "ai", "droid", "factory"],
428
+ requiresToken: true
429
+ };
430
+ function droidInstallStep(authToken, resolvedConfig, requiresToken, tokenEntry, priorTokenStore, saveTokenStoreFn) {
431
+ try {
432
+ const result = writeDroidMcpEntry(authToken, resolvedConfig);
433
+ return { ok: true, rollback: result.rollback, mcpPath: result.mcpPath };
434
+ } catch (droidErr) {
435
+ const errMsg = droidErr instanceof Error ? droidErr.message : String(droidErr);
436
+ let tokenSuffix = "";
437
+ if (requiresToken && tokenEntry !== null && priorTokenStore !== null) {
438
+ try {
439
+ saveTokenStoreFn(priorTokenStore);
440
+ tokenSuffix = " Token has been rolled back.";
441
+ } catch (e) {
442
+ tokenSuffix = ` Token rollback FAILED (${e instanceof Error ? e.message : String(e)}) \u2014 manually inspect ~/.remnic/tokens.json and reinstall.`;
443
+ }
444
+ }
445
+ return {
446
+ ok: false,
447
+ errorMessage: `Droid install aborted: ~/.factory/mcp.json write failed \u2014 ${errMsg}.${tokenSuffix} Resolve the write permission issue on ~/.factory/, then reinstall.`
448
+ };
449
+ }
450
+ }
451
+ function readDroidMcpProvenance(configPath) {
452
+ let mcpConfigPath = null;
453
+ let registryParseFailed = false;
454
+ if (!fs2.existsSync(configPath)) {
455
+ return { mcpConfigPath: null, registryParseFailed: false };
456
+ }
457
+ try {
458
+ const stored = JSON.parse(fs2.readFileSync(configPath, "utf8"));
459
+ if (typeof stored.factoryMcpPath === "string" && stored.factoryMcpPath.length > 0) {
460
+ mcpConfigPath = stored.factoryMcpPath;
461
+ }
462
+ } catch {
463
+ registryParseFailed = true;
464
+ }
465
+ if (mcpConfigPath === null && !registryParseFailed) {
466
+ try {
467
+ mcpConfigPath = resolveFactoryMcpPath();
468
+ } catch {
469
+ }
470
+ }
471
+ return { mcpConfigPath, registryParseFailed };
472
+ }
473
+ function writeSecretFileSync(filePath, data) {
474
+ const dir = path2.dirname(filePath);
475
+ const base = path2.basename(filePath);
476
+ const tmpPath = path2.join(
477
+ dir,
478
+ `.${base}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`
479
+ );
480
+ let wroteTemp = false;
481
+ try {
482
+ fs2.writeFileSync(tmpPath, data, { mode: 384, flag: "wx" });
483
+ wroteTemp = true;
484
+ try {
485
+ fs2.chmodSync(tmpPath, 384);
486
+ } catch {
487
+ }
488
+ fs2.renameSync(tmpPath, filePath);
489
+ try {
490
+ fs2.chmodSync(filePath, 384);
491
+ } catch {
492
+ }
493
+ } catch (err) {
494
+ if (wroteTemp) {
495
+ try {
496
+ fs2.unlinkSync(tmpPath);
497
+ } catch {
498
+ }
499
+ }
500
+ throw err;
501
+ }
502
+ }
503
+ function writeDroidMcpEntry(authToken, resolvedConfig) {
504
+ const mcpPath = resolveFactoryMcpPath();
505
+ const priorContent = readFactoryMcpIfExists(mcpPath);
506
+ const mcpConfig = upsertFactoryMcpRemnicEntry(priorContent, authToken, resolvedConfig);
507
+ fs2.mkdirSync(path2.dirname(mcpPath), { recursive: true });
508
+ const rollback = () => {
509
+ try {
510
+ if (priorContent === null) {
511
+ if (fs2.existsSync(mcpPath)) fs2.unlinkSync(mcpPath);
512
+ } else {
513
+ writeSecretFileSync(mcpPath, priorContent);
514
+ }
515
+ } catch {
516
+ }
517
+ };
518
+ try {
519
+ writeSecretFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
520
+ } catch (writeErr) {
521
+ try {
522
+ rollback();
523
+ } catch {
524
+ }
525
+ throw writeErr;
526
+ }
527
+ return { mcpPath, rollback };
528
+ }
529
+ function removeDroidMcpEntry(mcpPath) {
530
+ const expectedSuffix = path2.join(".factory", "mcp.json");
531
+ if (!path2.isAbsolute(mcpPath) || !mcpPath.endsWith(expectedSuffix)) {
532
+ throw new Error(
533
+ `MCP config path ${JSON.stringify(mcpPath)} failed safety validation (must be absolute and end with "${expectedSuffix}"). Refusing to modify \u2014 remove the "remnic" entry manually if it exists.`
534
+ );
535
+ }
536
+ const priorContent = readFactoryMcpIfExists(mcpPath);
537
+ if (priorContent === null) return null;
538
+ const updated = removeFactoryMcpRemnicEntry(priorContent);
539
+ if (updated === null) return null;
540
+ writeSecretFileSync(mcpPath, JSON.stringify(updated, null, 2));
541
+ return `Removed remnic entry from Droid MCP config: ${mcpPath}`;
542
+ }
543
+ function droidMcpDoctorCheck(savedPath) {
544
+ const mcpPath = savedPath ?? resolveFactoryMcpPath();
545
+ if (savedPath !== void 0) {
546
+ const expectedSuffix = path2.join(".factory", "mcp.json");
547
+ if (!path2.isAbsolute(savedPath) || !savedPath.endsWith(expectedSuffix)) {
548
+ return { name: "Droid MCP config", ok: false, detail: `Unsafe path in droid.json: ${savedPath}` };
549
+ }
550
+ }
551
+ try {
552
+ const raw = fs2.readFileSync(mcpPath, "utf8");
553
+ const parsed = JSON.parse(raw);
554
+ const servers = parsed.mcpServers;
555
+ if (typeof servers !== "object" || servers === null || !("remnic" in servers)) {
556
+ return { name: "Droid MCP config", ok: false, detail: `remnic entry missing in ${mcpPath} \u2014 run \`remnic connectors install droid\`` };
557
+ }
558
+ const remnic = servers.remnic;
559
+ if (remnic.type !== "http" || typeof remnic.url !== "string") {
560
+ return { name: "Droid MCP config", ok: false, detail: `remnic entry malformed in ${mcpPath}` };
561
+ }
562
+ const headers = remnic.headers;
563
+ const hasAuth = headers && typeof headers["Authorization"] === "string" && headers["Authorization"].startsWith("Bearer ");
564
+ return {
565
+ name: "Droid MCP config",
566
+ ok: !!hasAuth,
567
+ detail: hasAuth ? `remnic entry present in ${mcpPath}` : `remnic entry missing Authorization header in ${mcpPath} \u2014 run \`remnic connectors install droid\``
568
+ };
569
+ } catch {
570
+ return { name: "Droid MCP config", ok: false, detail: `Cannot read ${mcpPath} \u2014 run \`remnic connectors install droid\`` };
571
+ }
572
+ }
573
+ function resolveFactoryMcpPath() {
574
+ const envHome = readEnvVar("HOME");
575
+ const home = envHome && envHome.length > 0 ? envHome : os.homedir();
576
+ return path2.resolve(home, ".factory", "mcp.json");
577
+ }
578
+ function readFactoryMcpIfExists(mcpPath) {
579
+ try {
580
+ if (!fs2.existsSync(mcpPath)) return null;
581
+ return fs2.readFileSync(mcpPath, "utf8");
582
+ } catch {
583
+ return null;
584
+ }
585
+ }
586
+ var REMNIC_DEFAULT_MCP_URL = "http://127.0.0.1:4318/mcp";
587
+ function upsertFactoryMcpRemnicEntry(priorContent, authToken, resolvedConfig) {
588
+ let config;
589
+ if (priorContent !== null) {
590
+ try {
591
+ const parsed = JSON.parse(priorContent);
592
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
593
+ config = parsed;
594
+ } else {
595
+ console.warn("[remnic/connectors] ~/.factory/mcp.json contained non-object JSON; starting fresh.");
596
+ config = {};
597
+ }
598
+ } catch {
599
+ throw new Error(
600
+ "~/.factory/mcp.json contains malformed JSON and cannot be parsed. Fix the file manually before reinstalling, or use --force to overwrite (this will lose existing MCP server entries)."
601
+ );
602
+ }
603
+ } else {
604
+ config = {};
605
+ }
606
+ if (typeof config.mcpServers !== "object" || config.mcpServers === null || Array.isArray(config.mcpServers)) {
607
+ config.mcpServers = {};
608
+ }
609
+ const servers = config.mcpServers;
610
+ const mcpUrl = typeof resolvedConfig.mcpServerUrl === "string" && resolvedConfig.mcpServerUrl.length > 0 ? resolvedConfig.mcpServerUrl : REMNIC_DEFAULT_MCP_URL;
611
+ const remnicEntry = { type: "http", url: mcpUrl };
612
+ const REMNIC_MANAGED_HEADERS = /* @__PURE__ */ new Set(["Authorization", "X-Engram-Namespace"]);
613
+ const headers = {};
614
+ if (typeof servers.remnic === "object" && servers.remnic !== null && typeof servers.remnic.headers === "object" && servers.remnic.headers !== null) {
615
+ const priorHeaders = servers.remnic.headers;
616
+ for (const [key, value] of Object.entries(priorHeaders)) {
617
+ if (!REMNIC_MANAGED_HEADERS.has(key) && typeof value === "string") {
618
+ headers[key] = value;
619
+ }
620
+ }
621
+ }
622
+ if (authToken && authToken.length > 0) {
623
+ headers["Authorization"] = `Bearer ${authToken}`;
624
+ }
625
+ const namespace = typeof resolvedConfig.namespace === "string" && resolvedConfig.namespace.length > 0 ? resolvedConfig.namespace : void 0;
626
+ if (namespace) {
627
+ headers["X-Engram-Namespace"] = namespace;
628
+ }
629
+ if (Object.keys(headers).length > 0) {
630
+ remnicEntry.headers = headers;
631
+ }
632
+ servers.remnic = remnicEntry;
633
+ return config;
634
+ }
635
+ function removeFactoryMcpRemnicEntry(priorContent) {
636
+ let config;
637
+ try {
638
+ const parsed = JSON.parse(priorContent);
639
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
640
+ return null;
641
+ }
642
+ config = parsed;
643
+ } catch {
644
+ return null;
645
+ }
646
+ if (typeof config.mcpServers !== "object" || config.mcpServers === null) {
647
+ return null;
648
+ }
649
+ const servers = config.mcpServers;
650
+ if (!("remnic" in servers)) {
651
+ return null;
652
+ }
653
+ delete servers.remnic;
654
+ return config;
655
+ }
656
+
657
+ // src/connectors/codex-marketplace.ts
658
+ import fs3 from "fs";
659
+ import path3 from "path";
404
660
  var MARKETPLACE_SCHEMA_VERSION = 1;
405
661
  var MARKETPLACE_MANIFEST_FILENAME = "marketplace.json";
406
662
  var VALID_INSTALL_TYPES = /* @__PURE__ */ new Set(["github", "git", "local", "url"]);
@@ -502,12 +758,12 @@ async function writeMarketplaceManifest(outputDir, manifest) {
502
758
  `Refusing to write invalid manifest: ${validation.errors.join("; ")}`
503
759
  );
504
760
  }
505
- fs2.mkdirSync(outputDir, { recursive: true });
506
- const destPath = path2.join(outputDir, MARKETPLACE_MANIFEST_FILENAME);
761
+ fs3.mkdirSync(outputDir, { recursive: true });
762
+ const destPath = path3.join(outputDir, MARKETPLACE_MANIFEST_FILENAME);
507
763
  const tmpPath = `${destPath}.tmp.${process.pid}`;
508
764
  const content = JSON.stringify(manifest, null, 2) + "\n";
509
- fs2.writeFileSync(tmpPath, content);
510
- fs2.renameSync(tmpPath, destPath);
765
+ fs3.writeFileSync(tmpPath, content);
766
+ fs3.renameSync(tmpPath, destPath);
511
767
  }
512
768
  async function installFromMarketplace(source, sourceType, config, logger) {
513
769
  const _log = logger ?? {
@@ -567,12 +823,12 @@ async function resolveManifest(source, sourceType, logger) {
567
823
  }
568
824
  }
569
825
  function resolveLocal(dirPath, logger) {
570
- const manifestPath = path2.join(dirPath, MARKETPLACE_MANIFEST_FILENAME);
571
- if (!fs2.existsSync(manifestPath)) {
826
+ const manifestPath = path3.join(dirPath, MARKETPLACE_MANIFEST_FILENAME);
827
+ if (!fs3.existsSync(manifestPath)) {
572
828
  throw new Error(`marketplace.json not found at ${manifestPath}`);
573
829
  }
574
830
  logger.debug?.(`reading local marketplace manifest: ${manifestPath}`);
575
- const raw = fs2.readFileSync(manifestPath, "utf-8");
831
+ const raw = fs3.readFileSync(manifestPath, "utf-8");
576
832
  let parsed;
577
833
  try {
578
834
  parsed = JSON.parse(raw);
@@ -624,15 +880,15 @@ async function resolveGit(gitUrl, logger) {
624
880
  }
625
881
  function readPackageVersion() {
626
882
  const candidates = [
627
- path2.resolve(import.meta.dirname ?? ".", "../../../.."),
628
- path2.resolve(import.meta.dirname ?? ".", "../../../../.."),
629
- path2.resolve(import.meta.dirname ?? ".", "..")
883
+ path3.resolve(import.meta.dirname ?? ".", "../../../.."),
884
+ path3.resolve(import.meta.dirname ?? ".", "../../../../.."),
885
+ path3.resolve(import.meta.dirname ?? ".", "..")
630
886
  ];
631
887
  for (const candidate of candidates) {
632
- const pkgPath = path2.join(candidate, "package.json");
888
+ const pkgPath = path3.join(candidate, "package.json");
633
889
  try {
634
- if (!fs2.existsSync(pkgPath)) continue;
635
- const raw = fs2.readFileSync(pkgPath, "utf-8");
890
+ if (!fs3.existsSync(pkgPath)) continue;
891
+ const raw = fs3.readFileSync(pkgPath, "utf-8");
636
892
  const parsed = JSON.parse(raw);
637
893
  if (typeof parsed === "object" && parsed !== null && typeof parsed.version === "string") {
638
894
  return parsed.version;
@@ -991,7 +1247,8 @@ var BUILTIN_CONNECTORS = [
991
1247
  author: "Remnic",
992
1248
  tags: ["official", "python", "hermes"],
993
1249
  requiresToken: true
994
- }
1250
+ },
1251
+ DROID_CONNECTOR_MANIFEST
995
1252
  ];
996
1253
  var CONNECTOR_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
997
1254
  function isValidConnectorId(connectorId) {
@@ -1002,7 +1259,7 @@ function isConnectorManifest(value) {
1002
1259
  }
1003
1260
  function loadRegistry() {
1004
1261
  const regPath = getRegistryPath();
1005
- if (!fs3.existsSync(regPath)) {
1262
+ if (!fs4.existsSync(regPath)) {
1006
1263
  const registry = {
1007
1264
  connectors: BUILTIN_CONNECTORS,
1008
1265
  registryPath: regPath
@@ -1011,7 +1268,7 @@ function loadRegistry() {
1011
1268
  return registry;
1012
1269
  }
1013
1270
  try {
1014
- const raw = fs3.readFileSync(regPath, "utf8");
1271
+ const raw = fs4.readFileSync(regPath, "utf8");
1015
1272
  const parsed = JSON.parse(raw);
1016
1273
  if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.connectors)) {
1017
1274
  throw new Error("invalid registry schema");
@@ -1034,19 +1291,19 @@ function loadRegistry() {
1034
1291
  }
1035
1292
  function saveRegistry(registry) {
1036
1293
  const regPath = registry.registryPath;
1037
- fs3.mkdirSync(path3.dirname(regPath), { recursive: true });
1038
- fs3.writeFileSync(regPath, JSON.stringify({ connectors: registry.connectors }, null, 2));
1294
+ fs4.mkdirSync(path4.dirname(regPath), { recursive: true });
1295
+ fs4.writeFileSync(regPath, JSON.stringify({ connectors: registry.connectors }, null, 2));
1039
1296
  }
1040
1297
  function listConnectors() {
1041
1298
  const registry = loadRegistry();
1042
1299
  const connectorsDir = getConnectorsDir();
1043
1300
  const installedIds = /* @__PURE__ */ new Set();
1044
- if (fs3.existsSync(connectorsDir)) {
1045
- for (const entry of fs3.readdirSync(connectorsDir)) {
1301
+ if (fs4.existsSync(connectorsDir)) {
1302
+ for (const entry of fs4.readdirSync(connectorsDir)) {
1046
1303
  if (entry.endsWith(".json")) {
1047
1304
  try {
1048
1305
  const config = JSON.parse(
1049
- fs3.readFileSync(path3.join(connectorsDir, entry), "utf8")
1306
+ fs4.readFileSync(path4.join(connectorsDir, entry), "utf8")
1050
1307
  );
1051
1308
  if (isValidConnectorId(config.connectorId)) {
1052
1309
  installedIds.add(config.connectorId);
@@ -1062,9 +1319,9 @@ function listConnectors() {
1062
1319
  }));
1063
1320
  const installed = [];
1064
1321
  for (const id of installedIds) {
1065
- const configPath = path3.join(connectorsDir, `${id}.json`);
1322
+ const configPath = path4.join(connectorsDir, `${id}.json`);
1066
1323
  try {
1067
- const raw = JSON.parse(fs3.readFileSync(configPath, "utf8"));
1324
+ const raw = JSON.parse(fs4.readFileSync(configPath, "utf8"));
1068
1325
  const { token: _redacted, ...config } = raw;
1069
1326
  installed.push({
1070
1327
  connectorId: id,
@@ -1088,9 +1345,9 @@ function getConnectorToken(connectorId) {
1088
1345
  }
1089
1346
  }
1090
1347
  function readSavedConnectorConfig(configPath) {
1091
- if (!fs3.existsSync(configPath)) return {};
1348
+ if (!fs4.existsSync(configPath)) return {};
1092
1349
  try {
1093
- const parsed = JSON.parse(fs3.readFileSync(configPath, "utf8"));
1350
+ const parsed = JSON.parse(fs4.readFileSync(configPath, "utf8"));
1094
1351
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
1095
1352
  const {
1096
1353
  connectorId: _connectorId,
@@ -1144,10 +1401,10 @@ function installConnector(options) {
1144
1401
  let backfillNote = "";
1145
1402
  if (options.connectorId === "hermes") {
1146
1403
  try {
1147
- const hermesJsonPath = path3.join(getConnectorsDir(), "hermes.json");
1404
+ const hermesJsonPath = path4.join(getConnectorsDir(), "hermes.json");
1148
1405
  let parsed = null;
1149
1406
  try {
1150
- const parsedRaw = JSON.parse(fs3.readFileSync(hermesJsonPath, "utf8"));
1407
+ const parsedRaw = JSON.parse(fs4.readFileSync(hermesJsonPath, "utf8"));
1151
1408
  if (parsedRaw !== null && typeof parsedRaw === "object" && !Array.isArray(parsedRaw)) {
1152
1409
  parsed = parsedRaw;
1153
1410
  }
@@ -1163,7 +1420,7 @@ function installConnector(options) {
1163
1420
  currentConfigPath = hermesConfigPath(
1164
1421
  typeof profileRaw === "string" && profileRaw.length > 0 ? profileRaw : "default"
1165
1422
  );
1166
- activeConfigHasBlock = fs3.existsSync(currentConfigPath) && /^remnic:/m.test(fs3.readFileSync(currentConfigPath, "utf8"));
1423
+ activeConfigHasBlock = fs4.existsSync(currentConfigPath) && /^remnic:/m.test(fs4.readFileSync(currentConfigPath, "utf8"));
1167
1424
  } catch (resolveErr) {
1168
1425
  configResolutionError = resolveErr instanceof Error ? resolveErr.message : String(resolveErr);
1169
1426
  activeConfigHasBlock = false;
@@ -1226,7 +1483,7 @@ function installConnector(options) {
1226
1483
  parsed.pluginShimPath = outcome.persistPath;
1227
1484
  }
1228
1485
  try {
1229
- writeSecretFileSync(hermesJsonPath, JSON.stringify(parsed, null, 2));
1486
+ writeSecretFileSync2(hermesJsonPath, JSON.stringify(parsed, null, 2));
1230
1487
  } catch (persistErr) {
1231
1488
  const rollbackFailures = [];
1232
1489
  if (outcome.materializedAt !== null && outcome.createdNew && (priorPersisted === null || !sameShimTarget(outcome.materializedAt, priorPersisted))) {
@@ -1267,8 +1524,8 @@ function installConnector(options) {
1267
1524
  };
1268
1525
  }
1269
1526
  const configDir = getConnectorsDir();
1270
- fs3.mkdirSync(configDir, { recursive: true });
1271
- const configPath = path3.join(configDir, `${options.connectorId}.json`);
1527
+ fs4.mkdirSync(configDir, { recursive: true });
1528
+ const configPath = path4.join(configDir, `${options.connectorId}.json`);
1272
1529
  const savedConnectorConfig = existing ? readSavedConnectorConfig(configPath) : {};
1273
1530
  let hermesSavedProfile;
1274
1531
  let hermesSavedHost;
@@ -1279,9 +1536,9 @@ function installConnector(options) {
1279
1536
  let hermesResolvedPort;
1280
1537
  let hermesResolvedAllowInsecureHttp = false;
1281
1538
  if (options.connectorId === "hermes") {
1282
- if (fs3.existsSync(configPath)) {
1539
+ if (fs4.existsSync(configPath)) {
1283
1540
  try {
1284
- const prev = JSON.parse(fs3.readFileSync(configPath, "utf8"));
1541
+ const prev = JSON.parse(fs4.readFileSync(configPath, "utf8"));
1285
1542
  if (prev?.profile != null) {
1286
1543
  try {
1287
1544
  hermesSavedProfile = sanitizeHermesProfile(String(prev.profile));
@@ -1428,7 +1685,7 @@ function installConnector(options) {
1428
1685
  const envHermesHome = readEnvVar("HERMES_HOME");
1429
1686
  if (typeof envHermesHome === "string" && envHermesHome.trim().length > 0) {
1430
1687
  try {
1431
- fs3.mkdirSync(path3.dirname(hermesConfigPath(hermesProfile)), { recursive: true });
1688
+ fs4.mkdirSync(path4.dirname(hermesConfigPath(hermesProfile)), { recursive: true });
1432
1689
  } catch {
1433
1690
  }
1434
1691
  }
@@ -1474,9 +1731,9 @@ function installConnector(options) {
1474
1731
  let yamlRollbackErrMsg = "";
1475
1732
  try {
1476
1733
  if (yamlResult.priorContent === null) {
1477
- fs3.unlinkSync(yamlResult.configPath);
1734
+ fs4.unlinkSync(yamlResult.configPath);
1478
1735
  } else if (typeof yamlResult.priorContent === "string") {
1479
- writeSecretFileSync(yamlResult.configPath, yamlResult.priorContent);
1736
+ writeSecretFileSync2(yamlResult.configPath, yamlResult.priorContent);
1480
1737
  }
1481
1738
  } catch (yamlRestoreErr) {
1482
1739
  yamlRolledBack = false;
@@ -1549,7 +1806,7 @@ function installConnector(options) {
1549
1806
  let fallbackDetail = "";
1550
1807
  if (isPlausibleHermesConfigPath(priorConfigPath)) {
1551
1808
  try {
1552
- const beforeRefresh = fs3.readFileSync(priorConfigPath, "utf8");
1809
+ const beforeRefresh = fs4.readFileSync(priorConfigPath, "utf8");
1553
1810
  const refresh = upsertHermesConfigAt(priorConfigPath, {
1554
1811
  host: hermesHost,
1555
1812
  port: hermesPort,
@@ -1596,7 +1853,7 @@ function installConnector(options) {
1596
1853
  continue;
1597
1854
  }
1598
1855
  try {
1599
- const beforeCleanup = fs3.readFileSync(candidate, "utf8");
1856
+ const beforeCleanup = fs4.readFileSync(candidate, "utf8");
1600
1857
  const cleanup = removeHermesConfigFile(candidate);
1601
1858
  if (cleanup.updated) {
1602
1859
  hermesPriorConfigMutations.push({ mutatedPath: candidate, priorContent: beforeCleanup });
@@ -1619,7 +1876,7 @@ function installConnector(options) {
1619
1876
  }
1620
1877
  let blockSurvives = false;
1621
1878
  try {
1622
- blockSurvives = /^remnic:/m.test(fs3.readFileSync(candidate, "utf8"));
1879
+ blockSurvives = /^remnic:/m.test(fs4.readFileSync(candidate, "utf8"));
1623
1880
  } catch {
1624
1881
  blockSurvives = false;
1625
1882
  }
@@ -1635,7 +1892,7 @@ function installConnector(options) {
1635
1892
  delete resolvedConfig.priorHermesConfigPath;
1636
1893
  }
1637
1894
  try {
1638
- writeSecretFileSync(configPath, JSON.stringify(resolvedConfig, null, 2));
1895
+ writeSecretFileSync2(configPath, JSON.stringify(resolvedConfig, null, 2));
1639
1896
  } catch (writeErr) {
1640
1897
  let tokenRollbackFailed = false;
1641
1898
  let tokenRollbackMsg = "token store restored to pre-install snapshot";
@@ -1651,7 +1908,7 @@ function installConnector(options) {
1651
1908
  let unlinkSucceeded = false;
1652
1909
  let unlinkErr;
1653
1910
  try {
1654
- fs3.unlinkSync(yamlResult.configPath);
1911
+ fs4.unlinkSync(yamlResult.configPath);
1655
1912
  unlinkSucceeded = true;
1656
1913
  } catch (err) {
1657
1914
  unlinkErr = err;
@@ -1663,7 +1920,7 @@ function installConnector(options) {
1663
1920
  yamlRollbackMsg = `config.yaml rollback failed: could not remove newly-created file \u2014 ${unlinkMsg}`;
1664
1921
  }
1665
1922
  } else if (typeof yamlResult.priorContent === "string") {
1666
- writeSecretFileSync(yamlResult.configPath, yamlResult.priorContent);
1923
+ writeSecretFileSync2(yamlResult.configPath, yamlResult.priorContent);
1667
1924
  yamlRollbackMsg = "config.yaml restored to prior content";
1668
1925
  }
1669
1926
  } catch (yamlRollbackErr) {
@@ -1710,7 +1967,7 @@ function installConnector(options) {
1710
1967
  const priorConfigRollbackFailures = [];
1711
1968
  for (const mutation of [...hermesPriorConfigMutations].reverse()) {
1712
1969
  try {
1713
- writeSecretFileSync(mutation.mutatedPath, mutation.priorContent);
1970
+ writeSecretFileSync2(mutation.mutatedPath, mutation.priorContent);
1714
1971
  } catch (restoreErr) {
1715
1972
  priorConfigRollbackFailures.push(
1716
1973
  `could not restore ${mutation.mutatedPath} (${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)})`
@@ -1839,9 +2096,9 @@ function installConnector(options) {
1839
2096
  if (options.connectorId === "weclone") {
1840
2097
  try {
1841
2098
  let proxyConfigPath = null;
1842
- if (existing && fs3.existsSync(configPath)) {
2099
+ if (existing && fs4.existsSync(configPath)) {
1843
2100
  try {
1844
- const savedRegistryConfig = JSON.parse(fs3.readFileSync(configPath, "utf8"));
2101
+ const savedRegistryConfig = JSON.parse(fs4.readFileSync(configPath, "utf8"));
1845
2102
  if (typeof savedRegistryConfig.proxyConfigPath === "string" && savedRegistryConfig.proxyConfigPath.length > 0) {
1846
2103
  proxyConfigPath = savedRegistryConfig.proxyConfigPath;
1847
2104
  }
@@ -1857,21 +2114,21 @@ function installConnector(options) {
1857
2114
  priorConfig: prior ? safeParseJson(prior) : null,
1858
2115
  authToken: tokenEntry?.token
1859
2116
  });
1860
- fs3.mkdirSync(path3.dirname(proxyConfigPath), { recursive: true });
2117
+ fs4.mkdirSync(path4.dirname(proxyConfigPath), { recursive: true });
1861
2118
  weCloneProxyHandleRollback = () => {
1862
2119
  try {
1863
2120
  if (prior === null) {
1864
- if (fs3.existsSync(proxyConfigPath)) {
1865
- fs3.unlinkSync(proxyConfigPath);
2121
+ if (fs4.existsSync(proxyConfigPath)) {
2122
+ fs4.unlinkSync(proxyConfigPath);
1866
2123
  }
1867
2124
  } else {
1868
- writeSecretFileSync(proxyConfigPath, prior);
2125
+ writeSecretFileSync2(proxyConfigPath, prior);
1869
2126
  }
1870
2127
  } catch {
1871
2128
  }
1872
2129
  };
1873
2130
  try {
1874
- writeSecretFileSync(
2131
+ writeSecretFileSync2(
1875
2132
  proxyConfigPath,
1876
2133
  JSON.stringify(proxyConfig, null, 2)
1877
2134
  );
@@ -1908,6 +2165,22 @@ function installConnector(options) {
1908
2165
  };
1909
2166
  }
1910
2167
  }
2168
+ let droidMcpRollback = null;
2169
+ if (options.connectorId === "droid") {
2170
+ const stepResult = droidInstallStep(
2171
+ tokenEntry?.token,
2172
+ resolvedConfig,
2173
+ manifest.requiresToken ?? false,
2174
+ tokenEntry,
2175
+ nonHermesPriorTokenStore,
2176
+ saveTokenStore
2177
+ );
2178
+ if (!stepResult.ok) {
2179
+ return { connectorId: options.connectorId, status: "error", message: stepResult.errorMessage };
2180
+ }
2181
+ droidMcpRollback = stepResult.rollback;
2182
+ resolvedConfig.factoryMcpPath = stepResult.mcpPath;
2183
+ }
1911
2184
  const INTERNAL_KEYS_DENYLIST = [
1912
2185
  "extensionSourceDir"
1913
2186
  // test-only override for the plugin-codex source path
@@ -1916,7 +2189,7 @@ function installConnector(options) {
1916
2189
  delete resolvedConfig[key];
1917
2190
  }
1918
2191
  try {
1919
- writeSecretFileSync(configPath, JSON.stringify(resolvedConfig, null, 2));
2192
+ writeSecretFileSync2(configPath, JSON.stringify(resolvedConfig, null, 2));
1920
2193
  } catch (writeErr) {
1921
2194
  let configWriteTokenRolledBack = false;
1922
2195
  let configWriteTokenRollbackMsg = "";
@@ -1944,6 +2217,12 @@ function installConnector(options) {
1944
2217
  } catch {
1945
2218
  }
1946
2219
  }
2220
+ if (droidMcpRollback !== null) {
2221
+ try {
2222
+ droidMcpRollback();
2223
+ } catch {
2224
+ }
2225
+ }
1947
2226
  const configWriteTokenSuffix = manifest.requiresToken && tokenEntry !== null ? configWriteTokenRolledBack ? " Token has been rolled back." : ` Token rollback FAILED (${configWriteTokenRollbackMsg}) \u2014 tokens.json may contain an orphaned entry. Manually inspect ~/.remnic/tokens.json and reinstall.` : "";
1948
2227
  return {
1949
2228
  connectorId: options.connectorId,
@@ -1972,13 +2251,13 @@ function removeConnector(connectorId) {
1972
2251
  message: `Removal aborted: invalid connector ID ${JSON.stringify(connectorId)}. Connector IDs must match [A-Za-z0-9][A-Za-z0-9._-]*.`
1973
2252
  };
1974
2253
  }
1975
- const configPath = path3.join(configDir, `${connectorId}.json`);
2254
+ const configPath = path4.join(configDir, `${connectorId}.json`);
1976
2255
  let codexHomeOverride = null;
1977
2256
  let savedInstallExtension = void 0;
1978
2257
  let configParsed = false;
1979
- if (connectorId === "codex-cli" && fs3.existsSync(configPath)) {
2258
+ if (connectorId === "codex-cli" && fs4.existsSync(configPath)) {
1980
2259
  try {
1981
- const parsed = JSON.parse(fs3.readFileSync(configPath, "utf8"));
2260
+ const parsed = JSON.parse(fs4.readFileSync(configPath, "utf8"));
1982
2261
  configParsed = true;
1983
2262
  if (typeof parsed.codexHome === "string" && parsed.codexHome.length > 0) {
1984
2263
  codexHomeOverride = parsed.codexHome;
@@ -1997,9 +2276,9 @@ function removeConnector(connectorId) {
1997
2276
  let savedHermesConfigPath = null;
1998
2277
  const savedPriorHermesConfigPaths = [];
1999
2278
  const savedPriorHermesShimPaths = [];
2000
- if (connectorId === "hermes" && fs3.existsSync(configPath)) {
2279
+ if (connectorId === "hermes" && fs4.existsSync(configPath)) {
2001
2280
  try {
2002
- const parsedRaw = JSON.parse(fs3.readFileSync(configPath, "utf8"));
2281
+ const parsedRaw = JSON.parse(fs4.readFileSync(configPath, "utf8"));
2003
2282
  if (parsedRaw === null || typeof parsedRaw !== "object" || Array.isArray(parsedRaw)) {
2004
2283
  throw new Error("hermes.json is not a JSON object");
2005
2284
  }
@@ -2036,7 +2315,7 @@ function removeConnector(connectorId) {
2036
2315
  };
2037
2316
  }
2038
2317
  }
2039
- if (!fs3.existsSync(configPath)) {
2318
+ if (!fs4.existsSync(configPath)) {
2040
2319
  let staleTokenRevoked = false;
2041
2320
  try {
2042
2321
  staleTokenRevoked = revokeToken(connectorId);
@@ -2053,7 +2332,7 @@ function removeConnector(connectorId) {
2053
2332
  let storedProfile = "default";
2054
2333
  if (connectorId === "hermes") {
2055
2334
  try {
2056
- const stored = JSON.parse(fs3.readFileSync(configPath, "utf8"));
2335
+ const stored = JSON.parse(fs4.readFileSync(configPath, "utf8"));
2057
2336
  if (typeof stored?.profile === "string") storedProfile = stored.profile;
2058
2337
  } catch {
2059
2338
  }
@@ -2062,7 +2341,7 @@ function removeConnector(connectorId) {
2062
2341
  let weCloneRegistryParseFailed = false;
2063
2342
  if (connectorId === "weclone") {
2064
2343
  try {
2065
- const stored = JSON.parse(fs3.readFileSync(configPath, "utf8"));
2344
+ const stored = JSON.parse(fs4.readFileSync(configPath, "utf8"));
2066
2345
  if (typeof stored.proxyConfigPath === "string" && stored.proxyConfigPath.length > 0) {
2067
2346
  weCloneProxyConfigPath = stored.proxyConfigPath;
2068
2347
  }
@@ -2076,6 +2355,17 @@ function removeConnector(connectorId) {
2076
2355
  }
2077
2356
  }
2078
2357
  }
2358
+ let droidMcpConfigPath = null;
2359
+ let droidRegistryParseFailed = false;
2360
+ if (connectorId === "droid") {
2361
+ const prov = readDroidMcpProvenance(configPath);
2362
+ droidMcpConfigPath = prov.mcpConfigPath;
2363
+ droidRegistryParseFailed = prov.registryParseFailed;
2364
+ }
2365
+ if (connectorId === "droid" && droidRegistryParseFailed) {
2366
+ console.warn(`[remnic/connectors] removeConnector: droid.json malformed \u2014 aborting. Fix or delete ${configPath} manually and retry.`);
2367
+ return { connectorId, configPath, message: "Removal aborted: droid.json is malformed. Registry config left in place.", status: "skipped", reason: "config-parse-failed" };
2368
+ }
2079
2369
  if (connectorId === "weclone" && weCloneRegistryParseFailed) {
2080
2370
  console.warn(
2081
2371
  "[remnic/connectors] removeConnector: weclone.json is malformed \u2014 aborting removal to preserve provenance. Fix or delete " + configPath + " manually and retry."
@@ -2088,7 +2378,7 @@ function removeConnector(connectorId) {
2088
2378
  reason: "config-parse-failed"
2089
2379
  };
2090
2380
  }
2091
- if (connectorId === "codex-cli" && fs3.existsSync(configPath) && !configParsed) {
2381
+ if (connectorId === "codex-cli" && fs4.existsSync(configPath) && !configParsed) {
2092
2382
  console.warn(
2093
2383
  "[remnic/connectors] removeConnector: codex-cli.json is malformed \u2014 aborting removal to preserve provenance. Fix or delete " + configPath + " manually and retry."
2094
2384
  );
@@ -2131,7 +2421,7 @@ function removeConnector(connectorId) {
2131
2421
  for (const candidate of uniqueCandidates) {
2132
2422
  let needsCleanup = false;
2133
2423
  try {
2134
- needsCleanup = /^remnic:/m.test(fs3.readFileSync(candidate, "utf8"));
2424
+ needsCleanup = /^remnic:/m.test(fs4.readFileSync(candidate, "utf8"));
2135
2425
  } catch {
2136
2426
  needsCleanup = false;
2137
2427
  }
@@ -2145,8 +2435,8 @@ function removeConnector(connectorId) {
2145
2435
  continue;
2146
2436
  }
2147
2437
  try {
2148
- fs3.accessSync(candidate, fs3.constants.W_OK);
2149
- fs3.accessSync(path3.dirname(candidate), fs3.constants.W_OK);
2438
+ fs4.accessSync(candidate, fs4.constants.W_OK);
2439
+ fs4.accessSync(path4.dirname(candidate), fs4.constants.W_OK);
2150
2440
  } catch {
2151
2441
  blocked.push(`${candidate} (not writable)`);
2152
2442
  }
@@ -2161,7 +2451,7 @@ function removeConnector(connectorId) {
2161
2451
  }
2162
2452
  }
2163
2453
  try {
2164
- fs3.unlinkSync(configPath);
2454
+ fs4.unlinkSync(configPath);
2165
2455
  } catch (unlinkErr) {
2166
2456
  const sanitizedErr = unlinkErr instanceof Error ? unlinkErr.message : String(unlinkErr);
2167
2457
  return {
@@ -2187,14 +2477,14 @@ function removeConnector(connectorId) {
2187
2477
  "WeClone proxy config cleanup skipped: no persisted path found in saved config (likely a legacy install predating proxyConfigPath provenance)."
2188
2478
  );
2189
2479
  } else {
2190
- const expectedSuffix = path3.join("connectors", "weclone.json");
2191
- const isSafePath = path3.isAbsolute(weCloneProxyConfigPath) && weCloneProxyConfigPath.endsWith(expectedSuffix);
2480
+ const expectedSuffix = path4.join("connectors", "weclone.json");
2481
+ const isSafePath = path4.isAbsolute(weCloneProxyConfigPath) && weCloneProxyConfigPath.endsWith(expectedSuffix);
2192
2482
  if (!isSafePath) {
2193
2483
  weCloneProxyDeleteFailed = `Proxy config path ${JSON.stringify(weCloneProxyConfigPath)} failed safety validation (must be absolute and end with "${expectedSuffix}"). Refusing to delete \u2014 remove the file manually if it exists.`;
2194
2484
  } else {
2195
2485
  try {
2196
- if (fs3.existsSync(weCloneProxyConfigPath)) {
2197
- fs3.unlinkSync(weCloneProxyConfigPath);
2486
+ if (fs4.existsSync(weCloneProxyConfigPath)) {
2487
+ fs4.unlinkSync(weCloneProxyConfigPath);
2198
2488
  notes.push(`Removed WeClone proxy config: ${weCloneProxyConfigPath}`);
2199
2489
  }
2200
2490
  } catch (err) {
@@ -2212,6 +2502,23 @@ function removeConnector(connectorId) {
2212
2502
  message: `WeClone remove partially succeeded: ${tokenStatus}, but the proxy config at ${weCloneProxyConfigPath} could not be deleted (${weCloneProxyDeleteFailed}). Manually remove that file \u2014 it may still contain a Remnic daemon bearer token.`
2213
2503
  };
2214
2504
  }
2505
+ let droidMcpDeleteFailed = null;
2506
+ if (connectorId === "droid") {
2507
+ if (droidMcpConfigPath === null) {
2508
+ notes.push("Droid MCP config cleanup skipped: no persisted path found (legacy install).");
2509
+ } else {
2510
+ try {
2511
+ const note = removeDroidMcpEntry(droidMcpConfigPath);
2512
+ if (note) notes.push(note);
2513
+ } catch (err) {
2514
+ droidMcpDeleteFailed = err instanceof Error ? err.message : String(err);
2515
+ }
2516
+ }
2517
+ }
2518
+ if (droidMcpDeleteFailed !== null && droidMcpConfigPath !== null) {
2519
+ const ts = tokenRevoked ? "token was revoked" : "TOKEN REVOCATION ALSO FAILED \u2014 inspect ~/.remnic/tokens.json and revoke manually";
2520
+ 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.` };
2521
+ }
2215
2522
  if (connectorId === "hermes") {
2216
2523
  try {
2217
2524
  const shimCandidates = [];
@@ -2286,17 +2593,17 @@ function sanitizeHermesProfile(profile) {
2286
2593
  function hermesConfigPath(profile) {
2287
2594
  const safeProfile = sanitizeHermesProfile(profile);
2288
2595
  const hermesRoot = resolveHermesRoot();
2289
- const rootConfigPath = path3.join(hermesRoot, "config.yaml");
2290
- const profilesRoot = path3.join(hermesRoot, "profiles");
2596
+ const rootConfigPath = path4.join(hermesRoot, "config.yaml");
2597
+ const profilesRoot = path4.join(hermesRoot, "profiles");
2291
2598
  if (safeProfile === "default") {
2292
- const defaultProfileDir = path3.join(profilesRoot, safeProfile);
2293
- if (isFile(rootConfigPath) || !fs3.existsSync(rootConfigPath) && !isDirectory(defaultProfileDir)) {
2599
+ const defaultProfileDir = path4.join(profilesRoot, safeProfile);
2600
+ if (isFile(rootConfigPath) || !fs4.existsSync(rootConfigPath) && !isDirectory(defaultProfileDir)) {
2294
2601
  return rootConfigPath;
2295
2602
  }
2296
2603
  }
2297
- const cfgPath = path3.resolve(profilesRoot, safeProfile, "config.yaml");
2298
- const rel = path3.relative(profilesRoot, cfgPath);
2299
- if (rel.startsWith("..") || path3.isAbsolute(rel)) {
2604
+ const cfgPath = path4.resolve(profilesRoot, safeProfile, "config.yaml");
2605
+ const rel = path4.relative(profilesRoot, cfgPath);
2606
+ if (rel.startsWith("..") || path4.isAbsolute(rel)) {
2300
2607
  throw new Error(
2301
2608
  `Invalid Hermes profile path: resolved outside ${profilesRoot}`
2302
2609
  );
@@ -2305,30 +2612,30 @@ function hermesConfigPath(profile) {
2305
2612
  }
2306
2613
  function isDirectory(filePath) {
2307
2614
  try {
2308
- return fs3.statSync(filePath).isDirectory();
2615
+ return fs4.statSync(filePath).isDirectory();
2309
2616
  } catch {
2310
2617
  return false;
2311
2618
  }
2312
2619
  }
2313
2620
  function isFile(filePath) {
2314
2621
  try {
2315
- return fs3.statSync(filePath).isFile();
2622
+ return fs4.statSync(filePath).isFile();
2316
2623
  } catch {
2317
2624
  return false;
2318
2625
  }
2319
2626
  }
2320
2627
  function hermesConfigTarget(filePath) {
2321
2628
  try {
2322
- return fs3.realpathSync.native(filePath);
2629
+ return fs4.realpathSync.native(filePath);
2323
2630
  } catch {
2324
- return path3.resolve(filePath);
2631
+ return path4.resolve(filePath);
2325
2632
  }
2326
2633
  }
2327
2634
  function sameHermesConfigTarget(leftPath, rightPath) {
2328
2635
  return hermesConfigTarget(leftPath) === hermesConfigTarget(rightPath);
2329
2636
  }
2330
2637
  function hermesDefaultProfileConfigPath() {
2331
- return path3.join(resolveHermesRoot(), "profiles", "default", "config.yaml");
2638
+ return path4.join(resolveHermesRoot(), "profiles", "default", "config.yaml");
2332
2639
  }
2333
2640
  function hermesConfigCleanupPaths(profile) {
2334
2641
  const cfgPath = hermesConfigPath(profile);
@@ -2383,30 +2690,30 @@ function sanitizeHermesPort(port) {
2383
2690
  }
2384
2691
  return numeric;
2385
2692
  }
2386
- function writeSecretFileSync(filePath, data) {
2387
- const dir = path3.dirname(filePath);
2388
- const base = path3.basename(filePath);
2389
- const tmpPath = path3.join(
2693
+ function writeSecretFileSync2(filePath, data) {
2694
+ const dir = path4.dirname(filePath);
2695
+ const base = path4.basename(filePath);
2696
+ const tmpPath = path4.join(
2390
2697
  dir,
2391
2698
  `.${base}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`
2392
2699
  );
2393
2700
  let wroteTemp = false;
2394
2701
  try {
2395
- fs3.writeFileSync(tmpPath, data, { mode: 384, flag: "wx" });
2702
+ fs4.writeFileSync(tmpPath, data, { mode: 384, flag: "wx" });
2396
2703
  wroteTemp = true;
2397
2704
  try {
2398
- fs3.chmodSync(tmpPath, 384);
2705
+ fs4.chmodSync(tmpPath, 384);
2399
2706
  } catch {
2400
2707
  }
2401
- fs3.renameSync(tmpPath, filePath);
2708
+ fs4.renameSync(tmpPath, filePath);
2402
2709
  try {
2403
- fs3.chmodSync(filePath, 384);
2710
+ fs4.chmodSync(filePath, 384);
2404
2711
  } catch {
2405
2712
  }
2406
2713
  } catch (err) {
2407
2714
  if (wroteTemp) {
2408
2715
  try {
2409
- fs3.unlinkSync(tmpPath);
2716
+ fs4.unlinkSync(tmpPath);
2410
2717
  } catch {
2411
2718
  }
2412
2719
  }
@@ -2418,7 +2725,7 @@ function upsertHermesConfig(opts) {
2418
2725
  }
2419
2726
  function upsertHermesConfigAt(cfgPath, opts) {
2420
2727
  assertConfigComponentsNotSymlinked(cfgPath);
2421
- const profileDir = path3.dirname(cfgPath);
2728
+ const profileDir = path4.dirname(cfgPath);
2422
2729
  const safeHost = sanitizeHermesHost(opts.host);
2423
2730
  const safePort = sanitizeHermesPort(opts.port);
2424
2731
  const allowInsecureHttp = opts.allowInsecureHttp ?? false;
@@ -2440,15 +2747,15 @@ function upsertHermesConfigAt(cfgPath, opts) {
2440
2747
  ` token: "${opts.token}"`,
2441
2748
  ` allow_insecure_http: ${allowInsecureHttp}`
2442
2749
  ].join("\n");
2443
- if (!fs3.existsSync(cfgPath)) {
2444
- writeSecretFileSync(cfgPath, block + "\n");
2750
+ if (!fs4.existsSync(cfgPath)) {
2751
+ writeSecretFileSync2(cfgPath, block + "\n");
2445
2752
  return { updated: true, skipped: false, configPath: cfgPath, priorContent: null };
2446
2753
  }
2447
- const raw = fs3.readFileSync(cfgPath, "utf8");
2754
+ const raw = fs4.readFileSync(cfgPath, "utf8");
2448
2755
  const hasRemnicBlock = /^remnic:/m.test(raw);
2449
2756
  if (!hasRemnicBlock) {
2450
2757
  const separator = raw.endsWith("\n") ? "\n" : "\n\n";
2451
- writeSecretFileSync(cfgPath, raw + separator + block + "\n");
2758
+ writeSecretFileSync2(cfgPath, raw + separator + block + "\n");
2452
2759
  return { updated: true, skipped: false, configPath: cfgPath, priorContent: raw };
2453
2760
  }
2454
2761
  const splitLines = raw.split("\n");
@@ -2503,7 +2810,7 @@ function upsertHermesConfigAt(cfgPath, opts) {
2503
2810
  if (!written.token) newLines.push(` token: "${opts.token}"`);
2504
2811
  if (!written.allowInsecureHttp) newLines.push(` allow_insecure_http: ${allowInsecureHttp}`);
2505
2812
  }
2506
- writeSecretFileSync(cfgPath, newLines.join("\n") + "\n");
2813
+ writeSecretFileSync2(cfgPath, newLines.join("\n") + "\n");
2507
2814
  return { updated: true, skipped: false, configPath: cfgPath, priorContent: raw };
2508
2815
  }
2509
2816
  function removeHermesConfig(opts) {
@@ -2592,7 +2899,7 @@ function removeHermesConfigFile(cfgPath) {
2592
2899
  configPath: cfgPath
2593
2900
  };
2594
2901
  }
2595
- if (!fs3.existsSync(cfgPath)) {
2902
+ if (!fs4.existsSync(cfgPath)) {
2596
2903
  return {
2597
2904
  updated: false,
2598
2905
  skipped: true,
@@ -2600,7 +2907,7 @@ function removeHermesConfigFile(cfgPath) {
2600
2907
  configPath: cfgPath
2601
2908
  };
2602
2909
  }
2603
- const raw = fs3.readFileSync(cfgPath, "utf8");
2910
+ const raw = fs4.readFileSync(cfgPath, "utf8");
2604
2911
  if (!/^remnic:/m.test(raw)) {
2605
2912
  return {
2606
2913
  updated: false,
@@ -2629,7 +2936,7 @@ function removeHermesConfigFile(cfgPath) {
2629
2936
  while (newLines.length > 0 && newLines[newLines.length - 1]?.trim() === "") {
2630
2937
  newLines.pop();
2631
2938
  }
2632
- writeSecretFileSync(cfgPath, newLines.length > 0 ? newLines.join("\n") + "\n" : "");
2939
+ writeSecretFileSync2(cfgPath, newLines.length > 0 ? newLines.join("\n") + "\n" : "");
2633
2940
  return { updated: true, skipped: false, configPath: cfgPath };
2634
2941
  }
2635
2942
  async function doctorConnector(connectorId) {
@@ -2642,15 +2949,15 @@ async function doctorConnector(connectorId) {
2642
2949
  healthy: false
2643
2950
  };
2644
2951
  }
2645
- const configPath = path3.join(getConnectorsDir(), `${connectorId}.json`);
2952
+ const configPath = path4.join(getConnectorsDir(), `${connectorId}.json`);
2646
2953
  const checks = [];
2647
2954
  checks.push({
2648
2955
  name: "Config file",
2649
- ok: fs3.existsSync(configPath),
2956
+ ok: fs4.existsSync(configPath),
2650
2957
  detail: configPath
2651
2958
  });
2652
2959
  try {
2653
- const raw = fs3.readFileSync(configPath, "utf8");
2960
+ const raw = fs4.readFileSync(configPath, "utf8");
2654
2961
  JSON.parse(raw);
2655
2962
  checks.push({ name: "Config valid", ok: true, detail: "OK" });
2656
2963
  } catch (e) {
@@ -2674,12 +2981,15 @@ async function doctorConnector(connectorId) {
2674
2981
  }
2675
2982
  const memoryDir = instance.config.memoryDir;
2676
2983
  if (memoryDir) {
2677
- if (fs3.existsSync(memoryDir)) {
2984
+ if (fs4.existsSync(memoryDir)) {
2678
2985
  checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
2679
2986
  } else {
2680
2987
  checks.push({ name: "Memory directory", ok: false, detail: `Not found: ${memoryDir}` });
2681
2988
  }
2682
2989
  }
2990
+ if (connectorId === "droid") {
2991
+ checks.push(droidMcpDoctorCheck(instance.config.factoryMcpPath));
2992
+ }
2683
2993
  const healthy = checks.every((c) => c.ok);
2684
2994
  return { connectorId, checks, healthy };
2685
2995
  }
@@ -2688,32 +2998,32 @@ var CODEX_EXTENSIONS_SUBDIR = "memories_extensions";
2688
2998
  var REMNIC_EXTENSION_DIR_NAME = "remnic";
2689
2999
  function resolveCodexHome(override) {
2690
3000
  if (override && typeof override === "string" && override.trim().length > 0) {
2691
- return path3.resolve(override.trim());
3001
+ return path4.resolve(override.trim());
2692
3002
  }
2693
3003
  const envHome = readEnvVar("CODEX_HOME");
2694
3004
  if (envHome && envHome.trim().length > 0) {
2695
- return path3.resolve(envHome.trim());
3005
+ return path4.resolve(envHome.trim());
2696
3006
  }
2697
3007
  const home = readEnvVar("HOME") || readEnvVar("USERPROFILE") || resolveHomeDir();
2698
- return path3.resolve(home, ".codex");
3008
+ return path4.resolve(home, ".codex");
2699
3009
  }
2700
3010
  function resolveCodexMemoryExtensionPaths(codexHomeOverride) {
2701
3011
  const codexHome = resolveCodexHome(codexHomeOverride);
2702
- const memoriesDir = path3.join(codexHome, CODEX_MEMORIES_SUBDIR);
2703
- const extensionsRoot = path3.join(path3.dirname(memoriesDir), CODEX_EXTENSIONS_SUBDIR);
2704
- const remnicExtensionDir = path3.join(extensionsRoot, REMNIC_EXTENSION_DIR_NAME);
3012
+ const memoriesDir = path4.join(codexHome, CODEX_MEMORIES_SUBDIR);
3013
+ const extensionsRoot = path4.join(path4.dirname(memoriesDir), CODEX_EXTENSIONS_SUBDIR);
3014
+ const remnicExtensionDir = path4.join(extensionsRoot, REMNIC_EXTENSION_DIR_NAME);
2705
3015
  return { codexHome, memoriesDir, extensionsRoot, remnicExtensionDir };
2706
3016
  }
2707
3017
  function locatePluginCodexExtensionSource(override) {
2708
3018
  if (override && typeof override === "string" && override.trim().length > 0) {
2709
- const resolved = path3.resolve(override.trim());
2710
- if (fs3.existsSync(resolved) && fs3.statSync(resolved).isDirectory()) {
3019
+ const resolved = path4.resolve(override.trim());
3020
+ if (fs4.existsSync(resolved) && fs4.statSync(resolved).isDirectory()) {
2711
3021
  return resolved;
2712
3022
  }
2713
3023
  throw new Error(`Codex extension source directory not found: ${resolved}`);
2714
3024
  }
2715
- const EXTENSION_SUBPATH = path3.join("memories_extensions", "remnic");
2716
- const WORKSPACE_RELATIVE_PATH = path3.join(
3025
+ const EXTENSION_SUBPATH = path4.join("memories_extensions", "remnic");
3026
+ const WORKSPACE_RELATIVE_PATH = path4.join(
2717
3027
  "packages",
2718
3028
  "plugin-codex",
2719
3029
  "memories_extensions",
@@ -2721,15 +3031,15 @@ function locatePluginCodexExtensionSource(override) {
2721
3031
  );
2722
3032
  const searched = [];
2723
3033
  try {
2724
- const moduleDir = path3.dirname(fileURLToPath(import.meta.url));
2725
- const bundledCandidate = path3.join(moduleDir, "codex");
3034
+ const moduleDir = path4.dirname(fileURLToPath(import.meta.url));
3035
+ const bundledCandidate = path4.join(moduleDir, "codex");
2726
3036
  searched.push(bundledCandidate);
2727
- if (fs3.existsSync(bundledCandidate) && fs3.statSync(bundledCandidate).isDirectory()) {
3037
+ if (fs4.existsSync(bundledCandidate) && fs4.statSync(bundledCandidate).isDirectory()) {
2728
3038
  return bundledCandidate;
2729
3039
  }
2730
- const distConnectorsCandidate = path3.join(moduleDir, "connectors", "codex");
3040
+ const distConnectorsCandidate = path4.join(moduleDir, "connectors", "codex");
2731
3041
  searched.push(distConnectorsCandidate);
2732
- if (fs3.existsSync(distConnectorsCandidate) && fs3.statSync(distConnectorsCandidate).isDirectory()) {
3042
+ if (fs4.existsSync(distConnectorsCandidate) && fs4.statSync(distConnectorsCandidate).isDirectory()) {
2733
3043
  return distConnectorsCandidate;
2734
3044
  }
2735
3045
  } catch {
@@ -2737,19 +3047,19 @@ function locatePluginCodexExtensionSource(override) {
2737
3047
  try {
2738
3048
  const requireFromHere = createRequire(import.meta.url);
2739
3049
  const pluginPkgJsonPath = requireFromHere.resolve("@remnic/plugin-codex/package.json");
2740
- const pluginPkgRoot = path3.dirname(pluginPkgJsonPath);
2741
- const candidate = path3.join(pluginPkgRoot, EXTENSION_SUBPATH);
3050
+ const pluginPkgRoot = path4.dirname(pluginPkgJsonPath);
3051
+ const candidate = path4.join(pluginPkgRoot, EXTENSION_SUBPATH);
2742
3052
  searched.push(candidate);
2743
- if (fs3.existsSync(candidate) && fs3.statSync(candidate).isDirectory()) {
3053
+ if (fs4.existsSync(candidate) && fs4.statSync(candidate).isDirectory()) {
2744
3054
  return candidate;
2745
3055
  }
2746
3056
  } catch {
2747
3057
  }
2748
3058
  try {
2749
- const moduleDir = path3.dirname(fileURLToPath(import.meta.url));
3059
+ const moduleDir = path4.dirname(fileURLToPath(import.meta.url));
2750
3060
  let dir = moduleDir;
2751
3061
  for (let depth = 0; depth < 8; depth += 1) {
2752
- const candidate = path3.join(
3062
+ const candidate = path4.join(
2753
3063
  dir,
2754
3064
  "node_modules",
2755
3065
  "@remnic",
@@ -2757,10 +3067,10 @@ function locatePluginCodexExtensionSource(override) {
2757
3067
  EXTENSION_SUBPATH
2758
3068
  );
2759
3069
  searched.push(candidate);
2760
- if (fs3.existsSync(candidate) && fs3.statSync(candidate).isDirectory()) {
3070
+ if (fs4.existsSync(candidate) && fs4.statSync(candidate).isDirectory()) {
2761
3071
  return candidate;
2762
3072
  }
2763
- const parent = path3.dirname(dir);
3073
+ const parent = path4.dirname(dir);
2764
3074
  if (parent === dir) break;
2765
3075
  dir = parent;
2766
3076
  }
@@ -2768,19 +3078,19 @@ function locatePluginCodexExtensionSource(override) {
2768
3078
  }
2769
3079
  const anchors = [];
2770
3080
  try {
2771
- anchors.push(path3.dirname(fileURLToPath(import.meta.url)));
3081
+ anchors.push(path4.dirname(fileURLToPath(import.meta.url)));
2772
3082
  } catch {
2773
3083
  }
2774
3084
  anchors.push(process.cwd());
2775
3085
  for (const anchor of anchors) {
2776
3086
  let dir = anchor;
2777
3087
  for (let depth = 0; depth < 12; depth += 1) {
2778
- const candidate = path3.join(dir, WORKSPACE_RELATIVE_PATH);
3088
+ const candidate = path4.join(dir, WORKSPACE_RELATIVE_PATH);
2779
3089
  searched.push(candidate);
2780
- if (fs3.existsSync(candidate) && fs3.statSync(candidate).isDirectory()) {
3090
+ if (fs4.existsSync(candidate) && fs4.statSync(candidate).isDirectory()) {
2781
3091
  return candidate;
2782
3092
  }
2783
- const parent = path3.dirname(dir);
3093
+ const parent = path4.dirname(dir);
2784
3094
  if (parent === dir) break;
2785
3095
  dir = parent;
2786
3096
  }
@@ -2791,15 +3101,15 @@ function locatePluginCodexExtensionSource(override) {
2791
3101
  }
2792
3102
  function copyDirRecursiveSync(src, dest) {
2793
3103
  let count = 0;
2794
- fs3.mkdirSync(dest, { recursive: true });
2795
- const entries = fs3.readdirSync(src, { withFileTypes: true });
3104
+ fs4.mkdirSync(dest, { recursive: true });
3105
+ const entries = fs4.readdirSync(src, { withFileTypes: true });
2796
3106
  for (const entry of entries) {
2797
- const from = path3.join(src, entry.name);
2798
- const to = path3.join(dest, entry.name);
3107
+ const from = path4.join(src, entry.name);
3108
+ const to = path4.join(dest, entry.name);
2799
3109
  if (entry.isDirectory()) {
2800
3110
  count += copyDirRecursiveSync(from, to);
2801
3111
  } else if (entry.isFile()) {
2802
- fs3.copyFileSync(from, to);
3112
+ fs4.copyFileSync(from, to);
2803
3113
  count += 1;
2804
3114
  }
2805
3115
  }
@@ -2808,29 +3118,29 @@ function copyDirRecursiveSync(src, dest) {
2808
3118
  function installCodexMemoryExtension(options = {}) {
2809
3119
  const paths = resolveCodexMemoryExtensionPaths(options.codexHome ?? null);
2810
3120
  const sourceDir = locatePluginCodexExtensionSource(options.sourceDir ?? null);
2811
- fs3.mkdirSync(paths.extensionsRoot, { recursive: true });
3121
+ fs4.mkdirSync(paths.extensionsRoot, { recursive: true });
2812
3122
  const tmpPrefix = `.${REMNIC_EXTENSION_DIR_NAME}.tmp-`;
2813
3123
  const STALE_TMP_THRESHOLD_MS = 10 * 60 * 1e3;
2814
3124
  const now = Date.now();
2815
3125
  try {
2816
- const existingEntries = fs3.readdirSync(paths.extensionsRoot);
3126
+ const existingEntries = fs4.readdirSync(paths.extensionsRoot);
2817
3127
  for (const entry of existingEntries) {
2818
3128
  if (!entry.startsWith(tmpPrefix)) continue;
2819
- const stalePath = path3.join(paths.extensionsRoot, entry);
3129
+ const stalePath = path4.join(paths.extensionsRoot, entry);
2820
3130
  try {
2821
- const stat = fs3.statSync(stalePath);
3131
+ const stat = fs4.statSync(stalePath);
2822
3132
  const ageMs = now - stat.mtimeMs;
2823
3133
  if (ageMs < STALE_TMP_THRESHOLD_MS) {
2824
3134
  continue;
2825
3135
  }
2826
- fs3.rmSync(stalePath, { recursive: true, force: true });
3136
+ fs4.rmSync(stalePath, { recursive: true, force: true });
2827
3137
  } catch {
2828
3138
  }
2829
3139
  }
2830
3140
  } catch {
2831
3141
  }
2832
3142
  const tmpName = `${tmpPrefix}${process.pid}-${Date.now()}`;
2833
- const tmpDir = path3.join(paths.extensionsRoot, tmpName);
3143
+ const tmpDir = path4.join(paths.extensionsRoot, tmpName);
2834
3144
  let filesCopied = 0;
2835
3145
  let commitFn = () => {
2836
3146
  };
@@ -2839,16 +3149,16 @@ function installCodexMemoryExtension(options = {}) {
2839
3149
  try {
2840
3150
  filesCopied = copyDirRecursiveSync(sourceDir, tmpDir);
2841
3151
  const backupDir = `${paths.remnicExtensionDir}.bak-${Date.now()}`;
2842
- const hadExisting = fs3.existsSync(paths.remnicExtensionDir);
3152
+ const hadExisting = fs4.existsSync(paths.remnicExtensionDir);
2843
3153
  if (hadExisting) {
2844
- fs3.renameSync(paths.remnicExtensionDir, backupDir);
3154
+ fs4.renameSync(paths.remnicExtensionDir, backupDir);
2845
3155
  }
2846
3156
  try {
2847
- fs3.renameSync(tmpDir, paths.remnicExtensionDir);
3157
+ fs4.renameSync(tmpDir, paths.remnicExtensionDir);
2848
3158
  } catch (renameErr) {
2849
3159
  if (hadExisting) {
2850
3160
  try {
2851
- fs3.renameSync(backupDir, paths.remnicExtensionDir);
3161
+ fs4.renameSync(backupDir, paths.remnicExtensionDir);
2852
3162
  } catch {
2853
3163
  }
2854
3164
  }
@@ -2857,7 +3167,7 @@ function installCodexMemoryExtension(options = {}) {
2857
3167
  commitFn = () => {
2858
3168
  if (hadExisting) {
2859
3169
  try {
2860
- fs3.rmSync(backupDir, { recursive: true, force: true });
3170
+ fs4.rmSync(backupDir, { recursive: true, force: true });
2861
3171
  } catch {
2862
3172
  }
2863
3173
  }
@@ -2865,31 +3175,31 @@ function installCodexMemoryExtension(options = {}) {
2865
3175
  rollbackFn = () => {
2866
3176
  if (hadExisting) {
2867
3177
  try {
2868
- if (fs3.existsSync(paths.remnicExtensionDir)) {
2869
- fs3.rmSync(paths.remnicExtensionDir, { recursive: true, force: true });
3178
+ if (fs4.existsSync(paths.remnicExtensionDir)) {
3179
+ fs4.rmSync(paths.remnicExtensionDir, { recursive: true, force: true });
2870
3180
  }
2871
- fs3.renameSync(backupDir, paths.remnicExtensionDir);
3181
+ fs4.renameSync(backupDir, paths.remnicExtensionDir);
2872
3182
  } catch {
2873
3183
  }
2874
3184
  } else {
2875
3185
  try {
2876
- if (fs3.existsSync(paths.remnicExtensionDir)) {
2877
- fs3.rmSync(paths.remnicExtensionDir, { recursive: true, force: true });
3186
+ if (fs4.existsSync(paths.remnicExtensionDir)) {
3187
+ fs4.rmSync(paths.remnicExtensionDir, { recursive: true, force: true });
2878
3188
  }
2879
3189
  } catch {
2880
3190
  }
2881
3191
  }
2882
3192
  };
2883
3193
  } catch (err) {
2884
- if (fs3.existsSync(tmpDir)) {
3194
+ if (fs4.existsSync(tmpDir)) {
2885
3195
  try {
2886
- fs3.rmSync(tmpDir, { recursive: true, force: true });
3196
+ fs4.rmSync(tmpDir, { recursive: true, force: true });
2887
3197
  } catch {
2888
3198
  }
2889
3199
  }
2890
3200
  throw err;
2891
3201
  }
2892
- const instructionsPath = path3.join(paths.remnicExtensionDir, "instructions.md");
3202
+ const instructionsPath = path4.join(paths.remnicExtensionDir, "instructions.md");
2893
3203
  return {
2894
3204
  ...paths,
2895
3205
  instructionsPath,
@@ -2901,8 +3211,8 @@ function installCodexMemoryExtension(options = {}) {
2901
3211
  function removeCodexMemoryExtension(options = {}) {
2902
3212
  const paths = resolveCodexMemoryExtensionPaths(options.codexHome ?? null);
2903
3213
  let removed = false;
2904
- if (fs3.existsSync(paths.remnicExtensionDir)) {
2905
- fs3.rmSync(paths.remnicExtensionDir, { recursive: true, force: true });
3214
+ if (fs4.existsSync(paths.remnicExtensionDir)) {
3215
+ fs4.rmSync(paths.remnicExtensionDir, { recursive: true, force: true });
2906
3216
  removed = true;
2907
3217
  }
2908
3218
  return { ...paths, removed };
@@ -2913,11 +3223,11 @@ function resolveWeCloneProxyConfigPath() {
2913
3223
  const remnicHome = readEnvVar("REMNIC_HOME");
2914
3224
  const override = remnicHome && remnicHome.length > 0 ? remnicHome : readEnvVar("ENGRAM_HOME");
2915
3225
  if (override && override.length > 0) {
2916
- return path3.resolve(expandTildePath(override), "connectors", WECLONE_PROXY_CONFIG_FILENAME);
3226
+ return path4.resolve(expandTildePath(override), "connectors", WECLONE_PROXY_CONFIG_FILENAME);
2917
3227
  }
2918
3228
  const envHome = readEnvVar("HOME");
2919
- const home = envHome && envHome.length > 0 ? envHome : os.homedir();
2920
- return path3.resolve(
3229
+ const home = envHome && envHome.length > 0 ? envHome : os2.homedir();
3230
+ return path4.resolve(
2921
3231
  home,
2922
3232
  WECLONE_PROXY_CONFIG_DIRNAME,
2923
3233
  "connectors",
@@ -2926,8 +3236,8 @@ function resolveWeCloneProxyConfigPath() {
2926
3236
  }
2927
3237
  function readWeCloneProxyConfigIfExists(configPath) {
2928
3238
  try {
2929
- if (!fs3.existsSync(configPath)) return null;
2930
- return fs3.readFileSync(configPath, "utf8");
3239
+ if (!fs4.existsSync(configPath)) return null;
3240
+ return fs4.readFileSync(configPath, "utf8");
2931
3241
  } catch {
2932
3242
  return null;
2933
3243
  }
@@ -3047,6 +3357,10 @@ function buildWeCloneProxyConfig(args) {
3047
3357
  }
3048
3358
 
3049
3359
  export {
3360
+ DROID_CONNECTOR_MANIFEST,
3361
+ resolveFactoryMcpPath,
3362
+ upsertFactoryMcpRemnicEntry,
3363
+ removeFactoryMcpRemnicEntry,
3050
3364
  MARKETPLACE_SCHEMA_VERSION,
3051
3365
  MARKETPLACE_MANIFEST_FILENAME,
3052
3366
  generateMarketplaceManifest,
@@ -3074,4 +3388,4 @@ export {
3074
3388
  resolveWeCloneProxyConfigPath,
3075
3389
  buildWeCloneProxyConfig
3076
3390
  };
3077
- //# sourceMappingURL=chunk-ANMIOQPU.js.map
3391
+ //# sourceMappingURL=chunk-4XN35YQD.js.map