@remnic/core 10.0.91 → 10.0.92

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 (229) hide show
  1. package/dist/access-admin-ops-surface.js +15 -15
  2. package/dist/access-authorization-probe.js +16 -16
  3. package/dist/access-boundary.js +15 -15
  4. package/dist/access-cli.js +59 -59
  5. package/dist/access-extraction-force-flush.js +15 -15
  6. package/dist/access-http-briefing.js +16 -16
  7. package/dist/access-http-query.js +17 -17
  8. package/dist/access-http.js +32 -32
  9. package/dist/access-identity-continuity-surface.js +15 -15
  10. package/dist/access-lcm-surface.js +15 -15
  11. package/dist/access-mcp.js +25 -25
  12. package/dist/access-namespace-preflight.js +15 -15
  13. package/dist/access-observe-write-surface.js +15 -15
  14. package/dist/access-operations-batch.js +16 -16
  15. package/dist/access-operations.js +23 -23
  16. package/dist/access-recall-concurrency.js +15 -15
  17. package/dist/access-recall-diagnostics.js +2 -2
  18. package/dist/access-recall-response.js +15 -15
  19. package/dist/access-recall-surface.js +15 -15
  20. package/dist/access-service.d.ts +1 -0
  21. package/dist/access-service.d.ts.map +1 -1
  22. package/dist/access-service.js +15 -15
  23. package/dist/access-surface-catalog.js +17 -17
  24. package/dist/active-recall.js +3 -3
  25. package/dist/briefing.js +3 -3
  26. package/dist/causal-consolidation.js +4 -4
  27. package/dist/{chunk-VMVVSZTD.js → chunk-2FGLEF7C.js} +2 -2
  28. package/dist/{chunk-VNUOAXWP.js → chunk-3RLK65ZK.js} +2 -2
  29. package/dist/{chunk-V4XE263I.js → chunk-43AA5FVD.js} +1 -1
  30. package/dist/chunk-43AA5FVD.js.map +1 -0
  31. package/dist/{chunk-EV76IZ37.js → chunk-4J363OAA.js} +2 -2
  32. package/dist/{chunk-27XYV2XL.js → chunk-4WR2OD7K.js} +2 -2
  33. package/dist/{chunk-J4MMPQ7Q.js → chunk-5HFXGXE5.js} +3 -3
  34. package/dist/{chunk-XICOH5HT.js → chunk-5M5M22GW.js} +2 -2
  35. package/dist/{chunk-Z4Q6USKJ.js → chunk-6F42QONS.js} +2 -2
  36. package/dist/{chunk-ADYP7HXE.js → chunk-6F5MJFXY.js} +3 -3
  37. package/dist/{chunk-LJQFJF4J.js → chunk-7GLJMDEQ.js} +2 -2
  38. package/dist/{chunk-SHUBTAY2.js → chunk-7W3RXOIG.js} +7 -7
  39. package/dist/{chunk-QL7RHYK6.js → chunk-ATPWZ4F7.js} +3 -3
  40. package/dist/{chunk-YS2GHSWN.js → chunk-B4QYQFGY.js} +7 -4
  41. package/dist/chunk-B4QYQFGY.js.map +1 -0
  42. package/dist/{chunk-MVMRUGBH.js → chunk-BJRTMNCB.js} +5 -5
  43. package/dist/{chunk-5UCMYPVF.js → chunk-BLJT6JP2.js} +2 -2
  44. package/dist/{chunk-RSK2WIEM.js → chunk-BQZEGOZ4.js} +2 -2
  45. package/dist/{chunk-PUEO37QG.js → chunk-BRLXOZLM.js} +2 -2
  46. package/dist/{chunk-GRTKLWYX.js → chunk-BSACVS6R.js} +3 -3
  47. package/dist/{chunk-ODL4ZTNI.js → chunk-DKAA2IHQ.js} +12 -12
  48. package/dist/{chunk-3XIWW4TB.js → chunk-E3A7ELSG.js} +2 -2
  49. package/dist/{chunk-P5VZSSYL.js → chunk-E4IRW2FG.js} +8 -8
  50. package/dist/{chunk-N74SGESS.js → chunk-E7YZXWIS.js} +2 -2
  51. package/dist/{chunk-ZT6WPSII.js → chunk-ETZLQOUR.js} +2 -2
  52. package/dist/{chunk-JBCCWVU2.js → chunk-EXHXJETE.js} +2 -2
  53. package/dist/{chunk-APYY5CX3.js → chunk-F55YQP7N.js} +5 -4
  54. package/dist/chunk-F55YQP7N.js.map +1 -0
  55. package/dist/{chunk-TRBGGJKZ.js → chunk-FLRP63GU.js} +25 -24
  56. package/dist/chunk-FLRP63GU.js.map +1 -0
  57. package/dist/{chunk-KEPXC4KN.js → chunk-FNXQZGUS.js} +2 -2
  58. package/dist/{chunk-JC36FPQ5.js → chunk-FQKBJJYB.js} +2 -2
  59. package/dist/{chunk-WWK6J6SE.js → chunk-FSO3G4JJ.js} +2 -2
  60. package/dist/{chunk-FRSHF6FU.js → chunk-GVGAO3WV.js} +2 -2
  61. package/dist/{chunk-RYWROSL5.js → chunk-HF3BKUVV.js} +3 -3
  62. package/dist/{chunk-NJJMVS5Y.js → chunk-HH5LY6RR.js} +2 -2
  63. package/dist/{chunk-HVKUCT3W.js → chunk-HVX4LPNY.js} +2 -2
  64. package/dist/{chunk-WUUES6CU.js → chunk-ID6JGIMD.js} +2 -2
  65. package/dist/{chunk-7L3TODI7.js → chunk-JV4S6VDH.js} +2 -2
  66. package/dist/{chunk-3UMDRGFS.js → chunk-LUJCQQ3L.js} +2 -2
  67. package/dist/{chunk-6HM6HARE.js → chunk-MB6ZJDN6.js} +2 -2
  68. package/dist/{chunk-GGRRF4PZ.js → chunk-MDPT6QFK.js} +1 -1
  69. package/dist/{chunk-GGRRF4PZ.js.map → chunk-MDPT6QFK.js.map} +1 -1
  70. package/dist/{chunk-AH637HZ5.js → chunk-MXHMNKWG.js} +2 -2
  71. package/dist/{chunk-OFVCFKDH.js → chunk-N4KAE2NB.js} +2 -2
  72. package/dist/{chunk-BCCG7VWM.js → chunk-NBH6K6G5.js} +63 -9
  73. package/dist/chunk-NBH6K6G5.js.map +1 -0
  74. package/dist/{chunk-ATPWMT2E.js → chunk-NTRUKAAE.js} +2 -2
  75. package/dist/{chunk-VPQFK63H.js → chunk-P4WNBSTW.js} +2 -2
  76. package/dist/{chunk-EURPSF4Y.js → chunk-PH5ZQM35.js} +2 -2
  77. package/dist/{chunk-ZZ67UTQX.js → chunk-PMJFRDJI.js} +2 -2
  78. package/dist/{chunk-RO7RUBLD.js → chunk-PWXPRVLK.js} +2 -2
  79. package/dist/{chunk-66L5ZRJC.js → chunk-QJPJXCS4.js} +2 -2
  80. package/dist/{chunk-WLBEZZK5.js → chunk-R2LBF4HH.js} +3 -3
  81. package/dist/{chunk-EWJZZDRG.js → chunk-RHQLIHMB.js} +2 -2
  82. package/dist/{chunk-6QMWECO5.js → chunk-RIMK327Y.js} +2 -2
  83. package/dist/{chunk-QVMOCJRV.js → chunk-RRJBDXAQ.js} +2 -2
  84. package/dist/{chunk-AOFEMUHG.js → chunk-SUSW74WU.js} +3 -3
  85. package/dist/{chunk-63O7LVMN.js → chunk-U6UNF5ZS.js} +2 -2
  86. package/dist/{chunk-KZSGBWOJ.js → chunk-V2KGDESV.js} +2 -2
  87. package/dist/{chunk-ZCLEYJPB.js → chunk-X562NQFA.js} +26 -25
  88. package/dist/chunk-X562NQFA.js.map +1 -0
  89. package/dist/{chunk-KUIRDD74.js → chunk-XDSCJOH7.js} +4 -4
  90. package/dist/{chunk-7O2MC42R.js → chunk-XNRLRNQF.js} +2 -2
  91. package/dist/{chunk-GNXGJBCA.js → chunk-XYKBWTWI.js} +2 -2
  92. package/dist/{chunk-BMWMTAQF.js → chunk-Z7JIZ42P.js} +2 -2
  93. package/dist/{chunk-STSLB4HT.js → chunk-ZTTCDQ4I.js} +16 -13
  94. package/dist/chunk-ZTTCDQ4I.js.map +1 -0
  95. package/dist/cli.d.ts.map +1 -1
  96. package/dist/cli.js +47 -47
  97. package/dist/coding/export-okf-codegraph.js +2 -2
  98. package/dist/compounding/engine.js +4 -4
  99. package/dist/config.d.ts.map +1 -1
  100. package/dist/config.js +3 -3
  101. package/dist/connectors/codex-materialize-runner.js +3 -3
  102. package/dist/connectors/index.js +3 -3
  103. package/dist/connectors/live/framework.d.ts +7 -0
  104. package/dist/connectors/live/framework.d.ts.map +1 -1
  105. package/dist/connectors/live/google-drive.d.ts +15 -3
  106. package/dist/connectors/live/google-drive.d.ts.map +1 -1
  107. package/dist/convergence-refresh.js +5 -5
  108. package/dist/corpus-watermark.js +5 -5
  109. package/dist/entity-retrieval.js +3 -3
  110. package/dist/external-wiki-access.js +16 -16
  111. package/dist/extraction.js +3 -3
  112. package/dist/harmonic-retrieval.js +3 -3
  113. package/dist/index.js +59 -59
  114. package/dist/live-connectors-runner.d.ts +2 -0
  115. package/dist/live-connectors-runner.d.ts.map +1 -1
  116. package/dist/live-connectors-runner.js +3 -3
  117. package/dist/location/index.js +5 -5
  118. package/dist/maintenance/memory-governance.js +3 -3
  119. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  120. package/dist/maintenance/rebuild-memory-projection-runner.js +5 -5
  121. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  122. package/dist/memory-browse-operations.js +16 -16
  123. package/dist/namespaces/migrate.js +4 -4
  124. package/dist/namespaces/storage.js +3 -3
  125. package/dist/operator-doctor-corpus.js +6 -6
  126. package/dist/operator-toolkit.js +12 -12
  127. package/dist/orchestration/backlog-scheduler.js +60 -60
  128. package/dist/orchestration/buffer-drain-runner.js +60 -60
  129. package/dist/orchestration/maintenance.js +13 -13
  130. package/dist/orchestrator.d.ts +2 -0
  131. package/dist/orchestrator.d.ts.map +1 -1
  132. package/dist/orchestrator.js +59 -59
  133. package/dist/recall-explain-renderer.js +3 -3
  134. package/dist/recall-navigate-access.js +2 -2
  135. package/dist/recall-navigate-disclosure.js +2 -2
  136. package/dist/recall-navigate.js +2 -2
  137. package/dist/recall-navigation-operations.js +16 -16
  138. package/dist/recall-navigation.js +15 -15
  139. package/dist/recall-xray-cli.js +4 -4
  140. package/dist/recall-xray-renderer.js +3 -3
  141. package/dist/recall-xray.js +2 -2
  142. package/dist/resume-bundles.js +4 -4
  143. package/dist/semantic-consolidation.js +4 -4
  144. package/dist/semantic-rule-promotion.js +3 -3
  145. package/dist/semantic-rule-verifier.js +3 -3
  146. package/dist/source-agent-qualifier.js +3 -3
  147. package/dist/standup/build.js +3 -3
  148. package/dist/{state-store-I5HLZTZT.js → state-store-EEAX2MBS.js} +2 -2
  149. package/dist/storage.js +2 -2
  150. package/dist/support-passport/index.js +18 -18
  151. package/dist/transfer/export-okf.js +3 -3
  152. package/dist/types.d.ts +10 -10
  153. package/dist/types.d.ts.map +1 -1
  154. package/dist/types.js +1 -1
  155. package/dist/verified-recall.js +3 -3
  156. package/dist/who-knows-cli.js +4 -4
  157. package/dist/who-knows.js +3 -3
  158. package/package.json +2 -2
  159. package/src/access-service.ts +3 -0
  160. package/src/cli.ts +1 -2
  161. package/src/config.test.ts +17 -0
  162. package/src/config.ts +25 -7
  163. package/src/connectors/live/framework.ts +8 -0
  164. package/src/connectors/live/google-drive.test.ts +35 -0
  165. package/src/connectors/live/google-drive.ts +108 -10
  166. package/src/live-connectors-runner.ts +3 -0
  167. package/src/live-connectors-secretref.test.ts +126 -0
  168. package/src/orchestrator.ts +5 -5
  169. package/src/types.ts +10 -10
  170. package/dist/chunk-APYY5CX3.js.map +0 -1
  171. package/dist/chunk-BCCG7VWM.js.map +0 -1
  172. package/dist/chunk-STSLB4HT.js.map +0 -1
  173. package/dist/chunk-TRBGGJKZ.js.map +0 -1
  174. package/dist/chunk-V4XE263I.js.map +0 -1
  175. package/dist/chunk-YS2GHSWN.js.map +0 -1
  176. package/dist/chunk-ZCLEYJPB.js.map +0 -1
  177. /package/dist/{chunk-VMVVSZTD.js.map → chunk-2FGLEF7C.js.map} +0 -0
  178. /package/dist/{chunk-VNUOAXWP.js.map → chunk-3RLK65ZK.js.map} +0 -0
  179. /package/dist/{chunk-EV76IZ37.js.map → chunk-4J363OAA.js.map} +0 -0
  180. /package/dist/{chunk-27XYV2XL.js.map → chunk-4WR2OD7K.js.map} +0 -0
  181. /package/dist/{chunk-J4MMPQ7Q.js.map → chunk-5HFXGXE5.js.map} +0 -0
  182. /package/dist/{chunk-XICOH5HT.js.map → chunk-5M5M22GW.js.map} +0 -0
  183. /package/dist/{chunk-Z4Q6USKJ.js.map → chunk-6F42QONS.js.map} +0 -0
  184. /package/dist/{chunk-ADYP7HXE.js.map → chunk-6F5MJFXY.js.map} +0 -0
  185. /package/dist/{chunk-LJQFJF4J.js.map → chunk-7GLJMDEQ.js.map} +0 -0
  186. /package/dist/{chunk-SHUBTAY2.js.map → chunk-7W3RXOIG.js.map} +0 -0
  187. /package/dist/{chunk-QL7RHYK6.js.map → chunk-ATPWZ4F7.js.map} +0 -0
  188. /package/dist/{chunk-MVMRUGBH.js.map → chunk-BJRTMNCB.js.map} +0 -0
  189. /package/dist/{chunk-5UCMYPVF.js.map → chunk-BLJT6JP2.js.map} +0 -0
  190. /package/dist/{chunk-RSK2WIEM.js.map → chunk-BQZEGOZ4.js.map} +0 -0
  191. /package/dist/{chunk-PUEO37QG.js.map → chunk-BRLXOZLM.js.map} +0 -0
  192. /package/dist/{chunk-GRTKLWYX.js.map → chunk-BSACVS6R.js.map} +0 -0
  193. /package/dist/{chunk-ODL4ZTNI.js.map → chunk-DKAA2IHQ.js.map} +0 -0
  194. /package/dist/{chunk-3XIWW4TB.js.map → chunk-E3A7ELSG.js.map} +0 -0
  195. /package/dist/{chunk-P5VZSSYL.js.map → chunk-E4IRW2FG.js.map} +0 -0
  196. /package/dist/{chunk-N74SGESS.js.map → chunk-E7YZXWIS.js.map} +0 -0
  197. /package/dist/{chunk-ZT6WPSII.js.map → chunk-ETZLQOUR.js.map} +0 -0
  198. /package/dist/{chunk-JBCCWVU2.js.map → chunk-EXHXJETE.js.map} +0 -0
  199. /package/dist/{chunk-KEPXC4KN.js.map → chunk-FNXQZGUS.js.map} +0 -0
  200. /package/dist/{chunk-JC36FPQ5.js.map → chunk-FQKBJJYB.js.map} +0 -0
  201. /package/dist/{chunk-WWK6J6SE.js.map → chunk-FSO3G4JJ.js.map} +0 -0
  202. /package/dist/{chunk-FRSHF6FU.js.map → chunk-GVGAO3WV.js.map} +0 -0
  203. /package/dist/{chunk-RYWROSL5.js.map → chunk-HF3BKUVV.js.map} +0 -0
  204. /package/dist/{chunk-NJJMVS5Y.js.map → chunk-HH5LY6RR.js.map} +0 -0
  205. /package/dist/{chunk-HVKUCT3W.js.map → chunk-HVX4LPNY.js.map} +0 -0
  206. /package/dist/{chunk-WUUES6CU.js.map → chunk-ID6JGIMD.js.map} +0 -0
  207. /package/dist/{chunk-7L3TODI7.js.map → chunk-JV4S6VDH.js.map} +0 -0
  208. /package/dist/{chunk-3UMDRGFS.js.map → chunk-LUJCQQ3L.js.map} +0 -0
  209. /package/dist/{chunk-6HM6HARE.js.map → chunk-MB6ZJDN6.js.map} +0 -0
  210. /package/dist/{chunk-AH637HZ5.js.map → chunk-MXHMNKWG.js.map} +0 -0
  211. /package/dist/{chunk-OFVCFKDH.js.map → chunk-N4KAE2NB.js.map} +0 -0
  212. /package/dist/{chunk-ATPWMT2E.js.map → chunk-NTRUKAAE.js.map} +0 -0
  213. /package/dist/{chunk-VPQFK63H.js.map → chunk-P4WNBSTW.js.map} +0 -0
  214. /package/dist/{chunk-EURPSF4Y.js.map → chunk-PH5ZQM35.js.map} +0 -0
  215. /package/dist/{chunk-ZZ67UTQX.js.map → chunk-PMJFRDJI.js.map} +0 -0
  216. /package/dist/{chunk-RO7RUBLD.js.map → chunk-PWXPRVLK.js.map} +0 -0
  217. /package/dist/{chunk-66L5ZRJC.js.map → chunk-QJPJXCS4.js.map} +0 -0
  218. /package/dist/{chunk-WLBEZZK5.js.map → chunk-R2LBF4HH.js.map} +0 -0
  219. /package/dist/{chunk-EWJZZDRG.js.map → chunk-RHQLIHMB.js.map} +0 -0
  220. /package/dist/{chunk-6QMWECO5.js.map → chunk-RIMK327Y.js.map} +0 -0
  221. /package/dist/{chunk-QVMOCJRV.js.map → chunk-RRJBDXAQ.js.map} +0 -0
  222. /package/dist/{chunk-AOFEMUHG.js.map → chunk-SUSW74WU.js.map} +0 -0
  223. /package/dist/{chunk-63O7LVMN.js.map → chunk-U6UNF5ZS.js.map} +0 -0
  224. /package/dist/{chunk-KZSGBWOJ.js.map → chunk-V2KGDESV.js.map} +0 -0
  225. /package/dist/{chunk-KUIRDD74.js.map → chunk-XDSCJOH7.js.map} +0 -0
  226. /package/dist/{chunk-7O2MC42R.js.map → chunk-XNRLRNQF.js.map} +0 -0
  227. /package/dist/{chunk-GNXGJBCA.js.map → chunk-XYKBWTWI.js.map} +0 -0
  228. /package/dist/{chunk-BMWMTAQF.js.map → chunk-Z7JIZ42P.js.map} +0 -0
  229. /package/dist/{state-store-I5HLZTZT.js.map → state-store-EEAX2MBS.js.map} +0 -0
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-7L3TODI7.js";
4
+ } from "./chunk-JV4S6VDH.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-WWK6J6SE.js";
6
+ import "./chunk-FSO3G4JJ.js";
7
7
  import "./chunk-QGVCFVX6.js";
