@remnic/core 9.3.638 → 9.3.640

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 (293) hide show
  1. package/dist/access-cli.js +31 -31
  2. package/dist/access-http.d.ts +56 -5
  3. package/dist/access-http.js +17 -17
  4. package/dist/access-mcp.d.ts +4 -4
  5. package/dist/access-mcp.js +16 -16
  6. package/dist/access-schema.d.ts +3 -0
  7. package/dist/access-schema.js +1 -1
  8. package/dist/{access-service-DvEvBv9_.d.ts → access-service-jyYute38.d.ts} +3 -2
  9. package/dist/access-service.d.ts +4 -4
  10. package/dist/access-service.js +14 -14
  11. package/dist/action-confidence.d.ts +1 -1
  12. package/dist/active-memory-bridge.d.ts +1 -1
  13. package/dist/active-recall.d.ts +1 -1
  14. package/dist/active-recall.js +1 -1
  15. package/dist/{auto-sync-RFADEHIQ.js → auto-sync-54QQHOG5.js} +4 -4
  16. package/dist/behavior-learner.d.ts +1 -1
  17. package/dist/behavior-signals.d.ts +1 -1
  18. package/dist/bootstrap.d.ts +3 -3
  19. package/dist/briefing.d.ts +1 -1
  20. package/dist/briefing.js +3 -3
  21. package/dist/buffer-surprise-report.d.ts +1 -1
  22. package/dist/buffer.d.ts +1 -1
  23. package/dist/calibration.d.ts +1 -1
  24. package/dist/calibration.js +1 -1
  25. package/dist/causal-behavior.d.ts +1 -1
  26. package/dist/causal-consolidation.d.ts +1 -1
  27. package/dist/causal-consolidation.js +5 -5
  28. package/dist/{chunk-3RDYU3JS.js → chunk-3AZDLWDW.js} +3 -3
  29. package/dist/{chunk-FPNQF475.js → chunk-3F7RMHC4.js} +1 -1
  30. package/dist/chunk-3F7RMHC4.js.map +1 -0
  31. package/dist/{chunk-KXTLEB4L.js → chunk-3SF7QNKF.js} +2 -2
  32. package/dist/{chunk-U2YPUWRB.js → chunk-4GYGEKUB.js} +53 -7
  33. package/dist/chunk-4GYGEKUB.js.map +1 -0
  34. package/dist/{chunk-6BDVBBBY.js → chunk-666A3MOW.js} +88 -30
  35. package/dist/chunk-666A3MOW.js.map +1 -0
  36. package/dist/{chunk-EDQVAMQI.js → chunk-6GIKAUTN.js} +2 -2
  37. package/dist/{chunk-4HFJQCJZ.js → chunk-7HYPN2GC.js} +2 -2
  38. package/dist/{chunk-Q6YIJGXJ.js → chunk-7OGJQP7T.js} +2 -2
  39. package/dist/{chunk-242XFZ36.js → chunk-7OH7KPF5.js} +2 -2
  40. package/dist/{chunk-RW5DGAGO.js → chunk-7V36WCUW.js} +2 -2
  41. package/dist/{chunk-7A2QKUUA.js → chunk-7XRSLMUD.js} +2 -2
  42. package/dist/{chunk-723OMPUI.js → chunk-A3BS64GV.js} +7 -1
  43. package/dist/chunk-A3BS64GV.js.map +1 -0
  44. package/dist/{chunk-JCLECECB.js → chunk-A3UPMOJZ.js} +2 -2
  45. package/dist/{chunk-QHXW3LZV.js → chunk-C3EJ3UIS.js} +3 -3
  46. package/dist/{chunk-YCX45GOQ.js → chunk-C4YAIWDG.js} +3 -3
  47. package/dist/{chunk-A3HKTPPV.js → chunk-C63WC454.js} +12 -1
  48. package/dist/chunk-C63WC454.js.map +1 -0
  49. package/dist/{chunk-4S3N6HFG.js → chunk-C6XO6ONP.js} +2 -2
  50. package/dist/{chunk-WD2W4234.js → chunk-CDHRUNBX.js} +11 -2
  51. package/dist/chunk-CDHRUNBX.js.map +1 -0
  52. package/dist/{chunk-YQNADJCT.js → chunk-CMZLMIZI.js} +2 -2
  53. package/dist/{chunk-KVDUDYEN.js → chunk-DDRNDPX4.js} +2 -2
  54. package/dist/{chunk-ORFGK3XI.js → chunk-E6ZDCOHM.js} +2 -2
  55. package/dist/{chunk-TKWGAOLV.js → chunk-EEC4PCG5.js} +2 -2
  56. package/dist/{chunk-PW6GURU3.js → chunk-EKIQBGAY.js} +2 -2
  57. package/dist/{chunk-YR6GIWWY.js → chunk-GQL52GQ5.js} +2 -2
  58. package/dist/{chunk-77NAFXUD.js → chunk-H3HDXD3U.js} +2 -2
  59. package/dist/{chunk-X7EJF46S.js → chunk-H4RWKZE2.js} +2 -2
  60. package/dist/{chunk-LASA46TQ.js → chunk-HRXCPKN4.js} +2 -2
  61. package/dist/{chunk-PUEAEQSN.js → chunk-ISMZIMD3.js} +2 -2
  62. package/dist/{chunk-LEG7XWS2.js → chunk-IXSTQGYV.js} +2 -2
  63. package/dist/{chunk-CMN5AWAZ.js → chunk-J2KFC47S.js} +2 -2
  64. package/dist/{chunk-OSPVAP56.js → chunk-JFHEEDRY.js} +20 -12
  65. package/dist/chunk-JFHEEDRY.js.map +1 -0
  66. package/dist/{chunk-RAGXUVQW.js → chunk-KVUG7FF7.js} +4 -4
  67. package/dist/{chunk-K47C6M2C.js → chunk-M75TBFKQ.js} +2 -2
  68. package/dist/{chunk-DEDTFRH2.js → chunk-MUKXANAM.js} +14 -3
  69. package/dist/chunk-MUKXANAM.js.map +1 -0
  70. package/dist/chunk-O75CRYGF.js +15 -0
  71. package/dist/chunk-O75CRYGF.js.map +1 -0
  72. package/dist/{chunk-YROCXMCK.js → chunk-RJGPH2Q3.js} +2 -2
  73. package/dist/{chunk-QDAWVW75.js → chunk-SBHQBC37.js} +2 -2
  74. package/dist/{chunk-NRST7W5Q.js → chunk-SEOTBRO4.js} +3 -3
  75. package/dist/{chunk-QYGIQ5NM.js → chunk-SHHT4JTC.js} +2 -2
  76. package/dist/{chunk-MNDFVT4F.js → chunk-UDZYZ5Q5.js} +12 -10
  77. package/dist/chunk-UDZYZ5Q5.js.map +1 -0
  78. package/dist/{chunk-C4KKM62E.js → chunk-UU5LHD6J.js} +2 -2
  79. package/dist/{chunk-I3YAA4BI.js → chunk-UZBK2JR6.js} +19 -19
  80. package/dist/{chunk-TJRV4MWX.js → chunk-WAKPKNEX.js} +172 -51
  81. package/dist/chunk-WAKPKNEX.js.map +1 -0
  82. package/dist/{chunk-7KRYJUTB.js → chunk-Y2XKJJEI.js} +3 -3
  83. package/dist/{chunk-2JIYTTQJ.js → chunk-YMI4NRV7.js} +5 -5
  84. package/dist/{cli-BJBKNWIS.d.ts → cli-A4AIhv9e.d.ts} +3 -3
  85. package/dist/cli.d.ts +5 -5
  86. package/dist/cli.js +31 -31
  87. package/dist/compat/checks.js +2 -2
  88. package/dist/compounding/engine.d.ts +1 -1
  89. package/dist/compounding/engine.js +3 -3
  90. package/dist/compounding/preference-consolidator.d.ts +1 -1
  91. package/dist/compression-optimizer.d.ts +1 -1
  92. package/dist/config.d.ts +1 -1
  93. package/dist/config.js +1 -1
  94. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  95. package/dist/connectors/codex-materialize-runner.js +3 -3
  96. package/dist/connectors/codex-materialize.d.ts +1 -1
  97. package/dist/connectors/index.d.ts +1 -1
  98. package/dist/connectors/index.js +5 -5
  99. package/dist/consolidation-provenance-check.d.ts +1 -1
  100. package/dist/consolidation-undo.d.ts +1 -1
  101. package/dist/contradiction/index.d.ts +1 -1
  102. package/dist/conversation-index/backend.d.ts +1 -1
  103. package/dist/conversation-index/backend.js +3 -3
  104. package/dist/conversation-index/chunker.d.ts +1 -1
  105. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  106. package/dist/conversation-index/faiss-adapter.js +2 -2
  107. package/dist/conversation-index/indexer.d.ts +1 -1
  108. package/dist/conversation-index/search.d.ts +1 -1
  109. package/dist/day-summary.d.ts +1 -1
  110. package/dist/delinearize.d.ts +1 -1
  111. package/dist/direct-answer-wiring.d.ts +1 -1
  112. package/dist/direct-answer.d.ts +1 -1
  113. package/dist/embedding-fallback.d.ts +1 -1
  114. package/dist/enrichment/index.d.ts +1 -1
  115. package/dist/entity-retrieval.d.ts +1 -1
  116. package/dist/entity-retrieval.js +3 -3
  117. package/dist/entity-schema.d.ts +1 -1
  118. package/dist/explicit-capture.d.ts +3 -3
  119. package/dist/extraction-judge-telemetry.d.ts +1 -1
  120. package/dist/extraction-judge-training.d.ts +1 -1
  121. package/dist/extraction-judge.d.ts +1 -1
  122. package/dist/extraction-judge.js +2 -2
  123. package/dist/extraction.d.ts +1 -1
  124. package/dist/extraction.js +4 -4
  125. package/dist/fallback-llm.d.ts +1 -1
  126. package/dist/fallback-llm.js +1 -1
  127. package/dist/identity-continuity.d.ts +1 -1
  128. package/dist/importance.d.ts +1 -1
  129. package/dist/index.d.ts +9 -9
  130. package/dist/index.js +45 -45
  131. package/dist/intent.d.ts +1 -1
  132. package/dist/lcm/engine.d.ts +1 -1
  133. package/dist/lcm/index.d.ts +1 -1
  134. package/dist/lcm/tools.d.ts +1 -1
  135. package/dist/lifecycle.d.ts +1 -1
  136. package/dist/live-connectors-runner.d.ts +1 -1
  137. package/dist/local-llm.d.ts +1 -1
  138. package/dist/local-llm.js +2 -2
  139. package/dist/maintenance/memory-governance-cron.d.ts +8 -0
  140. package/dist/maintenance/memory-governance-cron.js +1 -1
  141. package/dist/maintenance/memory-governance.d.ts +1 -1
  142. package/dist/maintenance/memory-governance.js +3 -3
  143. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  144. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  145. package/dist/mcp-memory-inspector-app.d.ts +4 -4
  146. package/dist/memory-action-policy.d.ts +1 -1
  147. package/dist/memory-cache.d.ts +1 -1
  148. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  149. package/dist/memory-projection-store.d.ts +1 -1
  150. package/dist/memory-provenance.d.ts +1 -1
  151. package/dist/memory-worth-outcomes.d.ts +1 -1
  152. package/dist/migrate/from-engram.js +2 -2
  153. package/dist/models-json.d.ts +1 -1
  154. package/dist/namespaces/migrate.d.ts +1 -1
  155. package/dist/namespaces/migrate.js +10 -10
  156. package/dist/namespaces/principal.d.ts +1 -1
  157. package/dist/namespaces/search.d.ts +1 -1
  158. package/dist/namespaces/search.js +6 -6
  159. package/dist/namespaces/storage.d.ts +1 -1
  160. package/dist/namespaces/storage.js +3 -3
  161. package/dist/native-knowledge.d.ts +1 -1
  162. package/dist/network/tailscale.js +2 -2
  163. package/dist/operator-toolkit.d.ts +1 -1
  164. package/dist/operator-toolkit.js +13 -13
  165. package/dist/{orchestrator-ibTTeoUa.d.ts → orchestrator-BEDTiuEO.d.ts} +11 -5
  166. package/dist/orchestrator.d.ts +3 -3
  167. package/dist/orchestrator.js +27 -27
  168. package/dist/patterns-cli.d.ts +1 -1
  169. package/dist/policy-runtime.d.ts +1 -1
  170. package/dist/qmd-recall-cache.d.ts +1 -1
  171. package/dist/qmd.d.ts +4 -1
  172. package/dist/qmd.js +2 -2
  173. package/dist/recall-disclosure-escalation.d.ts +1 -1
  174. package/dist/recall-explain-renderer.d.ts +1 -1
  175. package/dist/recall-explain-renderer.js +3 -3
  176. package/dist/recall-planner-llm.d.ts +1 -1
  177. package/dist/recall-planner-llm.js +1 -1
  178. package/dist/recall-state.d.ts +1 -1
  179. package/dist/recall-tag-filter.d.ts +1 -1
  180. package/dist/recall-xray-cli.d.ts +1 -1
  181. package/dist/recall-xray-cli.js +4 -4
  182. package/dist/recall-xray-renderer.d.ts +1 -1
  183. package/dist/recall-xray-renderer.js +3 -3
  184. package/dist/recall-xray.d.ts +1 -1
  185. package/dist/recall-xray.js +2 -2
  186. package/dist/resolve-auth-token.d.ts +1 -1
  187. package/dist/resume-bundles.js +2 -2
  188. package/dist/retrieval-agents.d.ts +1 -1
  189. package/dist/retrieval-tiers.d.ts +1 -1
  190. package/dist/routing/engine.d.ts +1 -1
  191. package/dist/routing/store.d.ts +1 -1
  192. package/dist/runtime/child-process.js +1 -1
  193. package/dist/search/embed-helper.d.ts +1 -1
  194. package/dist/search/factory.d.ts +1 -1
  195. package/dist/search/factory.js +5 -5
  196. package/dist/search/index.d.ts +1 -1
  197. package/dist/search/index.js +5 -5
  198. package/dist/search/lancedb-backend.d.ts +1 -1
  199. package/dist/search/meilisearch-backend.d.ts +1 -1
  200. package/dist/search/noop-backend.d.ts +1 -1
  201. package/dist/search/orama-backend.d.ts +1 -1
  202. package/dist/search/port.d.ts +1 -1
  203. package/dist/search/remote-backend.d.ts +1 -1
  204. package/dist/{semantic-consolidation-BPs6BURk.d.ts → semantic-consolidation-Byut1ufK.d.ts} +1 -1
  205. package/dist/semantic-consolidation.d.ts +2 -2
  206. package/dist/semantic-consolidation.js +4 -4
  207. package/dist/semantic-rule-promotion.js +3 -3
  208. package/dist/semantic-rule-verifier.d.ts +1 -1
  209. package/dist/semantic-rule-verifier.js +3 -3
  210. package/dist/session-observer-bands.d.ts +1 -1
  211. package/dist/session-observer-state.d.ts +1 -1
  212. package/dist/shared-context/manager.d.ts +1 -1
  213. package/dist/signal.d.ts +1 -1
  214. package/dist/storage.d.ts +1 -1
  215. package/dist/storage.js +2 -2
  216. package/dist/summarizer.d.ts +1 -1
  217. package/dist/summarizer.js +4 -4
  218. package/dist/summary-snapshot.d.ts +1 -1
  219. package/dist/temporal-supersession.d.ts +1 -1
  220. package/dist/temporal-validity.d.ts +1 -1
  221. package/dist/threading.d.ts +1 -1
  222. package/dist/tier-migration.d.ts +1 -1
  223. package/dist/tier-routing.d.ts +1 -1
  224. package/dist/topics.d.ts +1 -1
  225. package/dist/transcript.d.ts +1 -1
  226. package/dist/{types-CpMPD8xl.d.ts → types-BzA1FKbg.d.ts} +4 -0
  227. package/dist/types.d.ts +1 -1
  228. package/dist/types.js +1 -1
  229. package/dist/utility-runtime.d.ts +1 -1
  230. package/dist/verified-recall.js +3 -3
  231. package/package.json +3 -1
  232. package/src/access-http.test.ts +110 -2
  233. package/src/access-http.ts +117 -1
  234. package/src/access-mcp.ts +15 -6
  235. package/src/access-schema.ts +14 -0
  236. package/src/access-service.ts +4 -1
  237. package/src/config.ts +14 -0
  238. package/src/fallback-llm.ts +16 -0
  239. package/src/index.ts +9 -1
  240. package/src/maintenance/memory-governance-cron.ts +113 -30
  241. package/src/orchestrator.ts +197 -32
  242. package/src/qmd.test.ts +35 -0
  243. package/src/qmd.ts +16 -1
  244. package/src/runtime/child-process.test.ts +15 -0
  245. package/src/runtime/child-process.ts +9 -22
  246. package/src/types.ts +4 -0
  247. package/dist/chunk-6BDVBBBY.js.map +0 -1
  248. package/dist/chunk-723OMPUI.js.map +0 -1
  249. package/dist/chunk-A3HKTPPV.js.map +0 -1
  250. package/dist/chunk-DEDTFRH2.js.map +0 -1
  251. package/dist/chunk-FPNQF475.js.map +0 -1
  252. package/dist/chunk-MNDFVT4F.js.map +0 -1
  253. package/dist/chunk-NNVTUXEB.js +0 -23
  254. package/dist/chunk-NNVTUXEB.js.map +0 -1
  255. package/dist/chunk-OSPVAP56.js.map +0 -1
  256. package/dist/chunk-TJRV4MWX.js.map +0 -1
  257. package/dist/chunk-U2YPUWRB.js.map +0 -1
  258. package/dist/chunk-WD2W4234.js.map +0 -1
  259. /package/dist/{auto-sync-RFADEHIQ.js.map → auto-sync-54QQHOG5.js.map} +0 -0
  260. /package/dist/{chunk-3RDYU3JS.js.map → chunk-3AZDLWDW.js.map} +0 -0
  261. /package/dist/{chunk-KXTLEB4L.js.map → chunk-3SF7QNKF.js.map} +0 -0
  262. /package/dist/{chunk-EDQVAMQI.js.map → chunk-6GIKAUTN.js.map} +0 -0
  263. /package/dist/{chunk-4HFJQCJZ.js.map → chunk-7HYPN2GC.js.map} +0 -0
  264. /package/dist/{chunk-Q6YIJGXJ.js.map → chunk-7OGJQP7T.js.map} +0 -0
  265. /package/dist/{chunk-242XFZ36.js.map → chunk-7OH7KPF5.js.map} +0 -0
  266. /package/dist/{chunk-RW5DGAGO.js.map → chunk-7V36WCUW.js.map} +0 -0
  267. /package/dist/{chunk-7A2QKUUA.js.map → chunk-7XRSLMUD.js.map} +0 -0
  268. /package/dist/{chunk-JCLECECB.js.map → chunk-A3UPMOJZ.js.map} +0 -0
  269. /package/dist/{chunk-QHXW3LZV.js.map → chunk-C3EJ3UIS.js.map} +0 -0
  270. /package/dist/{chunk-YCX45GOQ.js.map → chunk-C4YAIWDG.js.map} +0 -0
  271. /package/dist/{chunk-4S3N6HFG.js.map → chunk-C6XO6ONP.js.map} +0 -0
  272. /package/dist/{chunk-YQNADJCT.js.map → chunk-CMZLMIZI.js.map} +0 -0
  273. /package/dist/{chunk-KVDUDYEN.js.map → chunk-DDRNDPX4.js.map} +0 -0
  274. /package/dist/{chunk-ORFGK3XI.js.map → chunk-E6ZDCOHM.js.map} +0 -0
  275. /package/dist/{chunk-TKWGAOLV.js.map → chunk-EEC4PCG5.js.map} +0 -0
  276. /package/dist/{chunk-PW6GURU3.js.map → chunk-EKIQBGAY.js.map} +0 -0
  277. /package/dist/{chunk-YR6GIWWY.js.map → chunk-GQL52GQ5.js.map} +0 -0
  278. /package/dist/{chunk-77NAFXUD.js.map → chunk-H3HDXD3U.js.map} +0 -0
  279. /package/dist/{chunk-X7EJF46S.js.map → chunk-H4RWKZE2.js.map} +0 -0
  280. /package/dist/{chunk-LASA46TQ.js.map → chunk-HRXCPKN4.js.map} +0 -0
  281. /package/dist/{chunk-PUEAEQSN.js.map → chunk-ISMZIMD3.js.map} +0 -0
  282. /package/dist/{chunk-LEG7XWS2.js.map → chunk-IXSTQGYV.js.map} +0 -0
  283. /package/dist/{chunk-CMN5AWAZ.js.map → chunk-J2KFC47S.js.map} +0 -0
  284. /package/dist/{chunk-RAGXUVQW.js.map → chunk-KVUG7FF7.js.map} +0 -0
  285. /package/dist/{chunk-K47C6M2C.js.map → chunk-M75TBFKQ.js.map} +0 -0
  286. /package/dist/{chunk-YROCXMCK.js.map → chunk-RJGPH2Q3.js.map} +0 -0
  287. /package/dist/{chunk-QDAWVW75.js.map → chunk-SBHQBC37.js.map} +0 -0
  288. /package/dist/{chunk-NRST7W5Q.js.map → chunk-SEOTBRO4.js.map} +0 -0
  289. /package/dist/{chunk-QYGIQ5NM.js.map → chunk-SHHT4JTC.js.map} +0 -0
  290. /package/dist/{chunk-C4KKM62E.js.map → chunk-UU5LHD6J.js.map} +0 -0
  291. /package/dist/{chunk-I3YAA4BI.js.map → chunk-UZBK2JR6.js.map} +0 -0
  292. /package/dist/{chunk-7KRYJUTB.js.map → chunk-Y2XKJJEI.js.map} +0 -0
  293. /package/dist/{chunk-2JIYTTQJ.js.map → chunk-YMI4NRV7.js.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.3.638",
3
+ "version": "9.3.640",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -2873,6 +2873,7 @@
2873
2873
  "@sinclair/typebox": "^0.34.0",
2874
2874
  "apache-arrow": "^18.1.0",
2875
2875
  "better-sqlite3": "^12.6.2",
2876
+ "cross-spawn": "^7.0.6",
2876
2877
  "meilisearch": "^0.46.0",
2877
2878
  "node-gyp": "^12.3.0",
2878
2879
  "openai": "^6.0.0",
@@ -2885,6 +2886,7 @@
2885
2886
  },
