@remnic/core 9.3.613 → 9.3.615
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.
- package/dist/access-cli.js +59 -58
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +4 -2
- package/dist/access-http.js +23 -23
- package/dist/access-mcp.d.ts +9 -2
- package/dist/access-mcp.js +20 -20
- package/dist/access-schema.d.ts +26 -14
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-D2J9dh_9.d.ts → access-service-CBNEKjzN.d.ts} +71 -6
- package/dist/access-service.d.ts +2 -2
- package/dist/access-service.js +17 -17
- package/dist/active-recall.js +20 -3
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/behavior-learner.js +2 -3
- package/dist/behavior-learner.js.map +1 -1
- package/dist/bootstrap.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer.d.ts +1 -1
- package/dist/buffer.js +1 -1
- package/dist/calibration.d.ts +5 -2
- package/dist/calibration.js +7 -5
- package/dist/calibration.js.map +1 -1
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/causal-consolidation.d.ts +8 -2
- package/dist/causal-consolidation.js +13 -11
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-3BP57I6J.js → chunk-2F6NP3NT.js} +2 -1
- package/dist/{chunk-3BP57I6J.js.map → chunk-2F6NP3NT.js.map} +1 -1
- package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
- package/dist/{chunk-HSVJGWYS.js → chunk-2ROPI5OE.js} +2 -2
- package/dist/{chunk-C4SQJZAF.js → chunk-2SGJY2UY.js} +6 -3
- package/dist/chunk-2SGJY2UY.js.map +1 -0
- package/dist/{chunk-ZDTVJXIP.js → chunk-3MAONBX3.js} +13 -5
- package/dist/chunk-3MAONBX3.js.map +1 -0
- package/dist/{chunk-G3Z3QEF5.js → chunk-3PY7VHV7.js} +2 -2
- package/dist/chunk-3PY7VHV7.js.map +1 -0
- package/dist/{chunk-CF3ZF2YU.js → chunk-3QSU4NFF.js} +3 -3
- package/dist/{chunk-AJA46VX5.js → chunk-3T74IZB3.js} +11 -2
- package/dist/chunk-3T74IZB3.js.map +1 -0
- package/dist/{chunk-KVEVLBKC.js → chunk-4HFJQCJZ.js} +13 -8
- package/dist/chunk-4HFJQCJZ.js.map +1 -0
- package/dist/{chunk-KGK2QKWL.js → chunk-4R4KTDIE.js} +1 -1
- package/dist/chunk-4R4KTDIE.js.map +1 -0
- package/dist/{chunk-OI27U2HT.js → chunk-5BTCT236.js} +2 -2
- package/dist/{chunk-TH67Q46T.js → chunk-5OHHEORR.js} +64 -21
- package/dist/chunk-5OHHEORR.js.map +1 -0
- package/dist/{chunk-CO7ZO4TU.js → chunk-5VDJMYTF.js} +2 -2
- package/dist/{chunk-BFBF3XEF.js → chunk-6BDVBBBY.js} +33 -25
- package/dist/{chunk-BFBF3XEF.js.map → chunk-6BDVBBBY.js.map} +1 -1
- package/dist/{chunk-EAZGEEG2.js → chunk-6L46YAEZ.js} +45 -9
- package/dist/chunk-6L46YAEZ.js.map +1 -0
- package/dist/{chunk-YFS5OEKO.js → chunk-7MLB4NCL.js} +2 -2
- package/dist/{chunk-LZ3VEOU5.js → chunk-AL4RAJL5.js} +22 -5
- package/dist/chunk-AL4RAJL5.js.map +1 -0
- package/dist/{chunk-557IAFPD.js → chunk-APRRL26Q.js} +2 -2
- package/dist/{chunk-QDDHYAKV.js → chunk-AZDOWD2L.js} +2 -2
- package/dist/{chunk-MLT75J5S.js → chunk-B6SU7YSE.js} +3 -3
- package/dist/{chunk-FXKPZ3H6.js → chunk-BPSGLMQ4.js} +2 -2
- package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-NOMEVTUD.js → chunk-C6C7XVKG.js} +5 -4
- package/dist/chunk-C6C7XVKG.js.map +1 -0
- package/dist/{chunk-XKIQZXUB.js → chunk-CI7RKSRE.js} +7 -1
- package/dist/chunk-CI7RKSRE.js.map +1 -0
- package/dist/{chunk-IK34DVAC.js → chunk-CIOMS6DI.js} +2 -2
- package/dist/{chunk-2I5JGH3M.js → chunk-CYEPCZN5.js} +2 -2
- package/dist/{chunk-2I5JGH3M.js.map → chunk-CYEPCZN5.js.map} +1 -1
- package/dist/{chunk-JHMFYY7L.js → chunk-DCGT4FPP.js} +13 -5
- package/dist/chunk-DCGT4FPP.js.map +1 -0
- package/dist/{chunk-7DZRO2DC.js → chunk-DEPRLVLK.js} +2 -2
- package/dist/{chunk-CSKLPDN6.js → chunk-DEVUWMME.js} +52 -19
- package/dist/chunk-DEVUWMME.js.map +1 -0
- package/dist/{chunk-DHGSZ3UD.js → chunk-DGNQRNLL.js} +2 -2
- package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-HJNQQICM.js → chunk-EXUAP5LH.js} +108 -51
- package/dist/chunk-EXUAP5LH.js.map +1 -0
- package/dist/chunk-FAV25DUZ.js +12 -0
- package/dist/chunk-FAV25DUZ.js.map +1 -0
- package/dist/{chunk-ETUPBUHB.js → chunk-GDASG7NC.js} +2 -2
- package/dist/{chunk-L227SKTB.js → chunk-GDB4J2H3.js} +17 -1
- package/dist/chunk-GDB4J2H3.js.map +1 -0
- package/dist/{chunk-IP73YCZP.js → chunk-GLPBYIXN.js} +4 -2
- package/dist/chunk-GLPBYIXN.js.map +1 -0
- package/dist/{chunk-4HP7HIE3.js → chunk-HP5FMB6L.js} +2 -2
- package/dist/{chunk-EVZFIAPG.js → chunk-IBTZEBUD.js} +23 -10
- package/dist/chunk-IBTZEBUD.js.map +1 -0
- package/dist/{chunk-DOX2CG6Y.js → chunk-IEUU7O4F.js} +2 -2
- package/dist/{chunk-EUML3N6B.js → chunk-IMA6GU4Y.js} +3 -3
- package/dist/chunk-IMA6GU4Y.js.map +1 -0
- package/dist/{chunk-JNANKJLN.js → chunk-JOASJWQR.js} +2 -2
- package/dist/chunk-JOASJWQR.js.map +1 -0
- package/dist/{chunk-WSGF57U2.js → chunk-JQDZQ4TB.js} +2 -2
- package/dist/{chunk-HINSGUA7.js → chunk-KBL3JJR6.js} +9 -13
- package/dist/chunk-KBL3JJR6.js.map +1 -0
- package/dist/{chunk-IOTENEVL.js → chunk-KGLPJROV.js} +57 -50
- package/dist/chunk-KGLPJROV.js.map +1 -0
- package/dist/{chunk-W7L6HXUC.js → chunk-LXOM6IQU.js} +2 -2
- package/dist/{chunk-G6R5UD3Q.js → chunk-MGN7VHWQ.js} +42 -1
- package/dist/{chunk-G6R5UD3Q.js.map → chunk-MGN7VHWQ.js.map} +1 -1
- package/dist/{chunk-DLJ4IR6M.js → chunk-MHQC2WU2.js} +2 -2
- package/dist/chunk-MHQC2WU2.js.map +1 -0
- package/dist/{chunk-5RPTH6AU.js → chunk-NM5NQYJE.js} +20 -19
- package/dist/chunk-NM5NQYJE.js.map +1 -0
- package/dist/{chunk-6JGNHWCI.js → chunk-OBIRVF36.js} +3 -3
- package/dist/{chunk-CHCA44C3.js → chunk-ODPLEWB6.js} +3 -3
- package/dist/chunk-ODPLEWB6.js.map +1 -0
- package/dist/{chunk-HENLZHIT.js → chunk-OIF36KGD.js} +7 -4
- package/dist/chunk-OIF36KGD.js.map +1 -0
- package/dist/{chunk-GUPISBV2.js → chunk-PP2JH3GP.js} +2 -2
- package/dist/{chunk-OXJBNGBK.js → chunk-PSUB67YB.js} +2 -2
- package/dist/{chunk-UWY7GIVS.js → chunk-PYIFUBRK.js} +45 -13
- package/dist/chunk-PYIFUBRK.js.map +1 -0
- package/dist/{chunk-KIB7SDIJ.js → chunk-Q6YIJGXJ.js} +2 -2
- package/dist/{chunk-ZT3EGNLR.js → chunk-QPD426WT.js} +2 -2
- package/dist/{chunk-RLV3PQGH.js → chunk-QVO4YOB7.js} +6 -6
- package/dist/{chunk-GMAG2HS4.js → chunk-RG3LBSGH.js} +46 -9
- package/dist/chunk-RG3LBSGH.js.map +1 -0
- package/dist/{chunk-XSWKORGM.js → chunk-S53OYO3F.js} +3 -1
- package/dist/chunk-S53OYO3F.js.map +1 -0
- package/dist/{chunk-YCN4BVDK.js → chunk-SCPFRKIT.js} +4 -2
- package/dist/chunk-SCPFRKIT.js.map +1 -0
- package/dist/{chunk-NZPF2SYV.js → chunk-T7N6KQGS.js} +138 -5
- package/dist/chunk-T7N6KQGS.js.map +1 -0
- package/dist/{chunk-VJXSUAO7.js → chunk-TNOWU6RP.js} +13 -10
- package/dist/chunk-TNOWU6RP.js.map +1 -0
- package/dist/{chunk-PCI747N2.js → chunk-TZVQQTG4.js} +48 -19
- package/dist/chunk-TZVQQTG4.js.map +1 -0
- package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
- package/dist/{chunk-IK7DCC5H.js → chunk-VMGLYN42.js} +2 -2
- package/dist/{chunk-KM2A35EO.js → chunk-WB3LYXC5.js} +11 -7
- package/dist/chunk-WB3LYXC5.js.map +1 -0
- package/dist/{chunk-PPPZY2EU.js → chunk-WD2W4234.js} +9 -3
- package/dist/chunk-WD2W4234.js.map +1 -0
- package/dist/{chunk-NSKYFGDL.js → chunk-X4QQB7O6.js} +2 -2
- package/dist/{chunk-HPWVAEET.js → chunk-X6IRLNOO.js} +3 -7
- package/dist/chunk-X6IRLNOO.js.map +1 -0
- package/dist/{chunk-46GJIW5M.js → chunk-XAZOWLW4.js} +5 -5
- package/dist/{chunk-46GJIW5M.js.map → chunk-XAZOWLW4.js.map} +1 -1
- package/dist/{chunk-XPSVGJYA.js → chunk-YRMKDTKF.js} +12 -9
- package/dist/chunk-YRMKDTKF.js.map +1 -0
- package/dist/{chunk-6ZZP4EJF.js → chunk-ZJR7VG5L.js} +3 -3
- package/dist/{chunk-6ZZP4EJF.js.map → chunk-ZJR7VG5L.js.map} +1 -1
- package/dist/{chunk-2QANQKSQ.js → chunk-ZK32E74R.js} +156 -45
- package/dist/chunk-ZK32E74R.js.map +1 -0
- package/dist/{cli-OrfKXNU4.d.ts → cli-Cw729yLf.d.ts} +6 -2
- package/dist/cli.d.ts +3 -3
- package/dist/cli.js +61 -60
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.js +39 -11
- package/dist/compounding/preference-consolidator.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.js +1 -1
- package/dist/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/indexer.js +1 -1
- package/dist/cross-namespace-budget.js +1 -1
- package/dist/enrichment/index.js +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/evals.js +1 -1
- package/dist/explicit-capture.d.ts +11 -1
- package/dist/explicit-capture.js +1 -1
- package/dist/extraction-judge.js +8 -1
- package/dist/extraction.js +2 -2
- package/dist/fallback-llm.d.ts +23 -6
- package/dist/fallback-llm.js +5 -3
- package/dist/{first-start-migration-GYJWIH36.js → first-start-migration-FF7YFGRP.js} +6 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +95 -94
- package/dist/index.js.map +1 -1
- package/dist/lcm/archive.js +2 -2
- package/dist/lcm/engine.js +5 -5
- package/dist/lcm/index.js +7 -7
- package/dist/lcm/summarizer.js +3 -3
- package/dist/maintenance/memory-governance-cron.d.ts +6 -4
- package/dist/maintenance/memory-governance-cron.js +1 -1
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +2 -2
- package/dist/mcp-memory-inspector-app.js +1 -1
- package/dist/migrate/from-engram.js +1 -1
- package/dist/namespaces/migrate.js +16 -15
- package/dist/namespaces/search.js +12 -11
- package/dist/namespaces/storage.js +3 -3
- package/dist/network/webdav.d.ts +2 -0
- package/dist/network/webdav.js +1 -1
- package/dist/objective-state-writers.js +2 -2
- package/dist/operator-toolkit.d.ts +3 -1
- package/dist/operator-toolkit.js +21 -20
- package/dist/{orchestrator-DTRQG75J.d.ts → orchestrator-CqWOjfgl.d.ts} +46 -3
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +48 -45
- package/dist/patterns-cli.js +1 -1
- package/dist/qmd-recall-cache.d.ts +2 -0
- package/dist/qmd-recall-cache.js +1 -1
- package/dist/qmd.d.ts +37 -2
- package/dist/qmd.js +4 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +57 -0
- package/dist/recall-planner-llm.js +167 -0
- package/dist/recall-planner-llm.js.map +1 -0
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.js +2 -2
- package/dist/routing/store.js +1 -1
- package/dist/schemas.d.ts +22 -22
- package/dist/search/factory.js +11 -10
- package/dist/search/index.js +11 -10
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +3 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +3 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/noop-backend.js +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +3 -2
- package/dist/search/port.d.ts +6 -1
- package/dist/search/port.js +7 -0
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/search/remote-backend.js +1 -1
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/session-observer-state.js +1 -1
- package/dist/storage.js +2 -2
- package/dist/summarizer.js +2 -2
- package/dist/temporal-index.js +1 -1
- package/dist/{tier-stats-SKML2OSF.js → tier-stats-3LYQ3VV5.js} +3 -3
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-sqlite.js +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/types.d.ts +32 -0
- package/dist/types.js +1 -1
- package/dist/utility-learner.js +1 -1
- package/dist/utility-runtime.js +2 -2
- package/dist/verified-recall.js +3 -3
- package/dist/work/board.js +2 -2
- package/dist/work/storage.d.ts +2 -0
- package/dist/work/storage.js +1 -1
- package/package.json +1 -1
- package/src/access-http.ts +24 -10
- package/src/access-mcp.test.ts +160 -0
- package/src/access-mcp.ts +72 -7
- package/src/access-schema.ts +11 -0
- package/src/access-service-coding-write.test.ts +478 -0
- package/src/access-service.ts +237 -32
- package/src/active-recall.test.ts +40 -0
- package/src/active-recall.ts +19 -2
- package/src/behavior-learner.ts +5 -3
- package/src/buffer-session.test.ts +58 -0
- package/src/buffer-surprise-trigger.test.ts +4 -18
- package/src/buffer.ts +39 -11
- package/src/calibration.ts +10 -4
- package/src/causal-consolidation.test.ts +47 -2
- package/src/causal-consolidation.ts +13 -9
- package/src/cli.ts +19 -4
- package/src/compounding/engine.ts +2 -0
- package/src/compounding/preference-consolidator.test.ts +292 -0
- package/src/compounding/preference-consolidator.ts +55 -19
- package/src/config.test.ts +213 -0
- package/src/config.ts +175 -4
- package/src/connectors/codex-materialize-runner.ts +7 -4
- package/src/consolidation-provenance-check.ts +24 -5
- package/src/conversation-index/indexer.test.ts +22 -0
- package/src/conversation-index/indexer.ts +7 -3
- package/src/cross-namespace-budget.test.ts +44 -21
- package/src/cross-namespace-budget.ts +2 -2
- package/src/enrichment/pipeline.ts +11 -16
- package/src/evals.ts +1 -1
- package/src/explicit-capture.ts +19 -2
- package/src/extraction-judge-chain.test.ts +55 -0
- package/src/extraction-judge.ts +7 -9
- package/src/extraction.ts +16 -5
- package/src/fallback-llm.test.ts +600 -1
- package/src/fallback-llm.ts +91 -22
- package/src/maintenance/memory-governance-cron.ts +39 -29
- package/src/mcp-memory-inspector-app.ts +54 -12
- package/src/message-parts/index.ts +6 -0
- package/src/message-parts/message-parts.test.ts +30 -0
- package/src/migrate/from-engram.ts +19 -5
- package/src/namespaces/search.test.ts +15 -2
- package/src/namespaces/search.ts +1 -1
- package/src/network/webdav.ts +61 -21
- package/src/operator-toolkit.ts +6 -2
- package/src/orchestrator.ts +173 -20
- package/src/qmd-client.test.ts +85 -0
- package/src/qmd-recall-cache.test.ts +16 -0
- package/src/qmd-recall-cache.ts +7 -0
- package/src/qmd.test.ts +54 -0
- package/src/qmd.ts +119 -19
- package/src/recall-planner-llm.test.ts +224 -0
- package/src/recall-planner-llm.ts +289 -0
- package/src/routing/store.ts +4 -8
- package/src/search/factory.ts +3 -0
- package/src/search/lancedb-backend.ts +15 -3
- package/src/search/meilisearch-backend.ts +70 -7
- package/src/search/noop-backend.ts +5 -1
- package/src/search/orama-backend.ts +15 -3
- package/src/search/port.ts +15 -0
- package/src/search/remote-backend.ts +5 -1
- package/src/session-observer-state.ts +1 -1
- package/src/summarizer.ts +3 -3
- package/src/temporal-index.test.ts +18 -0
- package/src/temporal-index.ts +45 -0
- package/src/training-export/cli-date-validation.test.ts +36 -0
- package/src/training-export/date-parse.ts +21 -2
- package/src/transfer/export-sqlite.ts +3 -0
- package/src/types.ts +35 -0
- package/src/utility-learner.ts +1 -0
- package/src/work/storage.ts +23 -0
- package/dist/chunk-2QANQKSQ.js.map +0 -1
- package/dist/chunk-5RPTH6AU.js.map +0 -1
- package/dist/chunk-AJA46VX5.js.map +0 -1
- package/dist/chunk-C4SQJZAF.js.map +0 -1
- package/dist/chunk-CHCA44C3.js.map +0 -1
- package/dist/chunk-CSKLPDN6.js.map +0 -1
- package/dist/chunk-DLJ4IR6M.js.map +0 -1
- package/dist/chunk-EAZGEEG2.js.map +0 -1
- package/dist/chunk-EUML3N6B.js.map +0 -1
- package/dist/chunk-EVZFIAPG.js.map +0 -1
- package/dist/chunk-G3Z3QEF5.js.map +0 -1
- package/dist/chunk-GMAG2HS4.js.map +0 -1
- package/dist/chunk-HENLZHIT.js.map +0 -1
- package/dist/chunk-HINSGUA7.js.map +0 -1
- package/dist/chunk-HJNQQICM.js.map +0 -1
- package/dist/chunk-HPWVAEET.js.map +0 -1
- package/dist/chunk-IOTENEVL.js.map +0 -1
- package/dist/chunk-IP73YCZP.js.map +0 -1
- package/dist/chunk-JHMFYY7L.js.map +0 -1
- package/dist/chunk-JNANKJLN.js.map +0 -1
- package/dist/chunk-KGK2QKWL.js.map +0 -1
- package/dist/chunk-KM2A35EO.js.map +0 -1
- package/dist/chunk-KVEVLBKC.js.map +0 -1
- package/dist/chunk-L227SKTB.js.map +0 -1
- package/dist/chunk-LZ3VEOU5.js.map +0 -1
- package/dist/chunk-NOMEVTUD.js.map +0 -1
- package/dist/chunk-NZPF2SYV.js.map +0 -1
- package/dist/chunk-PCI747N2.js.map +0 -1
- package/dist/chunk-PPPZY2EU.js.map +0 -1
- package/dist/chunk-TH67Q46T.js.map +0 -1
- package/dist/chunk-UWY7GIVS.js.map +0 -1
- package/dist/chunk-VJXSUAO7.js.map +0 -1
- package/dist/chunk-XKIQZXUB.js.map +0 -1
- package/dist/chunk-XPSVGJYA.js.map +0 -1
- package/dist/chunk-XSWKORGM.js.map +0 -1
- package/dist/chunk-YCN4BVDK.js.map +0 -1
- package/dist/chunk-ZDTVJXIP.js.map +0 -1
- /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
- /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-HSVJGWYS.js.map → chunk-2ROPI5OE.js.map} +0 -0
- /package/dist/{chunk-CF3ZF2YU.js.map → chunk-3QSU4NFF.js.map} +0 -0
- /package/dist/{chunk-OI27U2HT.js.map → chunk-5BTCT236.js.map} +0 -0
- /package/dist/{chunk-CO7ZO4TU.js.map → chunk-5VDJMYTF.js.map} +0 -0
- /package/dist/{chunk-YFS5OEKO.js.map → chunk-7MLB4NCL.js.map} +0 -0
- /package/dist/{chunk-557IAFPD.js.map → chunk-APRRL26Q.js.map} +0 -0
- /package/dist/{chunk-QDDHYAKV.js.map → chunk-AZDOWD2L.js.map} +0 -0
- /package/dist/{chunk-MLT75J5S.js.map → chunk-B6SU7YSE.js.map} +0 -0
- /package/dist/{chunk-FXKPZ3H6.js.map → chunk-BPSGLMQ4.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-IK34DVAC.js.map → chunk-CIOMS6DI.js.map} +0 -0
- /package/dist/{chunk-7DZRO2DC.js.map → chunk-DEPRLVLK.js.map} +0 -0
- /package/dist/{chunk-DHGSZ3UD.js.map → chunk-DGNQRNLL.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-ETUPBUHB.js.map → chunk-GDASG7NC.js.map} +0 -0
- /package/dist/{chunk-4HP7HIE3.js.map → chunk-HP5FMB6L.js.map} +0 -0
- /package/dist/{chunk-DOX2CG6Y.js.map → chunk-IEUU7O4F.js.map} +0 -0
- /package/dist/{chunk-WSGF57U2.js.map → chunk-JQDZQ4TB.js.map} +0 -0
- /package/dist/{chunk-W7L6HXUC.js.map → chunk-LXOM6IQU.js.map} +0 -0
- /package/dist/{chunk-6JGNHWCI.js.map → chunk-OBIRVF36.js.map} +0 -0
- /package/dist/{chunk-GUPISBV2.js.map → chunk-PP2JH3GP.js.map} +0 -0
- /package/dist/{chunk-OXJBNGBK.js.map → chunk-PSUB67YB.js.map} +0 -0
- /package/dist/{chunk-KIB7SDIJ.js.map → chunk-Q6YIJGXJ.js.map} +0 -0
- /package/dist/{chunk-ZT3EGNLR.js.map → chunk-QPD426WT.js.map} +0 -0
- /package/dist/{chunk-RLV3PQGH.js.map → chunk-QVO4YOB7.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-IK7DCC5H.js.map → chunk-VMGLYN42.js.map} +0 -0
- /package/dist/{chunk-NSKYFGDL.js.map → chunk-X4QQB7O6.js.map} +0 -0
- /package/dist/{first-start-migration-GYJWIH36.js.map → first-start-migration-FF7YFGRP.js.map} +0 -0
- /package/dist/{tier-stats-SKML2OSF.js.map → tier-stats-3LYQ3VV5.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/evals.ts"],"sourcesContent":["import path from \"node:path\";\nimport { cp, mkdir, readFile, readdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { listJsonFiles, listNamedFiles, readJsonFile } from \"./json-store.js\";\n\nexport type EvalRunStatus = \"running\" | \"completed\" | \"failed\" | \"partial\";\n\nexport interface EvalBenchmarkCase {\n id: string;\n prompt: string;\n expectedSignals?: string[];\n notes?: string;\n}\n\nexport type EvalBenchmarkType = \"standard\" | \"memory-red-team\";\n\nexport interface EvalBenchmarkManifest {\n schemaVersion: 1;\n benchmarkId: string;\n benchmarkType?: EvalBenchmarkType;\n title: string;\n description?: string;\n tags?: string[];\n sourceLinks?: string[];\n attackClass?: string;\n targetSurface?: string;\n cases: EvalBenchmarkCase[];\n}\n\nexport interface EvalRunMetrics {\n recallPrecisionAtK?: number;\n actionOutcomeScore?: number;\n objectiveStateCoverage?: number;\n causalPathRecall?: number;\n trustViolationRate?: number;\n creationRecoveryScore?: number;\n}\n\nexport interface EvalRunSummary {\n schemaVersion: 1;\n runId: string;\n benchmarkId: string;\n status: EvalRunStatus;\n startedAt: string;\n completedAt?: string;\n totalCases: number;\n passedCases: number;\n failedCases: number;\n metrics?: EvalRunMetrics;\n notes?: string;\n gitRef?: string;\n}\n\nexport interface EvalShadowRecallRecord {\n schemaVersion: 1;\n traceId: string;\n recordedAt: string;\n sessionKey: string;\n promptHash: string;\n promptLength: number;\n retrievalQueryHash: string;\n retrievalQueryLength: number;\n recallMode: \"no_recall\" | \"minimal\" | \"full\" | \"graph_mode\";\n recallResultLimit: number;\n source: \"none\" | \"hot_qmd\" | \"hot_embedding\" | \"cold_fallback\" | \"recent_scan\";\n recalledMemoryCount: number;\n injected: boolean;\n contextChars: number;\n memoryIds: string[];\n policyVersion?: string;\n identityInjectionMode?: \"recovery_only\" | \"minimal\" | \"full\" | \"none\";\n identityInjectedChars?: number;\n identityInjectionTruncated?: boolean;\n durationMs: number;\n timings?: Record<string, string>;\n}\n\nexport interface EvalHarnessStatus {\n enabled: boolean;\n shadowModeEnabled: boolean;\n rootDir: string;\n benchmarkDir: string;\n runsDir: string;\n benchmarks: {\n total: number;\n valid: number;\n invalid: number;\n redTeam: number;\n totalCases: number;\n attackClasses: string[];\n tags: string[];\n targetSurfaces: string[];\n sourceLinks: string[];\n };\n runs: {\n total: number;\n invalid: number;\n completed: number;\n failed: number;\n partial: number;\n running: number;\n latestRunId?: string;\n latestBenchmarkId?: string;\n latestCompletedAt?: string;\n };\n shadows: {\n total: number;\n invalid: number;\n latestTraceId?: string;\n latestRecordedAt?: string;\n latestSessionKey?: string;\n };\n baselines: {\n enabled: boolean;\n total: number;\n invalid: number;\n latestSnapshotId?: string;\n latestCreatedAt?: string;\n latestBenchmarkCount?: number;\n };\n latestRun?: EvalRunSummary;\n latestShadow?: EvalShadowRecallRecord;\n latestBaseline?: EvalBaselineSnapshot;\n invalidBenchmarks: Array<{\n path: string;\n error: string;\n }>;\n invalidRuns: Array<{\n path: string;\n error: string;\n }>;\n invalidShadows: Array<{\n path: string;\n error: string;\n }>;\n invalidBaselines: Array<{\n path: string;\n error: string;\n }>;\n}\n\nexport interface EvalBenchmarkDelta {\n benchmarkId: string;\n baseRunId: string;\n candidateRunId: string;\n basePassRate: number;\n candidatePassRate: number;\n passRateDelta: number;\n metricDeltas: Partial<Record<keyof EvalRunMetrics, number>>;\n regressions: string[];\n improvements: string[];\n}\n\nexport interface EvalCiGateReport {\n passed: boolean;\n baseRootDir: string;\n candidateRootDir: string;\n comparedBenchmarks: number;\n missingCandidateBenchmarks: string[];\n invalidArtifacts: {\n base: {\n benchmarks: number;\n runs: number;\n shadows: number;\n };\n candidate: {\n benchmarks: number;\n runs: number;\n shadows: number;\n };\n };\n regressions: string[];\n improvements: string[];\n deltas: EvalBenchmarkDelta[];\n}\n\nexport interface EvalBaselineDeltaReport {\n passed: boolean;\n baselineSnapshotId: string;\n baselineCreatedAt: string;\n baselineSourceRootDir: string;\n candidateRootDir: string;\n comparedBenchmarks: number;\n missingCandidateBenchmarks: string[];\n invalidArtifacts: {\n candidate: {\n benchmarks: number;\n runs: number;\n shadows: number;\n baselines: number;\n };\n };\n regressions: string[];\n improvements: string[];\n deltas: EvalBenchmarkDelta[];\n markdownReport: string;\n}\n\nexport interface EvalStoredBaselineCiGateReport extends EvalBaselineDeltaReport {\n baseRootDir: string;\n baselineResolvedFrom: \"base\" | \"candidate\";\n}\n\nexport interface EvalBaselineSnapshotBenchmark {\n benchmarkId: string;\n runId: string;\n completedAt?: string;\n gitRef?: string;\n passRate: number;\n metrics?: EvalRunMetrics;\n}\n\nexport interface EvalBaselineSnapshot {\n schemaVersion: 1;\n snapshotId: string;\n createdAt: string;\n sourceRootDir: string;\n benchmarkCount: number;\n benchmarks: EvalBaselineSnapshotBenchmark[];\n notes?: string;\n gitRef?: string;\n}\n\nexport interface EvalBenchmarkPackSummary {\n sourcePath: string;\n manifestPath: string;\n benchmarkId: string;\n benchmarkType: EvalBenchmarkType;\n title: string;\n attackClass?: string;\n targetSurface?: string;\n totalCases: number;\n tags: string[];\n sourceLinks: string[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction assertString(value: unknown, field: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`${field} must be a non-empty string`);\n }\n return value.trim();\n}\n\nfunction optionalStringArray(value: unknown, field: string): string[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) {\n throw new Error(`${field} must be an array of strings`);\n }\n const out = value\n .filter((item): item is string => typeof item === \"string\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n if (out.length !== value.length) {\n throw new Error(`${field} must be an array of non-empty strings`);\n }\n return out;\n}\n\nexport function resolveEvalStoreDir(memoryDir: string, overrideDir?: string): string {\n if (typeof overrideDir === \"string\" && overrideDir.trim().length > 0) {\n return overrideDir.trim();\n }\n return path.join(memoryDir, \"state\", \"evals\");\n}\n\nfunction assertSafePathSegment(value: string, field: string): string {\n if (value === \".\" || value === \"..\" || value.includes(\"/\") || value.includes(\"\\\\\")) {\n throw new Error(`${field} must be a safe path segment`);\n }\n return value;\n}\n\nfunction assertSafeBenchmarkId(benchmarkId: string): string {\n return assertSafePathSegment(benchmarkId, \"benchmarkId\");\n}\n\nconst ISO_UTC_TIMESTAMP_RE = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;\n\nfunction assertIsoTimestamp(value: unknown, field: string): string {\n const timestamp = assertString(value, field);\n if (!ISO_UTC_TIMESTAMP_RE.test(timestamp)) {\n throw new Error(`${field} must be a valid ISO timestamp`);\n }\n const parsed = Date.parse(timestamp);\n if (!Number.isFinite(parsed)) {\n throw new Error(`${field} must be a valid ISO timestamp`);\n }\n const normalized = new Date(parsed).toISOString();\n if (normalized !== timestamp) {\n throw new Error(`${field} must be a valid ISO timestamp`);\n }\n return normalized;\n}\n\nfunction assertNonNegativeInteger(value: unknown, field: string): number {\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed) || parsed < 0) {\n throw new Error(`${field} must be a non-negative integer`);\n }\n return parsed;\n}\n\nfunction assertPathWithin(rootDir: string, targetPath: string, field: string): void {\n const resolvedRoot = path.resolve(rootDir);\n const resolvedTarget = path.resolve(targetPath);\n const relative = path.relative(resolvedRoot, resolvedTarget);\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) {\n return;\n }\n throw new Error(`${field} must stay within ${rootDir}`);\n}\n\nexport function validateEvalBenchmarkManifest(\n raw: unknown,\n options?: { memoryRedTeamBenchEnabled?: boolean },\n): EvalBenchmarkManifest {\n if (!isRecord(raw)) throw new Error(\"benchmark manifest must be an object\");\n if (raw.schemaVersion !== 1) throw new Error(\"schemaVersion must be 1\");\n if (!Array.isArray(raw.cases)) throw new Error(\"cases must be an array\");\n const benchmarkTypeRaw =\n typeof raw.benchmarkType === \"string\" && raw.benchmarkType.trim().length > 0\n ? raw.benchmarkType.trim()\n : \"standard\";\n if (![\"standard\", \"memory-red-team\"].includes(benchmarkTypeRaw)) {\n throw new Error(\"benchmarkType must be one of standard|memory-red-team\");\n }\n\n const cases = raw.cases.map((item, index) => {\n if (!isRecord(item)) throw new Error(`cases[${index}] must be an object`);\n return {\n id: assertString(item.id, `cases[${index}].id`),\n prompt: assertString(item.prompt, `cases[${index}].prompt`),\n expectedSignals: optionalStringArray(item.expectedSignals, `cases[${index}].expectedSignals`),\n notes: typeof item.notes === \"string\" && item.notes.trim().length > 0 ? item.notes.trim() : undefined,\n } satisfies EvalBenchmarkCase;\n });\n\n const benchmarkType = benchmarkTypeRaw as EvalBenchmarkType;\n if (benchmarkType === \"memory-red-team\" && options?.memoryRedTeamBenchEnabled !== true) {\n throw new Error(\"memory-red-team benchmark packs require memoryRedTeamBenchEnabled\");\n }\n const attackClass =\n typeof raw.attackClass === \"string\" && raw.attackClass.trim().length > 0\n ? raw.attackClass.trim()\n : undefined;\n const targetSurface =\n typeof raw.targetSurface === \"string\" && raw.targetSurface.trim().length > 0\n ? raw.targetSurface.trim()\n : undefined;\n if (benchmarkType === \"memory-red-team\" && attackClass === undefined) {\n throw new Error(\"attackClass must be a non-empty string\");\n }\n if (benchmarkType === \"memory-red-team\" && targetSurface === undefined) {\n throw new Error(\"targetSurface must be a non-empty string\");\n }\n\n return {\n schemaVersion: 1,\n benchmarkId: assertString(raw.benchmarkId, \"benchmarkId\"),\n benchmarkType,\n title: assertString(raw.title, \"title\"),\n description:\n typeof raw.description === \"string\" && raw.description.trim().length > 0\n ? raw.description.trim()\n : undefined,\n tags: optionalStringArray(raw.tags, \"tags\"),\n sourceLinks: optionalStringArray(raw.sourceLinks, \"sourceLinks\"),\n attackClass,\n targetSurface,\n cases,\n };\n}\n\nexport function validateEvalRunSummary(raw: unknown): EvalRunSummary {\n if (!isRecord(raw)) throw new Error(\"eval run summary must be an object\");\n if (raw.schemaVersion !== 1) throw new Error(\"schemaVersion must be 1\");\n const status = assertString(raw.status, \"status\");\n if (![\"running\", \"completed\", \"failed\", \"partial\"].includes(status)) {\n throw new Error(\"status must be one of running|completed|failed|partial\");\n }\n\n const totalCases = assertNonNegativeInteger(raw.totalCases, \"totalCases\");\n const passedCases = assertNonNegativeInteger(raw.passedCases, \"passedCases\");\n const failedCases = assertNonNegativeInteger(raw.failedCases, \"failedCases\");\n if (passedCases + failedCases > totalCases) {\n throw new Error(\"passedCases + failedCases must be less than or equal to totalCases\");\n }\n\n const metrics = parseOptionalEvalRunMetrics(raw.metrics);\n const completedAt =\n typeof raw.completedAt === \"string\" && raw.completedAt.trim().length > 0\n ? assertIsoTimestamp(raw.completedAt, \"completedAt\")\n : undefined;\n\n return {\n schemaVersion: 1,\n runId: assertString(raw.runId, \"runId\"),\n benchmarkId: assertString(raw.benchmarkId, \"benchmarkId\"),\n status: status as EvalRunStatus,\n startedAt: assertIsoTimestamp(raw.startedAt, \"startedAt\"),\n completedAt,\n totalCases,\n passedCases,\n failedCases,\n metrics,\n notes: typeof raw.notes === \"string\" && raw.notes.trim().length > 0 ? raw.notes.trim() : undefined,\n gitRef: typeof raw.gitRef === \"string\" && raw.gitRef.trim().length > 0 ? raw.gitRef.trim() : undefined,\n };\n}\n\nexport function validateEvalBaselineSnapshot(raw: unknown): EvalBaselineSnapshot {\n if (!isRecord(raw)) throw new Error(\"eval baseline snapshot must be an object\");\n if (raw.schemaVersion !== 1) throw new Error(\"schemaVersion must be 1\");\n if (!Array.isArray(raw.benchmarks)) throw new Error(\"benchmarks must be an array\");\n\n const benchmarks = raw.benchmarks.map((item, index) => {\n if (!isRecord(item)) throw new Error(`benchmarks[${index}] must be an object`);\n const passRate = Number(item.passRate);\n if (!Number.isFinite(passRate) || passRate < 0 || passRate > 1) {\n throw new Error(`benchmarks[${index}].passRate must be a number between 0 and 1`);\n }\n\n const metrics = parseOptionalEvalRunMetrics(item.metrics);\n\n return {\n benchmarkId: assertString(item.benchmarkId, `benchmarks[${index}].benchmarkId`),\n runId: assertString(item.runId, `benchmarks[${index}].runId`),\n completedAt:\n typeof item.completedAt === \"string\" && item.completedAt.trim().length > 0\n ? assertIsoTimestamp(item.completedAt, `benchmarks[${index}].completedAt`)\n : undefined,\n gitRef:\n typeof item.gitRef === \"string\" && item.gitRef.trim().length > 0\n ? item.gitRef.trim()\n : undefined,\n passRate,\n metrics,\n } satisfies EvalBaselineSnapshotBenchmark;\n });\n\n const benchmarkCount = Number(raw.benchmarkCount);\n if (!Number.isFinite(benchmarkCount) || benchmarkCount < 0) {\n throw new Error(\"benchmarkCount must be a non-negative number\");\n }\n if (benchmarkCount !== benchmarks.length) {\n throw new Error(\"benchmarkCount must match benchmarks.length\");\n }\n\n return {\n schemaVersion: 1,\n snapshotId: assertString(raw.snapshotId, \"snapshotId\"),\n createdAt: assertIsoTimestamp(raw.createdAt, \"createdAt\"),\n sourceRootDir: assertString(raw.sourceRootDir, \"sourceRootDir\"),\n benchmarkCount,\n benchmarks,\n notes: typeof raw.notes === \"string\" && raw.notes.trim().length > 0 ? raw.notes.trim() : undefined,\n gitRef: typeof raw.gitRef === \"string\" && raw.gitRef.trim().length > 0 ? raw.gitRef.trim() : undefined,\n };\n}\n\nfunction parseOptionalEvalRunMetrics(raw: unknown): EvalRunMetrics | undefined {\n if (!isRecord(raw)) return undefined;\n return {\n recallPrecisionAtK: typeof raw.recallPrecisionAtK === \"number\" ? raw.recallPrecisionAtK : undefined,\n actionOutcomeScore: typeof raw.actionOutcomeScore === \"number\" ? raw.actionOutcomeScore : undefined,\n objectiveStateCoverage: typeof raw.objectiveStateCoverage === \"number\" ? raw.objectiveStateCoverage : undefined,\n causalPathRecall: typeof raw.causalPathRecall === \"number\" ? raw.causalPathRecall : undefined,\n trustViolationRate: typeof raw.trustViolationRate === \"number\" ? raw.trustViolationRate : undefined,\n creationRecoveryScore: typeof raw.creationRecoveryScore === \"number\" ? raw.creationRecoveryScore : undefined,\n } satisfies EvalRunMetrics;\n}\n\nexport function validateEvalShadowRecallRecord(raw: unknown): EvalShadowRecallRecord {\n if (!isRecord(raw)) throw new Error(\"eval shadow recall record must be an object\");\n if (raw.schemaVersion !== 1) throw new Error(\"schemaVersion must be 1\");\n\n const recallMode = assertString(raw.recallMode, \"recallMode\");\n if (![\"no_recall\", \"minimal\", \"full\", \"graph_mode\"].includes(recallMode)) {\n throw new Error(\"recallMode must be one of no_recall|minimal|full|graph_mode\");\n }\n\n const source = assertString(raw.source, \"source\");\n if (![\"none\", \"hot_qmd\", \"hot_embedding\", \"cold_fallback\", \"recent_scan\"].includes(source)) {\n throw new Error(\"source must be one of none|hot_qmd|hot_embedding|cold_fallback|recent_scan\");\n }\n\n const promptLength = Number(raw.promptLength);\n const retrievalQueryLength = Number(raw.retrievalQueryLength);\n const recallResultLimit = Number(raw.recallResultLimit);\n const recalledMemoryCount = Number(raw.recalledMemoryCount);\n const contextChars = Number(raw.contextChars);\n const durationMs = Number(raw.durationMs);\n\n for (const [field, value] of [\n [\"promptLength\", promptLength],\n [\"retrievalQueryLength\", retrievalQueryLength],\n [\"recallResultLimit\", recallResultLimit],\n [\"recalledMemoryCount\", recalledMemoryCount],\n [\"contextChars\", contextChars],\n [\"durationMs\", durationMs],\n ] as const) {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`${field} must be a non-negative number`);\n }\n }\n\n const memoryIds = optionalStringArray(raw.memoryIds, \"memoryIds\") ?? [];\n if (typeof raw.injected !== \"boolean\") throw new Error(\"injected must be a boolean\");\n\n let timings: Record<string, string> | undefined;\n if (raw.timings !== undefined) {\n if (!isRecord(raw.timings)) throw new Error(\"timings must be an object of strings\");\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(raw.timings)) {\n if (typeof value !== \"string\") throw new Error(\"timings must be an object of strings\");\n out[key] = value;\n }\n timings = out;\n }\n\n const identityInjectionModeRaw =\n typeof raw.identityInjectionMode === \"string\" && raw.identityInjectionMode.trim().length > 0\n ? raw.identityInjectionMode.trim()\n : undefined;\n if (\n identityInjectionModeRaw !== undefined &&\n ![\"recovery_only\", \"minimal\", \"full\", \"none\"].includes(identityInjectionModeRaw)\n ) {\n throw new Error(\"identityInjectionMode must be one of recovery_only|minimal|full|none\");\n }\n\n return {\n schemaVersion: 1,\n traceId: assertSafePathSegment(assertString(raw.traceId, \"traceId\"), \"traceId\"),\n recordedAt: assertIsoTimestamp(raw.recordedAt, \"recordedAt\"),\n sessionKey: assertString(raw.sessionKey, \"sessionKey\"),\n promptHash: assertString(raw.promptHash, \"promptHash\"),\n promptLength,\n retrievalQueryHash: assertString(raw.retrievalQueryHash, \"retrievalQueryHash\"),\n retrievalQueryLength,\n recallMode: recallMode as EvalShadowRecallRecord[\"recallMode\"],\n recallResultLimit,\n source: source as EvalShadowRecallRecord[\"source\"],\n recalledMemoryCount,\n injected: raw.injected,\n contextChars,\n memoryIds,\n policyVersion:\n typeof raw.policyVersion === \"string\" && raw.policyVersion.trim().length > 0\n ? raw.policyVersion.trim()\n : undefined,\n identityInjectionMode: identityInjectionModeRaw as EvalShadowRecallRecord[\"identityInjectionMode\"],\n identityInjectedChars:\n typeof raw.identityInjectedChars === \"number\" && Number.isFinite(raw.identityInjectedChars)\n ? raw.identityInjectedChars\n : undefined,\n identityInjectionTruncated:\n typeof raw.identityInjectionTruncated === \"boolean\" ? raw.identityInjectionTruncated : undefined,\n durationMs,\n timings,\n };\n}\n\ninterface EvalStoreSnapshot {\n status: EvalHarnessStatus;\n manifests: EvalBenchmarkManifest[];\n runs: EvalRunSummary[];\n shadows: EvalShadowRecallRecord[];\n baselines: EvalBaselineSnapshot[];\n}\n\ninterface EvalStoreSnapshotOptions {\n rootDir: string;\n enabled: boolean;\n shadowModeEnabled: boolean;\n baselineSnapshotsEnabled?: boolean;\n memoryRedTeamBenchEnabled?: boolean;\n}\n\nconst LOWER_IS_BETTER_METRICS = new Set<keyof EvalRunMetrics>([\"trustViolationRate\"]);\n\nfunction computePassRate(run: EvalRunSummary): number {\n return run.totalCases > 0 ? run.passedCases / run.totalCases : 0;\n}\n\nfunction latestCompletedRunsByBenchmark(runs: EvalRunSummary[]): Map<string, EvalRunSummary> {\n const sorted = [...runs]\n .filter((run) => run.status === \"completed\")\n .sort((a, b) => {\n const aTime = Date.parse(a.completedAt ?? a.startedAt);\n const bTime = Date.parse(b.completedAt ?? b.startedAt);\n return (Number.isNaN(bTime) ? 0 : bTime) - (Number.isNaN(aTime) ? 0 : aTime);\n });\n const out = new Map<string, EvalRunSummary>();\n for (const run of sorted) {\n if (!out.has(run.benchmarkId)) {\n out.set(run.benchmarkId, run);\n }\n }\n return out;\n}\n\nfunction compareMetricDeltas(\n baseMetrics: EvalRunMetrics | undefined,\n candidateMetrics: EvalRunMetrics | undefined,\n): {\n deltas: Partial<Record<keyof EvalRunMetrics, number>>;\n regressions: string[];\n improvements: string[];\n} {\n const deltas: Partial<Record<keyof EvalRunMetrics, number>> = {};\n const regressions: string[] = [];\n const improvements: string[] = [];\n if (!baseMetrics || !candidateMetrics) {\n return { deltas, regressions, improvements };\n }\n\n for (const metric of Object.keys(baseMetrics) as Array<keyof EvalRunMetrics>) {\n const baseValue = baseMetrics[metric];\n const candidateValue = candidateMetrics[metric];\n if (typeof baseValue !== \"number\" || typeof candidateValue !== \"number\") continue;\n const delta = candidateValue - baseValue;\n deltas[metric] = delta;\n if (delta === 0) continue;\n const lowerIsBetter = LOWER_IS_BETTER_METRICS.has(metric);\n const improved = lowerIsBetter ? delta < 0 : delta > 0;\n const summary = `${metric} ${baseValue} -> ${candidateValue}`;\n if (improved) {\n improvements.push(summary);\n } else {\n regressions.push(summary);\n }\n }\n\n return { deltas, regressions, improvements };\n}\n\nfunction formatEvalBaselineDeltaMarkdown(report: EvalBaselineDeltaReport): string {\n const lines = [\n \"# Eval Baseline Delta Report\",\n \"\",\n `- Passed: ${report.passed ? \"yes\" : \"no\"}`,\n `- Baseline snapshot: ${report.baselineSnapshotId}`,\n `- Baseline created: ${report.baselineCreatedAt}`,\n `- Baseline source root: ${report.baselineSourceRootDir}`,\n `- Candidate root: ${report.candidateRootDir}`,\n `- Benchmarks compared: ${report.comparedBenchmarks}`,\n ];\n\n if (report.missingCandidateBenchmarks.length > 0) {\n lines.push(`- Missing candidate benchmarks: ${report.missingCandidateBenchmarks.join(\", \")}`);\n }\n\n lines.push(\n `- Invalid candidate artifacts: benchmarks=${report.invalidArtifacts.candidate.benchmarks}, runs=${report.invalidArtifacts.candidate.runs}, shadows=${report.invalidArtifacts.candidate.shadows}, baselines=${report.invalidArtifacts.candidate.baselines}`,\n \"\",\n \"## Regressions\",\n );\n if (report.regressions.length === 0) {\n lines.push(\"- none\");\n } else {\n for (const regression of report.regressions) lines.push(`- ${regression}`);\n }\n\n lines.push(\"\", \"## Improvements\");\n if (report.improvements.length === 0) {\n lines.push(\"- none\");\n } else {\n for (const improvement of report.improvements) lines.push(`- ${improvement}`);\n }\n\n lines.push(\"\", \"## Benchmark Deltas\");\n if (report.deltas.length === 0) {\n lines.push(\"- none\");\n } else {\n for (const delta of report.deltas) {\n lines.push(\n `- ${delta.benchmarkId}: passRate ${delta.basePassRate} -> ${delta.candidatePassRate} (delta ${delta.passRateDelta})`,\n );\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nasync function collectEvalStoreSnapshot(options: EvalStoreSnapshotOptions): Promise<EvalStoreSnapshot> {\n const rootDir = options.rootDir;\n const benchmarkDir = path.join(rootDir, \"benchmarks\");\n const runsDir = path.join(rootDir, \"runs\");\n const shadowDir = path.join(rootDir, \"shadow\");\n const baselineDir = path.join(rootDir, \"baselines\");\n const benchmarkFiles = await listNamedFiles(benchmarkDir, \"manifest.json\");\n const runFiles = await listJsonFiles(runsDir);\n const shadowFiles = await listJsonFiles(shadowDir);\n const baselineFiles = await listJsonFiles(baselineDir);\n\n const invalidBenchmarks: Array<{ path: string; error: string }> = [];\n const invalidRuns: Array<{ path: string; error: string }> = [];\n const invalidShadows: Array<{ path: string; error: string }> = [];\n const invalidBaselines: Array<{ path: string; error: string }> = [];\n const manifests: EvalBenchmarkManifest[] = [];\n\n for (const filePath of benchmarkFiles) {\n try {\n manifests.push(\n validateEvalBenchmarkManifest(await readJsonFile(filePath), {\n memoryRedTeamBenchEnabled: options.memoryRedTeamBenchEnabled,\n }),\n );\n } catch (error) {\n invalidBenchmarks.push({\n path: filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n const runs: EvalRunSummary[] = [];\n for (const filePath of runFiles) {\n try {\n runs.push(validateEvalRunSummary(await readJsonFile(filePath)));\n } catch (error) {\n invalidRuns.push({\n path: filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n const shadows: EvalShadowRecallRecord[] = [];\n for (const filePath of shadowFiles) {\n try {\n shadows.push(validateEvalShadowRecallRecord(await readJsonFile(filePath)));\n } catch (error) {\n invalidShadows.push({\n path: filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n const baselines: EvalBaselineSnapshot[] = [];\n for (const filePath of baselineFiles) {\n try {\n baselines.push(validateEvalBaselineSnapshot(await readJsonFile(filePath)));\n } catch (error) {\n invalidBaselines.push({\n path: filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n runs.sort((a, b) => {\n const aTime = Date.parse(a.completedAt ?? a.startedAt);\n const bTime = Date.parse(b.completedAt ?? b.startedAt);\n return (Number.isNaN(bTime) ? 0 : bTime) - (Number.isNaN(aTime) ? 0 : aTime);\n });\n shadows.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));\n baselines.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n\n const tags = new Set<string>();\n const attackClasses = new Set<string>();\n const sourceLinks = new Set<string>();\n const targetSurfaces = new Set<string>();\n let totalCases = 0;\n let redTeam = 0;\n for (const manifest of manifests) {\n totalCases += manifest.cases.length;\n if (manifest.benchmarkType === \"memory-red-team\") {\n redTeam += 1;\n if (manifest.attackClass) attackClasses.add(manifest.attackClass);\n if (manifest.targetSurface) targetSurfaces.add(manifest.targetSurface);\n }\n for (const tag of manifest.tags ?? []) tags.add(tag);\n for (const link of manifest.sourceLinks ?? []) sourceLinks.add(link);\n }\n\n return {\n status: {\n enabled: options.enabled,\n shadowModeEnabled: options.shadowModeEnabled,\n rootDir,\n benchmarkDir,\n runsDir,\n benchmarks: {\n total: benchmarkFiles.length,\n valid: manifests.length,\n invalid: invalidBenchmarks.length,\n redTeam,\n totalCases,\n attackClasses: [...attackClasses].sort(),\n tags: [...tags].sort(),\n targetSurfaces: [...targetSurfaces].sort(),\n sourceLinks: [...sourceLinks].sort(),\n },\n runs: {\n total: runFiles.length,\n invalid: invalidRuns.length,\n completed: runs.filter((run) => run.status === \"completed\").length,\n failed: runs.filter((run) => run.status === \"failed\").length,\n partial: runs.filter((run) => run.status === \"partial\").length,\n running: runs.filter((run) => run.status === \"running\").length,\n latestRunId: runs[0]?.runId,\n latestBenchmarkId: runs[0]?.benchmarkId,\n latestCompletedAt: runs[0]?.completedAt,\n },\n shadows: {\n total: shadowFiles.length,\n invalid: invalidShadows.length,\n latestTraceId: shadows[0]?.traceId,\n latestRecordedAt: shadows[0]?.recordedAt,\n latestSessionKey: shadows[0]?.sessionKey,\n },\n baselines: {\n enabled: options.baselineSnapshotsEnabled === true,\n total: baselineFiles.length,\n invalid: invalidBaselines.length,\n latestSnapshotId: baselines[0]?.snapshotId,\n latestCreatedAt: baselines[0]?.createdAt,\n latestBenchmarkCount: baselines[0]?.benchmarkCount,\n },\n latestRun: runs[0],\n latestShadow: shadows[0],\n latestBaseline: baselines[0],\n invalidBenchmarks,\n invalidRuns,\n invalidShadows,\n invalidBaselines,\n },\n manifests,\n runs,\n shadows,\n baselines,\n };\n}\n\nasync function resolveBenchmarkManifestPath(sourcePath: string): Promise<{ sourceKind: \"file\" | \"directory\"; manifestPath: string }> {\n const info = await stat(sourcePath);\n if (info.isDirectory()) {\n return {\n sourceKind: \"directory\",\n manifestPath: path.join(sourcePath, \"manifest.json\"),\n };\n }\n if (info.isFile()) {\n return {\n sourceKind: \"file\",\n manifestPath: sourcePath,\n };\n }\n throw new Error(\"benchmark pack source must be a file or directory\");\n}\n\nexport async function validateEvalBenchmarkPack(\n sourcePath: string,\n options?: { memoryRedTeamBenchEnabled?: boolean },\n): Promise<EvalBenchmarkPackSummary> {\n const trimmedSourcePath = sourcePath.trim();\n if (trimmedSourcePath.length === 0) {\n throw new Error(\"benchmark pack path must be a non-empty string\");\n }\n const { manifestPath } = await resolveBenchmarkManifestPath(trimmedSourcePath);\n const manifest = validateEvalBenchmarkManifest(await readJsonFile(manifestPath), {\n memoryRedTeamBenchEnabled: options?.memoryRedTeamBenchEnabled,\n });\n return {\n sourcePath: trimmedSourcePath,\n manifestPath,\n benchmarkId: assertSafeBenchmarkId(manifest.benchmarkId),\n benchmarkType: manifest.benchmarkType ?? \"standard\",\n title: manifest.title,\n attackClass: manifest.attackClass,\n targetSurface: manifest.targetSurface,\n totalCases: manifest.cases.length,\n tags: [...(manifest.tags ?? [])],\n sourceLinks: [...(manifest.sourceLinks ?? [])],\n };\n}\n\nexport async function importEvalBenchmarkPack(options: {\n sourcePath: string;\n memoryDir: string;\n evalStoreDir?: string;\n force?: boolean;\n memoryRedTeamBenchEnabled?: boolean;\n}): Promise<EvalBenchmarkPackSummary & { targetDir: string; overwritten: boolean }> {\n const summary = await validateEvalBenchmarkPack(options.sourcePath, {\n memoryRedTeamBenchEnabled: options.memoryRedTeamBenchEnabled,\n });\n const rootDir = resolveEvalStoreDir(options.memoryDir, options.evalStoreDir);\n const benchmarkDir = path.join(rootDir, \"benchmarks\");\n const targetDir = path.join(benchmarkDir, summary.benchmarkId);\n const { sourceKind, manifestPath } = await resolveBenchmarkManifestPath(summary.sourcePath);\n\n let overwritten = false;\n try {\n await stat(targetDir);\n if (options.force !== true) {\n throw new Error(`benchmark pack already exists at ${targetDir}; rerun with force to replace it`);\n }\n overwritten = true;\n await rm(targetDir, { recursive: true, force: true });\n } catch (error) {\n if (!(error instanceof Error) || !(\"code\" in error) || (error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n\n await mkdir(benchmarkDir, { recursive: true });\n if (sourceKind === \"directory\") {\n await cp(summary.sourcePath, targetDir, { recursive: true });\n } else {\n await mkdir(targetDir, { recursive: true });\n await cp(manifestPath, path.join(targetDir, \"manifest.json\"));\n }\n\n return {\n ...summary,\n targetDir,\n overwritten,\n };\n}\n\nexport async function recordEvalShadowRecall(options: {\n memoryDir: string;\n evalStoreDir?: string;\n record: EvalShadowRecallRecord;\n}): Promise<string> {\n const rootDir = resolveEvalStoreDir(options.memoryDir, options.evalStoreDir);\n const validated = validateEvalShadowRecallRecord(options.record);\n const day = validated.recordedAt.slice(0, 10);\n const shadowRoot = path.join(rootDir, \"shadow\");\n const shadowDir = path.join(shadowRoot, day);\n const targetPath = path.join(shadowDir, `${validated.traceId}.json`);\n assertPathWithin(shadowRoot, targetPath, \"shadow recall record path\");\n await mkdir(shadowDir, { recursive: true });\n await writeFile(targetPath, JSON.stringify(validated, null, 2), \"utf-8\");\n return targetPath;\n}\n\nexport async function getEvalHarnessStatus(options: {\n memoryDir: string;\n evalStoreDir?: string;\n enabled: boolean;\n shadowModeEnabled: boolean;\n baselineSnapshotsEnabled?: boolean;\n memoryRedTeamBenchEnabled?: boolean;\n}): Promise<EvalHarnessStatus> {\n return (\n await collectEvalStoreSnapshot({\n rootDir: resolveEvalStoreDir(options.memoryDir, options.evalStoreDir),\n enabled: options.enabled,\n shadowModeEnabled: options.shadowModeEnabled,\n baselineSnapshotsEnabled: options.baselineSnapshotsEnabled,\n memoryRedTeamBenchEnabled: options.memoryRedTeamBenchEnabled,\n })\n ).status;\n}\n\nexport async function createEvalBaselineSnapshot(options: {\n memoryDir: string;\n evalStoreDir?: string;\n baselineSnapshotsEnabled: boolean;\n snapshotId: string;\n createdAt?: string;\n notes?: string;\n gitRef?: string;\n}): Promise<{ targetPath: string; snapshot: EvalBaselineSnapshot }> {\n if (options.baselineSnapshotsEnabled !== true) {\n throw new Error(\"benchmark baseline snapshots are disabled\");\n }\n\n const snapshotId = assertSafePathSegment(assertString(options.snapshotId, \"snapshotId\"), \"snapshotId\");\n const rootDir = resolveEvalStoreDir(options.memoryDir, options.evalStoreDir);\n const store = await collectEvalStoreSnapshot({\n rootDir,\n enabled: true,\n shadowModeEnabled: true,\n baselineSnapshotsEnabled: true,\n memoryRedTeamBenchEnabled: true,\n });\n const latestRuns = latestCompletedRunsByBenchmark(store.runs);\n const benchmarks = [...latestRuns.values()]\n .sort((a, b) => a.benchmarkId.localeCompare(b.benchmarkId))\n .map((run) => ({\n benchmarkId: run.benchmarkId,\n runId: run.runId,\n completedAt: run.completedAt,\n gitRef: run.gitRef,\n passRate: computePassRate(run),\n metrics: run.metrics,\n } satisfies EvalBaselineSnapshotBenchmark));\n\n const snapshot = validateEvalBaselineSnapshot({\n schemaVersion: 1,\n snapshotId,\n createdAt: options.createdAt ?? new Date().toISOString(),\n sourceRootDir: rootDir,\n benchmarkCount: benchmarks.length,\n benchmarks,\n notes: options.notes,\n gitRef: options.gitRef,\n });\n\n const targetPath = path.join(rootDir, \"baselines\", `${snapshot.snapshotId}.json`);\n await mkdir(path.dirname(targetPath), { recursive: true });\n await writeFile(targetPath, JSON.stringify(snapshot, null, 2), \"utf-8\");\n return { targetPath, snapshot };\n}\n\nexport async function runEvalBaselineDeltaReport(options: {\n memoryDir: string;\n evalStoreDir?: string;\n benchmarkDeltaReporterEnabled: boolean;\n snapshotId: string;\n}): Promise<EvalBaselineDeltaReport> {\n if (options.benchmarkDeltaReporterEnabled !== true) {\n throw new Error(\"benchmark delta reporter is disabled\");\n }\n\n const snapshotId = assertSafePathSegment(assertString(options.snapshotId, \"snapshotId\"), \"snapshotId\");\n const candidateRootDir = resolveEvalStoreDir(options.memoryDir, options.evalStoreDir);\n const candidateSnapshot = await collectEvalStoreSnapshot({\n rootDir: candidateRootDir,\n enabled: true,\n shadowModeEnabled: true,\n baselineSnapshotsEnabled: true,\n memoryRedTeamBenchEnabled: true,\n });\n const baselineSnapshot = candidateSnapshot.baselines.find((snapshot) => snapshot.snapshotId === snapshotId);\n if (!baselineSnapshot) {\n throw new Error(`benchmark baseline snapshot not found: ${snapshotId}`);\n }\n\n return buildEvalBaselineDeltaReport({\n baselineSnapshot,\n candidateSnapshot,\n });\n}\n\nexport async function runEvalStoredBaselineCiGate(options: {\n baseMemoryDir?: string;\n baseEvalStoreDir: string;\n candidateMemoryDir?: string;\n candidateEvalStoreDir: string;\n snapshotId: string;\n}): Promise<EvalStoredBaselineCiGateReport> {\n const snapshotId = assertSafePathSegment(assertString(options.snapshotId, \"snapshotId\"), \"snapshotId\");\n const baseRootDir = resolveEvalStoreDir(options.baseMemoryDir ?? options.baseEvalStoreDir, options.baseEvalStoreDir);\n const candidateRootDir = resolveEvalStoreDir(\n options.candidateMemoryDir ?? options.candidateEvalStoreDir,\n options.candidateEvalStoreDir,\n );\n const [baseSnapshot, candidateSnapshot] = await Promise.all([\n collectEvalStoreSnapshot({\n rootDir: baseRootDir,\n enabled: true,\n shadowModeEnabled: true,\n baselineSnapshotsEnabled: true,\n memoryRedTeamBenchEnabled: true,\n }),\n collectEvalStoreSnapshot({\n rootDir: candidateRootDir,\n enabled: true,\n shadowModeEnabled: true,\n baselineSnapshotsEnabled: true,\n memoryRedTeamBenchEnabled: true,\n }),\n ]);\n const baselineSnapshot =\n baseSnapshot.baselines.find((snapshot) => snapshot.snapshotId === snapshotId) ??\n candidateSnapshot.baselines.find((snapshot) => snapshot.snapshotId === snapshotId);\n if (!baselineSnapshot) {\n throw new Error(`benchmark baseline snapshot not found: ${snapshotId}`);\n }\n\n return {\n baseRootDir,\n baselineResolvedFrom: baseSnapshot.baselines.some((snapshot) => snapshot.snapshotId === snapshotId) ? \"base\" : \"candidate\",\n ...buildEvalBaselineDeltaReport({\n baselineSnapshot,\n candidateSnapshot,\n }),\n };\n}\n\nfunction buildEvalBaselineDeltaReport(options: {\n baselineSnapshot: EvalBaselineSnapshot;\n candidateSnapshot: EvalStoreSnapshot;\n}): EvalBaselineDeltaReport {\n const { baselineSnapshot, candidateSnapshot } = options;\n\n const regressions: string[] = [];\n const improvements: string[] = [];\n\n if (candidateSnapshot.status.invalidBenchmarks.length > 0) {\n regressions.push(`candidate store has ${candidateSnapshot.status.invalidBenchmarks.length} invalid benchmark manifest(s)`);\n }\n if (candidateSnapshot.status.invalidRuns.length > 0) {\n regressions.push(`candidate store has ${candidateSnapshot.status.invalidRuns.length} invalid run summary file(s)`);\n }\n if (candidateSnapshot.status.invalidShadows.length > 0) {\n regressions.push(`candidate store has ${candidateSnapshot.status.invalidShadows.length} invalid shadow record(s)`);\n }\n if (candidateSnapshot.status.invalidBaselines.length > 0) {\n regressions.push(`candidate store has ${candidateSnapshot.status.invalidBaselines.length} invalid baseline snapshot file(s)`);\n }\n\n const candidateRuns = latestCompletedRunsByBenchmark(candidateSnapshot.runs);\n const baselineBenchmarks = new Map(\n baselineSnapshot.benchmarks.map((benchmark) => [benchmark.benchmarkId, benchmark] as const),\n );\n const missingCandidateBenchmarks = [...baselineBenchmarks.keys()]\n .filter((benchmarkId) => !candidateRuns.has(benchmarkId))\n .sort();\n for (const benchmarkId of missingCandidateBenchmarks) {\n regressions.push(`candidate is missing latest completed benchmark run for ${benchmarkId}`);\n }\n\n const deltas: EvalBenchmarkDelta[] = [];\n for (const benchmarkId of [...baselineBenchmarks.keys()].sort()) {\n const baseBenchmark = baselineBenchmarks.get(benchmarkId);\n const candidateRun = candidateRuns.get(benchmarkId);\n if (!baseBenchmark || !candidateRun) continue;\n\n const passRateDelta = computePassRate(candidateRun) - baseBenchmark.passRate;\n const delta: EvalBenchmarkDelta = {\n benchmarkId,\n baseRunId: baseBenchmark.runId,\n candidateRunId: candidateRun.runId,\n basePassRate: baseBenchmark.passRate,\n candidatePassRate: computePassRate(candidateRun),\n passRateDelta,\n metricDeltas: {},\n regressions: [],\n improvements: [],\n };\n\n if (passRateDelta < 0) {\n delta.regressions.push(`passRate ${baseBenchmark.passRate} -> ${delta.candidatePassRate}`);\n regressions.push(`${benchmarkId} pass rate regressed (${baseBenchmark.passRate} -> ${delta.candidatePassRate})`);\n } else if (passRateDelta > 0) {\n delta.improvements.push(`passRate ${baseBenchmark.passRate} -> ${delta.candidatePassRate}`);\n improvements.push(`${benchmarkId} pass rate improved (${baseBenchmark.passRate} -> ${delta.candidatePassRate})`);\n }\n\n const metricDelta = compareMetricDeltas(baseBenchmark.metrics, candidateRun.metrics);\n delta.metricDeltas = metricDelta.deltas;\n for (const regression of metricDelta.regressions) {\n delta.regressions.push(regression);\n regressions.push(`${benchmarkId} ${regression}`);\n }\n for (const improvement of metricDelta.improvements) {\n delta.improvements.push(improvement);\n improvements.push(`${benchmarkId} ${improvement}`);\n }\n deltas.push(delta);\n }\n\n const report: EvalBaselineDeltaReport = {\n passed: regressions.length === 0,\n baselineSnapshotId: baselineSnapshot.snapshotId,\n baselineCreatedAt: baselineSnapshot.createdAt,\n baselineSourceRootDir: baselineSnapshot.sourceRootDir,\n candidateRootDir: candidateSnapshot.status.rootDir,\n comparedBenchmarks: deltas.length,\n missingCandidateBenchmarks,\n invalidArtifacts: {\n candidate: {\n benchmarks: candidateSnapshot.status.invalidBenchmarks.length,\n runs: candidateSnapshot.status.invalidRuns.length,\n shadows: candidateSnapshot.status.invalidShadows.length,\n baselines: candidateSnapshot.status.invalidBaselines.length,\n },\n },\n regressions,\n improvements,\n deltas,\n markdownReport: \"\",\n };\n report.markdownReport = formatEvalBaselineDeltaMarkdown(report);\n return report;\n}\n\nfunction resolveRequiredEvalStoreRoot(options: { memoryDir?: string; evalStoreDir?: string }, label: string): string {\n if (typeof options.evalStoreDir === \"string\" && options.evalStoreDir.trim().length > 0) {\n return options.evalStoreDir.trim();\n }\n if (typeof options.memoryDir === \"string\" && options.memoryDir.trim().length > 0) {\n return resolveEvalStoreDir(options.memoryDir.trim());\n }\n throw new Error(`${label} requires memoryDir or evalStoreDir`);\n}\n\nexport async function runEvalBenchmarkCiGate(options: {\n baseMemoryDir?: string;\n candidateMemoryDir?: string;\n baseEvalStoreDir?: string;\n candidateEvalStoreDir?: string;\n}): Promise<EvalCiGateReport> {\n const baseRootDir = resolveRequiredEvalStoreRoot(\n { memoryDir: options.baseMemoryDir, evalStoreDir: options.baseEvalStoreDir },\n \"base\",\n );\n const candidateRootDir = resolveRequiredEvalStoreRoot(\n { memoryDir: options.candidateMemoryDir, evalStoreDir: options.candidateEvalStoreDir },\n \"candidate\",\n );\n const baseSnapshot = await collectEvalStoreSnapshot({\n rootDir: baseRootDir,\n enabled: true,\n shadowModeEnabled: true,\n memoryRedTeamBenchEnabled: true,\n });\n const candidateSnapshot = await collectEvalStoreSnapshot({\n rootDir: candidateRootDir,\n enabled: true,\n shadowModeEnabled: true,\n memoryRedTeamBenchEnabled: true,\n });\n\n const regressions: string[] = [];\n const improvements: string[] = [];\n\n if (baseSnapshot.status.invalidBenchmarks.length > 0) {\n regressions.push(`base store has ${baseSnapshot.status.invalidBenchmarks.length} invalid benchmark manifest(s)`);\n }\n if (baseSnapshot.status.invalidRuns.length > 0) {\n regressions.push(`base store has ${baseSnapshot.status.invalidRuns.length} invalid run summary file(s)`);\n }\n if (baseSnapshot.status.invalidShadows.length > 0) {\n regressions.push(`base store has ${baseSnapshot.status.invalidShadows.length} invalid shadow record(s)`);\n }\n if (candidateSnapshot.status.invalidBenchmarks.length > 0) {\n regressions.push(`candidate store has ${candidateSnapshot.status.invalidBenchmarks.length} invalid benchmark manifest(s)`);\n }\n if (candidateSnapshot.status.invalidRuns.length > 0) {\n regressions.push(`candidate store has ${candidateSnapshot.status.invalidRuns.length} invalid run summary file(s)`);\n }\n if (candidateSnapshot.status.invalidShadows.length > 0) {\n regressions.push(`candidate store has ${candidateSnapshot.status.invalidShadows.length} invalid shadow record(s)`);\n }\n\n const baseRuns = latestCompletedRunsByBenchmark(baseSnapshot.runs);\n const candidateRuns = latestCompletedRunsByBenchmark(candidateSnapshot.runs);\n const missingCandidateBenchmarks = [...baseRuns.keys()]\n .filter((benchmarkId) => !candidateRuns.has(benchmarkId))\n .sort();\n for (const benchmarkId of missingCandidateBenchmarks) {\n regressions.push(`candidate is missing latest completed benchmark run for ${benchmarkId}`);\n }\n\n const deltas: EvalBenchmarkDelta[] = [];\n for (const benchmarkId of [...baseRuns.keys()].sort()) {\n const baseRun = baseRuns.get(benchmarkId);\n const candidateRun = candidateRuns.get(benchmarkId);\n if (!baseRun || !candidateRun) continue;\n\n const basePassRate = computePassRate(baseRun);\n const candidatePassRate = computePassRate(candidateRun);\n const passRateDelta = candidatePassRate - basePassRate;\n const delta: EvalBenchmarkDelta = {\n benchmarkId,\n baseRunId: baseRun.runId,\n candidateRunId: candidateRun.runId,\n basePassRate,\n candidatePassRate,\n passRateDelta,\n metricDeltas: {},\n regressions: [],\n improvements: [],\n };\n\n if (passRateDelta < 0) {\n delta.regressions.push(`passRate ${basePassRate} -> ${candidatePassRate}`);\n regressions.push(`${benchmarkId} pass rate regressed (${basePassRate} -> ${candidatePassRate})`);\n } else if (passRateDelta > 0) {\n delta.improvements.push(`passRate ${basePassRate} -> ${candidatePassRate}`);\n improvements.push(`${benchmarkId} pass rate improved (${basePassRate} -> ${candidatePassRate})`);\n }\n\n const metricDelta = compareMetricDeltas(baseRun.metrics, candidateRun.metrics);\n delta.metricDeltas = metricDelta.deltas;\n for (const regression of metricDelta.regressions) {\n delta.regressions.push(regression);\n regressions.push(`${benchmarkId} ${regression}`);\n }\n for (const improvement of metricDelta.improvements) {\n delta.improvements.push(improvement);\n improvements.push(`${benchmarkId} ${improvement}`);\n }\n deltas.push(delta);\n }\n\n return {\n passed: regressions.length === 0,\n baseRootDir: baseSnapshot.status.rootDir,\n candidateRootDir: candidateSnapshot.status.rootDir,\n comparedBenchmarks: deltas.length,\n missingCandidateBenchmarks,\n invalidArtifacts: {\n base: {\n benchmarks: baseSnapshot.status.invalidBenchmarks.length,\n runs: baseSnapshot.status.invalidRuns.length,\n shadows: baseSnapshot.status.invalidShadows.length,\n },\n candidate: {\n benchmarks: candidateSnapshot.status.invalidBenchmarks.length,\n runs: candidateSnapshot.status.invalidRuns.length,\n shadows: candidateSnapshot.status.invalidShadows.length,\n },\n },\n regressions,\n improvements,\n deltas,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/search/meilisearch-backend.ts"],"sourcesContent":["import { log } from \"../logger.js\";\nimport type { SearchBackend, SearchExecutionOptions, SearchQueryOptions, SearchResult } from \"./port.js\";\nimport { scanMemoryDir } from \"./document-scanner.js\";\nimport { isSearchAborted, throwIfSearchAborted } from \"./abort.js\";\n\nexport interface MeilisearchBackendOptions {\n host: string;\n apiKey?: string;\n collection: string;\n timeoutMs?: number;\n autoIndex?: boolean;\n memoryDir?: string;\n}\n\n/**\n * Meilisearch search backend — server-based SDK client.\n *\n * Requires a running Meilisearch instance. Uses the official `meilisearch` SDK.\n * When `autoIndex` is true, update() pushes docs from the local memory directory.\n */\nexport class MeilisearchBackend implements SearchBackend {\n private readonly host: string;\n private readonly apiKey?: string;\n private readonly collection: string;\n private readonly timeoutMs: number;\n private readonly autoIndex: boolean;\n private readonly memoryDir?: string;\n private available = false;\n private client: any = null;\n private meiliModule: any = null;\n\n constructor(opts: MeilisearchBackendOptions) {\n this.host = opts.host;\n this.apiKey = opts.apiKey;\n this.collection = opts.collection;\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n this.autoIndex = opts.autoIndex ?? false;\n this.memoryDir = opts.memoryDir;\n }\n\n async probe(): Promise<boolean> {\n try {\n const client = await this.ensureClient();\n await client.health();\n this.available = true;\n return true;\n } catch (err) {\n log.debug(`MeilisearchBackend probe failed: ${err}`);\n this.available = false;\n return false;\n }\n }\n\n isAvailable(): boolean {\n return this.available;\n }\n\n debugStatus(): string {\n return `backend=meilisearch available=${this.available} host=${this.host}`;\n }\n\n async search(\n query: string,\n collection?: string,\n maxResults?: number,\n _options?: SearchQueryOptions,\n execution?: SearchExecutionOptions,\n ): Promise<SearchResult[]> {\n if (isSearchAborted(execution)) return [];\n // Try hybrid first; fall back to plain FTS only if hybrid throws (e.g. no embedder configured)\n try {\n return await this.doSearch(query, maxResults ?? 10, { hybrid: { semanticRatio: 0.5, embedder: \"default\" } }, collection, true, execution);\n } catch {\n if (isSearchAborted(execution)) return [];\n return this.bm25Search(query, collection, maxResults, execution);\n }\n }\n\n async searchGlobal(query: string, maxResults?: number, execution?: SearchExecutionOptions): Promise<SearchResult[]> {\n const limit = maxResults ?? 10;\n if (!this.available) return [];\n\n try {\n throwIfSearchAborted(execution, \"MeilisearchBackend global search aborted\");\n const client = await this.ensureClient();\n const indexes = await client.getIndexes();\n throwIfSearchAborted(execution, \"MeilisearchBackend global search aborted\");\n const queries = (indexes.results ?? []).map((idx: any) => ({\n indexUid: idx.uid,\n q: query,\n limit,\n showRankingScore: true,\n }));\n if (queries.length === 0) return [];\n\n const multiResult = await client.multiSearch({ queries });\n throwIfSearchAborted(execution, \"MeilisearchBackend global search aborted\");\n const allResults: SearchResult[] = [];\n for (const result of multiResult.results ?? []) {\n allResults.push(...this.mapHits(result.hits ?? []));\n }\n allResults.sort((a, b) => b.score - a.score);\n return allResults.slice(0, limit);\n } catch (err) {\n log.debug(`MeilisearchBackend searchGlobal failed: ${err}`);\n return [];\n }\n }\n\n async bm25Search(query: string, collection?: string, maxResults?: number, execution?: SearchExecutionOptions): Promise<SearchResult[]> {\n return this.doSearch(query, maxResults ?? 10, undefined, collection, false, execution);\n }\n\n async vectorSearch(query: string, collection?: string, maxResults?: number, execution?: SearchExecutionOptions): Promise<SearchResult[]> {\n return this.doSearch(query, maxResults ?? 10, { hybrid: { semanticRatio: 1.0, embedder: \"default\" } }, collection, false, execution);\n }\n\n async hybridSearch(query: string, collection?: string, maxResults?: number, execution?: SearchExecutionOptions): Promise<SearchResult[]> {\n return this.doSearch(query, maxResults ?? 10, { hybrid: { semanticRatio: 0.5, embedder: \"default\" } }, collection, false, execution);\n }\n\n async update(execution?: SearchExecutionOptions): Promise<void> {\n await this.updateCollection(this.collection, execution);\n }\n\n async updateCollection(collection: string, execution?: SearchExecutionOptions): Promise<void> {\n if (!this.memoryDir) return;\n await this.updateCollectionFromDir(collection, this.memoryDir, execution);\n }\n\n async updateCollectionFromDir(collection: string, memoryDir: string, execution?: SearchExecutionOptions): Promise<void> {\n if (!this.autoIndex) return;\n if (!this.available) return;\n if (isSearchAborted(execution)) return;\n\n try {\n const client = await this.ensureClient();\n if (isSearchAborted(execution)) return;\n const docs = await scanMemoryDir(memoryDir);\n if (isSearchAborted(execution)) return;\n const index = client.index(collection);\n\n const meilDocs = docs.map((d) => ({\n id: d.docid,\n path: d.path,\n content: d.content,\n snippet: d.snippet,\n }));\n\n // Upsert current docs and wait for the task to complete\n if (isSearchAborted(execution)) return;\n const addTask = await index.addDocuments(meilDocs, { primaryKey: \"id\" });\n await client.waitForTask(addTask.taskUid, { timeOutMs: this.timeoutMs });\n if (isSearchAborted(execution)) return;\n\n // Remove docs that no longer exist on disk (paginated to handle large indexes)\n const currentIds = new Set(docs.map((d) => d.docid));\n try {\n const PAGE_SIZE = 1000;\n let offset = 0;\n let staleIds: string[] = [];\n let hasMore = true;\n while (hasMore) {\n if (isSearchAborted(execution)) return;\n const page = await index.getDocuments({ limit: PAGE_SIZE, offset, fields: [\"id\"] });\n const results = page.results ?? [];\n for (const doc of results) {\n const id = doc.id as string;\n if (!currentIds.has(id)) staleIds.push(id);\n }\n offset += results.length;\n hasMore = results.length === PAGE_SIZE;\n }\n if (staleIds.length > 0) {\n if (isSearchAborted(execution)) return;\n const delTask = await index.deleteDocuments(staleIds);\n await client.waitForTask(delTask.taskUid, { timeOutMs: this.timeoutMs });\n }\n } catch {\n // Deletion cleanup is best-effort\n }\n } catch (err) {\n log.debug(`MeilisearchBackend update failed: ${err}`);\n }\n }\n\n async embed(): Promise<void> {\n // Meilisearch handles its own embedding when configured with an embedder\n }\n\n async embedCollection(collection: string): Promise<void> {\n // Meilisearch handles its own embedding when configured with an embedder\n // The collection parameter is accepted for interface compliance but Meilisearch\n // manages embeddings server-side per index (collection).\n }\n\n async ensureCollection(\n _memoryDir: string,\n _execution?: SearchExecutionOptions,\n ): Promise<\"present\" | \"missing\" | \"unknown\" | \"skipped\"> {\n if (!this.available) return \"skipped\";\n try {\n const client = await this.ensureClient();\n try {\n await client.getIndex(this.collection);\n return \"present\";\n } catch {\n // Index doesn't exist — create it\n await client.createIndex(this.collection, { primaryKey: \"id\" });\n return \"present\";\n }\n } catch {\n return \"skipped\";\n }\n }\n\n private async ensureClient(): Promise<any> {\n if (this.client) return this.client;\n if (!this.meiliModule) {\n this.meiliModule = await import(\"meilisearch\");\n }\n const MeiliSearch = this.meiliModule.MeiliSearch ?? this.meiliModule.default?.MeiliSearch;\n this.client = new MeiliSearch({\n host: this.host,\n apiKey: this.apiKey,\n timeout: this.timeoutMs,\n });\n return this.client;\n }\n\n private async doSearch(\n query: string,\n limit: number,\n extra?: Record<string, unknown>,\n collection?: string,\n rethrow = false,\n execution?: SearchExecutionOptions,\n ): Promise<SearchResult[]> {\n if (!this.available) return [];\n if (isSearchAborted(execution)) return [];\n try {\n const client = await this.ensureClient();\n throwIfSearchAborted(execution, \"MeilisearchBackend search aborted\");\n const index = client.index(collection ?? this.collection);\n const result = await index.search(query, { limit, showRankingScore: true, ...extra });\n throwIfSearchAborted(execution, \"MeilisearchBackend search aborted\");\n return this.mapHits(result.hits ?? []);\n } catch (err) {\n log.debug(`MeilisearchBackend search failed: ${err}`);\n if (rethrow) throw err;\n return [];\n }\n }\n\n private mapHits(hits: any[]): SearchResult[] {\n return hits.map((hit) => ({\n docid: hit.id ?? \"\",\n path: hit.path ?? \"\",\n snippet: hit._formatted?.content ?? hit.snippet ?? hit.content?.slice(0, 200) ?? \"\",\n score: hit._rankingScore ?? 0.5,\n }));\n }\n}\n"],"mappings":";;;;;;;;;;;;AAoBO,IAAM,qBAAN,MAAkD;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY;AAAA,EACZ,SAAc;AAAA,EACd,cAAmB;AAAA,EAE3B,YAAY,MAAiC;AAC3C,SAAK,OAAO,KAAK;AACjB,SAAK,SAAS,KAAK;AACnB,SAAK,aAAa,KAAK;AACvB,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,YAAY,KAAK;AAAA,EACxB;AAAA,EAEA,MAAM,QAA0B;AAC9B,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,aAAa;AACvC,YAAM,OAAO,OAAO;AACpB,WAAK,YAAY;AACjB,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,MAAM,oCAAoC,GAAG,EAAE;AACnD,WAAK,YAAY;AACjB,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAsB;AACpB,WAAO,iCAAiC,KAAK,SAAS,SAAS,KAAK,IAAI;AAAA,EAC1E;AAAA,EAEA,MAAM,OACJ,OACA,YACA,YACA,UACA,WACyB;AACzB,QAAI,gBAAgB,SAAS,EAAG,QAAO,CAAC;AAExC,QAAI;AACF,aAAO,MAAM,KAAK,SAAS,OAAO,cAAc,IAAI,EAAE,QAAQ,EAAE,eAAe,KAAK,UAAU,UAAU,EAAE,GAAG,YAAY,MAAM,SAAS;AAAA,IAC1I,QAAQ;AACN,UAAI,gBAAgB,SAAS,EAAG,QAAO,CAAC;AACxC,aAAO,KAAK,WAAW,OAAO,YAAY,YAAY,SAAS;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,OAAe,YAAqB,WAA6D;AAClH,UAAM,QAAQ,cAAc;AAC5B,QAAI,CAAC,KAAK,UAAW,QAAO,CAAC;AAE7B,QAAI;AACF,2BAAqB,WAAW,0CAA0C;AAC1E,YAAM,SAAS,MAAM,KAAK,aAAa;AACvC,YAAM,UAAU,MAAM,OAAO,WAAW;AACxC,2BAAqB,WAAW,0CAA0C;AAC1E,YAAM,WAAW,QAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,SAAc;AAAA,QACzD,UAAU,IAAI;AAAA,QACd,GAAG;AAAA,QACH;AAAA,QACA,kBAAkB;AAAA,MACpB,EAAE;AACF,UAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAElC,YAAM,cAAc,MAAM,OAAO,YAAY,EAAE,QAAQ,CAAC;AACxD,2BAAqB,WAAW,0CAA0C;AAC1E,YAAM,aAA6B,CAAC;AACpC,iBAAW,UAAU,YAAY,WAAW,CAAC,GAAG;AAC9C,mBAAW,KAAK,GAAG,KAAK,QAAQ,OAAO,QAAQ,CAAC,CAAC,CAAC;AAAA,MACpD;AACA,iBAAW,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAC3C,aAAO,WAAW,MAAM,GAAG,KAAK;AAAA,IAClC,SAAS,KAAK;AACZ,UAAI,MAAM,2CAA2C,GAAG,EAAE;AAC1D,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,OAAe,YAAqB,YAAqB,WAA6D;AACrI,WAAO,KAAK,SAAS,OAAO,cAAc,IAAI,QAAW,YAAY,OAAO,SAAS;AAAA,EACvF;AAAA,EAEA,MAAM,aAAa,OAAe,YAAqB,YAAqB,WAA6D;AACvI,WAAO,KAAK,SAAS,OAAO,cAAc,IAAI,EAAE,QAAQ,EAAE,eAAe,GAAK,UAAU,UAAU,EAAE,GAAG,YAAY,OAAO,SAAS;AAAA,EACrI;AAAA,EAEA,MAAM,aAAa,OAAe,YAAqB,YAAqB,WAA6D;AACvI,WAAO,KAAK,SAAS,OAAO,cAAc,IAAI,EAAE,QAAQ,EAAE,eAAe,KAAK,UAAU,UAAU,EAAE,GAAG,YAAY,OAAO,SAAS;AAAA,EACrI;AAAA,EAEA,MAAM,OAAO,WAAmD;AAC9D,UAAM,KAAK,iBAAiB,KAAK,YAAY,SAAS;AAAA,EACxD;AAAA,EAEA,MAAM,iBAAiB,YAAoB,WAAmD;AAC5F,QAAI,CAAC,KAAK,UAAW;AACrB,UAAM,KAAK,wBAAwB,YAAY,KAAK,WAAW,SAAS;AAAA,EAC1E;AAAA,EAEA,MAAM,wBAAwB,YAAoB,WAAmB,WAAmD;AACtH,QAAI,CAAC,KAAK,UAAW;AACrB,QAAI,CAAC,KAAK,UAAW;AACrB,QAAI,gBAAgB,SAAS,EAAG;AAEhC,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,aAAa;AACvC,UAAI,gBAAgB,SAAS,EAAG;AAChC,YAAM,OAAO,MAAM,cAAc,SAAS;AAC1C,UAAI,gBAAgB,SAAS,EAAG;AAChC,YAAM,QAAQ,OAAO,MAAM,UAAU;AAErC,YAAM,WAAW,KAAK,IAAI,CAAC,OAAO;AAAA,QAChC,IAAI,EAAE;AAAA,QACN,MAAM,EAAE;AAAA,QACR,SAAS,EAAE;AAAA,QACX,SAAS,EAAE;AAAA,MACb,EAAE;AAGF,UAAI,gBAAgB,SAAS,EAAG;AAChC,YAAM,UAAU,MAAM,MAAM,aAAa,UAAU,EAAE,YAAY,KAAK,CAAC;AACvE,YAAM,OAAO,YAAY,QAAQ,SAAS,EAAE,WAAW,KAAK,UAAU,CAAC;AACvE,UAAI,gBAAgB,SAAS,EAAG;AAGhC,YAAM,aAAa,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACnD,UAAI;AACF,cAAM,YAAY;AAClB,YAAI,SAAS;AACb,YAAI,WAAqB,CAAC;AAC1B,YAAI,UAAU;AACd,eAAO,SAAS;AACd,cAAI,gBAAgB,SAAS,EAAG;AAChC,gBAAM,OAAO,MAAM,MAAM,aAAa,EAAE,OAAO,WAAW,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;AAClF,gBAAM,UAAU,KAAK,WAAW,CAAC;AACjC,qBAAW,OAAO,SAAS;AACzB,kBAAM,KAAK,IAAI;AACf,gBAAI,CAAC,WAAW,IAAI,EAAE,EAAG,UAAS,KAAK,EAAE;AAAA,UAC3C;AACA,oBAAU,QAAQ;AAClB,oBAAU,QAAQ,WAAW;AAAA,QAC/B;AACA,YAAI,SAAS,SAAS,GAAG;AACvB,cAAI,gBAAgB,SAAS,EAAG;AAChC,gBAAM,UAAU,MAAM,MAAM,gBAAgB,QAAQ;AACpD,gBAAM,OAAO,YAAY,QAAQ,SAAS,EAAE,WAAW,KAAK,UAAU,CAAC;AAAA,QACzE;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,MAAM,qCAAqC,GAAG,EAAE;AAAA,IACtD;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AAAA,EAEA,MAAM,gBAAgB,YAAmC;AAAA,EAIzD;AAAA,EAEA,MAAM,iBACJ,YACA,YACwD;AACxD,QAAI,CAAC,KAAK,UAAW,QAAO;AAC5B,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,aAAa;AACvC,UAAI;AACF,cAAM,OAAO,SAAS,KAAK,UAAU;AACrC,eAAO;AAAA,MACT,QAAQ;AAEN,cAAM,OAAO,YAAY,KAAK,YAAY,EAAE,YAAY,KAAK,CAAC;AAC9D,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,eAA6B;AACzC,QAAI,KAAK,OAAQ,QAAO,KAAK;AAC7B,QAAI,CAAC,KAAK,aAAa;AACrB,WAAK,cAAc,MAAM,OAAO,aAAa;AAAA,IAC/C;AACA,UAAM,cAAc,KAAK,YAAY,eAAe,KAAK,YAAY,SAAS;AAC9E,SAAK,SAAS,IAAI,YAAY;AAAA,MAC5B,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK;AAAA,IAChB,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,SACZ,OACA,OACA,OACA,YACA,UAAU,OACV,WACyB;AACzB,QAAI,CAAC,KAAK,UAAW,QAAO,CAAC;AAC7B,QAAI,gBAAgB,SAAS,EAAG,QAAO,CAAC;AACxC,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,aAAa;AACvC,2BAAqB,WAAW,mCAAmC;AACnE,YAAM,QAAQ,OAAO,MAAM,cAAc,KAAK,UAAU;AACxD,YAAM,SAAS,MAAM,MAAM,OAAO,OAAO,EAAE,OAAO,kBAAkB,MAAM,GAAG,MAAM,CAAC;AACpF,2BAAqB,WAAW,mCAAmC;AACnE,aAAO,KAAK,QAAQ,OAAO,QAAQ,CAAC,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,UAAI,MAAM,qCAAqC,GAAG,EAAE;AACpD,UAAI,QAAS,OAAM;AACnB,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEQ,QAAQ,MAA6B;AAC3C,WAAO,KAAK,IAAI,CAAC,SAAS;AAAA,MACxB,OAAO,IAAI,MAAM;AAAA,MACjB,MAAM,IAAI,QAAQ;AAAA,MAClB,SAAS,IAAI,YAAY,WAAW,IAAI,WAAW,IAAI,SAAS,MAAM,GAAG,GAAG,KAAK;AAAA,MACjF,OAAO,IAAI,iBAAiB;AAAA,IAC9B,EAAE;AAAA,EACJ;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/conversation-index/indexer.ts"],"sourcesContent":["import { lstat, mkdir, writeFile } from \"node:fs/promises\";\nimport type { Stats } from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport { log } from \"../logger.js\";\nimport type { FaissConversationIndexAdapter } from \"./faiss-adapter.js\";\nimport type { ConversationChunk } from \"./chunker.js\";\n\nconst MAX_PATH_COMPONENT_LENGTH = 200;\n\nfunction sanitizePathComponent(\n value: string,\n fallback: string,\n opts: { lowercase?: boolean } = {},\n): string {\n const raw = typeof value === \"string\" && value.trim().length > 0\n ? value.trim()\n : fallback;\n const normalized = opts.lowercase ? raw.toLowerCase() : raw;\n const sanitized = normalized\n .replace(/[^a-zA-Z0-9._-]+/g, \"_\")\n .slice(0, MAX_PATH_COMPONENT_LENGTH);\n if (!sanitized || sanitized === \".\" || sanitized === \"..\") {\n return fallback;\n }\n return sanitized;\n}\n\nexport function sanitizeSessionKey(sessionKey: string): string {\n const raw = typeof sessionKey === \"string\" && sessionKey.trim().length > 0\n ? sessionKey.trim()\n : \"\";\n const safe = sanitizePathComponent(raw, \"unknown-session\", { lowercase: true });\n if (!raw) return safe;\n const suffix = `-${createHash(\"sha256\").update(raw).digest(\"hex\").slice(0, 12)}`;\n return `${safe.slice(0, MAX_PATH_COMPONENT_LENGTH - suffix.length)}${suffix}`;\n}\n\nfunction sanitizeChunkId(id: string): string {\n return sanitizePathComponent(id, \"chunk\");\n}\n\nfunction datePathComponent(startTs: string): string {\n const match = typeof startTs === \"string\"\n ? /^(\\d{4})-(\\d{2})-(\\d{2})T/.exec(startTs)\n : null;\n if (!match) {\n throw new Error(\"invalid conversation chunk start timestamp\");\n }\n const date = new Date(startTs);\n if (!Number.isFinite(date.getTime())) {\n throw new Error(\"invalid conversation chunk start timestamp\");\n }\n const [, year, month, day] = match;\n if (\n date.getUTCFullYear() !== Number(year) ||\n date.getUTCMonth() + 1 !== Number(month) ||\n date.getUTCDate() !== Number(day)\n ) {\n throw new Error(\"invalid conversation chunk start timestamp\");\n }\n return date.toISOString().slice(0, 10);\n}\n\nfunction resolveInsideRoot(rootDir: string, candidate: string): string {\n const root = path.resolve(rootDir);\n const resolved = path.resolve(candidate);\n const rel = path.relative(root, resolved);\n if (\n rel === \"\" ||\n (rel !== \"..\" && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel))\n ) {\n return resolved;\n }\n throw new Error(\"conversation chunk path escapes index root\");\n}\n\nasync function lstatIfExists(candidate: string): Promise<Stats | undefined> {\n try {\n return await lstat(candidate);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n}\n\nasync function rejectSymlinkIfExists(candidate: string): Promise<void> {\n const stat = await lstatIfExists(candidate);\n if (stat?.isSymbolicLink()) {\n throw new Error(\"conversation chunk path contains symlink\");\n }\n}\n\nasync function rejectExistingSymlinksInPath(baseDir: string, candidate: string): Promise<void> {\n const base = path.resolve(baseDir);\n const resolved = path.resolve(candidate);\n\n let current = base;\n while (current !== path.dirname(current)) {\n const stat = await lstatIfExists(current);\n if (stat) {\n if (stat.isSymbolicLink()) {\n throw new Error(\"conversation chunk path contains symlink\");\n }\n break;\n }\n current = path.dirname(current);\n }\n\n const relative = path.relative(base, resolved);\n if (relative === \"\") return;\n\n current = base;\n for (const part of relative.split(path.sep)) {\n current = path.join(current, part);\n const stat = await lstatIfExists(current);\n if (!stat) return;\n if (stat.isSymbolicLink()) {\n throw new Error(\"conversation chunk path contains symlink\");\n }\n }\n}\n\nasync function rejectExistingSymlinkAncestors(\n rootDir: string,\n candidate: string,\n): Promise<void> {\n const root = path.resolve(rootDir);\n const resolved = resolveInsideRoot(root, candidate);\n await rejectExistingSymlinksInPath(root, resolved);\n}\n\nexport async function writeConversationChunks(\n rootDir: string,\n chunks: ConversationChunk[],\n): Promise<string[]> {\n const written: string[] = [];\n const root = path.resolve(rootDir);\n await rejectExistingSymlinksInPath(root, root);\n await mkdir(root, { recursive: true });\n await rejectExistingSymlinksInPath(root, root);\n\n for (const c of chunks) {\n const safe = sanitizeSessionKey(c.sessionKey);\n const date = datePathComponent(c.startTs);\n const dir = resolveInsideRoot(root, path.join(root, safe, date));\n await rejectExistingSymlinkAncestors(root, dir);\n await mkdir(dir, { recursive: true });\n await rejectExistingSymlinkAncestors(root, dir);\n const fp = resolveInsideRoot(root, path.join(dir, `${sanitizeChunkId(c.id)}.md`));\n await rejectExistingSymlinkAncestors(root, path.dirname(fp));\n await rejectSymlinkIfExists(fp);\n const content =\n `---\\n` +\n `kind: conversation_chunk\\n` +\n `sessionKey: ${c.sessionKey}\\n` +\n `startTs: ${c.startTs}\\n` +\n `endTs: ${c.endTs}\\n` +\n `---\\n\\n` +\n c.text +\n \"\\n\";\n await writeFile(fp, content, \"utf-8\");\n written.push(fp);\n }\n return written;\n}\n\nexport interface ConversationChunkUpsertResult {\n upserted: number;\n skipped: boolean;\n reason?: \"adapter-unavailable\" | \"adapter-error\";\n}\n\nexport interface ConversationChunkRebuildResult {\n rebuilt: number;\n skipped: boolean;\n reason?: \"adapter-unavailable\" | \"adapter-error\";\n}\n\nexport async function upsertConversationChunksFailOpen(\n adapter: FaissConversationIndexAdapter | undefined,\n chunks: ConversationChunk[],\n options: { retentionCutoffMs?: number } = {},\n): Promise<ConversationChunkUpsertResult> {\n if (!adapter) {\n return { upserted: 0, skipped: true, reason: \"adapter-unavailable\" };\n }\n try {\n const upserted = await adapter.upsertChunks(chunks, options);\n return { upserted, skipped: false };\n } catch (err) {\n log.debug(`conversation index FAISS upsert failed (fail-open): ${err}`);\n return { upserted: 0, skipped: true, reason: \"adapter-error\" };\n }\n}\n\nexport async function rebuildConversationChunksFailOpen(\n adapter: FaissConversationIndexAdapter | undefined,\n chunks: ConversationChunk[],\n): Promise<ConversationChunkRebuildResult> {\n if (!adapter) {\n return { rebuilt: 0, skipped: true, reason: \"adapter-unavailable\" };\n }\n try {\n const rebuilt = await adapter.rebuildChunks(chunks);\n return { rebuilt, skipped: false };\n } catch (err) {\n log.debug(`conversation index FAISS rebuild failed (fail-open): ${err}`);\n return { rebuilt: 0, skipped: true, reason: \"adapter-error\" };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/enrichment/types.ts","../src/enrichment/provider-registry.ts","../src/enrichment/web-search-provider.ts","../src/enrichment/pipeline.ts","../src/enrichment/audit.ts"],"sourcesContent":["/**\n * Enrichment pipeline types (issue #365).\n *\n * Defines the provider interface, candidate shape, pipeline config,\n * and result types for the external enrichment subsystem.\n */\n\nimport type { ImportanceLevel, MemoryCategory } from \"../types.js\";\n\n// ---------------------------------------------------------------------------\n// Provider config & interface\n// ---------------------------------------------------------------------------\n\nexport type EnrichmentCostTier = \"free\" | \"cheap\" | \"expensive\";\n\nexport interface EnrichmentProviderConfig {\n id: string;\n enabled: boolean;\n costTier: EnrichmentCostTier;\n rateLimit?: { maxPerMinute: number; maxPerDay: number };\n}\n\nexport interface EnrichmentCandidate {\n text: string;\n source: string;\n sourceUrl?: string;\n confidence: number;\n category: MemoryCategory;\n tags?: string[];\n}\n\nexport interface EnrichmentProvider {\n readonly id: string;\n readonly costTier: EnrichmentCostTier;\n enrich(entity: EntityEnrichmentInput): Promise<EnrichmentCandidate[]>;\n isAvailable(): Promise<boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// Entity enrichment input\n// ---------------------------------------------------------------------------\n\nexport interface EntityEnrichmentInput {\n name: string;\n type: string;\n knownFacts: string[];\n importanceLevel: ImportanceLevel;\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline result\n// ---------------------------------------------------------------------------\n\nexport interface EnrichmentResult {\n entityName: string;\n provider: string;\n candidatesFound: number;\n candidatesAccepted: number;\n candidatesRejected: number;\n acceptedCandidates: EnrichmentCandidate[];\n elapsed: number;\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline config\n// ---------------------------------------------------------------------------\n\nexport interface EnrichmentPipelineConfig {\n enabled: boolean;\n providers: EnrichmentProviderConfig[];\n importanceThresholds: {\n critical: string[];\n high: string[];\n normal: string[];\n low: string[];\n };\n maxCandidatesPerEntity: number;\n autoEnrichOnCreate: boolean;\n scheduleIntervalMs: number;\n}\n\n/**\n * Build a default (disabled) pipeline config. Every consumer that needs a\n * config object should call this rather than duplicating the defaults.\n */\nexport function defaultEnrichmentPipelineConfig(): EnrichmentPipelineConfig {\n return {\n enabled: false,\n providers: [],\n importanceThresholds: {\n critical: [],\n high: [],\n normal: [],\n low: [],\n },\n maxCandidatesPerEntity: 20,\n autoEnrichOnCreate: false,\n scheduleIntervalMs: 3_600_000,\n };\n}\n","/**\n * Enrichment provider registry (issue #365).\n *\n * Central registry for enrichment providers. Providers register themselves\n * at startup; the pipeline queries the registry to determine which providers\n * to run for a given importance tier.\n */\n\nimport type { ImportanceLevel } from \"../types.js\";\nimport type {\n EnrichmentPipelineConfig,\n EnrichmentProvider,\n} from \"./types.js\";\n\nexport class EnrichmentProviderRegistry {\n private readonly providers = new Map<string, EnrichmentProvider>();\n\n /** Register a provider. Overwrites any existing provider with the same id. */\n register(provider: EnrichmentProvider): void {\n this.providers.set(provider.id, provider);\n }\n\n /** Look up a single provider by id. */\n get(id: string): EnrichmentProvider | undefined {\n return this.providers.get(id);\n }\n\n /**\n * Return all registered providers whose id appears in the config's\n * `providers` list with `enabled: true`.\n */\n listEnabled(config: EnrichmentPipelineConfig): EnrichmentProvider[] {\n const enabledIds = new Set(\n config.providers\n .filter((p) => p.enabled)\n .map((p) => p.id),\n );\n const result: EnrichmentProvider[] = [];\n for (const [id, provider] of this.providers.entries()) {\n if (enabledIds.has(id)) {\n result.push(provider);\n }\n }\n return result;\n }\n\n /**\n * Return providers that should run for a given importance level.\n * Providers are resolved from `config.importanceThresholds[level]` and\n * filtered to only those that are both registered and enabled.\n */\n getForImportance(\n level: ImportanceLevel,\n config: EnrichmentPipelineConfig,\n ): EnrichmentProvider[] {\n // \"trivial\" entities never get enrichment providers\n if (level === \"trivial\") return [];\n\n const thresholds = config.importanceThresholds;\n const providerIds: string[] =\n level === \"critical\"\n ? thresholds.critical\n : level === \"high\"\n ? thresholds.high\n : level === \"normal\"\n ? thresholds.normal\n : thresholds.low;\n\n const enabledIds = new Set(\n config.providers\n .filter((p) => p.enabled)\n .map((p) => p.id),\n );\n\n const result: EnrichmentProvider[] = [];\n for (const id of providerIds) {\n if (!enabledIds.has(id)) continue;\n const provider = this.providers.get(id);\n if (provider) {\n result.push(provider);\n }\n }\n return result;\n }\n}\n","/**\n * Web search enrichment provider stub (issue #365).\n *\n * A basic provider backed by web search. Since this is opt-in and we do not\n * want to hard-code an API key, the provider accepts an optional `searchFn`\n * injection point. When no search function is configured it returns empty\n * results, making it safe to register unconditionally.\n */\n\nimport type {\n EnrichmentCandidate,\n EnrichmentCostTier,\n EnrichmentProvider,\n EntityEnrichmentInput,\n} from \"./types.js\";\n\nexport type WebSearchFn = (query: string) => Promise<string[]>;\n\nexport interface WebSearchProviderOptions {\n /**\n * Injected search function. Each returned string is treated as a raw\n * snippet. When `undefined` the provider returns empty results.\n */\n searchFn?: WebSearchFn;\n}\n\nexport class WebSearchProvider implements EnrichmentProvider {\n readonly id = \"web-search\";\n readonly costTier: EnrichmentCostTier = \"cheap\";\n\n private readonly searchFn: WebSearchFn | undefined;\n\n constructor(options: WebSearchProviderOptions = {}) {\n this.searchFn = options.searchFn;\n }\n\n async isAvailable(): Promise<boolean> {\n return this.searchFn !== undefined;\n }\n\n async enrich(entity: EntityEnrichmentInput): Promise<EnrichmentCandidate[]> {\n if (!this.searchFn) return [];\n\n const query = `${entity.name} ${entity.type}`;\n const snippets = await this.searchFn(query);\n\n return snippets\n .filter((s) => typeof s === \"string\" && s.trim().length > 0)\n .map((snippet) => ({\n text: snippet.trim(),\n source: this.id,\n sourceUrl: undefined,\n confidence: 0.5,\n category: \"fact\" as const,\n tags: [\"web-search\"],\n }));\n }\n}\n","/**\n * Enrichment pipeline orchestrator (issue #365).\n *\n * For each entity, determines the importance tier, resolves the providers\n * to run, executes them in sequence (respecting rate limits), tags\n * candidates, and caps at `maxCandidatesPerEntity`.\n *\n * Accepted candidates are returned in each `EnrichmentResult` via the\n * `acceptedCandidates` field so that callers can persist them.\n */\n\nimport type { LoggerBackend } from \"../logger.js\";\nimport type { EnrichmentProviderRegistry } from \"./provider-registry.js\";\nimport type {\n EnrichmentCandidate,\n EnrichmentPipelineConfig,\n EnrichmentProvider,\n EnrichmentResult,\n EntityEnrichmentInput,\n} from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Rate-limit tracking\n// ---------------------------------------------------------------------------\n\ninterface RateLimitBucket {\n minuteCount: number;\n minuteReset: number;\n dayCount: number;\n dayReset: number;\n}\n\nconst rateBuckets = new Map<string, RateLimitBucket>();\n\nfunction isRateLimited(\n provider: EnrichmentProvider,\n config: EnrichmentPipelineConfig,\n): boolean {\n const providerCfg = config.providers.find((p) => p.id === provider.id);\n if (!providerCfg?.rateLimit) return false;\n\n const now = Date.now();\n let bucket = rateBuckets.get(provider.id);\n if (!bucket) {\n bucket = {\n minuteCount: 0,\n minuteReset: now + 60_000,\n dayCount: 0,\n dayReset: now + 86_400_000,\n };\n rateBuckets.set(provider.id, bucket);\n }\n\n // Reset windows if expired\n if (now >= bucket.minuteReset) {\n bucket.minuteCount = 0;\n bucket.minuteReset = now + 60_000;\n }\n if (now >= bucket.dayReset) {\n bucket.dayCount = 0;\n bucket.dayReset = now + 86_400_000;\n }\n\n const { maxPerMinute, maxPerDay } = providerCfg.rateLimit;\n return bucket.minuteCount >= maxPerMinute || bucket.dayCount >= maxPerDay;\n}\n\nfunction recordCall(\n providerId: string,\n): void {\n const bucket = rateBuckets.get(providerId);\n if (bucket) {\n bucket.minuteCount += 1;\n bucket.dayCount += 1;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline\n// ---------------------------------------------------------------------------\n\nexport async function runEnrichmentPipeline(\n entities: EntityEnrichmentInput[],\n registry: EnrichmentProviderRegistry,\n config: EnrichmentPipelineConfig,\n log: LoggerBackend,\n): Promise<EnrichmentResult[]> {\n if (!config.enabled) return [];\n if (entities.length === 0) return [];\n\n const results: EnrichmentResult[] = [];\n\n for (const entity of entities) {\n const providers = registry.getForImportance(entity.importanceLevel, config);\n const maxCandidates = config.maxCandidatesPerEntity;\n const hasPositiveCandidateBudget = maxCandidates > 0;\n let remainingCandidateBudget = hasPositiveCandidateBudget\n ? maxCandidates\n : Number.POSITIVE_INFINITY;\n\n for (const provider of providers) {\n if (hasPositiveCandidateBudget && remainingCandidateBudget <= 0) {\n break;\n }\n\n const start = Date.now();\n\n // Check availability\n let available: boolean;\n try {\n available = await provider.isAvailable();\n } catch {\n available = false;\n }\n\n if (!available) {\n log.debug?.(\n `enrichment: skipping provider ${provider.id} for ${entity.name} — unavailable`,\n );\n results.push({\n entityName: entity.name,\n provider: provider.id,\n candidatesFound: 0,\n candidatesAccepted: 0,\n candidatesRejected: 0,\n acceptedCandidates: [],\n elapsed: Date.now() - start,\n });\n continue;\n }\n\n // Check rate limit\n if (isRateLimited(provider, config)) {\n log.debug?.(\n `enrichment: skipping provider ${provider.id} for ${entity.name} — rate limited`,\n );\n results.push({\n entityName: entity.name,\n provider: provider.id,\n candidatesFound: 0,\n candidatesAccepted: 0,\n candidatesRejected: 0,\n acceptedCandidates: [],\n elapsed: Date.now() - start,\n });\n continue;\n }\n\n // Run provider.\n // Count every attempt toward rate-limit buckets — including failures —\n // because the provider may have consumed external quota before throwing\n // (PR #425 review finding 2).\n let candidates: EnrichmentCandidate[];\n try {\n candidates = await provider.enrich(entity);\n } catch (err) {\n recordCall(provider.id);\n log.error?.(\n `enrichment: provider ${provider.id} failed for ${entity.name}: ${err instanceof Error ? err.message : String(err)}`,\n );\n results.push({\n entityName: entity.name,\n provider: provider.id,\n candidatesFound: 0,\n candidatesAccepted: 0,\n candidatesRejected: 0,\n acceptedCandidates: [],\n elapsed: Date.now() - start,\n });\n continue;\n }\n recordCall(provider.id);\n\n // Tag each candidate with provider id\n for (const candidate of candidates) {\n candidate.source = provider.id;\n }\n\n // Cap at maxCandidatesPerEntity across all providers for this entity.\n // 0 means \"accept none\"; undefined/negative means \"no cap\".\n let accepted: EnrichmentCandidate[];\n if (maxCandidates === 0) {\n accepted = [];\n } else if (hasPositiveCandidateBudget) {\n accepted = candidates.slice(0, remainingCandidateBudget);\n remainingCandidateBudget -= accepted.length;\n } else {\n accepted = candidates;\n }\n const rejected = candidates.length - accepted.length;\n\n results.push({\n entityName: entity.name,\n provider: provider.id,\n candidatesFound: candidates.length,\n candidatesAccepted: accepted.length,\n candidatesRejected: rejected,\n acceptedCandidates: accepted,\n elapsed: Date.now() - start,\n });\n }\n }\n\n return results;\n}\n","/**\n * Enrichment audit trail (issue #365).\n *\n * Append-only JSONL log for every enrichment candidate that was evaluated.\n * Each entry records whether the candidate was accepted or rejected, the\n * provider that produced it, and an optional reason string.\n */\n\nimport { mkdir, readFile, appendFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface EnrichmentAuditEntry {\n timestamp: string;\n entityName: string;\n provider: string;\n candidateText: string;\n sourceUrl?: string;\n accepted: boolean;\n reason?: string;\n}\n\n// ---------------------------------------------------------------------------\n// File helpers\n// ---------------------------------------------------------------------------\n\nconst AUDIT_FILENAME = \"enrichment-audit.jsonl\";\n\nfunction auditFilePath(auditDir: string): string {\n return path.join(auditDir, AUDIT_FILENAME);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Append a single audit entry to the JSONL log. Creates the audit directory\n * and file if they do not exist.\n */\nexport async function appendAuditEntry(\n auditDir: string,\n entry: EnrichmentAuditEntry,\n): Promise<void> {\n await mkdir(auditDir, { recursive: true });\n const line = JSON.stringify(entry) + \"\\n\";\n await appendFile(auditFilePath(auditDir), line, \"utf-8\");\n}\n\n/**\n * Read the audit log and return entries, optionally filtered to entries at\n * or after `since` (ISO 8601 timestamp, half-open interval).\n */\nexport async function readAuditLog(\n auditDir: string,\n since?: string,\n): Promise<EnrichmentAuditEntry[]> {\n const filePath = auditFilePath(auditDir);\n if (!existsSync(filePath)) return [];\n const sinceMs = since === undefined ? undefined : Date.parse(since);\n if (since !== undefined && !Number.isFinite(sinceMs)) {\n throw new Error(`Invalid enrichment audit since timestamp: ${since}`);\n }\n\n const raw = await readFile(filePath, \"utf-8\");\n const entries: EnrichmentAuditEntry[] = [];\n\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.length === 0) continue;\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n \"timestamp\" in parsed &&\n \"entityName\" in parsed\n ) {\n const entry = parsed as EnrichmentAuditEntry;\n if (typeof entry.timestamp !== \"string\") continue;\n const entryMs = Date.parse(entry.timestamp);\n if (!Number.isFinite(entryMs)) continue;\n if (sinceMs !== undefined && entryMs < sinceMs) continue;\n entries.push(entry);\n }\n } catch {\n // Skip malformed lines\n }\n }\n\n return entries;\n}\n"],"mappings":"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","names":[]}
|