8
8
  import "./chunk-UHVXE24Y.js";
9
9
  import "./chunk-IGOW4TJE.js";
@@ -82,7 +82,7 @@ import "./chunk-7RJUVTVF.js";
82
82
  import "./chunk-AL3UYZ5N.js";
83
83
  import "./chunk-RL6NEVXT.js";
84
84
  import "./chunk-YET735EZ.js";
85
- import "./chunk-V4XE263I.js";
85
+ import "./chunk-43AA5FVD.js";
86
86
  import "./chunk-YBA52OKG.js";
87
87
  import "./chunk-YCNIGRRF.js";
88
88
  import "./chunk-VUFL7X3H.js";
@@ -4,9 +4,9 @@ import {
4
4
  renderWhoKnows,
5
5
  renderWhoKnowsJson,
6
6
  renderWhoKnowsText
7
- } from "./chunk-EV76IZ37.js";
8
- import "./chunk-JBCCWVU2.js";
9
- import "./chunk-WWK6J6SE.js";
7
+ } from "./chunk-4J363OAA.js";
8
+ import "./chunk-EXHXJETE.js";
9
+ import "./chunk-FSO3G4JJ.js";
10
10
  import "./chunk-QGVCFVX6.js";
11
11
  import "./chunk-UHVXE24Y.js";
