@remnic/core 9.3.654 → 9.3.655
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 +23 -23
- package/dist/access-http.d.ts +4 -4
- package/dist/access-http.js +16 -16
- package/dist/access-mcp.d.ts +4 -4
- package/dist/access-mcp.js +15 -15
- package/dist/{access-service-C8A5hoXJ.d.ts → access-service-BEJvriUt.d.ts} +2 -2
- package/dist/access-service.d.ts +4 -4
- package/dist/access-service.js +14 -14
- 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-BP2EV6W5.js → chunk-2RCGZ67B.js} +4 -4
- package/dist/{chunk-FVRBLJP6.js → chunk-54LOUIBE.js} +2 -2
- package/dist/{chunk-LJCEWTG3.js → chunk-55ZMNKMQ.js} +8 -8
- package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
- package/dist/{chunk-OL2364SB.js → chunk-5QD3QD76.js} +854 -223
- package/dist/chunk-5QD3QD76.js.map +1 -0
- package/dist/{chunk-DBM2BD22.js → chunk-67G4T7KI.js} +3 -3
- package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
- package/dist/{chunk-2DSTAWNZ.js → chunk-A3Y37UWI.js} +3 -3
- package/dist/{chunk-T2C6QJG2.js → chunk-BGKXTVNG.js} +2 -2
- package/dist/{chunk-JYN7QNTA.js → chunk-COVZLGMR.js} +17 -17
- package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
- package/dist/chunk-EKQMQQ3U.js.map +1 -0
- package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
- package/dist/{chunk-RGPUQ66K.js → chunk-IQ53ZSXV.js} +2 -2
- package/dist/{chunk-YLZLPVKK.js → chunk-KOI765XP.js} +104 -1
- package/dist/chunk-KOI765XP.js.map +1 -0
- package/dist/{chunk-QW6JZO5P.js → chunk-KZZ4YAEC.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-QKK64Z6M.js → chunk-NCSJKK23.js} +2 -2
- package/dist/{chunk-NCGWXCSW.js → chunk-NRBGRZW4.js} +2 -2
- package/dist/{chunk-GPW2E4LN.js → chunk-OKW6F5S5.js} +3 -3
- package/dist/{chunk-Y2RIIF6H.js → chunk-PTMJ2FH2.js} +2 -2
- package/dist/{chunk-JMQSYGXS.js → chunk-PVE7KSQP.js} +2 -2
- package/dist/{chunk-NAZWHTYV.js → chunk-QDVQ4AN2.js} +4 -4
- package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
- package/dist/chunk-QRSKPI62.js.map +1 -0
- package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
- package/dist/{chunk-NE2JBMLN.js → chunk-TDZSSJV4.js} +1 -1
- package/dist/chunk-TDZSSJV4.js.map +1 -0
- package/dist/{chunk-6CVI6BP6.js → chunk-TEO46GMM.js} +2 -2
- package/dist/{chunk-K6X553JB.js → chunk-UCEABZZN.js} +2 -2
- package/dist/{chunk-ENV6RDTD.js → chunk-UCEDY5M7.js} +2 -2
- package/dist/{chunk-ZCORQM74.js → chunk-UYNFWZWG.js} +2 -2
- package/dist/{chunk-XWQ6ERUG.js → chunk-WDTUYOLS.js} +2 -2
- package/dist/{chunk-Z5MQI7K2.js → chunk-XOFXKASO.js} +2 -2
- package/dist/{chunk-3RACUBII.js → chunk-XRKQOQLY.js} +2 -2
- package/dist/{chunk-BJA6DQOC.js → chunk-YYN3LIYA.js} +5 -5
- package/dist/{cli-uQgvDFNE.d.ts → cli-BGahB_d3.d.ts} +3 -3
- package/dist/cli.d.ts +5 -5
- package/dist/cli.js +28 -28
- 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/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/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +33 -33
- 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/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-BgzZlWxH.d.ts} +11 -14
- package/dist/orchestrator.d.ts +3 -3
- package/dist/orchestrator.js +19 -19
- 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/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-Z8d_uMq8.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 +1 -1
- package/dist/semantic-rule-verifier.js +3 -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/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-2OPlQWJG.d.ts} +12 -0
- 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.js +3 -3
- package/package.json +1 -1
- package/src/config.test.ts +69 -0
- package/src/config.ts +135 -0
- package/src/maintenance/namespace-planner.test.ts +1120 -0
- package/src/maintenance/namespace-planner.ts +893 -0
- package/src/namespaces/search.test.ts +130 -2
- package/src/namespaces/search.ts +71 -10
- package/src/orchestrator-flush.test.ts +464 -44
- package/src/orchestrator.ts +97 -66
- package/src/qmd-client.test.ts +59 -0
- package/src/qmd.ts +124 -84
- package/src/search/port.ts +16 -0
- package/src/types.ts +12 -0
- package/dist/chunk-JVRPJ7D4.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-YLZLPVKK.js.map +0 -1
- /package/dist/{chunk-BP2EV6W5.js.map → chunk-2RCGZ67B.js.map} +0 -0
- /package/dist/{chunk-FVRBLJP6.js.map → chunk-54LOUIBE.js.map} +0 -0
- /package/dist/{chunk-LJCEWTG3.js.map → chunk-55ZMNKMQ.js.map} +0 -0
- /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
- /package/dist/{chunk-DBM2BD22.js.map → chunk-67G4T7KI.js.map} +0 -0
- /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
- /package/dist/{chunk-2DSTAWNZ.js.map → chunk-A3Y37UWI.js.map} +0 -0
- /package/dist/{chunk-T2C6QJG2.js.map → chunk-BGKXTVNG.js.map} +0 -0
- /package/dist/{chunk-JYN7QNTA.js.map → chunk-COVZLGMR.js.map} +0 -0
- /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
- /package/dist/{chunk-RGPUQ66K.js.map → chunk-IQ53ZSXV.js.map} +0 -0
- /package/dist/{chunk-QW6JZO5P.js.map → chunk-KZZ4YAEC.js.map} +0 -0
- /package/dist/{chunk-QKK64Z6M.js.map → chunk-NCSJKK23.js.map} +0 -0
- /package/dist/{chunk-NCGWXCSW.js.map → chunk-NRBGRZW4.js.map} +0 -0
- /package/dist/{chunk-GPW2E4LN.js.map → chunk-OKW6F5S5.js.map} +0 -0
- /package/dist/{chunk-Y2RIIF6H.js.map → chunk-PTMJ2FH2.js.map} +0 -0
- /package/dist/{chunk-JMQSYGXS.js.map → chunk-PVE7KSQP.js.map} +0 -0
- /package/dist/{chunk-NAZWHTYV.js.map → chunk-QDVQ4AN2.js.map} +0 -0
- /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
- /package/dist/{chunk-6CVI6BP6.js.map → chunk-TEO46GMM.js.map} +0 -0
- /package/dist/{chunk-K6X553JB.js.map → chunk-UCEABZZN.js.map} +0 -0
- /package/dist/{chunk-ENV6RDTD.js.map → chunk-UCEDY5M7.js.map} +0 -0
- /package/dist/{chunk-ZCORQM74.js.map → chunk-UYNFWZWG.js.map} +0 -0
- /package/dist/{chunk-XWQ6ERUG.js.map → chunk-WDTUYOLS.js.map} +0 -0
- /package/dist/{chunk-Z5MQI7K2.js.map → chunk-XOFXKASO.js.map} +0 -0
- /package/dist/{chunk-3RACUBII.js.map → chunk-XRKQOQLY.js.map} +0 -0
- /package/dist/{chunk-BJA6DQOC.js.map → chunk-YYN3LIYA.js.map} +0 -0
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
CompoundingEngine,
|
|
31
31
|
defaultTierMigrationCycleBudget
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-UYNFWZWG.js";
|
|
33
33
|
import {
|
|
34
34
|
SharedContextManager
|
|
35
35
|
} from "./chunk-DRD2Q7HQ.js";
|
|
@@ -175,7 +175,7 @@ import {
|
|
|
175
175
|
buildEntityRecallSection,
|
|
176
176
|
entityRecentTranscriptLookbackHours,
|
|
177
177
|
readRecentEntityTranscriptEntries
|
|
178
|
-
} from "./chunk-
|
|
178
|
+
} from "./chunk-NRBGRZW4.js";
|
|
179
179
|
import {
|
|
180
180
|
buildEventOrderRecallSection,
|
|
181
181
|
shouldRecallEventOrderEvidence
|
|
@@ -210,7 +210,7 @@ import {
|
|
|
210
210
|
materializeAfterSemanticConsolidation,
|
|
211
211
|
parseConsolidationResponse,
|
|
212
212
|
parseOperatorAwareConsolidationResponse
|
|
213
|
-
} from "./chunk-
|
|
213
|
+
} from "./chunk-BGKXTVNG.js";
|
|
214
214
|
import {
|
|
215
215
|
normalizeReplaySessionKey
|
|
216
216
|
} from "./chunk-2PRQG7PV.js";
|
|
@@ -219,13 +219,13 @@ import {
|
|
|
219
219
|
} from "./chunk-X6IRLNOO.js";
|
|
220
220
|
import {
|
|
221
221
|
searchVerifiedEpisodes
|
|
222
|
-
} from "./chunk-
|
|
222
|
+
} from "./chunk-NCSJKK23.js";
|
|
223
223
|
import {
|
|
224
224
|
ThreadingManager
|
|
225
225
|
} from "./chunk-W4RVMTHR.js";
|
|
226
226
|
import {
|
|
227
227
|
searchVerifiedSemanticRules
|
|
228
|
-
} from "./chunk-
|
|
228
|
+
} from "./chunk-UCEABZZN.js";
|
|
229
229
|
import {
|
|
230
230
|
searchWorkProductLedgerEntries
|
|
231
231
|
} from "./chunk-ZRWB5D4H.js";
|
|
@@ -239,7 +239,7 @@ import {
|
|
|
239
239
|
NamespaceStorageRouter,
|
|
240
240
|
resolveDefaultNamespaceRoot,
|
|
241
241
|
resolveNamespaceStorageRoot
|
|
242
|
-
} from "./chunk-
|
|
242
|
+
} from "./chunk-XRKQOQLY.js";
|
|
243
243
|
import {
|
|
244
244
|
isAboveImportanceThreshold,
|
|
245
245
|
scoreImportance
|
|
@@ -317,14 +317,14 @@ import {
|
|
|
317
317
|
} from "./chunk-FF4KLI5W.js";
|
|
318
318
|
import {
|
|
319
319
|
buildXraySnapshot
|
|
320
|
-
} from "./chunk-
|
|
320
|
+
} from "./chunk-54LOUIBE.js";
|
|
321
321
|
import {
|
|
322
322
|
NamespaceSearchRouter
|
|
323
|
-
} from "./chunk-
|
|
323
|
+
} from "./chunk-EKQMQQ3U.js";
|
|
324
324
|
import {
|
|
325
325
|
createConversationIndexRuntime,
|
|
326
326
|
createSearchBackend
|
|
327
|
-
} from "./chunk-
|
|
327
|
+
} from "./chunk-SSSXWIBP.js";
|
|
328
328
|
import {
|
|
329
329
|
NoopSearchBackend
|
|
330
330
|
} from "./chunk-CYEPCZN5.js";
|
|
@@ -338,7 +338,7 @@ import {
|
|
|
338
338
|
} from "./chunk-OIF36KGD.js";
|
|
339
339
|
import {
|
|
340
340
|
parseQmdExplain
|
|
341
|
-
} from "./chunk-
|
|
341
|
+
} from "./chunk-QRSKPI62.js";
|
|
342
342
|
import {
|
|
343
343
|
objectiveStateStoreOverrideForNamespace,
|
|
344
344
|
searchObjectiveStateSnapshots
|
|
@@ -357,7 +357,7 @@ import {
|
|
|
357
357
|
} from "./chunk-Y56J7CXW.js";
|
|
358
358
|
import {
|
|
359
359
|
buildChainFollowupGenerator
|
|
360
|
-
} from "./chunk-
|
|
360
|
+
} from "./chunk-PTMJ2FH2.js";
|
|
361
361
|
import {
|
|
362
362
|
ALL_CATEGORY_DIRS,
|
|
363
363
|
ContentHashIndex,
|
|
@@ -368,7 +368,7 @@ import {
|
|
|
368
368
|
normalizeEntityName,
|
|
369
369
|
parseEntityFile,
|
|
370
370
|
stripAttributesSuffix
|
|
371
|
-
} from "./chunk-
|
|
371
|
+
} from "./chunk-TEO46GMM.js";
|
|
372
372
|
import {
|
|
373
373
|
isValidTranscriptDate,
|
|
374
374
|
loadSpeakerRegistry,
|
|
@@ -383,11 +383,14 @@ import {
|
|
|
383
383
|
} from "./chunk-J6A3CX5N.js";
|
|
384
384
|
import {
|
|
385
385
|
confidenceTier
|
|
386
|
-
} from "./chunk-
|
|
386
|
+
} from "./chunk-TDZSSJV4.js";
|
|
387
387
|
import {
|
|
388
388
|
inferMemoryStatus,
|
|
389
389
|
isActiveMemoryStatus
|
|
390
390
|
} from "./chunk-RULE4VG5.js";
|
|
391
|
+
import {
|
|
392
|
+
displayErrorDetail
|
|
393
|
+
} from "./chunk-6KYMPV2O.js";
|
|
391
394
|
import {
|
|
392
395
|
lintWorkspaceFiles,
|
|
393
396
|
rotateMarkdownFileToArchive
|
|
@@ -438,17 +441,17 @@ import {
|
|
|
438
441
|
} from "./chunk-AC5LO7IU.js";
|
|
439
442
|
|
|
440
443
|
// src/orchestrator.ts
|
|
441
|
-
import
|
|
444
|
+
import path4 from "path";
|
|
442
445
|
import os from "os";
|
|
443
|
-
import { createHash, randomBytes } from "crypto";
|
|
446
|
+
import { createHash as createHash2, randomBytes } from "crypto";
|
|
444
447
|
import { existsSync, readFileSync } from "fs";
|
|
445
448
|
import {
|
|
446
|
-
mkdir as
|
|
447
|
-
readdir as
|
|
448
|
-
readFile as
|
|
449
|
-
stat as
|
|
449
|
+
mkdir as mkdir4,
|
|
450
|
+
readdir as readdir3,
|
|
451
|
+
readFile as readFile4,
|
|
452
|
+
stat as stat3,
|
|
450
453
|
unlink as unlink2,
|
|
451
|
-
writeFile as
|
|
454
|
+
writeFile as writeFile4
|
|
452
455
|
} from "fs/promises";
|
|
453
456
|
|
|
454
457
|
// src/procedural/procedure-recall.ts
|
|
@@ -2051,9 +2054,9 @@ var NamespaceCatalog = class {
|
|
|
2051
2054
|
}
|
|
2052
2055
|
if (await this.hasSymlinkedAncestor(candidate)) return false;
|
|
2053
2056
|
try {
|
|
2054
|
-
const
|
|
2055
|
-
if (
|
|
2056
|
-
if (!
|
|
2057
|
+
const stat4 = await lstat(candidate);
|
|
2058
|
+
if (stat4.isSymbolicLink()) return false;
|
|
2059
|
+
if (!stat4.isDirectory()) return false;
|
|
2057
2060
|
} catch {
|
|
2058
2061
|
return this.isNearestExistingAncestorContained(candidate, memoryReal);
|
|
2059
2062
|
}
|
|
@@ -2114,8 +2117,8 @@ var NamespaceCatalog = class {
|
|
|
2114
2117
|
}
|
|
2115
2118
|
if (!(isPathInside(memoryReal, real) || real === memoryReal)) return false;
|
|
2116
2119
|
try {
|
|
2117
|
-
const
|
|
2118
|
-
return
|
|
2120
|
+
const stat4 = await lstat(real);
|
|
2121
|
+
return stat4.isDirectory();
|
|
2119
2122
|
} catch {
|
|
2120
2123
|
return false;
|
|
2121
2124
|
}
|
|
@@ -2279,14 +2282,14 @@ var NamespaceCatalog = class {
|
|
|
2279
2282
|
if (normalizeNamespaceIdentity(namespace) !== this.defaultNamespaceIdentity && path2.resolve(root) === path2.resolve(this.memoryDir)) {
|
|
2280
2283
|
return false;
|
|
2281
2284
|
}
|
|
2282
|
-
let
|
|
2285
|
+
let stat4;
|
|
2283
2286
|
try {
|
|
2284
|
-
|
|
2287
|
+
stat4 = await lstat(root);
|
|
2285
2288
|
} catch {
|
|
2286
2289
|
return false;
|
|
2287
2290
|
}
|
|
2288
|
-
if (
|
|
2289
|
-
if (!
|
|
2291
|
+
if (stat4.isSymbolicLink()) return false;
|
|
2292
|
+
if (!stat4.isDirectory()) return false;
|
|
2290
2293
|
try {
|
|
2291
2294
|
const real = await realpath(root);
|
|
2292
2295
|
if (memoryReal && !isPathInside(memoryReal, real)) return false;
|
|
@@ -2463,18 +2466,18 @@ var NamespaceCatalog = class {
|
|
|
2463
2466
|
for (const entry of entries) {
|
|
2464
2467
|
const token = entry.name;
|
|
2465
2468
|
const fullPath = path2.join(namespacesDir, token);
|
|
2466
|
-
let
|
|
2469
|
+
let stat4;
|
|
2467
2470
|
try {
|
|
2468
|
-
|
|
2471
|
+
stat4 = await lstat(fullPath);
|
|
2469
2472
|
} catch (err) {
|
|
2470
2473
|
skipped.push({ token, reason: "error", detail: err instanceof Error ? err.message : String(err) });
|
|
2471
2474
|
continue;
|
|
2472
2475
|
}
|
|
2473
|
-
if (
|
|
2476
|
+
if (stat4.isSymbolicLink()) {
|
|
2474
2477
|
skipped.push({ token, reason: "symlink", detail: fullPath });
|
|
2475
2478
|
continue;
|
|
2476
2479
|
}
|
|
2477
|
-
if (!
|
|
2480
|
+
if (!stat4.isDirectory()) continue;
|
|
2478
2481
|
try {
|
|
2479
2482
|
const real = await realpath(fullPath);
|
|
2480
2483
|
if (memoryReal && !isPathInside(memoryReal, real)) {
|
|
@@ -2865,6 +2868,611 @@ function isPathInside(root, child) {
|
|
|
2865
2868
|
return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
|
|
2866
2869
|
}
|
|
2867
2870
|
|
|
2871
|
+
// src/maintenance/namespace-planner.ts
|
|
2872
|
+
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
2873
|
+
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";
|
|
2874
|
+
import path3 from "path";
|
|
2875
|
+
var DEFAULT_MAX_NAMESPACES_PER_CYCLE = 20;
|
|
2876
|
+
var DEFAULT_LOCK_STALE_MS = 10 * 6e4;
|
|
2877
|
+
var LOCK_BASE = "maintenance-locks";
|
|
2878
|
+
var STATUS_BASE = "namespace-maintenance-status";
|
|
2879
|
+
var namespaceMaintenanceFs = { open: open2, rm };
|
|
2880
|
+
function configuredNamespaces(config) {
|
|
2881
|
+
return Array.from(
|
|
2882
|
+
new Set(
|
|
2883
|
+
[config.defaultNamespace, config.sharedNamespace, ...config.namespacePolicies.map((policy) => policy.name)].map((value) => value.trim()).filter(Boolean)
|
|
2884
|
+
)
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
function inferConfiguredKind(config, namespace) {
|
|
2888
|
+
if (namespace === config.defaultNamespace.trim()) return "default";
|
|
2889
|
+
if (namespace === config.sharedNamespace.trim()) return "shared";
|
|
2890
|
+
return "explicit";
|
|
2891
|
+
}
|
|
2892
|
+
function maxNamespacesPerCycle(config) {
|
|
2893
|
+
return Math.max(
|
|
2894
|
+
1,
|
|
2895
|
+
Math.floor(
|
|
2896
|
+
typeof config.maintenanceMaxNamespacesPerCycle === "number" && Number.isFinite(config.maintenanceMaxNamespacesPerCycle) ? config.maintenanceMaxNamespacesPerCycle : DEFAULT_MAX_NAMESPACES_PER_CYCLE
|
|
2897
|
+
)
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
function namespaceKindAllowed(config, kind) {
|
|
2901
|
+
switch (kind) {
|
|
2902
|
+
case "branch":
|
|
2903
|
+
return config.maintenanceIncludeBranchNamespaces === true;
|
|
2904
|
+
case "project":
|
|
2905
|
+
return config.maintenanceIncludeProjectNamespaces !== false;
|
|
2906
|
+
case "team-project":
|
|
2907
|
+
return config.maintenanceIncludeTeamProjectNamespaces !== false;
|
|
2908
|
+
default:
|
|
2909
|
+
return true;
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
function disabledReasonForKind(kind) {
|
|
2913
|
+
if (kind === "branch") return "branch_disabled";
|
|
2914
|
+
if (kind === "project") return "project_disabled";
|
|
2915
|
+
if (kind === "team-project") return "team_project_disabled";
|
|
2916
|
+
return "fanout_disabled";
|
|
2917
|
+
}
|
|
2918
|
+
async function catalogRootIsLive(config, record) {
|
|
2919
|
+
if (typeof record.storageDir !== "string" || record.storageDir.length === 0) {
|
|
2920
|
+
return false;
|
|
2921
|
+
}
|
|
2922
|
+
try {
|
|
2923
|
+
const liveRoot = await resolveNamespaceStorageRoot(config, record.namespace);
|
|
2924
|
+
if (path3.resolve(liveRoot) !== path3.resolve(record.storageDir)) return false;
|
|
2925
|
+
return hasMemoryData(liveRoot);
|
|
2926
|
+
} catch {
|
|
2927
|
+
return false;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
function candidateSortKey(candidate) {
|
|
2931
|
+
const write = candidate.lastWriteAt ?? "";
|
|
2932
|
+
return `${write}\0${candidate.namespace}`;
|
|
2933
|
+
}
|
|
2934
|
+
function candidatePriority(candidate) {
|
|
2935
|
+
if (candidate.kind === "default") return 0;
|
|
2936
|
+
if (candidate.kind === "shared") return 1;
|
|
2937
|
+
if (candidate.source === "configured") return 2;
|
|
2938
|
+
if (candidate.kind === "team-project") return 3;
|
|
2939
|
+
if (candidate.kind === "project") return 4;
|
|
2940
|
+
if (candidate.kind === "self") return 5;
|
|
2941
|
+
if (candidate.kind === "legacy") return 6;
|
|
2942
|
+
if (candidate.kind === "branch") return 8;
|
|
2943
|
+
return 7;
|
|
2944
|
+
}
|
|
2945
|
+
function sortCandidates(a, b) {
|
|
2946
|
+
const priority = candidatePriority(a) - candidatePriority(b);
|
|
2947
|
+
if (priority !== 0) return priority;
|
|
2948
|
+
const am = Date.parse(a.lastMaintenanceAt ?? "");
|
|
2949
|
+
const bm = Date.parse(b.lastMaintenanceAt ?? "");
|
|
2950
|
+
const aMaintained = Number.isFinite(am);
|
|
2951
|
+
const bMaintained = Number.isFinite(bm);
|
|
2952
|
+
if (aMaintained && bMaintained && am !== bm) return am - bm;
|
|
2953
|
+
if (aMaintained !== bMaintained) return aMaintained ? 1 : -1;
|
|
2954
|
+
const aw = Date.parse(a.lastWriteAt ?? "");
|
|
2955
|
+
const bw = Date.parse(b.lastWriteAt ?? "");
|
|
2956
|
+
const aValid = Number.isFinite(aw);
|
|
2957
|
+
const bValid = Number.isFinite(bw);
|
|
2958
|
+
if (aValid && bValid && aw !== bw) return bw - aw;
|
|
2959
|
+
if (aValid !== bValid) return aValid ? -1 : 1;
|
|
2960
|
+
const byKey = candidateSortKey(a).localeCompare(candidateSortKey(b));
|
|
2961
|
+
if (byKey !== 0) return byKey;
|
|
2962
|
+
return a.namespace.localeCompare(b.namespace);
|
|
2963
|
+
}
|
|
2964
|
+
async function planNamespaceMaintenance(config, options) {
|
|
2965
|
+
const generatedAt = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
2966
|
+
const configured = configuredNamespaces(config);
|
|
2967
|
+
const byNamespace = /* @__PURE__ */ new Map();
|
|
2968
|
+
const skipped = [];
|
|
2969
|
+
for (const namespace of configured) {
|
|
2970
|
+
const kind = inferConfiguredKind(config, namespace);
|
|
2971
|
+
byNamespace.set(namespace, {
|
|
2972
|
+
namespace,
|
|
2973
|
+
kind,
|
|
2974
|
+
source: "configured"
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
if (config.namespacesEnabled && config.maintenanceNamespaceFanoutEnabled !== false) {
|
|
2978
|
+
const configuredSet = new Set(configured);
|
|
2979
|
+
try {
|
|
2980
|
+
const records = options.catalog?.enabled ? await options.catalog.listNamespaces() : [];
|
|
2981
|
+
for (const record of records) {
|
|
2982
|
+
const namespace = record.namespace.trim();
|
|
2983
|
+
if (!namespace) continue;
|
|
2984
|
+
const isConfigured = configuredSet.has(namespace);
|
|
2985
|
+
const kind = isConfigured ? inferConfiguredKind(config, namespace) : record.kind;
|
|
2986
|
+
if (!namespaceKindAllowed(config, kind)) {
|
|
2987
|
+
skipped.push({
|
|
2988
|
+
namespace,
|
|
2989
|
+
kind,
|
|
2990
|
+
reason: disabledReasonForKind(kind)
|
|
2991
|
+
});
|
|
2992
|
+
continue;
|
|
2993
|
+
}
|
|
2994
|
+
if (!isConfigured && !await catalogRootIsLive(config, record)) {
|
|
2995
|
+
skipped.push({
|
|
2996
|
+
namespace,
|
|
2997
|
+
kind,
|
|
2998
|
+
reason: "unsafe_or_stale_root"
|
|
2999
|
+
});
|
|
3000
|
+
continue;
|
|
3001
|
+
}
|
|
3002
|
+
byNamespace.set(namespace, {
|
|
3003
|
+
namespace,
|
|
3004
|
+
kind,
|
|
3005
|
+
storageDir: record.storageDir,
|
|
3006
|
+
source: isConfigured ? "configured" : "catalog",
|
|
3007
|
+
lastWriteAt: record.lastWriteAt,
|
|
3008
|
+
lastMaintenanceAt: record.lastMaintenanceAt?.[options.jobName]
|
|
3009
|
+
});
|
|
3010
|
+
}
|
|
3011
|
+
} catch (error) {
|
|
3012
|
+
skipped.push({
|
|
3013
|
+
namespace: "*",
|
|
3014
|
+
reason: "catalog_read_failed",
|
|
3015
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
3016
|
+
});
|
|
3017
|
+
}
|
|
3018
|
+
} else if (config.namespacesEnabled) {
|
|
3019
|
+
skipped.push({
|
|
3020
|
+
namespace: "*",
|
|
3021
|
+
reason: "fanout_disabled"
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
if (options.budgetMode !== "unbounded") {
|
|
3025
|
+
const latestStatusAtByNamespace = await readLatestStatusAtByNamespace(config, options.jobName);
|
|
3026
|
+
for (const candidate of byNamespace.values()) {
|
|
3027
|
+
if (!candidate.lastMaintenanceAt) {
|
|
3028
|
+
candidate.lastMaintenanceAt = latestStatusAtByNamespace.get(candidate.namespace);
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
const candidates = [...byNamespace.values()].filter((candidate) => namespaceKindAllowed(config, candidate.kind)).sort(sortCandidates);
|
|
3033
|
+
const max = maxNamespacesPerCycle(config);
|
|
3034
|
+
const applyCycleBudget = options.budgetMode !== "unbounded";
|
|
3035
|
+
const selected = applyCycleBudget ? candidates.slice(0, max) : candidates;
|
|
3036
|
+
if (applyCycleBudget) {
|
|
3037
|
+
for (const candidate of candidates.slice(max)) {
|
|
3038
|
+
skipped.push({
|
|
3039
|
+
namespace: candidate.namespace,
|
|
3040
|
+
kind: candidate.kind,
|
|
3041
|
+
reason: "budget_exhausted"
|
|
3042
|
+
});
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
return {
|
|
3046
|
+
jobName: options.jobName,
|
|
3047
|
+
generatedAt,
|
|
3048
|
+
namespaces: selected,
|
|
3049
|
+
skipped,
|
|
3050
|
+
budget: {
|
|
3051
|
+
maxNamespacesPerCycle: max,
|
|
3052
|
+
selected: selected.length
|
|
3053
|
+
}
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
3056
|
+
function stablePathSegment(value) {
|
|
3057
|
+
const sanitized = value.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 128) || "unnamed";
|
|
3058
|
+
if (sanitized.length <= 128 && sanitized === value) return sanitized;
|
|
3059
|
+
return `${sanitized.slice(0, 80)}-${createHash("sha256").update(value).digest("hex").slice(0, 16)}`;
|
|
3060
|
+
}
|
|
3061
|
+
function namespacePathSegment(namespace) {
|
|
3062
|
+
const token = namespaceIdentityToken(namespace);
|
|
3063
|
+
if (token.length <= 160) return token;
|
|
3064
|
+
return `ns-${createHash("sha256").update(namespace).digest("hex")}`;
|
|
3065
|
+
}
|
|
3066
|
+
function lockPath(config, jobName, namespace) {
|
|
3067
|
+
return path3.join(
|
|
3068
|
+
config.memoryDir,
|
|
3069
|
+
"state",
|
|
3070
|
+
LOCK_BASE,
|
|
3071
|
+
stablePathSegment(jobName),
|
|
3072
|
+
`${namespacePathSegment(namespace)}.lock`
|
|
3073
|
+
);
|
|
3074
|
+
}
|
|
3075
|
+
function namespaceMaintenanceLockStaleMs(config) {
|
|
3076
|
+
if (typeof config.maintenanceNamespaceLockStaleMs === "number" && Number.isFinite(config.maintenanceNamespaceLockStaleMs) && config.maintenanceNamespaceLockStaleMs > 0) {
|
|
3077
|
+
return Math.floor(config.maintenanceNamespaceLockStaleMs);
|
|
3078
|
+
}
|
|
3079
|
+
return DEFAULT_LOCK_STALE_MS;
|
|
3080
|
+
}
|
|
3081
|
+
function namespaceMaintenanceLockHeartbeatMs(config) {
|
|
3082
|
+
const staleMs = namespaceMaintenanceLockStaleMs(config);
|
|
3083
|
+
return Math.max(1, Math.min(3e4, Math.floor(staleMs / 3) || 1));
|
|
3084
|
+
}
|
|
3085
|
+
function errorCode(error) {
|
|
3086
|
+
return typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
3087
|
+
}
|
|
3088
|
+
async function withNamespaceMaintenanceLockHeartbeat(config, locks, task) {
|
|
3089
|
+
const activeLocks = Array.isArray(locks) ? locks : [locks];
|
|
3090
|
+
const interval = setInterval(() => {
|
|
3091
|
+
for (const lock of activeLocks) {
|
|
3092
|
+
void lock.touch().catch(() => void 0);
|
|
3093
|
+
}
|
|
3094
|
+
}, namespaceMaintenanceLockHeartbeatMs(config));
|
|
3095
|
+
interval.unref?.();
|
|
3096
|
+
try {
|
|
3097
|
+
return await task();
|
|
3098
|
+
} finally {
|
|
3099
|
+
clearInterval(interval);
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
async function removeStaleLockDirectory(filePath) {
|
|
3103
|
+
let entries;
|
|
3104
|
+
try {
|
|
3105
|
+
entries = await readdir2(filePath, { withFileTypes: true });
|
|
3106
|
+
} catch (error) {
|
|
3107
|
+
if (errorCode(error) === "ENOENT") return;
|
|
3108
|
+
throw error;
|
|
3109
|
+
}
|
|
3110
|
+
for (const entry of entries) {
|
|
3111
|
+
if (!entry.isFile()) continue;
|
|
3112
|
+
await namespaceMaintenanceFs.rm(path3.join(filePath, entry.name), { force: true });
|
|
3113
|
+
}
|
|
3114
|
+
try {
|
|
3115
|
+
await rmdir(filePath);
|
|
3116
|
+
} catch (error) {
|
|
3117
|
+
if (errorCode(error) === "ENOENT") return;
|
|
3118
|
+
throw error;
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
async function tryAcquireNamespaceMaintenanceLock(config, jobName, namespace) {
|
|
3122
|
+
const filePath = lockPath(config, jobName, namespace);
|
|
3123
|
+
await mkdir3(path3.dirname(filePath), { recursive: true });
|
|
3124
|
+
try {
|
|
3125
|
+
const lockId = randomUUID2();
|
|
3126
|
+
await mkdir3(filePath);
|
|
3127
|
+
const ownerPath = path3.join(filePath, `${lockId}.json`);
|
|
3128
|
+
let handle;
|
|
3129
|
+
try {
|
|
3130
|
+
handle = await namespaceMaintenanceFs.open(ownerPath, "wx");
|
|
3131
|
+
await handle.writeFile(
|
|
3132
|
+
`${JSON.stringify({
|
|
3133
|
+
lockId,
|
|
3134
|
+
pid: process.pid,
|
|
3135
|
+
jobName,
|
|
3136
|
+
namespace,
|
|
3137
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3138
|
+
})}
|
|
3139
|
+
`,
|
|
3140
|
+
"utf8"
|
|
3141
|
+
);
|
|
3142
|
+
await handle.close();
|
|
3143
|
+
} catch (setupError) {
|
|
3144
|
+
await handle?.close().catch(() => void 0);
|
|
3145
|
+
await namespaceMaintenanceFs.rm(ownerPath, { force: true }).catch(() => void 0);
|
|
3146
|
+
await rmdir(filePath).catch(() => void 0);
|
|
3147
|
+
throw setupError;
|
|
3148
|
+
}
|
|
3149
|
+
return {
|
|
3150
|
+
path: filePath,
|
|
3151
|
+
async touch() {
|
|
3152
|
+
try {
|
|
3153
|
+
const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
|
|
3154
|
+
if (parsed.lockId === lockId) {
|
|
3155
|
+
const now = /* @__PURE__ */ new Date();
|
|
3156
|
+
await utimes2(ownerPath, now, now);
|
|
3157
|
+
await utimes2(filePath, now, now);
|
|
3158
|
+
}
|
|
3159
|
+
} catch {
|
|
3160
|
+
}
|
|
3161
|
+
},
|
|
3162
|
+
async release() {
|
|
3163
|
+
try {
|
|
3164
|
+
const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
|
|
3165
|
+
if (parsed.lockId === lockId) {
|
|
3166
|
+
await namespaceMaintenanceFs.rm(ownerPath, { force: true });
|
|
3167
|
+
await rmdir(filePath).catch(() => void 0);
|
|
3168
|
+
}
|
|
3169
|
+
} catch {
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
};
|
|
3173
|
+
} catch (error) {
|
|
3174
|
+
if (errorCode(error) === "EEXIST") {
|
|
3175
|
+
const staleMs = namespaceMaintenanceLockStaleMs(config);
|
|
3176
|
+
try {
|
|
3177
|
+
const s = await lstat2(filePath);
|
|
3178
|
+
if (s.isSymbolicLink()) {
|
|
3179
|
+
return null;
|
|
3180
|
+
}
|
|
3181
|
+
if ((s.isFile() || s.isDirectory()) && Date.now() - s.mtimeMs > staleMs) {
|
|
3182
|
+
try {
|
|
3183
|
+
if (s.isDirectory()) {
|
|
3184
|
+
await removeStaleLockDirectory(filePath);
|
|
3185
|
+
} else {
|
|
3186
|
+
await namespaceMaintenanceFs.rm(filePath, { force: true });
|
|
3187
|
+
}
|
|
3188
|
+
} catch (removeError) {
|
|
3189
|
+
if (errorCode(removeError) === "ENOENT") {
|
|
3190
|
+
return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
|
|
3191
|
+
}
|
|
3192
|
+
if (errorCode(removeError) === "ENOTEMPTY") {
|
|
3193
|
+
return null;
|
|
3194
|
+
}
|
|
3195
|
+
throw removeError;
|
|
3196
|
+
}
|
|
3197
|
+
return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
|
|
3198
|
+
}
|
|
3199
|
+
} catch (statError) {
|
|
3200
|
+
if (errorCode(statError) === "ENOENT") {
|
|
3201
|
+
return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
|
|
3202
|
+
}
|
|
3203
|
+
throw statError;
|
|
3204
|
+
}
|
|
3205
|
+
return null;
|
|
3206
|
+
}
|
|
3207
|
+
throw error;
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
function statusBasePath(config) {
|
|
3211
|
+
return path3.join(config.memoryDir, "state", STATUS_BASE);
|
|
3212
|
+
}
|
|
3213
|
+
function statusPath(config, jobName, namespace) {
|
|
3214
|
+
return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.json`);
|
|
3215
|
+
}
|
|
3216
|
+
function lastRanStatusPath(config, jobName, namespace) {
|
|
3217
|
+
return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.last-ran.json`);
|
|
3218
|
+
}
|
|
3219
|
+
function parseStatus(value) {
|
|
3220
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
3221
|
+
const v = value;
|
|
3222
|
+
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") {
|
|
3223
|
+
return v;
|
|
3224
|
+
}
|
|
3225
|
+
return null;
|
|
3226
|
+
}
|
|
3227
|
+
async function readLatestStatusAtByNamespace(config, jobName) {
|
|
3228
|
+
const latest = /* @__PURE__ */ new Map();
|
|
3229
|
+
const latestMs = /* @__PURE__ */ new Map();
|
|
3230
|
+
for (const status of [...await readStatusFiles(config), ...await readLastRanStatusFiles(config)]) {
|
|
3231
|
+
if (status.state !== "ran") continue;
|
|
3232
|
+
if (status.jobName !== jobName) continue;
|
|
3233
|
+
const completedAtMs = Date.parse(status.completedAt);
|
|
3234
|
+
if (!Number.isFinite(completedAtMs)) continue;
|
|
3235
|
+
const previousMs = latestMs.get(status.namespace);
|
|
3236
|
+
if (previousMs !== void 0 && previousMs >= completedAtMs) continue;
|
|
3237
|
+
latestMs.set(status.namespace, completedAtMs);
|
|
3238
|
+
latest.set(status.namespace, status.completedAt);
|
|
3239
|
+
}
|
|
3240
|
+
return latest;
|
|
3241
|
+
}
|
|
3242
|
+
async function readStatusFile(filePath) {
|
|
3243
|
+
try {
|
|
3244
|
+
const parsed = JSON.parse(await readFile3(filePath, "utf8"));
|
|
3245
|
+
return parseStatus(parsed);
|
|
3246
|
+
} catch {
|
|
3247
|
+
return null;
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
async function readStatusFiles(config) {
|
|
3251
|
+
if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
|
|
3252
|
+
return [];
|
|
3253
|
+
}
|
|
3254
|
+
const root = statusBasePath(config);
|
|
3255
|
+
const statuses = [];
|
|
3256
|
+
let jobDirs;
|
|
3257
|
+
try {
|
|
3258
|
+
jobDirs = await readdir2(root, { withFileTypes: true });
|
|
3259
|
+
} catch {
|
|
3260
|
+
return statuses;
|
|
3261
|
+
}
|
|
3262
|
+
for (const jobDir of jobDirs) {
|
|
3263
|
+
if (!jobDir.isDirectory()) continue;
|
|
3264
|
+
let files;
|
|
3265
|
+
try {
|
|
3266
|
+
files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
|
|
3267
|
+
} catch {
|
|
3268
|
+
continue;
|
|
3269
|
+
}
|
|
3270
|
+
for (const file of files) {
|
|
3271
|
+
if (!file.isFile() || !file.name.endsWith(".json")) continue;
|
|
3272
|
+
if (file.name.endsWith(".last-ran.json")) continue;
|
|
3273
|
+
const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
|
|
3274
|
+
if (status) statuses.push(status);
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
return statuses;
|
|
3278
|
+
}
|
|
3279
|
+
async function readLastRanStatusFiles(config) {
|
|
3280
|
+
if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
|
|
3281
|
+
return [];
|
|
3282
|
+
}
|
|
3283
|
+
const root = statusBasePath(config);
|
|
3284
|
+
const statuses = [];
|
|
3285
|
+
let jobDirs;
|
|
3286
|
+
try {
|
|
3287
|
+
jobDirs = await readdir2(root, { withFileTypes: true });
|
|
3288
|
+
} catch {
|
|
3289
|
+
return statuses;
|
|
3290
|
+
}
|
|
3291
|
+
for (const jobDir of jobDirs) {
|
|
3292
|
+
if (!jobDir.isDirectory()) continue;
|
|
3293
|
+
let files;
|
|
3294
|
+
try {
|
|
3295
|
+
files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
|
|
3296
|
+
} catch {
|
|
3297
|
+
continue;
|
|
3298
|
+
}
|
|
3299
|
+
for (const file of files) {
|
|
3300
|
+
if (!file.isFile() || !file.name.endsWith(".last-ran.json")) continue;
|
|
3301
|
+
const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
|
|
3302
|
+
if (status) statuses.push(status);
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
return statuses;
|
|
3306
|
+
}
|
|
3307
|
+
async function writeStatusPayload(target, status) {
|
|
3308
|
+
const dir = path3.dirname(target);
|
|
3309
|
+
await mkdir3(dir, { recursive: true });
|
|
3310
|
+
const temp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
3311
|
+
const payload = {
|
|
3312
|
+
version: 1,
|
|
3313
|
+
...status
|
|
3314
|
+
};
|
|
3315
|
+
await writeFile3(temp, `${JSON.stringify(payload, null, 2)}
|
|
3316
|
+
`, "utf8");
|
|
3317
|
+
await rename2(temp, target);
|
|
3318
|
+
}
|
|
3319
|
+
async function writeStatusFile(config, status) {
|
|
3320
|
+
await writeStatusPayload(statusPath(config, status.jobName, status.namespace), status);
|
|
3321
|
+
if (status.state === "ran") {
|
|
3322
|
+
await writeStatusPayload(lastRanStatusPath(config, status.jobName, status.namespace), status);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
async function recordNamespaceMaintenanceStatusSafely(config, status) {
|
|
3326
|
+
try {
|
|
3327
|
+
await writeStatusFile(config, status);
|
|
3328
|
+
} catch {
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
function maintenanceErrorDetail(error) {
|
|
3332
|
+
return displayErrorDetail(error) || "Error";
|
|
3333
|
+
}
|
|
3334
|
+
async function runNamespaceMaintenanceBatchPlan(config, plan, runner, catalog, options = {}) {
|
|
3335
|
+
const statuses = [];
|
|
3336
|
+
for (const skipped of plan.skipped) {
|
|
3337
|
+
if (skipped.namespace === "*") continue;
|
|
3338
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3339
|
+
const status = {
|
|
3340
|
+
namespace: skipped.namespace,
|
|
3341
|
+
jobName: plan.jobName,
|
|
3342
|
+
state: "skipped",
|
|
3343
|
+
reason: skipped.reason,
|
|
3344
|
+
startedAt: now,
|
|
3345
|
+
completedAt: now
|
|
3346
|
+
};
|
|
3347
|
+
statuses.push(status);
|
|
3348
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3349
|
+
}
|
|
3350
|
+
const acquired = [];
|
|
3351
|
+
try {
|
|
3352
|
+
for (const candidate of plan.namespaces) {
|
|
3353
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3354
|
+
const lock = await tryAcquireNamespaceMaintenanceLock(config, plan.jobName, candidate.namespace);
|
|
3355
|
+
if (!lock) {
|
|
3356
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3357
|
+
const status = {
|
|
3358
|
+
namespace: candidate.namespace,
|
|
3359
|
+
jobName: plan.jobName,
|
|
3360
|
+
state: "skipped",
|
|
3361
|
+
reason: "lock_held",
|
|
3362
|
+
startedAt,
|
|
3363
|
+
completedAt
|
|
3364
|
+
};
|
|
3365
|
+
statuses.push(status);
|
|
3366
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3367
|
+
continue;
|
|
3368
|
+
}
|
|
3369
|
+
acquired.push({ candidate, lock, startedAt });
|
|
3370
|
+
}
|
|
3371
|
+
} catch (error) {
|
|
3372
|
+
await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
|
|
3373
|
+
throw error;
|
|
3374
|
+
}
|
|
3375
|
+
if (options.requireAllLocks && acquired.length > 0 && acquired.length < plan.namespaces.length) {
|
|
3376
|
+
for (const { candidate, startedAt } of acquired) {
|
|
3377
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3378
|
+
const status = {
|
|
3379
|
+
namespace: candidate.namespace,
|
|
3380
|
+
jobName: plan.jobName,
|
|
3381
|
+
state: "skipped",
|
|
3382
|
+
reason: "batch_lock_incomplete",
|
|
3383
|
+
startedAt,
|
|
3384
|
+
completedAt
|
|
3385
|
+
};
|
|
3386
|
+
statuses.push(status);
|
|
3387
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3388
|
+
}
|
|
3389
|
+
await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
|
|
3390
|
+
return {
|
|
3391
|
+
jobName: plan.jobName,
|
|
3392
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3393
|
+
ran: statuses.filter((s) => s.state === "ran").length,
|
|
3394
|
+
skipped: statuses.filter((s) => s.state === "skipped").length,
|
|
3395
|
+
failed: statuses.filter((s) => s.state === "failed").length,
|
|
3396
|
+
statuses
|
|
3397
|
+
};
|
|
3398
|
+
}
|
|
3399
|
+
if (acquired.length === 0) {
|
|
3400
|
+
return {
|
|
3401
|
+
jobName: plan.jobName,
|
|
3402
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3403
|
+
ran: statuses.filter((s) => s.state === "ran").length,
|
|
3404
|
+
skipped: statuses.filter((s) => s.state === "skipped").length,
|
|
3405
|
+
failed: statuses.filter((s) => s.state === "failed").length,
|
|
3406
|
+
statuses
|
|
3407
|
+
};
|
|
3408
|
+
}
|
|
3409
|
+
try {
|
|
3410
|
+
const result = await withNamespaceMaintenanceLockHeartbeat(
|
|
3411
|
+
config,
|
|
3412
|
+
acquired.map(({ lock }) => lock),
|
|
3413
|
+
() => runner(acquired.map(({ candidate }) => candidate))
|
|
3414
|
+
);
|
|
3415
|
+
for (const { candidate, startedAt } of acquired) {
|
|
3416
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3417
|
+
const status = {
|
|
3418
|
+
namespace: candidate.namespace,
|
|
3419
|
+
jobName: plan.jobName,
|
|
3420
|
+
state: "ran",
|
|
3421
|
+
startedAt,
|
|
3422
|
+
completedAt,
|
|
3423
|
+
itemCount: itemCountForNamespace(result, candidate.namespace)
|
|
3424
|
+
};
|
|
3425
|
+
statuses.push(status);
|
|
3426
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3427
|
+
try {
|
|
3428
|
+
await catalog?.markMaintenance(candidate.namespace, plan.jobName, new Date(completedAt));
|
|
3429
|
+
} catch {
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
} catch (error) {
|
|
3433
|
+
const skipReason = options.skipReasonForError?.(error);
|
|
3434
|
+
for (const { candidate, startedAt } of acquired) {
|
|
3435
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3436
|
+
const status = skipReason ? {
|
|
3437
|
+
namespace: candidate.namespace,
|
|
3438
|
+
jobName: plan.jobName,
|
|
3439
|
+
state: "skipped",
|
|
3440
|
+
reason: skipReason,
|
|
3441
|
+
startedAt,
|
|
3442
|
+
completedAt
|
|
3443
|
+
} : {
|
|
3444
|
+
namespace: candidate.namespace,
|
|
3445
|
+
jobName: plan.jobName,
|
|
3446
|
+
state: "failed",
|
|
3447
|
+
reason: "job_failed",
|
|
3448
|
+
startedAt,
|
|
3449
|
+
completedAt,
|
|
3450
|
+
error: maintenanceErrorDetail(error)
|
|
3451
|
+
};
|
|
3452
|
+
statuses.push(status);
|
|
3453
|
+
await recordNamespaceMaintenanceStatusSafely(config, status);
|
|
3454
|
+
}
|
|
3455
|
+
} finally {
|
|
3456
|
+
await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
|
|
3457
|
+
}
|
|
3458
|
+
return {
|
|
3459
|
+
jobName: plan.jobName,
|
|
3460
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3461
|
+
ran: statuses.filter((s) => s.state === "ran").length,
|
|
3462
|
+
skipped: statuses.filter((s) => s.state === "skipped").length,
|
|
3463
|
+
failed: statuses.filter((s) => s.state === "failed").length,
|
|
3464
|
+
statuses
|
|
3465
|
+
};
|
|
3466
|
+
}
|
|
3467
|
+
function itemCountForNamespace(result, namespace) {
|
|
3468
|
+
const itemCounts = result?.itemCounts;
|
|
3469
|
+
if (itemCounts instanceof Map) return itemCounts.get(namespace);
|
|
3470
|
+
if (itemCounts && Object.prototype.hasOwnProperty.call(itemCounts, namespace)) {
|
|
3471
|
+
return itemCounts[namespace];
|
|
3472
|
+
}
|
|
3473
|
+
return result?.itemCount;
|
|
3474
|
+
}
|
|
3475
|
+
|
|
2868
3476
|
// src/orchestrator.ts
|
|
2869
3477
|
var BulkImportBatchPartialFailureError = class extends Error {
|
|
2870
3478
|
partialResult;
|
|
@@ -2926,7 +3534,7 @@ function flattenStructuredSectionEvidence(sections) {
|
|
|
2926
3534
|
);
|
|
2927
3535
|
}
|
|
2928
3536
|
function fingerprintEntitySynthesisEvidence(entity) {
|
|
2929
|
-
const fingerprint =
|
|
3537
|
+
const fingerprint = createHash2("sha256");
|
|
2930
3538
|
const timelineEntries = entity.timeline.map((entry) => [
|
|
2931
3539
|
entry.timestamp,
|
|
2932
3540
|
entry.source ?? "",
|
|
@@ -2976,7 +3584,7 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
|
|
|
2976
3584
|
}
|
|
2977
3585
|
}
|
|
2978
3586
|
function qmdCollectionPathParts(resultPath) {
|
|
2979
|
-
if (!resultPath ||
|
|
3587
|
+
if (!resultPath || path4.isAbsolute(resultPath)) return null;
|
|
2980
3588
|
const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2981
3589
|
const slashIndex = normalized.indexOf("/");
|
|
2982
3590
|
if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
|
|
@@ -2989,9 +3597,9 @@ function qmdCollectionPathParts(resultPath) {
|
|
|
2989
3597
|
}
|
|
2990
3598
|
function qmdResultPathCandidates(storageDir, resultPath) {
|
|
2991
3599
|
const candidates = /* @__PURE__ */ new Set();
|
|
2992
|
-
const storageRoot =
|
|
3600
|
+
const storageRoot = path4.resolve(storageDir);
|
|
2993
3601
|
const addCandidate = (candidate) => {
|
|
2994
|
-
const resolved =
|
|
3602
|
+
const resolved = path4.resolve(candidate);
|
|
2995
3603
|
if (isPathInsideStorageRoot(storageRoot, resolved)) {
|
|
2996
3604
|
candidates.add(resolved);
|
|
2997
3605
|
}
|
|
@@ -2999,12 +3607,12 @@ function qmdResultPathCandidates(storageDir, resultPath) {
|
|
|
2999
3607
|
const addRelativeCandidates = (relativePath) => {
|
|
3000
3608
|
const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3001
3609
|
if (!normalized) return;
|
|
3002
|
-
addCandidate(
|
|
3610
|
+
addCandidate(path4.join(storageRoot, normalized));
|
|
3003
3611
|
if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
|
|
3004
|
-
addCandidate(
|
|
3612
|
+
addCandidate(path4.join(storageRoot, "facts", normalized));
|
|
3005
3613
|
}
|
|
3006
3614
|
};
|
|
3007
|
-
if (
|
|
3615
|
+
if (path4.isAbsolute(resultPath)) {
|
|
3008
3616
|
addCandidate(resultPath);
|
|
3009
3617
|
} else {
|
|
3010
3618
|
addRelativeCandidates(resultPath);
|
|
@@ -3121,11 +3729,11 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
|
|
|
3121
3729
|
return await Promise.race([checkedPromise, timeoutPromise]);
|
|
3122
3730
|
}
|
|
3123
3731
|
function defaultWorkspaceDir() {
|
|
3124
|
-
return
|
|
3732
|
+
return path4.join(os.homedir(), ".openclaw", "workspace");
|
|
3125
3733
|
}
|
|
3126
3734
|
function sanitizeSessionKeyForFilename(sessionKey) {
|
|
3127
3735
|
const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
3128
|
-
const hash =
|
|
3736
|
+
const hash = createHash2("sha256").update(sessionKey).digest("hex").slice(0, 12);
|
|
3129
3737
|
return `${readable}-${hash}`;
|
|
3130
3738
|
}
|
|
3131
3739
|
function latestSourceValidAtFromTurns(turns) {
|
|
@@ -3426,11 +4034,11 @@ function mergeGraphExpandedResults(primary, expanded) {
|
|
|
3426
4034
|
return Array.from(mergedByPath.values());
|
|
3427
4035
|
}
|
|
3428
4036
|
function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
3429
|
-
const absolutePath =
|
|
3430
|
-
const rel =
|
|
4037
|
+
const absolutePath = path4.isAbsolute(candidatePath) ? candidatePath : path4.resolve(storageDir, candidatePath);
|
|
4038
|
+
const rel = path4.relative(storageDir, absolutePath);
|
|
3431
4039
|
if (!rel || rel === ".") return null;
|
|
3432
4040
|
if (rel.startsWith("..")) return null;
|
|
3433
|
-
return rel.split(
|
|
4041
|
+
return rel.split(path4.sep).join("/");
|
|
3434
4042
|
}
|
|
3435
4043
|
function normalizeGraphActivationScore(score) {
|
|
3436
4044
|
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
@@ -3572,7 +4180,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
|
|
|
3572
4180
|
for (const mem of allMemsForGraph ?? []) {
|
|
3573
4181
|
const id = mem.frontmatter.id;
|
|
3574
4182
|
if (!id) continue;
|
|
3575
|
-
pathById.set(id,
|
|
4183
|
+
pathById.set(id, path4.relative(storageDir, mem.path));
|
|
3576
4184
|
}
|
|
3577
4185
|
return pathById;
|
|
3578
4186
|
}
|
|
@@ -3580,7 +4188,7 @@ function appendMemoryToGraphContext(options) {
|
|
|
3580
4188
|
if (!Array.isArray(options.allMemsForGraph)) return;
|
|
3581
4189
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
3582
4190
|
options.allMemsForGraph.push({
|
|
3583
|
-
path:
|
|
4191
|
+
path: path4.join(options.storageDir, options.memoryRelPath),
|
|
3584
4192
|
content: options.content,
|
|
3585
4193
|
frontmatter: {
|
|
3586
4194
|
id: options.memoryId,
|
|
@@ -3600,16 +4208,20 @@ function resolvePersistedMemoryRelativePath(options) {
|
|
|
3600
4208
|
const persisted = options.pathById.get(options.memoryId);
|
|
3601
4209
|
if (persisted) return persisted;
|
|
3602
4210
|
if (options.category === "correction") {
|
|
3603
|
-
return
|
|
4211
|
+
return path4.join("corrections", `${options.memoryId}.md`);
|
|
3604
4212
|
}
|
|
3605
4213
|
const subtree = options.category === "procedure" ? "procedures" : options.category === "reasoning_trace" ? "reasoning-traces" : "facts";
|
|
3606
4214
|
const idParts = options.memoryId.split("-");
|
|
3607
4215
|
const maybeTimestamp = Number(idParts[1]);
|
|
3608
4216
|
if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
|
|
3609
4217
|
const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
|
|
3610
|
-
return
|
|
4218
|
+
return path4.join(subtree, day, `${options.memoryId}.md`);
|
|
3611
4219
|
}
|
|
3612
|
-
return
|
|
4220
|
+
return path4.join(subtree, `${options.memoryId}.md`);
|
|
4221
|
+
}
|
|
4222
|
+
function qmdMaintenanceSkipReasonForError(error) {
|
|
4223
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4224
|
+
return /^QMD (?:update|embed) skipped by .*min-interval gate$/.test(message) ? "throttled" : null;
|
|
3613
4225
|
}
|
|
3614
4226
|
var Orchestrator = class _Orchestrator {
|
|
3615
4227
|
storage;
|
|
@@ -3737,6 +4349,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3737
4349
|
qmdMaintenancePending = false;
|
|
3738
4350
|
qmdMaintenanceInFlight = false;
|
|
3739
4351
|
lastQmdEmbedAtMs = 0;
|
|
4352
|
+
lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map();
|
|
3740
4353
|
lastQmdReprobeAtMs = 0;
|
|
3741
4354
|
tierMigrationInFlight = false;
|
|
3742
4355
|
lastTierMigrationRunAtMs = 0;
|
|
@@ -4038,7 +4651,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4038
4651
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
4039
4652
|
if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
|
|
4040
4653
|
if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
|
|
4041
|
-
const resolvedStorageDir =
|
|
4654
|
+
const resolvedStorageDir = path4.resolve(storageDir);
|
|
4042
4655
|
let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
|
|
4043
4656
|
if (!hints) {
|
|
4044
4657
|
hints = /* @__PURE__ */ new Set();
|
|
@@ -4049,21 +4662,21 @@ var Orchestrator = class _Orchestrator {
|
|
|
4049
4662
|
storageDirMatchesNamespaceHint(namespace, storageDir) {
|
|
4050
4663
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
4051
4664
|
if (!ns) return false;
|
|
4052
|
-
const resolvedStorageDir =
|
|
4053
|
-
const resolvedMemoryDir =
|
|
4665
|
+
const resolvedStorageDir = path4.resolve(storageDir);
|
|
4666
|
+
const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
|
|
4054
4667
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
4055
4668
|
if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
|
|
4056
|
-
const resolvedNamespacesDir =
|
|
4669
|
+
const resolvedNamespacesDir = path4.join(resolvedMemoryDir, "namespaces");
|
|
4057
4670
|
if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
|
|
4058
|
-
const rawRoot =
|
|
4059
|
-
const tokenRoot =
|
|
4671
|
+
const rawRoot = path4.resolve(resolvedNamespacesDir, ns);
|
|
4672
|
+
const tokenRoot = path4.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
|
|
4060
4673
|
return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
|
|
4061
4674
|
}
|
|
4062
4675
|
namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
|
|
4063
|
-
if (resolvedStorageDir ===
|
|
4676
|
+
if (resolvedStorageDir === path4.resolve(this.config.memoryDir)) {
|
|
4064
4677
|
return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
|
|
4065
4678
|
}
|
|
4066
|
-
const leaf =
|
|
4679
|
+
const leaf = path4.basename(resolvedStorageDir);
|
|
4067
4680
|
const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
|
|
4068
4681
|
if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
|
|
4069
4682
|
if (record.namespace === leaf) return 1;
|
|
@@ -4091,7 +4704,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4091
4704
|
loadNamespaceStorageDirHintsFromCatalog() {
|
|
4092
4705
|
if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
|
|
4093
4706
|
this.namespaceStorageDirHintsLoaded = true;
|
|
4094
|
-
const catalogPath =
|
|
4707
|
+
const catalogPath = path4.join(this.config.memoryDir, "state", "namespaces.jsonl");
|
|
4095
4708
|
if (!existsSync(catalogPath)) return;
|
|
4096
4709
|
let body;
|
|
4097
4710
|
try {
|
|
@@ -4128,7 +4741,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4128
4741
|
if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
|
|
4129
4742
|
continue;
|
|
4130
4743
|
}
|
|
4131
|
-
const resolvedStorageDir =
|
|
4744
|
+
const resolvedStorageDir = path4.resolve(record.storageDir);
|
|
4132
4745
|
const current = preferredByStorageDir.get(resolvedStorageDir);
|
|
4133
4746
|
preferredByStorageDir.set(
|
|
4134
4747
|
resolvedStorageDir,
|
|
@@ -4145,57 +4758,27 @@ var Orchestrator = class _Orchestrator {
|
|
|
4145
4758
|
}
|
|
4146
4759
|
}
|
|
4147
4760
|
/**
|
|
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.
|
|
4761
|
+
* Shared namespace maintenance planner (issue #1500). This extends the
|
|
4762
|
+
* #1499 catalog-union QMD helper into a reusable contract: configured
|
|
4763
|
+
* namespaces are always considered, dynamic catalog namespaces are admitted
|
|
4764
|
+
* only when their live router root still matches real memory data, and branch
|
|
4765
|
+
* namespaces are opt-in. Recurring jobs use the per-cycle budget; startup and
|
|
4766
|
+
* recovery discovery paths use the same safety filters without that cycle
|
|
4767
|
+
* budget so every live namespace is ensured/synced.
|
|
4159
4768
|
*/
|
|
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
|
-
);
|
|
4769
|
+
async namespaceMaintenancePlan(jobName) {
|
|
4770
|
+
return planNamespaceMaintenance(this.config, {
|
|
4771
|
+
jobName,
|
|
4772
|
+
catalog: this.namespaceCatalog
|
|
4773
|
+
});
|
|
4185
4774
|
}
|
|
4186
|
-
async
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
return false;
|
|
4194
|
-
}
|
|
4195
|
-
return hasMemoryData(liveRoot);
|
|
4196
|
-
} catch {
|
|
4197
|
-
return false;
|
|
4198
|
-
}
|
|
4775
|
+
async maintenanceNamespaces(jobName = "qmd", budgetMode = "unbounded") {
|
|
4776
|
+
const plan = await planNamespaceMaintenance(this.config, {
|
|
4777
|
+
jobName,
|
|
4778
|
+
catalog: this.namespaceCatalog,
|
|
4779
|
+
budgetMode
|
|
4780
|
+
});
|
|
4781
|
+
return plan.namespaces.map((candidate) => candidate.namespace);
|
|
4199
4782
|
}
|
|
4200
4783
|
buildConfiguredQmdSearchOptions(queryText) {
|
|
4201
4784
|
const intentHint = this.config.qmdIntentHintsEnabled ? buildQmdIntentHint(inferIntentFromText(queryText)) : void 0;
|
|
@@ -4271,7 +4854,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4271
4854
|
this.config = config;
|
|
4272
4855
|
this.profiler = new ProfilingCollector({
|
|
4273
4856
|
enabled: config.profilingEnabled,
|
|
4274
|
-
storageDir: config.profilingStorageDir ||
|
|
4857
|
+
storageDir: config.profilingStorageDir || path4.join(config.memoryDir, "profiling"),
|
|
4275
4858
|
maxTraces: config.profilingMaxTraces
|
|
4276
4859
|
});
|
|
4277
4860
|
this.namespaceCatalog = new NamespaceCatalog(config);
|
|
@@ -4316,7 +4899,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4316
4899
|
this.compounding = config.compoundingEnabled ? new CompoundingEngine(config, this.storage) : void 0;
|
|
4317
4900
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
4318
4901
|
this.transcript = new TranscriptManager(config);
|
|
4319
|
-
this.conversationIndexDir =
|
|
4902
|
+
this.conversationIndexDir = path4.join(
|
|
4320
4903
|
config.memoryDir,
|
|
4321
4904
|
"conversation-index",
|
|
4322
4905
|
"chunks"
|
|
@@ -4373,7 +4956,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4373
4956
|
this.modelRegistry
|
|
4374
4957
|
);
|
|
4375
4958
|
this.threading = new ThreadingManager(
|
|
4376
|
-
|
|
4959
|
+
path4.join(config.memoryDir, "threads"),
|
|
4377
4960
|
config.threadingGapMinutes
|
|
4378
4961
|
);
|
|
4379
4962
|
this.tmtBuilder = new TmtBuilder(config.memoryDir, {
|
|
@@ -4452,7 +5035,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4452
5035
|
utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
|
|
4453
5036
|
utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
|
|
4454
5037
|
};
|
|
4455
|
-
return
|
|
5038
|
+
return createHash2("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
|
|
4456
5039
|
}
|
|
4457
5040
|
effectiveLifecycleThresholds() {
|
|
4458
5041
|
const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
|
|
@@ -4672,11 +5255,11 @@ var Orchestrator = class _Orchestrator {
|
|
|
4672
5255
|
if (this.config.compactionResetEnabled) {
|
|
4673
5256
|
try {
|
|
4674
5257
|
const wsDir = this.config.workspaceDir || defaultWorkspaceDir();
|
|
4675
|
-
const files = await
|
|
5258
|
+
const files = await readdir3(wsDir).catch(() => []);
|
|
4676
5259
|
for (const f of files) {
|
|
4677
5260
|
if (!f.startsWith(".compaction-reset-signal-")) continue;
|
|
4678
|
-
const fp =
|
|
4679
|
-
const s = await
|
|
5261
|
+
const fp = path4.join(wsDir, f);
|
|
5262
|
+
const s = await stat3(fp).catch(() => null);
|
|
4680
5263
|
if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
|
|
4681
5264
|
await unlink2(fp).catch(() => {
|
|
4682
5265
|
});
|
|
@@ -4954,9 +5537,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
4954
5537
|
`wearables auto-sync started: every ${this.config.wearables.autoSyncIntervalMinutes}m over ${this.config.wearables.autoSyncDays}d (deep ${this.config.wearables.autoSyncDeepDays}d daily)`
|
|
4955
5538
|
);
|
|
4956
5539
|
} catch (err) {
|
|
4957
|
-
const { displayErrorDetail } = await import("./runtime/better-sqlite.js");
|
|
5540
|
+
const { displayErrorDetail: displayErrorDetail2 } = await import("./runtime/better-sqlite.js");
|
|
4958
5541
|
log.warn(
|
|
4959
|
-
`wearables auto-sync failed to start (non-fatal): ${
|
|
5542
|
+
`wearables auto-sync failed to start (non-fatal): ${displayErrorDetail2(err)}`
|
|
4960
5543
|
);
|
|
4961
5544
|
}
|
|
4962
5545
|
}
|
|
@@ -5069,7 +5652,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5069
5652
|
*/
|
|
5070
5653
|
async autoRegisterDaySummaryCron() {
|
|
5071
5654
|
const home = resolveHomeDir();
|
|
5072
|
-
const jobsPath =
|
|
5655
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5073
5656
|
try {
|
|
5074
5657
|
if (!existsSync(jobsPath)) {
|
|
5075
5658
|
log.debug(
|
|
@@ -5122,7 +5705,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5122
5705
|
}
|
|
5123
5706
|
async autoRegisterNightlyGovernanceCron() {
|
|
5124
5707
|
const home = resolveHomeDir();
|
|
5125
|
-
const jobsPath =
|
|
5708
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5126
5709
|
try {
|
|
5127
5710
|
if (!existsSync(jobsPath)) {
|
|
5128
5711
|
log.debug("nightly governance cron: jobs.json not found, skipping auto-register");
|
|
@@ -5144,7 +5727,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5144
5727
|
}
|
|
5145
5728
|
async autoRegisterProceduralMiningCron() {
|
|
5146
5729
|
const home = resolveHomeDir();
|
|
5147
|
-
const jobsPath =
|
|
5730
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5148
5731
|
try {
|
|
5149
5732
|
if (!existsSync(jobsPath)) {
|
|
5150
5733
|
log.debug("procedural mining cron: jobs.json not found, skipping auto-register");
|
|
@@ -5164,7 +5747,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5164
5747
|
}
|
|
5165
5748
|
async autoRegisterContradictionScanCron() {
|
|
5166
5749
|
const home = resolveHomeDir();
|
|
5167
|
-
const jobsPath =
|
|
5750
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5168
5751
|
try {
|
|
5169
5752
|
if (!existsSync(jobsPath)) {
|
|
5170
5753
|
log.debug("contradiction scan cron: jobs.json not found, skipping auto-register");
|
|
@@ -5184,7 +5767,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5184
5767
|
}
|
|
5185
5768
|
async autoRegisterPatternReinforcementCron() {
|
|
5186
5769
|
const home = resolveHomeDir();
|
|
5187
|
-
const jobsPath =
|
|
5770
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5188
5771
|
try {
|
|
5189
5772
|
if (!existsSync(jobsPath)) {
|
|
5190
5773
|
log.debug("pattern reinforcement cron: jobs.json not found, skipping auto-register");
|
|
@@ -5246,7 +5829,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5246
5829
|
}
|
|
5247
5830
|
async autoRegisterGraphEdgeDecayCron() {
|
|
5248
5831
|
const home = resolveHomeDir();
|
|
5249
|
-
const jobsPath =
|
|
5832
|
+
const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
|
|
5250
5833
|
try {
|
|
5251
5834
|
if (!existsSync(jobsPath)) {
|
|
5252
5835
|
log.debug("graph edge decay cron: jobs.json not found, skipping auto-register");
|
|
@@ -5303,15 +5886,15 @@ ${doc.content}` : doc.content,
|
|
|
5303
5886
|
this.lastFileHygieneRunAtMs = now;
|
|
5304
5887
|
if (hygiene.rotateEnabled) {
|
|
5305
5888
|
for (const rel of hygiene.rotatePaths) {
|
|
5306
|
-
const abs =
|
|
5889
|
+
const abs = path4.isAbsolute(rel) ? rel : path4.join(this.config.workspaceDir, rel);
|
|
5307
5890
|
try {
|
|
5308
|
-
const raw = await
|
|
5891
|
+
const raw = await readFile4(abs, "utf-8");
|
|
5309
5892
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
5310
|
-
const archiveDir =
|
|
5893
|
+
const archiveDir = path4.join(
|
|
5311
5894
|
this.config.workspaceDir,
|
|
5312
5895
|
hygiene.archiveDir
|
|
5313
5896
|
);
|
|
5314
|
-
const base =
|
|
5897
|
+
const base = path4.basename(abs);
|
|
5315
5898
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
5316
5899
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
5317
5900
|
filePath: abs,
|
|
@@ -5319,7 +5902,7 @@ ${doc.content}` : doc.content,
|
|
|
5319
5902
|
archivePrefix: prefix,
|
|
5320
5903
|
keepTailChars: hygiene.rotateKeepTailChars
|
|
5321
5904
|
});
|
|
5322
|
-
await
|
|
5905
|
+
await writeFile4(abs, newContent, "utf-8");
|
|
5323
5906
|
}
|
|
5324
5907
|
} catch {
|
|
5325
5908
|
}
|
|
@@ -5336,8 +5919,8 @@ ${doc.content}` : doc.content,
|
|
|
5336
5919
|
log.warn(w.message);
|
|
5337
5920
|
}
|
|
5338
5921
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
5339
|
-
const fp =
|
|
5340
|
-
await
|
|
5922
|
+
const fp = path4.join(this.config.memoryDir, hygiene.warningsLogPath);
|
|
5923
|
+
await mkdir4(path4.dirname(fp), { recursive: true });
|
|
5341
5924
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
5342
5925
|
const block = `
|
|
5343
5926
|
|
|
@@ -5346,11 +5929,11 @@ ${doc.content}` : doc.content,
|
|
|
5346
5929
|
` + warnings.map((w) => `- ${w.message}`).join("\n") + "\n";
|
|
5347
5930
|
let existing = "";
|
|
5348
5931
|
try {
|
|
5349
|
-
existing = await
|
|
5932
|
+
existing = await readFile4(fp, "utf-8");
|
|
5350
5933
|
} catch {
|
|
5351
5934
|
existing = "# Engram File Hygiene Warnings\n";
|
|
5352
5935
|
}
|
|
5353
|
-
await
|
|
5936
|
+
await writeFile4(fp, existing + block, "utf-8");
|
|
5354
5937
|
}
|
|
5355
5938
|
}
|
|
5356
5939
|
}
|
|
@@ -5820,18 +6403,18 @@ ${evidenceText}`
|
|
|
5820
6403
|
const now = options.now instanceof Date && Number.isFinite(options.now.getTime()) ? options.now : /* @__PURE__ */ new Date();
|
|
5821
6404
|
const targetLocalDate = formatDateInTimeZone(now, timeZone);
|
|
5822
6405
|
const datesToScan = utcDateKeysForLocalDay(now, timeZone);
|
|
5823
|
-
const factsBaseDir =
|
|
6406
|
+
const factsBaseDir = path4.join(storage.dir, "facts");
|
|
5824
6407
|
const MAX_CHARS = 1e5;
|
|
5825
6408
|
const facts = [];
|
|
5826
6409
|
for (const date of datesToScan) {
|
|
5827
|
-
const factsDir =
|
|
6410
|
+
const factsDir = path4.join(factsBaseDir, date);
|
|
5828
6411
|
try {
|
|
5829
|
-
const entries = await
|
|
6412
|
+
const entries = await readdir3(factsDir, { withFileTypes: true });
|
|
5830
6413
|
for (const entry of entries) {
|
|
5831
6414
|
if (!entry.name.endsWith(".md")) continue;
|
|
5832
|
-
const fullPath =
|
|
6415
|
+
const fullPath = path4.join(factsDir, entry.name);
|
|
5833
6416
|
try {
|
|
5834
|
-
const raw = await
|
|
6417
|
+
const raw = await readFile4(fullPath, "utf-8");
|
|
5835
6418
|
const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
5836
6419
|
if (!fmMatch) continue;
|
|
5837
6420
|
const fmBlock = fmMatch[1];
|
|
@@ -5850,7 +6433,7 @@ ${evidenceText}`
|
|
|
5850
6433
|
facts.push({
|
|
5851
6434
|
path: fullPath,
|
|
5852
6435
|
frontmatter: {
|
|
5853
|
-
id: fm.id ||
|
|
6436
|
+
id: fm.id || path4.basename(entry.name, ".md"),
|
|
5854
6437
|
category: fm.category || "fact",
|
|
5855
6438
|
created,
|
|
5856
6439
|
updated: fm.updated || created,
|
|
@@ -5872,15 +6455,15 @@ ${evidenceText}`
|
|
|
5872
6455
|
return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
|
|
5873
6456
|
});
|
|
5874
6457
|
const hourlySummaries = [];
|
|
5875
|
-
const hourlyBaseDir =
|
|
6458
|
+
const hourlyBaseDir = path4.join(storage.dir, "summaries", "hourly");
|
|
5876
6459
|
try {
|
|
5877
|
-
const sessionKeys = await
|
|
6460
|
+
const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
|
|
5878
6461
|
for (const sk of sessionKeys) {
|
|
5879
6462
|
if (!sk.isDirectory()) continue;
|
|
5880
6463
|
for (const date of datesToScan) {
|
|
5881
|
-
const summaryFile =
|
|
6464
|
+
const summaryFile = path4.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
5882
6465
|
try {
|
|
5883
|
-
const raw = await
|
|
6466
|
+
const raw = await readFile4(summaryFile, "utf-8");
|
|
5884
6467
|
const filtered = filterHourlySummaryMarkdownForLocalDay(
|
|
5885
6468
|
raw,
|
|
5886
6469
|
date,
|
|
@@ -5982,13 +6565,13 @@ ${evidenceText}`
|
|
|
5982
6565
|
}
|
|
5983
6566
|
async getLastGraphRecallSnapshot(namespace) {
|
|
5984
6567
|
const storage = await this.getStorage(namespace);
|
|
5985
|
-
const snapshotPath =
|
|
6568
|
+
const snapshotPath = path4.join(
|
|
5986
6569
|
storage.dir,
|
|
5987
6570
|
"state",
|
|
5988
6571
|
"last_graph_recall.json"
|
|
5989
6572
|
);
|
|
5990
6573
|
try {
|
|
5991
|
-
const raw = await
|
|
6574
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
5992
6575
|
const parsed = JSON.parse(raw);
|
|
5993
6576
|
if (!parsed || typeof parsed !== "object") return null;
|
|
5994
6577
|
return {
|
|
@@ -6021,9 +6604,9 @@ ${evidenceText}`
|
|
|
6021
6604
|
}
|
|
6022
6605
|
async getLastIntentSnapshot(namespace) {
|
|
6023
6606
|
const storage = await this.getStorage(namespace);
|
|
6024
|
-
const snapshotPath =
|
|
6607
|
+
const snapshotPath = path4.join(storage.dir, "state", "last_intent.json");
|
|
6025
6608
|
try {
|
|
6026
|
-
const raw = await
|
|
6609
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
6027
6610
|
const parsed = JSON.parse(raw);
|
|
6028
6611
|
if (!parsed || typeof parsed !== "object") return null;
|
|
6029
6612
|
const graphDecision = parsed.graphDecision && typeof parsed.graphDecision === "object" ? parsed.graphDecision : void 0;
|
|
@@ -6054,13 +6637,13 @@ ${evidenceText}`
|
|
|
6054
6637
|
}
|
|
6055
6638
|
async getLastQmdRecallSnapshot(namespace) {
|
|
6056
6639
|
const storage = await this.getStorage(namespace);
|
|
6057
|
-
const snapshotPath =
|
|
6640
|
+
const snapshotPath = path4.join(
|
|
6058
6641
|
storage.dir,
|
|
6059
6642
|
"state",
|
|
6060
6643
|
"last_qmd_recall.json"
|
|
6061
6644
|
);
|
|
6062
6645
|
try {
|
|
6063
|
-
const raw = await
|
|
6646
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
6064
6647
|
const parsed = JSON.parse(raw);
|
|
6065
6648
|
if (!parsed || typeof parsed !== "object") return null;
|
|
6066
6649
|
return {
|
|
@@ -6204,10 +6787,10 @@ ${r.snippet.trim()}
|
|
|
6204
6787
|
}
|
|
6205
6788
|
async countConversationChunkDocs(dir) {
|
|
6206
6789
|
try {
|
|
6207
|
-
const entries = await
|
|
6790
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
6208
6791
|
let total = 0;
|
|
6209
6792
|
for (const entry of entries) {
|
|
6210
|
-
const fullPath =
|
|
6793
|
+
const fullPath = path4.join(dir, entry.name);
|
|
6211
6794
|
if (entry.isDirectory()) {
|
|
6212
6795
|
total += await this.countConversationChunkDocs(fullPath);
|
|
6213
6796
|
continue;
|
|
@@ -6933,7 +7516,7 @@ ${r.snippet.trim()}
|
|
|
6933
7516
|
if (!options.onDebugSnapshot) return;
|
|
6934
7517
|
await options.onDebugSnapshot({
|
|
6935
7518
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6936
|
-
queryHash:
|
|
7519
|
+
queryHash: createHash2("sha256").update(prompt).digest("hex"),
|
|
6937
7520
|
queryLength: prompt.length,
|
|
6938
7521
|
collection: options.collection,
|
|
6939
7522
|
namespaces: options.recallNamespaces,
|
|
@@ -7106,7 +7689,7 @@ ${r.snippet.trim()}
|
|
|
7106
7689
|
resolvedPath = resolvedCold.result.path;
|
|
7107
7690
|
resolvedResult = resolvedCold.result;
|
|
7108
7691
|
}
|
|
7109
|
-
if (!
|
|
7692
|
+
if (!path4.isAbsolute(resolvedPath)) {
|
|
7110
7693
|
resolvedAmbiguousSeeds.set(result.path, null);
|
|
7111
7694
|
return null;
|
|
7112
7695
|
}
|
|
@@ -7131,7 +7714,7 @@ ${r.snippet.trim()}
|
|
|
7131
7714
|
}
|
|
7132
7715
|
continue;
|
|
7133
7716
|
}
|
|
7134
|
-
if (
|
|
7717
|
+
if (path4.isAbsolute(result.path)) {
|
|
7135
7718
|
const resolved = await resolveAmbiguousSeedOwner(result, null);
|
|
7136
7719
|
if (resolved) {
|
|
7137
7720
|
addResultForNamespace(resolved.namespace, resolved.result);
|
|
@@ -7174,7 +7757,7 @@ ${r.snippet.trim()}
|
|
|
7174
7757
|
0
|
|
7175
7758
|
);
|
|
7176
7759
|
seedPaths.push(
|
|
7177
|
-
...seedRelativePaths.map((rel) =>
|
|
7760
|
+
...seedRelativePaths.map((rel) => path4.join(storage.dir, rel))
|
|
7178
7761
|
);
|
|
7179
7762
|
const seedSet = new Set(seedRelativePaths);
|
|
7180
7763
|
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
@@ -7190,7 +7773,7 @@ ${r.snippet.trim()}
|
|
|
7190
7773
|
for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
|
|
7191
7774
|
if (deadlineExpired()) break;
|
|
7192
7775
|
if (seedSet.has(candidate.path)) continue;
|
|
7193
|
-
const memoryPath =
|
|
7776
|
+
const memoryPath = path4.resolve(storage.dir, candidate.path);
|
|
7194
7777
|
const memory = await storage.readMemoryByPath(memoryPath);
|
|
7195
7778
|
if (deadlineExpired()) break;
|
|
7196
7779
|
if (!memory) continue;
|
|
@@ -7215,7 +7798,7 @@ ${r.snippet.trim()}
|
|
|
7215
7798
|
path: memory.path,
|
|
7216
7799
|
score,
|
|
7217
7800
|
namespace,
|
|
7218
|
-
seed:
|
|
7801
|
+
seed: path4.resolve(storage.dir, candidate.seed),
|
|
7219
7802
|
hopDepth: candidate.hopDepth,
|
|
7220
7803
|
decayedWeight: candidate.decayedWeight,
|
|
7221
7804
|
graphType: candidate.graphType,
|
|
@@ -7236,12 +7819,12 @@ ${r.snippet.trim()}
|
|
|
7236
7819
|
}
|
|
7237
7820
|
async recordLastGraphRecallSnapshot(options) {
|
|
7238
7821
|
try {
|
|
7239
|
-
const snapshotPath =
|
|
7822
|
+
const snapshotPath = path4.join(
|
|
7240
7823
|
options.storage.dir,
|
|
7241
7824
|
"state",
|
|
7242
7825
|
"last_graph_recall.json"
|
|
7243
7826
|
);
|
|
7244
|
-
await
|
|
7827
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7245
7828
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7246
7829
|
const totalSeedCount = options.seedPaths.length;
|
|
7247
7830
|
const totalExpandedCount = options.expandedPaths.length;
|
|
@@ -7253,7 +7836,7 @@ ${r.snippet.trim()}
|
|
|
7253
7836
|
const payload = {
|
|
7254
7837
|
recordedAt: now,
|
|
7255
7838
|
mode: options.recallMode,
|
|
7256
|
-
queryHash:
|
|
7839
|
+
queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
|
|
7257
7840
|
queryLength: options.prompt.length,
|
|
7258
7841
|
namespaces: options.recallNamespaces,
|
|
7259
7842
|
seedCount: totalSeedCount,
|
|
@@ -7268,20 +7851,20 @@ ${r.snippet.trim()}
|
|
|
7268
7851
|
finalResults: (options.finalResults ?? []).slice(0, 64),
|
|
7269
7852
|
shadowComparison: options.shadowComparison
|
|
7270
7853
|
};
|
|
7271
|
-
await
|
|
7854
|
+
await writeFile4(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
7272
7855
|
} catch (err) {
|
|
7273
7856
|
log.debug(`last graph recall write failed: ${err}`);
|
|
7274
7857
|
}
|
|
7275
7858
|
}
|
|
7276
7859
|
async recordLastIntentSnapshot(options) {
|
|
7277
7860
|
try {
|
|
7278
|
-
const snapshotPath =
|
|
7861
|
+
const snapshotPath = path4.join(
|
|
7279
7862
|
options.storage.dir,
|
|
7280
7863
|
"state",
|
|
7281
7864
|
"last_intent.json"
|
|
7282
7865
|
);
|
|
7283
|
-
await
|
|
7284
|
-
await
|
|
7866
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7867
|
+
await writeFile4(
|
|
7285
7868
|
snapshotPath,
|
|
7286
7869
|
JSON.stringify(options.snapshot, null, 2),
|
|
7287
7870
|
"utf-8"
|
|
@@ -7292,13 +7875,13 @@ ${r.snippet.trim()}
|
|
|
7292
7875
|
}
|
|
7293
7876
|
async recordLastQmdRecallSnapshot(options) {
|
|
7294
7877
|
try {
|
|
7295
|
-
const snapshotPath =
|
|
7878
|
+
const snapshotPath = path4.join(
|
|
7296
7879
|
options.storage.dir,
|
|
7297
7880
|
"state",
|
|
7298
7881
|
"last_qmd_recall.json"
|
|
7299
7882
|
);
|
|
7300
|
-
await
|
|
7301
|
-
await
|
|
7883
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7884
|
+
await writeFile4(
|
|
7302
7885
|
snapshotPath,
|
|
7303
7886
|
JSON.stringify(options.snapshot, null, 2),
|
|
7304
7887
|
"utf-8"
|
|
@@ -7312,9 +7895,9 @@ ${r.snippet.trim()}
|
|
|
7312
7895
|
const stateDir = await this.resolveStateDirForNamespace(
|
|
7313
7896
|
options.namespace
|
|
7314
7897
|
);
|
|
7315
|
-
const snapshotPath =
|
|
7316
|
-
await
|
|
7317
|
-
await
|
|
7898
|
+
const snapshotPath = path4.join(stateDir, "last_intent.json");
|
|
7899
|
+
await mkdir4(path4.dirname(snapshotPath), { recursive: true });
|
|
7900
|
+
await writeFile4(
|
|
7318
7901
|
snapshotPath,
|
|
7319
7902
|
JSON.stringify(options.snapshot, null, 2),
|
|
7320
7903
|
"utf-8"
|
|
@@ -7325,24 +7908,24 @@ ${r.snippet.trim()}
|
|
|
7325
7908
|
}
|
|
7326
7909
|
async resolveStateDirForNamespace(namespace) {
|
|
7327
7910
|
if (!this.config.namespacesEnabled) {
|
|
7328
|
-
return
|
|
7911
|
+
return path4.join(this.config.memoryDir, "state");
|
|
7329
7912
|
}
|
|
7330
7913
|
if (namespace !== this.config.defaultNamespace) {
|
|
7331
|
-
return
|
|
7914
|
+
return path4.join(this.config.memoryDir, "namespaces", namespace, "state");
|
|
7332
7915
|
}
|
|
7333
|
-
const candidate =
|
|
7916
|
+
const candidate = path4.join(
|
|
7334
7917
|
this.config.memoryDir,
|
|
7335
7918
|
"namespaces",
|
|
7336
7919
|
this.config.defaultNamespace
|
|
7337
7920
|
);
|
|
7338
7921
|
try {
|
|
7339
|
-
const candidateStat = await
|
|
7922
|
+
const candidateStat = await stat3(candidate);
|
|
7340
7923
|
if (candidateStat.isDirectory()) {
|
|
7341
|
-
return
|
|
7924
|
+
return path4.join(candidate, "state");
|
|
7342
7925
|
}
|
|
7343
7926
|
} catch {
|
|
7344
7927
|
}
|
|
7345
|
-
return
|
|
7928
|
+
return path4.join(this.config.memoryDir, "state");
|
|
7346
7929
|
}
|
|
7347
7930
|
buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
|
|
7348
7931
|
return results.slice(0, limit).map((result) => ({
|
|
@@ -7584,8 +8167,8 @@ ${r.snippet.trim()}
|
|
|
7584
8167
|
timings,
|
|
7585
8168
|
logger: log
|
|
7586
8169
|
});
|
|
7587
|
-
const promptHash =
|
|
7588
|
-
const traceId =
|
|
8170
|
+
const promptHash = createHash2("sha256").update(prompt).digest("hex");
|
|
8171
|
+
const traceId = createHash2("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
|
|
7589
8172
|
const sectionBuckets = /* @__PURE__ */ new Map();
|
|
7590
8173
|
const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
|
|
7591
8174
|
cronRecallPolicyEnabled: this.config.cronRecallPolicyEnabled,
|
|
@@ -7594,7 +8177,7 @@ ${r.snippet.trim()}
|
|
|
7594
8177
|
cronConversationRecallMode: this.config.cronConversationRecallMode
|
|
7595
8178
|
});
|
|
7596
8179
|
const retrievalQuery = queryPolicy.retrievalQuery || prompt;
|
|
7597
|
-
const retrievalQueryHash =
|
|
8180
|
+
const retrievalQueryHash = createHash2("sha256").update(retrievalQuery).digest("hex");
|
|
7598
8181
|
const policyVersion = this.currentPolicyVersion();
|
|
7599
8182
|
let impressionRecorded = false;
|
|
7600
8183
|
let recallSource = "none";
|
|
@@ -7752,7 +8335,7 @@ ${r.snippet.trim()}
|
|
|
7752
8335
|
const graphExpandedResultPaths = /* @__PURE__ */ new Set();
|
|
7753
8336
|
const graphSourceLabelsForPath = (resultPath) => {
|
|
7754
8337
|
const labels = [];
|
|
7755
|
-
const normalizedPath = resultPath.split(
|
|
8338
|
+
const normalizedPath = resultPath.split(path4.sep).join("/");
|
|
7756
8339
|
const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
|
|
7757
8340
|
if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
|
|
7758
8341
|
if (graphExpandedResultPaths.has(resultPath))
|
|
@@ -9070,16 +9653,16 @@ ${formatted}`;
|
|
|
9070
9653
|
if (!this.config.compactionResetEnabled) return null;
|
|
9071
9654
|
const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
|
|
9072
9655
|
const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
|
|
9073
|
-
const signalPath =
|
|
9656
|
+
const signalPath = path4.join(
|
|
9074
9657
|
workspaceDir,
|
|
9075
9658
|
`.compaction-reset-signal-${safeSessionKey}`
|
|
9076
9659
|
);
|
|
9077
|
-
const bootPath =
|
|
9660
|
+
const bootPath = path4.join(workspaceDir, "BOOT.md");
|
|
9078
9661
|
try {
|
|
9079
|
-
const signalStat = await
|
|
9662
|
+
const signalStat = await stat3(signalPath).catch(() => null);
|
|
9080
9663
|
if (!signalStat) return null;
|
|
9081
9664
|
const signalAge = Date.now() - signalStat.mtimeMs;
|
|
9082
|
-
const signalData = JSON.parse(await
|
|
9665
|
+
const signalData = JSON.parse(await readFile4(signalPath, "utf-8"));
|
|
9083
9666
|
if (signalData.sessionKey !== effectiveSessionKey) {
|
|
9084
9667
|
log.debug(
|
|
9085
9668
|
`recall: compaction signal is for ${signalData.sessionKey}, not ${effectiveSessionKey} \u2014 skipping`
|
|
@@ -9099,7 +9682,7 @@ ${formatted}`;
|
|
|
9099
9682
|
|
|
9100
9683
|
`;
|
|
9101
9684
|
try {
|
|
9102
|
-
const bootContent = await
|
|
9685
|
+
const bootContent = await readFile4(bootPath, "utf-8");
|
|
9103
9686
|
section += "### BOOT.md (working state before compaction)\n\n";
|
|
9104
9687
|
section += bootContent + "\n";
|
|
9105
9688
|
} catch {
|
|
@@ -11204,7 +11787,7 @@ _Context: ${topQuestion.context}_`
|
|
|
11204
11787
|
const shouldUseStableBatchKey = turns.some(
|
|
11205
11788
|
(turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
|
|
11206
11789
|
);
|
|
11207
|
-
const stableBatchFingerprint = shouldUseStableBatchKey ?
|
|
11790
|
+
const stableBatchFingerprint = shouldUseStableBatchKey ? createHash2("sha256").update(
|
|
11208
11791
|
turns.map(
|
|
11209
11792
|
(turn) => [
|
|
11210
11793
|
turn.role,
|
|
@@ -11461,7 +12044,7 @@ _Context: ${topQuestion.context}_`
|
|
|
11461
12044
|
buildExtractionFingerprint(turns, bufferKey) {
|
|
11462
12045
|
const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
|
|
11463
12046
|
if (!normalized) return null;
|
|
11464
|
-
return
|
|
12047
|
+
return createHash2("sha256").update(`${bufferKey}
|
|
11465
12048
|
${normalized}`).digest("hex");
|
|
11466
12049
|
}
|
|
11467
12050
|
shouldQueueExtraction(turns, options = {}) {
|
|
@@ -11951,7 +12534,7 @@ ${normalized}`).digest("hex");
|
|
|
11951
12534
|
);
|
|
11952
12535
|
this.tierMigrationInFlight = true;
|
|
11953
12536
|
try {
|
|
11954
|
-
const coldStorage = new StorageManager(
|
|
12537
|
+
const coldStorage = new StorageManager(path4.join(storage.dir, "cold"));
|
|
11955
12538
|
const [hotMemories, coldMemories] = await Promise.all([
|
|
11956
12539
|
storage.readAllMemories(),
|
|
11957
12540
|
coldStorage.readAllMemories()
|
|
@@ -12095,13 +12678,61 @@ ${normalized}`).digest("hex");
|
|
|
12095
12678
|
this.qmdMaintenancePending = false;
|
|
12096
12679
|
try {
|
|
12097
12680
|
if (this.config.namespacesEnabled) {
|
|
12098
|
-
const
|
|
12099
|
-
await this.namespaceSearchRouter.updateNamespaces(maintenanceNamespaces);
|
|
12681
|
+
const plan = await this.namespaceMaintenancePlan("qmd");
|
|
12100
12682
|
const now = Date.now();
|
|
12101
|
-
|
|
12102
|
-
|
|
12683
|
+
const lastEmbedAtByNamespace = this.lastQmdEmbedAtMsByNamespace ?? (this.lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map());
|
|
12684
|
+
const dueEmbedNamespaces = (namespaces) => {
|
|
12685
|
+
if (!this.config.qmdAutoEmbedEnabled) return [];
|
|
12686
|
+
return namespaces.filter(
|
|
12687
|
+
(namespace) => now - (lastEmbedAtByNamespace.get(namespace) ?? 0) >= this.config.qmdEmbedMinIntervalMs
|
|
12688
|
+
);
|
|
12689
|
+
};
|
|
12690
|
+
const markEmbedded = (namespaces) => {
|
|
12691
|
+
if (namespaces.length === 0) return;
|
|
12692
|
+
for (const namespace of namespaces) {
|
|
12693
|
+
lastEmbedAtByNamespace.set(namespace, now);
|
|
12694
|
+
}
|
|
12103
12695
|
this.lastQmdEmbedAtMs = now;
|
|
12104
|
-
}
|
|
12696
|
+
};
|
|
12697
|
+
await runNamespaceMaintenanceBatchPlan(
|
|
12698
|
+
this.config,
|
|
12699
|
+
plan,
|
|
12700
|
+
async (candidates) => {
|
|
12701
|
+
const namespaces = candidates.map((candidate) => candidate.namespace);
|
|
12702
|
+
const embedNamespaces = dueEmbedNamespaces(namespaces);
|
|
12703
|
+
let result;
|
|
12704
|
+
try {
|
|
12705
|
+
result = await this.namespaceSearchRouter.updateNamespacesDetailed(
|
|
12706
|
+
namespaces,
|
|
12707
|
+
void 0,
|
|
12708
|
+
{ strict: true }
|
|
12709
|
+
);
|
|
12710
|
+
} catch (error) {
|
|
12711
|
+
if (embedNamespaces.length > 0 && qmdMaintenanceSkipReasonForError(error) === "throttled") {
|
|
12712
|
+
await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
|
|
12713
|
+
markEmbedded(embedNamespaces);
|
|
12714
|
+
}
|
|
12715
|
+
throw error;
|
|
12716
|
+
}
|
|
12717
|
+
if (result.backendCount <= 0) {
|
|
12718
|
+
throw new Error("no eligible QMD backend for selected namespaces");
|
|
12719
|
+
}
|
|
12720
|
+
if (result.eligibleNamespaces.length !== namespaces.length) {
|
|
12721
|
+
const eligible = new Set(result.eligibleNamespaces);
|
|
12722
|
+
const missing = namespaces.filter((namespace) => !eligible.has(namespace));
|
|
12723
|
+
throw new Error(`QMD backend ineligible for selected namespaces (${missing.length})`);
|
|
12724
|
+
}
|
|
12725
|
+
if (embedNamespaces.length > 0) {
|
|
12726
|
+
await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
|
|
12727
|
+
markEmbedded(embedNamespaces);
|
|
12728
|
+
}
|
|
12729
|
+
return { itemCount: result.backendCount };
|
|
12730
|
+
},
|
|
12731
|
+
this.namespaceCatalog,
|
|
12732
|
+
{
|
|
12733
|
+
skipReasonForError: qmdMaintenanceSkipReasonForError
|
|
12734
|
+
}
|
|
12735
|
+
);
|
|
12105
12736
|
} else {
|
|
12106
12737
|
await this.qmd.update();
|
|
12107
12738
|
const now = Date.now();
|
|
@@ -13196,7 +13827,7 @@ ${normalized}`).digest("hex");
|
|
|
13196
13827
|
const allMems = allMemsForGraph ?? [];
|
|
13197
13828
|
for (const m of allMems) {
|
|
13198
13829
|
if (m.frontmatter.entityRef === entityRef) {
|
|
13199
|
-
const rel =
|
|
13830
|
+
const rel = path4.relative(storage.dir, m.path);
|
|
13200
13831
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
13201
13832
|
}
|
|
13202
13833
|
}
|
|
@@ -13512,14 +14143,14 @@ ${normalized}`).digest("hex");
|
|
|
13512
14143
|
}
|
|
13513
14144
|
if (this.config.semanticConsolidationEnabled) {
|
|
13514
14145
|
try {
|
|
13515
|
-
const stateFilePath =
|
|
14146
|
+
const stateFilePath = path4.join(
|
|
13516
14147
|
this.config.memoryDir,
|
|
13517
14148
|
"state",
|
|
13518
14149
|
"semantic-consolidation-last-run.json"
|
|
13519
14150
|
);
|
|
13520
14151
|
let shouldRun = true;
|
|
13521
14152
|
try {
|
|
13522
|
-
const stateRaw = await
|
|
14153
|
+
const stateRaw = await readFile4(stateFilePath, "utf-8");
|
|
13523
14154
|
const stateData = JSON.parse(stateRaw);
|
|
13524
14155
|
if (stateData.lastRunAt) {
|
|
13525
14156
|
const lastRunMs = new Date(stateData.lastRunAt).getTime();
|
|
@@ -13560,9 +14191,9 @@ ${normalized}`).digest("hex");
|
|
|
13560
14191
|
);
|
|
13561
14192
|
}
|
|
13562
14193
|
if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
|
|
13563
|
-
const stateDir =
|
|
13564
|
-
await
|
|
13565
|
-
await
|
|
14194
|
+
const stateDir = path4.join(this.config.memoryDir, "state");
|
|
14195
|
+
await mkdir4(stateDir, { recursive: true });
|
|
14196
|
+
await writeFile4(
|
|
13566
14197
|
stateFilePath,
|
|
13567
14198
|
JSON.stringify({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
13568
14199
|
"utf-8"
|
|
@@ -13761,7 +14392,7 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
13761
14392
|
}
|
|
13762
14393
|
});
|
|
13763
14394
|
const content = renderCompressionGuidelinesMarkdown(refinedCandidate);
|
|
13764
|
-
const contentHash =
|
|
14395
|
+
const contentHash = createHash2("sha256").update(content).digest("hex");
|
|
13765
14396
|
const semanticRefinementApplied = JSON.stringify(refinedCandidate.ruleUpdates) !== JSON.stringify(candidate.ruleUpdates);
|
|
13766
14397
|
const changedRules = refinedCandidate.ruleUpdates.filter(
|
|
13767
14398
|
(rule) => rule.delta !== 0
|
|
@@ -14064,13 +14695,13 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
14064
14695
|
protectedCategories: this.config.lifecycleProtectedCategories
|
|
14065
14696
|
}
|
|
14066
14697
|
};
|
|
14067
|
-
const metricsPath =
|
|
14698
|
+
const metricsPath = path4.join(
|
|
14068
14699
|
storage.dir,
|
|
14069
14700
|
"state",
|
|
14070
14701
|
"lifecycle-metrics.json"
|
|
14071
14702
|
);
|
|
14072
|
-
await
|
|
14073
|
-
await
|
|
14703
|
+
await mkdir4(path4.dirname(metricsPath), { recursive: true });
|
|
14704
|
+
await writeFile4(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
|
|
14074
14705
|
return updatedCount;
|
|
14075
14706
|
}
|
|
14076
14707
|
/**
|
|
@@ -14603,7 +15234,7 @@ ${lines.join("\n\n")}`;
|
|
|
14603
15234
|
const seenStorageDirs = /* @__PURE__ */ new Set();
|
|
14604
15235
|
const addStorage = (storage) => {
|
|
14605
15236
|
const storageDir = storageDirFor(storage);
|
|
14606
|
-
const storageKey = storageDir ?
|
|
15237
|
+
const storageKey = storageDir ? path4.resolve(storageDir) : `storage-without-dir-${storages.length}`;
|
|
14607
15238
|
if (seenStorageDirs.has(storageKey)) return;
|
|
14608
15239
|
seenStorageDirs.add(storageKey);
|
|
14609
15240
|
storages.push(storage);
|
|
@@ -14633,7 +15264,7 @@ ${lines.join("\n\n")}`;
|
|
|
14633
15264
|
continue;
|
|
14634
15265
|
}
|
|
14635
15266
|
try {
|
|
14636
|
-
const coldRoot =
|
|
15267
|
+
const coldRoot = path4.join(storageDir, "cold");
|
|
14637
15268
|
for (const candidate of qmdResultPathCandidates(
|
|
14638
15269
|
coldRoot,
|
|
14639
15270
|
parts.relativePath
|
|
@@ -14674,7 +15305,7 @@ ${lines.join("\n\n")}`;
|
|
|
14674
15305
|
return null;
|
|
14675
15306
|
}
|
|
14676
15307
|
}
|
|
14677
|
-
if (
|
|
15308
|
+
if (path4.isAbsolute(resultPath)) {
|
|
14678
15309
|
if (!fallbackStorageDir) {
|
|
14679
15310
|
return await fallbackStorage.readMemoryByPath(resultPath);
|
|
14680
15311
|
}
|
|
@@ -14713,7 +15344,7 @@ ${lines.join("\n\n")}`;
|
|
|
14713
15344
|
);
|
|
14714
15345
|
if (!memory) return null;
|
|
14715
15346
|
let ownerNamespace = null;
|
|
14716
|
-
if (
|
|
15347
|
+
if (path4.isAbsolute(memory.path)) {
|
|
14717
15348
|
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
14718
15349
|
memory.path,
|
|
14719
15350
|
fallbackStorage,
|
|
@@ -14737,16 +15368,16 @@ ${lines.join("\n\n")}`;
|
|
|
14737
15368
|
};
|
|
14738
15369
|
}
|
|
14739
15370
|
async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
14740
|
-
const resolvedPath =
|
|
14741
|
-
const memoryRoot =
|
|
14742
|
-
const namespacesRoot =
|
|
15371
|
+
const resolvedPath = path4.resolve(resultPath);
|
|
15372
|
+
const memoryRoot = path4.resolve(this.config.memoryDir);
|
|
15373
|
+
const namespacesRoot = path4.join(memoryRoot, "namespaces");
|
|
14743
15374
|
const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
|
|
14744
15375
|
const matches = [];
|
|
14745
15376
|
const seenDirs = /* @__PURE__ */ new Set();
|
|
14746
15377
|
const maybeAddStorage = (storage, namespace) => {
|
|
14747
15378
|
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
14748
15379
|
if (!storageDir) return;
|
|
14749
|
-
const candidateRoot =
|
|
15380
|
+
const candidateRoot = path4.resolve(storageDir);
|
|
14750
15381
|
if (seenDirs.has(candidateRoot)) return;
|
|
14751
15382
|
if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
|
|
14752
15383
|
if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
@@ -14764,7 +15395,7 @@ ${lines.join("\n\n")}`;
|
|
|
14764
15395
|
candidateNamespaces.add(ns);
|
|
14765
15396
|
}
|
|
14766
15397
|
if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
14767
|
-
const relativeToNamespaces =
|
|
15398
|
+
const relativeToNamespaces = path4.relative(namespacesRoot, resolvedPath);
|
|
14768
15399
|
const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
|
|
14769
15400
|
if (namespaceSegment) {
|
|
14770
15401
|
candidateNamespaces.add(
|
|
@@ -14809,7 +15440,7 @@ ${lines.join("\n\n")}`;
|
|
|
14809
15440
|
nsMap = buildMemoryWorthCounterMap(memories);
|
|
14810
15441
|
this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
|
|
14811
15442
|
}
|
|
14812
|
-
for (const [
|
|
15443
|
+
for (const [path5, c] of nsMap) counters.set(path5, c);
|
|
14813
15444
|
} catch (err) {
|
|
14814
15445
|
log.debug("memory-worth: failed to read namespace, skipping", {
|
|
14815
15446
|
namespace: ns,
|
|
@@ -14980,12 +15611,12 @@ ${lines.join("\n\n")}`;
|
|
|
14980
15611
|
*/
|
|
14981
15612
|
semanticDedupScopeFor(targetStorage) {
|
|
14982
15613
|
if (!this.config.namespacesEnabled) return {};
|
|
14983
|
-
const memoryDir =
|
|
14984
|
-
const storageDir =
|
|
15614
|
+
const memoryDir = path4.resolve(this.config.memoryDir);
|
|
15615
|
+
const storageDir = path4.resolve(targetStorage.dir);
|
|
14985
15616
|
if (storageDir === memoryDir) {
|
|
14986
15617
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
14987
15618
|
}
|
|
14988
|
-
let rel =
|
|
15619
|
+
let rel = path4.relative(memoryDir, storageDir);
|
|
14989
15620
|
if (!rel || rel.startsWith("..")) {
|
|
14990
15621
|
log.debug(
|
|
14991
15622
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -15004,7 +15635,7 @@ ${lines.join("\n\n")}`;
|
|
|
15004
15635
|
if (hits.length === 0) return [];
|
|
15005
15636
|
const results = [];
|
|
15006
15637
|
for (const hit of hits) {
|
|
15007
|
-
const fullPath =
|
|
15638
|
+
const fullPath = path4.isAbsolute(hit.path) ? hit.path : path4.join(this.config.memoryDir, hit.path);
|
|
15008
15639
|
const memory = await this.storage.readMemoryByPath(fullPath);
|
|
15009
15640
|
if (!memory) continue;
|
|
15010
15641
|
results.push({
|
|
@@ -15179,7 +15810,7 @@ ${lines.join("\n\n")}`;
|
|
|
15179
15810
|
const storage = await this.storageRouter.storageFor(namespace);
|
|
15180
15811
|
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
15181
15812
|
if (!storageDir) continue;
|
|
15182
|
-
const recallRoot =
|
|
15813
|
+
const recallRoot = path4.resolve(storageDir);
|
|
15183
15814
|
if (seenRecallRoots.has(recallRoot)) continue;
|
|
15184
15815
|
seenRecallRoots.add(recallRoot);
|
|
15185
15816
|
recallRoots.push(recallRoot);
|
|
@@ -15203,8 +15834,8 @@ ${lines.join("\n\n")}`;
|
|
|
15203
15834
|
if (resolvedCold) scopedResults.push(resolvedCold.result);
|
|
15204
15835
|
continue;
|
|
15205
15836
|
}
|
|
15206
|
-
if (
|
|
15207
|
-
const resolvedPath =
|
|
15837
|
+
if (path4.isAbsolute(result.path)) {
|
|
15838
|
+
const resolvedPath = path4.resolve(result.path);
|
|
15208
15839
|
if (recallRoots.some(
|
|
15209
15840
|
(recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
|
|
15210
15841
|
)) {
|
|
@@ -15945,8 +16576,8 @@ ${lines.join("\n\n")}`;
|
|
|
15945
16576
|
}
|
|
15946
16577
|
namespaceFromStorageDir(storageDir) {
|
|
15947
16578
|
if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
|
|
15948
|
-
const resolvedStorageDir =
|
|
15949
|
-
const resolvedMemoryDir =
|
|
16579
|
+
const resolvedStorageDir = path4.resolve(storageDir);
|
|
16580
|
+
const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
|
|
15950
16581
|
if (resolvedStorageDir === resolvedMemoryDir)
|
|
15951
16582
|
return this.config.defaultNamespace;
|
|
15952
16583
|
const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
|
|
@@ -16076,4 +16707,4 @@ export {
|
|
|
16076
16707
|
resolvePersistedMemoryRelativePath,
|
|
16077
16708
|
Orchestrator
|
|
16078
16709
|
};
|
|
16079
|
-
//# sourceMappingURL=chunk-
|
|
16710
|
+
//# sourceMappingURL=chunk-5QD3QD76.js.map
|