@remnic/core 9.69.11 → 9.69.13

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 (360) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +4 -4
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +5 -5
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +4 -4
  7. package/dist/access-cli.js +28 -28
  8. package/dist/access-coding-context-resolution.d.ts +1 -1
  9. package/dist/access-extraction-force-flush.d.ts +11 -11
  10. package/dist/access-extraction-force-flush.js +4 -4
  11. package/dist/access-health-types.d.ts +1 -1
  12. package/dist/access-http-lcm-compaction.d.ts +11 -11
  13. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  14. package/dist/access-http-offline-stream.d.ts +11 -11
  15. package/dist/access-http-query.d.ts +2 -2
  16. package/dist/access-http-query.js +4 -4
  17. package/dist/access-http.d.ts +12 -12
  18. package/dist/access-http.js +15 -15
  19. package/dist/access-identity-continuity-surface.d.ts +9 -9
  20. package/dist/access-identity-continuity-surface.js +4 -4
  21. package/dist/access-lcm-surface.d.ts +11 -11
  22. package/dist/access-lcm-surface.js +4 -4
  23. package/dist/access-mcp.d.ts +11 -11
  24. package/dist/access-mcp.js +11 -11
  25. package/dist/access-memory-search-fanout.d.ts +2 -2
  26. package/dist/{access-namespace-preflight-Cy0yPsaE.d.ts → access-namespace-preflight-Rzuo1nGR.d.ts} +1 -1
  27. package/dist/access-namespace-preflight.d.ts +3 -3
  28. package/dist/access-namespace-preflight.js +4 -4
  29. package/dist/access-observe-write-surface.d.ts +11 -11
  30. package/dist/access-observe-write-surface.js +4 -4
  31. package/dist/access-offline-manifest.d.ts +9 -9
  32. package/dist/access-operations-batch.js +5 -5
  33. package/dist/access-operations.d.ts +17 -17
  34. package/dist/access-operations.js +10 -10
  35. package/dist/access-recall-concurrency.d.ts +11 -11
  36. package/dist/access-recall-concurrency.js +4 -4
  37. package/dist/access-recall-response.d.ts +11 -11
  38. package/dist/access-recall-response.js +4 -4
  39. package/dist/access-recall-surface.d.ts +11 -11
  40. package/dist/access-recall-surface.js +4 -4
  41. package/dist/access-schema.d.ts +91 -91
  42. package/dist/{access-service-Cqfk3dD1.d.ts → access-service-Bb2Fykzc.d.ts} +71 -71
  43. package/dist/access-service-helpers.d.ts +11 -11
  44. package/dist/access-service.d.ts +11 -11
  45. package/dist/access-service.js +4 -4
  46. package/dist/access-surface-catalog.d.ts +11 -11
  47. package/dist/access-surface-catalog.js +6 -6
  48. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  49. package/dist/action-confidence.d.ts +1 -1
  50. package/dist/active-memory-bridge.d.ts +1 -1
  51. package/dist/active-recall.d.ts +1 -1
  52. package/dist/active-recall.js +4 -4
  53. package/dist/ambient-provenance.d.ts +1 -1
  54. package/dist/artifact-search.d.ts +1 -1
  55. package/dist/behavior-learner.d.ts +1 -1
  56. package/dist/behavior-signals.d.ts +1 -1
  57. package/dist/bootstrap.d.ts +9 -9
  58. package/dist/briefing-window.d.ts +2 -2
  59. package/dist/briefing.d.ts +2 -2
  60. package/dist/buffer-surprise-report.d.ts +1 -1
  61. package/dist/buffer-turn-helpers.d.ts +1 -1
  62. package/dist/buffer.d.ts +2 -2
  63. package/dist/buffer.js +4 -4
  64. package/dist/bulk-import/index.d.ts +3 -3
  65. package/dist/calibration.d.ts +1 -1
  66. package/dist/capabilities.d.ts +1 -1
  67. package/dist/{catalog-9X8WpZNO.d.ts → catalog-DjTLVOYp.d.ts} +1 -1
  68. package/dist/causal-behavior.d.ts +1 -1
  69. package/dist/causal-consolidation.d.ts +1 -1
  70. package/dist/causal-trajectory-graph.d.ts +1 -1
  71. package/dist/{chunk-TEZ2HTC7.js → chunk-33JKYLPX.js} +2 -2
  72. package/dist/{chunk-MNH2GM4O.js → chunk-3BS2OGDT.js} +6 -19
  73. package/dist/{chunk-MNH2GM4O.js.map → chunk-3BS2OGDT.js.map} +1 -1
  74. package/dist/{chunk-5PTS43CH.js → chunk-4LG4CPOC.js} +2 -2
  75. package/dist/{chunk-Z33VUMKY.js → chunk-5H2G5X4R.js} +2 -2
  76. package/dist/{chunk-XFPHV65N.js → chunk-5JQV4T5Q.js} +2 -2
  77. package/dist/{chunk-OASGWNYL.js → chunk-63I7LMLG.js} +2 -2
  78. package/dist/{chunk-J3NGQ5SC.js → chunk-7GSSHAXC.js} +2 -2
  79. package/dist/{chunk-X4FIZAVQ.js → chunk-7JV4JST3.js} +854 -42
  80. package/dist/chunk-7JV4JST3.js.map +1 -0
  81. package/dist/{chunk-VHAKBUBD.js → chunk-B64IVEOH.js} +2 -2
  82. package/dist/{chunk-R7FXPG4T.js → chunk-C25N5HWX.js} +2 -2
  83. package/dist/{chunk-DH3V7RCQ.js → chunk-F2ERDKY2.js} +7 -7
  84. package/dist/{chunk-LJNLLNEM.js → chunk-HODFGQGT.js} +2 -2
  85. package/dist/{chunk-B75VCEX5.js → chunk-K2IJH4D3.js} +2 -2
  86. package/dist/{chunk-227WJVPY.js → chunk-KLSPKMIO.js} +2 -2
  87. package/dist/{chunk-5P2KNFJZ.js → chunk-MSDIETFC.js} +3 -3
  88. package/dist/{chunk-HFRGCNFY.js → chunk-OAKATRAN.js} +2 -2
  89. package/dist/chunk-OGUKSLYZ.js +560 -0
  90. package/dist/chunk-OGUKSLYZ.js.map +1 -0
  91. package/dist/{chunk-M6L7HI7R.js → chunk-P6FHFTZ7.js} +16 -1
  92. package/dist/chunk-P6FHFTZ7.js.map +1 -0
  93. package/dist/{chunk-LWBSEYW3.js → chunk-PAWIY5OQ.js} +5 -5
  94. package/dist/{chunk-3ITTF7YH.js → chunk-QVI63XSO.js} +90 -383
  95. package/dist/chunk-QVI63XSO.js.map +1 -0
  96. package/dist/{chunk-6TOWUN2R.js → chunk-RE3H6Y2X.js} +2 -2
  97. package/dist/{chunk-V3HUBF7T.js → chunk-S35IIP5P.js} +2 -2
  98. package/dist/{chunk-3YKOFCKP.js → chunk-SXHBZXHK.js} +2 -2
  99. package/dist/{chunk-7NCUHD5U.js → chunk-VAMZYOOV.js} +2 -2
  100. package/dist/{chunk-PGCZLHRB.js → chunk-W272SWN7.js} +3 -3
  101. package/dist/{chunk-5HO3QBAD.js → chunk-W6GEMUZM.js} +2 -2
  102. package/dist/{chunk-UCNQV43K.js → chunk-XQYTSZW3.js} +2 -2
  103. package/dist/{chunk-GR4C3FHT.js → chunk-ZKZCJRRO.js} +2 -2
  104. package/dist/{cli-Dk-lM_tI.d.ts → cli-DXXy60A4.d.ts} +5 -5
  105. package/dist/cli.d.ts +13 -13
  106. package/dist/cli.js +21 -21
  107. package/dist/coding/export-okf-codegraph.d.ts +1 -1
  108. package/dist/coding/pre-action-gate.d.ts +1 -1
  109. package/dist/compounding/engine.d.ts +2 -2
  110. package/dist/compounding/preference-consolidator.d.ts +1 -1
  111. package/dist/compression-optimizer.d.ts +1 -1
  112. package/dist/config.d.ts +1 -1
  113. package/dist/config.js +4 -4
  114. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  115. package/dist/connectors/codex-materialize.d.ts +1 -1
  116. package/dist/connectors/index.d.ts +1 -1
  117. package/dist/consolidation-provenance-check.d.ts +2 -2
  118. package/dist/consolidation-undo.d.ts +2 -2
  119. package/dist/contradiction/index.d.ts +3 -3
  120. package/dist/converge-config.d.ts +1 -1
  121. package/dist/convergence-refresh.d.ts +2 -2
  122. package/dist/conversation-index/backend.d.ts +1 -1
  123. package/dist/conversation-index/chunker.d.ts +1 -1
  124. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  125. package/dist/conversation-index/indexer.d.ts +1 -1
  126. package/dist/conversation-index/search.d.ts +1 -1
  127. package/dist/corpus-watermark.d.ts +1 -1
  128. package/dist/cross-lingual-recall.d.ts +1 -1
  129. package/dist/day-summary.d.ts +1 -1
  130. package/dist/deep-recall-http-glue.d.ts +11 -11
  131. package/dist/deep-recall-mcp-tools.d.ts +11 -11
  132. package/dist/deep-recall-policy-llm.d.ts +1 -1
  133. package/dist/deep-recall-seeds.d.ts +1 -1
  134. package/dist/delinearize.d.ts +1 -1
  135. package/dist/dependency-propagation-config.d.ts +1 -1
  136. package/dist/{dependency-propagation-delivery-BZGUecZf.d.ts → dependency-propagation-delivery-37JdQv_3.d.ts} +1 -1
  137. package/dist/direct-answer-wiring.d.ts +1 -1
  138. package/dist/direct-answer.d.ts +1 -1
  139. package/dist/embedding-fallback.d.ts +1 -1
  140. package/dist/enrichment/index.d.ts +1 -1
  141. package/dist/entity-origin-fields.d.ts +1 -1
  142. package/dist/entity-retrieval.d.ts +2 -2
  143. package/dist/entity-schema.d.ts +1 -1
  144. package/dist/episodic-context.d.ts +1 -1
  145. package/dist/eval-trajectory-contracts.d.ts +1 -1
  146. package/dist/eval-trajectory-store.d.ts +1 -1
  147. package/dist/eval-trajectory.d.ts +1 -1
  148. package/dist/explicit-capture.d.ts +9 -9
  149. package/dist/external-wiki-access.d.ts +11 -11
  150. package/dist/external-wiki-access.js +5 -5
  151. package/dist/external-wiki-collection-registration.d.ts +1 -1
  152. package/dist/external-wiki-collection.d.ts +1 -1
  153. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  154. package/dist/extraction-error-classification.d.ts +1 -1
  155. package/dist/extraction-faithfulness.d.ts +1 -1
  156. package/dist/extraction-judge-telemetry.d.ts +1 -1
  157. package/dist/extraction-judge-training.d.ts +1 -1
  158. package/dist/extraction-judge.d.ts +1 -1
  159. package/dist/extraction-liveness.d.ts +1 -1
  160. package/dist/extraction-normalization.d.ts +1 -1
  161. package/dist/extraction-prompt.d.ts +1 -1
  162. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  163. package/dist/extraction-source-grounding.d.ts +1 -1
  164. package/dist/extraction.d.ts +1 -1
  165. package/dist/extraction.js +5 -5
  166. package/dist/fallback-llm.d.ts +1 -1
  167. package/dist/graph-dashboard-diff.d.ts +1 -1
  168. package/dist/graph-dashboard-key.d.ts +1 -1
  169. package/dist/graph-dashboard-parser.d.ts +1 -1
  170. package/dist/graph-edge-reinforcement.d.ts +1 -1
  171. package/dist/graph-path-reconstruction.d.ts +1 -1
  172. package/dist/graph-path-scoring.d.ts +1 -1
  173. package/dist/graph-snapshot.d.ts +1 -1
  174. package/dist/graph.d.ts +1 -1
  175. package/dist/importance.d.ts +1 -1
  176. package/dist/importers/index.d.ts +1 -1
  177. package/dist/in-flight-reads.d.ts +1 -1
  178. package/dist/{index-B4iTvT-w.d.ts → index-DquhYqsc.d.ts} +2 -2
  179. package/dist/index.d.ts +876 -738
  180. package/dist/index.js +59 -37
  181. package/dist/intent.d.ts +1 -1
  182. package/dist/lcm/engine.d.ts +1 -1
  183. package/dist/lcm/index.d.ts +1 -1
  184. package/dist/lcm/tools.d.ts +1 -1
  185. package/dist/lifecycle.d.ts +1 -1
  186. package/dist/live-connectors-runner.d.ts +1 -1
  187. package/dist/local-llm.d.ts +1 -1
  188. package/dist/local-model-endpoint.d.ts +1 -1
  189. package/dist/location/index.d.ts +3 -3
  190. package/dist/location/index.js +5 -5
  191. package/dist/maintenance/memory-governance.d.ts +1 -1
  192. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  193. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  194. package/dist/{maintenance-BBpNqEeJ.d.ts → maintenance-CizZOycr.d.ts} +3 -3
  195. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  196. package/dist/memory-action-policy.d.ts +1 -1
  197. package/dist/memory-cache.d.ts +1 -1
  198. package/dist/memory-controller.d.ts +1 -1
  199. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  200. package/dist/memory-projection-store.d.ts +1 -1
  201. package/dist/memory-provenance.d.ts +1 -1
  202. package/dist/memory-snapshot.d.ts +1 -1
  203. package/dist/memory-subject-cli.d.ts +11 -11
  204. package/dist/memory-subject.d.ts +11 -11
  205. package/dist/memory-worth-outcomes.d.ts +2 -2
  206. package/dist/models-json.d.ts +1 -1
  207. package/dist/namespaces/migrate.d.ts +3 -3
  208. package/dist/namespaces/principal.d.ts +1 -1
  209. package/dist/namespaces/search.d.ts +1 -1
  210. package/dist/namespaces/storage.d.ts +3 -3
  211. package/dist/native-knowledge.d.ts +1 -1
  212. package/dist/offline-sync-impression-drain.d.ts +1 -1
  213. package/dist/operator-doctor-corpus.d.ts +1 -1
  214. package/dist/operator-doctor-replica.d.ts +1 -1
  215. package/dist/operator-toolkit.d.ts +3 -3
  216. package/dist/operator-toolkit.js +5 -5
  217. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  218. package/dist/orchestration/maintenance.d.ts +4 -4
  219. package/dist/orchestration/maintenance.js +6 -6
  220. package/dist/{orchestrator-DglY1H0w.d.ts → orchestrator-DqLcuNMP.d.ts} +8 -8
  221. package/dist/orchestrator.d.ts +9 -9
  222. package/dist/orchestrator.js +28 -28
  223. package/dist/patterns-cli.d.ts +1 -1
  224. package/dist/{pipeline-C7qRsy6g.d.ts → pipeline-DbJpmcRu.d.ts} +1 -1
  225. package/dist/policy-runtime.d.ts +1 -1
  226. package/dist/proactive-contention.d.ts +1 -1
  227. package/dist/provenance.d.ts +1 -1
  228. package/dist/{public-http-CPpCsi35.d.ts → public-http-NQ3UUp6W.d.ts} +1 -1
  229. package/dist/{qmd-YRLTa3AE.d.ts → qmd-DA_7fbSz.d.ts} +1 -1
  230. package/dist/qmd-preflight.d.ts +2 -2
  231. package/dist/qmd-recall-cache.d.ts +1 -1
  232. package/dist/qmd.d.ts +2 -2
  233. package/dist/recall-concurrency-config.d.ts +1 -1
  234. package/dist/recall-disclosure-escalation.d.ts +1 -1
  235. package/dist/recall-explain-renderer.d.ts +1 -1
  236. package/dist/recall-memory-map.d.ts +1 -1
  237. package/dist/recall-navigate-access.d.ts +1 -1
  238. package/dist/recall-navigate-disclosure.d.ts +1 -1
  239. package/dist/recall-navigate.d.ts +1 -1
  240. package/dist/recall-planner-llm.d.ts +1 -1
  241. package/dist/recall-state.d.ts +1 -1
  242. package/dist/recall-tag-filter.d.ts +1 -1
  243. package/dist/recall-timings.d.ts +1 -1
  244. package/dist/recall-xray-cli.d.ts +1 -1
  245. package/dist/recall-xray-renderer.d.ts +1 -1
  246. package/dist/recall-xray.d.ts +1 -1
  247. package/dist/reconcile/cursor.d.ts +1 -1
  248. package/dist/reconcile/manifest.d.ts +1 -1
  249. package/dist/reconcile/plan.d.ts +1 -1
  250. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  251. package/dist/replay/normalizers/claude.d.ts +1 -1
  252. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  253. package/dist/replay/normalizers/shared.d.ts +1 -1
  254. package/dist/replay/runner.d.ts +1 -1
  255. package/dist/replay/types.d.ts +1 -1
  256. package/dist/replica-divergence.d.ts +1 -1
  257. package/dist/replica-peers-config.d.ts +1 -1
  258. package/dist/resolve-auth-token.d.ts +1 -1
  259. package/dist/resume-bundles.js +5 -5
  260. package/dist/retrieval-agents.d.ts +2 -2
  261. package/dist/retrieval-tiers.d.ts +1 -1
  262. package/dist/routing/engine.d.ts +1 -1
  263. package/dist/routing/store.d.ts +1 -1
  264. package/dist/salvage-envelope.d.ts +1 -1
  265. package/dist/schemas.d.ts +176 -176
  266. package/dist/{scope-profiles-BVvqVzJX.d.ts → scope-profiles-BpiWKZzx.d.ts} +1 -1
  267. package/dist/search/embed-helper.d.ts +1 -1
  268. package/dist/search/factory.d.ts +1 -1
  269. package/dist/search/index.d.ts +1 -1
  270. package/dist/search/lancedb-backend.d.ts +1 -1
  271. package/dist/search/meilisearch-backend.d.ts +1 -1
  272. package/dist/search/noop-backend.d.ts +1 -1
  273. package/dist/search/orama-backend.d.ts +1 -1
  274. package/dist/search/port.d.ts +1 -1
  275. package/dist/search/remote-backend.d.ts +1 -1
  276. package/dist/{semantic-consolidation-BzCI6Kuu.d.ts → semantic-consolidation-NJpaZpkY.d.ts} +1 -1
  277. package/dist/semantic-consolidation.d.ts +2 -2
  278. package/dist/semantic-rule-verifier.d.ts +1 -1
  279. package/dist/{service-DQ3Gscy5.d.ts → service-DdlZjX1D.d.ts} +2 -2
  280. package/dist/session-observer-bands.d.ts +1 -1
  281. package/dist/session-observer-state.d.ts +1 -1
  282. package/dist/shared-context/manager.d.ts +7 -7
  283. package/dist/signal.d.ts +1 -1
  284. package/dist/source-agent-qualifier.d.ts +1 -1
  285. package/dist/source-agent-qualifier.js +4 -4
  286. package/dist/standup/build.js +2 -2
  287. package/dist/{storage-DmTbQdD0.d.ts → storage-C7BWrpU9.d.ts} +1 -1
  288. package/dist/storage.d.ts +2 -2
  289. package/dist/subject-config.d.ts +1 -1
  290. package/dist/summarizer.d.ts +1 -1
  291. package/dist/summary-snapshot.d.ts +1 -1
  292. package/dist/support-passport/index.d.ts +14 -14
  293. package/dist/support-passport/index.js +7 -7
  294. package/dist/temporal-supersession.d.ts +2 -2
  295. package/dist/temporal-timeline-recall.d.ts +1 -1
  296. package/dist/temporal-validity.d.ts +1 -1
  297. package/dist/threading.d.ts +1 -1
  298. package/dist/tier-migration.d.ts +2 -2
  299. package/dist/tier-routing.d.ts +1 -1
  300. package/dist/topics.d.ts +1 -1
  301. package/dist/transcript.d.ts +1 -1
  302. package/dist/transfer/export-okf.d.ts +1 -1
  303. package/dist/transfer/types.d.ts +78 -78
  304. package/dist/trust-score-stage.d.ts +1 -1
  305. package/dist/trust-score.d.ts +1 -1
  306. package/dist/{types-CLRTESSD.d.ts → types-Cy1l6fzp.d.ts} +48 -1
  307. package/dist/types.d.ts +1 -1
  308. package/dist/utility-runtime.d.ts +1 -1
  309. package/dist/who-knows-cli.d.ts +11 -11
  310. package/dist/who-knows.d.ts +11 -11
  311. package/dist/write-envelope.d.ts +1 -1
  312. package/package.json +2 -2
  313. package/src/activity/config.test.ts +94 -1
  314. package/src/activity/config.ts +256 -3
  315. package/src/activity/digest.ts +21 -0
  316. package/src/activity/index.ts +2 -0
  317. package/src/activity/runner.ts +2 -17
  318. package/src/activity/timeline/publish-cli.test.ts +169 -0
  319. package/src/activity/timeline/publish-cli.ts +144 -0
  320. package/src/activity/timeline/query.ts +51 -15
  321. package/src/activity/types.ts +45 -0
  322. package/src/activity/vault-insert.ts +14 -33
  323. package/src/activity/vault-path.ts +100 -22
  324. package/src/activity/vault-publish.test.ts +51 -0
  325. package/src/activity/vault-publish.ts +157 -17
  326. package/src/activity/vault-publisher.test.ts +881 -0
  327. package/src/activity/vault-publisher.ts +597 -0
  328. package/src/activity/vault-region.test.ts +5 -0
  329. package/src/activity/vault-region.ts +7 -2
  330. package/src/cli/timeline-publish-commands.ts +34 -0
  331. package/src/cli.ts +2 -2
  332. package/src/config.test.ts +24 -1
  333. package/dist/chunk-3ITTF7YH.js.map +0 -1
  334. package/dist/chunk-KJUWWN3T.js +0 -237
  335. package/dist/chunk-KJUWWN3T.js.map +0 -1
  336. package/dist/chunk-M6L7HI7R.js.map +0 -1
  337. package/dist/chunk-X4FIZAVQ.js.map +0 -1
  338. /package/dist/{chunk-TEZ2HTC7.js.map → chunk-33JKYLPX.js.map} +0 -0
  339. /package/dist/{chunk-5PTS43CH.js.map → chunk-4LG4CPOC.js.map} +0 -0
  340. /package/dist/{chunk-Z33VUMKY.js.map → chunk-5H2G5X4R.js.map} +0 -0
  341. /package/dist/{chunk-XFPHV65N.js.map → chunk-5JQV4T5Q.js.map} +0 -0
  342. /package/dist/{chunk-OASGWNYL.js.map → chunk-63I7LMLG.js.map} +0 -0
  343. /package/dist/{chunk-J3NGQ5SC.js.map → chunk-7GSSHAXC.js.map} +0 -0
  344. /package/dist/{chunk-VHAKBUBD.js.map → chunk-B64IVEOH.js.map} +0 -0
  345. /package/dist/{chunk-R7FXPG4T.js.map → chunk-C25N5HWX.js.map} +0 -0
  346. /package/dist/{chunk-DH3V7RCQ.js.map → chunk-F2ERDKY2.js.map} +0 -0
  347. /package/dist/{chunk-LJNLLNEM.js.map → chunk-HODFGQGT.js.map} +0 -0
  348. /package/dist/{chunk-B75VCEX5.js.map → chunk-K2IJH4D3.js.map} +0 -0
  349. /package/dist/{chunk-227WJVPY.js.map → chunk-KLSPKMIO.js.map} +0 -0
  350. /package/dist/{chunk-5P2KNFJZ.js.map → chunk-MSDIETFC.js.map} +0 -0
  351. /package/dist/{chunk-HFRGCNFY.js.map → chunk-OAKATRAN.js.map} +0 -0
  352. /package/dist/{chunk-LWBSEYW3.js.map → chunk-PAWIY5OQ.js.map} +0 -0
  353. /package/dist/{chunk-6TOWUN2R.js.map → chunk-RE3H6Y2X.js.map} +0 -0
  354. /package/dist/{chunk-V3HUBF7T.js.map → chunk-S35IIP5P.js.map} +0 -0
  355. /package/dist/{chunk-3YKOFCKP.js.map → chunk-SXHBZXHK.js.map} +0 -0
  356. /package/dist/{chunk-7NCUHD5U.js.map → chunk-VAMZYOOV.js.map} +0 -0
  357. /package/dist/{chunk-PGCZLHRB.js.map → chunk-W272SWN7.js.map} +0 -0
  358. /package/dist/{chunk-5HO3QBAD.js.map → chunk-W6GEMUZM.js.map} +0 -0
  359. /package/dist/{chunk-UCNQV43K.js.map → chunk-XQYTSZW3.js.map} +0 -0
  360. /package/dist/{chunk-GR4C3FHT.js.map → chunk-ZKZCJRRO.js.map} +0 -0