12
12
  import "./chunk-IGOW4TJE.js";
@@ -85,7 +85,7 @@ import "./chunk-7RJUVTVF.js";
85
85
  import "./chunk-AL3UYZ5N.js";
86
86
  import "./chunk-RL6NEVXT.js";
87
87
  import "./chunk-YET735EZ.js";
88
- import "./chunk-V4XE263I.js";
88
+ import "./chunk-43AA5FVD.js";
89
89
  import "./chunk-YBA52OKG.js";
90
90
  import "./chunk-YCNIGRRF.js";
91
91
  import "./chunk-VUFL7X3H.js";
package/dist/who-knows.js CHANGED
@@ -9,8 +9,8 @@ import {
9
9
  loadWhoKnowsEntities,
10
10
  tokenizeTopic,
11
11
  validateWhoKnowsInput
12
- } from "./chunk-JBCCWVU2.js";
13
- import "./chunk-WWK6J6SE.js";
12
+ } from "./chunk-EXHXJETE.js";
13
+ import "./chunk-FSO3G4JJ.js";
14
14
  import "./chunk-QGVCFVX6.js";
15
15
  import "./chunk-UHVXE24Y.js";
16
16
  import "./chunk-IGOW4TJE.js";
@@ -89,7 +89,7 @@ import "./chunk-7RJUVTVF.js";
89
89
  import "./chunk-AL3UYZ5N.js";