2886
2887
  "devDependencies": {
2887
2888
  "@types/better-sqlite3": "^7.6.13",
2889
+ "@types/cross-spawn": "^6.0.6",
2888
2890
  "tsup": "^8.5.1",
2889
2891
  "tsx": "^4.21.0",
2890
2892
  "typescript": "^5.9.3"
@@ -5,7 +5,7 @@ import path from "node:path";
5
5
  import test from "node:test";
6
6
  import { gzipSync } from "node:zlib";
7
7
 
8
- import { EngramAccessHttpServer } from "./access-http.js";
8
+ import { EngramAccessHttpServer, type RemnicAdminControls, type RemnicAdminDashboardStatus } from "./access-http.js";
9
9
  import { EngramAccessInputError, type EngramAccessService } from "./access-service.js";
10
10
  import { parseConfig } from "./config.js";
11
11
  import { readPair, writePair } from "./contradiction/contradiction-review.js";
@@ -117,7 +117,9 @@ test("HTTP admin console assets are public but API routes require bearer authent
117
117
  try {
118
118
  const shell = await fetch(`http://127.0.0.1:${status.port}/remnic/ui/`);
119
119
  assert.equal(shell.status, 200);
120
- assert.match(await shell.text(), /Remnic Admin Console/);
120
+ const shellText = await shell.text();
121
+ assert.match(shellText, /Remnic Admin Console/);
122
+ assert.doesNotMatch(shellText, /test-token/);
121
123
 
122
124
  const app = await fetch(`http://127.0.0.1:${status.port}/remnic/ui/app.js`);
123
125
  assert.equal(app.status, 200);
@@ -133,6 +135,112 @@ test("HTTP admin console assets are public but API routes require bearer authent
133
135
  }
134
136
  });
135
137
 
138
+ test("HTTP admin console can prefill the primary bearer token when explicitly enabled", async () => {
139
+ const service = {} as EngramAccessService;
140
+ const server = new EngramAccessHttpServer({
141
+ service,
142
+ port: 0,
143
+ authToken: "test-token",
144
+ adminConsolePrefillToken: true,
145
+ });
146
+
147
+ const status = await server.start();
148
+ try {
149
+ const unauthenticatedShell = await fetch(`http://127.0.0.1:${status.port}/engram/ui/`);
150
+ assert.equal(unauthenticatedShell.status, 200);
151
+ assert.doesNotMatch(await unauthenticatedShell.text(), /test-token/);
152
+
153
+ const shell = await fetch(`http://127.0.0.1:${status.port}/engram/ui/`, {
154
+ headers: { authorization: "Bearer test-token" },
155
+ });
156
+ assert.equal(shell.status, 200);
157
+ assert.equal(shell.headers.get("cache-control"), "private, no-store");
158
+ assert.equal(shell.headers.get("vary"), "authorization");
159
+ const shellText = await shell.text();
160
+ assert.match(
161
+ shellText,
162
+ /window\.__REMNIC_ADMIN_CONSOLE_PREFILL_TOKEN__="test-token"/,
163
+ );
164
+
165
+ const app = await fetch(`http://127.0.0.1:${status.port}/engram/ui/app.js`);
166
+ assert.equal(app.status, 200);
167
+ assert.doesNotMatch(await app.text(), /test-token/);
168
+ } finally {
169
+ await server.stop();
170
+ }
171
+ });
172
+
173
+ test("HTTP admin dashboard endpoints require bearer authentication and apply config patches", async () => {
174
+ const service = {} as EngramAccessService;
175
+ const patches: unknown[] = [];
176
+ const dashboard: RemnicAdminDashboardStatus = {
177
+ config: {
178
+ path: "/tmp/remnic/config.json",
179
+ exists: true,
180
+ writable: true,
181
+ restartRequired: false,
182
+ values: {
183
+ modelSource: "plugin",
184
+ model: "gpt-4.1-mini",
185
+ },
186
+ },
187
+ harnesses: [],
188
+ models: [],
189
+ features: [],
190
+ };
191
+ const adminControls: RemnicAdminControls = {
192
+ status: async () => dashboard,
193
+ update: async (patch) => {
194
+ patches.push(patch);
195
+ return {
196
+ ...dashboard,
197
+ config: {
198
+ ...dashboard.config,
199
+ restartRequired: true,
200
+ values: {
201
+ ...dashboard.config.values,
202
+ modelSource: "gateway",
203
+ gatewayAgentId: "sage-router",
204
+ },
205
+ },
206
+ };
207
+ },
208
+ };
209
+ const server = new EngramAccessHttpServer({
210
+ service,
211
+ port: 0,
212
+ authToken: "test-token",
213
+ adminControls,
214
+ });
215
+
216
+ const status = await server.start();
217
+ try {
218
+ const unauthorized = await fetch(`http://127.0.0.1:${status.port}/engram/v1/admin/dashboard`);
219
+ assert.equal(unauthorized.status, 401);
220
+
221
+ const dashboardResponse = await fetch(`http://127.0.0.1:${status.port}/engram/v1/admin/dashboard`, {
222
+ headers: { authorization: "Bearer test-token" },
223
+ });
224
+ assert.equal(dashboardResponse.status, 200);
225
+ assert.deepEqual(await dashboardResponse.json(), dashboard);
226
+
227
+ const patchResponse = await fetch(`http://127.0.0.1:${status.port}/remnic/v1/admin/config`, {
228
+ method: "PATCH",
229
+ headers: {
230
+ authorization: "Bearer test-token",
231
+ "content-type": "application/json",
232
+ },
233
+ body: JSON.stringify({ modelSource: "gateway", gatewayAgentId: "sage-router" }),
234
+ });
235
+ assert.equal(patchResponse.status, 200);
236
+ const body = await patchResponse.json() as RemnicAdminDashboardStatus;
237
+ assert.equal(body.config.restartRequired, true);
238
+ assert.deepEqual(patches, [{ modelSource: "gateway", gatewayAgentId: "sage-router" }]);
239
+ } finally {
240
+ await server.stop();
241
+ }
242
+ });
243
+
136
244
  test("HTTP coding-context endpoint accepts projectTag shorthand", async () => {
137
245
  const calls: unknown[] = [];
138
246
  const service = {
@@ -41,6 +41,8 @@ export interface EngramAccessHttpServerOptions {
41
41
  maxBodyBytes?: number;
42
42
  adminConsoleEnabled?: boolean;
43
43
  adminConsolePublicDir?: string;
44
+ /** Inject the primary auth token into the admin console shell for trusted launch surfaces. */
45
+ adminConsolePrefillToken?: boolean;
44
46
  trustPrincipalHeader?: boolean;
45
47
  /** Enable adapter-based identity resolution from request headers */
46
48
  enableAdapters?: boolean;
@@ -52,6 +54,8 @@ export interface EngramAccessHttpServerOptions {
52
54
  citationsAutoDetect?: boolean;
53
55
  /** Advertise legacy engram.* tool aliases on tools/list (issue #1427). Default true. */
54
56
  emitLegacyTools?: boolean;
57
+ /** Optional authenticated admin dashboard/config controls supplied by the host server. */
58
+ adminControls?: RemnicAdminControls;
55
59
  }
56
60
 
57
61
  export interface EngramAccessHttpServerStatus {
@@ -61,6 +65,57 @@ export interface EngramAccessHttpServerStatus {
61
65
  maxBodyBytes: number;
62
66
  }
63
67
 
68
+ export interface RemnicAdminHarnessStatus {
69
+ id: string;
70
+ label: string;
71
+ detected: boolean;
72
+ enabled: boolean;
73
+ source?: string;
74
+ detail?: string;
75
+ }
76
+
77
+ export interface RemnicAdminModelOption {
78
+ id: string;
79
+ label: string;
80
+ provider: string;
81
+ detected: boolean;
82
+ enabled: boolean;
83
+ default?: boolean;
84
+ source?: string;
85
+ endpoint?: string;
86
+ }
87
+
88
+ export interface RemnicAdminFeatureStatus {
89
+ key: string;
90
+ label: string;
91
+ enabled: boolean;
92
+ writable: boolean;
93
+ restartRequired?: boolean;
94
+ }
95
+
96
+ export interface RemnicAdminConfigStatus {
97
+ path: string;
98
+ exists: boolean;
99
+ writable: boolean;
100
+ restartRequired: boolean;
101
+ values: Record<string, string | number | boolean | null>;
102
+ }
103
+
104
+ export interface RemnicAdminDashboardStatus {
105
+ config: RemnicAdminConfigStatus;
106
+ harnesses: RemnicAdminHarnessStatus[];
107
+ providers?: RemnicAdminHarnessStatus[];
108
+ models: RemnicAdminModelOption[];
109
+ features: RemnicAdminFeatureStatus[];
110
+ }
111
+
112
+ export type RemnicAdminConfigPatch = Record<string, unknown>;
113
+
114
+ export interface RemnicAdminControls {
115
+ status: () => Promise<RemnicAdminDashboardStatus>;
116
+ update?: (patch: RemnicAdminConfigPatch) => Promise<RemnicAdminDashboardStatus>;
117
+ }
118
+
64
119
  function resolveDefaultAdminConsolePublicDir(): string {
65
120
  const thisDir = path.dirname(fileURLToPath(import.meta.url));
66
121
  const candidates = [
@@ -210,6 +265,8 @@ export class EngramAccessHttpServer {
210
265
  private readonly maxBodyBytes: number;
211
266
  private readonly adminConsoleEnabled: boolean;
212
267
  private readonly adminConsolePublicDir: string;
268
+ private readonly adminConsolePrefillToken?: string;
269
+ private readonly adminControls?: RemnicAdminControls;
213
270
  private readonly trustPrincipalHeader: boolean;
214
271
  private readonly adapterRegistry: AdapterRegistry | null;
215
272
  private readonly writeRequestTimestamps: number[] = [];
@@ -242,6 +299,8 @@ export class EngramAccessHttpServer {
242
299
  : 131072;
243
300
  this.adminConsoleEnabled = options.adminConsoleEnabled !== false;
244
301
  this.adminConsolePublicDir = options.adminConsolePublicDir ?? defaultAdminConsolePublicDir;
302
+ this.adminConsolePrefillToken = options.adminConsolePrefillToken === true ? this.authToken : undefined;
303
+ this.adminControls = options.adminControls;
245
304
  this.trustPrincipalHeader = options.trustPrincipalHeader === true;
246
305
  this.adapterRegistry = options.enableAdapters !== false
247
306
  ? (options.adapterRegistry ?? new AdapterRegistry())
@@ -492,6 +551,38 @@ export class EngramAccessHttpServer {
492
551
  return;
493
552
  }
494
553
 
554
+ if (
555
+ req.method === "GET" &&
556
+ (pathname === "/engram/v1/admin/dashboard" || pathname === "/remnic/v1/admin/dashboard")
557
+ ) {
558
+ if (!this.adminControls) {
559
+ this.respondJson(res, 404, { error: "admin_controls_unavailable", code: "admin_controls_unavailable" });
560
+ return;
561
+ }
562
+ this.respondJson(res, 200, await this.adminControls.status());
563
+ return;
564
+ }
565
+
566
+ if (
567
+ req.method === "PATCH" &&
568
+ (pathname === "/engram/v1/admin/config" || pathname === "/remnic/v1/admin/config")
569
+ ) {
570
+ if (!this.adminControls?.update) {
571
+ this.respondJson(res, 404, { error: "admin_controls_unavailable", code: "admin_controls_unavailable" });
572
+ return;
573
+ }
574
+ try {
575
+ this.respondJson(res, 200, await this.adminControls.update(await this.readJsonBody(req)));
576
+ } catch (error) {
577
+ throw new HttpError(
578
+ 400,
579
+ error instanceof Error ? error.message : "invalid_admin_config_patch",
580
+ "invalid_admin_config_patch",
581
+ );
582
+ }
583
+ return;
584
+ }
585
+
495
586
  if (req.method === "POST" && pathname === "/engram/v1/recall") {
496
587
  const body = await this.readValidatedBody(req, "recall");
497
588
  // Preserve the distinction between `codingContext: null` (explicit
@@ -2244,7 +2335,7 @@ export class EngramAccessHttpServer {
2244
2335
  return true;
2245
2336
  }
2246
2337
  if (pathname === "/remnic/ui/" || pathname === "/engram/ui/") {
2247
- await this.respondStatic(res, path.join(this.adminConsolePublicDir, "index.html"), "text/html; charset=utf-8");
2338
+ await this.respondAdminConsoleShell(req, res, pathname);
2248
2339
  return true;
2249
2340
  }
2250
2341
  if (pathname === "/remnic/ui/app.js" || pathname === "/engram/ui/app.js") {
@@ -2254,6 +2345,31 @@ export class EngramAccessHttpServer {
2254
2345
  return false;
2255
2346
  }
2256
2347
 
2348
+ private async respondAdminConsoleShell(
2349
+ req: IncomingMessage,
2350
+ res: ServerResponse,
2351
+ pathname: string,
2352
+ ): Promise<void> {
2353
+ try {
2354
+ let body = await readFile(path.join(this.adminConsolePublicDir, "index.html"), "utf-8");
2355
+ const canPrefillToken = this.adminConsolePrefillToken && this.isAuthorized(req, pathname);
2356
+ if (canPrefillToken) {
2357
+ const script = `<script>window.__REMNIC_ADMIN_CONSOLE_PREFILL_TOKEN__=${JSON.stringify(this.adminConsolePrefillToken)};</script>`;
2358
+ body = body.includes("</head>")
2359
+ ? body.replace("</head>", `${script}</head>`)
2360
+ : `${script}${body}`;
2361
+ res.setHeader("cache-control", "private, no-store");
2362
+ }
2363
+ res.setHeader("vary", "authorization");
2364
+ res.statusCode = 200;
2365
+ res.setHeader("content-type", "text/html; charset=utf-8");
2366
+ res.setHeader("content-length", String(Buffer.byteLength(body)));
2367
+ res.end(body);
2368
+ } catch {
2369
+ this.respondJson(res, 404, { error: "not_found" });
2370
+ }
2371
+ }
2372
+
2257
2373
  private async respondStatic(res: ServerResponse, filePath: string, contentType: string): Promise<void> {
2258
2374
  try {
2259
2375
  const body = await readFile(filePath, "utf-8");
package/src/access-mcp.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  type CapsuleExportRequest,
9
9
  type CapsuleImportRequest,
10
10
  type CapsuleListRequest,
11
+ type DaySummaryRequest,
11
12
  type MemoryStoreRequest,
12
13
  type SchemaName,
13
14
  type SchemaTypeFor,
@@ -102,6 +103,14 @@ function resolveChatGptInspectorRecallSessionKey(
102
103
  }
103
104
 
104
105
  const STRICT_MCP_SCHEMA_KEYS: Partial<Record<SchemaName, readonly string[]>> = {
106
+ daySummary: [
107
+ "memories",
108
+ "sessionKey",
109
+ "namespace",
110
+ "timeZone",
111
+ "cwd",
112
+ "projectTag",
113
+ ],
105
114
  memoryStore: [
106
115
  "schemaVersion",
107
116
  "idempotencyKey",
@@ -765,6 +774,8 @@ export class EngramMcpServer {
765
774
  memories: { type: "string" },
766
775
  sessionKey: { type: "string" },
767
776
  namespace: { type: "string" },
777
+ timeZone: { type: "string" },
778
+ ...MCP_GIT_CONTEXT_SCHEMA_PROPS_IGNORED,
768
779
  },
769
780
  required: [],
770
781
  additionalProperties: false,
@@ -2638,12 +2649,10 @@ export class EngramMcpServer {
2638
2649
  actionConfidence,
2639
2650
  );
2640
2651
  }
2641
- case "engram.day_summary":
2642
- return this.service.daySummary({
2643
- memories: typeof args.memories === "string" ? args.memories : "",
2644
- sessionKey: typeof args.sessionKey === "string" ? args.sessionKey : undefined,
2645
- namespace: typeof args.namespace === "string" ? args.namespace : undefined,
2646
- });
2652
+ case "engram.day_summary": {
2653
+ const body: DaySummaryRequest = parseMcpRequest("daySummary", args);
2654
+ return this.service.daySummary(body);
2655
+ }
2647
2656
  case "engram.capsule_export": {
2648
2657
  const body: CapsuleExportRequest = parseMcpRequest("capsuleExport", args);
2649
2658
  return this.service.capsuleExport({
@@ -46,6 +46,19 @@ const sessionKeySchema = z.string().trim().min(1).max(512).optional();
46
46
  const idempotencyKeySchema = z.string().trim().min(1).max(256).optional();
47
47
  const dryRunSchema = z.boolean().optional();
48
48
  const schemaVersionSchema = z.number().int().optional();
49
+ const timeZoneSchema = z
50
+ .string()
51
+ .trim()
52
+ .min(1)
53
+ .max(128)
54
+ .refine((value) => {
55
+ try {
56
+ Intl.DateTimeFormat(undefined, { timeZone: value });
57
+ return true;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }, "must be a valid IANA timezone");
49
62
 
50
63
  // ---------------------------------------------------------------------------
51
64
  // Recall
@@ -330,6 +343,7 @@ export const daySummaryRequestSchema = z.object({
330
343
  memories: z.string().max(100000).optional(),
331
344
  sessionKey: sessionKeySchema,
332
345
  namespace: namespaceSchema,
346
+ timeZone: timeZoneSchema.optional(),
333
347
  });
334
348
 
335
349
  // ---------------------------------------------------------------------------
@@ -425,6 +425,7 @@ export interface EngramAccessDaySummaryRequest {
425
425
  memories?: string;
426
426
  sessionKey?: string;
427
427
  namespace?: string;
428
+ timeZone?: string;
428
429
  }
429
430
 
430
431
  /** Inputs accepted by the `remnic_briefing` MCP tool. */
@@ -2021,7 +2022,9 @@ export class EngramAccessService {
2021
2022
 
2022
2023
  if (memories.length === 0) {
2023
2024
  // Auto-gather today's facts from the resolved namespace
2024
- return this.orchestrator.generateDaySummaryAuto(namespace);
2025
+ return this.orchestrator.generateDaySummaryAuto(namespace, {
2026
+ timeZone: request.timeZone,
2027
+ });
2025
2028
  }
2026
2029
  return this.orchestrator.generateDaySummary(memories);
2027
2030
  }
package/src/config.ts CHANGED
@@ -2059,6 +2059,20 @@ export function parseConfig(raw: unknown): PluginConfig {
2059
2059
  hourlySummariesEnabled: cfg.hourlySummariesEnabled !== false, // default: true
2060
2060
  daySummaryEnabled: cfg.daySummaryEnabled !== false, // default: true
2061
2061
  hourlySummaryCronAutoRegister: cfg.hourlySummaryCronAutoRegister === true,
2062
+ // Day summary timezone override (issue #1475). When unset, the plugin
2063
+ // falls back to the server's local timezone.
2064
+ daySummaryTimezone:
2065
+ typeof cfg.daySummaryTimezone === "string" && cfg.daySummaryTimezone.trim().length > 0
2066
+ ? (() => {
2067
+ const tz = (cfg.daySummaryTimezone as string).trim();
2068
+ try {
2069
+ Intl.DateTimeFormat(undefined, { timeZone: tz });
2070
+ return tz;
2071
+ } catch {
2072
+ throw new Error(`daySummaryTimezone must be a valid IANA timezone: ${tz}`);
2073
+ }
2074
+ })()
2075
+ : undefined,
2062
2076
  // Codex P1 on PR 763 round 2: gate the nightly-governance cron
2063
2077
  // (deep-sleep's primary scheduled execution path) on
2064
2078
  // dreams.phases.deepSleep.enabled. When the phase is disabled the
@@ -109,6 +109,16 @@ const LEGACY_PROVIDER_IDS = new Set(["openai-codex", "claude-cli"]);
109
109
  const MANAGED_SECRETREF_MARKER = ["secretref", "managed"].join("-");
110
110
  const PROVIDER_API_KEY_FIELD = ["api", "Key"].join("") as keyof ModelProviderConfig;
111
111
 
112
+ /**
113
+ * Built-in provider fallbacks for providers that are commonly configured via
114
+ * OAuth or gateway-managed auth rather than an explicit apiKey in
115
+ * openclaw.json. These entries let resolveProviderConfig() succeed so the
116
+ * chain proceeds to tryModel() → resolveRuntimeAuth(), which is where the
117
+ * gateway's native OAuth token exchange happens.
118
+ *
119
+ * Without these, OAuth-only providers like `openai` are rejected with
120
+ * "provider not found" before runtime auth is ever attempted.
121
+ */
112
122
  const BUILT_IN_PROVIDER_FALLBACKS: Record<string, ModelProviderConfig> = {
113
123
  anthropic: {
114
124
  baseUrl: "https://api.anthropic.com/v1",
@@ -116,6 +126,12 @@ const BUILT_IN_PROVIDER_FALLBACKS: Record<string, ModelProviderConfig> = {
116
126
  models: [],
117
127
  [PROVIDER_API_KEY_FIELD]: MANAGED_SECRETREF_MARKER,
118
128
  },
129
+ openai: {
130
+ baseUrl: "https://api.openai.com/v1",
131
+ api: "openai-responses",
132
+ models: [],
133
+ [PROVIDER_API_KEY_FIELD]: MANAGED_SECRETREF_MARKER,
134
+ },
119
135
  };
120
136
 
121
137
  /**
package/src/index.ts CHANGED
@@ -341,7 +341,15 @@ export {
341
341
  // ---------------------------------------------------------------------------
342
342
 
343
343
  export { EngramAccessService, EngramAccessInputError } from "./access-service.js";
344
- export { EngramAccessHttpServer } from "./access-http.js";
344
+ export {
345
+ EngramAccessHttpServer,
346
+ type RemnicAdminConfigPatch,
347
+ type RemnicAdminControls,
348
+ type RemnicAdminDashboardStatus,
349
+ type RemnicAdminFeatureStatus,
350
+ type RemnicAdminHarnessStatus,
351
+ type RemnicAdminModelOption,
352
+ } from "./access-http.js";
345
353
  export { EngramMcpServer } from "./access-mcp.js";
346
354
 
347
355
  // agentAccessHttp.authToken SecretRef resolution (issue #757). Exposed so
@@ -72,7 +72,11 @@ export async function ensureCronJob(
72
72
  jobsPath: string,
73
73
  jobId: string,
74
74
  buildJob: () => Record<string, unknown>,
75
- options: { updateExisting?: boolean; updateFields?: string[] } = {},
75
+ options: {
76
+ updateExisting?: boolean;
77
+ updateFields?: string[];
78
+ deepMerge?: Record<string, unknown>;
79
+ } = {},
76
80
  ): Promise<{ created: boolean; updated: boolean; jobId: string }> {
77
81
  const releaseLock = await acquireCronJobsLock(jobsPath);
78
82
  try {
@@ -87,7 +91,7 @@ export async function ensureCronJob(
87
91
 
88
92
  const desired = buildJob();
89
93
  const existing = jobs[existingIndex];
90
- const next = mergeCronJobUpdate(existing, desired, options.updateFields);
94
+ const next = mergeCronJobUpdate(existing, desired, options.updateFields, options.deepMerge);
91
95
  if (stableJson(existing) === stableJson(next)) {
92
96
  return { created: false, updated: false, jobId };
93
97
  }
@@ -107,23 +111,56 @@ export async function ensureCronJob(
107
111
  }
108
112
  }
109
113
 
114
+ function deepMergeObjects(
115
+ target: Record<string, unknown>,
116
+ source: Record<string, unknown>,
117
+ ): Record<string, unknown> {
118
+ const result = { ...target };
119
+ for (const [key, value] of Object.entries(source)) {
120
+ if (value === null) {
121
+ // null means "remove this key"
122
+ delete result[key];
123
+ } else if (
124
+ value && typeof value === "object" && !Array.isArray(value) &&
125
+ result[key] && typeof result[key] === "object" && !Array.isArray(result[key])
126
+ ) {
127
+ result[key] = deepMergeObjects(
128
+ result[key] as Record<string, unknown>,
129
+ value as Record<string, unknown>,
130
+ );
131
+ } else {
132
+ result[key] = value;
133
+ }
134
+ }
135
+ return result;
136
+ }
137
+
110
138
  function mergeCronJobUpdate(
111
139
  existing: Record<string, unknown>,
112
140
  desired: Record<string, unknown>,
113
141
  updateFields?: string[],
142
+ deepMerge?: Record<string, unknown>,
114
143
  ): Record<string, unknown> {
115
- if (!updateFields) {
144
+ let next = { ...existing };
145
+
146
+ if (!updateFields && !deepMerge) {
116
147
  return desired;
117
148
  }
118
149
 
119
- const next = { ...existing };
120
- for (const field of updateFields) {
121
- if (Object.prototype.hasOwnProperty.call(desired, field)) {
122
- next[field] = desired[field];
123
- } else {
124
- delete next[field];
150
+ if (updateFields) {
151
+ for (const field of updateFields) {
152
+ if (Object.prototype.hasOwnProperty.call(desired, field)) {
153
+ next[field] = desired[field];
154
+ } else {
155
+ delete next[field];
156
+ }
125
157
  }
126
158
  }
159
+
160
+ if (deepMerge) {
161
+ next = deepMergeObjects(next, deepMerge);
162
+ }
163
+
127
164
  return next;
128
165
  }
129
166
 
@@ -146,34 +183,80 @@ export async function ensureDaySummaryCron(
146
183
  options: {
147
184
  timezone: string;
148
185
  agentId?: string;
186
+ /** Whether agentId was explicitly provided (vs defaulted to "main"). */
187
+ hasExplicitAgentId?: boolean;
188
+ /** Optional model override (e.g. from summaryModel or taskModelChain.primary). */
189
+ model?: string;
190
+ /** Optional fallbacks to include alongside the model. */
191
+ fallbacks?: string[];
149
192
  },
150
- ): Promise<{ created: boolean; jobId: string }> {
193
+ ): Promise<{ created: boolean; updated: boolean; jobId: string }> {
151
194
  const agentId =
152
195
  typeof options.agentId === "string" && options.agentId.trim().length > 0
153
196
  ? options.agentId.trim()
154
197
  : "main";
198
+ const daySummaryParams = JSON.stringify({ timeZone: options.timezone });
155
199
 
156
- return ensureCronJob(jobsPath, DAY_SUMMARY_CRON_ID, () => ({
157
- id: DAY_SUMMARY_CRON_ID,
158
- agentId,
159
- name: "Remnic Day Summary (auto)",
160
- enabled: true,
161
- schedule: {
162
- kind: "cron",
163
- expr: "47 23 * * *",
164
- tz: options.timezone,
165
- },
166
- sessionTarget: "isolated",
167
- wakeMode: "now",
168
- payload: {
169
- kind: "agentTurn",
170
- timeoutSeconds: 900,
171
- thinking: "off",
172
- message:
173
- "You are OpenClaw automation. Call tool engram.day_summary with empty params (it will auto-gather today's facts). If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.",
200
+ const payload: Record<string, unknown> = {
201
+ kind: "agentTurn",
202
+ timeoutSeconds: 900,
203
+ thinking: "off",
204
+ message:
205
+ `You are OpenClaw automation. Call tool engram.day_summary with params ${daySummaryParams} (it will auto-gather today's facts for that timezone). If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.`,
206
+ };
207
+ if (options.model) {
208
+ payload.model = options.model;
209
+ }
210
+ if (options.fallbacks && options.fallbacks.length > 0) {
211
+ payload.fallbacks = options.fallbacks;
212
+ }
213
+
214
+ return ensureCronJob(
215
+ jobsPath,
216
+ DAY_SUMMARY_CRON_ID,
217
+ () => ({
218
+ id: DAY_SUMMARY_CRON_ID,
219
+ agentId,
220
+ name: "Remnic Day Summary (auto)",
221
+ enabled: true,
222
+ schedule: {
223
+ kind: "cron",
224
+ expr: "47 23 * * *",
225
+ tz: options.timezone,
226
+ },
227
+ sessionTarget: "isolated",
228
+ wakeMode: "now",
229
+ // Mirror model at job root for backward compat with older OpenClaw
230
+ // builds that read root model instead of payload.model.
231
+ ...(options.model ? { model: options.model } : {}),
232
+ payload,
233
+ delivery: { mode: "none" },
234
+ }),
235
+ // Reconcile on every startup so model/timezone changes propagate.
236
+ // Issue #1474 (model reconcile) + #1475 (timezone reconcile).
237
+ // Only update managed leaves to avoid clobbering user edits to
238
+ // schedule.expr, payload.message, payload.timeoutSeconds, etc.
239
+ // Only reconcile agentId when explicitly provided, so manually-set
240
+ // cron personas are preserved.
241
+ {
242
+ updateExisting: true,
243
+ updateFields: options.hasExplicitAgentId ? ["agentId"] : [],
244
+ deepMerge: {
245
+ schedule: { tz: options.timezone },
246
+ // Mirror model at job root for backward compat with older OpenClaw
247
+ // builds that read root model instead of payload.model.
248
+ model: options.model ?? null,
249
+ // Always write model/fallbacks so stale values are cleared when
250
+ // an operator removes summaryModel or taskModelChain from config.
251
+ payload: {
252
+ model: options.model ?? null,
253
+ fallbacks: (options.fallbacks && options.fallbacks.length > 0)
254
+ ? options.fallbacks
255
+ : null,
256
+ },
257
+ },
174
258
  },
175
- delivery: { mode: "none" },
176
- }));
259
+ );
177
260
  }
178
261
 
179
262
  export async function ensureNightlyGovernanceCron(