@remnic/core 9.69.52 → 9.69.54
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-admin-ops-surface.d.ts +1 -1
- package/dist/access-admin-ops-surface.js +4 -4
- package/dist/access-authorization-probe.d.ts +1 -1
- package/dist/access-authorization-probe.js +5 -5
- package/dist/access-boundary.d.ts +1 -1
- package/dist/access-boundary.js +4 -4
- package/dist/access-cli.js +23 -23
- package/dist/access-extraction-force-flush.d.ts +1 -1
- package/dist/access-extraction-force-flush.js +4 -4
- package/dist/access-http-briefing.d.ts +1 -1
- package/dist/access-http-briefing.js +5 -5
- package/dist/access-http-lcm-compaction.d.ts +1 -1
- package/dist/access-http-lifecycle-flush.d.ts +1 -1
- package/dist/access-http-offline-stream.d.ts +1 -1
- package/dist/access-http-query.js +4 -4
- package/dist/access-http.d.ts +2 -2
- package/dist/access-http.js +16 -16
- package/dist/access-identity-continuity-surface.js +4 -4
- package/dist/access-lcm-surface.d.ts +1 -1
- package/dist/access-lcm-surface.js +4 -4
- package/dist/access-mcp-shared-context-tools.d.ts +1 -1
- package/dist/access-mcp.d.ts +1 -1
- package/dist/access-mcp.js +11 -11
- package/dist/access-namespace-preflight.js +4 -4
- package/dist/access-observe-write-surface.d.ts +1 -1
- package/dist/access-observe-write-surface.js +4 -4
- package/dist/access-operations-batch.js +5 -5
- package/dist/access-operations.d.ts +1 -1
- package/dist/access-operations.js +10 -10
- package/dist/access-recall-concurrency.d.ts +1 -1
- package/dist/access-recall-concurrency.js +4 -4
- package/dist/access-recall-response.d.ts +1 -1
- package/dist/access-recall-response.js +4 -4
- package/dist/access-recall-surface.d.ts +1 -1
- package/dist/access-recall-surface.js +4 -4
- package/dist/access-schema.d.ts +113 -113
- package/dist/{access-service-CUNM5RfA.d.ts → access-service-H-qEdnSs.d.ts} +64 -64
- package/dist/access-service-helpers.d.ts +1 -1
- package/dist/access-service.d.ts +1 -1
- package/dist/access-service.js +4 -4
- package/dist/access-surface-catalog.d.ts +1 -1
- package/dist/access-surface-catalog.js +6 -6
- package/dist/active-recall.js +1 -1
- package/dist/{chunk-TEQQQTQS.js → chunk-2HJKAVAS.js} +2 -2
- package/dist/{chunk-SEQ6DWXD.js → chunk-5IKW2VP6.js} +2 -2
- package/dist/{chunk-HWT6KRGS.js → chunk-6UEM5EOB.js} +2 -2
- package/dist/{chunk-UCY4EHAG.js → chunk-A4TQFNRX.js} +3 -3
- package/dist/{chunk-72N2P44O.js → chunk-ARRKSBQU.js} +2 -2
- package/dist/{chunk-WBW34YCJ.js → chunk-BCXZ4BDS.js} +2 -2
- package/dist/{chunk-V5BU5PVE.js → chunk-CO7KBRPF.js} +2 -2
- package/dist/{chunk-HG42J2EX.js → chunk-EQNZC3BH.js} +2 -2
- package/dist/{chunk-35EH6KW4.js → chunk-EYK3UHAP.js} +2 -2
- package/dist/{chunk-DCRK7I5E.js → chunk-HUQMVI3A.js} +93 -4
- package/dist/chunk-HUQMVI3A.js.map +1 -0
- package/dist/{chunk-UVZBDIJX.js → chunk-KGY6F4VJ.js} +488 -48
- package/dist/chunk-KGY6F4VJ.js.map +1 -0
- package/dist/{chunk-U6CMLAP4.js → chunk-M7HFDWOS.js} +2 -2
- package/dist/{chunk-2UDAABV6.js → chunk-MTJUIIM4.js} +2 -2
- package/dist/{chunk-GRX6YH4E.js → chunk-MXTCV3B5.js} +2 -2
- package/dist/{chunk-MSTKJI5T.js → chunk-OKOG5MXF.js} +590 -684
- package/dist/chunk-OKOG5MXF.js.map +1 -0
- package/dist/{chunk-6KCQNFDQ.js → chunk-SOOWBRMH.js} +8 -8
- package/dist/{chunk-72AV2H3R.js → chunk-U3NBO4IX.js} +39 -3
- package/dist/chunk-U3NBO4IX.js.map +1 -0
- package/dist/{chunk-EW3Y73MN.js → chunk-UJBIWY5M.js} +2 -2
- package/dist/{chunk-SVUUOLKM.js → chunk-VMKAA5SU.js} +2 -2
- package/dist/{chunk-JE4H2QBO.js → chunk-WJ5KWJLK.js} +2 -2
- package/dist/{chunk-UQTXER7M.js → chunk-ZADYEZY4.js} +2 -2
- package/dist/{chunk-2INZSV27.js → chunk-ZANEMAEV.js} +2 -2
- package/dist/{chunk-SOFATSHJ.js → chunk-ZHV6FGVF.js} +8 -8
- package/dist/{cli-CCc34xV7.d.ts → cli-VGDSn2zY.d.ts} +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +20 -20
- package/dist/config.js +1 -1
- package/dist/deep-recall-http-glue.d.ts +1 -1
- package/dist/deep-recall-mcp-tools.d.ts +1 -1
- package/dist/directory-sidecars.d.ts +30 -7
- package/dist/directory-sidecars.js +5 -1
- package/dist/external-wiki-access.d.ts +1 -1
- package/dist/external-wiki-access.js +5 -5
- package/dist/external-wiki-mcp-tools.d.ts +1 -1
- package/dist/index.d.ts +819 -721
- package/dist/index.js +35 -25
- package/dist/mcp-memory-inspector-app.d.ts +1 -1
- package/dist/memory-browse-http-glue.d.ts +1 -1
- package/dist/memory-browse-mcp-tools.d.ts +1 -1
- package/dist/memory-browse-operations.js +5 -5
- package/dist/memory-browse.js +3 -3
- package/dist/memory-subject-cli.d.ts +1 -1
- package/dist/memory-subject.d.ts +1 -1
- package/dist/operator-toolkit.js +2 -2
- package/dist/orchestrator.js +23 -23
- package/dist/{public-http-UWVcqMcb.d.ts → public-http-P0cnHzYB.d.ts} +1 -1
- package/dist/recall-navigation-http-glue.d.ts +1 -1
- package/dist/recall-navigation-mcp-tools.d.ts +1 -1
- package/dist/recall-navigation-operations.js +5 -5
- package/dist/recall-navigation.js +4 -4
- package/dist/recall-state-view-admission.js +3 -3
- package/dist/resume-bundles.js +2 -2
- package/dist/schemas.d.ts +160 -160
- package/dist/shared-context/manager.d.ts +8 -8
- package/dist/support-passport/index.d.ts +4 -4
- package/dist/support-passport/index.js +7 -7
- package/dist/transfer/types.d.ts +78 -78
- package/dist/who-knows-cli.d.ts +1 -1
- package/dist/who-knows.d.ts +1 -1
- package/package.json +2 -2
- package/src/activity/index.ts +2 -0
- package/src/activity/timeline/index.ts +1 -0
- package/src/activity/timeline/week-dashboard.test.ts +362 -0
- package/src/activity/timeline/week-dashboard.ts +273 -0
- package/src/activity/timeline/weekly.ts +2 -1
- package/src/directory-sidecars.test.ts +113 -0
- package/src/directory-sidecars.ts +70 -8
- package/src/experience/session-experience-mining.test.ts +186 -0
- package/src/experience/session-experience-mining.ts +90 -0
- package/src/lifecycle/seed-graduation.test.ts +209 -0
- package/src/lifecycle/seed-graduation.ts +94 -11
- package/src/orchestration/persistence-index.ts +50 -0
- package/src/orchestration/recall-recognition-index.test.ts +249 -0
- package/src/orchestration/recall-recognition-index.ts +169 -0
- package/src/procedural/procedure-miner.ts +8 -6
- package/src/testing/subjects/recall-recognition-index.test.ts +97 -0
- package/dist/chunk-72AV2H3R.js.map +0 -1
- package/dist/chunk-DCRK7I5E.js.map +0 -1
- package/dist/chunk-MSTKJI5T.js.map +0 -1
- package/dist/chunk-UVZBDIJX.js.map +0 -1
- /package/dist/{chunk-TEQQQTQS.js.map → chunk-2HJKAVAS.js.map} +0 -0
- /package/dist/{chunk-SEQ6DWXD.js.map → chunk-5IKW2VP6.js.map} +0 -0
- /package/dist/{chunk-HWT6KRGS.js.map → chunk-6UEM5EOB.js.map} +0 -0
- /package/dist/{chunk-UCY4EHAG.js.map → chunk-A4TQFNRX.js.map} +0 -0
- /package/dist/{chunk-72N2P44O.js.map → chunk-ARRKSBQU.js.map} +0 -0
- /package/dist/{chunk-WBW34YCJ.js.map → chunk-BCXZ4BDS.js.map} +0 -0
- /package/dist/{chunk-V5BU5PVE.js.map → chunk-CO7KBRPF.js.map} +0 -0
- /package/dist/{chunk-HG42J2EX.js.map → chunk-EQNZC3BH.js.map} +0 -0
- /package/dist/{chunk-35EH6KW4.js.map → chunk-EYK3UHAP.js.map} +0 -0
- /package/dist/{chunk-U6CMLAP4.js.map → chunk-M7HFDWOS.js.map} +0 -0
- /package/dist/{chunk-2UDAABV6.js.map → chunk-MTJUIIM4.js.map} +0 -0
- /package/dist/{chunk-GRX6YH4E.js.map → chunk-MXTCV3B5.js.map} +0 -0
- /package/dist/{chunk-6KCQNFDQ.js.map → chunk-SOOWBRMH.js.map} +0 -0
- /package/dist/{chunk-EW3Y73MN.js.map → chunk-UJBIWY5M.js.map} +0 -0
- /package/dist/{chunk-SVUUOLKM.js.map → chunk-VMKAA5SU.js.map} +0 -0
- /package/dist/{chunk-JE4H2QBO.js.map → chunk-WJ5KWJLK.js.map} +0 -0
- /package/dist/{chunk-UQTXER7M.js.map → chunk-ZADYEZY4.js.map} +0 -0
- /package/dist/{chunk-2INZSV27.js.map → chunk-ZANEMAEV.js.map} +0 -0
- /package/dist/{chunk-SOFATSHJ.js.map → chunk-ZHV6FGVF.js.map} +0 -0
|
@@ -111,7 +111,7 @@ import {
|
|
|
111
111
|
import {
|
|
112
112
|
indexStateViewAnnotatedResults,
|
|
113
113
|
resolveRecallStateViewActive
|
|
114
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-ARRKSBQU.js";
|
|
115
115
|
import {
|
|
116
116
|
applyRecallStateViews
|
|
117
117
|
} from "./chunk-DBB5JPSL.js";
|
|
@@ -231,7 +231,7 @@ import {
|
|
|
231
231
|
runTimelinePublishCli,
|
|
232
232
|
screenCandidateFact,
|
|
233
233
|
summarizeVaultPublish
|
|
234
|
-
} from "./chunk-
|
|
234
|
+
} from "./chunk-ZHV6FGVF.js";
|
|
235
235
|
import {
|
|
236
236
|
normalizeReplaySessionKey
|
|
237
237
|
} from "./chunk-AJVLDJU6.js";
|
|
@@ -261,7 +261,7 @@ import {
|
|
|
261
261
|
import {
|
|
262
262
|
runNamespaceMaintenanceFanout,
|
|
263
263
|
summarizeNamespaceMaintenanceHealth
|
|
264
|
-
} from "./chunk-
|
|
264
|
+
} from "./chunk-5IKW2VP6.js";
|
|
265
265
|
import {
|
|
266
266
|
planNamespaceMaintenance
|
|
267
267
|
} from "./chunk-7RKAE6Y4.js";
|
|
@@ -325,13 +325,14 @@ import {
|
|
|
325
325
|
import {
|
|
326
326
|
REFUSED_MERGE_CATEGORIES,
|
|
327
327
|
applyNoveltyGate,
|
|
328
|
+
buildMergeFrontmatterUpdate,
|
|
328
329
|
connectorMatchesScope,
|
|
329
330
|
decideSemanticMerge,
|
|
330
331
|
detectMeetings,
|
|
331
332
|
embeddingsFromCosineHits,
|
|
332
333
|
normalizeConnectorScope,
|
|
333
334
|
runSeedGraduationPass
|
|
334
|
-
} from "./chunk-
|
|
335
|
+
} from "./chunk-KGY6F4VJ.js";
|
|
335
336
|
import {
|
|
336
337
|
compileCorrectionRule,
|
|
337
338
|
correctionsFilePath,
|
|
@@ -344,9 +345,12 @@ import {
|
|
|
344
345
|
resolveVaultNotePath
|
|
345
346
|
} from "./chunk-3KJTSCSX.js";
|
|
346
347
|
import {
|
|
348
|
+
buildRecognitionIndex,
|
|
347
349
|
decideRecognitionTier,
|
|
348
350
|
loadRecognitionIndex,
|
|
349
|
-
|
|
351
|
+
recognitionIndexPath,
|
|
352
|
+
runRecognitionTier,
|
|
353
|
+
saveRecognitionIndex
|
|
350
354
|
} from "./chunk-4KQIWY4A.js";
|
|
351
355
|
import {
|
|
352
356
|
AMBIENT_CAPTURE_PROMPT_RULE,
|
|
@@ -354,7 +358,7 @@ import {
|
|
|
354
358
|
} from "./chunk-QW27DOHG.js";
|
|
355
359
|
import {
|
|
356
360
|
MeetingsInputError
|
|
357
|
-
} from "./chunk-
|
|
361
|
+
} from "./chunk-SOOWBRMH.js";
|
|
358
362
|
import {
|
|
359
363
|
WearablesInputError,
|
|
360
364
|
describeErrorForOperator
|
|
@@ -378,8 +382,10 @@ import {
|
|
|
378
382
|
SessionContextCoordinator,
|
|
379
383
|
capturePassiveCorrections,
|
|
380
384
|
clusterByKey,
|
|
381
|
-
detectPassiveCorrections
|
|
382
|
-
|
|
385
|
+
detectPassiveCorrections,
|
|
386
|
+
renderSessionExperiencePreview,
|
|
387
|
+
scoreSessionExperienceForPrompt
|
|
388
|
+
} from "./chunk-HUQMVI3A.js";
|
|
383
389
|
import {
|
|
384
390
|
importCapsule
|
|
385
391
|
} from "./chunk-VVX5PZFS.js";
|
|
@@ -419,7 +425,7 @@ import {
|
|
|
419
425
|
isTopLevelArchivePath,
|
|
420
426
|
journalPath,
|
|
421
427
|
writeJournalFile
|
|
422
|
-
} from "./chunk-
|
|
428
|
+
} from "./chunk-2HJKAVAS.js";
|
|
423
429
|
import {
|
|
424
430
|
searchHarmonicRetrieval
|
|
425
431
|
} from "./chunk-TQT4AOPO.js";
|
|
@@ -661,9 +667,6 @@ import {
|
|
|
661
667
|
import {
|
|
662
668
|
fallbackLlmRuntimeContextFromConfig
|
|
663
669
|
} from "./chunk-EP6BA7VV.js";
|
|
664
|
-
import {
|
|
665
|
-
normalizeRecallTokenSet
|
|
666
|
-
} from "./chunk-YCVB7X56.js";
|
|
667
670
|
import {
|
|
668
671
|
graphemeUnits,
|
|
669
672
|
truncateGraphemeSafe
|
|
@@ -850,7 +853,7 @@ import {
|
|
|
850
853
|
} from "./chunk-3WCASNQZ.js";
|
|
851
854
|
|
|
852
855
|
// src/orchestrator.ts
|
|
853
|
-
import
|
|
856
|
+
import path23 from "path";
|
|
854
857
|
import { createHash as createHash9 } from "crypto";
|
|
855
858
|
|
|
856
859
|
// src/orchestration/tier-migration-coordinator.ts
|
|
@@ -5600,93 +5603,6 @@ async function persistRepairedContentHash(storage, targetId, committedContent, c
|
|
|
5600
5603
|
}
|
|
5601
5604
|
}
|
|
5602
5605
|
|
|
5603
|
-
// src/dedup/merge-provenance.ts
|
|
5604
|
-
var MERGE_DERIVED_VIA = "merge";
|
|
5605
|
-
var ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
5606
|
-
function assertIsoInstant(value, field) {
|
|
5607
|
-
if (typeof value !== "string" || !ISO_TIMESTAMP.test(value)) {
|
|
5608
|
-
throw new RangeError(`${field} must be a full ISO 8601 instant, got ${JSON.stringify(value)}`);
|
|
5609
|
-
}
|
|
5610
|
-
const ms = Date.parse(value);
|
|
5611
|
-
if (Number.isNaN(ms)) {
|
|
5612
|
-
throw new RangeError(`${field} must be a full ISO 8601 instant, got ${JSON.stringify(value)}`);
|
|
5613
|
-
}
|
|
5614
|
-
if (!new Date(ms).toISOString().startsWith(value.slice(0, 10))) {
|
|
5615
|
-
throw new RangeError(`${field} is not a real calendar date: ${JSON.stringify(value)}`);
|
|
5616
|
-
}
|
|
5617
|
-
return value;
|
|
5618
|
-
}
|
|
5619
|
-
function assertOffset(value, field) {
|
|
5620
|
-
if (value === void 0) return;
|
|
5621
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
5622
|
-
throw new RangeError(`${field} must be a non-negative integer when present, got ${String(value)}`);
|
|
5623
|
-
}
|
|
5624
|
-
}
|
|
5625
|
-
function normalizeSource(source, index) {
|
|
5626
|
-
const label = `sources[${index}]`;
|
|
5627
|
-
for (const field of ["sessionKey", "quote"]) {
|
|
5628
|
-
const value = source[field];
|
|
5629
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
5630
|
-
throw new RangeError(`${label}.${field} must be a non-blank string`);
|
|
5631
|
-
}
|
|
5632
|
-
}
|
|
5633
|
-
assertIsoInstant(source.observedAt, `${label}.observedAt`);
|
|
5634
|
-
if (source.turnId !== void 0 && (typeof source.turnId !== "string" || source.turnId.trim() === "")) {
|
|
5635
|
-
throw new RangeError(`${label}.turnId must be a non-blank string when present`);
|
|
5636
|
-
}
|
|
5637
|
-
assertOffset(source.charStart, `${label}.charStart`);
|
|
5638
|
-
assertOffset(source.charEnd, `${label}.charEnd`);
|
|
5639
|
-
if (source.charStart !== void 0 && source.charEnd !== void 0 && source.charEnd < source.charStart) {
|
|
5640
|
-
throw new RangeError(`${label}.charEnd must be >= charStart`);
|
|
5641
|
-
}
|
|
5642
|
-
const copy = {
|
|
5643
|
-
sessionKey: source.sessionKey,
|
|
5644
|
-
observedAt: source.observedAt,
|
|
5645
|
-
quote: source.quote
|
|
5646
|
-
};
|
|
5647
|
-
if (source.turnId !== void 0) copy.turnId = source.turnId;
|
|
5648
|
-
if (source.charStart !== void 0) copy.charStart = source.charStart;
|
|
5649
|
-
if (source.charEnd !== void 0) copy.charEnd = source.charEnd;
|
|
5650
|
-
return copy;
|
|
5651
|
-
}
|
|
5652
|
-
function sourceKey(source) {
|
|
5653
|
-
return JSON.stringify([
|
|
5654
|
-
source.sessionKey,
|
|
5655
|
-
source.turnId ?? null,
|
|
5656
|
-
source.observedAt,
|
|
5657
|
-
source.quote,
|
|
5658
|
-
source.charStart ?? null,
|
|
5659
|
-
source.charEnd ?? null
|
|
5660
|
-
]);
|
|
5661
|
-
}
|
|
5662
|
-
function buildMergeFrontmatterUpdate(input) {
|
|
5663
|
-
const updated = assertIsoInstant(input.nowIso, "nowIso");
|
|
5664
|
-
const previous = input.targetReinforcementCount;
|
|
5665
|
-
if (previous !== void 0 && (typeof previous !== "number" || !Number.isInteger(previous) || previous < 0)) {
|
|
5666
|
-
throw new RangeError(
|
|
5667
|
-
`reinforcement_count must be a non-negative integer when supplied, got ${String(previous)}`
|
|
5668
|
-
);
|
|
5669
|
-
}
|
|
5670
|
-
const seen = /* @__PURE__ */ new Set();
|
|
5671
|
-
const sources = [];
|
|
5672
|
-
const append = (source, index) => {
|
|
5673
|
-
const copy = normalizeSource(source, index);
|
|
5674
|
-
const key = sourceKey(copy);
|
|
5675
|
-
if (seen.has(key)) return;
|
|
5676
|
-
seen.add(key);
|
|
5677
|
-
sources.push(copy);
|
|
5678
|
-
};
|
|
5679
|
-
const target = input.targetSources ?? [];
|
|
5680
|
-
target.forEach(append);
|
|
5681
|
-
input.incomingSources.forEach((source, i) => append(source, target.length + i));
|
|
5682
|
-
return {
|
|
5683
|
-
updated,
|
|
5684
|
-
derived_via: MERGE_DERIVED_VIA,
|
|
5685
|
-
reinforcement_count: (previous ?? 0) + 1,
|
|
5686
|
-
sources
|
|
5687
|
-
};
|
|
5688
|
-
}
|
|
5689
|
-
|
|
5690
5606
|
// src/dedup/merge-judge.ts
|
|
5691
5607
|
import { z } from "zod";
|
|
5692
5608
|
var MERGE_JUDGE_SYSTEM_PROMPT = `You maintain a long-term memory store. Given a NEW memory and up to N EXISTING
|
|
@@ -9897,44 +9813,8 @@ var GraphRecallCoordinator = class {
|
|
|
9897
9813
|
}
|
|
9898
9814
|
};
|
|
9899
9815
|
|
|
9900
|
-
// src/experience/session-experience-recall.ts
|
|
9901
|
-
function tokenOverlapScore(prompt, memoryText) {
|
|
9902
|
-
const norm = (s) => s.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 2);
|
|
9903
|
-
const promptTokens = new Set(norm(prompt));
|
|
9904
|
-
const memTokens = new Set(norm(memoryText));
|
|
9905
|
-
if (promptTokens.size === 0 || memTokens.size === 0) return 0;
|
|
9906
|
-
let inter = 0;
|
|
9907
|
-
for (const t of promptTokens) {
|
|
9908
|
-
if (memTokens.has(t)) inter++;
|
|
9909
|
-
}
|
|
9910
|
-
const union = /* @__PURE__ */ new Set([...promptTokens, ...memTokens]);
|
|
9911
|
-
return inter / Math.max(1, union.size);
|
|
9912
|
-
}
|
|
9913
|
-
function isSessionExperienceMemory(memory) {
|
|
9914
|
-
const hash = memory.frontmatter.structuredAttributes?.experience_session_hash;
|
|
9915
|
-
return typeof hash === "string" && hash.length > 0;
|
|
9916
|
-
}
|
|
9917
|
-
function scoreSessionExperienceForPrompt(memory, prompt) {
|
|
9918
|
-
if (!isSessionExperienceMemory(memory)) return null;
|
|
9919
|
-
const situation = memory.frontmatter.structuredAttributes?.experience_situation ?? "";
|
|
9920
|
-
const situationScore = tokenOverlapScore(prompt, situation);
|
|
9921
|
-
const bodyScore = tokenOverlapScore(prompt, memory.content);
|
|
9922
|
-
return Math.min(1, situationScore * 0.75 + bodyScore * 0.25);
|
|
9923
|
-
}
|
|
9924
|
-
function renderSessionExperiencePreview(memory) {
|
|
9925
|
-
if (!isSessionExperienceMemory(memory)) return null;
|
|
9926
|
-
const attrs = memory.frontmatter.structuredAttributes ?? {};
|
|
9927
|
-
const situation = (attrs.experience_situation ?? "").trim();
|
|
9928
|
-
const approach = (attrs.experience_approach ?? "").trim();
|
|
9929
|
-
const reflection = (attrs.experience_reflection ?? "").trim();
|
|
9930
|
-
if (situation.length === 0 && approach.length === 0 && reflection.length === 0) {
|
|
9931
|
-
return `Experience. ${memory.content.replace(/\s+/g, " ").trim()}`;
|
|
9932
|
-
}
|
|
9933
|
-
return `Experience. Situation: ${situation} Approach: ${approach} Reflection: ${reflection}`.replace(/\s+/g, " ").trim();
|
|
9934
|
-
}
|
|
9935
|
-
|
|
9936
9816
|
// src/procedural/procedure-recall.ts
|
|
9937
|
-
function
|
|
9817
|
+
function tokenOverlapScore(prompt, memoryText) {
|
|
9938
9818
|
const norm = (s) => s.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 2);
|
|
9939
9819
|
const promptTokens = new Set(norm(prompt));
|
|
9940
9820
|
const memTokens = new Set(norm(memoryText));
|
|
@@ -9949,7 +9829,7 @@ function tokenOverlapScore2(prompt, memoryText) {
|
|
|
9949
9829
|
function scoreProcedureForPrompt(m, prompt, queryIntent, experienceEnabled) {
|
|
9950
9830
|
const memText = `${m.content}
|
|
9951
9831
|
${(m.frontmatter.tags ?? []).join(" ")}`;
|
|
9952
|
-
const jaccard =
|
|
9832
|
+
const jaccard = tokenOverlapScore(prompt, memText);
|
|
9953
9833
|
const memIntent = inferIntentFromText(m.content.slice(0, 2e3));
|
|
9954
9834
|
const intentScore = intentCompatibilityScore(queryIntent, memIntent);
|
|
9955
9835
|
const base = jaccard * 0.55 + intentScore * 0.45;
|
|
@@ -17655,7 +17535,121 @@ var OrchestratorInitCoordinator = class {
|
|
|
17655
17535
|
};
|
|
17656
17536
|
|
|
17657
17537
|
// src/orchestration/persistence-index.ts
|
|
17538
|
+
import path19 from "path";
|
|
17539
|
+
|
|
17540
|
+
// src/orchestration/recall-recognition-index.ts
|
|
17541
|
+
import { promises as fsp } from "fs";
|
|
17658
17542
|
import path18 from "path";
|
|
17543
|
+
import { setTimeout as delay } from "timers/promises";
|
|
17544
|
+
var writeChains = /* @__PURE__ */ new Map();
|
|
17545
|
+
var LOCK_POLL_MS = 10;
|
|
17546
|
+
var LOCK_ATTEMPTS = 50;
|
|
17547
|
+
var LOCK_STALE_MS = 6e4;
|
|
17548
|
+
function recognitionDescriptionFromContent(content) {
|
|
17549
|
+
const trimmed = content.trim();
|
|
17550
|
+
if (trimmed.length === 0) return "";
|
|
17551
|
+
const newline = trimmed.indexOf("\n");
|
|
17552
|
+
return newline === -1 ? trimmed : trimmed.slice(0, newline).trimEnd();
|
|
17553
|
+
}
|
|
17554
|
+
function withIndexChain(indexPath, op) {
|
|
17555
|
+
const previous = writeChains.get(indexPath) ?? Promise.resolve();
|
|
17556
|
+
const run = previous.then(op, op);
|
|
17557
|
+
const tail = run.then(() => void 0, () => void 0);
|
|
17558
|
+
writeChains.set(indexPath, tail);
|
|
17559
|
+
void tail.then(() => {
|
|
17560
|
+
if (writeChains.get(indexPath) === tail) writeChains.delete(indexPath);
|
|
17561
|
+
});
|
|
17562
|
+
return run;
|
|
17563
|
+
}
|
|
17564
|
+
async function removeAbandonedRecognitionLock(lockDir) {
|
|
17565
|
+
try {
|
|
17566
|
+
const info = await fsp.lstat(lockDir);
|
|
17567
|
+
if (info.isSymbolicLink()) return "blocked";
|
|
17568
|
+
if (!info.isDirectory()) {
|
|
17569
|
+
await fsp.rm(lockDir, { force: true });
|
|
17570
|
+
return "removed";
|
|
17571
|
+
}
|
|
17572
|
+
if (Date.now() - info.mtimeMs < LOCK_STALE_MS) return "wait";
|
|
17573
|
+
await fsp.rm(lockDir, { recursive: true, force: true });
|
|
17574
|
+
return "removed";
|
|
17575
|
+
} catch (error) {
|
|
17576
|
+
if (error?.code === "ENOENT") return "removed";
|
|
17577
|
+
return "blocked";
|
|
17578
|
+
}
|
|
17579
|
+
}
|
|
17580
|
+
async function withRecognitionIndexLock(memoryDir, op) {
|
|
17581
|
+
const lockDir = `${recognitionIndexPath(memoryDir)}.lock.d`;
|
|
17582
|
+
for (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt++) {
|
|
17583
|
+
try {
|
|
17584
|
+
await fsp.mkdir(lockDir);
|
|
17585
|
+
try {
|
|
17586
|
+
return await op();
|
|
17587
|
+
} finally {
|
|
17588
|
+
await fsp.rm(lockDir, { recursive: true, force: true }).catch(() => void 0);
|
|
17589
|
+
}
|
|
17590
|
+
} catch (error) {
|
|
17591
|
+
const code = error?.code;
|
|
17592
|
+
if (code === "ENOENT") {
|
|
17593
|
+
await fsp.mkdir(path18.dirname(lockDir), { recursive: true }).catch(() => void 0);
|
|
17594
|
+
continue;
|
|
17595
|
+
}
|
|
17596
|
+
if (code !== "EEXIST") throw error;
|
|
17597
|
+
const cleanup = await removeAbandonedRecognitionLock(lockDir);
|
|
17598
|
+
if (cleanup === "blocked") {
|
|
17599
|
+
throw new Error(`recognition index lock blocked at ${lockDir}`);
|
|
17600
|
+
}
|
|
17601
|
+
if (cleanup === "removed") continue;
|
|
17602
|
+
await delay(LOCK_POLL_MS);
|
|
17603
|
+
}
|
|
17604
|
+
}
|
|
17605
|
+
throw new Error(`recognition index lock timed out at ${lockDir}`);
|
|
17606
|
+
}
|
|
17607
|
+
function applyChanges(entries, changes) {
|
|
17608
|
+
const next = entries.map((entry) => ({ id: entry.id, description: entry.description }));
|
|
17609
|
+
const byId = new Map(next.map((entry, index) => [entry.id, index]));
|
|
17610
|
+
for (const change of changes) {
|
|
17611
|
+
const id = change.id.trim();
|
|
17612
|
+
if (id.length === 0) continue;
|
|
17613
|
+
if (change.action === "remove") {
|
|
17614
|
+
const index = byId.get(id);
|
|
17615
|
+
if (index === void 0) continue;
|
|
17616
|
+
next.splice(index, 1);
|
|
17617
|
+
byId.delete(id);
|
|
17618
|
+
for (const [key, value] of byId) {
|
|
17619
|
+
if (value > index) byId.set(key, value - 1);
|
|
17620
|
+
}
|
|
17621
|
+
continue;
|
|
17622
|
+
}
|
|
17623
|
+
const description = recognitionDescriptionFromContent(change.content);
|
|
17624
|
+
const existing = byId.get(id);
|
|
17625
|
+
if (existing !== void 0) {
|
|
17626
|
+
next[existing] = { id, description };
|
|
17627
|
+
} else {
|
|
17628
|
+
byId.set(id, next.length);
|
|
17629
|
+
next.push({ id, description });
|
|
17630
|
+
}
|
|
17631
|
+
}
|
|
17632
|
+
return next;
|
|
17633
|
+
}
|
|
17634
|
+
function meaningfulChanges(changes) {
|
|
17635
|
+
return changes.filter((change) => change.id.trim().length > 0);
|
|
17636
|
+
}
|
|
17637
|
+
async function maintainRecognitionIndexAfterWrite(args) {
|
|
17638
|
+
if (args.enabled !== true) return;
|
|
17639
|
+
const changes = meaningfulChanges(args.changes);
|
|
17640
|
+
if (changes.length === 0) return;
|
|
17641
|
+
const indexPath = recognitionIndexPath(args.memoryDir);
|
|
17642
|
+
await withIndexChain(
|
|
17643
|
+
indexPath,
|
|
17644
|
+
() => withRecognitionIndexLock(args.memoryDir, async () => {
|
|
17645
|
+
const loaded = await loadRecognitionIndex(args.memoryDir);
|
|
17646
|
+
const entries = applyChanges(loaded?.entries ?? [], changes);
|
|
17647
|
+
await saveRecognitionIndex(args.memoryDir, buildRecognitionIndex(entries));
|
|
17648
|
+
})
|
|
17649
|
+
);
|
|
17650
|
+
}
|
|
17651
|
+
|
|
17652
|
+
// src/orchestration/persistence-index.ts
|
|
17659
17653
|
var PersistenceIndexCoordinator = class {
|
|
17660
17654
|
constructor(deps) {
|
|
17661
17655
|
this.deps = deps;
|
|
@@ -17847,7 +17841,7 @@ var PersistenceIndexCoordinator = class {
|
|
|
17847
17841
|
const allMems = allMemsForGraph ?? [];
|
|
17848
17842
|
for (const m of allMems) {
|
|
17849
17843
|
if (m.frontmatter.entityRef === entityRef) {
|
|
17850
|
-
const rel =
|
|
17844
|
+
const rel = path19.relative(storage.dir, m.path);
|
|
17851
17845
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
17852
17846
|
}
|
|
17853
17847
|
}
|
|
@@ -17898,6 +17892,7 @@ var PersistenceIndexCoordinator = class {
|
|
|
17898
17892
|
* Fail-open: any error is logged but does not abort extraction.
|
|
17899
17893
|
*/
|
|
17900
17894
|
async updateTemporalTagIndexes(storage, persistedIds) {
|
|
17895
|
+
await this.maintainRecognitionIndex(storage, persistedIds);
|
|
17901
17896
|
const caps = resolveCapabilities(this.deps.config);
|
|
17902
17897
|
if (!resolveIndexingCapabilities(this.deps.config).queryAwareIndexing && !caps.parallelRetrieval && !resolveRecallEnhancementCapabilities(this.deps.config).eventOrderRecall)
|
|
17903
17898
|
return;
|
|
@@ -17998,11 +17993,51 @@ var PersistenceIndexCoordinator = class {
|
|
|
17998
17993
|
);
|
|
17999
17994
|
return enriched;
|
|
18000
17995
|
}
|
|
17996
|
+
/**
|
|
17997
|
+
* Upsert persisted memories into the namespace recognition index.
|
|
17998
|
+
* `recallRecognitionTier !== true` returns before any index I/O.
|
|
17999
|
+
* A missing index is bootstrapped from the active corpus so the first
|
|
18000
|
+
* post-enable write cannot publish a partial index that recall would
|
|
18001
|
+
* treat as the full working set.
|
|
18002
|
+
*/
|
|
18003
|
+
async maintainRecognitionIndex(storage, persistedIds) {
|
|
18004
|
+
try {
|
|
18005
|
+
if (this.deps.config.recallRecognitionTier !== true) return;
|
|
18006
|
+
const indexMissing = await loadRecognitionIndex(storage.dir) === null;
|
|
18007
|
+
if (!indexMissing && persistedIds.length === 0) return;
|
|
18008
|
+
const changes = [];
|
|
18009
|
+
const pushUpsert = (memory) => {
|
|
18010
|
+
if (!isActiveMemoryStatus(memory.frontmatter.status)) return;
|
|
18011
|
+
const memoryId = memory.frontmatter.id;
|
|
18012
|
+
if (typeof memoryId !== "string" || memoryId.trim().length === 0) return;
|
|
18013
|
+
changes.push({ action: "upsert", id: memoryId, content: memory.content ?? "" });
|
|
18014
|
+
};
|
|
18015
|
+
if (indexMissing) {
|
|
18016
|
+
const corpus = await storage.readAllMemories().catch(() => []);
|
|
18017
|
+
for (const memory of corpus) pushUpsert(memory);
|
|
18018
|
+
}
|
|
18019
|
+
for (const id of persistedIds) {
|
|
18020
|
+
let memory = await storage.getMemoryById(id);
|
|
18021
|
+
if (!memory) {
|
|
18022
|
+
const cold = await storage.getMemoryByIdIncludingArchived(id).catch(() => null);
|
|
18023
|
+
if (cold && isActiveMemoryStatus(cold.frontmatter.status)) memory = cold;
|
|
18024
|
+
}
|
|
18025
|
+
if (memory) pushUpsert(memory);
|
|
18026
|
+
}
|
|
18027
|
+
await maintainRecognitionIndexAfterWrite({
|
|
18028
|
+
memoryDir: storage.dir,
|
|
18029
|
+
enabled: true,
|
|
18030
|
+
changes
|
|
18031
|
+
});
|
|
18032
|
+
} catch (err) {
|
|
18033
|
+
log.debug(`recognition-index update error (non-fatal): ${err}`);
|
|
18034
|
+
}
|
|
18035
|
+
}
|
|
18001
18036
|
};
|
|
18002
18037
|
|
|
18003
18038
|
// src/orchestration/workspace-ops.ts
|
|
18004
18039
|
import { lstat as lstat2, mkdir as mkdir6, readFile as readFile8, readdir as readdir3, realpath as realpath2, writeFile as writeFile6 } from "fs/promises";
|
|
18005
|
-
import
|
|
18040
|
+
import path20 from "path";
|
|
18006
18041
|
|
|
18007
18042
|
// src/maintenance/pattern-reinforcement.ts
|
|
18008
18043
|
function patternReinforcementKey(content) {
|
|
@@ -19906,8 +19941,8 @@ var MeetingsService = class {
|
|
|
19906
19941
|
// src/orchestration/workspace-ops.ts
|
|
19907
19942
|
var MEETINGS_BUILD_DEBOUNCE_MS = 5e3;
|
|
19908
19943
|
function matchesMemoryPath(candidatePath, requestedPath, memoryDir) {
|
|
19909
|
-
const normalizedCandidate =
|
|
19910
|
-
return normalizedCandidate ===
|
|
19944
|
+
const normalizedCandidate = path20.resolve(candidatePath);
|
|
19945
|
+
return normalizedCandidate === path20.resolve(requestedPath) || normalizedCandidate === path20.resolve(memoryDir, requestedPath);
|
|
19911
19946
|
}
|
|
19912
19947
|
function accessTrackingPathCandidates(storageDir, memoryPath) {
|
|
19913
19948
|
const candidates = qmdResultPathCandidates(storageDir, memoryPath);
|
|
@@ -19915,12 +19950,12 @@ function accessTrackingPathCandidates(storageDir, memoryPath) {
|
|
|
19915
19950
|
if (!parts) return candidates;
|
|
19916
19951
|
candidates.push(
|
|
19917
19952
|
...qmdResultPathCandidates(storageDir, parts.relativePath),
|
|
19918
|
-
...qmdResultPathCandidates(
|
|
19953
|
+
...qmdResultPathCandidates(path20.join(storageDir, "cold"), parts.relativePath)
|
|
19919
19954
|
);
|
|
19920
19955
|
return [...new Set(candidates)];
|
|
19921
19956
|
}
|
|
19922
19957
|
function canonicalMemoryPath(memoryPath, memoryDir) {
|
|
19923
|
-
return
|
|
19958
|
+
return path20.resolve(path20.isAbsolute(memoryPath) ? memoryPath : path20.resolve(memoryDir, memoryPath));
|
|
19924
19959
|
}
|
|
19925
19960
|
var WorkspaceOpsCoordinator = class {
|
|
19926
19961
|
constructor(deps) {
|
|
@@ -20002,15 +20037,15 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20002
20037
|
this.deps.lastFileHygieneRunAtMs = now;
|
|
20003
20038
|
if (hygiene.rotateEnabled) {
|
|
20004
20039
|
for (const rel of hygiene.rotatePaths) {
|
|
20005
|
-
const abs =
|
|
20040
|
+
const abs = path20.isAbsolute(rel) ? rel : path20.join(this.deps.config.workspaceDir, rel);
|
|
20006
20041
|
try {
|
|
20007
20042
|
const raw = await readFile8(abs, "utf-8");
|
|
20008
20043
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
20009
|
-
const archiveDir =
|
|
20044
|
+
const archiveDir = path20.join(
|
|
20010
20045
|
this.deps.config.workspaceDir,
|
|
20011
20046
|
hygiene.archiveDir
|
|
20012
20047
|
);
|
|
20013
|
-
const base =
|
|
20048
|
+
const base = path20.basename(abs);
|
|
20014
20049
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
20015
20050
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
20016
20051
|
filePath: abs,
|
|
@@ -20035,8 +20070,8 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20035
20070
|
log.warn(w.message);
|
|
20036
20071
|
}
|
|
20037
20072
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
20038
|
-
const fp =
|
|
20039
|
-
await mkdir6(
|
|
20073
|
+
const fp = path20.join(this.deps.config.memoryDir, hygiene.warningsLogPath);
|
|
20074
|
+
await mkdir6(path20.dirname(fp), { recursive: true });
|
|
20040
20075
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
20041
20076
|
const block = `
|
|
20042
20077
|
|
|
@@ -20076,7 +20111,7 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20076
20111
|
for (const categoryDir of RECALL_FALLBACK_DIRS) {
|
|
20077
20112
|
if (memoryRootReal === null) break;
|
|
20078
20113
|
for (const date of datesToScan) {
|
|
20079
|
-
const dateDir =
|
|
20114
|
+
const dateDir = path20.join(storage.dir, categoryDir, date);
|
|
20080
20115
|
try {
|
|
20081
20116
|
const dirStat = await lstat2(dateDir);
|
|
20082
20117
|
if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
|
|
@@ -20085,7 +20120,7 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20085
20120
|
for (const entry of entries) {
|
|
20086
20121
|
if (entry.isSymbolicLink()) continue;
|
|
20087
20122
|
if (!entry.name.endsWith(".md")) continue;
|
|
20088
|
-
const fullPath =
|
|
20123
|
+
const fullPath = path20.join(dateDir, entry.name);
|
|
20089
20124
|
try {
|
|
20090
20125
|
assertPathInsideRoot(memoryRootReal, await realpath2(fullPath), fullPath);
|
|
20091
20126
|
const memory = await storage.readMemoryByPath(fullPath);
|
|
@@ -20107,13 +20142,13 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20107
20142
|
return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
|
|
20108
20143
|
});
|
|
20109
20144
|
const hourlySummaries = [];
|
|
20110
|
-
const hourlyBaseDir =
|
|
20145
|
+
const hourlyBaseDir = path20.join(storage.dir, "summaries", "hourly");
|
|
20111
20146
|
try {
|
|
20112
20147
|
const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
|
|
20113
20148
|
for (const sk of sessionKeys) {
|
|
20114
20149
|
if (!sk.isDirectory()) continue;
|
|
20115
20150
|
for (const date of datesToScan) {
|
|
20116
|
-
const summaryFile =
|
|
20151
|
+
const summaryFile = path20.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
20117
20152
|
try {
|
|
20118
20153
|
const raw = await readFile8(summaryFile, "utf-8");
|
|
20119
20154
|
const filtered = filterHourlySummaryMarkdownForLocalDay(
|
|
@@ -20590,18 +20625,18 @@ ${reflectionsContent.trim()}
|
|
|
20590
20625
|
// src/orchestration/namespace-read-fanout.ts
|
|
20591
20626
|
import { existsSync, readFileSync } from "fs";
|
|
20592
20627
|
import { stat as stat3 } from "fs/promises";
|
|
20593
|
-
import
|
|
20628
|
+
import path22 from "path";
|
|
20594
20629
|
|
|
20595
20630
|
// src/orchestration/orchestrator-namespace-scope.ts
|
|
20596
|
-
import
|
|
20631
|
+
import path21 from "path";
|
|
20597
20632
|
function computeSemanticDedupScope(targetStorage, config) {
|
|
20598
20633
|
if (!resolveNamespaceCapabilities(config).namespaces) return {};
|
|
20599
|
-
const memoryDir =
|
|
20600
|
-
const storageDir =
|
|
20634
|
+
const memoryDir = path21.resolve(config.memoryDir);
|
|
20635
|
+
const storageDir = path21.resolve(targetStorage.dir);
|
|
20601
20636
|
if (storageDir === memoryDir) {
|
|
20602
20637
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
20603
20638
|
}
|
|
20604
|
-
let rel =
|
|
20639
|
+
let rel = path21.relative(memoryDir, storageDir);
|
|
20605
20640
|
if (!rel || rel.startsWith("..")) {
|
|
20606
20641
|
log.debug(
|
|
20607
20642
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -20654,7 +20689,7 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20654
20689
|
loadNamespaceStorageDirHintsFromCatalog() {
|
|
20655
20690
|
if (this.deps.namespaceStorageDirHintsLoaded || !this.deps.namespaceCatalog.enabled) return;
|
|
20656
20691
|
this.deps.namespaceStorageDirHintsLoaded = true;
|
|
20657
|
-
const catalogPath =
|
|
20692
|
+
const catalogPath = path22.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
|
|
20658
20693
|
if (!existsSync(catalogPath)) return;
|
|
20659
20694
|
let body;
|
|
20660
20695
|
try {
|
|
@@ -20691,7 +20726,7 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20691
20726
|
if (!this.deps.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
|
|
20692
20727
|
continue;
|
|
20693
20728
|
}
|
|
20694
|
-
const resolvedStorageDir =
|
|
20729
|
+
const resolvedStorageDir = path22.resolve(record.storageDir);
|
|
20695
20730
|
const current = preferredByStorageDir.get(resolvedStorageDir);
|
|
20696
20731
|
preferredByStorageDir.set(
|
|
20697
20732
|
resolvedStorageDir,
|
|
@@ -20876,12 +20911,12 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20876
20911
|
}
|
|
20877
20912
|
async resolveStateDirForNamespace(namespace) {
|
|
20878
20913
|
if (!resolveNamespaceCapabilities(this.deps.config).namespaces) {
|
|
20879
|
-
return
|
|
20914
|
+
return path22.join(this.deps.config.memoryDir, "state");
|
|
20880
20915
|
}
|
|
20881
20916
|
if (namespace !== this.deps.config.defaultNamespace) {
|
|
20882
|
-
return
|
|
20917
|
+
return path22.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
|
|
20883
20918
|
}
|
|
20884
|
-
const candidate =
|
|
20919
|
+
const candidate = path22.join(
|
|
20885
20920
|
this.deps.config.memoryDir,
|
|
20886
20921
|
"namespaces",
|
|
20887
20922
|
this.deps.config.defaultNamespace
|
|
@@ -20889,11 +20924,11 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20889
20924
|
try {
|
|
20890
20925
|
const candidateStat = await stat3(candidate);
|
|
20891
20926
|
if (candidateStat.isDirectory()) {
|
|
20892
|
-
return
|
|
20927
|
+
return path22.join(candidate, "state");
|
|
20893
20928
|
}
|
|
20894
20929
|
} catch {
|
|
20895
20930
|
}
|
|
20896
|
-
return
|
|
20931
|
+
return path22.join(this.deps.config.memoryDir, "state");
|
|
20897
20932
|
}
|
|
20898
20933
|
namespaceFromPath(p) {
|
|
20899
20934
|
if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return this.deps.config.defaultNamespace;
|
|
@@ -21348,7 +21383,7 @@ var Orchestrator = class {
|
|
|
21348
21383
|
if (this.destroyed) throw new Error("orchestrator has been destroyed");
|
|
21349
21384
|
if (!this._dependencyPropagationDelivery) {
|
|
21350
21385
|
this._dependencyPropagationDelivery = new DependencyPropagationDelivery({
|
|
21351
|
-
queueRoot:
|
|
21386
|
+
queueRoot: path23.join(this.config.memoryDir, "state", "dependency-propagation"),
|
|
21352
21387
|
config: this.config,
|
|
21353
21388
|
extraction: this.extraction,
|
|
21354
21389
|
getStorage: (namespace) => this.getStorage(namespace),
|
|
@@ -21703,7 +21738,7 @@ var Orchestrator = class {
|
|
|
21703
21738
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
21704
21739
|
if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
|
|
21705
21740
|
if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
|
|
21706
|
-
const resolvedStorageDir =
|
|
21741
|
+
const resolvedStorageDir = path23.resolve(storageDir);
|
|
21707
21742
|
let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
|
|
21708
21743
|
if (!hints) {
|
|
21709
21744
|
hints = /* @__PURE__ */ new Set();
|
|
@@ -21714,21 +21749,21 @@ var Orchestrator = class {
|
|
|
21714
21749
|
storageDirMatchesNamespaceHint(namespace, storageDir) {
|
|
21715
21750
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
21716
21751
|
if (!ns) return false;
|
|
21717
|
-
const resolvedStorageDir =
|
|
21718
|
-
const resolvedMemoryDir =
|
|
21752
|
+
const resolvedStorageDir = path23.resolve(storageDir);
|
|
21753
|
+
const resolvedMemoryDir = path23.resolve(this.config.memoryDir);
|
|
21719
21754
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
21720
21755
|
if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
|
|
21721
|
-
const resolvedNamespacesDir =
|
|
21756
|
+
const resolvedNamespacesDir = path23.join(resolvedMemoryDir, "namespaces");
|
|
21722
21757
|
if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
|
|
21723
|
-
const rawRoot =
|
|
21724
|
-
const tokenRoot =
|
|
21758
|
+
const rawRoot = path23.resolve(resolvedNamespacesDir, ns);
|
|
21759
|
+
const tokenRoot = path23.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
|
|
21725
21760
|
return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
|
|
21726
21761
|
}
|
|
21727
21762
|
namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
|
|
21728
|
-
if (resolvedStorageDir ===
|
|
21763
|
+
if (resolvedStorageDir === path23.resolve(this.config.memoryDir)) {
|
|
21729
21764
|
return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
|
|
21730
21765
|
}
|
|
21731
|
-
const leaf =
|
|
21766
|
+
const leaf = path23.basename(resolvedStorageDir);
|
|
21732
21767
|
const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
|
|
21733
21768
|
if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
|
|
21734
21769
|
if (record.namespace === leaf) return 1;
|
|
@@ -21869,7 +21904,7 @@ var Orchestrator = class {
|
|
|
21869
21904
|
StorageManager.setOkfConformanceDefault(config.memoryDir, config.okf?.conformanceEnabled);
|
|
21870
21905
|
this.profiler = new ProfilingCollector({
|
|
21871
21906
|
enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
|
|
21872
|
-
storageDir: config.profilingStorageDir ||
|
|
21907
|
+
storageDir: config.profilingStorageDir || path23.join(config.memoryDir, "profiling"),
|
|
21873
21908
|
maxTraces: config.profilingMaxTraces
|
|
21874
21909
|
});
|
|
21875
21910
|
this.namespaceCatalog = new NamespaceCatalog(config);
|
|
@@ -21956,7 +21991,7 @@ var Orchestrator = class {
|
|
|
21956
21991
|
this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
|
|
21957
21992
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
21958
21993
|
this.transcript = new TranscriptManager(config);
|
|
21959
|
-
this.conversationIndexDir =
|
|
21994
|
+
this.conversationIndexDir = path23.join(
|
|
21960
21995
|
config.memoryDir,
|
|
21961
21996
|
"conversation-index",
|
|
21962
21997
|
"chunks"
|
|
@@ -22107,7 +22142,7 @@ var Orchestrator = class {
|
|
|
22107
22142
|
getHandleHistory: () => this.handleHistory
|
|
22108
22143
|
});
|
|
22109
22144
|
this.threading = new ThreadingManager(
|
|
22110
|
-
|
|
22145
|
+
path23.join(config.memoryDir, "threads"),
|
|
22111
22146
|
config.threadingGapMinutes
|
|
22112
22147
|
);
|
|
22113
22148
|
const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
|
|
@@ -24275,8 +24310,8 @@ var DEFAULT_MAX_BINARY_SIZE_BYTES = 50 * 1024 * 1024;
|
|
|
24275
24310
|
var DEFAULT_GRACE_PERIOD_DAYS = 7;
|
|
24276
24311
|
|
|
24277
24312
|
// src/binary-lifecycle/backend.ts
|
|
24278
|
-
import
|
|
24279
|
-
import
|
|
24313
|
+
import fsp2 from "fs/promises";
|
|
24314
|
+
import path24 from "path";
|
|
24280
24315
|
var FilesystemBackend = class {
|
|
24281
24316
|
type = "filesystem";
|
|
24282
24317
|
basePath;
|
|
@@ -24284,30 +24319,30 @@ var FilesystemBackend = class {
|
|
|
24284
24319
|
if (!basePath || basePath.trim().length === 0) {
|
|
24285
24320
|
throw new Error("FilesystemBackend requires a non-empty basePath");
|
|
24286
24321
|
}
|
|
24287
|
-
this.basePath =
|
|
24322
|
+
this.basePath = path24.resolve(basePath);
|
|
24288
24323
|
}
|
|
24289
24324
|
resolveRemotePath(remotePath) {
|
|
24290
|
-
const resolved =
|
|
24291
|
-
const relative =
|
|
24292
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
24325
|
+
const resolved = path24.isAbsolute(remotePath) ? path24.resolve(remotePath) : path24.resolve(this.basePath, remotePath);
|
|
24326
|
+
const relative = path24.relative(this.basePath, resolved);
|
|
24327
|
+
if (relative === ".." || relative.startsWith(`..${path24.sep}`) || path24.isAbsolute(relative)) {
|
|
24293
24328
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24294
24329
|
}
|
|
24295
24330
|
return resolved;
|
|
24296
24331
|
}
|
|
24297
24332
|
isInsideBase(candidate, realBase) {
|
|
24298
|
-
const relative =
|
|
24299
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
24333
|
+
const relative = path24.relative(realBase, candidate);
|
|
24334
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path24.sep}`) && !path24.isAbsolute(relative);
|
|
24300
24335
|
}
|
|
24301
24336
|
async realBasePathIfExists() {
|
|
24302
24337
|
try {
|
|
24303
|
-
const stat5 = await
|
|
24338
|
+
const stat5 = await fsp2.lstat(this.basePath);
|
|
24304
24339
|
if (stat5.isSymbolicLink()) {
|
|
24305
24340
|
throw new Error(`FilesystemBackend basePath must not be a symlink: ${this.basePath}`);
|
|
24306
24341
|
}
|
|
24307
24342
|
if (!stat5.isDirectory()) {
|
|
24308
24343
|
throw new Error(`FilesystemBackend basePath must be a directory: ${this.basePath}`);
|
|
24309
24344
|
}
|
|
24310
|
-
return await
|
|
24345
|
+
return await fsp2.realpath(this.basePath);
|
|
24311
24346
|
} catch (err) {
|
|
24312
24347
|
if (err.code === "ENOENT") {
|
|
24313
24348
|
return null;
|
|
@@ -24316,7 +24351,7 @@ var FilesystemBackend = class {
|
|
|
24316
24351
|
}
|
|
24317
24352
|
}
|
|
24318
24353
|
async ensureBaseDirectory() {
|
|
24319
|
-
await
|
|
24354
|
+
await fsp2.mkdir(this.basePath, { recursive: true });
|
|
24320
24355
|
const realBase = await this.realBasePathIfExists();
|
|
24321
24356
|
if (realBase === null) {
|
|
24322
24357
|
throw new Error(`FilesystemBackend failed to create basePath: ${this.basePath}`);
|
|
@@ -24325,15 +24360,15 @@ var FilesystemBackend = class {
|
|
|
24325
24360
|
}
|
|
24326
24361
|
async ensureSafeParentDirectory(dest) {
|
|
24327
24362
|
const realBase = await this.ensureBaseDirectory();
|
|
24328
|
-
const destDir =
|
|
24329
|
-
const relativeDir =
|
|
24330
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
24363
|
+
const destDir = path24.dirname(dest);
|
|
24364
|
+
const relativeDir = path24.relative(this.basePath, destDir);
|
|
24365
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path24.sep);
|
|
24331
24366
|
let current = this.basePath;
|
|
24332
24367
|
for (const segment of segments) {
|
|
24333
24368
|
if (segment === "." || segment === "") continue;
|
|
24334
|
-
current =
|
|
24369
|
+
current = path24.join(current, segment);
|
|
24335
24370
|
try {
|
|
24336
|
-
const stat5 = await
|
|
24371
|
+
const stat5 = await fsp2.lstat(current);
|
|
24337
24372
|
if (stat5.isSymbolicLink()) {
|
|
24338
24373
|
throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);
|
|
24339
24374
|
}
|
|
@@ -24344,10 +24379,10 @@ var FilesystemBackend = class {
|
|
|
24344
24379
|
if (err.code !== "ENOENT") {
|
|
24345
24380
|
throw err;
|
|
24346
24381
|
}
|
|
24347
|
-
await
|
|
24382
|
+
await fsp2.mkdir(current);
|
|
24348
24383
|
}
|
|
24349
24384
|
}
|
|
24350
|
-
const realParent = await
|
|
24385
|
+
const realParent = await fsp2.realpath(destDir);
|
|
24351
24386
|
if (!this.isInsideBase(realParent, realBase)) {
|
|
24352
24387
|
throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${dest}`);
|
|
24353
24388
|
}
|
|
@@ -24359,16 +24394,16 @@ var FilesystemBackend = class {
|
|
|
24359
24394
|
if (realBase === null) {
|
|
24360
24395
|
return null;
|
|
24361
24396
|
}
|
|
24362
|
-
const destDir =
|
|
24363
|
-
const relativeDir =
|
|
24364
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
24397
|
+
const destDir = path24.dirname(dest);
|
|
24398
|
+
const relativeDir = path24.relative(this.basePath, destDir);
|
|
24399
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path24.sep);
|
|
24365
24400
|
let current = this.basePath;
|
|
24366
24401
|
for (const segment of segments) {
|
|
24367
24402
|
if (segment === "." || segment === "") continue;
|
|
24368
|
-
current =
|
|
24403
|
+
current = path24.join(current, segment);
|
|
24369
24404
|
let stat5;
|
|
24370
24405
|
try {
|
|
24371
|
-
stat5 = await
|
|
24406
|
+
stat5 = await fsp2.lstat(current);
|
|
24372
24407
|
} catch (err) {
|
|
24373
24408
|
if (err.code === "ENOENT") {
|
|
24374
24409
|
return null;
|
|
@@ -24382,7 +24417,7 @@ var FilesystemBackend = class {
|
|
|
24382
24417
|
return null;
|
|
24383
24418
|
}
|
|
24384
24419
|
}
|
|
24385
|
-
const realParent = await
|
|
24420
|
+
const realParent = await fsp2.realpath(destDir).catch((err) => {
|
|
24386
24421
|
if (isErrnoCode(err, "ENOENT")) return null;
|
|
24387
24422
|
throw err;
|
|
24388
24423
|
});
|
|
@@ -24393,7 +24428,7 @@ var FilesystemBackend = class {
|
|
|
24393
24428
|
throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24394
24429
|
}
|
|
24395
24430
|
try {
|
|
24396
|
-
const stat5 = await
|
|
24431
|
+
const stat5 = await fsp2.lstat(dest);
|
|
24397
24432
|
if (stat5.isSymbolicLink()) {
|
|
24398
24433
|
throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);
|
|
24399
24434
|
}
|
|
@@ -24406,20 +24441,20 @@ var FilesystemBackend = class {
|
|
|
24406
24441
|
}
|
|
24407
24442
|
throw err;
|
|
24408
24443
|
}
|
|
24409
|
-
const realDest = await
|
|
24444
|
+
const realDest = await fsp2.realpath(dest);
|
|
24410
24445
|
if (!this.isInsideBase(realDest, realBase)) {
|
|
24411
24446
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24412
24447
|
}
|
|
24413
24448
|
return dest;
|
|
24414
24449
|
}
|
|
24415
24450
|
async upload(localPath, remotePath) {
|
|
24416
|
-
if (
|
|
24451
|
+
if (path24.isAbsolute(remotePath)) {
|
|
24417
24452
|
throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);
|
|
24418
24453
|
}
|
|
24419
24454
|
const dest = this.resolveRemotePath(remotePath);
|
|
24420
24455
|
const realBase = await this.ensureSafeParentDirectory(dest);
|
|
24421
24456
|
try {
|
|
24422
|
-
const stat5 = await
|
|
24457
|
+
const stat5 = await fsp2.lstat(dest);
|
|
24423
24458
|
if (stat5.isSymbolicLink()) {
|
|
24424
24459
|
throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);
|
|
24425
24460
|
}
|
|
@@ -24428,8 +24463,8 @@ var FilesystemBackend = class {
|
|
|
24428
24463
|
throw err;
|
|
24429
24464
|
}
|
|
24430
24465
|
}
|
|
24431
|
-
await
|
|
24432
|
-
const realDest = await
|
|
24466
|
+
await fsp2.copyFile(localPath, dest);
|
|
24467
|
+
const realDest = await fsp2.realpath(dest);
|
|
24433
24468
|
if (!this.isInsideBase(realDest, realBase)) {
|
|
24434
24469
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24435
24470
|
}
|
|
@@ -24445,7 +24480,7 @@ var FilesystemBackend = class {
|
|
|
24445
24480
|
return;
|
|
24446
24481
|
}
|
|
24447
24482
|
try {
|
|
24448
|
-
await
|
|
24483
|
+
await fsp2.unlink(dest);
|
|
24449
24484
|
} catch (err) {
|
|
24450
24485
|
if (err.code !== "ENOENT") throw err;
|
|
24451
24486
|
}
|
|
@@ -24485,8 +24520,8 @@ function createBackend(cfg) {
|
|
|
24485
24520
|
}
|
|
24486
24521
|
|
|
24487
24522
|
// src/binary-lifecycle/scanner.ts
|
|
24488
|
-
import
|
|
24489
|
-
import
|
|
24523
|
+
import fsp3 from "fs/promises";
|
|
24524
|
+
import path25 from "path";
|
|
24490
24525
|
import crypto from "crypto";
|
|
24491
24526
|
function matchesPatterns(filename, patterns) {
|
|
24492
24527
|
const lower = filename.toLowerCase();
|
|
@@ -24506,13 +24541,13 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24506
24541
|
async function walk(dir) {
|
|
24507
24542
|
let entries;
|
|
24508
24543
|
try {
|
|
24509
|
-
entries = await
|
|
24544
|
+
entries = await fsp3.readdir(dir, { withFileTypes: true });
|
|
24510
24545
|
} catch {
|
|
24511
24546
|
return;
|
|
24512
24547
|
}
|
|
24513
24548
|
for (const entry of entries) {
|
|
24514
|
-
const fullPath =
|
|
24515
|
-
const relativePath =
|
|
24549
|
+
const fullPath = path25.join(dir, entry.name);
|
|
24550
|
+
const relativePath = path25.relative(memoryDir, fullPath).split(path25.sep).join("/");
|
|
24516
24551
|
if (entry.isDirectory()) {
|
|
24517
24552
|
if (entry.name === ".binary-lifecycle") continue;
|
|
24518
24553
|
await walk(fullPath);
|
|
@@ -24521,7 +24556,7 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24521
24556
|
if (!entry.isFile()) continue;
|
|
24522
24557
|
if (!matchesPatterns(entry.name, config.scanPatterns)) continue;
|
|
24523
24558
|
try {
|
|
24524
|
-
const stat5 = await
|
|
24559
|
+
const stat5 = await fsp3.stat(fullPath);
|
|
24525
24560
|
if (stat5.size > config.maxBinarySizeBytes) continue;
|
|
24526
24561
|
if (stat5.size === 0) continue;
|
|
24527
24562
|
const existing = tracked.get(relativePath);
|
|
@@ -24546,27 +24581,27 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24546
24581
|
return results;
|
|
24547
24582
|
}
|
|
24548
24583
|
async function hashFile(filePath) {
|
|
24549
|
-
const content = await
|
|
24584
|
+
const content = await fsp3.readFile(filePath);
|
|
24550
24585
|
return crypto.createHash("sha256").update(content).digest("hex");
|
|
24551
24586
|
}
|
|
24552
24587
|
|
|
24553
24588
|
// src/binary-lifecycle/manifest.ts
|
|
24554
|
-
import
|
|
24555
|
-
import
|
|
24589
|
+
import fsp4 from "fs/promises";
|
|
24590
|
+
import path26 from "path";
|
|
24556
24591
|
import crypto2 from "crypto";
|
|
24557
24592
|
var MANIFEST_DIR = ".binary-lifecycle";
|
|
24558
24593
|
var MANIFEST_FILE = "manifest.json";
|
|
24559
24594
|
function manifestDir(memoryDir) {
|
|
24560
|
-
return
|
|
24595
|
+
return path26.join(memoryDir, MANIFEST_DIR);
|
|
24561
24596
|
}
|
|
24562
24597
|
function manifestPath(memoryDir) {
|
|
24563
|
-
return
|
|
24598
|
+
return path26.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
|
|
24564
24599
|
}
|
|
24565
24600
|
async function readManifest(memoryDir) {
|
|
24566
24601
|
const filePath = manifestPath(memoryDir);
|
|
24567
24602
|
let raw;
|
|
24568
24603
|
try {
|
|
24569
|
-
raw = await
|
|
24604
|
+
raw = await fsp4.readFile(filePath, "utf-8");
|
|
24570
24605
|
} catch (err) {
|
|
24571
24606
|
if (err.code === "ENOENT") {
|
|
24572
24607
|
return emptyManifest();
|
|
@@ -24590,17 +24625,17 @@ async function readManifest(memoryDir) {
|
|
|
24590
24625
|
}
|
|
24591
24626
|
async function writeManifest(memoryDir, manifest) {
|
|
24592
24627
|
const dir = manifestDir(memoryDir);
|
|
24593
|
-
await
|
|
24628
|
+
await fsp4.mkdir(dir, { recursive: true });
|
|
24594
24629
|
const dest = manifestPath(memoryDir);
|
|
24595
24630
|
const tmpSuffix = crypto2.randomBytes(8).toString("hex");
|
|
24596
24631
|
const tmpPath = `${dest}.${tmpSuffix}.tmp`;
|
|
24597
24632
|
const content = JSON.stringify(manifest, null, 2) + "\n";
|
|
24598
|
-
await
|
|
24633
|
+
await fsp4.writeFile(tmpPath, content, "utf-8");
|
|
24599
24634
|
try {
|
|
24600
|
-
await
|
|
24635
|
+
await fsp4.rename(tmpPath, dest);
|
|
24601
24636
|
} catch (renameErr) {
|
|
24602
24637
|
try {
|
|
24603
|
-
await
|
|
24638
|
+
await fsp4.unlink(tmpPath);
|
|
24604
24639
|
} catch {
|
|
24605
24640
|
}
|
|
24606
24641
|
throw renameErr;
|
|
@@ -24611,18 +24646,18 @@ function emptyManifest() {
|
|
|
24611
24646
|
}
|
|
24612
24647
|
|
|
24613
24648
|
// src/binary-lifecycle/pipeline.ts
|
|
24614
|
-
import
|
|
24615
|
-
import
|
|
24649
|
+
import fsp5 from "fs/promises";
|
|
24650
|
+
import path27 from "path";
|
|
24616
24651
|
import crypto3 from "crypto";
|
|
24617
24652
|
var historicalIdCache = new HistoricalEntityCanonicalIdCache();
|
|
24618
24653
|
function isRecallCorpusMarkdown(mdPath, memoryDir) {
|
|
24619
|
-
const rel =
|
|
24620
|
-
if (rel.startsWith("..") ||
|
|
24621
|
-
const top = rel.split(
|
|
24654
|
+
const rel = path27.relative(memoryDir, mdPath);
|
|
24655
|
+
if (rel.startsWith("..") || path27.isAbsolute(rel)) return false;
|
|
24656
|
+
const top = rel.split(path27.sep)[0];
|
|
24622
24657
|
return RECALL_FALLBACK_DIRS.includes(top);
|
|
24623
24658
|
}
|
|
24624
24659
|
async function hashFile2(filePath) {
|
|
24625
|
-
const content = await
|
|
24660
|
+
const content = await fsp5.readFile(filePath);
|
|
24626
24661
|
return crypto3.createHash("sha256").update(content).digest("hex");
|
|
24627
24662
|
}
|
|
24628
24663
|
function guessMimeType(ext) {
|
|
@@ -24642,13 +24677,13 @@ function escapeRegex(s) {
|
|
|
24642
24677
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
24643
24678
|
}
|
|
24644
24679
|
function resolveManifestAssetPath(memoryDir, originalPath) {
|
|
24645
|
-
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") ||
|
|
24680
|
+
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path27.isAbsolute(originalPath) || path27.win32.isAbsolute(originalPath)) {
|
|
24646
24681
|
return null;
|
|
24647
24682
|
}
|
|
24648
|
-
const memoryRoot =
|
|
24649
|
-
const fullPath =
|
|
24650
|
-
const relative =
|
|
24651
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
24683
|
+
const memoryRoot = path27.resolve(memoryDir);
|
|
24684
|
+
const fullPath = path27.resolve(memoryRoot, originalPath);
|
|
24685
|
+
const relative = path27.relative(memoryRoot, fullPath);
|
|
24686
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path27.sep}`) || path27.isAbsolute(relative)) {
|
|
24652
24687
|
return null;
|
|
24653
24688
|
}
|
|
24654
24689
|
return fullPath;
|
|
@@ -24659,7 +24694,7 @@ function validateBinaryLifecycleConfig(config) {
|
|
|
24659
24694
|
}
|
|
24660
24695
|
}
|
|
24661
24696
|
function remotePathForAsset(backend, relPath) {
|
|
24662
|
-
const normalized = relPath.split(
|
|
24697
|
+
const normalized = relPath.split(path27.sep).join("/");
|
|
24663
24698
|
if (backend.type === "filesystem") {
|
|
24664
24699
|
return `.binary-lifecycle/mirrors/${normalized}`;
|
|
24665
24700
|
}
|
|
@@ -24672,11 +24707,11 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
|
|
|
24672
24707
|
let mirrored = 0;
|
|
24673
24708
|
const errors = [];
|
|
24674
24709
|
for (const relPath of newPaths) {
|
|
24675
|
-
const fullPath =
|
|
24710
|
+
const fullPath = path27.join(memoryDir, relPath);
|
|
24676
24711
|
try {
|
|
24677
|
-
const stat5 = await
|
|
24712
|
+
const stat5 = await fsp5.stat(fullPath);
|
|
24678
24713
|
const contentHash = await hashFile2(fullPath);
|
|
24679
|
-
const ext =
|
|
24714
|
+
const ext = path27.extname(relPath);
|
|
24680
24715
|
const mimeType = guessMimeType(ext);
|
|
24681
24716
|
const remotePath = remotePathForAsset(backend, relPath);
|
|
24682
24717
|
let backendLocation = remotePath;
|
|
@@ -24827,7 +24862,7 @@ async function stageRedirect(memoryDir, assets, log2, dryRun, readMarkdownFile,
|
|
|
24827
24862
|
for (const update of updates) {
|
|
24828
24863
|
try {
|
|
24829
24864
|
await withRawEntityPageMutation(memoryDir, update.mdPath, async () => {
|
|
24830
|
-
const stateDir =
|
|
24865
|
+
const stateDir = path27.join(memoryDir, "state");
|
|
24831
24866
|
const kind = classifyEntityRefWritePath(memoryDir, update.mdPath);
|
|
24832
24867
|
if (kind === "memory") {
|
|
24833
24868
|
const idsAtWrite = historicalIdCache.get(stateDir);
|
|
@@ -24920,10 +24955,10 @@ async function countRemainingLocalReferences(memoryDir, asset, assetAbsolute, md
|
|
|
24920
24955
|
return { remaining, errors };
|
|
24921
24956
|
}
|
|
24922
24957
|
function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
24923
|
-
const mdDir =
|
|
24958
|
+
const mdDir = path27.dirname(mdPath);
|
|
24924
24959
|
const candidates = /* @__PURE__ */ new Set();
|
|
24925
24960
|
const addCandidate = (candidate) => {
|
|
24926
|
-
const normalized = candidate.split(
|
|
24961
|
+
const normalized = candidate.split(path27.sep).join("/");
|
|
24927
24962
|
if (normalized.length === 0) return;
|
|
24928
24963
|
candidates.add(normalized);
|
|
24929
24964
|
const isParentTraversal = normalized === ".." || normalized.startsWith("../");
|
|
@@ -24931,10 +24966,10 @@ function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
|
24931
24966
|
candidates.add(`./${normalized}`);
|
|
24932
24967
|
}
|
|
24933
24968
|
};
|
|
24934
|
-
addCandidate(
|
|
24935
|
-
const originalPath = asset.originalPath.split(
|
|
24936
|
-
const originalAsFileRelative =
|
|
24937
|
-
if (
|
|
24969
|
+
addCandidate(path27.relative(mdDir, assetAbsolute));
|
|
24970
|
+
const originalPath = asset.originalPath.split(path27.sep).join("/");
|
|
24971
|
+
const originalAsFileRelative = path27.resolve(mdDir, ...originalPath.split("/"));
|
|
24972
|
+
if (path27.resolve(originalAsFileRelative) === path27.resolve(assetAbsolute)) {
|
|
24938
24973
|
addCandidate(originalPath);
|
|
24939
24974
|
}
|
|
24940
24975
|
addCandidate(`/${originalPath}`);
|
|
@@ -24998,7 +25033,7 @@ async function stageClean(memoryDir, assets, backend, gracePeriodDays, log2, dry
|
|
|
24998
25033
|
continue;
|
|
24999
25034
|
}
|
|
25000
25035
|
if (!dryRun) {
|
|
25001
|
-
await
|
|
25036
|
+
await fsp5.unlink(fullPath);
|
|
25002
25037
|
asset.status = "cleaned";
|
|
25003
25038
|
asset.cleanedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25004
25039
|
}
|
|
@@ -25025,12 +25060,12 @@ async function findMarkdownFiles(dir) {
|
|
|
25025
25060
|
async function walk(current) {
|
|
25026
25061
|
let entries;
|
|
25027
25062
|
try {
|
|
25028
|
-
entries = await
|
|
25063
|
+
entries = await fsp5.readdir(current, { withFileTypes: true });
|
|
25029
25064
|
} catch {
|
|
25030
25065
|
return;
|
|
25031
25066
|
}
|
|
25032
25067
|
for (const entry of entries) {
|
|
25033
|
-
const full =
|
|
25068
|
+
const full = path27.join(current, entry.name);
|
|
25034
25069
|
if (entry.isDirectory()) {
|
|
25035
25070
|
if (entry.name === ".binary-lifecycle") continue;
|
|
25036
25071
|
await walk(full);
|
|
@@ -25072,8 +25107,8 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
|
|
|
25072
25107
|
manifest.assets,
|
|
25073
25108
|
log2,
|
|
25074
25109
|
dryRun,
|
|
25075
|
-
opts?.readMarkdownFile ?? ((filePath) =>
|
|
25076
|
-
opts?.writeMarkdownFile ?? ((filePath, content) =>
|
|
25110
|
+
opts?.readMarkdownFile ?? ((filePath) => fsp5.readFile(filePath, "utf-8")),
|
|
25111
|
+
opts?.writeMarkdownFile ?? ((filePath, content) => fsp5.writeFile(filePath, content, "utf-8"))
|
|
25077
25112
|
);
|
|
25078
25113
|
const cleanResult = await stageClean(
|
|
25079
25114
|
memoryDir,
|
|
@@ -25105,7 +25140,7 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
|
|
|
25105
25140
|
|
|
25106
25141
|
// src/projection/index.ts
|
|
25107
25142
|
import fs from "fs";
|
|
25108
|
-
import
|
|
25143
|
+
import path28 from "path";
|
|
25109
25144
|
var VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);
|
|
25110
25145
|
async function generateContextTree(options) {
|
|
25111
25146
|
const startTime = Date.now();
|
|
@@ -25120,8 +25155,8 @@ async function generateContextTree(options) {
|
|
|
25120
25155
|
let nodesGenerated = 0;
|
|
25121
25156
|
let nodesSkipped = 0;
|
|
25122
25157
|
const categoryCounts = {};
|
|
25123
|
-
const resolvedMemoryDir =
|
|
25124
|
-
const resolvedOutputDir =
|
|
25158
|
+
const resolvedMemoryDir = path28.resolve(memoryDir);
|
|
25159
|
+
const resolvedOutputDir = path28.resolve(outputDir);
|
|
25125
25160
|
const requestedCategories = validateProjectionCategories(filterCategories);
|
|
25126
25161
|
const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);
|
|
25127
25162
|
assertNotSymlink(resolvedOutputDir, "context tree outputDir");
|
|
@@ -25159,7 +25194,7 @@ async function generateContextTree(options) {
|
|
|
25159
25194
|
}
|
|
25160
25195
|
}
|
|
25161
25196
|
if (includeEntities) {
|
|
25162
|
-
const entitiesDir =
|
|
25197
|
+
const entitiesDir = path28.join(memoryDir, "entities");
|
|
25163
25198
|
if (fs.existsSync(entitiesDir)) {
|
|
25164
25199
|
assertSafeInputRoot(realMemoryDir, entitiesDir, "entities root");
|
|
25165
25200
|
categoryCounts["entity"] = 0;
|
|
@@ -25171,7 +25206,7 @@ async function generateContextTree(options) {
|
|
|
25171
25206
|
continue;
|
|
25172
25207
|
}
|
|
25173
25208
|
const content = fs.readFileSync(filePath, "utf8");
|
|
25174
|
-
const fileName =
|
|
25209
|
+
const fileName = path28.basename(filePath, ".md");
|
|
25175
25210
|
const node = projectEntityNode(fileName, content);
|
|
25176
25211
|
const outputPath = resolveContainedOutputPath(realOutputDir, "entities", `${fileName}.md`);
|
|
25177
25212
|
writeProjectedContent(realOutputDir, outputPath, node.content);
|
|
@@ -25183,7 +25218,7 @@ async function generateContextTree(options) {
|
|
|
25183
25218
|
}
|
|
25184
25219
|
const shouldIncludeQuestions = includeQuestions && (requestedCategories === void 0 || requestedCategories.includes("question"));
|
|
25185
25220
|
if (shouldIncludeQuestions) {
|
|
25186
|
-
const questionsDir =
|
|
25221
|
+
const questionsDir = path28.join(memoryDir, "questions");
|
|
25187
25222
|
if (fs.existsSync(questionsDir)) {
|
|
25188
25223
|
assertSafeInputRoot(realMemoryDir, questionsDir, "questions root");
|
|
25189
25224
|
categoryCounts["question"] = 0;
|
|
@@ -25224,8 +25259,8 @@ async function generateContextTree(options) {
|
|
|
25224
25259
|
};
|
|
25225
25260
|
}
|
|
25226
25261
|
function isPathInside(root, candidate) {
|
|
25227
|
-
const relative =
|
|
25228
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
25262
|
+
const relative = path28.relative(root, candidate);
|
|
25263
|
+
return relative === "" || !relative.startsWith("..") && !path28.isAbsolute(relative);
|
|
25229
25264
|
}
|
|
25230
25265
|
function assertNotSymlink(targetPath, label) {
|
|
25231
25266
|
try {
|
|
@@ -25262,12 +25297,12 @@ function assertSafeInputRoot(realMemoryDir, targetPath, label) {
|
|
|
25262
25297
|
}
|
|
25263
25298
|
function assertSafeOutputTarget(realOutputDir, outputPath) {
|
|
25264
25299
|
let current = realOutputDir;
|
|
25265
|
-
const relative =
|
|
25266
|
-
if (relative.startsWith("..") ||
|
|
25300
|
+
const relative = path28.relative(realOutputDir, outputPath);
|
|
25301
|
+
if (relative.startsWith("..") || path28.isAbsolute(relative)) {
|
|
25267
25302
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
25268
25303
|
}
|
|
25269
|
-
for (const segment of relative.split(
|
|
25270
|
-
current =
|
|
25304
|
+
for (const segment of relative.split(path28.sep).filter(Boolean)) {
|
|
25305
|
+
current = path28.join(current, segment);
|
|
25271
25306
|
try {
|
|
25272
25307
|
const stat5 = fs.lstatSync(current);
|
|
25273
25308
|
if (stat5.isSymbolicLink()) {
|
|
@@ -25297,17 +25332,17 @@ function validateProjectionCategories(categories) {
|
|
|
25297
25332
|
return validated;
|
|
25298
25333
|
}
|
|
25299
25334
|
function resolveContainedOutputPath(outputRoot, ...segments) {
|
|
25300
|
-
const resolved =
|
|
25301
|
-
const relative =
|
|
25302
|
-
if (relative === "" || !relative.startsWith("..") && !
|
|
25335
|
+
const resolved = path28.resolve(outputRoot, ...segments);
|
|
25336
|
+
const relative = path28.relative(outputRoot, resolved);
|
|
25337
|
+
if (relative === "" || !relative.startsWith("..") && !path28.isAbsolute(relative)) {
|
|
25303
25338
|
return resolved;
|
|
25304
25339
|
}
|
|
25305
25340
|
throw new Error(`context tree output path escapes outputDir: ${segments.join("/")}`);
|
|
25306
25341
|
}
|
|
25307
25342
|
function writeProjectedContent(realOutputDir, outputPath, generatedContent) {
|
|
25308
25343
|
assertSafeOutputTarget(realOutputDir, outputPath);
|
|
25309
|
-
fs.mkdirSync(
|
|
25310
|
-
const realParent = fs.realpathSync(
|
|
25344
|
+
fs.mkdirSync(path28.dirname(outputPath), { recursive: true });
|
|
25345
|
+
const realParent = fs.realpathSync(path28.dirname(outputPath));
|
|
25311
25346
|
if (!isPathInside(realOutputDir, realParent)) {
|
|
25312
25347
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
25313
25348
|
}
|
|
@@ -25346,7 +25381,7 @@ function walkR(dir, realMemoryDir) {
|
|
|
25346
25381
|
const results = [];
|
|
25347
25382
|
function walk(directory) {
|
|
25348
25383
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
25349
|
-
const fullPath =
|
|
25384
|
+
const fullPath = path28.join(directory, entry.name);
|
|
25350
25385
|
if (entry.isSymbolicLink()) {
|
|
25351
25386
|
throw new Error(`context tree input path contains symlink: ${fullPath}`);
|
|
25352
25387
|
}
|
|
@@ -25399,13 +25434,13 @@ function extractBody(content) {
|
|
|
25399
25434
|
}
|
|
25400
25435
|
function projectNode(filePath, category, fm, rawContent) {
|
|
25401
25436
|
const body = extractBody(rawContent);
|
|
25402
|
-
const fileName =
|
|
25403
|
-
const dateDir =
|
|
25437
|
+
const fileName = path28.basename(filePath, ".md");
|
|
25438
|
+
const dateDir = path28.basename(path28.dirname(filePath));
|
|
25404
25439
|
let relPath;
|
|
25405
25440
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateDir)) {
|
|
25406
|
-
relPath =
|
|
25441
|
+
relPath = path28.join(category, dateDir, `${fileName}.md`);
|
|
25407
25442
|
} else {
|
|
25408
|
-
relPath =
|
|
25443
|
+
relPath = path28.join(category, `${fileName}.md`);
|
|
25409
25444
|
}
|
|
25410
25445
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25411
25446
|
const md = `# ${fm.id}
|
|
@@ -25451,7 +25486,7 @@ function projectEntityNode(fileName, content) {
|
|
|
25451
25486
|
${content}
|
|
25452
25487
|
`;
|
|
25453
25488
|
return {
|
|
25454
|
-
path:
|
|
25489
|
+
path: path28.join("entities", `${fileName}.md`),
|
|
25455
25490
|
category: "entity",
|
|
25456
25491
|
title: fileName,
|
|
25457
25492
|
content: md,
|
|
@@ -25504,7 +25539,7 @@ function generateIndex(categoryCounts, outputDir) {
|
|
|
25504
25539
|
|
|
25505
25540
|
// src/onboarding/index.ts
|
|
25506
25541
|
import fs2 from "fs";
|
|
25507
|
-
import
|
|
25542
|
+
import path29 from "path";
|
|
25508
25543
|
var LANGUAGE_RULES = [
|
|
25509
25544
|
{
|
|
25510
25545
|
language: "TypeScript",
|
|
@@ -25606,7 +25641,7 @@ function onboard(options) {
|
|
|
25606
25641
|
maxDepth = 6,
|
|
25607
25642
|
excludeDirs = []
|
|
25608
25643
|
} = options;
|
|
25609
|
-
const directory =
|
|
25644
|
+
const directory = path29.resolve(options.directory ?? process.cwd());
|
|
25610
25645
|
let rootStat;
|
|
25611
25646
|
try {
|
|
25612
25647
|
rootStat = fs2.statSync(directory);
|
|
@@ -25648,7 +25683,7 @@ function walkDir(root, exclude, maxDepth) {
|
|
|
25648
25683
|
}
|
|
25649
25684
|
for (const entry of entries) {
|
|
25650
25685
|
if (exclude.has(entry.name)) continue;
|
|
25651
|
-
const fullPath =
|
|
25686
|
+
const fullPath = path29.join(dir, entry.name);
|
|
25652
25687
|
if (entry.isDirectory()) {
|
|
25653
25688
|
walk(fullPath, depth + 1);
|
|
25654
25689
|
} else if (entry.isFile()) {
|
|
@@ -25663,11 +25698,11 @@ function detectLanguages(files, root) {
|
|
|
25663
25698
|
const results = [];
|
|
25664
25699
|
const extCounts = /* @__PURE__ */ new Map();
|
|
25665
25700
|
for (const f of files) {
|
|
25666
|
-
const ext =
|
|
25701
|
+
const ext = path29.extname(f).toLowerCase();
|
|
25667
25702
|
if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
|
|
25668
25703
|
}
|
|
25669
25704
|
const rootFiles = new Set(
|
|
25670
|
-
files.filter((f) =>
|
|
25705
|
+
files.filter((f) => path29.dirname(f) === root).map((f) => path29.basename(f))
|
|
25671
25706
|
);
|
|
25672
25707
|
for (const rule of LANGUAGE_RULES) {
|
|
25673
25708
|
const evidence = [];
|
|
@@ -25711,7 +25746,7 @@ function detectLanguages(files, root) {
|
|
|
25711
25746
|
}
|
|
25712
25747
|
function detectShape(files, root) {
|
|
25713
25748
|
const rootFiles = new Set(
|
|
25714
|
-
files.filter((f) =>
|
|
25749
|
+
files.filter((f) => path29.dirname(f) === root).map((f) => path29.basename(f))
|
|
25715
25750
|
);
|
|
25716
25751
|
const rootDirs = /* @__PURE__ */ new Set();
|
|
25717
25752
|
try {
|
|
@@ -25722,7 +25757,7 @@ function detectShape(files, root) {
|
|
|
25722
25757
|
}
|
|
25723
25758
|
const evidence = [];
|
|
25724
25759
|
if (rootFiles.has("package.json")) {
|
|
25725
|
-
const pkg = readJsonSafe(
|
|
25760
|
+
const pkg = readJsonSafe(path29.join(root, "package.json"));
|
|
25726
25761
|
if (pkg?.workspaces) {
|
|
25727
25762
|
evidence.push("package.json has workspaces");
|
|
25728
25763
|
return { shape: "monorepo", evidence };
|
|
@@ -25736,13 +25771,13 @@ function detectShape(files, root) {
|
|
|
25736
25771
|
evidence.push("workspace manifest found");
|
|
25737
25772
|
return { shape: "workspace", evidence };
|
|
25738
25773
|
}
|
|
25739
|
-
const cargoToml = readTomlWorkspace(
|
|
25774
|
+
const cargoToml = readTomlWorkspace(path29.join(root, "Cargo.toml"));
|
|
25740
25775
|
if (cargoToml) {
|
|
25741
25776
|
evidence.push("Cargo.toml has workspace");
|
|
25742
25777
|
return { shape: "workspace", evidence };
|
|
25743
25778
|
}
|
|
25744
25779
|
if (rootFiles.has("package.json")) {
|
|
25745
|
-
const pkg = readJsonSafe(
|
|
25780
|
+
const pkg = readJsonSafe(path29.join(root, "package.json"));
|
|
25746
25781
|
if (pkg?.exports || pkg?.main) {
|
|
25747
25782
|
if (pkg?.bin) {
|
|
25748
25783
|
evidence.push("package.json has bin");
|
|
@@ -25776,8 +25811,8 @@ function discoverDocs(files, root) {
|
|
|
25776
25811
|
{ pattern: /^\.editorconfig$/i, kind: "config" }
|
|
25777
25812
|
];
|
|
25778
25813
|
for (const filePath of files) {
|
|
25779
|
-
const basename =
|
|
25780
|
-
const relPath =
|
|
25814
|
+
const basename = path29.basename(filePath).toLowerCase();
|
|
25815
|
+
const relPath = path29.relative(root, filePath);
|
|
25781
25816
|
let kind;
|
|
25782
25817
|
for (const { pattern, kind: k } of docPatterns) {
|
|
25783
25818
|
if (pattern.test(basename)) {
|
|
@@ -25789,7 +25824,7 @@ function discoverDocs(files, root) {
|
|
|
25789
25824
|
kind = "docs";
|
|
25790
25825
|
}
|
|
25791
25826
|
if (!kind && (basename.endsWith(".md") || basename.endsWith(".mdx"))) {
|
|
25792
|
-
if (
|
|
25827
|
+
if (path29.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
|
|
25793
25828
|
kind = "docs";
|
|
25794
25829
|
}
|
|
25795
25830
|
}
|
|
@@ -25810,7 +25845,7 @@ function discoverDocs(files, root) {
|
|
|
25810
25845
|
return docs;
|
|
25811
25846
|
}
|
|
25812
25847
|
function isUnderDocsDir(relPath) {
|
|
25813
|
-
const parts = relPath.split(
|
|
25848
|
+
const parts = relPath.split(path29.sep);
|
|
25814
25849
|
return parts[0] === "docs" || parts[0] === "doc" || parts[0] === "documentation";
|
|
25815
25850
|
}
|
|
25816
25851
|
function buildPlan(languages, shape, docs, _root) {
|
|
@@ -25854,7 +25889,7 @@ function readTomlWorkspace(filePath) {
|
|
|
25854
25889
|
|
|
25855
25890
|
// src/curation/index.ts
|
|
25856
25891
|
import fs3 from "fs";
|
|
25857
|
-
import
|
|
25892
|
+
import path30 from "path";
|
|
25858
25893
|
import crypto4 from "crypto";
|
|
25859
25894
|
async function curate(options) {
|
|
25860
25895
|
const startTime = Date.now();
|
|
@@ -25945,12 +25980,12 @@ function resolveTargets(targetPath) {
|
|
|
25945
25980
|
const extensions = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
25946
25981
|
function walk(dir) {
|
|
25947
25982
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
25948
|
-
const fullPath =
|
|
25983
|
+
const fullPath = path30.join(dir, entry.name);
|
|
25949
25984
|
if (entry.isDirectory()) {
|
|
25950
25985
|
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
25951
25986
|
walk(fullPath);
|
|
25952
25987
|
}
|
|
25953
|
-
} else if (extensions.has(
|
|
25988
|
+
} else if (extensions.has(path30.extname(entry.name).toLowerCase())) {
|
|
25954
25989
|
results.push(fullPath);
|
|
25955
25990
|
}
|
|
25956
25991
|
}
|
|
@@ -25959,12 +25994,12 @@ function resolveTargets(targetPath) {
|
|
|
25959
25994
|
return results;
|
|
25960
25995
|
}
|
|
25961
25996
|
function resolveProvenanceRoot(targetPath) {
|
|
25962
|
-
const resolvedTarget =
|
|
25997
|
+
const resolvedTarget = path30.resolve(targetPath);
|
|
25963
25998
|
const stat5 = fs3.statSync(resolvedTarget);
|
|
25964
|
-
return stat5.isFile() ?
|
|
25999
|
+
return stat5.isFile() ? path30.dirname(resolvedTarget) : resolvedTarget;
|
|
25965
26000
|
}
|
|
25966
26001
|
function extractStatements(content, filePath, projectRoot, source, sourceFileHash, categoryOverride, confidence, entityRef, tags) {
|
|
25967
|
-
const relativePath =
|
|
26002
|
+
const relativePath = path30.relative(projectRoot, path30.resolve(filePath)) || path30.basename(filePath);
|
|
25968
26003
|
const statements = [];
|
|
25969
26004
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25970
26005
|
const paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p.length > 20 && p.length < 2e3);
|
|
@@ -26058,7 +26093,7 @@ function loadExistingMemories(memoryDir) {
|
|
|
26058
26093
|
if (!fs3.existsSync(memoryDir)) return result;
|
|
26059
26094
|
const dirs = ALL_CATEGORY_DIRS;
|
|
26060
26095
|
for (const dir of dirs) {
|
|
26061
|
-
const fullDir =
|
|
26096
|
+
const fullDir = path30.join(memoryDir, dir);
|
|
26062
26097
|
if (!fs3.existsSync(fullDir)) continue;
|
|
26063
26098
|
walkFiles(fullDir, (filePath) => {
|
|
26064
26099
|
const content = readFileSafe(filePath);
|
|
@@ -26081,11 +26116,11 @@ function writeStatement(stmt, memoryDir) {
|
|
|
26081
26116
|
const now = /* @__PURE__ */ new Date();
|
|
26082
26117
|
const dateDir = now.toISOString().split("T")[0];
|
|
26083
26118
|
const categoryDir = getCategoryDir(memoryDir, stmt.category);
|
|
26084
|
-
const dir =
|
|
26119
|
+
const dir = path30.join(categoryDir, dateDir);
|
|
26085
26120
|
fs3.mkdirSync(dir, { recursive: true });
|
|
26086
26121
|
const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;
|
|
26087
|
-
const filePath =
|
|
26088
|
-
const historicalIds = historicalIdCache2.get(
|
|
26122
|
+
const filePath = path30.join(dir, fileName);
|
|
26123
|
+
const historicalIds = historicalIdCache2.get(path30.join(memoryDir, "state"));
|
|
26089
26124
|
const rawBody = `${[
|
|
26090
26125
|
"---",
|
|
26091
26126
|
`id: ${stmt.id}`,
|
|
@@ -26108,7 +26143,7 @@ ${stmt.content}
|
|
|
26108
26143
|
fs3.writeFileSync(filePath, body);
|
|
26109
26144
|
try {
|
|
26110
26145
|
repairContentAfterJournalMoveSync({
|
|
26111
|
-
stateDir:
|
|
26146
|
+
stateDir: path30.join(memoryDir, "state"),
|
|
26112
26147
|
cache: historicalIdCache2,
|
|
26113
26148
|
idsAtWrite: historicalIds,
|
|
26114
26149
|
rawContent: rawBody,
|
|
@@ -26169,7 +26204,7 @@ function extractBody2(content) {
|
|
|
26169
26204
|
}
|
|
26170
26205
|
function walkFiles(dir, callback) {
|
|
26171
26206
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
26172
|
-
const fullPath =
|
|
26207
|
+
const fullPath = path30.join(dir, entry.name);
|
|
26173
26208
|
if (entry.isDirectory()) {
|
|
26174
26209
|
walkFiles(fullPath, callback);
|
|
26175
26210
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -26178,305 +26213,10 @@ function walkFiles(dir, callback) {
|
|
|
26178
26213
|
}
|
|
26179
26214
|
}
|
|
26180
26215
|
|
|
26181
|
-
// src/dedup/index.ts
|
|
26182
|
-
import crypto5 from "crypto";
|
|
26183
|
-
import fs4 from "fs";
|
|
26184
|
-
import path30 from "path";
|
|
26185
|
-
var DEFAULT_DEDUP_THRESHOLD = 0.85;
|
|
26186
|
-
var DEFAULT_MAX_LOAD = 1e4;
|
|
26187
|
-
function normalizeThreshold(value, defaultValue) {
|
|
26188
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1 ? value : defaultValue;
|
|
26189
|
-
}
|
|
26190
|
-
function normalizeMaxLoad(value, defaultValue) {
|
|
26191
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : defaultValue;
|
|
26192
|
-
}
|
|
26193
|
-
function findDuplicates(options) {
|
|
26194
|
-
const startTime = Date.now();
|
|
26195
|
-
const { memoryDir } = options;
|
|
26196
|
-
const threshold = normalizeThreshold(options.threshold, DEFAULT_DEDUP_THRESHOLD);
|
|
26197
|
-
const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);
|
|
26198
|
-
const memories = loadMemories(memoryDir, options.categories, maxLoad);
|
|
26199
|
-
const duplicates = [];
|
|
26200
|
-
for (let i = 0; i < memories.length; i++) {
|
|
26201
|
-
for (let j = i + 1; j < memories.length; j++) {
|
|
26202
|
-
const sim = computeSimilarity(memories[i].content, memories[j].content);
|
|
26203
|
-
if (sim >= threshold) {
|
|
26204
|
-
duplicates.push({
|
|
26205
|
-
left: memories[i],
|
|
26206
|
-
right: memories[j],
|
|
26207
|
-
similarity: sim,
|
|
26208
|
-
action: sim >= 0.98 ? "merge" : sim >= 0.9 ? "keep_right" : "keep_left"
|
|
26209
|
-
});
|
|
26210
|
-
}
|
|
26211
|
-
}
|
|
26212
|
-
}
|
|
26213
|
-
return {
|
|
26214
|
-
scanned: memories.length,
|
|
26215
|
-
duplicates,
|
|
26216
|
-
durationMs: Date.now() - startTime
|
|
26217
|
-
};
|
|
26218
|
-
}
|
|
26219
|
-
function findContradictions(options) {
|
|
26220
|
-
const startTime = Date.now();
|
|
26221
|
-
const { memoryDir } = options;
|
|
26222
|
-
const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);
|
|
26223
|
-
const memories = loadMemories(memoryDir, options.categories, maxLoad);
|
|
26224
|
-
const contradictions = [];
|
|
26225
|
-
for (let i = 0; i < memories.length; i++) {
|
|
26226
|
-
for (let j = i + 1; j < memories.length; j++) {
|
|
26227
|
-
const contra = detectContradiction(memories[i], memories[j]);
|
|
26228
|
-
if (contra) {
|
|
26229
|
-
contradictions.push(contra);
|
|
26230
|
-
}
|
|
26231
|
-
}
|
|
26232
|
-
}
|
|
26233
|
-
return {
|
|
26234
|
-
scanned: memories.length,
|
|
26235
|
-
contradictions,
|
|
26236
|
-
durationMs: Date.now() - startTime
|
|
26237
|
-
};
|
|
26238
|
-
}
|
|
26239
|
-
function computeSimilarity(a, b) {
|
|
26240
|
-
const normA = normalize(a);
|
|
26241
|
-
const normB = normalize(b);
|
|
26242
|
-
const punctuationBoundariesA = embeddedPunctuationSignature(a);
|
|
26243
|
-
const punctuationBoundariesB = embeddedPunctuationSignature(b);
|
|
26244
|
-
if (punctuationBoundariesA !== punctuationBoundariesB) return 0;
|
|
26245
|
-
if (normA === normB) return 1;
|
|
26246
|
-
if (hashContent2(normA) === hashContent2(normB)) return 0.99;
|
|
26247
|
-
if (normA.length > 50 && normB.length > 50) {
|
|
26248
|
-
if (normA.includes(normB.slice(0, 40)) || normB.includes(normA.slice(0, 40))) {
|
|
26249
|
-
return 0.9;
|
|
26250
|
-
}
|
|
26251
|
-
}
|
|
26252
|
-
const wordsA = tokenizeForSimilarity(normA);
|
|
26253
|
-
const wordsB = tokenizeForSimilarity(normB);
|
|
26254
|
-
const intersection = new Set([...wordsA].filter((w) => wordsB.has(w)));
|
|
26255
|
-
const union = /* @__PURE__ */ new Set([...wordsA, ...wordsB]);
|
|
26256
|
-
if (union.size === 0) return 0;
|
|
26257
|
-
return intersection.size / union.size;
|
|
26258
|
-
}
|
|
26259
|
-
function embeddedPunctuationSignature(text) {
|
|
26260
|
-
const chars = [...text.normalize("NFC")];
|
|
26261
|
-
const significant = /[\p{L}\p{M}\p{N}]/u;
|
|
26262
|
-
const ignored = /[\s']/u;
|
|
26263
|
-
const boundaries = [];
|
|
26264
|
-
let position = 0;
|
|
26265
|
-
for (let index = 0; index < chars.length; ) {
|
|
26266
|
-
const char = chars[index];
|
|
26267
|
-
if (char === void 0) break;
|
|
26268
|
-
if (significant.test(char)) {
|
|
26269
|
-
position++;
|
|
26270
|
-
index++;
|
|
26271
|
-
continue;
|
|
26272
|
-
}
|
|
26273
|
-
if (ignored.test(char)) {
|
|
26274
|
-
index++;
|
|
26275
|
-
continue;
|
|
26276
|
-
}
|
|
26277
|
-
const start = index;
|
|
26278
|
-
while (index < chars.length) {
|
|
26279
|
-
const next = chars[index];
|
|
26280
|
-
if (next === void 0 || significant.test(next) || ignored.test(next)) break;
|
|
26281
|
-
index++;
|
|
26282
|
-
}
|
|
26283
|
-
const before = chars[start - 1];
|
|
26284
|
-
const after = chars[index];
|
|
26285
|
-
if (before && after && significant.test(before) && significant.test(after)) {
|
|
26286
|
-
boundaries.push(`${position}:${chars.slice(start, index).join("")}`);
|
|
26287
|
-
}
|
|
26288
|
-
}
|
|
26289
|
-
return boundaries.join("\0");
|
|
26290
|
-
}
|
|
26291
|
-
function normalize(text) {
|
|
26292
|
-
return text.normalize("NFC").toLowerCase().replace(/[^\p{ASCII}\p{L}\p{M}\p{N}\s']/gu, " ").replace(/[^\p{L}\p{M}\p{N}\s']/gu, "").replace(/\s+/g, " ").trim();
|
|
26293
|
-
}
|
|
26294
|
-
function tokenizeForSimilarity(text) {
|
|
26295
|
-
if (/\p{Script=Hangul}/u.test(text)) {
|
|
26296
|
-
const tokens = normalizeRecallTokenSet(text);
|
|
26297
|
-
for (const segment of text.match(/\p{Script=Hangul}+/gu) ?? []) {
|
|
26298
|
-
const chars = [...segment];
|
|
26299
|
-
for (const size of [1, 2, 3, 4]) {
|
|
26300
|
-
for (let index = 0; index <= chars.length - size; index += 1) {
|
|
26301
|
-
tokens.add(chars.slice(index, index + size).join(""));
|
|
26302
|
-
}
|
|
26303
|
-
}
|
|
26304
|
-
}
|
|
26305
|
-
return tokens;
|
|
26306
|
-
}
|
|
26307
|
-
if (/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(text)) {
|
|
26308
|
-
return normalizeRecallTokenSet(text);
|
|
26309
|
-
}
|
|
26310
|
-
return text.length === 0 ? /* @__PURE__ */ new Set() : new Set(text.split(/\s+/));
|
|
26311
|
-
}
|
|
26312
|
-
var NEGATION_WORDS = /* @__PURE__ */ new Set([
|
|
26313
|
-
"not",
|
|
26314
|
-
"don't",
|
|
26315
|
-
"doesn't",
|
|
26316
|
-
"isn't",
|
|
26317
|
-
"aren't",
|
|
26318
|
-
"won't",
|
|
26319
|
-
"can't",
|
|
26320
|
-
"cannot",
|
|
26321
|
-
"never",
|
|
26322
|
-
"no",
|
|
26323
|
-
"none",
|
|
26324
|
-
"neither",
|
|
26325
|
-
"nor",
|
|
26326
|
-
"nothing",
|
|
26327
|
-
"nowhere"
|
|
26328
|
-
]);
|
|
26329
|
-
function detectContradiction(a, b) {
|
|
26330
|
-
const normA = normalize(a.content);
|
|
26331
|
-
const normB = normalize(b.content);
|
|
26332
|
-
const aHasNegation = containsNegation(normA);
|
|
26333
|
-
const bHasNegation = containsNegation(normB);
|
|
26334
|
-
if (aHasNegation === bHasNegation) return null;
|
|
26335
|
-
const strippedA = stripNegation(normA);
|
|
26336
|
-
const strippedB = stripNegation(normB);
|
|
26337
|
-
const sim = computeSimilarity(strippedA, strippedB);
|
|
26338
|
-
if (sim < 0.7) return null;
|
|
26339
|
-
const oppQuantifiers = [
|
|
26340
|
-
["always", "never"],
|
|
26341
|
-
["all", "none"],
|
|
26342
|
-
["every", "no"],
|
|
26343
|
-
["must", "must not"],
|
|
26344
|
-
["should", "should not"],
|
|
26345
|
-
["can", "cannot"]
|
|
26346
|
-
];
|
|
26347
|
-
for (const [pos, neg] of oppQuantifiers) {
|
|
26348
|
-
if (a.content.toLowerCase().includes(pos) && b.content.toLowerCase().includes(neg) || a.content.toLowerCase().includes(neg) && b.content.toLowerCase().includes(pos)) {
|
|
26349
|
-
return {
|
|
26350
|
-
left: a,
|
|
26351
|
-
right: b,
|
|
26352
|
-
severity: "high",
|
|
26353
|
-
reason: `Opposite quantifiers: "${pos}" vs "${neg}"`
|
|
26354
|
-
};
|
|
26355
|
-
}
|
|
26356
|
-
}
|
|
26357
|
-
return {
|
|
26358
|
-
left: a,
|
|
26359
|
-
right: b,
|
|
26360
|
-
severity: sim >= 0.85 ? "high" : "medium",
|
|
26361
|
-
reason: "Negated version of similar content"
|
|
26362
|
-
};
|
|
26363
|
-
}
|
|
26364
|
-
function containsNegation(text) {
|
|
26365
|
-
const words = text.split(/\s+/);
|
|
26366
|
-
return words.some((w) => NEGATION_WORDS.has(w));
|
|
26367
|
-
}
|
|
26368
|
-
function escapeRegExp(value) {
|
|
26369
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26370
|
-
}
|
|
26371
|
-
var stripNegationPattern = null;
|
|
26372
|
-
var stripNegationPatternSource = null;
|
|
26373
|
-
function stripNegationRegex() {
|
|
26374
|
-
const alternation = [...NEGATION_WORDS].sort((a, b) => b.length - a.length).map(escapeRegExp).join("|");
|
|
26375
|
-
if (stripNegationPattern === null || stripNegationPatternSource !== alternation) {
|
|
26376
|
-
stripNegationPattern = new RegExp(`\\b(?:${alternation})\\b`, "gi");
|
|
26377
|
-
stripNegationPatternSource = alternation;
|
|
26378
|
-
}
|
|
26379
|
-
return stripNegationPattern;
|
|
26380
|
-
}
|
|
26381
|
-
function stripNegation(text) {
|
|
26382
|
-
return text.replace(stripNegationRegex(), "").replace(/\s+/g, " ").trim();
|
|
26383
|
-
}
|
|
26384
|
-
function loadMemories(memoryDir, categories, maxLoad = 1e4) {
|
|
26385
|
-
const result = [];
|
|
26386
|
-
const allCategories = categories ?? ALL_CATEGORY_DIRS;
|
|
26387
|
-
if (!fs4.existsSync(memoryDir)) return result;
|
|
26388
|
-
const memoryRootReal = fs4.realpathSync(memoryDir);
|
|
26389
|
-
for (const category of allCategories) {
|
|
26390
|
-
if (result.length >= maxLoad) break;
|
|
26391
|
-
const dir = path30.join(memoryDir, category);
|
|
26392
|
-
if (!fs4.existsSync(dir)) continue;
|
|
26393
|
-
const categoryStat = fs4.lstatSync(dir);
|
|
26394
|
-
if (categoryStat.isSymbolicLink()) {
|
|
26395
|
-
throw new Error(`Refusing to scan symlinked memory category directory: ${dir}`);
|
|
26396
|
-
}
|
|
26397
|
-
if (!categoryStat.isDirectory()) continue;
|
|
26398
|
-
const categoryRootReal = fs4.realpathSync(dir);
|
|
26399
|
-
assertPathInsideRoot2(memoryRootReal, categoryRootReal, dir);
|
|
26400
|
-
walkMdFiles(dir, memoryRootReal, categoryRootReal, (filePath) => {
|
|
26401
|
-
if (result.length >= maxLoad) return;
|
|
26402
|
-
const content = readFileSafe2(filePath, memoryRootReal, categoryRootReal);
|
|
26403
|
-
if (!content) return;
|
|
26404
|
-
const fm = parseFrontmatter3(content);
|
|
26405
|
-
const body = extractBody3(content);
|
|
26406
|
-
if (!fm?.id || !body) return;
|
|
26407
|
-
result.push({
|
|
26408
|
-
id: fm.id,
|
|
26409
|
-
content: body,
|
|
26410
|
-
category: fm.category ?? category.slice(0, -1),
|
|
26411
|
-
filePath
|
|
26412
|
-
});
|
|
26413
|
-
});
|
|
26414
|
-
}
|
|
26415
|
-
return result;
|
|
26416
|
-
}
|
|
26417
|
-
function hashContent2(content) {
|
|
26418
|
-
return crypto5.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
26419
|
-
}
|
|
26420
|
-
function readFileSafe2(filePath, memoryRootReal, categoryRootReal) {
|
|
26421
|
-
try {
|
|
26422
|
-
const fileStat = fs4.lstatSync(filePath);
|
|
26423
|
-
if (fileStat.isSymbolicLink()) {
|
|
26424
|
-
throw new Error(`Refusing to read symlinked memory file: ${filePath}`);
|
|
26425
|
-
}
|
|
26426
|
-
const fileReal = fs4.realpathSync(filePath);
|
|
26427
|
-
assertPathInsideRoot2(memoryRootReal, fileReal, filePath);
|
|
26428
|
-
assertPathInsideRoot2(categoryRootReal, fileReal, filePath);
|
|
26429
|
-
return fs4.readFileSync(filePath, "utf8");
|
|
26430
|
-
} catch {
|
|
26431
|
-
return null;
|
|
26432
|
-
}
|
|
26433
|
-
}
|
|
26434
|
-
function parseFrontmatter3(content) {
|
|
26435
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
26436
|
-
if (!match) return null;
|
|
26437
|
-
const fm = {};
|
|
26438
|
-
for (const line of match[1].split("\n")) {
|
|
26439
|
-
const colonIdx = line.indexOf(":");
|
|
26440
|
-
if (colonIdx === -1) continue;
|
|
26441
|
-
const key = line.slice(0, colonIdx).trim();
|
|
26442
|
-
const value = line.slice(colonIdx + 1).trim();
|
|
26443
|
-
fm[key] = value;
|
|
26444
|
-
}
|
|
26445
|
-
return fm;
|
|
26446
|
-
}
|
|
26447
|
-
function extractBody3(content) {
|
|
26448
|
-
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)/);
|
|
26449
|
-
return match ? match[1].trim() : content.trim();
|
|
26450
|
-
}
|
|
26451
|
-
function assertPathInsideRoot2(rootReal, targetReal, sourcePath) {
|
|
26452
|
-
const rel = path30.relative(rootReal, targetReal);
|
|
26453
|
-
if (rel === "" || !rel.startsWith("..") && !path30.isAbsolute(rel)) {
|
|
26454
|
-
return;
|
|
26455
|
-
}
|
|
26456
|
-
throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);
|
|
26457
|
-
}
|
|
26458
|
-
function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
26459
|
-
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
26460
|
-
const fullPath = path30.join(dir, entry.name);
|
|
26461
|
-
const entryStat = fs4.lstatSync(fullPath);
|
|
26462
|
-
if (entryStat.isSymbolicLink()) {
|
|
26463
|
-
throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);
|
|
26464
|
-
}
|
|
26465
|
-
const entryReal = fs4.realpathSync(fullPath);
|
|
26466
|
-
assertPathInsideRoot2(memoryRootReal, entryReal, fullPath);
|
|
26467
|
-
assertPathInsideRoot2(categoryRootReal, entryReal, fullPath);
|
|
26468
|
-
if (entryStat.isDirectory()) {
|
|
26469
|
-
walkMdFiles(fullPath, memoryRootReal, categoryRootReal, callback);
|
|
26470
|
-
} else if (entry.name.endsWith(".md")) {
|
|
26471
|
-
callback(fullPath);
|
|
26472
|
-
}
|
|
26473
|
-
}
|
|
26474
|
-
}
|
|
26475
|
-
|
|
26476
26216
|
// src/sync/index.ts
|
|
26477
|
-
import
|
|
26217
|
+
import fs4 from "fs";
|
|
26478
26218
|
import path31 from "path";
|
|
26479
|
-
import
|
|
26219
|
+
import crypto5 from "crypto";
|
|
26480
26220
|
var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
26481
26221
|
var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
|
|
26482
26222
|
"node_modules",
|
|
@@ -26513,8 +26253,8 @@ function syncChanges(options) {
|
|
|
26513
26253
|
for (const [relPath, hash] of Object.entries(currentFiles)) {
|
|
26514
26254
|
newState.fileHashes[relPath] = hash;
|
|
26515
26255
|
}
|
|
26516
|
-
|
|
26517
|
-
|
|
26256
|
+
fs4.mkdirSync(path31.dirname(stateFilePath), { recursive: true });
|
|
26257
|
+
fs4.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
|
|
26518
26258
|
}
|
|
26519
26259
|
return {
|
|
26520
26260
|
scanned: Object.keys(currentFiles).length,
|
|
@@ -26568,7 +26308,7 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26568
26308
|
function walk(dir, isRoot = false) {
|
|
26569
26309
|
let entries;
|
|
26570
26310
|
try {
|
|
26571
|
-
entries =
|
|
26311
|
+
entries = fs4.readdirSync(dir, { withFileTypes: true });
|
|
26572
26312
|
} catch (err) {
|
|
26573
26313
|
if (isRoot) {
|
|
26574
26314
|
throw new Error(
|
|
@@ -26587,8 +26327,8 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26587
26327
|
if (!extensions.has(ext)) continue;
|
|
26588
26328
|
const relPath = path31.relative(root, fullPath);
|
|
26589
26329
|
try {
|
|
26590
|
-
const content =
|
|
26591
|
-
result[relPath] =
|
|
26330
|
+
const content = fs4.readFileSync(fullPath, "utf8");
|
|
26331
|
+
result[relPath] = hashContent2(content);
|
|
26592
26332
|
} catch {
|
|
26593
26333
|
}
|
|
26594
26334
|
}
|
|
@@ -26604,7 +26344,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26604
26344
|
if (!(relPath in previous)) {
|
|
26605
26345
|
let size = 0;
|
|
26606
26346
|
try {
|
|
26607
|
-
size =
|
|
26347
|
+
size = fs4.statSync(fullPath).size;
|
|
26608
26348
|
} catch {
|
|
26609
26349
|
}
|
|
26610
26350
|
changes.push({
|
|
@@ -26617,7 +26357,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26617
26357
|
} else if (previous[relPath] !== hash) {
|
|
26618
26358
|
let size = 0;
|
|
26619
26359
|
try {
|
|
26620
|
-
size =
|
|
26360
|
+
size = fs4.statSync(fullPath).size;
|
|
26621
26361
|
} catch {
|
|
26622
26362
|
}
|
|
26623
26363
|
changes.push({
|
|
@@ -26645,7 +26385,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26645
26385
|
}
|
|
26646
26386
|
function loadState(stateFilePath) {
|
|
26647
26387
|
try {
|
|
26648
|
-
const raw =
|
|
26388
|
+
const raw = fs4.readFileSync(stateFilePath, "utf8");
|
|
26649
26389
|
return JSON.parse(raw);
|
|
26650
26390
|
} catch {
|
|
26651
26391
|
return {
|
|
@@ -26655,14 +26395,14 @@ function loadState(stateFilePath) {
|
|
|
26655
26395
|
};
|
|
26656
26396
|
}
|
|
26657
26397
|
}
|
|
26658
|
-
function
|
|
26659
|
-
return
|
|
26398
|
+
function hashContent2(content) {
|
|
26399
|
+
return crypto5.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
26660
26400
|
}
|
|
26661
26401
|
|
|
26662
26402
|
// src/spaces/index.ts
|
|
26663
26403
|
import { spawnSync } from "child_process";
|
|
26664
|
-
import
|
|
26665
|
-
import
|
|
26404
|
+
import crypto6 from "crypto";
|
|
26405
|
+
import fs5 from "fs";
|
|
26666
26406
|
import path32 from "path";
|
|
26667
26407
|
var historicalIdCache3 = new HistoricalEntityCanonicalIdCache();
|
|
26668
26408
|
var MANIFEST_VERSION = 1;
|
|
@@ -26680,7 +26420,7 @@ function getManifestPath(baseDir) {
|
|
|
26680
26420
|
return path32.join(getSpacesDir(baseDir), "manifest.json");
|
|
26681
26421
|
}
|
|
26682
26422
|
function loadManifest(baseDir, memoryDirOverride) {
|
|
26683
|
-
if (
|
|
26423
|
+
if (fs5.existsSync(getManifestPath(baseDir))) {
|
|
26684
26424
|
try {
|
|
26685
26425
|
return readManifestUnlocked(baseDir, memoryDirOverride, { bootstrapIfMissing: false });
|
|
26686
26426
|
} catch (error) {
|
|
@@ -26706,7 +26446,7 @@ function updateManifest(baseDir, updater, memoryDirOverride) {
|
|
|
26706
26446
|
}
|
|
26707
26447
|
function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
|
|
26708
26448
|
const manifestPath2 = getManifestPath(baseDir);
|
|
26709
|
-
if (!
|
|
26449
|
+
if (!fs5.existsSync(manifestPath2)) {
|
|
26710
26450
|
if (options.bootstrapIfMissing === false) {
|
|
26711
26451
|
const error = new Error(`Spaces manifest not found: ${manifestPath2}`);
|
|
26712
26452
|
error.code = "ENOENT";
|
|
@@ -26719,21 +26459,21 @@ function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
|
|
|
26719
26459
|
version: MANIFEST_VERSION
|
|
26720
26460
|
};
|
|
26721
26461
|
}
|
|
26722
|
-
const raw = JSON.parse(
|
|
26462
|
+
const raw = JSON.parse(fs5.readFileSync(manifestPath2, "utf8"));
|
|
26723
26463
|
return raw;
|
|
26724
26464
|
}
|
|
26725
26465
|
function saveManifestUnlocked(manifest, baseDir) {
|
|
26726
26466
|
const manifestPath2 = getManifestPath(baseDir);
|
|
26727
26467
|
const manifestDir2 = path32.dirname(manifestPath2);
|
|
26728
|
-
|
|
26729
|
-
const tempPath = path32.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${
|
|
26468
|
+
fs5.mkdirSync(manifestDir2, { recursive: true });
|
|
26469
|
+
const tempPath = path32.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto6.randomUUID()}.tmp`);
|
|
26730
26470
|
try {
|
|
26731
|
-
|
|
26471
|
+
fs5.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}
|
|
26732
26472
|
`, { flag: "wx" });
|
|
26733
|
-
|
|
26473
|
+
fs5.renameSync(tempPath, manifestPath2);
|
|
26734
26474
|
} catch (error) {
|
|
26735
26475
|
try {
|
|
26736
|
-
|
|
26476
|
+
fs5.rmSync(tempPath, { force: true });
|
|
26737
26477
|
} catch {
|
|
26738
26478
|
}
|
|
26739
26479
|
throw error;
|
|
@@ -26741,7 +26481,7 @@ function saveManifestUnlocked(manifest, baseDir) {
|
|
|
26741
26481
|
}
|
|
26742
26482
|
function withManifestLock(baseDir, operation) {
|
|
26743
26483
|
const lockDir = `${getManifestPath(baseDir)}.lock`;
|
|
26744
|
-
|
|
26484
|
+
fs5.mkdirSync(path32.dirname(lockDir), { recursive: true });
|
|
26745
26485
|
const lockOwner = acquireManifestLock(lockDir);
|
|
26746
26486
|
try {
|
|
26747
26487
|
return operation();
|
|
@@ -26754,10 +26494,10 @@ function acquireManifestLock(lockDir) {
|
|
|
26754
26494
|
const owner = createManifestLockOwner();
|
|
26755
26495
|
const reclaimDir = getManifestLockReclaimDir(lockDir);
|
|
26756
26496
|
while (true) {
|
|
26757
|
-
if (
|
|
26497
|
+
if (fs5.existsSync(reclaimDir)) {
|
|
26758
26498
|
removeStaleManifestReclaimLock(reclaimDir);
|
|
26759
26499
|
}
|
|
26760
|
-
if (
|
|
26500
|
+
if (fs5.existsSync(reclaimDir)) {
|
|
26761
26501
|
if (Date.now() >= deadline) {
|
|
26762
26502
|
throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);
|
|
26763
26503
|
}
|
|
@@ -26765,15 +26505,15 @@ function acquireManifestLock(lockDir) {
|
|
|
26765
26505
|
continue;
|
|
26766
26506
|
}
|
|
26767
26507
|
try {
|
|
26768
|
-
|
|
26508
|
+
fs5.mkdirSync(lockDir, { recursive: false });
|
|
26769
26509
|
try {
|
|
26770
|
-
|
|
26510
|
+
fs5.writeFileSync(path32.join(lockDir, "owner"), `${owner}
|
|
26771
26511
|
`, { flag: "wx" });
|
|
26772
26512
|
} catch (error) {
|
|
26773
|
-
|
|
26513
|
+
fs5.rmSync(lockDir, { recursive: true, force: true });
|
|
26774
26514
|
throw error;
|
|
26775
26515
|
}
|
|
26776
|
-
if (
|
|
26516
|
+
if (fs5.existsSync(reclaimDir)) {
|
|
26777
26517
|
releaseManifestLock(lockDir, owner);
|
|
26778
26518
|
if (Date.now() >= deadline) {
|
|
26779
26519
|
throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);
|
|
@@ -26798,8 +26538,8 @@ function acquireManifestLock(lockDir) {
|
|
|
26798
26538
|
function releaseManifestLock(lockDir, owner) {
|
|
26799
26539
|
try {
|
|
26800
26540
|
const ownerPath = path32.join(lockDir, "owner");
|
|
26801
|
-
if (
|
|
26802
|
-
|
|
26541
|
+
if (fs5.readFileSync(ownerPath, "utf8").trim() === owner) {
|
|
26542
|
+
fs5.rmSync(lockDir, { recursive: true, force: true });
|
|
26803
26543
|
}
|
|
26804
26544
|
} catch (error) {
|
|
26805
26545
|
if (error.code !== "ENOENT") {
|
|
@@ -26811,12 +26551,12 @@ function removeStaleManifestLock(lockDir) {
|
|
|
26811
26551
|
const reclaimDir = getManifestLockReclaimDir(lockDir);
|
|
26812
26552
|
const reclaimOwner = createManifestLockOwner();
|
|
26813
26553
|
try {
|
|
26814
|
-
|
|
26554
|
+
fs5.mkdirSync(reclaimDir, { recursive: false });
|
|
26815
26555
|
try {
|
|
26816
|
-
|
|
26556
|
+
fs5.writeFileSync(path32.join(reclaimDir, "owner"), `${reclaimOwner}
|
|
26817
26557
|
`, { flag: "wx" });
|
|
26818
26558
|
} catch (error) {
|
|
26819
|
-
|
|
26559
|
+
fs5.rmSync(reclaimDir, { recursive: true, force: true });
|
|
26820
26560
|
throw error;
|
|
26821
26561
|
}
|
|
26822
26562
|
} catch (error) {
|
|
@@ -26834,18 +26574,18 @@ function removeStaleManifestLock(lockDir) {
|
|
|
26834
26574
|
if (isManifestLockOwnerActive(snapshot.owner)) {
|
|
26835
26575
|
return;
|
|
26836
26576
|
}
|
|
26837
|
-
const tombstoneDir = `${lockDir}.stale.${process.pid}.${
|
|
26577
|
+
const tombstoneDir = `${lockDir}.stale.${process.pid}.${crypto6.randomUUID()}`;
|
|
26838
26578
|
try {
|
|
26839
|
-
|
|
26579
|
+
fs5.renameSync(lockDir, tombstoneDir);
|
|
26840
26580
|
} catch (error) {
|
|
26841
26581
|
if (error.code !== "ENOENT") {
|
|
26842
26582
|
throw error;
|
|
26843
26583
|
}
|
|
26844
26584
|
return;
|
|
26845
26585
|
}
|
|
26846
|
-
|
|
26586
|
+
fs5.rmSync(tombstoneDir, { recursive: true, force: true });
|
|
26847
26587
|
} finally {
|
|
26848
|
-
|
|
26588
|
+
fs5.rmSync(reclaimDir, { recursive: true, force: true });
|
|
26849
26589
|
}
|
|
26850
26590
|
}
|
|
26851
26591
|
function getManifestLockReclaimDir(lockDir) {
|
|
@@ -26855,7 +26595,7 @@ function createManifestLockOwner() {
|
|
|
26855
26595
|
return JSON.stringify({
|
|
26856
26596
|
pid: process.pid,
|
|
26857
26597
|
startKey: readProcessStartKey(process.pid),
|
|
26858
|
-
token:
|
|
26598
|
+
token: crypto6.randomUUID()
|
|
26859
26599
|
});
|
|
26860
26600
|
}
|
|
26861
26601
|
function removeStaleManifestReclaimLock(reclaimDir) {
|
|
@@ -26866,21 +26606,21 @@ function removeStaleManifestReclaimLock(reclaimDir) {
|
|
|
26866
26606
|
if (isManifestLockOwnerActive(snapshot.owner)) {
|
|
26867
26607
|
return;
|
|
26868
26608
|
}
|
|
26869
|
-
const tombstoneDir = `${reclaimDir}.stale.${process.pid}.${
|
|
26609
|
+
const tombstoneDir = `${reclaimDir}.stale.${process.pid}.${crypto6.randomUUID()}`;
|
|
26870
26610
|
try {
|
|
26871
|
-
|
|
26611
|
+
fs5.renameSync(reclaimDir, tombstoneDir);
|
|
26872
26612
|
} catch (error) {
|
|
26873
26613
|
if (error.code !== "ENOENT") {
|
|
26874
26614
|
throw error;
|
|
26875
26615
|
}
|
|
26876
26616
|
return;
|
|
26877
26617
|
}
|
|
26878
|
-
|
|
26618
|
+
fs5.rmSync(tombstoneDir, { recursive: true, force: true });
|
|
26879
26619
|
}
|
|
26880
26620
|
function readManifestLockSnapshot(lockDir) {
|
|
26881
26621
|
let stat5;
|
|
26882
26622
|
try {
|
|
26883
|
-
stat5 =
|
|
26623
|
+
stat5 = fs5.statSync(lockDir);
|
|
26884
26624
|
} catch (error) {
|
|
26885
26625
|
if (error.code === "ENOENT") {
|
|
26886
26626
|
return void 0;
|
|
@@ -26888,7 +26628,7 @@ function readManifestLockSnapshot(lockDir) {
|
|
|
26888
26628
|
throw error;
|
|
26889
26629
|
}
|
|
26890
26630
|
try {
|
|
26891
|
-
const owner =
|
|
26631
|
+
const owner = fs5.readFileSync(path32.join(lockDir, "owner"), "utf8").trim();
|
|
26892
26632
|
return { mtimeMs: stat5.mtimeMs, owner };
|
|
26893
26633
|
} catch (error) {
|
|
26894
26634
|
if (error.code === "ENOENT") {
|
|
@@ -26962,7 +26702,7 @@ function createPersonalSpace(baseDir, memoryDirOverride) {
|
|
|
26962
26702
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
26963
26703
|
const standalonePath = path32.join(homeDir, ".engram", "memory");
|
|
26964
26704
|
const openclawPath = path32.join(homeDir, ".openclaw", "workspace", "memory", "local");
|
|
26965
|
-
const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (
|
|
26705
|
+
const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (fs5.existsSync(standalonePath) ? standalonePath : fs5.existsSync(openclawPath) ? openclawPath : standalonePath);
|
|
26966
26706
|
const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);
|
|
26967
26707
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
26968
26708
|
return {
|
|
@@ -27010,7 +26750,7 @@ function createSpace(options) {
|
|
|
27010
26750
|
owner: readEnvVar("USER"),
|
|
27011
26751
|
parentSpaceId: options.parentSpaceId
|
|
27012
26752
|
};
|
|
27013
|
-
|
|
26753
|
+
fs5.mkdirSync(memoryDir, { recursive: true });
|
|
27014
26754
|
manifest.spaces.push(created);
|
|
27015
26755
|
manifest.updatedAt = now;
|
|
27016
26756
|
return created;
|
|
@@ -27168,9 +26908,9 @@ async function promoteSpace(sourceSpaceId, targetSpaceId, options) {
|
|
|
27168
26908
|
const subjectWarnings = [];
|
|
27169
26909
|
const warnedMemoryIds = [];
|
|
27170
26910
|
if (target.kind === "team") {
|
|
27171
|
-
const sourceFiles =
|
|
26911
|
+
const sourceFiles = fs5.existsSync(source.memoryDir) ? walkMd(fs5.realpathSync(source.memoryDir)) : [];
|
|
27172
26912
|
for (const file of sourceFiles) {
|
|
27173
|
-
const fm = parseSimpleFrontmatter(
|
|
26913
|
+
const fm = parseSimpleFrontmatter(fs5.readFileSync(file, "utf8"));
|
|
27174
26914
|
if (!fm?.id) continue;
|
|
27175
26915
|
if (options?.memoryIds?.length && !options.memoryIds.includes(fm.id)) continue;
|
|
27176
26916
|
const decision = evaluateSubjectGuard({
|
|
@@ -27237,28 +26977,28 @@ async function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
|
|
|
27237
26977
|
}
|
|
27238
26978
|
function getAuditLog(baseDir) {
|
|
27239
26979
|
const auditPath = path32.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
27240
|
-
if (!
|
|
27241
|
-
const lines =
|
|
26980
|
+
if (!fs5.existsSync(auditPath)) return [];
|
|
26981
|
+
const lines = fs5.readFileSync(auditPath, "utf8").trim().split("\n");
|
|
27242
26982
|
return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
27243
26983
|
}
|
|
27244
26984
|
function appendAudit(entry, baseDir) {
|
|
27245
26985
|
const auditPath = path32.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
27246
|
-
|
|
26986
|
+
fs5.mkdirSync(path32.dirname(auditPath), { recursive: true });
|
|
27247
26987
|
const full = {
|
|
27248
|
-
id:
|
|
26988
|
+
id: crypto6.randomUUID(),
|
|
27249
26989
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27250
26990
|
...entry
|
|
27251
26991
|
};
|
|
27252
|
-
|
|
26992
|
+
fs5.appendFileSync(auditPath, `${JSON.stringify(full)}
|
|
27253
26993
|
`);
|
|
27254
26994
|
}
|
|
27255
26995
|
async function copyMemories(sourceDir, targetDir, options) {
|
|
27256
|
-
if (!
|
|
26996
|
+
if (!fs5.existsSync(sourceDir)) {
|
|
27257
26997
|
return { merged: 0, conflicts: [], skipped: 0 };
|
|
27258
26998
|
}
|
|
27259
|
-
const sourceRoot =
|
|
27260
|
-
|
|
27261
|
-
const targetRoot =
|
|
26999
|
+
const sourceRoot = fs5.realpathSync(sourceDir);
|
|
27000
|
+
fs5.mkdirSync(targetDir, { recursive: true });
|
|
27001
|
+
const targetRoot = fs5.realpathSync(targetDir);
|
|
27262
27002
|
const sourceFiles = walkMd(sourceRoot);
|
|
27263
27003
|
const sourceEntityIds = new Set(
|
|
27264
27004
|
sourceFiles.filter((p) => {
|
|
@@ -27302,7 +27042,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27302
27042
|
skipped++;
|
|
27303
27043
|
continue;
|
|
27304
27044
|
}
|
|
27305
|
-
const content =
|
|
27045
|
+
const content = fs5.readFileSync(sourcePath, "utf8");
|
|
27306
27046
|
const relativePath = path32.relative(sourceRoot, sourceRealPath);
|
|
27307
27047
|
const targetPath = path32.resolve(targetRoot, relativePath);
|
|
27308
27048
|
if (!isPathInsideRoot(targetPath, targetRoot)) {
|
|
@@ -27314,7 +27054,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27314
27054
|
const sourceRef = targetKind === "memory" ? readEntityRefFromFrontmatter(content) : null;
|
|
27315
27055
|
const refHasSourceClaimant = sourceRef !== null && sourceEntityIds.has(sourceRef);
|
|
27316
27056
|
const canonicalContent = targetKind === "memory" && !refHasSourceClaimant ? canonicalizeEntityRefFrontmatter(content, idsAtCompare) : content;
|
|
27317
|
-
const sourceHash =
|
|
27057
|
+
const sourceHash = hashContent3(content);
|
|
27318
27058
|
if (options?.filterIds?.length) {
|
|
27319
27059
|
const fm = parseSimpleFrontmatter(content);
|
|
27320
27060
|
if (!fm?.id || !options.filterIds.includes(fm.id)) {
|
|
@@ -27322,7 +27062,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27322
27062
|
continue;
|
|
27323
27063
|
}
|
|
27324
27064
|
}
|
|
27325
|
-
if (
|
|
27065
|
+
if (fs5.existsSync(targetPath)) {
|
|
27326
27066
|
const targetStat = safeLstat(targetPath);
|
|
27327
27067
|
if (!targetStat?.isFile() || targetStat.isSymbolicLink()) {
|
|
27328
27068
|
skipped++;
|
|
@@ -27334,14 +27074,14 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27334
27074
|
continue;
|
|
27335
27075
|
}
|
|
27336
27076
|
}
|
|
27337
|
-
if (
|
|
27338
|
-
const targetContent =
|
|
27339
|
-
const targetHash =
|
|
27340
|
-
if (
|
|
27077
|
+
if (fs5.existsSync(targetPath) && !options?.force) {
|
|
27078
|
+
const targetContent = fs5.readFileSync(targetPath, "utf8");
|
|
27079
|
+
const targetHash = hashContent3(targetContent);
|
|
27080
|
+
if (hashContent3(canonicalContent) === targetHash && historicalIdCache3.get(path32.join(targetRoot, "state")) === idsAtCompare) {
|
|
27341
27081
|
skipped++;
|
|
27342
27082
|
continue;
|
|
27343
27083
|
}
|
|
27344
|
-
if (
|
|
27084
|
+
if (hashContent3(canonicalContent) !== targetHash && sourceHash !== targetHash) {
|
|
27345
27085
|
conflicts.push({
|
|
27346
27086
|
memoryId: parseSimpleFrontmatter(content)?.id ?? relativePath,
|
|
27347
27087
|
sourcePath,
|
|
@@ -27353,7 +27093,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27353
27093
|
continue;
|
|
27354
27094
|
}
|
|
27355
27095
|
}
|
|
27356
|
-
|
|
27096
|
+
fs5.mkdirSync(path32.dirname(targetPath), { recursive: true });
|
|
27357
27097
|
const targetParentRealPath = safeRealpath(path32.dirname(targetPath));
|
|
27358
27098
|
if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {
|
|
27359
27099
|
skipped++;
|
|
@@ -27365,11 +27105,11 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27365
27105
|
const written = canonicalizeEntityRefFrontmatter(content, idsAtWrite);
|
|
27366
27106
|
let priorTarget = null;
|
|
27367
27107
|
try {
|
|
27368
|
-
priorTarget =
|
|
27108
|
+
priorTarget = fs5.readFileSync(targetPath, "utf8");
|
|
27369
27109
|
} catch {
|
|
27370
27110
|
priorTarget = null;
|
|
27371
27111
|
}
|
|
27372
|
-
|
|
27112
|
+
fs5.writeFileSync(targetPath, written);
|
|
27373
27113
|
try {
|
|
27374
27114
|
repairContentAfterJournalMoveSync({
|
|
27375
27115
|
stateDir,
|
|
@@ -27377,24 +27117,24 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27377
27117
|
idsAtWrite,
|
|
27378
27118
|
rawContent: content,
|
|
27379
27119
|
lastWritten: written,
|
|
27380
|
-
rewrite: (next) =>
|
|
27120
|
+
rewrite: (next) => fs5.writeFileSync(targetPath, next)
|
|
27381
27121
|
});
|
|
27382
27122
|
} catch (err) {
|
|
27383
27123
|
try {
|
|
27384
27124
|
if (priorTarget === null) {
|
|
27385
|
-
|
|
27125
|
+
fs5.unlinkSync(targetPath);
|
|
27386
27126
|
} else {
|
|
27387
|
-
|
|
27127
|
+
fs5.writeFileSync(targetPath, priorTarget);
|
|
27388
27128
|
}
|
|
27389
27129
|
} catch {
|
|
27390
27130
|
}
|
|
27391
27131
|
throw err;
|
|
27392
27132
|
}
|
|
27393
27133
|
} else if (targetKind === "memory") {
|
|
27394
|
-
|
|
27134
|
+
fs5.writeFileSync(targetPath, content);
|
|
27395
27135
|
reconcileNeeded = true;
|
|
27396
27136
|
} else {
|
|
27397
|
-
|
|
27137
|
+
fs5.writeFileSync(targetPath, content);
|
|
27398
27138
|
if (targetKind === "entity") {
|
|
27399
27139
|
reconcileNeeded = true;
|
|
27400
27140
|
}
|
|
@@ -27407,13 +27147,13 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27407
27147
|
}
|
|
27408
27148
|
return { merged, conflicts, skipped };
|
|
27409
27149
|
}
|
|
27410
|
-
function
|
|
27411
|
-
return
|
|
27150
|
+
function hashContent3(content) {
|
|
27151
|
+
return crypto6.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
27412
27152
|
}
|
|
27413
27153
|
function walkMd(dir) {
|
|
27414
27154
|
const results = [];
|
|
27415
27155
|
function walk(d) {
|
|
27416
|
-
for (const entry of
|
|
27156
|
+
for (const entry of fs5.readdirSync(d, { withFileTypes: true })) {
|
|
27417
27157
|
const fullPath = path32.join(d, entry.name);
|
|
27418
27158
|
if (entry.isSymbolicLink()) {
|
|
27419
27159
|
continue;
|
|
@@ -27430,14 +27170,14 @@ function walkMd(dir) {
|
|
|
27430
27170
|
}
|
|
27431
27171
|
function safeLstat(filePath) {
|
|
27432
27172
|
try {
|
|
27433
|
-
return
|
|
27173
|
+
return fs5.lstatSync(filePath);
|
|
27434
27174
|
} catch {
|
|
27435
27175
|
return null;
|
|
27436
27176
|
}
|
|
27437
27177
|
}
|
|
27438
27178
|
function safeRealpath(filePath) {
|
|
27439
27179
|
try {
|
|
27440
|
-
return
|
|
27180
|
+
return fs5.realpathSync(filePath);
|
|
27441
27181
|
} catch {
|
|
27442
27182
|
return null;
|
|
27443
27183
|
}
|
|
@@ -27563,7 +27303,7 @@ var REMNIC_RECALL_DECISION_RULES = `## When to Use Recall vs Direct Read
|
|
|
27563
27303
|
`;
|
|
27564
27304
|
|
|
27565
27305
|
// src/memory-extension/codex-publisher.ts
|
|
27566
|
-
import
|
|
27306
|
+
import fs6 from "fs";
|
|
27567
27307
|
import os from "os";
|
|
27568
27308
|
import path33 from "path";
|
|
27569
27309
|
var REMNIC_EXTENSION_DIR_NAME = "remnic";
|
|
@@ -27599,7 +27339,7 @@ var CodexMemoryExtensionPublisher = class {
|
|
|
27599
27339
|
async isHostAvailable() {
|
|
27600
27340
|
try {
|
|
27601
27341
|
const home = readEnvVar("CODEX_HOME")?.trim() || path33.join(resolveHomeDir(), ".codex");
|
|
27602
|
-
return
|
|
27342
|
+
return fs6.existsSync(home);
|
|
27603
27343
|
} catch {
|
|
27604
27344
|
return false;
|
|
27605
27345
|
}
|
|
@@ -27653,18 +27393,18 @@ When running inside the Codex phase-2 consolidation sandbox:
|
|
|
27653
27393
|
const filesWritten = [];
|
|
27654
27394
|
const skipped = [];
|
|
27655
27395
|
ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);
|
|
27656
|
-
|
|
27396
|
+
fs6.mkdirSync(extensionRoot, { recursive: true });
|
|
27657
27397
|
const content = await this.renderInstructions(ctx);
|
|
27658
27398
|
const tmpPath = `${instructionsPath}.tmp-${process.pid}-${Date.now()}`;
|
|
27659
27399
|
try {
|
|
27660
|
-
|
|
27661
|
-
|
|
27400
|
+
fs6.writeFileSync(tmpPath, content, "utf-8");
|
|
27401
|
+
fs6.renameSync(tmpPath, instructionsPath);
|
|
27662
27402
|
filesWritten.push(instructionsPath);
|
|
27663
27403
|
ctx.log.info(`Wrote ${instructionsPath}`);
|
|
27664
27404
|
} catch (err) {
|
|
27665
27405
|
try {
|
|
27666
|
-
if (
|
|
27667
|
-
|
|
27406
|
+
if (fs6.existsSync(tmpPath)) {
|
|
27407
|
+
fs6.unlinkSync(tmpPath);
|
|
27668
27408
|
}
|
|
27669
27409
|
} catch {
|
|
27670
27410
|
}
|
|
@@ -27679,8 +27419,8 @@ When running inside the Codex phase-2 consolidation sandbox:
|
|
|
27679
27419
|
}
|
|
27680
27420
|
async unpublish() {
|
|
27681
27421
|
const extensionRoot = await this.resolveExtensionRoot();
|
|
27682
|
-
if (
|
|
27683
|
-
|
|
27422
|
+
if (fs6.existsSync(extensionRoot)) {
|
|
27423
|
+
fs6.rmSync(extensionRoot, { recursive: true, force: true });
|
|
27684
27424
|
}
|
|
27685
27425
|
}
|
|
27686
27426
|
};
|
|
@@ -28610,6 +28350,153 @@ function findRecurringPatterns(input) {
|
|
|
28610
28350
|
return patterns;
|
|
28611
28351
|
}
|
|
28612
28352
|
|
|
28353
|
+
// src/activity/timeline/week-dashboard.ts
|
|
28354
|
+
var WEEKLY_DASHBOARD_FORMAT_VERSION = 1;
|
|
28355
|
+
var DEFAULT_TOP_SOURCE_LIMIT = 10;
|
|
28356
|
+
var DAY_MS2 = 864e5;
|
|
28357
|
+
var WEEK_DAYS_MS = 7 * DAY_MS2;
|
|
28358
|
+
function clippedInWeek(cards, weekStartMs, weekEndMs) {
|
|
28359
|
+
const clipped = [];
|
|
28360
|
+
for (const card of cards) {
|
|
28361
|
+
const startMs = Date.parse(card.startUtc);
|
|
28362
|
+
const endMs = Date.parse(card.endUtc);
|
|
28363
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs <= startMs) continue;
|
|
28364
|
+
const clipStartMs = Math.max(startMs, weekStartMs);
|
|
28365
|
+
const clipEndMs = Math.min(endMs, weekEndMs);
|
|
28366
|
+
if (clipEndMs > clipStartMs) {
|
|
28367
|
+
clipped.push({ card, startMs, endMs, clipStartMs, clipEndMs });
|
|
28368
|
+
}
|
|
28369
|
+
}
|
|
28370
|
+
return clipped;
|
|
28371
|
+
}
|
|
28372
|
+
function normalizedAttribution(cardId, attributions) {
|
|
28373
|
+
const attribution = attributions?.get(cardId);
|
|
28374
|
+
if (attribution === void 0) return null;
|
|
28375
|
+
if (typeof attribution.app !== "string" || attribution.app.trim() === "") {
|
|
28376
|
+
throw new RangeError(`attribution for card ${cardId} must have a non-blank app`);
|
|
28377
|
+
}
|
|
28378
|
+
const app = attribution.app.trim();
|
|
28379
|
+
if (attribution.domain === void 0) return { app };
|
|
28380
|
+
if (typeof attribution.domain !== "string" || attribution.domain.trim() === "") {
|
|
28381
|
+
throw new RangeError(`attribution for card ${cardId} must have a non-blank domain when present`);
|
|
28382
|
+
}
|
|
28383
|
+
return { app, domain: attribution.domain.trim().toLowerCase() };
|
|
28384
|
+
}
|
|
28385
|
+
function rankTotals(totals, limit) {
|
|
28386
|
+
return [...totals.entries()].map(([key, durationMs]) => ({ key, durationMs })).sort(
|
|
28387
|
+
(a, b) => b.durationMs - a.durationMs || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0)
|
|
28388
|
+
).slice(0, limit);
|
|
28389
|
+
}
|
|
28390
|
+
function buildWeeklyDashboard(cards, options) {
|
|
28391
|
+
const summary = buildWeeklyActivitySummary(cards, options);
|
|
28392
|
+
const topSourceLimit = options.topSourceLimit ?? DEFAULT_TOP_SOURCE_LIMIT;
|
|
28393
|
+
if (!Number.isInteger(topSourceLimit) || topSourceLimit < 1) {
|
|
28394
|
+
throw new RangeError(`topSourceLimit must be an integer >= 1; got ${topSourceLimit}`);
|
|
28395
|
+
}
|
|
28396
|
+
const weekStartMs = Date.parse(summary.weekStartUtc);
|
|
28397
|
+
const weekEndMs = Date.parse(summary.weekEndUtc);
|
|
28398
|
+
const inWeek = clippedInWeek(cards, weekStartMs, weekEndMs);
|
|
28399
|
+
const applicationTotals = /* @__PURE__ */ new Map();
|
|
28400
|
+
const domainTotals = /* @__PURE__ */ new Map();
|
|
28401
|
+
const applicationOccurrences = [];
|
|
28402
|
+
const categoryOccurrences = [];
|
|
28403
|
+
const evidence = {
|
|
28404
|
+
activityCardCount: 0,
|
|
28405
|
+
idleCardCount: 0,
|
|
28406
|
+
pauseCardCount: 0,
|
|
28407
|
+
evidenceCount: 0,
|
|
28408
|
+
distinctEvidenceCount: 0
|
|
28409
|
+
};
|
|
28410
|
+
const uncertainty = {
|
|
28411
|
+
clippedCardCount: 0,
|
|
28412
|
+
manualEditCount: 0,
|
|
28413
|
+
unclassifiedCardCount: 0
|
|
28414
|
+
};
|
|
28415
|
+
const distinctEvidence = /* @__PURE__ */ new Set();
|
|
28416
|
+
const dayWindows = summary.days.map((day) => ({
|
|
28417
|
+
date: day.date,
|
|
28418
|
+
startMs: Date.parse(day.startUtc),
|
|
28419
|
+
endMs: Date.parse(day.endUtc)
|
|
28420
|
+
}));
|
|
28421
|
+
for (const day of summary.days) {
|
|
28422
|
+
for (const total of day.categories) {
|
|
28423
|
+
if (total.durationMs > 0) {
|
|
28424
|
+
categoryOccurrences.push({ date: day.date, key: total.categoryId, durationMs: total.durationMs });
|
|
28425
|
+
}
|
|
28426
|
+
}
|
|
28427
|
+
}
|
|
28428
|
+
for (const { card, startMs, endMs, clipStartMs, clipEndMs } of inWeek) {
|
|
28429
|
+
if (startMs < weekStartMs || endMs > weekEndMs) {
|
|
28430
|
+
uncertainty.clippedCardCount++;
|
|
28431
|
+
}
|
|
28432
|
+
if (card.kind === "idle") {
|
|
28433
|
+
evidence.idleCardCount++;
|
|
28434
|
+
continue;
|
|
28435
|
+
}
|
|
28436
|
+
if (card.kind === "pause") {
|
|
28437
|
+
evidence.pauseCardCount++;
|
|
28438
|
+
continue;
|
|
28439
|
+
}
|
|
28440
|
+
evidence.activityCardCount++;
|
|
28441
|
+
for (const id of card.evidenceIds) {
|
|
28442
|
+
evidence.evidenceCount++;
|
|
28443
|
+
distinctEvidence.add(id);
|
|
28444
|
+
}
|
|
28445
|
+
if (card.manualEdit !== void 0) uncertainty.manualEditCount++;
|
|
28446
|
+
if (card.confidence === 0) uncertainty.unclassifiedCardCount++;
|
|
28447
|
+
const attribution = normalizedAttribution(card.id, options.attributions);
|
|
28448
|
+
if (attribution === null) continue;
|
|
28449
|
+
const durationMs = clipEndMs - clipStartMs;
|
|
28450
|
+
applicationTotals.set(attribution.app, (applicationTotals.get(attribution.app) ?? 0) + durationMs);
|
|
28451
|
+
if (attribution.domain !== void 0) {
|
|
28452
|
+
domainTotals.set(attribution.domain, (domainTotals.get(attribution.domain) ?? 0) + durationMs);
|
|
28453
|
+
}
|
|
28454
|
+
for (const day of dayWindows) {
|
|
28455
|
+
const dayStartMs = Math.max(clipStartMs, day.startMs);
|
|
28456
|
+
const dayEndMs = Math.min(clipEndMs, day.endMs);
|
|
28457
|
+
if (dayEndMs > dayStartMs) {
|
|
28458
|
+
applicationOccurrences.push({ date: day.date, key: attribution.app, durationMs: dayEndMs - dayStartMs });
|
|
28459
|
+
}
|
|
28460
|
+
}
|
|
28461
|
+
}
|
|
28462
|
+
evidence.distinctEvidenceCount = distinctEvidence.size;
|
|
28463
|
+
let previousPeriod = { available: false };
|
|
28464
|
+
if (options.previousWeekCards !== void 0) {
|
|
28465
|
+
const previousSummary = buildWeeklyActivitySummary(options.previousWeekCards, {
|
|
28466
|
+
...options,
|
|
28467
|
+
weekStartUtc: new Date(weekStartMs - WEEK_DAYS_MS).toISOString(),
|
|
28468
|
+
weekEndUtc: summary.weekStartUtc
|
|
28469
|
+
});
|
|
28470
|
+
previousPeriod = compareWeeklyPreviousPeriod({
|
|
28471
|
+
previous: previousSummary,
|
|
28472
|
+
current: summary,
|
|
28473
|
+
previousStartUtc: previousSummary.weekStartUtc,
|
|
28474
|
+
previousEndUtc: previousSummary.weekEndUtc
|
|
28475
|
+
});
|
|
28476
|
+
}
|
|
28477
|
+
return {
|
|
28478
|
+
...summary,
|
|
28479
|
+
previousPeriod,
|
|
28480
|
+
dashboardFormatVersion: WEEKLY_DASHBOARD_FORMAT_VERSION,
|
|
28481
|
+
sources: {
|
|
28482
|
+
applications: rankTotals(applicationTotals, topSourceLimit),
|
|
28483
|
+
domains: rankTotals(domainTotals, topSourceLimit)
|
|
28484
|
+
},
|
|
28485
|
+
recurring: {
|
|
28486
|
+
categories: findRecurringPatterns({
|
|
28487
|
+
occurrences: categoryOccurrences,
|
|
28488
|
+
minDays: options.recurrenceMinDays
|
|
28489
|
+
}),
|
|
28490
|
+
applications: findRecurringPatterns({
|
|
28491
|
+
occurrences: applicationOccurrences,
|
|
28492
|
+
minDays: options.recurrenceMinDays
|
|
28493
|
+
})
|
|
28494
|
+
},
|
|
28495
|
+
evidence,
|
|
28496
|
+
uncertainty
|
|
28497
|
+
};
|
|
28498
|
+
}
|
|
28499
|
+
|
|
28613
28500
|
// src/activity/timeline/week-config-hash.ts
|
|
28614
28501
|
var WEEK_START_DAYS = Object.freeze([
|
|
28615
28502
|
"monday",
|
|
@@ -29867,6 +29754,22 @@ function filterPrivacyWindow(items, options) {
|
|
|
29867
29754
|
});
|
|
29868
29755
|
}
|
|
29869
29756
|
|
|
29757
|
+
// src/activity/privacy-redact.ts
|
|
29758
|
+
function redactActivityFields(item, options) {
|
|
29759
|
+
const result = { ...item };
|
|
29760
|
+
for (const key of options.dropKeys) {
|
|
29761
|
+
delete result[key];
|
|
29762
|
+
}
|
|
29763
|
+
return result;
|
|
29764
|
+
}
|
|
29765
|
+
|
|
29766
|
+
// src/activity/privacy-keys.ts
|
|
29767
|
+
function normalizeDropKeys(keys) {
|
|
29768
|
+
const unique = [...new Set(keys.map((key) => key.trim()).filter((key) => key.length > 0))];
|
|
29769
|
+
unique.sort((a, b) => a.localeCompare(b));
|
|
29770
|
+
return unique;
|
|
29771
|
+
}
|
|
29772
|
+
|
|
29870
29773
|
// src/activity/vault-wikilink.ts
|
|
29871
29774
|
import path37 from "path";
|
|
29872
29775
|
function formatVaultWikilink(notePath) {
|
|
@@ -30958,8 +30861,6 @@ export {
|
|
|
30958
30861
|
generateContextTree,
|
|
30959
30862
|
onboard,
|
|
30960
30863
|
curate,
|
|
30961
|
-
findDuplicates,
|
|
30962
|
-
findContradictions,
|
|
30963
30864
|
decideSemanticDedup,
|
|
30964
30865
|
syncChanges,
|
|
30965
30866
|
watchForChanges,
|
|
@@ -31025,6 +30926,9 @@ export {
|
|
|
31025
30926
|
DEFAULT_RECURRENCE_MIN_DAYS,
|
|
31026
30927
|
MIN_RECURRENCE_MIN_DAYS,
|
|
31027
30928
|
findRecurringPatterns,
|
|
30929
|
+
WEEKLY_DASHBOARD_FORMAT_VERSION,
|
|
30930
|
+
DEFAULT_TOP_SOURCE_LIMIT,
|
|
30931
|
+
buildWeeklyDashboard,
|
|
31028
30932
|
WEEK_START_DAYS,
|
|
31029
30933
|
computeWeeklyConfigHash,
|
|
31030
30934
|
batchObservations,
|
|
@@ -31066,6 +30970,8 @@ export {
|
|
|
31066
30970
|
ACTIVITY_FEATURE_GATES,
|
|
31067
30971
|
resolveActivityGates,
|
|
31068
30972
|
filterPrivacyWindow,
|
|
30973
|
+
redactActivityFields,
|
|
30974
|
+
normalizeDropKeys,
|
|
31069
30975
|
formatVaultWikilink,
|
|
31070
30976
|
stripVaultMdSuffix,
|
|
31071
30977
|
joinVaultSegments,
|
|
@@ -31104,4 +31010,4 @@ export {
|
|
|
31104
31010
|
qmdStartupCollectionChecksWithTimeout,
|
|
31105
31011
|
Orchestrator
|
|
31106
31012
|
};
|
|
31107
|
-
//# sourceMappingURL=chunk-
|
|
31013
|
+
//# sourceMappingURL=chunk-OKOG5MXF.js.map
|