90
90
  import "./chunk-RL6NEVXT.js";
91
91
  import "./chunk-YET735EZ.js";
92
- import "./chunk-V4XE263I.js";
92
+ import "./chunk-43AA5FVD.js";
93
93
  import "./chunk-YBA52OKG.js";
94
94
  import "./chunk-YCNIGRRF.js";
95
95
  import "./chunk-VUFL7X3H.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.91",
3
+ "version": "10.0.92",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3386,7 +3386,7 @@
3386
3386
  "core"
3387
3387
  ],
3388
3388
  "peerDependencies": {
3389
- "@remnic/coding-graph": "^10.0.91"
3389
+ "@remnic/coding-graph": "^10.0.92"
3390
3390
  },
3391
3391
  "peerDependenciesMeta": {
3392
3392
  "@remnic/coding-graph": {
@@ -1365,6 +1365,7 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
1365
1365
  }
1366
1366
  private readonly extractionLivenessWarn = new ExtractionLivenessWarnThrottle();
1367
1367
 
1368
+ private readonly secretRefResolver: ResolveSecretRefFn | null;
1368
1369
  constructor(
1369
1370
  private readonly orchestrator: Orchestrator,
1370
1371
  options: {
@@ -1375,6 +1376,7 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
1375
1376
  ) {
1376
1377
  super();
1377
1378
  this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
1379
+ this.secretRefResolver = options.resolveSecretRef ?? null;
1378
1380
  // Peer SecretRef tokens resolve at poll time through the host resolver, the
1379
1381
  // same indirection as agentAccessHttp.authToken (review round 1). Absent a
1380
1382
  // resolver, string/${ENV} tokens still work and a SecretRef degrades to a
@@ -3721,6 +3723,7 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
3721
3723
  this.writableNamespaceFor(undefined, undefined, request.authenticatedPrincipal ?? principal);
3722
3724
  return this.orchestrator.runLiveConnectors({
3723
3725
  force: request.force === true,
3726
+ resolveSecretRef: this.secretRefResolver,
3724
3727
  });
3725
3728
  }
3726
3729
 
package/src/cli.ts CHANGED
@@ -6107,8 +6107,7 @@ export function registerCli(
6107
6107
  priorState: state,
6108
6108
  syncFn: (cursor) =>
6109
6109
  connector.syncIncremental({
6110
- cursor,
6111
- config: validatedCfg,
6110
+ cursor, config: validatedCfg, resolveSecretRef: hostSecretRefResolver(registerOptions),
6112
6111
  }),
6113
6112
  ingestFn: sharedIngestFn,
6114
6113
  writeCursorFn: makeWriteCursorFn(name),
@@ -1891,6 +1891,23 @@ test("parseConfig connectors.googleDrive accepts valid overrides", () => {
1891
1891
  ]);
1892
1892
  });
1893
1893
 
1894
+ test("parseConfig connectors.googleDrive keeps a SecretRef credential verbatim", () => {
1895
+ const secretRef = { source: "keychain", id: "projects/drive-secret" };
1896
+ const result = parseConfig({
1897
+ openaiApiKey: "sk-test",
1898
+ connectors: {
1899
+ googleDrive: {
1900
+ enabled: true,
1901
+ clientId: "synthetic-client",
1902
+ clientSecret: secretRef,
1903
+ refreshToken: "synthetic-token",
1904
+ },
1905
+ },
1906
+ });
1907
+ assert.deepEqual(result.connectors.googleDrive.clientSecret, secretRef);
1908
+ assert.equal(result.connectors.googleDrive.clientId, "synthetic-client");
1909
+ });
1910
+
1894
1911
  test("parseConfig rejects malformed connectors top-level", () => {
1895
1912
  assert.throws(
1896
1913
  () => parseConfig({ openaiApiKey: "sk-test", connectors: "nope" }),
package/src/config.ts CHANGED
@@ -19,6 +19,7 @@ import type {
19
19
  RecallSectionConfig,
20
20
  ReasoningEffort,
21
21
  SemanticChunkingConfigShape,
22
+ SecretRef,
22
23
  SessionObserverBandConfig,
23
24
  SlotBehaviorConfig,
24
25
  SlotMismatchMode,
@@ -3719,16 +3720,33 @@ export function parseConfig(
3719
3720
  ? (rawConnectors.googleDrive as Record<string, unknown>)
3720
3721
  : {};
3721
3722
  const driveEnabled = coerceBool(rawDrive.enabled) === true;
3723
+ const driveClientIdRaw = rawDrive.clientId;
3724
+ // SAFETY: a string value is a string; an object with a string source is a SecretRef, kept verbatim.
3722
3725
  const driveClientId =
3723
- typeof rawDrive.clientId === "string" ? rawDrive.clientId : "";
3726
+ Object.prototype.toString.call(driveClientIdRaw) === "[object String]"
3727
+ ? (driveClientIdRaw as string)
3728
+ : Object.prototype.toString.call(driveClientIdRaw) === "[object Object]" &&
3729
+ Object.prototype.toString.call((driveClientIdRaw as { source?: object }).source) === "[object String]"
3730
+ ? (driveClientIdRaw as SecretRef)
3731
+ : "";
3732
+ const driveClientSecretRaw = rawDrive[CLIENT_SECRET_FIELD];
3733
+ // SAFETY: a string value is a string; an object with a string source is a SecretRef, kept verbatim.
3724
3734
  const driveClientSecret =
3725
- typeof rawDrive[CLIENT_SECRET_FIELD] === "string"
3726
- ? rawDrive[CLIENT_SECRET_FIELD]
3727
- : "";
3735
+ Object.prototype.toString.call(driveClientSecretRaw) === "[object String]"
3736
+ ? (driveClientSecretRaw as string)
3737
+ : Object.prototype.toString.call(driveClientSecretRaw) === "[object Object]" &&
3738
+ Object.prototype.toString.call((driveClientSecretRaw as { source?: object }).source) === "[object String]"
3739
+ ? (driveClientSecretRaw as SecretRef)
3740
+ : "";
3741
+ const driveRefreshTokenRaw = rawDrive[REFRESH_TOKEN_FIELD];
3742
+ // SAFETY: a string value is a string; an object with a string source is a SecretRef, kept verbatim.
3728
3743
  const driveRefreshToken =
3729
- typeof rawDrive[REFRESH_TOKEN_FIELD] === "string"
3730
- ? rawDrive[REFRESH_TOKEN_FIELD]
3731
- : "";
3744
+ Object.prototype.toString.call(driveRefreshTokenRaw) === "[object String]"
3745
+ ? (driveRefreshTokenRaw as string)
3746
+ : Object.prototype.toString.call(driveRefreshTokenRaw) === "[object Object]" &&
3747
+ Object.prototype.toString.call((driveRefreshTokenRaw as { source?: object }).source) === "[object String]"
3748
+ ? (driveRefreshTokenRaw as SecretRef)
3749
+ : "";
3732
3750
  const drivePollCoerced = coerceNumber(rawDrive.pollIntervalMs);
3733
3751
  let drivePollIntervalMs = 300_000;
3734
3752
  if (drivePollCoerced !== undefined) {
@@ -1,3 +1,5 @@
1
+ import type { ResolveSecretRefFn } from "../../resolve-auth-token.js";
2
+
1
3
  /**
2
4
  * @remnic/core — Live Connectors Framework (issue #683 PR 1/N)
3
5
  *
@@ -139,6 +141,12 @@ export interface SyncIncrementalArgs {
139
141
  readonly config: ConnectorConfig;
140
142
  /** Optional abort signal. Connectors SHOULD honor it for cooperative cancellation. */
141
143
  readonly abortSignal?: AbortSignal;
144
+ /**
145
+ * Host resolver for credential fields that hold a SecretRef. A connector
146
+ * resolves those at poll time. Absent a resolver, a plain string still works
147
+ * and a SecretRef fails that connector only.
148
+ */
149
+ readonly resolveSecretRef?: ResolveSecretRefFn | null;
142
150
  }
143
151
 
144
152
  /**
@@ -88,6 +88,41 @@ test("validateGoogleDriveConfig accepts a minimal valid config", () => {
88
88
  assert.deepEqual([...cfg.folderIds], []);
89
89
  });
90
90
 
91
+ test("a SecretRef credential resolves at poll time and never reaches the persisted config", async () => {
92
+ const client = makeMockClient({});
93
+ let seenSecret = "";
94
+ const factory: GoogleDriveClientFactory = async (config) => {
95
+ seenSecret = config.clientSecret;
96
+ return client;
97
+ };
98
+ const connector = createGoogleDriveConnector({ clientFactory: factory });
99
+ const ref = { source: "keychain", id: "projects/drive-secret" };
100
+ const config: ConnectorConfig = { ...SYNTHETIC_CREDS, clientSecret: ref };
101
+ await connector.syncIncremental({
102
+ cursor: null,
103
+ config,
104
+ resolveSecretRef: async () => "resolved-drive-secret",
105
+ });
106
+ assert.equal(seenSecret, "resolved-drive-secret");
107
+ const persisted = JSON.stringify(connector.persistConfig?.(config) ?? {});
108
+ assert.equal(persisted.includes("resolved-drive-secret"), false);
109
+ assert.equal(persisted.includes("projects/drive-secret"), false);
110
+ });
111
+
112
+ test("a SecretRef with no resolver fails the connector and hides the reference", async () => {
113
+ const connector = createGoogleDriveConnector({ clientFactory: makeFactory(makeMockClient({})) });
114
+ const config: ConnectorConfig = { ...SYNTHETIC_CREDS, clientSecret: { source: "keychain", id: "projects/drive-secret" } };
115
+ let message = "";
116
+ try {
117
+ await connector.syncIncremental({ cursor: null, config });
118
+ } catch (err) {
119
+ message = err instanceof Error ? err.message : "";
120
+ }
121
+ assert.match(message, /clientSecret is a secret reference but no resolver is configured/);
122
+ assert.equal(message.includes("projects/drive-secret"), false);
123
+ assert.equal(message.includes("keychain"), false);
124
+ });
125
+
91
126
  test("validateGoogleDriveConfig rejects non-object input", () => {
92
127
  assert.throws(() => validateGoogleDriveConfig(null), /must be an object/);
93
128
  assert.throws(() => validateGoogleDriveConfig([]), /must be an object/);
@@ -65,6 +65,8 @@ import type {
65
65
  } from "./framework.js";
66
66
  import { isTransientHttpError } from "./transient-errors.js";
67
67
  import { throwIfAborted } from "../../abort-error.js";
68
+ import type { ResolveSecretRefFn } from "../../resolve-auth-token.js";
69
+ import type { SecretRef } from "../../types.js";
68
70
 
69
71
  /**
70
72
  * Stable connector id. Lives in the registry under this exact string.
@@ -122,15 +124,40 @@ const FOLDER_ID_PATTERN = /^[A-Za-z0-9_-]{8,256}$/;
122
124
  * Validated, frozen view of `connectors.googleDrive.*`.
123
125
  */
124
126
  export interface GoogleDriveConnectorConfig {
127
+ readonly clientId: DriveCredential;
128
+ readonly clientSecret: DriveCredential;
129
+ readonly refreshToken: DriveCredential;
130
+ /** Poll interval surfaced to the scheduler. */
131
+ readonly pollIntervalMs: number;
132
+ /** Folder ids to scope import to. Empty = "all accessible". */
133
+ readonly folderIds: readonly string[];
134
+ }
135
+
136
+ /** A credential field as configured: a plain string, or a SecretRef resolved at poll time. */
137
+ type DriveCredential = string | SecretRef;
138
+
139
+ interface DriveCredentialFields {
140
+ clientId: DriveCredential;
141
+ clientSecret: DriveCredential;
142
+ refreshToken: DriveCredential;
143
+ }
144
+
145
+ /** Resolved credentials passed to the Drive client. Always plain strings. */
146
+ interface GoogleDriveResolvedConfig {
125
147
  readonly clientId: string;
126
148
  readonly clientSecret: string;
127
149
  readonly refreshToken: string;
128
- /** Poll interval surfaced to the scheduler. */
129
150
  readonly pollIntervalMs: number;
130
- /** Folder ids to scope import to. Empty = "all accessible". */
131
151
  readonly folderIds: readonly string[];
132
152
  }
133
153
 
154
+ /** Disk form of a Drive config. A SecretRef clientId is omitted, never written. */
155
+ interface PersistedGoogleDriveConfig {
156
+ pollIntervalMs: number;
157
+ folderIds: readonly string[];
158
+ clientId?: string;
159
+ }
160
+
134
161
  /**
135
162
  * Optional injection point for tests. The real connector dynamically imports
136
163
  * `googleapis`; tests pass a stub here to avoid the optional-peer-dep
@@ -139,7 +166,7 @@ export interface GoogleDriveConnectorConfig {
139
166
  * The shape only covers the tiny slice of the SDK we actually use.
140
167
  */
141
168
  export interface GoogleDriveClientFactory {
142
- (config: GoogleDriveConnectorConfig): Promise<GoogleDriveClient>;
169
+ (config: GoogleDriveResolvedConfig): Promise<GoogleDriveClient>;
143
170
  }
144
171
 
145
172
  /**
@@ -243,9 +270,30 @@ export function validateGoogleDriveConfig(raw: unknown): GoogleDriveConnectorCon
243
270
  );
244
271
  }
245
272
  const r = raw as Record<string, unknown>;
246
- const clientId = requireNonEmptyString(r.clientId, "clientId");
247
- const clientSecret = requireNonEmptyString(r[CLIENT_SECRET_FIELD], CLIENT_SECRET_FIELD);
248
- const refreshToken = requireNonEmptyString(r[REFRESH_TOKEN_FIELD], REFRESH_TOKEN_FIELD);
273
+ const credentialKeys = ["clientId", CLIENT_SECRET_FIELD, REFRESH_TOKEN_FIELD] as const;
274
+ const credentials: DriveCredentialFields = {
275
+ clientId: "",
276
+ clientSecret: "",
277
+ refreshToken: "",
278
+ };
279
+ for (const key of credentialKeys) {
280
+ const value = r[key];
281
+ if (Object.prototype.toString.call(value) === "[object Object]") {
282
+ // SAFETY: the toString check proves value is a non-null object.
283
+ const source = (value as { source?: object }).source;
284
+ if (Object.prototype.toString.call(source) === "[object String]") {
285
+ // SAFETY: a string `source` on this object is the SecretRef discriminator.
286
+ credentials[key] = value as SecretRef;
287
+ } else {
288
+ credentials[key] = requireNonEmptyString(value, key);
289
+ }
290
+ } else {
291
+ credentials[key] = requireNonEmptyString(value, key);
292
+ }
293
+ }
294
+ const clientId = credentials.clientId;
295
+ const clientSecret = credentials.clientSecret;
296
+ const refreshToken = credentials.refreshToken;
249
297
 
250
298
  let pollIntervalMs: number;
251
299
  if (r.pollIntervalMs === undefined) {
@@ -321,6 +369,51 @@ function requireNonEmptyString(value: unknown, key: string): string {
321
369
  return trimmed;
322
370
  }
323
371
 
372
+
373
+ async function resolveCredential(
374
+ value: DriveCredential,
375
+ key: string,
376
+ resolver: ResolveSecretRefFn | null | undefined,
377
+ ): Promise<string> {
378
+ if (Object.prototype.toString.call(value) !== "[object Object]") {
379
+ // SAFETY: a DriveCredential that is not an object is the plain string form.
380
+ return value as string;
381
+ }
382
+ // SAFETY: the toString check proves value is a non-null object, so it is a SecretRef.
383
+ const ref = value as SecretRef;
384
+ if (resolver == null) {
385
+ throw new Error(`googleDrive: ${key} is a secret reference but no resolver is configured`);
386
+ }
387
+ let resolved: unknown;
388
+ try {
389
+ resolved = await resolver(ref);
390
+ } catch {
391
+ throw new Error(`googleDrive: ${key} secret reference could not be resolved`);
392
+ }
393
+ if (Object.prototype.toString.call(resolved) !== "[object String]") {
394
+ throw new Error(`googleDrive: ${key} secret reference resolved to a non-string value`);
395
+ }
396
+ // SAFETY: the toString check above proves `resolved` is a string.
397
+ const text = (resolved as string).trim();
398
+ if (text.length === 0) {
399
+ throw new Error(`googleDrive: ${key} secret reference resolved to an empty value`);
400
+ }
401
+ return text;
402
+ }
403
+
404
+ async function resolveGoogleDriveConfig(
405
+ stored: GoogleDriveConnectorConfig,
406
+ resolver: ResolveSecretRefFn | null | undefined,
407
+ ): Promise<GoogleDriveResolvedConfig> {
408
+ return {
409
+ clientId: await resolveCredential(stored.clientId, "clientId", resolver),
410
+ [CLIENT_SECRET_FIELD]: await resolveCredential(stored[CLIENT_SECRET_FIELD], CLIENT_SECRET_FIELD, resolver),
411
+ [REFRESH_TOKEN_FIELD]: await resolveCredential(stored[REFRESH_TOKEN_FIELD], REFRESH_TOKEN_FIELD, resolver),
412
+ pollIntervalMs: stored.pollIntervalMs,
413
+ folderIds: stored.folderIds,
414
+ };
415
+ }
416
+
324
417
  /**
325
418
  * Decide whether a Drive `change` corresponds to an importable text file
326
419
  * scoped to (optionally) the configured folder set.
@@ -405,16 +498,21 @@ export function createGoogleDriveConnector(
405
498
 
406
499
  persistConfig(validated: ConnectorConfig): ConnectorConfig {
407
500
  const config = validateGoogleDriveConfig(validated);
408
- return Object.freeze({
409
- clientId: config.clientId,
501
+ const persisted: PersistedGoogleDriveConfig = {
410
502
  pollIntervalMs: config.pollIntervalMs,
411
503
  folderIds: config.folderIds,
412
- });
504
+ };
505
+ if (Object.prototype.toString.call(config.clientId) === "[object String]") {
506
+ // SAFETY: the toString check proves clientId is a string, not a SecretRef.
507
+ persisted.clientId = config.clientId as string;
508
+ }
509
+ return Object.freeze(persisted);
510
+
413
511
  },
414
512
 
415
513
  async syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult> {
416
514
  // Re-validate on every pass: a JS caller could mutate it between passes.
417
- const config = validateGoogleDriveConfig(args.config);
515
+ const config = await resolveGoogleDriveConfig(validateGoogleDriveConfig(args.config), args.resolveSecretRef);
418
516
  throwIfAborted(args.abortSignal, "googleDrive: sync aborted");
419
517
 
420
518
  const client = await clientFactory(config);
@@ -31,6 +31,7 @@ import {
31
31
  } from "./connectors/live/index.js";
32
32
  import { abortError } from "./abort-error.js";
33
33
  import type { LiveConnectorsConfig } from "./types.js";
34
+ import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
34
35
 
35
36
  export type LiveConnectorSkipReason =
36
37
  | "disabled"
@@ -138,6 +139,7 @@ export async function runLiveConnectorsOnce(options: {
138
139
  now?: LiveConnectorsNow;
139
140
  abortSignal?: AbortSignal;
140
141
  definitions?: LiveConnectorDefinition[];
142
+ resolveSecretRef?: ResolveSecretRefFn | null;
141
143
  }): Promise<LiveConnectorsRunSummary> {
142
144
  const ranAt = resolveNow(options.now);
143
145
  const force = options.force === true;
@@ -228,6 +230,7 @@ export async function runLiveConnectorsOnce(options: {
228
230
  cursor,
229
231
  config: validatedConfig,
230
232
  abortSignal: pollAbortSignal,
233
+ resolveSecretRef: options.resolveSecretRef,
231
234
  }),
232
235
  ingestFn: async (docs) => {
233
236
  throwIfAborted(pollAbortSignal);
@@ -0,0 +1,126 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
6
+
7
+ import { parseConfig } from "./config.js";
8
+ import {
9
+ builtInLiveConnectorDefinitions,
10
+ runLiveConnectorsOnce,
11
+ } from "./live-connectors-runner.js";
12
+ import {
13
+ GOOGLE_DRIVE_CONNECTOR_ID,
14
+ NOTION_CONNECTOR_ID,
15
+ createGoogleDriveConnector,
16
+ type GoogleDriveClient,
17
+ } from "./connectors/live/index.js";
18
+ import type { LiveConnector } from "./connectors/live/framework.js";
19
+
20
+ const RESOLVED_SECRET = "resolved-drive-secret";
21
+ const SECRET_REF = { source: "keychain", id: "projects/drive-secret" };
22
+
23
+ function driveConfig() {
24
+ return {
25
+ openaiApiKey: "sk-test",
26
+ connectors: {
27
+ googleDrive: {
28
+ enabled: true,
29
+ clientId: "synthetic-client",
30
+ clientSecret: SECRET_REF,
31
+ refreshToken: "synthetic-token",
32
+ },
33
+ notion: { enabled: true, token: "secret_synthetic_notion_token" },
34
+ },
35
+ };
36
+ }
37
+
38
+ function notionStub(): LiveConnector {
39
+ return {
40
+ id: NOTION_CONNECTOR_ID,
41
+ displayName: "Notion",
42
+ validateConfig: () => ({}),
43
+ async syncIncremental() {
44
+ return { newDocs: [], nextCursor: { kind: "notion", value: "cursor-1", updatedAt: "2026-11-11T00:00:00.000Z" } };
45
+ },
46
+ };
47
+ }
48
+
49
+ test("a Drive SecretRef resolves through parseConfig and the runner, and stays out of the state file", async () => {
50
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-drive-secretref-"));
51
+ try {
52
+ const parsed = parseConfig(driveConfig());
53
+ const definitions = builtInLiveConnectorDefinitions(parsed.connectors);
54
+ let seenSecret = "";
55
+ const client: GoogleDriveClient = {
56
+ async getStartPageToken() {
57
+ return { startPageToken: "seed-token" };
58
+ },
59
+ async listChanges() {
60
+ return { changes: [], newStartPageToken: "next-token" };
61
+ },
62
+ async exportFile() {
63
+ return "";
64
+ },
65
+ async getFileMedia() {
66
+ return "";
67
+ },
68
+ };
69
+ for (const definition of definitions) {
70
+ if (definition.id === GOOGLE_DRIVE_CONNECTOR_ID) {
71
+ definition.createConnector = () =>
72
+ createGoogleDriveConnector({
73
+ clientFactory: async (config) => {
74
+ seenSecret = config.clientSecret;
75
+ return client;
76
+ },
77
+ });
78
+ }
79
+ if (definition.id === NOTION_CONNECTOR_ID) {
80
+ definition.createConnector = notionStub;
81
+ }
82
+ }
83
+ const summary = await runLiveConnectorsOnce({
84
+ memoryDir,
85
+ connectors: parsed.connectors,
86
+ definitions,
87
+ force: true,
88
+ resolveSecretRef: async () => RESOLVED_SECRET,
89
+ ingestDocuments: async () => {},
90
+ });
91
+ assert.equal(seenSecret, RESOLVED_SECRET);
92
+ const drive = summary.results.find((item) => item.id === GOOGLE_DRIVE_CONNECTOR_ID);
93
+ assert.equal(drive?.ran, true);
94
+ const statePath = path.join(memoryDir, "state", "connectors", `${GOOGLE_DRIVE_CONNECTOR_ID}.json`);
95
+ const stateText = await readFile(statePath, "utf-8");
96
+ assert.equal(stateText.includes(RESOLVED_SECRET), false);
97
+ assert.equal(stateText.includes(SECRET_REF.id), false);
98
+ } finally {
99
+ await rm(memoryDir, { recursive: true, force: true });
100
+ }
101
+ });
102
+
103
+ test("a Drive SecretRef with no resolver fails that connector and the others still run", async () => {
104
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-drive-secretref-"));
105
+ try {
106
+ const parsed = parseConfig(driveConfig());
107
+ const definitions = builtInLiveConnectorDefinitions(parsed.connectors);
108
+ for (const definition of definitions) {
109
+ if (definition.id === NOTION_CONNECTOR_ID) definition.createConnector = notionStub;
110
+ }
111
+ const summary = await runLiveConnectorsOnce({
112
+ memoryDir,
113
+ connectors: parsed.connectors,
114
+ definitions,
115
+ force: true,
116
+ ingestDocuments: async () => {},
117
+ });
118
+ const drive = summary.results.find((item) => item.id === GOOGLE_DRIVE_CONNECTOR_ID);
119
+ const notion = summary.results.find((item) => item.id === NOTION_CONNECTOR_ID);
120
+ assert.match(drive?.error ?? "", /clientSecret is a secret reference but no resolver is configured/);
121
+ assert.equal((drive?.error ?? "").includes(SECRET_REF.id), false);
122
+ assert.equal(notion?.ran, true);
123
+ } finally {
124
+ await rm(memoryDir, { recursive: true, force: true });
125
+ }
126
+ });
@@ -236,6 +236,7 @@ import {
236
236
  runLiveConnectorsOnce,
237
237
  type LiveConnectorsRunSummary,
238
238
  } from "./live-connectors-runner.js";
239
+ import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
239
240
  import {
240
241
  runPatternReinforcement,
241
242
  type PatternReinforcementResult,
@@ -2116,20 +2117,19 @@ export class Orchestrator {
2116
2117
  async runLiveConnectors(options: {
2117
2118
  force?: boolean;
2118
2119
  abortSignal?: AbortSignal;
2120
+ resolveSecretRef?: ResolveSecretRefFn | null;
2119
2121
  } = {}): Promise<LiveConnectorsRunSummary> {
2120
2122
  return runLiveConnectorsOnce({
2121
2123
  memoryDir: this.config.memoryDir,
2122
2124
  connectors: this.config.connectors,
2123
2125
  force: options.force === true,
2124
2126
  abortSignal: options.abortSignal,
2127
+ resolveSecretRef: options.resolveSecretRef,
2125
2128
  ingestDocuments: async (docs) => {
2126
2129
  const fetchedAt = new Date().toISOString();
2127
2130
  const turns = docs.map((doc) => ({
2128
- role: "assistant" as const,
2129
- content: doc.title
2130
- ? `# ${doc.title}\n\n${doc.content}`
2131
- : doc.content,
2132
- timestamp: fetchedAt,
2131
+ role: "assistant" as const, timestamp: fetchedAt,
2132
+ content: doc.title ? `# ${doc.title}\n\n${doc.content}` : doc.content,
2133
2133
  }));
2134
2134
  await this.ingestBulkImportBatch(turns);
2135
2135
  },
package/src/types.ts CHANGED
@@ -273,8 +273,9 @@ export interface NativeKnowledgeOpenClawWorkspaceConfig {
273
273
  * OpenClaw resolves these at runtime via its built-in secret resolver
274
274
  * (e.g. exec providers like `kc_*` for macOS Keychain). Plugins receive
275
275
  * the raw object in `pluginConfig` and must call the gateway's resolver
276
- * before using the value. Standalone Remnic does NOT resolve SecretRefs;
277
- * operators must use plain strings or `${ENV_VAR}` expansion instead.
276
+ * before using the value. A live connector credential field resolves a
277
+ * SecretRef at poll time through the host resolver. Other surfaces still
278
+ * need a plain string or `${ENV_VAR}` expansion.
278
279
  */
279
280
  export interface SecretRef {
280
281
  source: string;
@@ -2539,21 +2540,20 @@ export interface LiveConnectorsConfig {
2539
2540
  * shape (frozen, post-validation). This interface is the pre-validation
2540
2541
  * shape that `parseConfig` round-trips through.
2541
2542
  *
2542
- * `clientId` / `clientSecret` / `refreshToken` are stored as strings here so
2543
- * the schema can ship in `openclaw.plugin.json` and operators can populate
2544
- * them from a secret store (e.g. an env-substituted plist or systemd
2545
- * EnvironmentFile). They MUST NEVER be committed to source. The repo-wide
2546
- * privacy policy in CLAUDE.md applies.
2543
+ * `clientId` / `clientSecret` / `refreshToken` are a plain string or a
2544
+ * SecretRef. A SecretRef is kept verbatim here and resolved at poll time
2545
+ * through the host resolver. They MUST NEVER be committed to source. The
2546
+ * repo-wide privacy policy in CLAUDE.md applies.
2547
2547
  */
2548
2548
  export interface GoogleDriveLiveConnectorConfig {
2549
2549
  /** Master gate. Default false — operators must opt in explicitly. */
2550
2550
  enabled: boolean;
2551
2551
  /** OAuth2 client id. Populate from a secret store; never commit. */
2552
- clientId: string;
2552
+ clientId: string | SecretRef;
2553
2553
  /** OAuth2 client secret. Populate from a secret store; never commit. */
2554
- clientSecret: string;
2554
+ clientSecret: string | SecretRef;
2555
2555
  /** OAuth2 refresh token. Populate from a secret store; never commit. */
2556
- refreshToken: string;
2556
+ refreshToken: string | SecretRef;
2557
2557
  /** Poll interval in ms. Default 300000 (5 min); min 1000; max 86400000 (24h). */
2558
2558
  pollIntervalMs: number;
2559
2559
  /** Optional folder-id scope. Empty array = all accessible files. */