@remnic/core 9.3.654 → 9.3.656
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 +29 -29
- package/dist/access-http.d.ts +4 -4
- package/dist/access-http.js +17 -17
- package/dist/access-mcp.d.ts +4 -4
- package/dist/access-mcp.js +16 -16
- package/dist/access-schema.d.ts +10 -10
- package/dist/{access-service-C8A5hoXJ.d.ts → access-service-D_nbpexW.d.ts} +33 -2
- package/dist/access-service.d.ts +4 -4
- package/dist/access-service.js +15 -15
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +3 -3
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +4 -4
- package/dist/{chunk-JMQSYGXS.js → chunk-2BD7DG37.js} +2 -2
- package/dist/{chunk-FVRBLJP6.js → chunk-2MXEVL75.js} +2 -2
- package/dist/{chunk-LJCEWTG3.js → chunk-4UL7VPTD.js} +277 -58
- package/dist/chunk-4UL7VPTD.js.map +1 -0
- package/dist/{chunk-JYN7QNTA.js → chunk-54XF2FY7.js} +17 -17
- package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
- package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
- package/dist/{chunk-ZCORQM74.js → chunk-AGJKWOKV.js} +2 -2
- package/dist/{chunk-NE2JBMLN.js → chunk-AZBV4RRY.js} +1 -1
- package/dist/chunk-AZBV4RRY.js.map +1 -0
- package/dist/{chunk-YLZLPVKK.js → chunk-CTAV55JM.js} +344 -1
- package/dist/chunk-CTAV55JM.js.map +1 -0
- package/dist/{chunk-2DSTAWNZ.js → chunk-DIBWFCLA.js} +3 -3
- package/dist/{chunk-NAZWHTYV.js → chunk-DR67OK4E.js} +5 -5
- package/dist/{chunk-XBIACVCO.js → chunk-EC2AYKRX.js} +2 -2
- package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
- package/dist/chunk-EKQMQQ3U.js.map +1 -0
- package/dist/{chunk-RGPUQ66K.js → chunk-GCYFUTUC.js} +2 -2
- package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
- package/dist/{chunk-BJA6DQOC.js → chunk-GSHW5VVD.js} +5 -5
- package/dist/chunk-GYSYLGNE.js +650 -0
- package/dist/chunk-GYSYLGNE.js.map +1 -0
- package/dist/{chunk-NCGWXCSW.js → chunk-IOZ5WBWD.js} +2 -2
- package/dist/{chunk-QKK64Z6M.js → chunk-JSVFEHLL.js} +7 -5
- package/dist/chunk-JSVFEHLL.js.map +1 -0
- package/dist/{chunk-7LWRCOP7.js → chunk-LZTFCAKE.js} +2 -2
- package/dist/{chunk-2DGQLOOM.js → chunk-M3VYPE2H.js} +1 -1
- package/dist/{chunk-2DGQLOOM.js.map → chunk-M3VYPE2H.js.map} +1 -1
- package/dist/{chunk-6CVI6BP6.js → chunk-NXCK7DO7.js} +2 -2
- package/dist/{chunk-Z5MQI7K2.js → chunk-PEPHBH2W.js} +2 -2
- package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
- package/dist/chunk-QRSKPI62.js.map +1 -0
- package/dist/{chunk-XWQ6ERUG.js → chunk-QZRKNA5F.js} +2 -2
- package/dist/{chunk-PS3SYNHP.js → chunk-R5DB26G6.js} +2 -2
- package/dist/{chunk-OL2364SB.js → chunk-RDW5G6DO.js} +1502 -335
- package/dist/chunk-RDW5G6DO.js.map +1 -0
- package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
- package/dist/{chunk-T2C6QJG2.js → chunk-SWDHVH2P.js} +2 -2
- package/dist/{chunk-DBM2BD22.js → chunk-SXYCVRLK.js} +3 -3
- package/dist/{chunk-K6X553JB.js → chunk-TFFZUFEP.js} +7 -5
- package/dist/chunk-TFFZUFEP.js.map +1 -0
- package/dist/{chunk-ENV6RDTD.js → chunk-TIJYQXDI.js} +2 -2
- package/dist/{chunk-BP2EV6W5.js → chunk-VAEAGTEQ.js} +4 -4
- package/dist/{chunk-3RACUBII.js → chunk-WIKMCJUR.js} +2 -2
- package/dist/{chunk-QW6JZO5P.js → chunk-WWMHAMAY.js} +2 -2
- package/dist/{chunk-GPW2E4LN.js → chunk-YEZHZCUO.js} +4 -4
- package/dist/{chunk-5FOCXX5E.js → chunk-YVVQUAOO.js} +3 -3
- package/dist/{chunk-5FOCXX5E.js.map → chunk-YVVQUAOO.js.map} +1 -1
- package/dist/{chunk-3XGWCZ63.js → chunk-YXLT4EMM.js} +2 -2
- package/dist/{chunk-Y2RIIF6H.js → chunk-Z6UDTNY6.js} +2 -2
- package/dist/{cli-uQgvDFNE.d.ts → cli-aYxSuPvP.d.ts} +3 -3
- package/dist/cli.d.ts +5 -5
- package/dist/cli.js +29 -29
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +3 -3
- package/dist/explicit-cue-recall.js +2 -2
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/focused-list-recall.js +2 -2
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +121 -121
- package/dist/index.js +39 -39
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lcm-fallback-read.js +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +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 +4 -4
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +1 -1
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +15 -4
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.d.ts +1 -1
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +14 -14
- package/dist/{orchestrator-B4Y4sWQH.d.ts → orchestrator-D1wcmPNj.d.ts} +17 -14
- package/dist/orchestrator.d.ts +3 -3
- package/dist/orchestrator.js +25 -25
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +5 -1
- package/dist/qmd.js +2 -2
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/response-guidance-recall.js +2 -2
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +22 -22
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +6 -6
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +17 -1
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BKd0Pype.d.ts → semantic-consolidation-MWOdNtSE.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +3 -2
- package/dist/semantic-rule-verifier.js +5 -3
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/targeted-fact-recall.js +2 -2
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/{types-BgChEr0M.d.ts → types-CgcCpUrf.d.ts} +51 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.d.ts +2 -1
- package/dist/verified-recall.js +5 -3
- package/package.json +1 -1
- package/src/access-service-observe-lcm-parity.test.ts +86 -1
- package/src/access-service-observe-scope.test.ts +283 -1
- package/src/access-service-raw-excerpt-read-gate.test.ts +53 -0
- package/src/access-service.ts +391 -93
- package/src/coding/coding-namespace.ts +0 -3
- package/src/config.test.ts +69 -0
- package/src/config.ts +417 -0
- package/src/lcm-fallback-read.ts +2 -6
- package/src/maintenance/namespace-planner.test.ts +1120 -0
- package/src/maintenance/namespace-planner.ts +893 -0
- package/src/namespaces/scope-profiles.test.ts +1074 -0
- package/src/namespaces/scope-profiles.ts +456 -0
- package/src/namespaces/search.test.ts +130 -2
- package/src/namespaces/search.ts +71 -10
- package/src/orchestrator-flush.test.ts +606 -44
- package/src/orchestrator-source-attribution.test.ts +73 -0
- package/src/orchestrator.ts +932 -229
- package/src/qmd-client.test.ts +59 -0
- package/src/qmd.ts +124 -84
- package/src/search/port.ts +16 -0
- package/src/semantic-rule-verifier.ts +13 -6
- package/src/types.ts +64 -0
- package/src/verified-recall.ts +10 -6
- package/dist/chunk-JVRPJ7D4.js.map +0 -1
- package/dist/chunk-K6X553JB.js.map +0 -1
- package/dist/chunk-LJCEWTG3.js.map +0 -1
- package/dist/chunk-MMJANTJX.js +0 -339
- package/dist/chunk-MMJANTJX.js.map +0 -1
- package/dist/chunk-NE2JBMLN.js.map +0 -1
- package/dist/chunk-OL2364SB.js.map +0 -1
- package/dist/chunk-PYWNNF2I.js.map +0 -1
- package/dist/chunk-QKK64Z6M.js.map +0 -1
- package/dist/chunk-YLZLPVKK.js.map +0 -1
- /package/dist/{chunk-JMQSYGXS.js.map → chunk-2BD7DG37.js.map} +0 -0
- /package/dist/{chunk-FVRBLJP6.js.map → chunk-2MXEVL75.js.map} +0 -0
- /package/dist/{chunk-JYN7QNTA.js.map → chunk-54XF2FY7.js.map} +0 -0
- /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
- /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
- /package/dist/{chunk-ZCORQM74.js.map → chunk-AGJKWOKV.js.map} +0 -0
- /package/dist/{chunk-2DSTAWNZ.js.map → chunk-DIBWFCLA.js.map} +0 -0
- /package/dist/{chunk-NAZWHTYV.js.map → chunk-DR67OK4E.js.map} +0 -0
- /package/dist/{chunk-XBIACVCO.js.map → chunk-EC2AYKRX.js.map} +0 -0
- /package/dist/{chunk-RGPUQ66K.js.map → chunk-GCYFUTUC.js.map} +0 -0
- /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
- /package/dist/{chunk-BJA6DQOC.js.map → chunk-GSHW5VVD.js.map} +0 -0
- /package/dist/{chunk-NCGWXCSW.js.map → chunk-IOZ5WBWD.js.map} +0 -0
- /package/dist/{chunk-7LWRCOP7.js.map → chunk-LZTFCAKE.js.map} +0 -0
- /package/dist/{chunk-6CVI6BP6.js.map → chunk-NXCK7DO7.js.map} +0 -0
- /package/dist/{chunk-Z5MQI7K2.js.map → chunk-PEPHBH2W.js.map} +0 -0
- /package/dist/{chunk-XWQ6ERUG.js.map → chunk-QZRKNA5F.js.map} +0 -0
- /package/dist/{chunk-PS3SYNHP.js.map → chunk-R5DB26G6.js.map} +0 -0
- /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
- /package/dist/{chunk-T2C6QJG2.js.map → chunk-SWDHVH2P.js.map} +0 -0
- /package/dist/{chunk-DBM2BD22.js.map → chunk-SXYCVRLK.js.map} +0 -0
- /package/dist/{chunk-ENV6RDTD.js.map → chunk-TIJYQXDI.js.map} +0 -0
- /package/dist/{chunk-BP2EV6W5.js.map → chunk-VAEAGTEQ.js.map} +0 -0
- /package/dist/{chunk-3RACUBII.js.map → chunk-WIKMCJUR.js.map} +0 -0
- /package/dist/{chunk-QW6JZO5P.js.map → chunk-WWMHAMAY.js.map} +0 -0
- /package/dist/{chunk-GPW2E4LN.js.map → chunk-YEZHZCUO.js.map} +0 -0
- /package/dist/{chunk-3XGWCZ63.js.map → chunk-YXLT4EMM.js.map} +0 -0
- /package/dist/{chunk-Y2RIIF6H.js.map → chunk-Z6UDTNY6.js.map} +0 -0
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
CompoundingEngine,
|
|
31
31
|
defaultTierMigrationCycleBudget
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-AGJKWOKV.js";
|
|
33
33
|
import {
|
|
34
34
|
SharedContextManager
|
|
35
35
|
} from "./chunk-DRD2Q7HQ.js";
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
import {
|
|
57
57
|
buildTargetedFactRecallSection,
|
|
58
58
|
shouldRecallTargetedFactEvidence
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-R5DB26G6.js";
|
|
60
60
|
import {
|
|
61
61
|
applyTemporalSupersession,
|
|
62
62
|
normalizeSupersessionKey,
|
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
import {
|
|
72
72
|
buildResponseGuidanceRecallSection,
|
|
73
73
|
shouldRecallResponseGuidance
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-EC2AYKRX.js";
|
|
75
75
|
import {
|
|
76
76
|
mergeWithAgentResults,
|
|
77
77
|
runDirectAgent,
|
|
@@ -170,19 +170,19 @@ import {
|
|
|
170
170
|
import {
|
|
171
171
|
buildFocusedListRecallSection,
|
|
172
172
|
shouldRecallFocusedListEvidence
|
|
173
|
-
} from "./chunk-
|
|
173
|
+
} from "./chunk-LZTFCAKE.js";
|
|
174
174
|
import {
|
|
175
175
|
buildEntityRecallSection,
|
|
176
176
|
entityRecentTranscriptLookbackHours,
|
|
177
177
|
readRecentEntityTranscriptEntries
|
|
178
|
-
} from "./chunk-
|
|
178
|
+
} from "./chunk-IOZ5WBWD.js";
|
|
179
179
|
import {
|
|
180
180
|
buildEventOrderRecallSection,
|
|
181
181
|
shouldRecallEventOrderEvidence
|
|
182
182
|
} from "./chunk-UU6MVCJ6.js";
|
|
183
183
|
import {
|
|
184
184
|
buildExplicitCueRecallSection
|
|
185
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-YXLT4EMM.js";
|
|
186
186
|
import {
|
|
187
187
|
formatDaySummaryMemories
|
|
188
188
|
} from "./chunk-WLEB7WCG.js";
|
|
@@ -210,7 +210,7 @@ import {
|
|
|
210
210
|
materializeAfterSemanticConsolidation,
|
|
211
211
|
parseConsolidationResponse,
|
|
212
212
|
parseOperatorAwareConsolidationResponse
|
|
213
|
-
} from "./chunk-
|
|
213
|
+
} from "./chunk-SWDHVH2P.js";
|
|
214
214
|
import {
|
|
215
215
|
normalizeReplaySessionKey
|
|
216
216
|
} from "./chunk-2PRQG7PV.js";
|
|
@@ -218,14 +218,16 @@ import {
|
|
|
218
218
|
RoutingRulesStore
|
|
219
219
|
} from "./chunk-X6IRLNOO.js";
|
|
220
220
|
import {
|
|
221
|
+
compareVerifiedEpisodeResults,
|
|
221
222
|
searchVerifiedEpisodes
|
|
222
|
-
} from "./chunk-
|
|
223
|
+
} from "./chunk-JSVFEHLL.js";
|
|
223
224
|
import {
|
|
224
225
|
ThreadingManager
|
|
225
226
|
} from "./chunk-W4RVMTHR.js";
|
|
226
227
|
import {
|
|
228
|
+
compareVerifiedSemanticRuleResults,
|
|
227
229
|
searchVerifiedSemanticRules
|
|
228
|
-
} from "./chunk-
|
|
230
|
+
} from "./chunk-TFFZUFEP.js";
|
|
229
231
|
import {
|
|
230
232
|
searchWorkProductLedgerEntries
|
|
231
233
|
} from "./chunk-ZRWB5D4H.js";
|
|
@@ -239,7 +241,7 @@ import {
|
|
|
239
241
|
NamespaceStorageRouter,
|
|
240
242
|
resolveDefaultNamespaceRoot,
|
|
241
243
|
resolveNamespaceStorageRoot
|
|
242
|
-
} from "./chunk-
|
|
244
|
+
} from "./chunk-WIKMCJUR.js";
|
|
243
245
|
import {
|
|
244
246
|
isAboveImportanceThreshold,
|
|
245
247
|
scoreImportance
|
|
@@ -305,9 +307,11 @@ import {
|
|
|
305
307
|
import {
|
|
306
308
|
clusterByKey,
|
|
307
309
|
combineNamespaces,
|
|
310
|
+
expandScopeProfileReadNamespaces,
|
|
308
311
|
lcmReadSessionIdsForNamespaces,
|
|
309
|
-
resolveCodingNamespaceOverlay
|
|
310
|
-
|
|
312
|
+
resolveCodingNamespaceOverlay,
|
|
313
|
+
resolveScopeProfilePlan
|
|
314
|
+
} from "./chunk-GYSYLGNE.js";
|
|
311
315
|
import {
|
|
312
316
|
listTrustZoneRecords,
|
|
313
317
|
searchTrustZoneRecords
|
|
@@ -317,14 +321,14 @@ import {
|
|
|
317
321
|
} from "./chunk-FF4KLI5W.js";
|
|
318
322
|
import {
|
|
319
323
|
buildXraySnapshot
|
|
320
|
-
} from "./chunk-
|
|
324
|
+
} from "./chunk-2MXEVL75.js";
|
|
321
325
|
import {
|
|
322
326
|
NamespaceSearchRouter
|
|
323
|
-
} from "./chunk-
|
|
327
|
+
} from "./chunk-EKQMQQ3U.js";
|
|
324
328
|
import {
|
|
325
329
|
createConversationIndexRuntime,
|
|
326
330
|
createSearchBackend
|
|
327
|
-
} from "./chunk-
|
|
331
|
+
} from "./chunk-SSSXWIBP.js";
|
|
328
332
|
import {
|
|
329
333
|
NoopSearchBackend
|
|
330
334
|
} from "./chunk-CYEPCZN5.js";
|
|
@@ -338,7 +342,7 @@ import {
|
|
|
338
342
|
} from "./chunk-OIF36KGD.js";
|
|
339
343
|
import {
|
|
340
344
|
parseQmdExplain
|
|
341
|
-
} from "./chunk-
|
|
345
|
+
} from "./chunk-QRSKPI62.js";
|
|
342
346
|
import {
|
|
343
347
|
objectiveStateStoreOverrideForNamespace,
|
|
344
348
|
searchObjectiveStateSnapshots
|
|
@@ -357,7 +361,7 @@ import {
|
|
|
357
361
|
} from "./chunk-Y56J7CXW.js";
|
|
358
362
|
import {
|
|
359
363
|
buildChainFollowupGenerator
|
|
360
|
-
} from "./chunk-
|
|
364
|
+
} from "./chunk-Z6UDTNY6.js";
|
|
361
365
|
import {
|
|
362
366
|
ALL_CATEGORY_DIRS,
|
|
363
367
|
ContentHashIndex,
|
|
@@ -368,7 +372,7 @@ import {
|
|
|
368
372
|
normalizeEntityName,
|
|
369
373
|
parseEntityFile,
|
|
370
374
|
stripAttributesSuffix
|
|
371
|
-
} from "./chunk-
|
|
375
|
+
} from "./chunk-NXCK7DO7.js";
|
|
372
376
|
import {
|
|
373
377
|
isValidTranscriptDate,
|
|
374
378
|
loadSpeakerRegistry,
|
|
@@ -383,11 +387,14 @@ import {
|
|
|
383
387
|
} from "./chunk-J6A3CX5N.js";
|
|
384
388
|
import {
|
|
385
389
|
confidenceTier
|
|
386
|
-
} from "./chunk-
|
|
390
|
+
} from "./chunk-AZBV4RRY.js";
|
|
387
391
|
import {
|
|
388
392
|
inferMemoryStatus,
|
|
389
393
|
isActiveMemoryStatus
|
|
390
394
|
} from "./chunk-RULE4VG5.js";
|
|
395
|
+
import {
|
|
396
|
+
displayErrorDetail
|
|
397
|
+
} from "./chunk-6KYMPV2O.js";
|
|
391
398
|
import {
|
|
392
399
|
lintWorkspaceFiles,
|
|
393
400
|
rotateMarkdownFileToArchive
|
|
@@ -438,17 +445,17 @@ import {
|
|
|
438
445
|
} from "./chunk-AC5LO7IU.js";
|
|
439
446
|
|
|
440
447
|
// src/orchestrator.ts
|
|
441
|
-
import
|
|
448
|
+
import path4 from "path";
|
|
442
449
|
import os from "os";
|
|
443
|
-
import { createHash, randomBytes } from "crypto";
|
|
450
|
+
import { createHash as createHash2, randomBytes } from "crypto";
|
|
444
451
|
import { existsSync, readFileSync } from "fs";
|
|
445
452
|
import {
|
|
446
|
-
mkdir as
|
|
447
|
-
readdir as
|
|
448
|
-
readFile as
|
|
449
|
-
stat as
|
|
453
|
+
mkdir as mkdir4,
|
|
454
|
+
readdir as readdir3,
|
|
455
|
+
readFile as readFile4,
|
|
456
|
+
stat as stat3,
|
|
450
457
|
unlink as unlink2,
|
|
451
|
-
writeFile as
|
|
458
|
+
writeFile as writeFile4
|
|
452
459
|
} from "fs/promises";
|
|
453
460
|
|
|
454
461
|
// src/procedural/procedure-recall.ts
|
|
@@ -2051,9 +2058,9 @@ var NamespaceCatalog = class {
|
|
|
2051
2058
|
}
|
|
2052
2059
|
if (await this.hasSymlinkedAncestor(candidate)) return false;
|
|
2053
2060
|
try {
|
|
2054
|
-
const
|
|
2055
|
-
if (
|
|
2056
|
-
if (!
|
|
2061
|
+
const stat4 = await lstat(candidate);
|
|
2062
|
+
if (stat4.isSymbolicLink()) return false;
|
|
2063
|
+
if (!stat4.isDirectory()) return false;
|
|
2057
2064
|
} catch {
|
|
2058
2065
|
return this.isNearestExistingAncestorContained(candidate, memoryReal);
|
|
2059
2066
|
}
|
|
@@ -2114,8 +2121,8 @@ var NamespaceCatalog = class {
|
|
|
2114
2121
|
}
|
|
2115
2122
|
if (!(isPathInside(memoryReal, real) || real === memoryReal)) return false;
|
|
2116
2123
|
try {
|
|
2117
|
-
const
|
|
2118
|
-
return
|
|
2124
|
+
const stat4 = await lstat(real);
|
|
2125
|
+
return stat4.isDirectory();
|
|
2119
2126
|
} catch {
|
|
2120
2127
|
return false;
|
|
2121
2128
|
}
|
|
@@ -2279,14 +2286,14 @@ var NamespaceCatalog = class {
|
|
|
2279
2286
|
if (normalizeNamespaceIdentity(namespace) !== this.defaultNamespaceIdentity && path2.resolve(root) === path2.resolve(this.memoryDir)) {
|
|
2280
2287
|
return false;
|
|
2281
2288
|
}
|
|
2282
|
-
let
|
|
2289
|
+
let stat4;
|
|
2283
2290
|
try {
|
|
2284
|
-
|
|
2291
|
+
stat4 = await lstat(root);
|
|
2285
2292
|
} catch {
|
|
2286
2293
|
return false;
|
|
2287
2294
|
}
|
|
2288
|
-
if (
|
|
2289
|
-
if (!
|
|
2295
|
+
if (stat4.isSymbolicLink()) return false;
|
|
2296
|
+
if (!stat4.isDirectory()) return false;
|
|
2290
2297
|
try {
|
|
2291
2298
|
const real = await realpath(root);
|
|
2292
2299
|
if (memoryReal && !isPathInside(memoryReal, real)) return false;
|
|
@@ -2463,18 +2470,18 @@ var NamespaceCatalog = class {
|
|
|
2463
2470
|
for (const entry of entries) {
|
|
2464
2471
|
const token = entry.name;
|
|
2465
2472
|
const fullPath = path2.join(namespacesDir, token);
|
|
2466
|
-
let
|
|
2473
|
+
let stat4;
|
|
2467
2474
|
try {
|
|
2468
|
-
|
|
2475
|
+
stat4 = await lstat(fullPath);
|
|
2469
2476
|
} catch (err) {
|
|
2470
2477
|
skipped.push({ token, reason: "error", detail: err instanceof Error ? err.message : String(err) });
|
|
2471
2478
|
continue;
|
|
2472
2479
|
}
|
|
2473
|
-
if (
|
|
2480
|
+
if (stat4.isSymbolicLink()) {
|
|
2474
2481
|
skipped.push({ token, reason: "symlink", detail: fullPath });
|
|
2475
2482
|
continue;
|
|
2476
2483
|
}
|
|
2477
|
-
if (!
|
|
2484
|
+
if (!stat4.isDirectory()) continue;
|
|
2478
2485
|
try {
|
|
2479
2486
|
const real = await realpath(fullPath);
|
|
2480
2487
|
if (memoryReal && !isPathInside(memoryReal, real)) {
|
|
@@ -2865,6 +2872,611 @@ function isPathInside(root, child) {
|
|
|
2865
2872
|
return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
|
|
2866
2873
|
}
|
|
2867
2874
|
|
|
2875
|
+
// src/maintenance/namespace-planner.ts
|
|
2876
|
+
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
2877
|
+
import { lstat as lstat2, mkdir as mkdir3, open as open2, readFile as readFile3, readdir as readdir2, rename as rename2, rm, rmdir, utimes as utimes2, writeFile as writeFile3 } from "fs/promises";
|
|
2878
|
+
import path3 from "path";
|
|
2879
|
+
var DEFAULT_MAX_NAMESPACES_PER_CYCLE = 20;
|
|
2880
|
+
var DEFAULT_LOCK_STALE_MS = 10 * 6e4;
|
|
2881
|
+
var LOCK_BASE = "maintenance-locks";
|
|
2882
|
+
var STATUS_BASE = "namespace-maintenance-status";
|
|
2883
|
+
var namespaceMaintenanceFs = { open: open2, rm };
|
|
2884
|
+
function configuredNamespaces(config) {
|
|
2885
|
+
return Array.from(
|
|
2886
|
+
new Set(
|
|
2887
|
+
[config.defaultNamespace, config.sharedNamespace, ...config.namespacePolicies.map((policy) => policy.name)].map((value) => value.trim()).filter(Boolean)
|
|
2888
|
+
)
|
|
2889
|
+
);
|
|
2890
|
+
}
|
|
2891
|
+
function inferConfiguredKind(config, namespace) {
|
|
2892
|
+
if (namespace === config.defaultNamespace.trim()) return "default";
|
|
2893
|
+
if (namespace === config.sharedNamespace.trim()) return "shared";
|
|
2894
|
+
return "explicit";
|
|
2895
|
+
}
|
|
2896
|
+
function maxNamespacesPerCycle(config) {
|
|
2897
|
+
return Math.max(
|
|
2898
|
+
1,
|
|
2899
|
+
Math.floor(
|
|
2900
|
+
typeof config.maintenanceMaxNamespacesPerCycle === "number" && Number.isFinite(config.maintenanceMaxNamespacesPerCycle) ? config.maintenanceMaxNamespacesPerCycle : DEFAULT_MAX_NAMESPACES_PER_CYCLE
|
|
2901
|
+
)
|
|
2902
|
+
);
|
|
2903
|
+
}
|
|
2904
|
+
function namespaceKindAllowed(config, kind) {
|
|
2905
|
+
switch (kind) {
|
|
2906
|
+
case "branch":
|
|
2907
|
+
return config.maintenanceIncludeBranchNamespaces === true;
|
|
2908
|
+
case "project":
|
|
2909
|
+
return config.maintenanceIncludeProjectNamespaces !== false;
|
|
2910
|
+
case "team-project":
|
|
2911
|
+
return config.maintenanceIncludeTeamProjectNamespaces !== false;
|
|
2912
|
+
default:
|
|
2913
|
+
return true;
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
function disabledReasonForKind(kind) {
|
|
2917
|
+
if (kind === "branch") return "branch_disabled";
|
|
2918
|
+
if (kind === "project") return "project_disabled";
|
|
2919
|
+
if (kind === "team-project") return "team_project_disabled";
|
|
2920
|
+
return "fanout_disabled";
|
|
2921
|
+
}
|
|
2922
|
+
async function catalogRootIsLive(config, record) {
|
|
2923
|
+
if (typeof record.storageDir !== "string" || record.storageDir.length === 0) {
|
|
2924
|
+
return false;
|
|
2925
|
+
}
|
|
2926
|
+
try {
|
|
2927
|
+
const liveRoot = await resolveNamespaceStorageRoot(config, record.namespace);
|
|
2928
|
+
if (path3.resolve(liveRoot) !== path3.resolve(record.storageDir)) return false;
|
|
2929
|
+
return hasMemoryData(liveRoot);
|
|
2930
|
+
} catch {
|
|
2931
|
+
return false;
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
function candidateSortKey(candidate) {
|
|
2935
|
+
const write = candidate.lastWriteAt ?? "";
|
|
2936
|
+
return `${write}\0${candidate.namespace}`;
|
|
2937
|
+
}
|
|
2938
|
+
function candidatePriority(candidate) {
|
|
2939
|
+
if (candidate.kind === "default") return 0;
|
|
2940
|
+
if (candidate.kind === "shared") return 1;
|
|
2941
|
+
if (candidate.source === "configured") return 2;
|
|
2942
|
+
if (candidate.kind === "team-project") return 3;
|
|
2943
|
+
if (candidate.kind === "project") return 4;
|
|
2944
|
+
if (candidate.kind === "self") return 5;
|
|
2945
|
+
if (candidate.kind === "legacy") return 6;
|
|
2946
|
+
if (candidate.kind === "branch") return 8;
|
|
2947
|
+
return 7;
|
|
2948
|
+
}
|
|
2949
|
+
function sortCandidates(a, b) {
|
|
2950
|
+
const priority = candidatePriority(a) - candidatePriority(b);
|
|
2951
|
+
if (priority !== 0) return priority;
|
|
2952
|
+
const am = Date.parse(a.lastMaintenanceAt ?? "");
|
|
2953
|
+
const bm = Date.parse(b.lastMaintenanceAt ?? "");
|
|
2954
|
+
const aMaintained = Number.isFinite(am);
|
|
2955
|
+
const bMaintained = Number.isFinite(bm);
|
|
2956
|
+
if (aMaintained && bMaintained && am !== bm) return am - bm;
|
|
2957
|
+
if (aMaintained !== bMaintained) return aMaintained ? 1 : -1;
|
|
2958
|
+
const aw = Date.parse(a.lastWriteAt ?? "");
|
|
2959
|
+
const bw = Date.parse(b.lastWriteAt ?? "");
|
|
2960
|
+
const aValid = Number.isFinite(aw);
|
|
2961
|
+
const bValid = Number.isFinite(bw);
|
|
2962
|
+
if (aValid && bValid && aw !== bw) return bw - aw;
|
|
2963
|
+
if (aValid !== bValid) return aValid ? -1 : 1;
|
|
2964
|
+
const byKey = candidateSortKey(a).localeCompare(candidateSortKey(b));
|
|
2965
|
+
if (byKey !== 0) return byKey;
|
|
2966
|
+
return a.namespace.localeCompare(b.namespace);
|
|
2967
|
+
}
|
|
2968
|
+
async function planNamespaceMaintenance(config, options) {
|
|
2969
|
+
const generatedAt = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
2970
|
+
const configured = configuredNamespaces(config);
|
|
2971
|
+
const byNamespace = /* @__PURE__ */ new Map();
|
|
2972
|
+
const skipped = [];
|
|
2973
|
+
for (const namespace of configured) {
|
|
2974
|
+
const kind = inferConfiguredKind(config, namespace);
|
|
2975
|
+
byNamespace.set(namespace, {
|
|
2976
|
+
namespace,
|
|
2977
|
+
kind,
|
|
2978
|
+
source: "configured"
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2981
|
+
if (config.namespacesEnabled && config.maintenanceNamespaceFanoutEnabled !== false) {
|
|
2982
|
+
const configuredSet = new Set(configured);
|
|
2983
|
+
try {
|
|
2984
|
+
const records = options.catalog?.enabled ? await options.catalog.listNamespaces() : [];
|
|
2985
|
+
for (const record of records) {
|
|
2986
|
+
const namespace = record.namespace.trim();
|
|
2987
|
+
if (!namespace) continue;
|
|
2988
|
+
const isConfigured = configuredSet.has(namespace);
|
|
2989
|
+
const kind = isConfigured ? inferConfiguredKind(config, namespace) : record.kind;
|
|
2990
|
+
if (!namespaceKindAllowed(config, kind)) {
|
|
2991
|
+
skipped.push({
|
|
2992
|
+
namespace,
|
|
2993
|
+
kind,
|
|
2994
|
+
reason: disabledReasonForKind(kind)
|
|
2995
|
+
});
|
|
2996
|
+
continue;
|
|
2997
|
+
}
|
|
2998
|
+
if (!isConfigured && !await catalogRootIsLive(config, record)) {
|
|
2999
|
+
skipped.push({
|
|
3000
|
+
namespace,
|
|
3001
|
+
kind,
|
|
3002
|
+
reason: "unsafe_or_stale_root"
|
|
3003
|
+
});
|
|
3004
|
+
continue;
|
|
3005
|
+
}
|
|
3006
|
+
byNamespace.set(namespace, {
|
|
3007
|
+
namespace,
|
|
3008
|
+
kind,
|
|
3009
|
+
storageDir: record.storageDir,
|
|
3010
|
+
source: isConfigured ? "configured" : "catalog",
|
|
3011
|
+
lastWriteAt: record.lastWriteAt,
|
|
3012
|
+
lastMaintenanceAt: record.lastMaintenanceAt?.[options.jobName]
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
3015
|
+
} catch (error) {
|
|
3016
|
+
skipped.push({
|
|
3017
|
+
namespace: "*",
|
|
3018
|
+
reason: "catalog_read_failed",
|
|
3019
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
3020
|
+
});
|
|
3021
|
+
}
|
|
3022
|
+
} else if (config.namespacesEnabled) {
|
|
3023
|
+
skipped.push({
|
|
3024
|
+
namespace: "*",
|
|
3025
|
+
reason: "fanout_disabled"
|
|
3026
|
+
});
|
|
3027
|
+
}
|
|
3028
|
+
if (options.budgetMode !== "unbounded") {
|
|
3029
|
+
const latestStatusAtByNamespace = await readLatestStatusAtByNamespace(config, options.jobName);
|
|
3030
|
+
for (const candidate of byNamespace.values()) {
|
|
3031
|
+
if (!candidate.lastMaintenanceAt) {
|
|
3032
|
+
candidate.lastMaintenanceAt = latestStatusAtByNamespace.get(candidate.namespace);
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
const candidates = [...byNamespace.values()].filter((candidate) => namespaceKindAllowed(config, candidate.kind)).sort(sortCandidates);
|
|
3037
|
+
const max = maxNamespacesPerCycle(config);
|
|
3038
|
+
const applyCycleBudget = options.budgetMode !== "unbounded";
|
|
3039
|
+
const selected = applyCycleBudget ? candidates.slice(0, max) : candidates;
|
|
3040
|
+
if (applyCycleBudget) {
|
|
3041
|
+
for (const candidate of candidates.slice(max)) {
|
|
3042
|
+
skipped.push({
|
|
3043
|
+
namespace: candidate.namespace,
|
|
3044
|
+
kind: candidate.kind,
|
|
3045
|
+
reason: "budget_exhausted"
|
|
3046
|
+
});
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
return {
|
|
3050
|
+
jobName: options.jobName,
|
|
3051
|
+
generatedAt,
|
|
3052
|
+
namespaces: selected,
|
|
3053
|
+
skipped,
|
|
3054
|
+
budget: {
|
|
3055
|
+
maxNamespacesPerCycle: max,
|
|
3056
|
+
selected: selected.length
|
|
3057
|
+
}
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
function stablePathSegment(value) {
|
|
3061
|
+
const sanitized = value.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 128) || "unnamed";
|
|
3062
|
+
if (sanitized.length <= 128 && sanitized === value) return sanitized;
|
|
3063
|
+
return `${sanitized.slice(0, 80)}-${createHash("sha256").update(value).digest("hex").slice(0, 16)}`;
|
|
3064
|
+
}
|
|
3065
|
+
function namespacePathSegment(namespace) {
|
|
3066
|
+
const token = namespaceIdentityToken(namespace);
|
|
3067
|
+
if (token.length <= 160) return token;
|
|
3068
|
+
return `ns-${createHash("sha256").update(namespace).digest("hex")}`;
|
|
3069
|
+
}
|
|
3070
|
+
function lockPath(config, jobName, namespace) {
|
|
3071
|
+
return path3.join(
|
|
3072
|
+
config.memoryDir,
|
|
3073
|
+
"state",
|
|
3074
|
+
LOCK_BASE,
|
|
3075
|
+
stablePathSegment(jobName),
|
|
3076
|
+
`${namespacePathSegment(namespace)}.lock`
|
|
3077
|
+
);
|
|
3078
|
+
}
|
|
3079
|
+
function namespaceMaintenanceLockStaleMs(config) {
|
|
3080
|
+
if (typeof config.maintenanceNamespaceLockStaleMs === "number" && Number.isFinite(config.maintenanceNamespaceLockStaleMs) && config.maintenanceNamespaceLockStaleMs > 0) {
|
|
3081
|
+
return Math.floor(config.maintenanceNamespaceLockStaleMs);
|
|
3082
|
+
}
|
|
3083
|
+
return DEFAULT_LOCK_STALE_MS;
|
|
3084
|
+
}
|
|
3085
|
+
function namespaceMaintenanceLockHeartbeatMs(config) {
|
|
3086
|
+
const staleMs = namespaceMaintenanceLockStaleMs(config);
|
|
3087
|
+
return Math.max(1, Math.min(3e4, Math.floor(staleMs / 3) || 1));
|
|
3088
|
+
}
|
|
3089
|
+
function errorCode(error) {
|
|
3090
|
+
return typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
3091
|
+
}
|
|
3092
|
+
async function withNamespaceMaintenanceLockHeartbeat(config, locks, task) {
|
|
3093
|
+
const activeLocks = Array.isArray(locks) ? locks : [locks];
|
|
3094
|
+
const interval = setInterval(() => {
|
|
3095
|
+
for (const lock of activeLocks) {
|
|
3096
|
+
void lock.touch().catch(() => void 0);
|
|
3097
|
+
}
|
|
3098
|
+
}, namespaceMaintenanceLockHeartbeatMs(config));
|
|
3099
|
+
interval.unref?.();
|
|
3100
|
+
try {
|
|
3101
|
+
return await task();
|
|
3102
|
+
} finally {
|
|
3103
|
+
clearInterval(interval);
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
async function removeStaleLockDirectory(filePath) {
|
|
3107
|
+
let entries;
|
|
3108
|
+
try {
|
|
3109
|
+
entries = await readdir2(filePath, { withFileTypes: true });
|
|
3110
|
+
} catch (error) {
|
|
3111
|
+
if (errorCode(error) === "ENOENT") return;
|
|
3112
|
+
throw error;
|
|
3113
|
+
}
|
|
3114
|
+
for (const entry of entries) {
|
|
3115
|
+
if (!entry.isFile()) continue;
|
|
3116
|
+
await namespaceMaintenanceFs.rm(path3.join(filePath, entry.name), { force: true });
|
|
3117
|
+
}
|
|
3118
|
+
try {
|
|
3119
|
+
await rmdir(filePath);
|
|
3120
|
+
} catch (error) {
|
|
3121
|
+
if (errorCode(error) === "ENOENT") return;
|
|
3122
|
+
throw error;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
async function tryAcquireNamespaceMaintenanceLock(config, jobName, namespace) {
|
|
3126
|
+
const filePath = lockPath(config, jobName, namespace);
|
|
3127
|
+
await mkdir3(path3.dirname(filePath), { recursive: true });
|
|
3128
|
+
try {
|
|
3129
|
+
const lockId = randomUUID2();
|
|
3130
|
+
await mkdir3(filePath);
|
|
3131
|
+
const ownerPath = path3.join(filePath, `${lockId}.json`);
|
|
3132
|
+
let handle;
|
|
3133
|
+
try {
|
|
3134
|
+
handle = await namespaceMaintenanceFs.open(ownerPath, "wx");
|
|
3135
|
+
await handle.writeFile(
|
|
3136
|
+
`${JSON.stringify({
|
|
3137
|
+
lockId,
|
|
3138
|
+
pid: process.pid,
|
|
3139
|
+
jobName,
|
|
3140
|
+
namespace,
|
|
3141
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3142
|
+
})}
|
|
3143
|
+
`,
|
|
3144
|
+
"utf8"
|
|
3145
|
+
);
|
|
3146
|
+
await handle.close();
|
|
3147
|
+
} catch (setupError) {
|
|
3148
|
+
await handle?.close().catch(() => void 0);
|
|
3149
|
+
await namespaceMaintenanceFs.rm(ownerPath, { force: true }).catch(() => void 0);
|
|
3150
|
+
await rmdir(filePath).catch(() => void 0);
|
|
3151
|
+
throw setupError;
|
|
3152
|
+
}
|
|
3153
|
+
return {
|
|
3154
|
+
path: filePath,
|
|
3155
|
+
async touch() {
|
|
3156
|
+
try {
|
|
3157
|
+
const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
|
|
3158
|
+
if (parsed.lockId === lockId) {
|
|
3159
|
+
const now = /* @__PURE__ */ new Date();
|
|
3160
|
+
await utimes2(ownerPath, now, now);
|
|
3161
|
+
await utimes2(filePath, now, now);
|
|
3162
|
+
}
|
|
3163
|
+
} catch {
|
|
3164
|
+
}
|
|
3165
|
+
},
|
|
3166
|
+
async release() {
|
|
3167
|
+
try {
|
|
3168
|
+
const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
|
|
3169
|
+
if (parsed.lockId === lockId) {
|
|
3170
|
+
await namespaceMaintenanceFs.rm(ownerPath, { force: true });
|
|
3171
|
+
await rmdir(filePath).catch(() => void 0);
|
|
3172
|
+
}
|
|
3173
|
+
} catch {
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
};
|
|
3177
|
+
} catch (error) {
|
|
3178
|
+
if (errorCode(error) === "EEXIST") {
|
|
3179
|
+
const staleMs = namespaceMaintenanceLockStaleMs(config);
|
|
3180
|
+
try {
|
|
3181
|
+
const s = await lstat2(filePath);
|
|
3182
|
+
if (s.isSymbolicLink()) {
|
|
3183
|
+
return null;
|
|
3184
|
+
}
|
|
3185
|
+
if ((s.isFile() || s.isDirectory()) && Date.now() - s.mtimeMs > staleMs) {
|
|
3186
|
+
try {
|
|
3187
|
+
if (s.isDirectory()) {
|
|
3188
|
+
await removeStaleLockDirectory(filePath);
|
|
3189
|
+
} else {
|
|
3190
|
+
await namespaceMaintenanceFs.rm(filePath, { force: true });
|
|
3191
|
+
}
|
|
3192
|
+
} catch (removeError) {
|
|
3193
|
+
if (errorCode(removeError) === "ENOENT") {
|
|
3194
|
+
return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
|
|
3195
|
+
}
|
|
3196
|
+
if (errorCode(removeError) === "ENOTEMPTY") {
|
|
3197
|
+
return null;
|
|
3198
|
+
}
|
|
3199
|
+
throw removeError;
|
|
3200
|
+
}
|
|
3201
|
+
return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
|
|
3202
|
+
}
|
|
3203
|
+
} catch (statError) {
|
|
3204
|
+
if (errorCode(statError) === "ENOENT") {
|
|
3205
|
+
return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
|
|
3206
|
+
}
|
|
3207
|
+
throw statError;
|
|
3208
|
+
}
|
|
3209
|
+
return null;
|
|
3210
|
+
}
|
|
3211
|
+
throw error;
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
function statusBasePath(config) {
|
|
3215
|
+
return path3.join(config.memoryDir, "state", STATUS_BASE);
|
|
3216
|
+
}
|
|
3217
|
+
function statusPath(config, jobName, namespace) {
|
|
3218
|
+
return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.json`);
|
|
3219
|
+
}
|
|
3220
|
+
function lastRanStatusPath(config, jobName, namespace) {
|
|
3221
|
+
return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.last-ran.json`);
|
|
3222
|
+
}
|
|
3223
|
+
function parseStatus(value) {
|
|
3224
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
3225
|
+
const v = value;
|
|
3226
|
+
if (typeof v.namespace === "string" && typeof v.jobName === "string" && (v.state === "ran" || v.state === "skipped" || v.state === "failed") && typeof v.startedAt === "string" && typeof v.completedAt === "string") {
|
|
3227
|
+
return v;
|
|
3228
|
+
}
|
|
3229
|
+
return null;
|
|
3230
|
+
}
|
|
3231
|
+
async function readLatestStatusAtByNamespace(config, jobName) {
|
|
3232
|
+
const latest = /* @__PURE__ */ new Map();
|
|
3233
|
+
const latestMs = /* @__PURE__ */ new Map();
|
|
3234
|
+
for (const status of [...await readStatusFiles(config), ...await readLastRanStatusFiles(config)]) {
|
|
3235
|
+
if (status.state !== "ran") continue;
|
|
3236
|
+
if (status.jobName !== jobName) continue;
|
|
3237
|
+
const completedAtMs = Date.parse(status.completedAt);
|
|
3238
|
+
if (!Number.isFinite(completedAtMs)) continue;
|
|
3239
|
+
const previousMs = latestMs.get(status.namespace);
|
|
3240
|
+
if (previousMs !== void 0 && previousMs >= completedAtMs) continue;
|
|
3241
|
+
latestMs.set(status.namespace, completedAtMs);
|
|
3242
|
+
latest.set(status.namespace, status.completedAt);
|
|
3243
|
+
}
|
|
3244
|
+
return latest;
|
|
3245
|
+
}
|
|
3246
|
+
async function readStatusFile(filePath) {
|
|
3247
|
+
try {
|
|
3248
|
+
const parsed = JSON.parse(await readFile3(filePath, "utf8"));
|
|
3249
|
+
return parseStatus(parsed);
|
|
3250
|
+
} catch {
|
|
3251
|
+
return null;
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
async function readStatusFiles(config) {
|
|
3255
|
+
if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
|
|
3256
|
+
return [];
|
|
3257
|
+
}
|
|
3258
|
+
const root = statusBasePath(config);
|
|
3259
|
+
const statuses = [];
|
|
3260
|
+
let jobDirs;
|
|
3261
|
+
try {
|
|
3262
|
+
jobDirs = await readdir2(root, { withFileTypes: true });
|
|
3263
|
+
} catch {
|
|
3264
|
+
return statuses;
|
|
3265
|
+
}
|
|
3266
|
+
for (const jobDir of jobDirs) {
|
|
3267
|
+
if (!jobDir.isDirectory()) continue;
|
|
3268
|
+
let files;
|
|
3269
|
+
try {
|
|
3270
|
+
files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
|
|
3271
|
+
} catch {
|
|
3272
|
+
continue;
|
|
3273
|
+
}
|
|
3274
|
+
for (const file of files) {
|
|
3275
|
+
if (!file.isFile() || !file.name.endsWith(".json")) continue;
|
|
3276
|
+
if (file.name.endsWith(".last-ran.json")) continue;
|
|
3277
|
+
const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
|
|
3278
|
+
if (status) statuses.push(status);
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
return statuses;
|
|
3282
|
+
}
|
|
3283
|
+
async function readLastRanStatusFiles(config) {
|
|
3284
|
+
if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
|
|
3285
|
+
return [];
|
|
3286
|
+
}
|
|
3287
|
+
const root = statusBasePath(config);
|
|
3288
|
+
const statuses = [];
|
|
3289
|
+
let jobDirs;
|
|
3290
|
+
try {
|
|
3291
|
+
jobDirs = await readdir2(root, { withFileTypes: true });
|
|
3292
|
+
} catch {
|
|
3293
|
+
return statuses;
|
|
3294
|
+
}
|
|
3295
|
+
for (const jobDir of jobDirs) {
|
|
3296
|
+
if (!jobDir.isDirectory()) continue;
|
|
3297
|
+
let files;
|
|
3298
|
+
try {
|
|
3299
|
+
files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
|
|
3300
|
+
} catch {
|
|
3301
|
+
continue;
|
|
3302
|
+
}
|
|
3303
|
+
for (const file of files) {
|
|
3304
|
+
if (!file.isFile() || !file.name.endsWith(".last-ran.json")) continue;
|
|
3305
|
+
const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
|
|
3306
|
+
if (status) statuses.push(status);
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
return statuses;
|
|
3310
|
+
}
|
|
3311
|
+
async function writeStatusPayload(target, status) {
|
|
3312
|
+
const dir = path3.dirname(target);
|
|
3313
|
+
await mkdir3(dir, { recursive: true });
|
|
3314
|
+
const temp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
3315
|
+
const payload = {
|
|
3316
|
+
version: 1,
|
|
3317
|
+
...status
|
|
3318
|
+
};
|
|
3319
|
+
await writeFile3(temp, `${JSON.stringify(payload, null, 2)}
|
|
3320
|
+
`, "utf8");
|
|
3321
|
+
await rename2(temp, target);
|
|
3322
|
+
}
|
|
3323
|
+
async function writeStatusFile(config, status) {
|
|
3324
|
+
await writeStatusPayload(statusPath(config, status.jobName, status.namespace), status);
|
|
3325
|
+
if (status.state === "ran") {
|
|
3326
|
+
await writeStatusPayload(lastRanStatusPath(config, status.jobName, status.namespace), status);
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
async function recordNamespaceMaintenanceStatusSafely(config, status) {
|
|
3330
|
+
try {
|
|
3331
|
+
await writeStatusFile(config, status);
|
|
3332
|
+
} catch {
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
function maintenanceErrorDetail(error) {
|
|
3336
|
+
return displayErrorDetail(error) || "Error";
|
|
3337
|
+
}
|
|
3338
|
+
async function runNamespaceMaintenanceBatchPlan(config, plan, runner, catalog, options = {}) {
|
|
3339
|
+
const statuses = [];
|
|
3340
|
+
for (const skipped of plan.skipped) {
|
|
3341
|
+
if (skipped.namespace === "*") continue;
|
|
3342
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3343
|
+
const status = {
|
|
3344
|
+
namespace: skipped.namespace,
|
|
3345
|
+
jobName: plan.jobName,
|
|
3346
|
+
state: "skipped",
|
|
3347
|
+
reason: skipped.reason,
|
|
3348
|
+
startedAt: now,
|
|
3349
|
+
completedAt: now
|
|
3350
|
+
};
|
|
3351
|
+
statuses.push(status);
|
|
3352
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3353
|
+
}
|
|
3354
|
+
const acquired = [];
|
|
3355
|
+
try {
|
|
3356
|
+
for (const candidate of plan.namespaces) {
|
|
3357
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3358
|
+
const lock = await tryAcquireNamespaceMaintenanceLock(config, plan.jobName, candidate.namespace);
|
|
3359
|
+
if (!lock) {
|
|
3360
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3361
|
+
const status = {
|
|
3362
|
+
namespace: candidate.namespace,
|
|
3363
|
+
jobName: plan.jobName,
|
|
3364
|
+
state: "skipped",
|
|
3365
|
+
reason: "lock_held",
|
|
3366
|
+
startedAt,
|
|
3367
|
+
completedAt
|
|
3368
|
+
};
|
|
3369
|
+
statuses.push(status);
|
|
3370
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3371
|
+
continue;
|
|
3372
|
+
}
|
|
3373
|
+
acquired.push({ candidate, lock, startedAt });
|
|
3374
|
+
}
|
|
3375
|
+
} catch (error) {
|
|
3376
|
+
await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
|
|
3377
|
+
throw error;
|
|
3378
|
+
}
|
|
3379
|
+
if (options.requireAllLocks && acquired.length > 0 && acquired.length < plan.namespaces.length) {
|
|
3380
|
+
for (const { candidate, startedAt } of acquired) {
|
|
3381
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3382
|
+
const status = {
|
|
3383
|
+
namespace: candidate.namespace,
|
|
3384
|
+
jobName: plan.jobName,
|
|
3385
|
+
state: "skipped",
|
|
3386
|
+
reason: "batch_lock_incomplete",
|
|
3387
|
+
startedAt,
|
|
3388
|
+
completedAt
|
|
3389
|
+
};
|
|
3390
|
+
statuses.push(status);
|
|
3391
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3392
|
+
}
|
|
3393
|
+
await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
|
|
3394
|
+
return {
|
|
3395
|
+
jobName: plan.jobName,
|
|
3396
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3397
|
+
ran: statuses.filter((s) => s.state === "ran").length,
|
|
3398
|
+
skipped: statuses.filter((s) => s.state === "skipped").length,
|
|
3399
|
+
failed: statuses.filter((s) => s.state === "failed").length,
|
|
3400
|
+
statuses
|
|
3401
|
+
};
|
|
3402
|
+
}
|
|
3403
|
+
if (acquired.length === 0) {
|
|
3404
|
+
return {
|
|
3405
|
+
jobName: plan.jobName,
|
|
3406
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3407
|
+
ran: statuses.filter((s) => s.state === "ran").length,
|
|
3408
|
+
skipped: statuses.filter((s) => s.state === "skipped").length,
|
|
3409
|
+
failed: statuses.filter((s) => s.state === "failed").length,
|
|
3410
|
+
statuses
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3413
|
+
try {
|
|
3414
|
+
const result = await withNamespaceMaintenanceLockHeartbeat(
|
|
3415
|
+
config,
|
|
3416
|
+
acquired.map(({ lock }) => lock),
|
|
3417
|
+
() => runner(acquired.map(({ candidate }) => candidate))
|
|
3418
|
+
);
|
|
3419
|
+
for (const { candidate, startedAt } of acquired) {
|
|
3420
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3421
|
+
const status = {
|
|
3422
|
+
namespace: candidate.namespace,
|
|
3423
|
+
jobName: plan.jobName,
|
|
3424
|
+
state: "ran",
|
|
3425
|
+
startedAt,
|
|
3426
|
+
completedAt,
|
|
3427
|
+
itemCount: itemCountForNamespace(result, candidate.namespace)
|
|
3428
|
+
};
|
|
3429
|
+
statuses.push(status);
|
|
3430
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3431
|
+
try {
|
|
3432
|
+
await catalog?.markMaintenance(candidate.namespace, plan.jobName, new Date(completedAt));
|
|
3433
|
+
} catch {
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
} catch (error) {
|
|
3437
|
+
const skipReason = options.skipReasonForError?.(error);
|
|
3438
|
+
for (const { candidate, startedAt } of acquired) {
|
|
3439
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3440
|
+
const status = skipReason ? {
|
|
3441
|
+
namespace: candidate.namespace,
|
|
3442
|
+
jobName: plan.jobName,
|
|
3443
|
+
state: "skipped",
|
|
3444
|
+
reason: skipReason,
|
|
3445
|
+
startedAt,
|
|
3446
|
+
completedAt
|
|
3447
|
+
} : {
|
|
3448
|
+
namespace: candidate.namespace,
|
|
3449
|
+
jobName: plan.jobName,
|
|
3450
|
+
state: "failed",
|
|
3451
|
+
reason: "job_failed",
|
|
3452
|
+
startedAt,
|
|
3453
|
+
completedAt,
|
|
3454
|
+
error: maintenanceErrorDetail(error)
|
|
3455
|
+
};
|
|
3456
|
+
statuses.push(status);
|
|
3457
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3458
|
+
}
|
|
3459
|
+
} finally {
|
|
3460
|
+
await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
|
|
3461
|
+
}
|
|
3462
|
+
return {
|
|
3463
|
+
jobName: plan.jobName,
|
|
3464
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3465
|
+
ran: statuses.filter((s) => s.state === "ran").length,
|
|
3466
|
+
skipped: statuses.filter((s) => s.state === "skipped").length,
|
|
3467
|
+
failed: statuses.filter((s) => s.state === "failed").length,
|
|
3468
|
+
statuses
|
|
3469
|
+
};
|
|
3470
|
+
}
|
|
3471
|
+
function itemCountForNamespace(result, namespace) {
|
|
3472
|
+
const itemCounts = result?.itemCounts;
|
|
3473
|
+
if (itemCounts instanceof Map) return itemCounts.get(namespace);
|
|
3474
|
+
if (itemCounts && Object.prototype.hasOwnProperty.call(itemCounts, namespace)) {
|
|
3475
|
+
return itemCounts[namespace];
|
|
3476
|
+
}
|
|
3477
|
+
return result?.itemCount;
|
|
3478
|
+
}
|
|
3479
|
+
|
|
2868
3480
|
// src/orchestrator.ts
|
|
2869
3481
|
var BulkImportBatchPartialFailureError = class extends Error {
|
|
2870
3482
|
partialResult;
|
|
@@ -2926,7 +3538,7 @@ function flattenStructuredSectionEvidence(sections) {
|
|
|
2926
3538
|
);
|
|
2927
3539
|
}
|
|
2928
3540
|
function fingerprintEntitySynthesisEvidence(entity) {
|
|
2929
|
-
const fingerprint =
|
|
3541
|
+
const fingerprint = createHash2("sha256");
|
|
2930
3542
|
const timelineEntries = entity.timeline.map((entry) => [
|
|
2931
3543
|
entry.timestamp,
|
|
2932
3544
|
entry.source ?? "",
|
|
@@ -2976,7 +3588,7 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
|
|
|
2976
3588
|
}
|
|
2977
3589
|
}
|
|
2978
3590
|
function qmdCollectionPathParts(resultPath) {
|
|
2979
|
-
if (!resultPath ||
|
|
3591
|
+
if (!resultPath || path4.isAbsolute(resultPath)) return null;
|
|
2980
3592
|
const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2981
3593
|
const slashIndex = normalized.indexOf("/");
|
|
2982
3594
|
if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
|
|
@@ -2989,9 +3601,9 @@ function qmdCollectionPathParts(resultPath) {
|
|
|
2989
3601
|
}
|
|
2990
3602
|
function qmdResultPathCandidates(storageDir, resultPath) {
|
|
2991
3603
|
const candidates = /* @__PURE__ */ new Set();
|
|
2992
|
-
const storageRoot =
|
|
3604
|
+
const storageRoot = path4.resolve(storageDir);
|
|
2993
3605
|
const addCandidate = (candidate) => {
|
|
2994
|
-
const resolved =
|
|
3606
|
+
const resolved = path4.resolve(candidate);
|
|
2995
3607
|
if (isPathInsideStorageRoot(storageRoot, resolved)) {
|
|
2996
3608
|
candidates.add(resolved);
|
|
2997
3609
|
}
|
|
@@ -2999,12 +3611,12 @@ function qmdResultPathCandidates(storageDir, resultPath) {
|
|
|
2999
3611
|
const addRelativeCandidates = (relativePath) => {
|
|
3000
3612
|
const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3001
3613
|
if (!normalized) return;
|
|
3002
|
-
addCandidate(
|
|
3614
|
+
addCandidate(path4.join(storageRoot, normalized));
|
|
3003
3615
|
if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
|
|
3004
|
-
addCandidate(
|
|
3616
|
+
addCandidate(path4.join(storageRoot, "facts", normalized));
|
|
3005
3617
|
}
|
|
3006
3618
|
};
|
|
3007
|
-
if (
|
|
3619
|
+
if (path4.isAbsolute(resultPath)) {
|
|
3008
3620
|
addCandidate(resultPath);
|
|
3009
3621
|
} else {
|
|
3010
3622
|
addRelativeCandidates(resultPath);
|
|
@@ -3121,11 +3733,11 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
|
|
|
3121
3733
|
return await Promise.race([checkedPromise, timeoutPromise]);
|
|
3122
3734
|
}
|
|
3123
3735
|
function defaultWorkspaceDir() {
|
|
3124
|
-
return
|
|
3736
|
+
return path4.join(os.homedir(), ".openclaw", "workspace");
|
|
3125
3737
|
}
|
|
3126
3738
|
function sanitizeSessionKeyForFilename(sessionKey) {
|
|
3127
3739
|
const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
3128
|
-
const hash =
|
|
3740
|
+
const hash = createHash2("sha256").update(sessionKey).digest("hex").slice(0, 12);
|
|
3129
3741
|
return `${readable}-${hash}`;
|
|
3130
3742
|
}
|
|
3131
3743
|
function latestSourceValidAtFromTurns(turns) {
|
|
@@ -3426,11 +4038,11 @@ function mergeGraphExpandedResults(primary, expanded) {
|
|
|
3426
4038
|
return Array.from(mergedByPath.values());
|
|
3427
4039
|
}
|
|
3428
4040
|
function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
3429
|
-
const absolutePath =
|
|
3430
|
-
const rel =
|
|
4041
|
+
const absolutePath = path4.isAbsolute(candidatePath) ? candidatePath : path4.resolve(storageDir, candidatePath);
|
|
4042
|
+
const rel = path4.relative(storageDir, absolutePath);
|
|
3431
4043
|
if (!rel || rel === ".") return null;
|
|
3432
4044
|
if (rel.startsWith("..")) return null;
|
|
3433
|
-
return rel.split(
|
|
4045
|
+
return rel.split(path4.sep).join("/");
|
|
3434
4046
|
}
|
|
3435
4047
|
function normalizeGraphActivationScore(score) {
|
|
3436
4048
|
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
@@ -3572,7 +4184,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
|
|
|
3572
4184
|
for (const mem of allMemsForGraph ?? []) {
|
|
3573
4185
|
const id = mem.frontmatter.id;
|
|
3574
4186
|
if (!id) continue;
|
|
3575
|
-
pathById.set(id,
|
|
4187
|
+
pathById.set(id, path4.relative(storageDir, mem.path));
|
|
3576
4188
|
}
|
|
3577
4189
|
return pathById;
|
|
3578
4190
|
}
|
|
@@ -3580,7 +4192,7 @@ function appendMemoryToGraphContext(options) {
|
|
|
3580
4192
|
if (!Array.isArray(options.allMemsForGraph)) return;
|
|
3581
4193
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
3582
4194
|
options.allMemsForGraph.push({
|
|
3583
|
-
path:
|
|
4195
|
+
path: path4.join(options.storageDir, options.memoryRelPath),
|
|
3584
4196
|
content: options.content,
|
|
3585
4197
|
frontmatter: {
|
|
3586
4198
|
id: options.memoryId,
|
|
@@ -3600,16 +4212,20 @@ function resolvePersistedMemoryRelativePath(options) {
|
|
|
3600
4212
|
const persisted = options.pathById.get(options.memoryId);
|
|
3601
4213
|
if (persisted) return persisted;
|
|
3602
4214
|
if (options.category === "correction") {
|
|
3603
|
-
return
|
|
4215
|
+
return path4.join("corrections", `${options.memoryId}.md`);
|
|
3604
4216
|
}
|
|
3605
4217
|
const subtree = options.category === "procedure" ? "procedures" : options.category === "reasoning_trace" ? "reasoning-traces" : "facts";
|
|
3606
4218
|
const idParts = options.memoryId.split("-");
|
|
3607
4219
|
const maybeTimestamp = Number(idParts[1]);
|
|
3608
4220
|
if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
|
|
3609
4221
|
const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
|
|
3610
|
-
return
|
|
4222
|
+
return path4.join(subtree, day, `${options.memoryId}.md`);
|
|
3611
4223
|
}
|
|
3612
|
-
return
|
|
4224
|
+
return path4.join(subtree, `${options.memoryId}.md`);
|
|
4225
|
+
}
|
|
4226
|
+
function qmdMaintenanceSkipReasonForError(error) {
|
|
4227
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4228
|
+
return /^QMD (?:update|embed) skipped by .*min-interval gate$/.test(message) ? "throttled" : null;
|
|
3613
4229
|
}
|
|
3614
4230
|
var Orchestrator = class _Orchestrator {
|
|
3615
4231
|
storage;
|
|
@@ -3716,6 +4332,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3716
4332
|
_peerIdBySession = /* @__PURE__ */ new Map();
|
|
3717
4333
|
routingRulesStore = null;
|
|
3718
4334
|
contentHashIndex = null;
|
|
4335
|
+
contentHashIndexesByStorageDir = /* @__PURE__ */ new Map();
|
|
3719
4336
|
artifactSourceStatusCache = /* @__PURE__ */ new WeakMap();
|
|
3720
4337
|
static ARTIFACT_STATUS_CACHE_TTL_MS = 6e4;
|
|
3721
4338
|
// Access tracking buffer (Phase 1A)
|
|
@@ -3737,6 +4354,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3737
4354
|
qmdMaintenancePending = false;
|
|
3738
4355
|
qmdMaintenanceInFlight = false;
|
|
3739
4356
|
lastQmdEmbedAtMs = 0;
|
|
4357
|
+
lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map();
|
|
3740
4358
|
lastQmdReprobeAtMs = 0;
|
|
3741
4359
|
tierMigrationInFlight = false;
|
|
3742
4360
|
lastTierMigrationRunAtMs = 0;
|
|
@@ -4038,7 +4656,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4038
4656
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
4039
4657
|
if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
|
|
4040
4658
|
if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
|
|
4041
|
-
const resolvedStorageDir =
|
|
4659
|
+
const resolvedStorageDir = path4.resolve(storageDir);
|
|
4042
4660
|
let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
|
|
4043
4661
|
if (!hints) {
|
|
4044
4662
|
hints = /* @__PURE__ */ new Set();
|
|
@@ -4049,21 +4667,21 @@ var Orchestrator = class _Orchestrator {
|
|
|
4049
4667
|
storageDirMatchesNamespaceHint(namespace, storageDir) {
|
|
4050
4668
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
4051
4669
|
if (!ns) return false;
|
|
4052
|
-
const resolvedStorageDir =
|
|
4053
|
-
const resolvedMemoryDir =
|
|
4670
|
+
const resolvedStorageDir = path4.resolve(storageDir);
|
|
4671
|
+
const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
|
|
4054
4672
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
4055
4673
|
if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
|
|
4056
|
-
const resolvedNamespacesDir =
|
|
4674
|
+
const resolvedNamespacesDir = path4.join(resolvedMemoryDir, "namespaces");
|
|
4057
4675
|
if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
|
|
4058
|
-
const rawRoot =
|
|
4059
|
-
const tokenRoot =
|
|
4676
|
+
const rawRoot = path4.resolve(resolvedNamespacesDir, ns);
|
|
4677
|
+
const tokenRoot = path4.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
|
|
4060
4678
|
return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
|
|
4061
4679
|
}
|
|
4062
4680
|
namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
|
|
4063
|
-
if (resolvedStorageDir ===
|
|
4681
|
+
if (resolvedStorageDir === path4.resolve(this.config.memoryDir)) {
|
|
4064
4682
|
return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
|
|
4065
4683
|
}
|
|
4066
|
-
const leaf =
|
|
4684
|
+
const leaf = path4.basename(resolvedStorageDir);
|
|
4067
4685
|
const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
|
|
4068
4686
|
if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
|
|
4069
4687
|
if (record.namespace === leaf) return 1;
|
|
@@ -4091,7 +4709,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4091
4709
|
loadNamespaceStorageDirHintsFromCatalog() {
|
|
4092
4710
|
if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
|
|
4093
4711
|
this.namespaceStorageDirHintsLoaded = true;
|
|
4094
|
-
const catalogPath =
|
|
4712
|
+
const catalogPath = path4.join(this.config.memoryDir, "state", "namespaces.jsonl");
|
|
4095
4713
|
if (!existsSync(catalogPath)) return;
|
|
4096
4714
|
let body;
|
|
4097
4715
|
try {
|
|
@@ -4128,7 +4746,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4128
4746
|
if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
|
|
4129
4747
|
continue;
|
|
4130
4748
|
}
|
|
4131
|
-
const resolvedStorageDir =
|
|
4749
|
+
const resolvedStorageDir = path4.resolve(record.storageDir);
|
|
4132
4750
|
const current = preferredByStorageDir.get(resolvedStorageDir);
|
|
4133
4751
|
preferredByStorageDir.set(
|
|
4134
4752
|
resolvedStorageDir,
|
|
@@ -4145,57 +4763,27 @@ var Orchestrator = class _Orchestrator {
|
|
|
4145
4763
|
}
|
|
4146
4764
|
}
|
|
4147
4765
|
/**
|
|
4148
|
-
*
|
|
4149
|
-
*
|
|
4150
|
-
*
|
|
4151
|
-
*
|
|
4152
|
-
*
|
|
4153
|
-
*
|
|
4154
|
-
*
|
|
4155
|
-
* the catalog's namespaces so maintenance keeps dynamic namespaces fresh.
|
|
4156
|
-
* `updateNamespaces`/`embedNamespaces` already trim, dedup, and skip
|
|
4157
|
-
* unavailable/missing collections, so extra names are filtered safely. A catalog
|
|
4158
|
-
* read failure must never break maintenance — fall back to the configured set.
|
|
4766
|
+
* Shared namespace maintenance planner (issue #1500). This extends the
|
|
4767
|
+
* #1499 catalog-union QMD helper into a reusable contract: configured
|
|
4768
|
+
* namespaces are always considered, dynamic catalog namespaces are admitted
|
|
4769
|
+
* only when their live router root still matches real memory data, and branch
|
|
4770
|
+
* namespaces are opt-in. Recurring jobs use the per-cycle budget; startup and
|
|
4771
|
+
* recovery discovery paths use the same safety filters without that cycle
|
|
4772
|
+
* budget so every live namespace is ensured/synced.
|
|
4159
4773
|
*/
|
|
4160
|
-
async
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
try {
|
|
4166
|
-
const records = await this.namespaceCatalog.listNamespaces();
|
|
4167
|
-
const safeRecords = await Promise.all(
|
|
4168
|
-
records.map(async (record) => {
|
|
4169
|
-
const namespace = record.namespace.trim();
|
|
4170
|
-
if (!namespace || configuredSet.has(namespace)) return null;
|
|
4171
|
-
return await this.isCatalogedMaintenanceRootLive(record) ? namespace : null;
|
|
4172
|
-
})
|
|
4173
|
-
);
|
|
4174
|
-
cataloged = safeRecords.filter(
|
|
4175
|
-
(namespace) => namespace !== null
|
|
4176
|
-
);
|
|
4177
|
-
} catch {
|
|
4178
|
-
cataloged = [];
|
|
4179
|
-
}
|
|
4180
|
-
return Array.from(
|
|
4181
|
-
new Set(
|
|
4182
|
-
[...configured, ...cataloged].map((value) => value.trim()).filter(Boolean)
|
|
4183
|
-
)
|
|
4184
|
-
);
|
|
4774
|
+
async namespaceMaintenancePlan(jobName) {
|
|
4775
|
+
return planNamespaceMaintenance(this.config, {
|
|
4776
|
+
jobName,
|
|
4777
|
+
catalog: this.namespaceCatalog
|
|
4778
|
+
});
|
|
4185
4779
|
}
|
|
4186
|
-
async
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
return false;
|
|
4194
|
-
}
|
|
4195
|
-
return hasMemoryData(liveRoot);
|
|
4196
|
-
} catch {
|
|
4197
|
-
return false;
|
|
4198
|
-
}
|
|
4780
|
+
async maintenanceNamespaces(jobName = "qmd", budgetMode = "unbounded") {
|
|
4781
|
+
const plan = await planNamespaceMaintenance(this.config, {
|
|
4782
|
+
jobName,
|
|
4783
|
+
catalog: this.namespaceCatalog,
|
|
4784
|
+
budgetMode
|
|
4785
|
+
});
|
|
4786
|
+
return plan.namespaces.map((candidate) => candidate.namespace);
|
|
4199
4787
|
}
|
|
4200
4788
|
buildConfiguredQmdSearchOptions(queryText) {
|
|
4201
4789
|
const intentHint = this.config.qmdIntentHintsEnabled ? buildQmdIntentHint(inferIntentFromText(queryText)) : void 0;
|
|
@@ -4210,6 +4798,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
4210
4798
|
return Object.keys(searchOptions).length > 0 ? searchOptions : void 0;
|
|
4211
4799
|
}
|
|
4212
4800
|
async searchAcrossNamespaces(options) {
|
|
4801
|
+
if (this.config.namespacesEnabled && options.namespaces !== void 0 && options.namespaces.length === 0) {
|
|
4802
|
+
return [];
|
|
4803
|
+
}
|
|
4213
4804
|
const namespaces = this.config.namespacesEnabled ? Array.from(
|
|
4214
4805
|
new Set(
|
|
4215
4806
|
(options.namespaces?.length ? options.namespaces : this.configuredNamespaces()).map((value) => value.trim()).filter(Boolean)
|
|
@@ -4266,12 +4857,63 @@ var Orchestrator = class _Orchestrator {
|
|
|
4266
4857
|
}
|
|
4267
4858
|
invalidateLiveContentHashIndex() {
|
|
4268
4859
|
this.contentHashIndex = null;
|
|
4860
|
+
this.contentHashIndexesByStorageDir.clear();
|
|
4861
|
+
}
|
|
4862
|
+
async contentHashIndexForStorage(targetStorage) {
|
|
4863
|
+
if (!this.config.factDeduplicationEnabled) return null;
|
|
4864
|
+
if (targetStorage.dir === this.storage.dir) {
|
|
4865
|
+
if (!this.contentHashIndex) {
|
|
4866
|
+
this.contentHashIndex = this.storage.createContentHashIndex();
|
|
4867
|
+
await this.contentHashIndex.load();
|
|
4868
|
+
}
|
|
4869
|
+
return this.contentHashIndex;
|
|
4870
|
+
}
|
|
4871
|
+
const cached = this.contentHashIndexesByStorageDir.get(targetStorage.dir);
|
|
4872
|
+
if (cached) return cached;
|
|
4873
|
+
const index = targetStorage.createContentHashIndex();
|
|
4874
|
+
await index.load();
|
|
4875
|
+
this.contentHashIndexesByStorageDir.set(targetStorage.dir, index);
|
|
4876
|
+
log.info(
|
|
4877
|
+
`content-hash dedup: loaded ${index.size} hashes for storage ${targetStorage.dir}`
|
|
4878
|
+
);
|
|
4879
|
+
return index;
|
|
4880
|
+
}
|
|
4881
|
+
async hasContentHashDedup(targetStorage, content) {
|
|
4882
|
+
const index = await this.contentHashIndexForStorage(targetStorage);
|
|
4883
|
+
return index ? index.has(content) : false;
|
|
4884
|
+
}
|
|
4885
|
+
async addContentHashDedup(targetStorage, content) {
|
|
4886
|
+
const index = await this.contentHashIndexForStorage(targetStorage);
|
|
4887
|
+
if (!index) return;
|
|
4888
|
+
index.add(content);
|
|
4889
|
+
}
|
|
4890
|
+
async removeContentHashForMemory(targetStorage, memory, context) {
|
|
4891
|
+
const index = await this.contentHashIndexForStorage(targetStorage);
|
|
4892
|
+
if (!index) return;
|
|
4893
|
+
if (memory.frontmatter.contentHash) {
|
|
4894
|
+
index.removeByHash(memory.frontmatter.contentHash);
|
|
4895
|
+
return;
|
|
4896
|
+
}
|
|
4897
|
+
log.warn(
|
|
4898
|
+
`[${context}] removing hash for legacy memory ${memory.frontmatter.id ?? "(unknown)"} via content fallback - no contentHash in frontmatter`
|
|
4899
|
+
);
|
|
4900
|
+
index.remove(memory.content);
|
|
4901
|
+
}
|
|
4902
|
+
async saveContentHashIndexes() {
|
|
4903
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
4904
|
+
if (this.contentHashIndex) indexes.add(this.contentHashIndex);
|
|
4905
|
+
for (const index of this.contentHashIndexesByStorageDir.values()) {
|
|
4906
|
+
indexes.add(index);
|
|
4907
|
+
}
|
|
4908
|
+
for (const index of indexes) {
|
|
4909
|
+
await index.save();
|
|
4910
|
+
}
|
|
4269
4911
|
}
|
|
4270
4912
|
constructor(config) {
|
|
4271
4913
|
this.config = config;
|
|
4272
4914
|
this.profiler = new ProfilingCollector({
|
|
4273
4915
|
enabled: config.profilingEnabled,
|
|
4274
|
-
storageDir: config.profilingStorageDir ||
|
|
4916
|
+
storageDir: config.profilingStorageDir || path4.join(config.memoryDir, "profiling"),
|
|
4275
4917
|
maxTraces: config.profilingMaxTraces
|
|
4276
4918
|
});
|
|
4277
4919
|
this.namespaceCatalog = new NamespaceCatalog(config);
|
|
@@ -4316,7 +4958,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4316
4958
|
this.compounding = config.compoundingEnabled ? new CompoundingEngine(config, this.storage) : void 0;
|
|
4317
4959
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
4318
4960
|
this.transcript = new TranscriptManager(config);
|
|
4319
|
-
this.conversationIndexDir =
|
|
4961
|
+
this.conversationIndexDir = path4.join(
|
|
4320
4962
|
config.memoryDir,
|
|
4321
4963
|
"conversation-index",
|
|
4322
4964
|
"chunks"
|
|
@@ -4373,7 +5015,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4373
5015
|
this.modelRegistry
|
|
4374
5016
|
);
|
|
4375
5017
|
this.threading = new ThreadingManager(
|
|
4376
|
-
|
|
5018
|
+
path4.join(config.memoryDir, "threads"),
|
|
4377
5019
|
config.threadingGapMinutes
|
|
4378
5020
|
);
|
|
4379
5021
|
this.tmtBuilder = new TmtBuilder(config.memoryDir, {
|
|
@@ -4452,7 +5094,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4452
5094
|
utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
|
|
4453
5095
|
utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
|
|
4454
5096
|
};
|
|
4455
|
-
return
|
|
5097
|
+
return createHash2("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
|
|
4456
5098
|
}
|
|
4457
5099
|
effectiveLifecycleThresholds() {
|
|
4458
5100
|
const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
|
|
@@ -4672,11 +5314,11 @@ var Orchestrator = class _Orchestrator {
|
|
|
4672
5314
|
if (this.config.compactionResetEnabled) {
|
|
4673
5315
|
try {
|
|
4674
5316
|
const wsDir = this.config.workspaceDir || defaultWorkspaceDir();
|
|
4675
|
-
const files = await
|
|
5317
|
+
const files = await readdir3(wsDir).catch(() => []);
|
|
4676
5318
|
for (const f of files) {
|
|
4677
5319
|
if (!f.startsWith(".compaction-reset-signal-")) continue;
|
|
4678
|
-
const fp =
|
|
4679
|
-
const s = await
|
|
5320
|
+
const fp = path4.join(wsDir, f);
|
|
5321
|
+
const s = await stat3(fp).catch(() => null);
|
|
4680
5322
|
if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
|
|
4681
5323
|
await unlink2(fp).catch(() => {
|
|
4682
5324
|
});
|
|
@@ -4954,9 +5596,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
4954
5596
|
`wearables auto-sync started: every ${this.config.wearables.autoSyncIntervalMinutes}m over ${this.config.wearables.autoSyncDays}d (deep ${this.config.wearables.autoSyncDeepDays}d daily)`
|
|
4955
5597
|
);
|
|
4956
5598
|
} catch (err) {
|
|
4957
|
-
const { displayErrorDetail } = await import("./runtime/better-sqlite.js");
|
|
5599
|
+
const { displayErrorDetail: displayErrorDetail2 } = await import("./runtime/better-sqlite.js");
|
|
4958
5600
|
log.warn(
|
|
4959
|
-
`wearables auto-sync failed to start (non-fatal): ${
|
|
5601
|
+
`wearables auto-sync failed to start (non-fatal): ${displayErrorDetail2(err)}`
|
|
4960
5602
|
);
|
|
4961
5603
|
}
|
|
4962
5604
|
}
|
|
@@ -5069,7 +5711,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5069
5711
|
*/
|
|
5070
5712
|
async autoRegisterDaySummaryCron() {
|
|
5071
5713
|
const home = resolveHomeDir();
|
|
5072
|
-
const jobsPath =
|
|
5714
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5073
5715
|
try {
|
|
5074
5716
|
if (!existsSync(jobsPath)) {
|
|
5075
5717
|
log.debug(
|
|
@@ -5122,7 +5764,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5122
5764
|
}
|
|
5123
5765
|
async autoRegisterNightlyGovernanceCron() {
|
|
5124
5766
|
const home = resolveHomeDir();
|
|
5125
|
-
const jobsPath =
|
|
5767
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5126
5768
|
try {
|
|
5127
5769
|
if (!existsSync(jobsPath)) {
|
|
5128
5770
|
log.debug("nightly governance cron: jobs.json not found, skipping auto-register");
|
|
@@ -5144,7 +5786,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5144
5786
|
}
|
|
5145
5787
|
async autoRegisterProceduralMiningCron() {
|
|
5146
5788
|
const home = resolveHomeDir();
|
|
5147
|
-
const jobsPath =
|
|
5789
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5148
5790
|
try {
|
|
5149
5791
|
if (!existsSync(jobsPath)) {
|
|
5150
5792
|
log.debug("procedural mining cron: jobs.json not found, skipping auto-register");
|
|
@@ -5164,7 +5806,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5164
5806
|
}
|
|
5165
5807
|
async autoRegisterContradictionScanCron() {
|
|
5166
5808
|
const home = resolveHomeDir();
|
|
5167
|
-
const jobsPath =
|
|
5809
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5168
5810
|
try {
|
|
5169
5811
|
if (!existsSync(jobsPath)) {
|
|
5170
5812
|
log.debug("contradiction scan cron: jobs.json not found, skipping auto-register");
|
|
@@ -5184,7 +5826,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5184
5826
|
}
|
|
5185
5827
|
async autoRegisterPatternReinforcementCron() {
|
|
5186
5828
|
const home = resolveHomeDir();
|
|
5187
|
-
const jobsPath =
|
|
5829
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5188
5830
|
try {
|
|
5189
5831
|
if (!existsSync(jobsPath)) {
|
|
5190
5832
|
log.debug("pattern reinforcement cron: jobs.json not found, skipping auto-register");
|
|
@@ -5246,7 +5888,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5246
5888
|
}
|
|
5247
5889
|
async autoRegisterGraphEdgeDecayCron() {
|
|
5248
5890
|
const home = resolveHomeDir();
|
|
5249
|
-
const jobsPath =
|
|
5891
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5250
5892
|
try {
|
|
5251
5893
|
if (!existsSync(jobsPath)) {
|
|
5252
5894
|
log.debug("graph edge decay cron: jobs.json not found, skipping auto-register");
|
|
@@ -5303,15 +5945,15 @@ ${doc.content}` : doc.content,
|
|
|
5303
5945
|
this.lastFileHygieneRunAtMs = now;
|
|
5304
5946
|
if (hygiene.rotateEnabled) {
|
|
5305
5947
|
for (const rel of hygiene.rotatePaths) {
|
|
5306
|
-
const abs =
|
|
5948
|
+
const abs = path4.isAbsolute(rel) ? rel : path4.join(this.config.workspaceDir, rel);
|
|
5307
5949
|
try {
|
|
5308
|
-
const raw = await
|
|
5950
|
+
const raw = await readFile4(abs, "utf-8");
|
|
5309
5951
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
5310
|
-
const archiveDir =
|
|
5952
|
+
const archiveDir = path4.join(
|
|
5311
5953
|
this.config.workspaceDir,
|
|
5312
5954
|
hygiene.archiveDir
|
|
5313
5955
|
);
|
|
5314
|
-
const base =
|
|
5956
|
+
const base = path4.basename(abs);
|
|
5315
5957
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
5316
5958
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
5317
5959
|
filePath: abs,
|
|
@@ -5319,7 +5961,7 @@ ${doc.content}` : doc.content,
|
|
|
5319
5961
|
archivePrefix: prefix,
|
|
5320
5962
|
keepTailChars: hygiene.rotateKeepTailChars
|
|
5321
5963
|
});
|
|
5322
|
-
await
|
|
5964
|
+
await writeFile4(abs, newContent, "utf-8");
|
|
5323
5965
|
}
|
|
5324
5966
|
} catch {
|
|
5325
5967
|
}
|
|
@@ -5336,8 +5978,8 @@ ${doc.content}` : doc.content,
|
|
|
5336
5978
|
log.warn(w.message);
|
|
5337
5979
|
}
|
|
5338
5980
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
5339
|
-
const fp =
|
|
5340
|
-
await
|
|
5981
|
+
const fp = path4.join(this.config.memoryDir, hygiene.warningsLogPath);
|
|
5982
|
+
await mkdir4(path4.dirname(fp), { recursive: true });
|
|
5341
5983
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
5342
5984
|
const block = `
|
|
5343
5985
|
|
|
@@ -5346,11 +5988,11 @@ ${doc.content}` : doc.content,
|
|
|
5346
5988
|
` + warnings.map((w) => `- ${w.message}`).join("\n") + "\n";
|
|
5347
5989
|
let existing = "";
|
|
5348
5990
|
try {
|
|
5349
|
-
existing = await
|
|
5991
|
+
existing = await readFile4(fp, "utf-8");
|
|
5350
5992
|
} catch {
|
|
5351
5993
|
existing = "# Engram File Hygiene Warnings\n";
|
|
5352
5994
|
}
|
|
5353
|
-
await
|
|
5995
|
+
await writeFile4(fp, existing + block, "utf-8");
|
|
5354
5996
|
}
|
|
5355
5997
|
}
|
|
5356
5998
|
}
|
|
@@ -5545,16 +6187,11 @@ ${doc.content}` : doc.content,
|
|
|
5545
6187
|
relatedMemoryIds: [canonicalId]
|
|
5546
6188
|
});
|
|
5547
6189
|
if (archiveResult) {
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
`[semantic-consolidation] removing hash for legacy memory ${m.frontmatter.id ?? "(unknown)"} via content fallback \u2014 no contentHash in frontmatter`
|
|
5554
|
-
);
|
|
5555
|
-
this.contentHashIndex.remove(m.content);
|
|
5556
|
-
}
|
|
5557
|
-
}
|
|
6190
|
+
await this.removeContentHashForMemory(
|
|
6191
|
+
targetStorage,
|
|
6192
|
+
m,
|
|
6193
|
+
"semantic-consolidation"
|
|
6194
|
+
);
|
|
5558
6195
|
try {
|
|
5559
6196
|
await this.embeddingFallback.removeFromIndex(m.frontmatter.id);
|
|
5560
6197
|
if (this.config.queryAwareIndexingEnabled && m.path && m.frontmatter?.created) {
|
|
@@ -5590,8 +6227,8 @@ ${doc.content}` : doc.content,
|
|
|
5590
6227
|
}
|
|
5591
6228
|
}
|
|
5592
6229
|
}
|
|
5593
|
-
if (result.memoriesArchived > 0
|
|
5594
|
-
await this.
|
|
6230
|
+
if (result.memoriesArchived > 0) {
|
|
6231
|
+
await this.saveContentHashIndexes().catch(
|
|
5595
6232
|
(err) => log.warn(
|
|
5596
6233
|
`[semantic-consolidation] content-hash index save failed: ${err}`
|
|
5597
6234
|
)
|
|
@@ -5820,18 +6457,18 @@ ${evidenceText}`
|
|
|
5820
6457
|
const now = options.now instanceof Date && Number.isFinite(options.now.getTime()) ? options.now : /* @__PURE__ */ new Date();
|
|
5821
6458
|
const targetLocalDate = formatDateInTimeZone(now, timeZone);
|
|
5822
6459
|
const datesToScan = utcDateKeysForLocalDay(now, timeZone);
|
|
5823
|
-
const factsBaseDir =
|
|
6460
|
+
const factsBaseDir = path4.join(storage.dir, "facts");
|
|
5824
6461
|
const MAX_CHARS = 1e5;
|
|
5825
6462
|
const facts = [];
|
|
5826
6463
|
for (const date of datesToScan) {
|
|
5827
|
-
const factsDir =
|
|
6464
|
+
const factsDir = path4.join(factsBaseDir, date);
|
|
5828
6465
|
try {
|
|
5829
|
-
const entries = await
|
|
6466
|
+
const entries = await readdir3(factsDir, { withFileTypes: true });
|
|
5830
6467
|
for (const entry of entries) {
|
|
5831
6468
|
if (!entry.name.endsWith(".md")) continue;
|
|
5832
|
-
const fullPath =
|
|
6469
|
+
const fullPath = path4.join(factsDir, entry.name);
|
|
5833
6470
|
try {
|
|
5834
|
-
const raw = await
|
|
6471
|
+
const raw = await readFile4(fullPath, "utf-8");
|
|
5835
6472
|
const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
5836
6473
|
if (!fmMatch) continue;
|
|
5837
6474
|
const fmBlock = fmMatch[1];
|
|
@@ -5850,7 +6487,7 @@ ${evidenceText}`
|
|
|
5850
6487
|
facts.push({
|
|
5851
6488
|
path: fullPath,
|
|
5852
6489
|
frontmatter: {
|
|
5853
|
-
id: fm.id ||
|
|
6490
|
+
id: fm.id || path4.basename(entry.name, ".md"),
|
|
5854
6491
|
category: fm.category || "fact",
|
|
5855
6492
|
created,
|
|
5856
6493
|
updated: fm.updated || created,
|
|
@@ -5872,15 +6509,15 @@ ${evidenceText}`
|
|
|
5872
6509
|
return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
|
|
5873
6510
|
});
|
|
5874
6511
|
const hourlySummaries = [];
|
|
5875
|
-
const hourlyBaseDir =
|
|
6512
|
+
const hourlyBaseDir = path4.join(storage.dir, "summaries", "hourly");
|
|
5876
6513
|
try {
|
|
5877
|
-
const sessionKeys = await
|
|
6514
|
+
const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
|
|
5878
6515
|
for (const sk of sessionKeys) {
|
|
5879
6516
|
if (!sk.isDirectory()) continue;
|
|
5880
6517
|
for (const date of datesToScan) {
|
|
5881
|
-
const summaryFile =
|
|
6518
|
+
const summaryFile = path4.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
5882
6519
|
try {
|
|
5883
|
-
const raw = await
|
|
6520
|
+
const raw = await readFile4(summaryFile, "utf-8");
|
|
5884
6521
|
const filtered = filterHourlySummaryMarkdownForLocalDay(
|
|
5885
6522
|
raw,
|
|
5886
6523
|
date,
|
|
@@ -5982,13 +6619,13 @@ ${evidenceText}`
|
|
|
5982
6619
|
}
|
|
5983
6620
|
async getLastGraphRecallSnapshot(namespace) {
|
|
5984
6621
|
const storage = await this.getStorage(namespace);
|
|
5985
|
-
const snapshotPath =
|
|
6622
|
+
const snapshotPath = path4.join(
|
|
5986
6623
|
storage.dir,
|
|
5987
6624
|
"state",
|
|
5988
6625
|
"last_graph_recall.json"
|
|
5989
6626
|
);
|
|
5990
6627
|
try {
|
|
5991
|
-
const raw = await
|
|
6628
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
5992
6629
|
const parsed = JSON.parse(raw);
|
|
5993
6630
|
if (!parsed || typeof parsed !== "object") return null;
|
|
5994
6631
|
return {
|
|
@@ -6021,9 +6658,9 @@ ${evidenceText}`
|
|
|
6021
6658
|
}
|
|
6022
6659
|
async getLastIntentSnapshot(namespace) {
|
|
6023
6660
|
const storage = await this.getStorage(namespace);
|
|
6024
|
-
const snapshotPath =
|
|
6661
|
+
const snapshotPath = path4.join(storage.dir, "state", "last_intent.json");
|
|
6025
6662
|
try {
|
|
6026
|
-
const raw = await
|
|
6663
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
6027
6664
|
const parsed = JSON.parse(raw);
|
|
6028
6665
|
if (!parsed || typeof parsed !== "object") return null;
|
|
6029
6666
|
const graphDecision = parsed.graphDecision && typeof parsed.graphDecision === "object" ? parsed.graphDecision : void 0;
|
|
@@ -6054,13 +6691,13 @@ ${evidenceText}`
|
|
|
6054
6691
|
}
|
|
6055
6692
|
async getLastQmdRecallSnapshot(namespace) {
|
|
6056
6693
|
const storage = await this.getStorage(namespace);
|
|
6057
|
-
const snapshotPath =
|
|
6694
|
+
const snapshotPath = path4.join(
|
|
6058
6695
|
storage.dir,
|
|
6059
6696
|
"state",
|
|
6060
6697
|
"last_qmd_recall.json"
|
|
6061
6698
|
);
|
|
6062
6699
|
try {
|
|
6063
|
-
const raw = await
|
|
6700
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
6064
6701
|
const parsed = JSON.parse(raw);
|
|
6065
6702
|
if (!parsed || typeof parsed !== "object") return null;
|
|
6066
6703
|
return {
|
|
@@ -6204,10 +6841,10 @@ ${r.snippet.trim()}
|
|
|
6204
6841
|
}
|
|
6205
6842
|
async countConversationChunkDocs(dir) {
|
|
6206
6843
|
try {
|
|
6207
|
-
const entries = await
|
|
6844
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
6208
6845
|
let total = 0;
|
|
6209
6846
|
for (const entry of entries) {
|
|
6210
|
-
const fullPath =
|
|
6847
|
+
const fullPath = path4.join(dir, entry.name);
|
|
6211
6848
|
if (entry.isDirectory()) {
|
|
6212
6849
|
total += await this.countConversationChunkDocs(fullPath);
|
|
6213
6850
|
continue;
|
|
@@ -6499,7 +7136,8 @@ ${r.snippet.trim()}
|
|
|
6499
7136
|
this.enqueueDirectAnswerObservation(
|
|
6500
7137
|
prompt,
|
|
6501
7138
|
sessionKey,
|
|
6502
|
-
options.namespace?.trim() || void 0
|
|
7139
|
+
options.namespace?.trim() || void 0,
|
|
7140
|
+
options.principalOverride
|
|
6503
7141
|
);
|
|
6504
7142
|
} catch (err) {
|
|
6505
7143
|
log.debug(`direct-answer observation setup failed: ${err}`);
|
|
@@ -6554,17 +7192,32 @@ ${r.snippet.trim()}
|
|
|
6554
7192
|
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
6555
7193
|
}
|
|
6556
7194
|
}
|
|
6557
|
-
enqueueDirectAnswerObservation(prompt, sessionKey, namespaceOverride) {
|
|
7195
|
+
enqueueDirectAnswerObservation(prompt, sessionKey, namespaceOverride, principalOverride) {
|
|
6558
7196
|
const expectedSnapshot = this.lastRecall.get(sessionKey);
|
|
6559
7197
|
if (expectedSnapshot === null) return;
|
|
6560
7198
|
if (expectedSnapshot.plannerMode === "no_recall") return;
|
|
6561
|
-
const principal = resolvePrincipal(sessionKey, this.config);
|
|
7199
|
+
const principal = principalOverride ?? resolvePrincipal(sessionKey, this.config);
|
|
6562
7200
|
const observationCodingOverlay = namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config) ? null : this.applyCodingRecallOverlay(sessionKey);
|
|
6563
7201
|
const observationPrincipalSelf = defaultNamespaceForPrincipal(principal, this.config);
|
|
6564
7202
|
const observationCodingSelf = observationCodingOverlay ? combineNamespaces(observationPrincipalSelf, observationCodingOverlay.namespace) : null;
|
|
7203
|
+
const observationScopeProfilePlan = namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config) ? null : resolveScopeProfilePlan({
|
|
7204
|
+
config: this.config,
|
|
7205
|
+
principal,
|
|
7206
|
+
codingContext: sessionKey ? this.getCodingContextForSession(sessionKey) : null,
|
|
7207
|
+
codingOverlay: observationCodingOverlay
|
|
7208
|
+
});
|
|
6565
7209
|
let observationNamespaces;
|
|
6566
7210
|
if (namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config)) {
|
|
6567
7211
|
observationNamespaces = [namespaceOverride];
|
|
7212
|
+
} else if (observationScopeProfilePlan) {
|
|
7213
|
+
observationNamespaces = expandScopeProfileReadNamespaces({
|
|
7214
|
+
profilePlan: observationScopeProfilePlan,
|
|
7215
|
+
principalSelfNamespace: observationScopeProfilePlan.baseNamespace,
|
|
7216
|
+
config: this.config,
|
|
7217
|
+
principal,
|
|
7218
|
+
codingOverlay: observationCodingOverlay,
|
|
7219
|
+
legacyRecallNamespaces: recallNamespacesForPrincipal(principal, this.config)
|
|
7220
|
+
});
|
|
6568
7221
|
} else if (observationCodingOverlay && observationCodingSelf) {
|
|
6569
7222
|
const base = recallNamespacesForPrincipal(principal, this.config);
|
|
6570
7223
|
const mapped = base.map(
|
|
@@ -6933,7 +7586,7 @@ ${r.snippet.trim()}
|
|
|
6933
7586
|
if (!options.onDebugSnapshot) return;
|
|
6934
7587
|
await options.onDebugSnapshot({
|
|
6935
7588
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6936
|
-
queryHash:
|
|
7589
|
+
queryHash: createHash2("sha256").update(prompt).digest("hex"),
|
|
6937
7590
|
queryLength: prompt.length,
|
|
6938
7591
|
collection: options.collection,
|
|
6939
7592
|
namespaces: options.recallNamespaces,
|
|
@@ -7106,7 +7759,7 @@ ${r.snippet.trim()}
|
|
|
7106
7759
|
resolvedPath = resolvedCold.result.path;
|
|
7107
7760
|
resolvedResult = resolvedCold.result;
|
|
7108
7761
|
}
|
|
7109
|
-
if (!
|
|
7762
|
+
if (!path4.isAbsolute(resolvedPath)) {
|
|
7110
7763
|
resolvedAmbiguousSeeds.set(result.path, null);
|
|
7111
7764
|
return null;
|
|
7112
7765
|
}
|
|
@@ -7131,7 +7784,7 @@ ${r.snippet.trim()}
|
|
|
7131
7784
|
}
|
|
7132
7785
|
continue;
|
|
7133
7786
|
}
|
|
7134
|
-
if (
|
|
7787
|
+
if (path4.isAbsolute(result.path)) {
|
|
7135
7788
|
const resolved = await resolveAmbiguousSeedOwner(result, null);
|
|
7136
7789
|
if (resolved) {
|
|
7137
7790
|
addResultForNamespace(resolved.namespace, resolved.result);
|
|
@@ -7174,7 +7827,7 @@ ${r.snippet.trim()}
|
|
|
7174
7827
|
0
|
|
7175
7828
|
);
|
|
7176
7829
|
seedPaths.push(
|
|
7177
|
-
...seedRelativePaths.map((rel) =>
|
|
7830
|
+
...seedRelativePaths.map((rel) => path4.join(storage.dir, rel))
|
|
7178
7831
|
);
|
|
7179
7832
|
const seedSet = new Set(seedRelativePaths);
|
|
7180
7833
|
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
@@ -7190,7 +7843,7 @@ ${r.snippet.trim()}
|
|
|
7190
7843
|
for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
|
|
7191
7844
|
if (deadlineExpired()) break;
|
|
7192
7845
|
if (seedSet.has(candidate.path)) continue;
|
|
7193
|
-
const memoryPath =
|
|
7846
|
+
const memoryPath = path4.resolve(storage.dir, candidate.path);
|
|
7194
7847
|
const memory = await storage.readMemoryByPath(memoryPath);
|
|
7195
7848
|
if (deadlineExpired()) break;
|
|
7196
7849
|
if (!memory) continue;
|
|
@@ -7215,7 +7868,7 @@ ${r.snippet.trim()}
|
|
|
7215
7868
|
path: memory.path,
|
|
7216
7869
|
score,
|
|
7217
7870
|
namespace,
|
|
7218
|
-
seed:
|
|
7871
|
+
seed: path4.resolve(storage.dir, candidate.seed),
|
|
7219
7872
|
hopDepth: candidate.hopDepth,
|
|
7220
7873
|
decayedWeight: candidate.decayedWeight,
|
|
7221
7874
|
graphType: candidate.graphType,
|
|
@@ -7236,12 +7889,12 @@ ${r.snippet.trim()}
|
|
|
7236
7889
|
}
|
|
7237
7890
|
async recordLastGraphRecallSnapshot(options) {
|
|
7238
7891
|
try {
|
|
7239
|
-
const snapshotPath =
|
|
7892
|
+
const snapshotPath = path4.join(
|
|
7240
7893
|
options.storage.dir,
|
|
7241
7894
|
"state",
|
|
7242
7895
|
"last_graph_recall.json"
|
|
7243
7896
|
);
|
|
7244
|
-
await
|
|
7897
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7245
7898
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7246
7899
|
const totalSeedCount = options.seedPaths.length;
|
|
7247
7900
|
const totalExpandedCount = options.expandedPaths.length;
|
|
@@ -7253,7 +7906,7 @@ ${r.snippet.trim()}
|
|
|
7253
7906
|
const payload = {
|
|
7254
7907
|
recordedAt: now,
|
|
7255
7908
|
mode: options.recallMode,
|
|
7256
|
-
queryHash:
|
|
7909
|
+
queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
|
|
7257
7910
|
queryLength: options.prompt.length,
|
|
7258
7911
|
namespaces: options.recallNamespaces,
|
|
7259
7912
|
seedCount: totalSeedCount,
|
|
@@ -7268,20 +7921,20 @@ ${r.snippet.trim()}
|
|
|
7268
7921
|
finalResults: (options.finalResults ?? []).slice(0, 64),
|
|
7269
7922
|
shadowComparison: options.shadowComparison
|
|
7270
7923
|
};
|
|
7271
|
-
await
|
|
7924
|
+
await writeFile4(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
7272
7925
|
} catch (err) {
|
|
7273
7926
|
log.debug(`last graph recall write failed: ${err}`);
|
|
7274
7927
|
}
|
|
7275
7928
|
}
|
|
7276
7929
|
async recordLastIntentSnapshot(options) {
|
|
7277
7930
|
try {
|
|
7278
|
-
const snapshotPath =
|
|
7931
|
+
const snapshotPath = path4.join(
|
|
7279
7932
|
options.storage.dir,
|
|
7280
7933
|
"state",
|
|
7281
7934
|
"last_intent.json"
|
|
7282
7935
|
);
|
|
7283
|
-
await
|
|
7284
|
-
await
|
|
7936
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7937
|
+
await writeFile4(
|
|
7285
7938
|
snapshotPath,
|
|
7286
7939
|
JSON.stringify(options.snapshot, null, 2),
|
|
7287
7940
|
"utf-8"
|
|
@@ -7292,13 +7945,13 @@ ${r.snippet.trim()}
|
|
|
7292
7945
|
}
|
|
7293
7946
|
async recordLastQmdRecallSnapshot(options) {
|
|
7294
7947
|
try {
|
|
7295
|
-
const snapshotPath =
|
|
7948
|
+
const snapshotPath = path4.join(
|
|
7296
7949
|
options.storage.dir,
|
|
7297
7950
|
"state",
|
|
7298
7951
|
"last_qmd_recall.json"
|
|
7299
7952
|
);
|
|
7300
|
-
await
|
|
7301
|
-
await
|
|
7953
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7954
|
+
await writeFile4(
|
|
7302
7955
|
snapshotPath,
|
|
7303
7956
|
JSON.stringify(options.snapshot, null, 2),
|
|
7304
7957
|
"utf-8"
|
|
@@ -7312,9 +7965,9 @@ ${r.snippet.trim()}
|
|
|
7312
7965
|
const stateDir = await this.resolveStateDirForNamespace(
|
|
7313
7966
|
options.namespace
|
|
7314
7967
|
);
|
|
7315
|
-
const snapshotPath =
|
|
7316
|
-
await
|
|
7317
|
-
await
|
|
7968
|
+
const snapshotPath = path4.join(stateDir, "last_intent.json");
|
|
7969
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7970
|
+
await writeFile4(
|
|
7318
7971
|
snapshotPath,
|
|
7319
7972
|
JSON.stringify(options.snapshot, null, 2),
|
|
7320
7973
|
"utf-8"
|
|
@@ -7325,24 +7978,24 @@ ${r.snippet.trim()}
|
|
|
7325
7978
|
}
|
|
7326
7979
|
async resolveStateDirForNamespace(namespace) {
|
|
7327
7980
|
if (!this.config.namespacesEnabled) {
|
|
7328
|
-
return
|
|
7981
|
+
return path4.join(this.config.memoryDir, "state");
|
|
7329
7982
|
}
|
|
7330
7983
|
if (namespace !== this.config.defaultNamespace) {
|
|
7331
|
-
return
|
|
7984
|
+
return path4.join(this.config.memoryDir, "namespaces", namespace, "state");
|
|
7332
7985
|
}
|
|
7333
|
-
const candidate =
|
|
7986
|
+
const candidate = path4.join(
|
|
7334
7987
|
this.config.memoryDir,
|
|
7335
7988
|
"namespaces",
|
|
7336
7989
|
this.config.defaultNamespace
|
|
7337
7990
|
);
|
|
7338
7991
|
try {
|
|
7339
|
-
const candidateStat = await
|
|
7992
|
+
const candidateStat = await stat3(candidate);
|
|
7340
7993
|
if (candidateStat.isDirectory()) {
|
|
7341
|
-
return
|
|
7994
|
+
return path4.join(candidate, "state");
|
|
7342
7995
|
}
|
|
7343
7996
|
} catch {
|
|
7344
7997
|
}
|
|
7345
|
-
return
|
|
7998
|
+
return path4.join(this.config.memoryDir, "state");
|
|
7346
7999
|
}
|
|
7347
8000
|
buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
|
|
7348
8001
|
return results.slice(0, limit).map((result) => ({
|
|
@@ -7584,8 +8237,8 @@ ${r.snippet.trim()}
|
|
|
7584
8237
|
timings,
|
|
7585
8238
|
logger: log
|
|
7586
8239
|
});
|
|
7587
|
-
const promptHash =
|
|
7588
|
-
const traceId =
|
|
8240
|
+
const promptHash = createHash2("sha256").update(prompt).digest("hex");
|
|
8241
|
+
const traceId = createHash2("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
|
|
7589
8242
|
const sectionBuckets = /* @__PURE__ */ new Map();
|
|
7590
8243
|
const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
|
|
7591
8244
|
cronRecallPolicyEnabled: this.config.cronRecallPolicyEnabled,
|
|
@@ -7594,7 +8247,7 @@ ${r.snippet.trim()}
|
|
|
7594
8247
|
cronConversationRecallMode: this.config.cronConversationRecallMode
|
|
7595
8248
|
});
|
|
7596
8249
|
const retrievalQuery = queryPolicy.retrievalQuery || prompt;
|
|
7597
|
-
const retrievalQueryHash =
|
|
8250
|
+
const retrievalQueryHash = createHash2("sha256").update(retrievalQuery).digest("hex");
|
|
7598
8251
|
const policyVersion = this.currentPolicyVersion();
|
|
7599
8252
|
let impressionRecorded = false;
|
|
7600
8253
|
let recallSource = "none";
|
|
@@ -7697,10 +8350,26 @@ ${r.snippet.trim()}
|
|
|
7697
8350
|
const codingOverlay = namespaceOverride ? null : this.applyCodingRecallOverlay(sessionKey);
|
|
7698
8351
|
const principalSelfNamespace = defaultNamespaceForPrincipal(principal, this.config);
|
|
7699
8352
|
const codingSelfNamespace = codingOverlay ? combineNamespaces(principalSelfNamespace, codingOverlay.namespace) : null;
|
|
7700
|
-
const
|
|
8353
|
+
const scopeProfilePlan = namespaceOverride ? null : resolveScopeProfilePlan({
|
|
8354
|
+
config: this.config,
|
|
8355
|
+
principal,
|
|
8356
|
+
codingContext: sessionKey ? this.getCodingContextForSession(sessionKey) : null,
|
|
8357
|
+
codingOverlay
|
|
8358
|
+
});
|
|
8359
|
+
const profileEffectiveNamespace = scopeProfilePlan?.writeNamespace || scopeProfilePlan?.readNamespaces[0];
|
|
8360
|
+
const selfNamespace = namespaceOverride ?? profileEffectiveNamespace ?? codingSelfNamespace ?? principalSelfNamespace;
|
|
7701
8361
|
let recallNamespaces;
|
|
7702
8362
|
if (namespaceOverride) {
|
|
7703
8363
|
recallNamespaces = [namespaceOverride];
|
|
8364
|
+
} else if (scopeProfilePlan) {
|
|
8365
|
+
recallNamespaces = expandScopeProfileReadNamespaces({
|
|
8366
|
+
profilePlan: scopeProfilePlan,
|
|
8367
|
+
principalSelfNamespace: scopeProfilePlan.baseNamespace,
|
|
8368
|
+
config: this.config,
|
|
8369
|
+
principal,
|
|
8370
|
+
codingOverlay,
|
|
8371
|
+
legacyRecallNamespaces: readableRecallNamespaces
|
|
8372
|
+
});
|
|
7704
8373
|
} else if (codingOverlay && codingSelfNamespace) {
|
|
7705
8374
|
const mapped = readableRecallNamespaces.map(
|
|
7706
8375
|
(ns) => ns === principalSelfNamespace ? codingSelfNamespace : ns
|
|
@@ -7712,10 +8381,12 @@ ${r.snippet.trim()}
|
|
|
7712
8381
|
} else {
|
|
7713
8382
|
recallNamespaces = readableRecallNamespaces;
|
|
7714
8383
|
}
|
|
7715
|
-
const codingOverlaySelfReadable = codingOverlay !== null && readableRecallNamespaces.includes(principalSelfNamespace);
|
|
8384
|
+
const codingOverlaySelfReadable = codingOverlay !== null && (scopeProfilePlan ? scopeProfilePlan.layers.some((layer) => layer.id === "userProject" && layer.readable) : readableRecallNamespaces.includes(principalSelfNamespace));
|
|
7716
8385
|
let lcmReadNamespaces;
|
|
7717
8386
|
if (namespaceOverride) {
|
|
7718
8387
|
lcmReadNamespaces = [namespaceOverride];
|
|
8388
|
+
} else if (scopeProfilePlan) {
|
|
8389
|
+
lcmReadNamespaces = recallNamespaces;
|
|
7719
8390
|
} else if (codingOverlay && codingSelfNamespace && codingOverlaySelfReadable) {
|
|
7720
8391
|
const fallbackNs = codingOverlay.readFallbacks.map(
|
|
7721
8392
|
(fallback) => combineNamespaces(principalSelfNamespace, fallback)
|
|
@@ -7724,7 +8395,7 @@ ${r.snippet.trim()}
|
|
|
7724
8395
|
} else {
|
|
7725
8396
|
lcmReadNamespaces = [this.config.defaultNamespace];
|
|
7726
8397
|
}
|
|
7727
|
-
const lcmReadSessionIds = lcmReadSessionIdsForNamespaces(
|
|
8398
|
+
const lcmReadSessionIds = scopeProfilePlan && !sessionKey ? [] : lcmReadSessionIdsForNamespaces(
|
|
7728
8399
|
lcmReadNamespaces,
|
|
7729
8400
|
sessionKey,
|
|
7730
8401
|
this.config.defaultNamespace
|
|
@@ -7752,7 +8423,7 @@ ${r.snippet.trim()}
|
|
|
7752
8423
|
const graphExpandedResultPaths = /* @__PURE__ */ new Set();
|
|
7753
8424
|
const graphSourceLabelsForPath = (resultPath) => {
|
|
7754
8425
|
const labels = [];
|
|
7755
|
-
const normalizedPath = resultPath.split(
|
|
8426
|
+
const normalizedPath = resultPath.split(path4.sep).join("/");
|
|
7756
8427
|
const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
|
|
7757
8428
|
if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
|
|
7758
8429
|
if (graphExpandedResultPaths.has(resultPath))
|
|
@@ -7897,7 +8568,144 @@ ${r.snippet.trim()}
|
|
|
7897
8568
|
});
|
|
7898
8569
|
return "";
|
|
7899
8570
|
}
|
|
7900
|
-
const
|
|
8571
|
+
const profileStorageNamespaces = scopeProfilePlan ? recallNamespaces : [selfNamespace];
|
|
8572
|
+
const profileStorages = await Promise.all(
|
|
8573
|
+
profileStorageNamespaces.map((namespace) => this.storageRouter.storageFor(namespace))
|
|
8574
|
+
);
|
|
8575
|
+
const emptyProfileStorage = new Proxy(
|
|
8576
|
+
{ dir: path4.join(this.config.memoryDir, ".empty-scope-profile") },
|
|
8577
|
+
{
|
|
8578
|
+
get(target, prop) {
|
|
8579
|
+
if (prop in target) return target[prop];
|
|
8580
|
+
if (prop === "readProfile") return async () => "";
|
|
8581
|
+
if (prop === "readQuestions" || prop === "listEntityNames" || prop === "readContinuityIncidents")
|
|
8582
|
+
return async () => [];
|
|
8583
|
+
if (prop === "readIdentityAnchor" || prop === "readIdentityImprovementLoops")
|
|
8584
|
+
return async () => "";
|
|
8585
|
+
if (prop === "readEntity" || prop === "readMemoryByPath")
|
|
8586
|
+
return async () => null;
|
|
8587
|
+
return async () => [];
|
|
8588
|
+
}
|
|
8589
|
+
}
|
|
8590
|
+
);
|
|
8591
|
+
const profileStorage = profileStorages.length <= 1 ? profileStorages[0] ?? emptyProfileStorage : new Proxy(profileStorages[0], {
|
|
8592
|
+
get(target, prop) {
|
|
8593
|
+
if (prop === "readProfile") {
|
|
8594
|
+
return async () => {
|
|
8595
|
+
for (const storage of profileStorages) {
|
|
8596
|
+
const profile2 = await storage.readProfile();
|
|
8597
|
+
if (profile2.trim().length > 0) return profile2;
|
|
8598
|
+
}
|
|
8599
|
+
return "";
|
|
8600
|
+
};
|
|
8601
|
+
}
|
|
8602
|
+
if (prop === "readQuestions") {
|
|
8603
|
+
return async (...args) => {
|
|
8604
|
+
const merged = [];
|
|
8605
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8606
|
+
const priorityOf = (question) => {
|
|
8607
|
+
const priority = Number(question?.priority ?? 0);
|
|
8608
|
+
return Number.isFinite(priority) ? priority : 0;
|
|
8609
|
+
};
|
|
8610
|
+
for (const storage of profileStorages) {
|
|
8611
|
+
const questions = await storage.readQuestions(...args);
|
|
8612
|
+
for (const question of questions) {
|
|
8613
|
+
const key = typeof question === "string" ? question : JSON.stringify(question);
|
|
8614
|
+
if (seen.has(key)) continue;
|
|
8615
|
+
seen.add(key);
|
|
8616
|
+
merged.push(question);
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
return merged.sort(
|
|
8620
|
+
(left, right) => priorityOf(right) - priorityOf(left) || String(left?.id ?? "").localeCompare(String(right?.id ?? ""))
|
|
8621
|
+
);
|
|
8622
|
+
};
|
|
8623
|
+
}
|
|
8624
|
+
if (prop === "readIdentityAnchor") {
|
|
8625
|
+
return async () => {
|
|
8626
|
+
for (const storage of profileStorages) {
|
|
8627
|
+
const anchor = await storage.readIdentityAnchor() ?? "";
|
|
8628
|
+
if (anchor.trim().length > 0) return anchor;
|
|
8629
|
+
}
|
|
8630
|
+
return "";
|
|
8631
|
+
};
|
|
8632
|
+
}
|
|
8633
|
+
if (prop === "readIdentityImprovementLoops") {
|
|
8634
|
+
return async () => {
|
|
8635
|
+
const sections = [];
|
|
8636
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8637
|
+
for (const storage of profileStorages) {
|
|
8638
|
+
const loops = (await storage.readIdentityImprovementLoops() ?? "").trim();
|
|
8639
|
+
if (!loops || seen.has(loops)) continue;
|
|
8640
|
+
seen.add(loops);
|
|
8641
|
+
sections.push(loops);
|
|
8642
|
+
}
|
|
8643
|
+
return sections.join("\n\n");
|
|
8644
|
+
};
|
|
8645
|
+
}
|
|
8646
|
+
if (prop === "readContinuityIncidents") {
|
|
8647
|
+
return async (...args) => {
|
|
8648
|
+
const limit = typeof args[0] === "number" && Number.isFinite(args[0]) ? Math.max(0, args[0]) : void 0;
|
|
8649
|
+
const incidents = [];
|
|
8650
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8651
|
+
const incidentTime = (incident) => {
|
|
8652
|
+
const raw = incident?.updatedAt ?? incident?.openedAt ?? incident?.createdAt;
|
|
8653
|
+
const parsed = typeof raw === "string" ? Date.parse(raw) : Number.NaN;
|
|
8654
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
8655
|
+
};
|
|
8656
|
+
for (const storage of profileStorages) {
|
|
8657
|
+
for (const incident of await storage.readContinuityIncidents(...args)) {
|
|
8658
|
+
const key = JSON.stringify(incident);
|
|
8659
|
+
if (seen.has(key)) continue;
|
|
8660
|
+
seen.add(key);
|
|
8661
|
+
incidents.push(incident);
|
|
8662
|
+
}
|
|
8663
|
+
}
|
|
8664
|
+
incidents.sort(
|
|
8665
|
+
(left, right) => incidentTime(right) - incidentTime(left) || String(left?.id ?? "").localeCompare(String(right?.id ?? ""))
|
|
8666
|
+
);
|
|
8667
|
+
return limit === void 0 ? incidents : incidents.slice(0, limit);
|
|
8668
|
+
};
|
|
8669
|
+
}
|
|
8670
|
+
if (prop === "listEntityNames") {
|
|
8671
|
+
return async (...args) => {
|
|
8672
|
+
const names = /* @__PURE__ */ new Set();
|
|
8673
|
+
for (const storage of profileStorages) {
|
|
8674
|
+
for (const name of await storage.listEntityNames(...args)) names.add(name);
|
|
8675
|
+
}
|
|
8676
|
+
return [...names];
|
|
8677
|
+
};
|
|
8678
|
+
}
|
|
8679
|
+
if (prop === "readEntity" || prop === "readMemoryByPath") {
|
|
8680
|
+
return async (...args) => {
|
|
8681
|
+
for (const storage of profileStorages) {
|
|
8682
|
+
const value = await storage[prop](...args);
|
|
8683
|
+
if (value) return value;
|
|
8684
|
+
}
|
|
8685
|
+
return null;
|
|
8686
|
+
};
|
|
8687
|
+
}
|
|
8688
|
+
if (prop === "readAllMemories") {
|
|
8689
|
+
return async (...args) => {
|
|
8690
|
+
const memories = [];
|
|
8691
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8692
|
+
for (const storage of profileStorages) {
|
|
8693
|
+
for (const memory of await storage.readAllMemories(...args)) {
|
|
8694
|
+
const key = String(memory?.path ?? memory?.frontmatter?.id ?? JSON.stringify(memory));
|
|
8695
|
+
if (seen.has(key)) continue;
|
|
8696
|
+
seen.add(key);
|
|
8697
|
+
memories.push(memory);
|
|
8698
|
+
}
|
|
8699
|
+
}
|
|
8700
|
+
return memories;
|
|
8701
|
+
};
|
|
8702
|
+
}
|
|
8703
|
+
return target[prop];
|
|
8704
|
+
}
|
|
8705
|
+
});
|
|
8706
|
+
const profileStorageDirs = Array.from(
|
|
8707
|
+
new Set(profileStorages.map((storage) => storage.dir).filter((dir) => typeof dir === "string" && dir.length > 0))
|
|
8708
|
+
);
|
|
7901
8709
|
throwIfRecallAborted(options.abortSignal);
|
|
7902
8710
|
if (this.namespaceCatalog.enabled && recallResultLimit > 0 && !options.abortSignal?.aborted) {
|
|
7903
8711
|
for (const ns of recallNamespaces) this.markCatalogRead(ns);
|
|
@@ -7909,6 +8717,8 @@ ${r.snippet.trim()}
|
|
|
7909
8717
|
))
|
|
7910
8718
|
return null;
|
|
7911
8719
|
if (!this.sharedContext) return null;
|
|
8720
|
+
if (scopeProfilePlan && !(scopeProfilePlan.profile.readOrder.includes("serverShared") && scopeProfilePlan.readNamespaces.includes(this.config.sharedNamespace)))
|
|
8721
|
+
return null;
|
|
7912
8722
|
const t0 = Date.now();
|
|
7913
8723
|
const [priorities, roundtable, crossSignals] = await Promise.all([
|
|
7914
8724
|
this.sharedContext.readPriorities(),
|
|
@@ -8133,13 +8943,52 @@ ${lines.join("\n\n")}`;
|
|
|
8133
8943
|
if (!this.config.knowledgeIndexEnabled) return null;
|
|
8134
8944
|
const t0 = Date.now();
|
|
8135
8945
|
try {
|
|
8136
|
-
const
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8946
|
+
const knowledgeIndexMaxChars = this.getRecallSectionNumber("knowledge-index", "maxChars") ?? this.config.knowledgeIndexMaxChars;
|
|
8947
|
+
const knowledgeIndexMaxEntities = this.getRecallSectionNumber("knowledge-index", "maxEntities") ?? this.config.knowledgeIndexMaxEntities;
|
|
8948
|
+
const knowledgeIndexOptions = {
|
|
8949
|
+
maxEntities: knowledgeIndexMaxEntities,
|
|
8950
|
+
maxChars: knowledgeIndexMaxChars
|
|
8951
|
+
};
|
|
8952
|
+
const ki = scopeProfilePlan ? await (async () => {
|
|
8953
|
+
const perLayerOptions = {
|
|
8954
|
+
...knowledgeIndexOptions,
|
|
8955
|
+
maxEntities: Number.MAX_SAFE_INTEGER,
|
|
8956
|
+
maxChars: Number.MAX_SAFE_INTEGER
|
|
8957
|
+
};
|
|
8958
|
+
const results = await Promise.all(
|
|
8959
|
+
profileStorages.map(
|
|
8960
|
+
(storage) => storage.buildKnowledgeIndex(this.config, perLayerOptions)
|
|
8961
|
+
)
|
|
8962
|
+
);
|
|
8963
|
+
const sections = results.map((result) => result.result.trim()).filter((section) => section.length > 0);
|
|
8964
|
+
const maxRows = Math.max(0, Math.floor(knowledgeIndexMaxEntities));
|
|
8965
|
+
const rows = [];
|
|
8966
|
+
let header = null;
|
|
8967
|
+
for (const section of sections) {
|
|
8968
|
+
const lines = section.split("\n").map((line) => line.trimEnd()).filter((line) => line.length > 0);
|
|
8969
|
+
const tableHeaderIndex = lines.findIndex(
|
|
8970
|
+
(line) => line.startsWith("| Entity |")
|
|
8971
|
+
);
|
|
8972
|
+
if (tableHeaderIndex === -1) continue;
|
|
8973
|
+
header ??= lines.slice(0, tableHeaderIndex + 2);
|
|
8974
|
+
for (const row of lines.slice(tableHeaderIndex + 2)) {
|
|
8975
|
+
if (!row.startsWith("|")) continue;
|
|
8976
|
+
if (rows.length >= maxRows) break;
|
|
8977
|
+
rows.push(row);
|
|
8978
|
+
}
|
|
8979
|
+
if (rows.length >= maxRows) break;
|
|
8980
|
+
}
|
|
8981
|
+
const merged = header && rows.length > 0 ? `${header.join("\n")}
|
|
8982
|
+
${rows.join("\n")}
|
|
8983
|
+
` : "";
|
|
8984
|
+
return {
|
|
8985
|
+
result: this.truncateRecallSectionToBudget(
|
|
8986
|
+
merged,
|
|
8987
|
+
knowledgeIndexMaxChars
|
|
8988
|
+
),
|
|
8989
|
+
cached: results.every((result) => result.cached)
|
|
8990
|
+
};
|
|
8991
|
+
})() : await this.storage.buildKnowledgeIndex(this.config, knowledgeIndexOptions);
|
|
8143
8992
|
recordRecallSectionMetric({
|
|
8144
8993
|
section: "ki",
|
|
8145
8994
|
priority: "core",
|
|
@@ -8506,15 +9355,30 @@ ${lines.join("\n\n")}`;
|
|
|
8506
9355
|
});
|
|
8507
9356
|
return null;
|
|
8508
9357
|
}
|
|
8509
|
-
const
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
9358
|
+
const harmonicSearchDirs = scopeProfilePlan ? profileStorageDirs : [this.config.memoryDir];
|
|
9359
|
+
const harmonicResultsByDir = await Promise.all(
|
|
9360
|
+
harmonicSearchDirs.map(
|
|
9361
|
+
(memoryDir) => searchHarmonicRetrieval({
|
|
9362
|
+
memoryDir,
|
|
9363
|
+
abstractionNodeStoreDir: scopeProfilePlan ? void 0 : this.config.abstractionNodeStoreDir,
|
|
9364
|
+
query: retrievalQuery,
|
|
9365
|
+
maxResults,
|
|
9366
|
+
sessionKey,
|
|
9367
|
+
anchorsEnabled: this.config.abstractionAnchorsEnabled,
|
|
9368
|
+
abortSignal: harmonicRetrievalAbort.signal
|
|
9369
|
+
})
|
|
9370
|
+
)
|
|
9371
|
+
);
|
|
9372
|
+
const harmonicByNodeId = /* @__PURE__ */ new Map();
|
|
9373
|
+
for (const result of harmonicResultsByDir.flat()) {
|
|
9374
|
+
const existing = harmonicByNodeId.get(result.node.nodeId);
|
|
9375
|
+
if (!existing || result.score > existing.score) {
|
|
9376
|
+
harmonicByNodeId.set(result.node.nodeId, result);
|
|
9377
|
+
}
|
|
9378
|
+
}
|
|
9379
|
+
const results = [...harmonicByNodeId.values()].sort(
|
|
9380
|
+
(left, right) => right.score - left.score || right.anchorScore - left.anchorScore || right.node.recordedAt.localeCompare(left.node.recordedAt) || left.node.nodeId.localeCompare(right.node.nodeId)
|
|
9381
|
+
).slice(0, maxResults);
|
|
8518
9382
|
recordRecallSectionMetric({
|
|
8519
9383
|
section: "harmonicRetrieval",
|
|
8520
9384
|
priority: "enrichment",
|
|
@@ -8560,11 +9424,28 @@ ${lines.join("\n\n")}`;
|
|
|
8560
9424
|
const VERIFIED_RECALL_TIMEOUT_MS = 15e3;
|
|
8561
9425
|
let timeoutHandle;
|
|
8562
9426
|
const results = await Promise.race([
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
9427
|
+
Promise.all(
|
|
9428
|
+
profileStorageDirs.map(
|
|
9429
|
+
(memoryDir) => searchVerifiedEpisodes({
|
|
9430
|
+
memoryDir,
|
|
9431
|
+
query: retrievalQuery,
|
|
9432
|
+
maxResults,
|
|
9433
|
+
boxRecallDays: this.config.boxRecallDays
|
|
9434
|
+
}).catch((err) => {
|
|
9435
|
+
log.debug(`verified recall directory scan failed: ${err}`);
|
|
9436
|
+
return [];
|
|
9437
|
+
})
|
|
9438
|
+
)
|
|
9439
|
+
).then((groups) => {
|
|
9440
|
+
const merged = [];
|
|
9441
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9442
|
+
for (const result of groups.flat()) {
|
|
9443
|
+
const key = result.box.id || JSON.stringify(result);
|
|
9444
|
+
if (seen.has(key)) continue;
|
|
9445
|
+
seen.add(key);
|
|
9446
|
+
merged.push(result);
|
|
9447
|
+
}
|
|
9448
|
+
return merged.sort(compareVerifiedEpisodeResults).slice(0, maxResults);
|
|
8568
9449
|
}),
|
|
8569
9450
|
new Promise((resolve) => {
|
|
8570
9451
|
timeoutHandle = setTimeout(
|
|
@@ -8623,10 +9504,27 @@ ${lines.join("\n\n")}`;
|
|
|
8623
9504
|
const VERIFIED_RULES_TIMEOUT_MS = 15e3;
|
|
8624
9505
|
let rulesTimeoutHandle;
|
|
8625
9506
|
const results = await Promise.race([
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
|
|
9507
|
+
Promise.all(
|
|
9508
|
+
profileStorageDirs.map(
|
|
9509
|
+
(memoryDir) => searchVerifiedSemanticRules({
|
|
9510
|
+
memoryDir,
|
|
9511
|
+
query: retrievalQuery,
|
|
9512
|
+
maxResults
|
|
9513
|
+
}).catch((err) => {
|
|
9514
|
+
log.debug(`verified rules directory scan failed: ${err}`);
|
|
9515
|
+
return [];
|
|
9516
|
+
})
|
|
9517
|
+
)
|
|
9518
|
+
).then((groups) => {
|
|
9519
|
+
const merged = [];
|
|
9520
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9521
|
+
for (const result of groups.flat()) {
|
|
9522
|
+
const key = result.rule.frontmatter.id || result.rule.path || JSON.stringify(result);
|
|
9523
|
+
if (seen.has(key)) continue;
|
|
9524
|
+
seen.add(key);
|
|
9525
|
+
merged.push(result);
|
|
9526
|
+
}
|
|
9527
|
+
return merged.sort(compareVerifiedSemanticRuleResults).slice(0, maxResults);
|
|
8630
9528
|
}),
|
|
8631
9529
|
new Promise((resolve) => {
|
|
8632
9530
|
rulesTimeoutHandle = setTimeout(
|
|
@@ -8682,13 +9580,28 @@ ${lines.join("\n\n")}`;
|
|
|
8682
9580
|
});
|
|
8683
9581
|
return null;
|
|
8684
9582
|
}
|
|
8685
|
-
const
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
9583
|
+
const workProductSearchDirs = scopeProfilePlan ? profileStorageDirs : [this.config.memoryDir];
|
|
9584
|
+
const workProductResultsByDir = await Promise.all(
|
|
9585
|
+
workProductSearchDirs.map(
|
|
9586
|
+
(memoryDir) => searchWorkProductLedgerEntries({
|
|
9587
|
+
memoryDir,
|
|
9588
|
+
workProductLedgerDir: scopeProfilePlan ? void 0 : this.config.workProductLedgerDir,
|
|
9589
|
+
query: retrievalQuery,
|
|
9590
|
+
maxResults,
|
|
9591
|
+
sessionKey
|
|
9592
|
+
})
|
|
9593
|
+
)
|
|
9594
|
+
);
|
|
9595
|
+
const workProductByEntryId = /* @__PURE__ */ new Map();
|
|
9596
|
+
for (const result of workProductResultsByDir.flat()) {
|
|
9597
|
+
const existing = workProductByEntryId.get(result.entry.entryId);
|
|
9598
|
+
if (!existing || result.score > existing.score) {
|
|
9599
|
+
workProductByEntryId.set(result.entry.entryId, result);
|
|
9600
|
+
}
|
|
9601
|
+
}
|
|
9602
|
+
const results = [...workProductByEntryId.values()].sort(
|
|
9603
|
+
(left, right) => right.score - left.score || right.entry.recordedAt.localeCompare(left.entry.recordedAt) || left.entry.entryId.localeCompare(right.entry.entryId)
|
|
9604
|
+
).slice(0, maxResults);
|
|
8692
9605
|
recordRecallSectionMetric({
|
|
8693
9606
|
section: "workProducts",
|
|
8694
9607
|
priority: "core",
|
|
@@ -8862,22 +9775,50 @@ ${lines.join("\n\n")}`;
|
|
|
8862
9775
|
}
|
|
8863
9776
|
const maxPerAgent = this.config.parallelMaxResultsPerAgent;
|
|
8864
9777
|
const specializedAgentPromise = !queryAwarePrefilterIsEmpty && this.config.parallelRetrievalEnabled && maxPerAgent > 0 ? Promise.all([
|
|
8865
|
-
shouldRunAgent("direct", retrievalQuery, 0) ?
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
9778
|
+
shouldRunAgent("direct", retrievalQuery, 0) ? Promise.all(
|
|
9779
|
+
profileStorageDirs.map(
|
|
9780
|
+
(memoryDir) => runDirectAgent(
|
|
9781
|
+
retrievalQuery,
|
|
9782
|
+
memoryDir,
|
|
9783
|
+
maxPerAgent
|
|
9784
|
+
).catch((err) => {
|
|
9785
|
+
log.debug(`DirectAgent pre-start failed: ${err}`);
|
|
9786
|
+
return [];
|
|
9787
|
+
})
|
|
9788
|
+
)
|
|
9789
|
+
).then((groups) => {
|
|
9790
|
+
const merged = [];
|
|
9791
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9792
|
+
for (const result of groups.flat()) {
|
|
9793
|
+
const key = result.path ?? JSON.stringify(result);
|
|
9794
|
+
if (seen.has(key)) continue;
|
|
9795
|
+
seen.add(key);
|
|
9796
|
+
merged.push(result);
|
|
9797
|
+
}
|
|
9798
|
+
return merged.sort((a, b) => b.score - a.score).slice(0, maxPerAgent);
|
|
8872
9799
|
}) : Promise.resolve([]),
|
|
8873
|
-
shouldRunAgent("temporal", retrievalQuery, 0) ?
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
9800
|
+
shouldRunAgent("temporal", retrievalQuery, 0) ? Promise.all(
|
|
9801
|
+
profileStorageDirs.map(
|
|
9802
|
+
(memoryDir) => runTemporalAgent(
|
|
9803
|
+
retrievalQuery,
|
|
9804
|
+
memoryDir,
|
|
9805
|
+
maxPerAgent,
|
|
9806
|
+
queryAwarePrefilter.candidatePaths
|
|
9807
|
+
).catch((err) => {
|
|
9808
|
+
log.debug(`TemporalAgent pre-start failed for ${memoryDir}: ${err}`);
|
|
9809
|
+
return [];
|
|
9810
|
+
})
|
|
9811
|
+
)
|
|
9812
|
+
).then((groups) => {
|
|
9813
|
+
const merged = [];
|
|
9814
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9815
|
+
for (const result of groups.flat()) {
|
|
9816
|
+
const key = result.path ?? JSON.stringify(result);
|
|
9817
|
+
if (seen.has(key)) continue;
|
|
9818
|
+
seen.add(key);
|
|
9819
|
+
merged.push(result);
|
|
9820
|
+
}
|
|
9821
|
+
return merged.sort((a, b) => b.score - a.score).slice(0, maxPerAgent);
|
|
8881
9822
|
}) : Promise.resolve([])
|
|
8882
9823
|
]) : null;
|
|
8883
9824
|
try {
|
|
@@ -9070,16 +10011,16 @@ ${formatted}`;
|
|
|
9070
10011
|
if (!this.config.compactionResetEnabled) return null;
|
|
9071
10012
|
const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
|
|
9072
10013
|
const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
|
|
9073
|
-
const signalPath =
|
|
10014
|
+
const signalPath = path4.join(
|
|
9074
10015
|
workspaceDir,
|
|
9075
10016
|
`.compaction-reset-signal-${safeSessionKey}`
|
|
9076
10017
|
);
|
|
9077
|
-
const bootPath =
|
|
10018
|
+
const bootPath = path4.join(workspaceDir, "BOOT.md");
|
|
9078
10019
|
try {
|
|
9079
|
-
const signalStat = await
|
|
10020
|
+
const signalStat = await stat3(signalPath).catch(() => null);
|
|
9080
10021
|
if (!signalStat) return null;
|
|
9081
10022
|
const signalAge = Date.now() - signalStat.mtimeMs;
|
|
9082
|
-
const signalData = JSON.parse(await
|
|
10023
|
+
const signalData = JSON.parse(await readFile4(signalPath, "utf-8"));
|
|
9083
10024
|
if (signalData.sessionKey !== effectiveSessionKey) {
|
|
9084
10025
|
log.debug(
|
|
9085
10026
|
`recall: compaction signal is for ${signalData.sessionKey}, not ${effectiveSessionKey} \u2014 skipping`
|
|
@@ -9099,7 +10040,7 @@ ${formatted}`;
|
|
|
9099
10040
|
|
|
9100
10041
|
`;
|
|
9101
10042
|
try {
|
|
9102
|
-
const bootContent = await
|
|
10043
|
+
const bootContent = await readFile4(bootPath, "utf-8");
|
|
9103
10044
|
section += "### BOOT.md (working state before compaction)\n\n";
|
|
9104
10045
|
section += bootContent + "\n";
|
|
9105
10046
|
} catch {
|
|
@@ -9352,7 +10293,27 @@ ${formatted}`;
|
|
|
9352
10293
|
this.isRecallSectionEnabled(
|
|
9353
10294
|
"memory-boxes",
|
|
9354
10295
|
this.config.memoryBoxesEnabled === true
|
|
9355
|
-
) && this.config.memoryBoxesEnabled && this.config.boxRecallDays > 0 ?
|
|
10296
|
+
) && this.config.memoryBoxesEnabled && this.config.boxRecallDays > 0 ? Promise.all(
|
|
10297
|
+
profileStorages.map(
|
|
10298
|
+
(storage) => this.boxBuilderFor(storage).readRecentBoxes(this.config.boxRecallDays).catch(() => [])
|
|
10299
|
+
)
|
|
10300
|
+
).then((groups) => {
|
|
10301
|
+
const boxes = [];
|
|
10302
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10303
|
+
for (const box of groups.flat()) {
|
|
10304
|
+
const key = JSON.stringify(box);
|
|
10305
|
+
if (seen.has(key)) continue;
|
|
10306
|
+
seen.add(key);
|
|
10307
|
+
boxes.push(box);
|
|
10308
|
+
}
|
|
10309
|
+
return boxes.sort((a, b) => {
|
|
10310
|
+
const aTime = Date.parse(a.sealedAt ?? "");
|
|
10311
|
+
const bTime = Date.parse(b.sealedAt ?? "");
|
|
10312
|
+
const aRank = Number.isFinite(aTime) ? aTime : 0;
|
|
10313
|
+
const bRank = Number.isFinite(bTime) ? bTime : 0;
|
|
10314
|
+
return bRank - aRank;
|
|
10315
|
+
});
|
|
10316
|
+
}) : Promise.resolve([])
|
|
9356
10317
|
);
|
|
9357
10318
|
this.profiler.startSpan("phase-1-parallel", profileTraceId);
|
|
9358
10319
|
const phase1Start = Date.now();
|
|
@@ -11204,7 +12165,7 @@ _Context: ${topQuestion.context}_`
|
|
|
11204
12165
|
const shouldUseStableBatchKey = turns.some(
|
|
11205
12166
|
(turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
|
|
11206
12167
|
);
|
|
11207
|
-
const stableBatchFingerprint = shouldUseStableBatchKey ?
|
|
12168
|
+
const stableBatchFingerprint = shouldUseStableBatchKey ? createHash2("sha256").update(
|
|
11208
12169
|
turns.map(
|
|
11209
12170
|
(turn) => [
|
|
11210
12171
|
turn.role,
|
|
@@ -11461,7 +12422,7 @@ _Context: ${topQuestion.context}_`
|
|
|
11461
12422
|
buildExtractionFingerprint(turns, bufferKey) {
|
|
11462
12423
|
const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
|
|
11463
12424
|
if (!normalized) return null;
|
|
11464
|
-
return
|
|
12425
|
+
return createHash2("sha256").update(`${bufferKey}
|
|
11465
12426
|
${normalized}`).digest("hex");
|
|
11466
12427
|
}
|
|
11467
12428
|
shouldQueueExtraction(turns, options = {}) {
|
|
@@ -11609,7 +12570,41 @@ ${normalized}`).digest("hex");
|
|
|
11609
12570
|
};
|
|
11610
12571
|
}
|
|
11611
12572
|
const principal = typeof options.principalOverride === "string" && options.principalOverride.length > 0 ? options.principalOverride : resolvePrincipal(sessionKey, this.config);
|
|
11612
|
-
const
|
|
12573
|
+
const explicitWriteNamespace = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : void 0;
|
|
12574
|
+
const codingContextForWrite = sessionKey ? this.getCodingContextForSession(sessionKey) : null;
|
|
12575
|
+
const codingOverlayForWrite = resolveCodingNamespaceOverlay(
|
|
12576
|
+
codingContextForWrite,
|
|
12577
|
+
this.config.codingMode,
|
|
12578
|
+
this.config.defaultNamespace
|
|
12579
|
+
);
|
|
12580
|
+
const scopeProfileGatePlan = resolveScopeProfilePlan({
|
|
12581
|
+
config: this.config,
|
|
12582
|
+
principal,
|
|
12583
|
+
codingContext: codingContextForWrite,
|
|
12584
|
+
codingOverlay: codingOverlayForWrite
|
|
12585
|
+
});
|
|
12586
|
+
const scopeProfileWritePlan = explicitWriteNamespace ? null : scopeProfileGatePlan;
|
|
12587
|
+
if (scopeProfileWritePlan) {
|
|
12588
|
+
const selectedLayer = scopeProfileWritePlan.layers.find(
|
|
12589
|
+
(layer) => layer.id === scopeProfileWritePlan.writeLayer
|
|
12590
|
+
);
|
|
12591
|
+
const writeNamespaceReadable = scopeProfileWritePlan.readNamespaces.includes(
|
|
12592
|
+
scopeProfileWritePlan.writeNamespace
|
|
12593
|
+
);
|
|
12594
|
+
if (!selectedLayer?.writable || !writeNamespaceReadable) {
|
|
12595
|
+
log.warn(
|
|
12596
|
+
`runExtraction: skipping scope profile ${scopeProfileWritePlan.profileId} because write layer ${scopeProfileWritePlan.writeLayer} is not writable inside the profile read stack`
|
|
12597
|
+
);
|
|
12598
|
+
await clearBuffer();
|
|
12599
|
+
return {
|
|
12600
|
+
status: "skipped",
|
|
12601
|
+
reason: "scope_profile_no_writable_layer",
|
|
12602
|
+
persistedCount: 0,
|
|
12603
|
+
durableOutputCount: 0
|
|
12604
|
+
};
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
const selfNamespace = explicitWriteNamespace ?? scopeProfileWritePlan?.writeNamespace ?? this.applyCodingNamespaceOverlay(
|
|
11613
12608
|
sessionKey,
|
|
11614
12609
|
defaultNamespaceForPrincipal(principal, this.config)
|
|
11615
12610
|
);
|
|
@@ -11737,7 +12732,8 @@ ${normalized}`).digest("hex");
|
|
|
11737
12732
|
{ sessionKey, principal, validAt: sourceValidAt },
|
|
11738
12733
|
// Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
|
|
11739
12734
|
// real namespace rather than a guess decoded from the storage dir.
|
|
11740
|
-
selfNamespace
|
|
12735
|
+
selfNamespace,
|
|
12736
|
+
scopeProfileGatePlan
|
|
11741
12737
|
);
|
|
11742
12738
|
let postPersistMetadataFailed = false;
|
|
11743
12739
|
meta ??= await storage.loadMeta();
|
|
@@ -11951,7 +12947,7 @@ ${normalized}`).digest("hex");
|
|
|
11951
12947
|
);
|
|
11952
12948
|
this.tierMigrationInFlight = true;
|
|
11953
12949
|
try {
|
|
11954
|
-
const coldStorage = new StorageManager(
|
|
12950
|
+
const coldStorage = new StorageManager(path4.join(storage.dir, "cold"));
|
|
11955
12951
|
const [hotMemories, coldMemories] = await Promise.all([
|
|
11956
12952
|
storage.readAllMemories(),
|
|
11957
12953
|
coldStorage.readAllMemories()
|
|
@@ -12095,13 +13091,61 @@ ${normalized}`).digest("hex");
|
|
|
12095
13091
|
this.qmdMaintenancePending = false;
|
|
12096
13092
|
try {
|
|
12097
13093
|
if (this.config.namespacesEnabled) {
|
|
12098
|
-
const
|
|
12099
|
-
await this.namespaceSearchRouter.updateNamespaces(maintenanceNamespaces);
|
|
13094
|
+
const plan = await this.namespaceMaintenancePlan("qmd");
|
|
12100
13095
|
const now = Date.now();
|
|
12101
|
-
|
|
12102
|
-
|
|
13096
|
+
const lastEmbedAtByNamespace = this.lastQmdEmbedAtMsByNamespace ?? (this.lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map());
|
|
13097
|
+
const dueEmbedNamespaces = (namespaces) => {
|
|
13098
|
+
if (!this.config.qmdAutoEmbedEnabled) return [];
|
|
13099
|
+
return namespaces.filter(
|
|
13100
|
+
(namespace) => now - (lastEmbedAtByNamespace.get(namespace) ?? 0) >= this.config.qmdEmbedMinIntervalMs
|
|
13101
|
+
);
|
|
13102
|
+
};
|
|
13103
|
+
const markEmbedded = (namespaces) => {
|
|
13104
|
+
if (namespaces.length === 0) return;
|
|
13105
|
+
for (const namespace of namespaces) {
|
|
13106
|
+
lastEmbedAtByNamespace.set(namespace, now);
|
|
13107
|
+
}
|
|
12103
13108
|
this.lastQmdEmbedAtMs = now;
|
|
12104
|
-
}
|
|
13109
|
+
};
|
|
13110
|
+
await runNamespaceMaintenanceBatchPlan(
|
|
13111
|
+
this.config,
|
|
13112
|
+
plan,
|
|
13113
|
+
async (candidates) => {
|
|
13114
|
+
const namespaces = candidates.map((candidate) => candidate.namespace);
|
|
13115
|
+
const embedNamespaces = dueEmbedNamespaces(namespaces);
|
|
13116
|
+
let result;
|
|
13117
|
+
try {
|
|
13118
|
+
result = await this.namespaceSearchRouter.updateNamespacesDetailed(
|
|
13119
|
+
namespaces,
|
|
13120
|
+
void 0,
|
|
13121
|
+
{ strict: true }
|
|
13122
|
+
);
|
|
13123
|
+
} catch (error) {
|
|
13124
|
+
if (embedNamespaces.length > 0 && qmdMaintenanceSkipReasonForError(error) === "throttled") {
|
|
13125
|
+
await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
|
|
13126
|
+
markEmbedded(embedNamespaces);
|
|
13127
|
+
}
|
|
13128
|
+
throw error;
|
|
13129
|
+
}
|
|
13130
|
+
if (result.backendCount <= 0) {
|
|
13131
|
+
throw new Error("no eligible QMD backend for selected namespaces");
|
|
13132
|
+
}
|
|
13133
|
+
if (result.eligibleNamespaces.length !== namespaces.length) {
|
|
13134
|
+
const eligible = new Set(result.eligibleNamespaces);
|
|
13135
|
+
const missing = namespaces.filter((namespace) => !eligible.has(namespace));
|
|
13136
|
+
throw new Error(`QMD backend ineligible for selected namespaces (${missing.length})`);
|
|
13137
|
+
}
|
|
13138
|
+
if (embedNamespaces.length > 0) {
|
|
13139
|
+
await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
|
|
13140
|
+
markEmbedded(embedNamespaces);
|
|
13141
|
+
}
|
|
13142
|
+
return { itemCount: result.backendCount };
|
|
13143
|
+
},
|
|
13144
|
+
this.namespaceCatalog,
|
|
13145
|
+
{
|
|
13146
|
+
skipReasonForError: qmdMaintenanceSkipReasonForError
|
|
13147
|
+
}
|
|
13148
|
+
);
|
|
12105
13149
|
} else {
|
|
12106
13150
|
await this.qmd.update();
|
|
12107
13151
|
const now = Date.now();
|
|
@@ -12117,7 +13161,7 @@ ${normalized}`).digest("hex");
|
|
|
12117
13161
|
}
|
|
12118
13162
|
}
|
|
12119
13163
|
}
|
|
12120
|
-
async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace) {
|
|
13164
|
+
async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace, scopeProfileWritePlan) {
|
|
12121
13165
|
const citationEnabled = this.config.inlineSourceAttributionEnabled === true;
|
|
12122
13166
|
const citationTemplate = this.config.inlineSourceAttributionFormat;
|
|
12123
13167
|
const citationContextBase = citationEnabled ? {
|
|
@@ -12171,22 +13215,128 @@ ${normalized}`).digest("hex");
|
|
|
12171
13215
|
"inferred",
|
|
12172
13216
|
"speculative"
|
|
12173
13217
|
];
|
|
13218
|
+
const sharedProfileLayer = scopeProfileWritePlan?.layers.find(
|
|
13219
|
+
(layer) => layer.id === "serverShared" && layer.namespace === this.config.sharedNamespace
|
|
13220
|
+
);
|
|
13221
|
+
const sharedPromotionTarget = scopeProfileWritePlan?.promotionTargets.find(
|
|
13222
|
+
(target) => target.target === "serverShared" && target.namespace === this.config.sharedNamespace
|
|
13223
|
+
);
|
|
13224
|
+
const profileAllowsSharedWrites = !scopeProfileWritePlan || Boolean(
|
|
13225
|
+
scopeProfileWritePlan.profile.readOrder.includes("serverShared") && scopeProfileWritePlan.readNamespaces.includes(this.config.sharedNamespace) && sharedProfileLayer?.readable && sharedProfileLayer.writable && sharedPromotionTarget?.authorized
|
|
13226
|
+
);
|
|
13227
|
+
const profileAutoPromotionAllows = (category, confidence) => {
|
|
13228
|
+
if (!scopeProfileWritePlan) return false;
|
|
13229
|
+
const actualTier = confidenceTier(confidence);
|
|
13230
|
+
const actualRank = confidenceTierOrder.indexOf(actualTier);
|
|
13231
|
+
if (actualRank === -1) return false;
|
|
13232
|
+
const autoPromote = scopeProfileWritePlan.profile.autoPromote;
|
|
13233
|
+
if (!autoPromote.enabled) return false;
|
|
13234
|
+
if (!autoPromote.categories.includes(category)) return false;
|
|
13235
|
+
const minimumRank = confidenceTierOrder.indexOf(autoPromote.minConfidenceTier);
|
|
13236
|
+
return minimumRank !== -1 && actualRank <= minimumRank;
|
|
13237
|
+
};
|
|
13238
|
+
const sharedAutoPromotionAllows = (category, confidence) => {
|
|
13239
|
+
if (!scopeProfileWritePlan) {
|
|
13240
|
+
const actualTier = confidenceTier(confidence);
|
|
13241
|
+
const actualRank = confidenceTierOrder.indexOf(actualTier);
|
|
13242
|
+
if (actualRank === -1) return false;
|
|
13243
|
+
if (!this.config.autoPromoteToSharedEnabled) return false;
|
|
13244
|
+
if (!this.config.autoPromoteToSharedCategories.includes(category))
|
|
13245
|
+
return false;
|
|
13246
|
+
const minimumRank = confidenceTierOrder.indexOf(
|
|
13247
|
+
this.config.autoPromoteMinConfidenceTier
|
|
13248
|
+
);
|
|
13249
|
+
return minimumRank !== -1 && actualRank <= minimumRank;
|
|
13250
|
+
}
|
|
13251
|
+
return scopeProfileWritePlan.profile.autoPromote.targets.includes("serverShared") && profileAutoPromotionAllows(category, confidence);
|
|
13252
|
+
};
|
|
12174
13253
|
const shouldPromoteToShared = (targetStorage, category, confidence) => {
|
|
12175
|
-
if (!this.config.namespacesEnabled || !
|
|
13254
|
+
if (!this.config.namespacesEnabled || !profileAllowsSharedWrites || !sharedAutoPromotionAllows(category, confidence))
|
|
12176
13255
|
return false;
|
|
12177
13256
|
if (this.namespaceFromStorageDir(targetStorage.dir) === this.config.sharedNamespace)
|
|
12178
13257
|
return false;
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
13258
|
+
return true;
|
|
13259
|
+
};
|
|
13260
|
+
const promoteMemoryToProfileTargets = async (options) => {
|
|
13261
|
+
if (!scopeProfileWritePlan || !profileAutoPromotionAllows(options.category, options.confidence))
|
|
13262
|
+
return;
|
|
13263
|
+
const autoTargets = new Set(scopeProfileWritePlan.profile.autoPromote.targets);
|
|
13264
|
+
const targets = scopeProfileWritePlan.promotionTargets.filter(
|
|
13265
|
+
(target) => target.target !== "serverShared" && autoTargets.has(target.target) && target.authorized && target.namespace
|
|
12185
13266
|
);
|
|
12186
|
-
if (
|
|
12187
|
-
|
|
13267
|
+
if (targets.length === 0) return;
|
|
13268
|
+
const rawContent = citationEnabled && hasCitationForTemplate(options.content, citationTemplate) ? stripCitationForTemplate(options.content, citationTemplate) : options.content;
|
|
13269
|
+
const citedContent = applyInlineCitation(rawContent);
|
|
13270
|
+
const sanitizedBase = sanitizeMemoryContent(rawContent);
|
|
13271
|
+
const dedupContent = options.category === "fact" && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0 ? `${sanitizedBase.text}
|
|
13272
|
+
[Attributes: ${normalizeAttributePairs(options.structuredAttributes)}]` : sanitizedBase.text;
|
|
13273
|
+
for (const target of targets) {
|
|
13274
|
+
if (!target.namespace) continue;
|
|
13275
|
+
try {
|
|
13276
|
+
const targetStorage = await this.storageRouter.storageFor(target.namespace);
|
|
13277
|
+
if (targetStorage.dir === options.sourceStorage.dir) continue;
|
|
13278
|
+
if (options.category === "fact" && await targetStorage.hasFactContentHash(dedupContent)) {
|
|
13279
|
+
continue;
|
|
13280
|
+
}
|
|
13281
|
+
const promotedId = await targetStorage.writeMemory(
|
|
13282
|
+
options.category,
|
|
13283
|
+
citedContent,
|
|
13284
|
+
{
|
|
13285
|
+
confidence: options.confidence,
|
|
13286
|
+
tags: [...options.tags, `${target.target}-promotion`],
|
|
13287
|
+
entityRef: options.entityRef,
|
|
13288
|
+
structuredAttributes: options.structuredAttributes,
|
|
13289
|
+
source: `${options.source}-${target.target}-promotion`,
|
|
13290
|
+
importance: options.importance,
|
|
13291
|
+
lineage: [options.sourceMemoryId],
|
|
13292
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
13293
|
+
intentGoal: options.intentGoal,
|
|
13294
|
+
intentActionType: options.intentActionType,
|
|
13295
|
+
intentEntityTypes: options.intentEntityTypes,
|
|
13296
|
+
memoryKind: options.memoryKind,
|
|
13297
|
+
validAt: options.validAt,
|
|
13298
|
+
contentHashSource: options.category === "fact" ? dedupContent : rawContent
|
|
13299
|
+
}
|
|
13300
|
+
);
|
|
13301
|
+
if (this.config.temporalSupersessionEnabled && options.category === "fact" && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
|
|
13302
|
+
try {
|
|
13303
|
+
await applyTemporalSupersession({
|
|
13304
|
+
storage: targetStorage,
|
|
13305
|
+
newMemoryId: promotedId,
|
|
13306
|
+
entityRef: options.entityRef,
|
|
13307
|
+
structuredAttributes: options.structuredAttributes,
|
|
13308
|
+
createdAt: supersessionOrderingAt(options.validAt),
|
|
13309
|
+
enabled: true
|
|
13310
|
+
});
|
|
13311
|
+
} catch (profileSupersessionErr) {
|
|
13312
|
+
log.warn(
|
|
13313
|
+
`persistExtraction: ${target.target} promotion temporal supersession failed open for promoted ${promotedId}: ${profileSupersessionErr}`
|
|
13314
|
+
);
|
|
13315
|
+
}
|
|
13316
|
+
}
|
|
13317
|
+
this.markCatalogWrite(target.namespace, targetStorage.dir);
|
|
13318
|
+
trackPersistedId(targetStorage, promotedId, { includeReturnedIds: false });
|
|
13319
|
+
await this.indexPersistedMemory(targetStorage, promotedId);
|
|
13320
|
+
trackBehaviorSignals(
|
|
13321
|
+
targetStorage,
|
|
13322
|
+
buildBehaviorSignalsForMemory({
|
|
13323
|
+
memoryId: promotedId,
|
|
13324
|
+
category: options.category,
|
|
13325
|
+
content: options.content,
|
|
13326
|
+
namespace: target.namespace,
|
|
13327
|
+
confidence: options.confidence,
|
|
13328
|
+
source: "extraction"
|
|
13329
|
+
})
|
|
13330
|
+
);
|
|
13331
|
+
} catch (err) {
|
|
13332
|
+
log.warn(
|
|
13333
|
+
`persistExtraction: ${target.target} promotion failed open for ${options.sourceMemoryId}: ${err}`
|
|
13334
|
+
);
|
|
13335
|
+
}
|
|
13336
|
+
}
|
|
12188
13337
|
};
|
|
12189
13338
|
const promoteMemoryToShared = async (options) => {
|
|
13339
|
+
await promoteMemoryToProfileTargets(options);
|
|
12190
13340
|
if (!shouldPromoteToShared(
|
|
12191
13341
|
options.sourceStorage,
|
|
12192
13342
|
options.category,
|
|
@@ -12273,11 +13423,10 @@ ${normalized}`).digest("hex");
|
|
|
12273
13423
|
intentEntityTypes: options.intentEntityTypes,
|
|
12274
13424
|
memoryKind: options.memoryKind,
|
|
12275
13425
|
validAt: options.validAt,
|
|
12276
|
-
// Index the
|
|
12277
|
-
//
|
|
12278
|
-
//
|
|
12279
|
-
|
|
12280
|
-
contentHashSource: rawContent
|
|
13426
|
+
// Index the same canonical body used by hasFactContentHash above.
|
|
13427
|
+
// For structured facts this includes the normalized Attributes
|
|
13428
|
+
// suffix, matching StorageManager.writeMemory enrichment.
|
|
13429
|
+
contentHashSource: options.category === "fact" ? dedupContent : rawContent
|
|
12281
13430
|
}
|
|
12282
13431
|
);
|
|
12283
13432
|
if (this.config.temporalSupersessionEnabled && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
|
|
@@ -12551,7 +13700,7 @@ ${normalized}`).digest("hex");
|
|
|
12551
13700
|
}
|
|
12552
13701
|
if (this.config.extractionScopeClassificationEnabled && this.config.namespacesEnabled && fact.scope === "global" && !routedNamespaceExplicit) {
|
|
12553
13702
|
const currentNs = this.namespaceFromStorageDir(targetStorage.dir);
|
|
12554
|
-
if (currentNs !== this.config.sharedNamespace) {
|
|
13703
|
+
if (currentNs !== this.config.sharedNamespace && profileAllowsSharedWrites) {
|
|
12555
13704
|
try {
|
|
12556
13705
|
targetStorage = await this.storageRouter.storageFor(
|
|
12557
13706
|
this.config.sharedNamespace
|
|
@@ -12565,13 +13714,28 @@ ${normalized}`).digest("hex");
|
|
|
12565
13714
|
`scope-routing: failed to resolve shared namespace storage; writing to session namespace (fail-open): ${scopeRouteErr}`
|
|
12566
13715
|
);
|
|
12567
13716
|
}
|
|
13717
|
+
} else if (currentNs !== this.config.sharedNamespace) {
|
|
13718
|
+
log.debug(
|
|
13719
|
+
`scope-routing: skipped shared namespace for global fact because active scope profile ${scopeProfileWritePlan?.profileId ?? "none"} does not authorize serverShared writes`
|
|
13720
|
+
);
|
|
12568
13721
|
}
|
|
12569
13722
|
}
|
|
12570
13723
|
const canonicalContentForHash = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
|
|
12571
13724
|
const contentHashDedupKey = writeCategory === "procedure" ? buildProcedurePersistBody(fact.content, fact.procedureSteps) : canonicalContentForHash;
|
|
12572
|
-
|
|
13725
|
+
let exactDuplicate = false;
|
|
13726
|
+
try {
|
|
13727
|
+
exactDuplicate = await this.hasContentHashDedup(
|
|
13728
|
+
targetStorage,
|
|
13729
|
+
contentHashDedupKey
|
|
13730
|
+
);
|
|
13731
|
+
} catch (err) {
|
|
13732
|
+
log.warn(
|
|
13733
|
+
`content-hash dedup lookup failed for storage ${targetStorage.dir}; writing fact fail-open: ${err}`
|
|
13734
|
+
);
|
|
13735
|
+
}
|
|
13736
|
+
if (exactDuplicate) {
|
|
12573
13737
|
log.debug(
|
|
12574
|
-
`dedup: skipping duplicate fact "${fact.content.slice(0, 60)}\u2026"`
|
|
13738
|
+
`dedup: skipping duplicate fact "${fact.content.slice(0, 60)}\u2026" in storage ${targetStorage.dir}`
|
|
12575
13739
|
);
|
|
12576
13740
|
dedupedCount++;
|
|
12577
13741
|
continue;
|
|
@@ -12834,9 +13998,13 @@ ${normalized}`).digest("hex");
|
|
|
12834
13998
|
validAt: sourceContext?.validAt,
|
|
12835
13999
|
source: extractionWriteSource
|
|
12836
14000
|
});
|
|
12837
|
-
|
|
14001
|
+
try {
|
|
12838
14002
|
const canonicalChunkedContent = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
|
|
12839
|
-
this.
|
|
14003
|
+
await this.addContentHashDedup(targetStorage, canonicalChunkedContent);
|
|
14004
|
+
} catch (err) {
|
|
14005
|
+
log.warn(
|
|
14006
|
+
`content-hash dedup registration failed for chunked memory ${parentId}: ${err}`
|
|
14007
|
+
);
|
|
12840
14008
|
}
|
|
12841
14009
|
for (const chunk of chunkResult.chunks) {
|
|
12842
14010
|
const chunkId = `${parentId}-chunk-${chunk.index}`;
|
|
@@ -13038,10 +14206,14 @@ ${normalized}`).digest("hex");
|
|
|
13038
14206
|
intentEntityTypes: inferredIntent?.entityTypes
|
|
13039
14207
|
});
|
|
13040
14208
|
}
|
|
13041
|
-
|
|
14209
|
+
try {
|
|
13042
14210
|
const canonicalFactContent = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
|
|
13043
14211
|
const hashRegisterKey = writeCategory === "procedure" ? buildProcedurePersistBody(fact.content, fact.procedureSteps) : canonicalFactContent;
|
|
13044
|
-
this.
|
|
14212
|
+
await this.addContentHashDedup(targetStorage, hashRegisterKey);
|
|
14213
|
+
} catch (err) {
|
|
14214
|
+
log.warn(
|
|
14215
|
+
`content-hash dedup registration failed for memory ${memoryId}: ${err}`
|
|
14216
|
+
);
|
|
13045
14217
|
}
|
|
13046
14218
|
} finally {
|
|
13047
14219
|
this.markCatalogWrite(targetNamespaceName, targetStorage.dir);
|
|
@@ -13141,9 +14313,9 @@ ${normalized}`).digest("hex");
|
|
|
13141
14313
|
if (durableNonFactWritten) {
|
|
13142
14314
|
touchBaseNonFactNamespace();
|
|
13143
14315
|
}
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
14316
|
+
await this.saveContentHashIndexes().catch(
|
|
14317
|
+
(err) => log.warn(`content-hash index save failed: ${err}`)
|
|
14318
|
+
);
|
|
13147
14319
|
for (const {
|
|
13148
14320
|
storage: targetStorage,
|
|
13149
14321
|
events
|
|
@@ -13196,7 +14368,7 @@ ${normalized}`).digest("hex");
|
|
|
13196
14368
|
const allMems = allMemsForGraph ?? [];
|
|
13197
14369
|
for (const m of allMems) {
|
|
13198
14370
|
if (m.frontmatter.entityRef === entityRef) {
|
|
13199
|
-
const rel =
|
|
14371
|
+
const rel = path4.relative(storage.dir, m.path);
|
|
13200
14372
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
13201
14373
|
}
|
|
13202
14374
|
}
|
|
@@ -13512,14 +14684,14 @@ ${normalized}`).digest("hex");
|
|
|
13512
14684
|
}
|
|
13513
14685
|
if (this.config.semanticConsolidationEnabled) {
|
|
13514
14686
|
try {
|
|
13515
|
-
const stateFilePath =
|
|
14687
|
+
const stateFilePath = path4.join(
|
|
13516
14688
|
this.config.memoryDir,
|
|
13517
14689
|
"state",
|
|
13518
14690
|
"semantic-consolidation-last-run.json"
|
|
13519
14691
|
);
|
|
13520
14692
|
let shouldRun = true;
|
|
13521
14693
|
try {
|
|
13522
|
-
const stateRaw = await
|
|
14694
|
+
const stateRaw = await readFile4(stateFilePath, "utf-8");
|
|
13523
14695
|
const stateData = JSON.parse(stateRaw);
|
|
13524
14696
|
if (stateData.lastRunAt) {
|
|
13525
14697
|
const lastRunMs = new Date(stateData.lastRunAt).getTime();
|
|
@@ -13560,9 +14732,9 @@ ${normalized}`).digest("hex");
|
|
|
13560
14732
|
);
|
|
13561
14733
|
}
|
|
13562
14734
|
if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
|
|
13563
|
-
const stateDir =
|
|
13564
|
-
await
|
|
13565
|
-
await
|
|
14735
|
+
const stateDir = path4.join(this.config.memoryDir, "state");
|
|
14736
|
+
await mkdir4(stateDir, { recursive: true });
|
|
14737
|
+
await writeFile4(
|
|
13566
14738
|
stateFilePath,
|
|
13567
14739
|
JSON.stringify({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
13568
14740
|
"utf-8"
|
|
@@ -13761,7 +14933,7 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
13761
14933
|
}
|
|
13762
14934
|
});
|
|
13763
14935
|
const content = renderCompressionGuidelinesMarkdown(refinedCandidate);
|
|
13764
|
-
const contentHash =
|
|
14936
|
+
const contentHash = createHash2("sha256").update(content).digest("hex");
|
|
13765
14937
|
const semanticRefinementApplied = JSON.stringify(refinedCandidate.ruleUpdates) !== JSON.stringify(candidate.ruleUpdates);
|
|
13766
14938
|
const changedRules = refinedCandidate.ruleUpdates.filter(
|
|
13767
14939
|
(rule) => rule.delta !== 0
|
|
@@ -14064,13 +15236,13 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
14064
15236
|
protectedCategories: this.config.lifecycleProtectedCategories
|
|
14065
15237
|
}
|
|
14066
15238
|
};
|
|
14067
|
-
const metricsPath =
|
|
15239
|
+
const metricsPath = path4.join(
|
|
14068
15240
|
storage.dir,
|
|
14069
15241
|
"state",
|
|
14070
15242
|
"lifecycle-metrics.json"
|
|
14071
15243
|
);
|
|
14072
|
-
await
|
|
14073
|
-
await
|
|
15244
|
+
await mkdir4(path4.dirname(metricsPath), { recursive: true });
|
|
15245
|
+
await writeFile4(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
|
|
14074
15246
|
return updatedCount;
|
|
14075
15247
|
}
|
|
14076
15248
|
/**
|
|
@@ -14098,16 +15270,11 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
14098
15270
|
if (accessCount > this.config.factArchivalMaxAccessCount) continue;
|
|
14099
15271
|
const result = await this.storage.archiveMemory(memory);
|
|
14100
15272
|
if (result) {
|
|
14101
|
-
|
|
14102
|
-
|
|
14103
|
-
|
|
14104
|
-
|
|
14105
|
-
|
|
14106
|
-
`[fact-archival] removing hash for legacy memory ${memory.frontmatter.id ?? "(unknown)"} via content fallback \u2014 no contentHash in frontmatter`
|
|
14107
|
-
);
|
|
14108
|
-
this.contentHashIndex.remove(memory.content);
|
|
14109
|
-
}
|
|
14110
|
-
}
|
|
15273
|
+
await this.removeContentHashForMemory(
|
|
15274
|
+
this.storage,
|
|
15275
|
+
memory,
|
|
15276
|
+
"fact-archival"
|
|
15277
|
+
);
|
|
14111
15278
|
await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);
|
|
14112
15279
|
if (this.config.queryAwareIndexingEnabled && memory.path && memory.frontmatter?.created) {
|
|
14113
15280
|
deindexMemory(
|
|
@@ -14120,8 +15287,8 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
14120
15287
|
archivedCount++;
|
|
14121
15288
|
}
|
|
14122
15289
|
}
|
|
14123
|
-
if (archivedCount > 0
|
|
14124
|
-
await this.
|
|
15290
|
+
if (archivedCount > 0) {
|
|
15291
|
+
await this.saveContentHashIndexes().catch(
|
|
14125
15292
|
(err) => log.warn(`content-hash index save failed during archival: ${err}`)
|
|
14126
15293
|
);
|
|
14127
15294
|
}
|
|
@@ -14603,7 +15770,7 @@ ${lines.join("\n\n")}`;
|
|
|
14603
15770
|
const seenStorageDirs = /* @__PURE__ */ new Set();
|
|
14604
15771
|
const addStorage = (storage) => {
|
|
14605
15772
|
const storageDir = storageDirFor(storage);
|
|
14606
|
-
const storageKey = storageDir ?
|
|
15773
|
+
const storageKey = storageDir ? path4.resolve(storageDir) : `storage-without-dir-${storages.length}`;
|
|
14607
15774
|
if (seenStorageDirs.has(storageKey)) return;
|
|
14608
15775
|
seenStorageDirs.add(storageKey);
|
|
14609
15776
|
storages.push(storage);
|
|
@@ -14633,7 +15800,7 @@ ${lines.join("\n\n")}`;
|
|
|
14633
15800
|
continue;
|
|
14634
15801
|
}
|
|
14635
15802
|
try {
|
|
14636
|
-
const coldRoot =
|
|
15803
|
+
const coldRoot = path4.join(storageDir, "cold");
|
|
14637
15804
|
for (const candidate of qmdResultPathCandidates(
|
|
14638
15805
|
coldRoot,
|
|
14639
15806
|
parts.relativePath
|
|
@@ -14674,7 +15841,7 @@ ${lines.join("\n\n")}`;
|
|
|
14674
15841
|
return null;
|
|
14675
15842
|
}
|
|
14676
15843
|
}
|
|
14677
|
-
if (
|
|
15844
|
+
if (path4.isAbsolute(resultPath)) {
|
|
14678
15845
|
if (!fallbackStorageDir) {
|
|
14679
15846
|
return await fallbackStorage.readMemoryByPath(resultPath);
|
|
14680
15847
|
}
|
|
@@ -14713,7 +15880,7 @@ ${lines.join("\n\n")}`;
|
|
|
14713
15880
|
);
|
|
14714
15881
|
if (!memory) return null;
|
|
14715
15882
|
let ownerNamespace = null;
|
|
14716
|
-
if (
|
|
15883
|
+
if (path4.isAbsolute(memory.path)) {
|
|
14717
15884
|
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
14718
15885
|
memory.path,
|
|
14719
15886
|
fallbackStorage,
|
|
@@ -14737,16 +15904,16 @@ ${lines.join("\n\n")}`;
|
|
|
14737
15904
|
};
|
|
14738
15905
|
}
|
|
14739
15906
|
async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
14740
|
-
const resolvedPath =
|
|
14741
|
-
const memoryRoot =
|
|
14742
|
-
const namespacesRoot =
|
|
15907
|
+
const resolvedPath = path4.resolve(resultPath);
|
|
15908
|
+
const memoryRoot = path4.resolve(this.config.memoryDir);
|
|
15909
|
+
const namespacesRoot = path4.join(memoryRoot, "namespaces");
|
|
14743
15910
|
const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
|
|
14744
15911
|
const matches = [];
|
|
14745
15912
|
const seenDirs = /* @__PURE__ */ new Set();
|
|
14746
15913
|
const maybeAddStorage = (storage, namespace) => {
|
|
14747
15914
|
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
14748
15915
|
if (!storageDir) return;
|
|
14749
|
-
const candidateRoot =
|
|
15916
|
+
const candidateRoot = path4.resolve(storageDir);
|
|
14750
15917
|
if (seenDirs.has(candidateRoot)) return;
|
|
14751
15918
|
if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
|
|
14752
15919
|
if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
@@ -14764,7 +15931,7 @@ ${lines.join("\n\n")}`;
|
|
|
14764
15931
|
candidateNamespaces.add(ns);
|
|
14765
15932
|
}
|
|
14766
15933
|
if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
14767
|
-
const relativeToNamespaces =
|
|
15934
|
+
const relativeToNamespaces = path4.relative(namespacesRoot, resolvedPath);
|
|
14768
15935
|
const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
|
|
14769
15936
|
if (namespaceSegment) {
|
|
14770
15937
|
candidateNamespaces.add(
|
|
@@ -14809,7 +15976,7 @@ ${lines.join("\n\n")}`;
|
|
|
14809
15976
|
nsMap = buildMemoryWorthCounterMap(memories);
|
|
14810
15977
|
this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
|
|
14811
15978
|
}
|
|
14812
|
-
for (const [
|
|
15979
|
+
for (const [path5, c] of nsMap) counters.set(path5, c);
|
|
14813
15980
|
} catch (err) {
|
|
14814
15981
|
log.debug("memory-worth: failed to read namespace, skipping", {
|
|
14815
15982
|
namespace: ns,
|
|
@@ -14980,12 +16147,12 @@ ${lines.join("\n\n")}`;
|
|
|
14980
16147
|
*/
|
|
14981
16148
|
semanticDedupScopeFor(targetStorage) {
|
|
14982
16149
|
if (!this.config.namespacesEnabled) return {};
|
|
14983
|
-
const memoryDir =
|
|
14984
|
-
const storageDir =
|
|
16150
|
+
const memoryDir = path4.resolve(this.config.memoryDir);
|
|
16151
|
+
const storageDir = path4.resolve(targetStorage.dir);
|
|
14985
16152
|
if (storageDir === memoryDir) {
|
|
14986
16153
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
14987
16154
|
}
|
|
14988
|
-
let rel =
|
|
16155
|
+
let rel = path4.relative(memoryDir, storageDir);
|
|
14989
16156
|
if (!rel || rel.startsWith("..")) {
|
|
14990
16157
|
log.debug(
|
|
14991
16158
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -15004,7 +16171,7 @@ ${lines.join("\n\n")}`;
|
|
|
15004
16171
|
if (hits.length === 0) return [];
|
|
15005
16172
|
const results = [];
|
|
15006
16173
|
for (const hit of hits) {
|
|
15007
|
-
const fullPath =
|
|
16174
|
+
const fullPath = path4.isAbsolute(hit.path) ? hit.path : path4.join(this.config.memoryDir, hit.path);
|
|
15008
16175
|
const memory = await this.storage.readMemoryByPath(fullPath);
|
|
15009
16176
|
if (!memory) continue;
|
|
15010
16177
|
results.push({
|
|
@@ -15179,7 +16346,7 @@ ${lines.join("\n\n")}`;
|
|
|
15179
16346
|
const storage = await this.storageRouter.storageFor(namespace);
|
|
15180
16347
|
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
15181
16348
|
if (!storageDir) continue;
|
|
15182
|
-
const recallRoot =
|
|
16349
|
+
const recallRoot = path4.resolve(storageDir);
|
|
15183
16350
|
if (seenRecallRoots.has(recallRoot)) continue;
|
|
15184
16351
|
seenRecallRoots.add(recallRoot);
|
|
15185
16352
|
recallRoots.push(recallRoot);
|
|
@@ -15203,8 +16370,8 @@ ${lines.join("\n\n")}`;
|
|
|
15203
16370
|
if (resolvedCold) scopedResults.push(resolvedCold.result);
|
|
15204
16371
|
continue;
|
|
15205
16372
|
}
|
|
15206
|
-
if (
|
|
15207
|
-
const resolvedPath =
|
|
16373
|
+
if (path4.isAbsolute(result.path)) {
|
|
16374
|
+
const resolvedPath = path4.resolve(result.path);
|
|
15208
16375
|
if (recallRoots.some(
|
|
15209
16376
|
(recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
|
|
15210
16377
|
)) {
|
|
@@ -15945,8 +17112,8 @@ ${lines.join("\n\n")}`;
|
|
|
15945
17112
|
}
|
|
15946
17113
|
namespaceFromStorageDir(storageDir) {
|
|
15947
17114
|
if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
|
|
15948
|
-
const resolvedStorageDir =
|
|
15949
|
-
const resolvedMemoryDir =
|
|
17115
|
+
const resolvedStorageDir = path4.resolve(storageDir);
|
|
17116
|
+
const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
|
|
15950
17117
|
if (resolvedStorageDir === resolvedMemoryDir)
|
|
15951
17118
|
return this.config.defaultNamespace;
|
|
15952
17119
|
const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
|
|
@@ -16076,4 +17243,4 @@ export {
|
|
|
16076
17243
|
resolvePersistedMemoryRelativePath,
|
|
16077
17244
|
Orchestrator
|
|
16078
17245
|
};
|
|
16079
|
-
//# sourceMappingURL=chunk-
|
|
17246
|
+
//# sourceMappingURL=chunk-RDW5G6DO.js.map
|