@@ -0,0 +1,169 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import path from "node:path";
6
+
7
+ import { parseConfig } from "../../config.js";
8
+ import type { PluginConfig } from "../../types.js";
9
+ import { runTimelineCliCommand } from "./query.js";
10
+
11
+ const DATE = "2026-08-21";
12
+ const RECAP = "- 09:00-10:00 code review (60m)";
13
+
14
+ interface Capture {
15
+ out: string;
16
+ err: string;
17
+ io: { stdout: { write(chunk: string): unknown }; stderr: { write(chunk: string): unknown } };
18
+ }
19
+
20
+ function capture(): Capture {
21
+ const sink: Capture = {
22
+ out: "",
23
+ err: "",
24
+ io: {
25
+ stdout: {
26
+ write(chunk: string) {
27
+ sink.out += chunk;
28
+ return true;
29
+ },
30
+ },
31
+ stderr: {
32
+ write(chunk: string) {
33
+ sink.err += chunk;
34
+ return true;
35
+ },
36
+ },
37
+ },
38
+ };
39
+ return sink;
40
+ }
41
+
42
+ function makeFixture(): { config: PluginConfig; notePath: string; note: string } {
43
+ const root = mkdtempSync(path.join(tmpdir(), "remnic-publish-cli-"));
44
+ const memoryDir = path.join(root, "memory");
45
+ const vaultPath = path.join(root, "vault");
46
+ mkdirSync(path.join(memoryDir, "journal"), { recursive: true });
47
+ mkdirSync(vaultPath, { recursive: true });
48
+ writeFileSync(path.join(memoryDir, "journal", `${DATE}.md`), `${RECAP}\n`, "utf8");
49
+
50
+ const note = [
51
+ "# Daily",
52
+ "",
53
+ "human text that must survive",
54
+ "",
55
+ "<!-- remnic:Timeline:start -->",
56
+ "stale",
57
+ "<!-- remnic:Timeline:end -->",
58
+ "",
59
+ ].join("\n");
60
+ const notePath = path.join(vaultPath, `${DATE}.md`);
61
+ writeFileSync(notePath, note, "utf8");
62
+
63
+ const config = parseConfig({
64
+ memoryDir,
65
+ activity: {
66
+ timezone: "UTC",
67
+ timeline: { vault: { enabled: true, vaultPath, dailyNotePath: "{yyyy}-{MM}-{dd}.md" } },
68
+ },
69
+ });
70
+ return { config, notePath, note };
71
+ }
72
+
73
+ test("the shared timeline runner dispatches publish and writes the managed region", async () => {
74
+ const { config, notePath } = makeFixture();
75
+ const sink = capture();
76
+
77
+ const code = await runTimelineCliCommand(
78
+ // qa stays disabled: publish is not a qa surface and must not be gated by it.
79
+ { cards: null, qa: { enabled: false, maxRangeDays: 31 }, timelineEnabled: true, config },
80
+ ["publish", "--date", DATE],
81
+ sink.io,
82
+ );
83
+
84
+ assert.equal(code, 0, sink.err);
85
+ assert.doesNotMatch(sink.err, /unknown command publish/);
86
+ assert.match(sink.out, /updated=1/);
87
+ const after = readFileSync(notePath, "utf8");
88
+ assert.ok(after.includes(RECAP), "the recap is published into the managed region");
89
+ assert.ok(after.includes("human text that must survive"));
90
+ });
91
+
92
+ test("the shared timeline runner reports publish as a valid command", async () => {
93
+ const sink = capture();
94
+ const code = await runTimelineCliCommand(
95
+ { cards: null, qa: { enabled: true, maxRangeDays: 31 }, timelineEnabled: true },
96
+ ["bogus"],
97
+ sink.io,
98
+ );
99
+ assert.equal(code, 1);
100
+ assert.match(sink.err, /valid: range, search, publish/);
101
+ });
102
+
103
+ test("publish without a config refuses instead of throwing", async () => {
104
+ const sink = capture();
105
+ const code = await runTimelineCliCommand(
106
+ { cards: null, qa: { enabled: true, maxRangeDays: 31 }, timelineEnabled: true },
107
+ ["publish"],
108
+ sink.io,
109
+ );
110
+ assert.equal(code, 1);
111
+ assert.match(sink.err, /requires the Remnic config/);
112
+ });
113
+
114
+ test("--what with only separators is rejected with a validation error", async () => {
115
+ const { config, notePath, note } = makeFixture();
116
+ const sink = capture();
117
+
118
+ const code = await runTimelineCliCommand(
119
+ { cards: null, qa: { enabled: false, maxRangeDays: 31 }, timelineEnabled: true, config },
120
+ ["publish", "--date", DATE, "--what", ",,"],
121
+ sink.io,
122
+ );
123
+
124
+ assert.equal(code, 1);
125
+ assert.match(sink.err, /--what must name at least one artifact/);
126
+ assert.equal(readFileSync(notePath, "utf8"), note, "nothing is published");
127
+ });
128
+
129
+ test("publish rejects query-only flags instead of silently publishing today's note", async () => {
130
+ const { config, notePath, note } = makeFixture();
131
+ const sink = capture();
132
+
133
+ const code = await runTimelineCliCommand(
134
+ { cards: null, qa: { enabled: false, maxRangeDays: 31 }, timelineEnabled: true, config },
135
+ ["publish", "--from", "2026-08-01"],
136
+ sink.io,
137
+ );
138
+
139
+ assert.equal(code, 1);
140
+ assert.match(sink.err, /unknown flag --from \(valid: --date, --dry-run, --week, --what\)/);
141
+ assert.equal(readFileSync(notePath, "utf8"), note, "no note is touched by unsupported syntax");
142
+ });
143
+
144
+ test("range and search reject publish-only flags instead of ignoring them", async () => {
145
+ const { config } = makeFixture();
146
+ const deps = {
147
+ cards: null,
148
+ qa: { enabled: true, maxRangeDays: 31 },
149
+ timelineEnabled: true,
150
+ config,
151
+ } as const;
152
+
153
+ const rangeSink = capture();
154
+ const rangeCode = await runTimelineCliCommand(
155
+ deps,
156
+ ["range", "--date", DATE, "--from", `${DATE}T00:00:00.000Z`, "--to", `${DATE}T00:00:00.000Z`],
157
+ rangeSink.io,
158
+ );
159
+ assert.equal(rangeCode, 1);
160
+ assert.match(
161
+ rangeSink.err,
162
+ /unknown flag --date \(valid: --categories, --format, --from, --include-distractions, --to\)/,
163
+ );
164
+
165
+ const searchSink = capture();
166
+ const searchCode = await runTimelineCliCommand(deps, ["search", "--query", "x", "--dry-run"], searchSink.io);
167
+ assert.equal(searchCode, 1);
168
+ assert.match(searchSink.err, /unknown flag --dry-run \(valid: --from, --limit, --query, --to\)/);
169
+ });
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Shared `timeline publish` implementation (issue #1985).
3
+ *
4
+ * Both CLI trees dispatch this one function: the host command group in
5
+ * `cli/timeline-publish-commands.ts` and the standalone binary's shared
6
+ * runner in `timeline/query.ts`. A documented command that exists on only
7
+ * one tree is a defect — the shipped `@remnic/cli` binary must publish too.
8
+ */
9
+ import { existsSync, readFileSync } from "node:fs";
10
+
11
+ import type { PluginConfig } from "../../types.js";
12
+ import { activityDateInTimezone, isValidActivityDate } from "../digest.js";
13
+ import { journalPath } from "../journal.js";
14
+ import { publishVaultNote, type VaultSectionPublish } from "../vault-publisher.js";
15
+
16
+ export interface TimelinePublishIo {
17
+ stdout: { write(chunk: string): unknown };
18
+ stderr: { write(chunk: string): unknown };
19
+ }
20
+
21
+ export interface TimelinePublishOptions {
22
+ date?: unknown;
23
+ week?: unknown;
24
+ what?: unknown;
25
+ dryRun?: unknown;
26
+ }
27
+
28
+ const AVAILABLE_KINDS = ["timeline"] as const;
29
+ const KNOWN_KINDS = ["timeline", "standup", "weekly", "locations"] as const;
30
+ const UNLANDED_REASONS: Record<string, string> = {
31
+ standup: "the standup renderer lands with timeline phase 3",
32
+ weekly: "the weekly review renderer lands with timeline phase 4",
33
+ locations: "the location day renderer is not wired to publishing yet",
34
+ };
35
+
36
+ export function runTimelinePublishCli(
37
+ config: PluginConfig,
38
+ options: TimelinePublishOptions,
39
+ io: TimelinePublishIo,
40
+ ): number {
41
+ const vault = config.activity?.timeline?.vault;
42
+
43
+ if (options.week !== undefined) {
44
+ io.stderr.write("--week is not available yet: the weekly review renderer lands with timeline phase 4.\n");
45
+ return 1;
46
+ }
47
+ if (!vault || vault.enabled !== true) {
48
+ io.stderr.write(
49
+ "Vault publishing is disabled: set activity.timeline.vault.enabled=true and configure vaultPath first.\n",
50
+ );
51
+ return 1;
52
+ }
53
+
54
+ // Timeline artifacts are grouped on the configured activity timezone's
55
+ // calendar day, so "today" must be derived there — the host-local day
56
+ // drifts by one near either timezone's midnight.
57
+ const date =
58
+ typeof options.date === "string" && options.date.length > 0
59
+ ? options.date
60
+ : activityDateInTimezone(new Date(), config.activity?.timezone ?? "UTC");
61
+ if (!isValidActivityDate(date)) {
62
+ io.stderr.write(`Invalid --date "${date}"; expected YYYY-MM-DD.\n`);
63
+ return 1;
64
+ }
65
+
66
+ const requested = parseKinds(typeof options.what === "string" && options.what.length > 0 ? options.what : "timeline");
67
+ if (typeof requested !== "string") {
68
+ io.stderr.write(requested.error);
69
+ return 1;
70
+ }
71
+ const kinds = requested.split(",");
72
+ const sections: VaultSectionPublish[] = [];
73
+ let notePathTemplate = vault.dailyNotePath;
74
+
75
+ for (const kind of kinds) {
76
+ if ((AVAILABLE_KINDS as readonly string[]).indexOf(kind) === -1) {
77
+ io.stderr.write(`--what ${kind} is not available yet: ${UNLANDED_REASONS[kind] ?? "unknown kind"}.\n`);
78
+ return 1;
79
+ }
80
+ const target = vault.publish[kind as "timeline"];
81
+ if (target.enabled !== true) {
82
+ io.stderr.write(`--what ${kind} is disabled: enable activity.timeline.vault.publish.${kind}.enabled.\n`);
83
+ return 1;
84
+ }
85
+ // Honor the target's configured note file; config parsing already
86
+ // rejects target="weekly" with an empty weeklyNotePath.
87
+ notePathTemplate = target.target === "weekly" ? vault.weeklyNotePath : vault.dailyNotePath;
88
+ const source = journalPath(config.memoryDir, date);
89
+ if (!existsSync(source)) {
90
+ io.stderr.write(
91
+ `No timeline artifact for ${date}: run the journal recap generation first (${kind} target reads the persisted day recap).\n`,
92
+ );
93
+ return 1;
94
+ }
95
+ sections.push({ name: target.section, content: readFileSync(source, "utf8").trimEnd() });
96
+ }
97
+
98
+ const status = publishVaultNote({
99
+ vaultPath: vault.vaultPath,
100
+ notePathTemplate,
101
+ date,
102
+ sections,
103
+ strategy: vault.sectionStrategy,
104
+ insertUnderHeading: vault.insertUnderHeading.length > 0 ? vault.insertUnderHeading : undefined,
105
+ createMissingNotes: vault.createMissingNotes,
106
+ noteTemplate: vault.noteTemplate.length > 0 ? vault.noteTemplate : undefined,
107
+ propertiesMode: vault.properties.mode,
108
+ propertiesPrefix: vault.properties.prefix,
109
+ dryRun: options.dryRun === true,
110
+ });
111
+
112
+ for (const row of status.results) {
113
+ const label = row.outcome === "updated" && options.dryRun === true ? "would update" : row.outcome;
114
+ io.stdout.write(`${label} ${row.path}${row.reason ? ` (${row.reason})` : ""}\n`);
115
+ }
116
+ io.stdout.write(
117
+ `updated=${status.counts.updated} unchanged=${status.counts.unchanged} skipped=${status.counts.skipped} error=${status.counts.error}\n`,
118
+ );
119
+ return status.hasError ? 1 : 0;
120
+ }
121
+
122
+ /**
123
+ * `--what` is normalized to a comma-joined kind list. An empty normalized
124
+ * list (`--what ','`) is rejected here rather than reaching the publisher,
125
+ * which throws a RangeError on a zero-length section list.
126
+ */
127
+ function parseKinds(raw: string): string | { error: string } {
128
+ const kinds = raw
129
+ .split(",")
130
+ .map((part) => part.trim())
131
+ .filter((part) => part.length > 0);
132
+ for (const kind of kinds) {
133
+ if ((KNOWN_KINDS as readonly string[]).indexOf(kind) === -1) {
134
+ return { error: `Unknown --what kind "${kind}"; valid kinds are ${KNOWN_KINDS.join(", ")}.\n` };
135
+ }
136
+ }
137
+ if (new Set(kinds).size !== kinds.length) {
138
+ return { error: "--what must not repeat a kind.\n" };
139
+ }
140
+ if (kinds.length === 0) {
141
+ return { error: `--what must name at least one artifact; valid kinds are ${KNOWN_KINDS.join(", ")}.\n` };
142
+ }
143
+ return kinds.join(",");
144
+ }
@@ -9,7 +9,9 @@
9
9
  * MCP/HTTP and recall injection are later PRs.
10
10
  */
11
11
  import { parseFlexibleIsoTimestamp } from "../../utils/iso-timestamp.js";
12
+ import type { PluginConfig } from "../../types.js";
12
13
  import type { ActivityTimelineQaConfig } from "../types.js";
14
+ import { runTimelinePublishCli } from "./publish-cli.js";
13
15
  import type { TimelineCard } from "./types.js";
14
16
 
15
17
  const RANGE_FORMATS = ["cards", "compact"] as const;
@@ -70,6 +72,8 @@ export interface TimelineCliDeps {
70
72
  cards: readonly TimelineQueryCard[] | null;
71
73
  qa: ActivityTimelineQaConfig;
72
74
  timelineEnabled?: boolean;
75
+ /** Required for `publish`; range/search never read it. */
76
+ config?: PluginConfig;
73
77
  }
74
78
 
75
79
  const USAGE = `Usage: timeline <command> [options]
@@ -77,17 +81,25 @@ const USAGE = `Usage: timeline <command> [options]
77
81
  Commands:
78
82
  range --from <ISO> --to <ISO> [--format cards|compact] [--categories id,id] [--include-distractions]
79
83
  search --query <text> [--from <ISO>] [--to <ISO>] [--limit N]
84
+ publish [--date YYYY-MM-DD] [--what timeline] [--dry-run]
80
85
  `;
81
86
 
82
- const VALUE_FLAGS: Record<string, true> = {
83
- "--from": true,
84
- "--to": true,
85
- "--format": true,
86
- "--categories": true,
87
- "--query": true,
88
- "--limit": true,
87
+ // Per-subcommand flag allow-lists (issue #1985 review): a shared union table
88
+ // let `timeline publish --from …` parse and then silently discard `--from`,
89
+ // publishing today's note on a query-only flag — and `range --date` likewise.
90
+ // Every subcommand validates its own syntax before dispatch.
91
+ const PUBLISH_FLAGS = {
92
+ value: { "--date": true, "--week": true, "--what": true } as Record<string, true>,
93
+ boolean: { "--dry-run": true } as Record<string, true>,
94
+ };
95
+ const RANGE_FLAGS = {
96
+ value: { "--from": true, "--to": true, "--format": true, "--categories": true } as Record<string, true>,
97
+ boolean: { "--include-distractions": true } as Record<string, true>,
98
+ };
99
+ const SEARCH_FLAGS = {
100
+ value: { "--query": true, "--from": true, "--to": true, "--limit": true } as Record<string, true>,
101
+ boolean: {} as Record<string, true>,
89
102
  };
90
- const BOOLEAN_FLAGS: Record<string, true> = { "--include-distractions": true };
91
103
 
92
104
  function parseInstant(value: string, label: string): number {
93
105
  const ms = parseFlexibleIsoTimestamp(value);
@@ -214,16 +226,19 @@ export function queryTimelineSearch(
214
226
  return { ok: true, results: ranked };
215
227
  }
216
228
 
217
- function parseFlags(args: string[]): { flags: Map<string, string | true>; positional: string[] } {
229
+ function parseFlags(
230
+ args: string[],
231
+ spec: { value: Record<string, true>; boolean: Record<string, true> },
232
+ ): { flags: Map<string, string | true>; positional: string[] } {
218
233
  const flags = new Map<string, string | true>();
219
234
  const positional: string[] = [];
220
- for (let i = 0; i < args.length; i++) {
235
+ for (let i = 0; i < args.length; i += 1) {
221
236
  const arg = args[i]!;
222
237
  if (!arg.startsWith("--")) {
223
238
  positional.push(arg);
224
239
  continue;
225
240
  }
226
- if (VALUE_FLAGS[arg] === true) {
241
+ if (spec.value[arg] === true) {
227
242
  const value = args[i + 1];
228
243
  if (value === undefined || value.startsWith("--")) {
229
244
  throw new TypeError(`flag ${arg} requires a value`);
@@ -232,11 +247,11 @@ function parseFlags(args: string[]): { flags: Map<string, string | true>; positi
232
247
  i += 1;
233
248
  continue;
234
249
  }
235
- if (BOOLEAN_FLAGS[arg] === true) {
250
+ if (spec.boolean[arg] === true) {
236
251
  flags.set(arg, true);
237
252
  continue;
238
253
  }
239
- const known = [...Object.keys(VALUE_FLAGS), ...Object.keys(BOOLEAN_FLAGS)].sort().join(", ");
254
+ const known = [...Object.keys(spec.value), ...Object.keys(spec.boolean)].sort().join(", ");
240
255
  throw new TypeError(`unknown flag ${arg} (valid: ${known})`);
241
256
  }
242
257
  return { flags, positional };
@@ -259,11 +274,32 @@ export async function runTimelineCliCommand(
259
274
  io.stdout.write(USAGE);
260
275
  return command === undefined ? 1 : 0;
261
276
  }
277
+ // `publish` writes into the user's vault and is not a qa/query surface,
278
+ // so it dispatches before the qa gate. Flags are validated against the
279
+ // publish-only set: `--from`/`--format` are query syntax and must be
280
+ // rejected here, not silently dropped while today's note is published.
281
+ if (command === "publish") {
282
+ if (deps.config === undefined) {
283
+ io.stderr.write("timeline publish requires the Remnic config — run `remnic doctor`\n");
284
+ return 1;
285
+ }
286
+ const publishFlags = parseFlags(rest, PUBLISH_FLAGS).flags;
287
+ return runTimelinePublishCli(
288
+ deps.config,
289
+ {
290
+ date: flagString(publishFlags, "--date"),
291
+ week: flagString(publishFlags, "--week"),
292
+ what: flagString(publishFlags, "--what"),
293
+ dryRun: publishFlags.get("--dry-run") === true,
294
+ },
295
+ io,
296
+ );
297
+ }
262
298
  if (deps.timelineEnabled === false || !deps.qa.enabled) {
263
299
  io.stderr.write("timeline qa disabled — set activity.timeline.qa.enabled=true\n");
264
300
  return 1;
265
301
  }
266
- const { flags } = parseFlags(rest);
302
+ const { flags } = parseFlags(rest, command === "range" ? RANGE_FLAGS : SEARCH_FLAGS);
267
303
  if (command === "range") {
268
304
  const from = flagString(flags, "--from");
269
305
  const to = flagString(flags, "--to");
@@ -305,7 +341,7 @@ export async function runTimelineCliCommand(
305
341
  io.stdout.write(`${JSON.stringify(result)}\n`);
306
342
  return result.ok ? 0 : 1;
307
343
  }
308
- throw new TypeError(`unknown command ${command} (valid: range, search)`);
344
+ throw new TypeError(`unknown command ${command} (valid: range, search, publish)`);
309
345
  } catch (err) {
310
346
  io.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
311
347
  return 1;
@@ -105,6 +105,50 @@ export interface ActivityTimelineJournalConfig {
105
105
  heading?: string;
106
106
  }
107
107
 
108
+ /** Section ownership strategy for vault publishing (issue #1985). */
109
+ export type VaultSectionStrategy = "markers" | "heading";
110
+
111
+ /** Where section stats are written (issue #1985). `off` writes none. */
112
+ export type VaultPropertiesMode = "off" | "frontmatter" | "dataview-inline";
113
+
114
+ export interface ActivityTimelineVaultTargetConfig {
115
+ enabled: boolean;
116
+ target: "daily" | "weekly";
117
+ section: string;
118
+ }
119
+
120
+ /**
121
+ * Opt-in markdown-vault publisher settings (issue #1985). Default off:
122
+ * `enabled: false` means no vault reads or writes ever occur.
123
+ */
124
+ export interface ActivityTimelineVaultConfig {
125
+ enabled: boolean;
126
+ /** Vault root; absolute or `~` path. Required and non-empty when enabled. */
127
+ vaultPath: string;
128
+ /** Vault-relative daily-note path template; date tokens. */
129
+ dailyNotePath: string;
130
+ /** Empty means weekly-note publishing is disabled. */
131
+ weeklyNotePath: string;
132
+ createMissingNotes: boolean;
133
+ /** Vault-relative template file, used only when creating a missing note. */
134
+ noteTemplate: string;
135
+ sectionStrategy: VaultSectionStrategy;
136
+ publish: {
137
+ timeline: ActivityTimelineVaultTargetConfig;
138
+ /** Standup target lights up when phase 3 lands. */
139
+ standup: ActivityTimelineVaultTargetConfig;
140
+ /** Weekly target lights up when phase 4 lands. */
141
+ weekly: ActivityTimelineVaultTargetConfig;
142
+ /** Locations target lights up with the location day renderer. */
143
+ locations: ActivityTimelineVaultTargetConfig;
144
+ };
145
+ /** Markers strategy: heading under which missing marker pairs are inserted; empty = never insert. */
146
+ insertUnderHeading: string;
147
+ wikilinks: { places: boolean; placesFolder: string };
148
+ properties: { mode: VaultPropertiesMode; prefix: string };
149
+ autoPublish: boolean;
150
+ }
151
+
108
152
  /** Opt-in timeline Q&A range/search settings (issue #1983 PR1). Default off. */
109
153
  export interface ActivityTimelineQaConfig {
110
154
  enabled: boolean;
@@ -117,6 +161,7 @@ export interface ActivityTimelineConfig {
117
161
  enabled: boolean;
118
162
  journal: ActivityTimelineJournalConfig;
119
163
  qa: ActivityTimelineQaConfig;
164
+ vault: ActivityTimelineVaultConfig;
120
165
  }
121
166
 
122
167
  /** Opt-in activity synchronization + trust-gated extraction settings. */
@@ -2,10 +2,13 @@
2
2
  * Managed-region marker insertion (issue #1985).
3
3
  *
4
4
  * Inserts a `<!-- remnic:<name>:start/end -->` pair under a unique ATX
5
- * heading when the region is absent. This helper never replaces (see
6
- * `vault-publish.ts`), never creates files, and never invents a heading.
7
- * Pure string-in/string-out.
5
+ * heading when the region is absent. Code blocks fenced or indented —
6
+ * are invisible to
7
+ * the heading scan, so a live region is never inserted into a `## …`
8
+ * example. This helper never replaces (see `vault-publish.ts`), never
9
+ * creates files, and never invents a heading. Pure string-in/string-out.
8
10
  */
11
+ import { fileLines, parseAtxHeading } from "./vault-publish.js";
9
12
 
10
13
  export type InsertVaultRegionResult =
11
14
  | { ok: true; text: string; inserted: true }
@@ -26,13 +29,17 @@ export function insertMarkersUnderHeading(
26
29
 
27
30
  const startMarker = `<!-- remnic:${opts.name}:start -->`;
28
31
  const endMarker = `<!-- remnic:${opts.name}:end -->`;
29
- if (fileText.includes(startMarker) && fileText.includes(endMarker)) {
30
- return { ok: true, text: fileText, inserted: false };
31
- }
32
-
33
32
  const rows = fileLines(fileText);
33
+ // A fenced example pair is sample text, not a live region (issue #1985):
34
+ // only markers outside a code block count as "already present".
35
+ const present =
36
+ rows.some((row) => !row.fenced && row.line.includes(startMarker)) &&
37
+ rows.some((row) => !row.fenced && row.line.includes(endMarker));
38
+ if (present) return { ok: true, text: fileText, inserted: false };
39
+
34
40
  const hits: Array<{ row: (typeof rows)[number]; level: number }> = [];
35
41
  for (const row of rows) {
42
+ if (row.fenced) continue;
36
43
  const heading = parseAtxHeading(row.line);
37
44
  if (heading && heading.text === opts.heading) {
38
45
  hits.push({ row, level: heading.level });
@@ -58,29 +65,3 @@ export function insertMarkersUnderHeading(
58
65
  return { ok: true, text, inserted: true };
59
66
  }
60
67
 
61
- type FileLine = { line: string; start: number; next: number; number: number };
62
-
63
- function fileLines(fileText: string): FileLine[] {
64
- const rows: FileLine[] = [];
65
- let start = 0;
66
- let number = 1;
67
- while (start < fileText.length) {
68
- let i = start;
69
- while (i < fileText.length && fileText[i] !== "\n" && fileText[i] !== "\r") i++;
70
- let next = i;
71
- if (fileText[i] === "\r" && fileText[i + 1] === "\n") next = i + 2;
72
- else if (fileText[i] === "\n" || fileText[i] === "\r") next = i + 1;
73
- else next = fileText.length;
74
- rows.push({ line: fileText.slice(start, i), start, next, number });
75
- number += 1;
76
- start = next;
77
- }
78
- return rows;
79
- }
80
-
81
- function parseAtxHeading(line: string): { level: number; text: string } | null {
82
- let level = 0;
83
- while (level < line.length && level < 6 && line[level] === "#") level++;
84
- if (level === 0 || line[level] !== " ") return null;
85
- return { level, text: line.slice(level + 1) };
86
- }