@remnic/core 9.69.52 → 9.69.53
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 +20 -20
- 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/{chunk-TEQQQTQS.js → chunk-2HJKAVAS.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-MSTKJI5T.js → chunk-K7FXR75S.js} +442 -318
- package/dist/chunk-K7FXR75S.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-6KCQNFDQ.js → chunk-SOOWBRMH.js} +8 -8
- package/dist/{chunk-SOFATSHJ.js → chunk-TS66MUUJ.js} +5 -5
- 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-UQTXER7M.js → chunk-ZADYEZY4.js} +2 -2
- package/dist/{chunk-2INZSV27.js → chunk-ZANEMAEV.js} +2 -2
- package/dist/{cli-CCc34xV7.d.ts → cli-VGDSn2zY.d.ts} +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +17 -17
- 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 +680 -680
- package/dist/index.js +20 -20
- 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/orchestrator.js +20 -20
- 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/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/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/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-TEQQQTQS.js.map → chunk-2HJKAVAS.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-SOFATSHJ.js.map → chunk-TS66MUUJ.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-UQTXER7M.js.map → chunk-ZADYEZY4.js.map} +0 -0
- /package/dist/{chunk-2INZSV27.js.map → chunk-ZANEMAEV.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-TS66MUUJ.js";
|
|
235
235
|
import {
|
|
236
236
|
normalizeReplaySessionKey
|
|
237
237
|
} from "./chunk-AJVLDJU6.js";
|
|
@@ -344,9 +344,12 @@ import {
|
|
|
344
344
|
resolveVaultNotePath
|
|
345
345
|
} from "./chunk-3KJTSCSX.js";
|
|
346
346
|
import {
|
|
347
|
+
buildRecognitionIndex,
|
|
347
348
|
decideRecognitionTier,
|
|
348
349
|
loadRecognitionIndex,
|
|
349
|
-
|
|
350
|
+
recognitionIndexPath,
|
|
351
|
+
runRecognitionTier,
|
|
352
|
+
saveRecognitionIndex
|
|
350
353
|
} from "./chunk-4KQIWY4A.js";
|
|
351
354
|
import {
|
|
352
355
|
AMBIENT_CAPTURE_PROMPT_RULE,
|
|
@@ -354,7 +357,7 @@ import {
|
|
|
354
357
|
} from "./chunk-QW27DOHG.js";
|
|
355
358
|
import {
|
|
356
359
|
MeetingsInputError
|
|
357
|
-
} from "./chunk-
|
|
360
|
+
} from "./chunk-SOOWBRMH.js";
|
|
358
361
|
import {
|
|
359
362
|
WearablesInputError,
|
|
360
363
|
describeErrorForOperator
|
|
@@ -378,8 +381,10 @@ import {
|
|
|
378
381
|
SessionContextCoordinator,
|
|
379
382
|
capturePassiveCorrections,
|
|
380
383
|
clusterByKey,
|
|
381
|
-
detectPassiveCorrections
|
|
382
|
-
|
|
384
|
+
detectPassiveCorrections,
|
|
385
|
+
renderSessionExperiencePreview,
|
|
386
|
+
scoreSessionExperienceForPrompt
|
|
387
|
+
} from "./chunk-HUQMVI3A.js";
|
|
383
388
|
import {
|
|
384
389
|
importCapsule
|
|
385
390
|
} from "./chunk-VVX5PZFS.js";
|
|
@@ -419,7 +424,7 @@ import {
|
|
|
419
424
|
isTopLevelArchivePath,
|
|
420
425
|
journalPath,
|
|
421
426
|
writeJournalFile
|
|
422
|
-
} from "./chunk-
|
|
427
|
+
} from "./chunk-2HJKAVAS.js";
|
|
423
428
|
import {
|
|
424
429
|
searchHarmonicRetrieval
|
|
425
430
|
} from "./chunk-TQT4AOPO.js";
|
|
@@ -850,7 +855,7 @@ import {
|
|
|
850
855
|
} from "./chunk-3WCASNQZ.js";
|
|
851
856
|
|
|
852
857
|
// src/orchestrator.ts
|
|
853
|
-
import
|
|
858
|
+
import path23 from "path";
|
|
854
859
|
import { createHash as createHash9 } from "crypto";
|
|
855
860
|
|
|
856
861
|
// src/orchestration/tier-migration-coordinator.ts
|
|
@@ -2408,7 +2413,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2408
2413
|
namespaces,
|
|
2409
2414
|
{
|
|
2410
2415
|
readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
|
|
2411
|
-
readMemoryFrontmatter: async (
|
|
2416
|
+
readMemoryFrontmatter: async (path42, preferredNamespace) => {
|
|
2412
2417
|
if (!fallbackReader) {
|
|
2413
2418
|
for (const ns of namespaces) {
|
|
2414
2419
|
try {
|
|
@@ -2420,7 +2425,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2420
2425
|
}
|
|
2421
2426
|
if (!fallbackReader) return null;
|
|
2422
2427
|
const memory = await this.readQmdResultMemory(
|
|
2423
|
-
|
|
2428
|
+
path42,
|
|
2424
2429
|
fallbackReader,
|
|
2425
2430
|
namespaces,
|
|
2426
2431
|
preferredNamespace
|
|
@@ -9897,44 +9902,8 @@ var GraphRecallCoordinator = class {
|
|
|
9897
9902
|
}
|
|
9898
9903
|
};
|
|
9899
9904
|
|
|
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
9905
|
// src/procedural/procedure-recall.ts
|
|
9937
|
-
function
|
|
9906
|
+
function tokenOverlapScore(prompt, memoryText) {
|
|
9938
9907
|
const norm = (s) => s.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 2);
|
|
9939
9908
|
const promptTokens = new Set(norm(prompt));
|
|
9940
9909
|
const memTokens = new Set(norm(memoryText));
|
|
@@ -9949,7 +9918,7 @@ function tokenOverlapScore2(prompt, memoryText) {
|
|
|
9949
9918
|
function scoreProcedureForPrompt(m, prompt, queryIntent, experienceEnabled) {
|
|
9950
9919
|
const memText = `${m.content}
|
|
9951
9920
|
${(m.frontmatter.tags ?? []).join(" ")}`;
|
|
9952
|
-
const jaccard =
|
|
9921
|
+
const jaccard = tokenOverlapScore(prompt, memText);
|
|
9953
9922
|
const memIntent = inferIntentFromText(m.content.slice(0, 2e3));
|
|
9954
9923
|
const intentScore = intentCompatibilityScore(queryIntent, memIntent);
|
|
9955
9924
|
const base = jaccard * 0.55 + intentScore * 0.45;
|
|
@@ -17655,7 +17624,121 @@ var OrchestratorInitCoordinator = class {
|
|
|
17655
17624
|
};
|
|
17656
17625
|
|
|
17657
17626
|
// src/orchestration/persistence-index.ts
|
|
17627
|
+
import path19 from "path";
|
|
17628
|
+
|
|
17629
|
+
// src/orchestration/recall-recognition-index.ts
|
|
17630
|
+
import { promises as fsp } from "fs";
|
|
17658
17631
|
import path18 from "path";
|
|
17632
|
+
import { setTimeout as delay } from "timers/promises";
|
|
17633
|
+
var writeChains = /* @__PURE__ */ new Map();
|
|
17634
|
+
var LOCK_POLL_MS = 10;
|
|
17635
|
+
var LOCK_ATTEMPTS = 50;
|
|
17636
|
+
var LOCK_STALE_MS = 6e4;
|
|
17637
|
+
function recognitionDescriptionFromContent(content) {
|
|
17638
|
+
const trimmed = content.trim();
|
|
17639
|
+
if (trimmed.length === 0) return "";
|
|
17640
|
+
const newline = trimmed.indexOf("\n");
|
|
17641
|
+
return newline === -1 ? trimmed : trimmed.slice(0, newline).trimEnd();
|
|
17642
|
+
}
|
|
17643
|
+
function withIndexChain(indexPath, op) {
|
|
17644
|
+
const previous = writeChains.get(indexPath) ?? Promise.resolve();
|
|
17645
|
+
const run = previous.then(op, op);
|
|
17646
|
+
const tail = run.then(() => void 0, () => void 0);
|
|
17647
|
+
writeChains.set(indexPath, tail);
|
|
17648
|
+
void tail.then(() => {
|
|
17649
|
+
if (writeChains.get(indexPath) === tail) writeChains.delete(indexPath);
|
|
17650
|
+
});
|
|
17651
|
+
return run;
|
|
17652
|
+
}
|
|
17653
|
+
async function removeAbandonedRecognitionLock(lockDir) {
|
|
17654
|
+
try {
|
|
17655
|
+
const info = await fsp.lstat(lockDir);
|
|
17656
|
+
if (info.isSymbolicLink()) return "blocked";
|
|
17657
|
+
if (!info.isDirectory()) {
|
|
17658
|
+
await fsp.rm(lockDir, { force: true });
|
|
17659
|
+
return "removed";
|
|
17660
|
+
}
|
|
17661
|
+
if (Date.now() - info.mtimeMs < LOCK_STALE_MS) return "wait";
|
|
17662
|
+
await fsp.rm(lockDir, { recursive: true, force: true });
|
|
17663
|
+
return "removed";
|
|
17664
|
+
} catch (error) {
|
|
17665
|
+
if (error?.code === "ENOENT") return "removed";
|
|
17666
|
+
return "blocked";
|
|
17667
|
+
}
|
|
17668
|
+
}
|
|
17669
|
+
async function withRecognitionIndexLock(memoryDir, op) {
|
|
17670
|
+
const lockDir = `${recognitionIndexPath(memoryDir)}.lock.d`;
|
|
17671
|
+
for (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt++) {
|
|
17672
|
+
try {
|
|
17673
|
+
await fsp.mkdir(lockDir);
|
|
17674
|
+
try {
|
|
17675
|
+
return await op();
|
|
17676
|
+
} finally {
|
|
17677
|
+
await fsp.rm(lockDir, { recursive: true, force: true }).catch(() => void 0);
|
|
17678
|
+
}
|
|
17679
|
+
} catch (error) {
|
|
17680
|
+
const code = error?.code;
|
|
17681
|
+
if (code === "ENOENT") {
|
|
17682
|
+
await fsp.mkdir(path18.dirname(lockDir), { recursive: true }).catch(() => void 0);
|
|
17683
|
+
continue;
|
|
17684
|
+
}
|
|
17685
|
+
if (code !== "EEXIST") throw error;
|
|
17686
|
+
const cleanup = await removeAbandonedRecognitionLock(lockDir);
|
|
17687
|
+
if (cleanup === "blocked") {
|
|
17688
|
+
throw new Error(`recognition index lock blocked at ${lockDir}`);
|
|
17689
|
+
}
|
|
17690
|
+
if (cleanup === "removed") continue;
|
|
17691
|
+
await delay(LOCK_POLL_MS);
|
|
17692
|
+
}
|
|
17693
|
+
}
|
|
17694
|
+
throw new Error(`recognition index lock timed out at ${lockDir}`);
|
|
17695
|
+
}
|
|
17696
|
+
function applyChanges(entries, changes) {
|
|
17697
|
+
const next = entries.map((entry) => ({ id: entry.id, description: entry.description }));
|
|
17698
|
+
const byId = new Map(next.map((entry, index) => [entry.id, index]));
|
|
17699
|
+
for (const change of changes) {
|
|
17700
|
+
const id = change.id.trim();
|
|
17701
|
+
if (id.length === 0) continue;
|
|
17702
|
+
if (change.action === "remove") {
|
|
17703
|
+
const index = byId.get(id);
|
|
17704
|
+
if (index === void 0) continue;
|
|
17705
|
+
next.splice(index, 1);
|
|
17706
|
+
byId.delete(id);
|
|
17707
|
+
for (const [key, value] of byId) {
|
|
17708
|
+
if (value > index) byId.set(key, value - 1);
|
|
17709
|
+
}
|
|
17710
|
+
continue;
|
|
17711
|
+
}
|
|
17712
|
+
const description = recognitionDescriptionFromContent(change.content);
|
|
17713
|
+
const existing = byId.get(id);
|
|
17714
|
+
if (existing !== void 0) {
|
|
17715
|
+
next[existing] = { id, description };
|
|
17716
|
+
} else {
|
|
17717
|
+
byId.set(id, next.length);
|
|
17718
|
+
next.push({ id, description });
|
|
17719
|
+
}
|
|
17720
|
+
}
|
|
17721
|
+
return next;
|
|
17722
|
+
}
|
|
17723
|
+
function meaningfulChanges(changes) {
|
|
17724
|
+
return changes.filter((change) => change.id.trim().length > 0);
|
|
17725
|
+
}
|
|
17726
|
+
async function maintainRecognitionIndexAfterWrite(args) {
|
|
17727
|
+
if (args.enabled !== true) return;
|
|
17728
|
+
const changes = meaningfulChanges(args.changes);
|
|
17729
|
+
if (changes.length === 0) return;
|
|
17730
|
+
const indexPath = recognitionIndexPath(args.memoryDir);
|
|
17731
|
+
await withIndexChain(
|
|
17732
|
+
indexPath,
|
|
17733
|
+
() => withRecognitionIndexLock(args.memoryDir, async () => {
|
|
17734
|
+
const loaded = await loadRecognitionIndex(args.memoryDir);
|
|
17735
|
+
const entries = applyChanges(loaded?.entries ?? [], changes);
|
|
17736
|
+
await saveRecognitionIndex(args.memoryDir, buildRecognitionIndex(entries));
|
|
17737
|
+
})
|
|
17738
|
+
);
|
|
17739
|
+
}
|
|
17740
|
+
|
|
17741
|
+
// src/orchestration/persistence-index.ts
|
|
17659
17742
|
var PersistenceIndexCoordinator = class {
|
|
17660
17743
|
constructor(deps) {
|
|
17661
17744
|
this.deps = deps;
|
|
@@ -17847,7 +17930,7 @@ var PersistenceIndexCoordinator = class {
|
|
|
17847
17930
|
const allMems = allMemsForGraph ?? [];
|
|
17848
17931
|
for (const m of allMems) {
|
|
17849
17932
|
if (m.frontmatter.entityRef === entityRef) {
|
|
17850
|
-
const rel =
|
|
17933
|
+
const rel = path19.relative(storage.dir, m.path);
|
|
17851
17934
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
17852
17935
|
}
|
|
17853
17936
|
}
|
|
@@ -17898,6 +17981,7 @@ var PersistenceIndexCoordinator = class {
|
|
|
17898
17981
|
* Fail-open: any error is logged but does not abort extraction.
|
|
17899
17982
|
*/
|
|
17900
17983
|
async updateTemporalTagIndexes(storage, persistedIds) {
|
|
17984
|
+
await this.maintainRecognitionIndex(storage, persistedIds);
|
|
17901
17985
|
const caps = resolveCapabilities(this.deps.config);
|
|
17902
17986
|
if (!resolveIndexingCapabilities(this.deps.config).queryAwareIndexing && !caps.parallelRetrieval && !resolveRecallEnhancementCapabilities(this.deps.config).eventOrderRecall)
|
|
17903
17987
|
return;
|
|
@@ -17998,11 +18082,51 @@ var PersistenceIndexCoordinator = class {
|
|
|
17998
18082
|
);
|
|
17999
18083
|
return enriched;
|
|
18000
18084
|
}
|
|
18085
|
+
/**
|
|
18086
|
+
* Upsert persisted memories into the namespace recognition index.
|
|
18087
|
+
* `recallRecognitionTier !== true` returns before any index I/O.
|
|
18088
|
+
* A missing index is bootstrapped from the active corpus so the first
|
|
18089
|
+
* post-enable write cannot publish a partial index that recall would
|
|
18090
|
+
* treat as the full working set.
|
|
18091
|
+
*/
|
|
18092
|
+
async maintainRecognitionIndex(storage, persistedIds) {
|
|
18093
|
+
try {
|
|
18094
|
+
if (this.deps.config.recallRecognitionTier !== true) return;
|
|
18095
|
+
const indexMissing = await loadRecognitionIndex(storage.dir) === null;
|
|
18096
|
+
if (!indexMissing && persistedIds.length === 0) return;
|
|
18097
|
+
const changes = [];
|
|
18098
|
+
const pushUpsert = (memory) => {
|
|
18099
|
+
if (!isActiveMemoryStatus(memory.frontmatter.status)) return;
|
|
18100
|
+
const memoryId = memory.frontmatter.id;
|
|
18101
|
+
if (typeof memoryId !== "string" || memoryId.trim().length === 0) return;
|
|
18102
|
+
changes.push({ action: "upsert", id: memoryId, content: memory.content ?? "" });
|
|
18103
|
+
};
|
|
18104
|
+
if (indexMissing) {
|
|
18105
|
+
const corpus = await storage.readAllMemories().catch(() => []);
|
|
18106
|
+
for (const memory of corpus) pushUpsert(memory);
|
|
18107
|
+
}
|
|
18108
|
+
for (const id of persistedIds) {
|
|
18109
|
+
let memory = await storage.getMemoryById(id);
|
|
18110
|
+
if (!memory) {
|
|
18111
|
+
const cold = await storage.getMemoryByIdIncludingArchived(id).catch(() => null);
|
|
18112
|
+
if (cold && isActiveMemoryStatus(cold.frontmatter.status)) memory = cold;
|
|
18113
|
+
}
|
|
18114
|
+
if (memory) pushUpsert(memory);
|
|
18115
|
+
}
|
|
18116
|
+
await maintainRecognitionIndexAfterWrite({
|
|
18117
|
+
memoryDir: storage.dir,
|
|
18118
|
+
enabled: true,
|
|
18119
|
+
changes
|
|
18120
|
+
});
|
|
18121
|
+
} catch (err) {
|
|
18122
|
+
log.debug(`recognition-index update error (non-fatal): ${err}`);
|
|
18123
|
+
}
|
|
18124
|
+
}
|
|
18001
18125
|
};
|
|
18002
18126
|
|
|
18003
18127
|
// src/orchestration/workspace-ops.ts
|
|
18004
18128
|
import { lstat as lstat2, mkdir as mkdir6, readFile as readFile8, readdir as readdir3, realpath as realpath2, writeFile as writeFile6 } from "fs/promises";
|
|
18005
|
-
import
|
|
18129
|
+
import path20 from "path";
|
|
18006
18130
|
|
|
18007
18131
|
// src/maintenance/pattern-reinforcement.ts
|
|
18008
18132
|
function patternReinforcementKey(content) {
|
|
@@ -19906,8 +20030,8 @@ var MeetingsService = class {
|
|
|
19906
20030
|
// src/orchestration/workspace-ops.ts
|
|
19907
20031
|
var MEETINGS_BUILD_DEBOUNCE_MS = 5e3;
|
|
19908
20032
|
function matchesMemoryPath(candidatePath, requestedPath, memoryDir) {
|
|
19909
|
-
const normalizedCandidate =
|
|
19910
|
-
return normalizedCandidate ===
|
|
20033
|
+
const normalizedCandidate = path20.resolve(candidatePath);
|
|
20034
|
+
return normalizedCandidate === path20.resolve(requestedPath) || normalizedCandidate === path20.resolve(memoryDir, requestedPath);
|
|
19911
20035
|
}
|
|
19912
20036
|
function accessTrackingPathCandidates(storageDir, memoryPath) {
|
|
19913
20037
|
const candidates = qmdResultPathCandidates(storageDir, memoryPath);
|
|
@@ -19915,12 +20039,12 @@ function accessTrackingPathCandidates(storageDir, memoryPath) {
|
|
|
19915
20039
|
if (!parts) return candidates;
|
|
19916
20040
|
candidates.push(
|
|
19917
20041
|
...qmdResultPathCandidates(storageDir, parts.relativePath),
|
|
19918
|
-
...qmdResultPathCandidates(
|
|
20042
|
+
...qmdResultPathCandidates(path20.join(storageDir, "cold"), parts.relativePath)
|
|
19919
20043
|
);
|
|
19920
20044
|
return [...new Set(candidates)];
|
|
19921
20045
|
}
|
|
19922
20046
|
function canonicalMemoryPath(memoryPath, memoryDir) {
|
|
19923
|
-
return
|
|
20047
|
+
return path20.resolve(path20.isAbsolute(memoryPath) ? memoryPath : path20.resolve(memoryDir, memoryPath));
|
|
19924
20048
|
}
|
|
19925
20049
|
var WorkspaceOpsCoordinator = class {
|
|
19926
20050
|
constructor(deps) {
|
|
@@ -20002,15 +20126,15 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20002
20126
|
this.deps.lastFileHygieneRunAtMs = now;
|
|
20003
20127
|
if (hygiene.rotateEnabled) {
|
|
20004
20128
|
for (const rel of hygiene.rotatePaths) {
|
|
20005
|
-
const abs =
|
|
20129
|
+
const abs = path20.isAbsolute(rel) ? rel : path20.join(this.deps.config.workspaceDir, rel);
|
|
20006
20130
|
try {
|
|
20007
20131
|
const raw = await readFile8(abs, "utf-8");
|
|
20008
20132
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
20009
|
-
const archiveDir =
|
|
20133
|
+
const archiveDir = path20.join(
|
|
20010
20134
|
this.deps.config.workspaceDir,
|
|
20011
20135
|
hygiene.archiveDir
|
|
20012
20136
|
);
|
|
20013
|
-
const base =
|
|
20137
|
+
const base = path20.basename(abs);
|
|
20014
20138
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
20015
20139
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
20016
20140
|
filePath: abs,
|
|
@@ -20035,8 +20159,8 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20035
20159
|
log.warn(w.message);
|
|
20036
20160
|
}
|
|
20037
20161
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
20038
|
-
const fp =
|
|
20039
|
-
await mkdir6(
|
|
20162
|
+
const fp = path20.join(this.deps.config.memoryDir, hygiene.warningsLogPath);
|
|
20163
|
+
await mkdir6(path20.dirname(fp), { recursive: true });
|
|
20040
20164
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
20041
20165
|
const block = `
|
|
20042
20166
|
|
|
@@ -20076,7 +20200,7 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20076
20200
|
for (const categoryDir of RECALL_FALLBACK_DIRS) {
|
|
20077
20201
|
if (memoryRootReal === null) break;
|
|
20078
20202
|
for (const date of datesToScan) {
|
|
20079
|
-
const dateDir =
|
|
20203
|
+
const dateDir = path20.join(storage.dir, categoryDir, date);
|
|
20080
20204
|
try {
|
|
20081
20205
|
const dirStat = await lstat2(dateDir);
|
|
20082
20206
|
if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
|
|
@@ -20085,7 +20209,7 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20085
20209
|
for (const entry of entries) {
|
|
20086
20210
|
if (entry.isSymbolicLink()) continue;
|
|
20087
20211
|
if (!entry.name.endsWith(".md")) continue;
|
|
20088
|
-
const fullPath =
|
|
20212
|
+
const fullPath = path20.join(dateDir, entry.name);
|
|
20089
20213
|
try {
|
|
20090
20214
|
assertPathInsideRoot(memoryRootReal, await realpath2(fullPath), fullPath);
|
|
20091
20215
|
const memory = await storage.readMemoryByPath(fullPath);
|
|
@@ -20107,13 +20231,13 @@ var WorkspaceOpsCoordinator = class {
|
|
|
20107
20231
|
return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
|
|
20108
20232
|
});
|
|
20109
20233
|
const hourlySummaries = [];
|
|
20110
|
-
const hourlyBaseDir =
|
|
20234
|
+
const hourlyBaseDir = path20.join(storage.dir, "summaries", "hourly");
|
|
20111
20235
|
try {
|
|
20112
20236
|
const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
|
|
20113
20237
|
for (const sk of sessionKeys) {
|
|
20114
20238
|
if (!sk.isDirectory()) continue;
|
|
20115
20239
|
for (const date of datesToScan) {
|
|
20116
|
-
const summaryFile =
|
|
20240
|
+
const summaryFile = path20.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
20117
20241
|
try {
|
|
20118
20242
|
const raw = await readFile8(summaryFile, "utf-8");
|
|
20119
20243
|
const filtered = filterHourlySummaryMarkdownForLocalDay(
|
|
@@ -20590,18 +20714,18 @@ ${reflectionsContent.trim()}
|
|
|
20590
20714
|
// src/orchestration/namespace-read-fanout.ts
|
|
20591
20715
|
import { existsSync, readFileSync } from "fs";
|
|
20592
20716
|
import { stat as stat3 } from "fs/promises";
|
|
20593
|
-
import
|
|
20717
|
+
import path22 from "path";
|
|
20594
20718
|
|
|
20595
20719
|
// src/orchestration/orchestrator-namespace-scope.ts
|
|
20596
|
-
import
|
|
20720
|
+
import path21 from "path";
|
|
20597
20721
|
function computeSemanticDedupScope(targetStorage, config) {
|
|
20598
20722
|
if (!resolveNamespaceCapabilities(config).namespaces) return {};
|
|
20599
|
-
const memoryDir =
|
|
20600
|
-
const storageDir =
|
|
20723
|
+
const memoryDir = path21.resolve(config.memoryDir);
|
|
20724
|
+
const storageDir = path21.resolve(targetStorage.dir);
|
|
20601
20725
|
if (storageDir === memoryDir) {
|
|
20602
20726
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
20603
20727
|
}
|
|
20604
|
-
let rel =
|
|
20728
|
+
let rel = path21.relative(memoryDir, storageDir);
|
|
20605
20729
|
if (!rel || rel.startsWith("..")) {
|
|
20606
20730
|
log.debug(
|
|
20607
20731
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -20654,7 +20778,7 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20654
20778
|
loadNamespaceStorageDirHintsFromCatalog() {
|
|
20655
20779
|
if (this.deps.namespaceStorageDirHintsLoaded || !this.deps.namespaceCatalog.enabled) return;
|
|
20656
20780
|
this.deps.namespaceStorageDirHintsLoaded = true;
|
|
20657
|
-
const catalogPath =
|
|
20781
|
+
const catalogPath = path22.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
|
|
20658
20782
|
if (!existsSync(catalogPath)) return;
|
|
20659
20783
|
let body;
|
|
20660
20784
|
try {
|
|
@@ -20691,7 +20815,7 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20691
20815
|
if (!this.deps.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
|
|
20692
20816
|
continue;
|
|
20693
20817
|
}
|
|
20694
|
-
const resolvedStorageDir =
|
|
20818
|
+
const resolvedStorageDir = path22.resolve(record.storageDir);
|
|
20695
20819
|
const current = preferredByStorageDir.get(resolvedStorageDir);
|
|
20696
20820
|
preferredByStorageDir.set(
|
|
20697
20821
|
resolvedStorageDir,
|
|
@@ -20876,12 +21000,12 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20876
21000
|
}
|
|
20877
21001
|
async resolveStateDirForNamespace(namespace) {
|
|
20878
21002
|
if (!resolveNamespaceCapabilities(this.deps.config).namespaces) {
|
|
20879
|
-
return
|
|
21003
|
+
return path22.join(this.deps.config.memoryDir, "state");
|
|
20880
21004
|
}
|
|
20881
21005
|
if (namespace !== this.deps.config.defaultNamespace) {
|
|
20882
|
-
return
|
|
21006
|
+
return path22.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
|
|
20883
21007
|
}
|
|
20884
|
-
const candidate =
|
|
21008
|
+
const candidate = path22.join(
|
|
20885
21009
|
this.deps.config.memoryDir,
|
|
20886
21010
|
"namespaces",
|
|
20887
21011
|
this.deps.config.defaultNamespace
|
|
@@ -20889,11 +21013,11 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
20889
21013
|
try {
|
|
20890
21014
|
const candidateStat = await stat3(candidate);
|
|
20891
21015
|
if (candidateStat.isDirectory()) {
|
|
20892
|
-
return
|
|
21016
|
+
return path22.join(candidate, "state");
|
|
20893
21017
|
}
|
|
20894
21018
|
} catch {
|
|
20895
21019
|
}
|
|
20896
|
-
return
|
|
21020
|
+
return path22.join(this.deps.config.memoryDir, "state");
|
|
20897
21021
|
}
|
|
20898
21022
|
namespaceFromPath(p) {
|
|
20899
21023
|
if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return this.deps.config.defaultNamespace;
|
|
@@ -21348,7 +21472,7 @@ var Orchestrator = class {
|
|
|
21348
21472
|
if (this.destroyed) throw new Error("orchestrator has been destroyed");
|
|
21349
21473
|
if (!this._dependencyPropagationDelivery) {
|
|
21350
21474
|
this._dependencyPropagationDelivery = new DependencyPropagationDelivery({
|
|
21351
|
-
queueRoot:
|
|
21475
|
+
queueRoot: path23.join(this.config.memoryDir, "state", "dependency-propagation"),
|
|
21352
21476
|
config: this.config,
|
|
21353
21477
|
extraction: this.extraction,
|
|
21354
21478
|
getStorage: (namespace) => this.getStorage(namespace),
|
|
@@ -21703,7 +21827,7 @@ var Orchestrator = class {
|
|
|
21703
21827
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
21704
21828
|
if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
|
|
21705
21829
|
if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
|
|
21706
|
-
const resolvedStorageDir =
|
|
21830
|
+
const resolvedStorageDir = path23.resolve(storageDir);
|
|
21707
21831
|
let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
|
|
21708
21832
|
if (!hints) {
|
|
21709
21833
|
hints = /* @__PURE__ */ new Set();
|
|
@@ -21714,21 +21838,21 @@ var Orchestrator = class {
|
|
|
21714
21838
|
storageDirMatchesNamespaceHint(namespace, storageDir) {
|
|
21715
21839
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
21716
21840
|
if (!ns) return false;
|
|
21717
|
-
const resolvedStorageDir =
|
|
21718
|
-
const resolvedMemoryDir =
|
|
21841
|
+
const resolvedStorageDir = path23.resolve(storageDir);
|
|
21842
|
+
const resolvedMemoryDir = path23.resolve(this.config.memoryDir);
|
|
21719
21843
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
21720
21844
|
if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
|
|
21721
|
-
const resolvedNamespacesDir =
|
|
21845
|
+
const resolvedNamespacesDir = path23.join(resolvedMemoryDir, "namespaces");
|
|
21722
21846
|
if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
|
|
21723
|
-
const rawRoot =
|
|
21724
|
-
const tokenRoot =
|
|
21847
|
+
const rawRoot = path23.resolve(resolvedNamespacesDir, ns);
|
|
21848
|
+
const tokenRoot = path23.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
|
|
21725
21849
|
return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
|
|
21726
21850
|
}
|
|
21727
21851
|
namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
|
|
21728
|
-
if (resolvedStorageDir ===
|
|
21852
|
+
if (resolvedStorageDir === path23.resolve(this.config.memoryDir)) {
|
|
21729
21853
|
return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
|
|
21730
21854
|
}
|
|
21731
|
-
const leaf =
|
|
21855
|
+
const leaf = path23.basename(resolvedStorageDir);
|
|
21732
21856
|
const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
|
|
21733
21857
|
if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
|
|
21734
21858
|
if (record.namespace === leaf) return 1;
|
|
@@ -21869,7 +21993,7 @@ var Orchestrator = class {
|
|
|
21869
21993
|
StorageManager.setOkfConformanceDefault(config.memoryDir, config.okf?.conformanceEnabled);
|
|
21870
21994
|
this.profiler = new ProfilingCollector({
|
|
21871
21995
|
enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
|
|
21872
|
-
storageDir: config.profilingStorageDir ||
|
|
21996
|
+
storageDir: config.profilingStorageDir || path23.join(config.memoryDir, "profiling"),
|
|
21873
21997
|
maxTraces: config.profilingMaxTraces
|
|
21874
21998
|
});
|
|
21875
21999
|
this.namespaceCatalog = new NamespaceCatalog(config);
|
|
@@ -21956,7 +22080,7 @@ var Orchestrator = class {
|
|
|
21956
22080
|
this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
|
|
21957
22081
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
21958
22082
|
this.transcript = new TranscriptManager(config);
|
|
21959
|
-
this.conversationIndexDir =
|
|
22083
|
+
this.conversationIndexDir = path23.join(
|
|
21960
22084
|
config.memoryDir,
|
|
21961
22085
|
"conversation-index",
|
|
21962
22086
|
"chunks"
|
|
@@ -22107,7 +22231,7 @@ var Orchestrator = class {
|
|
|
22107
22231
|
getHandleHistory: () => this.handleHistory
|
|
22108
22232
|
});
|
|
22109
22233
|
this.threading = new ThreadingManager(
|
|
22110
|
-
|
|
22234
|
+
path23.join(config.memoryDir, "threads"),
|
|
22111
22235
|
config.threadingGapMinutes
|
|
22112
22236
|
);
|
|
22113
22237
|
const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
|
|
@@ -24200,9 +24324,9 @@ function readStructuralSymbol(entry) {
|
|
|
24200
24324
|
const rec = entry;
|
|
24201
24325
|
const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
|
|
24202
24326
|
if (!symbol) return null;
|
|
24203
|
-
const
|
|
24327
|
+
const path42 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
|
|
24204
24328
|
const kind = typeof rec.kind === "string" && rec.kind.length > 0 ? rec.kind : void 0;
|
|
24205
|
-
const item =
|
|
24329
|
+
const item = path42 !== void 0 && kind !== void 0 ? { symbol, path: path42, kind } : path42 !== void 0 ? { symbol, path: path42 } : kind !== void 0 ? { symbol, kind } : { symbol };
|
|
24206
24330
|
return item;
|
|
24207
24331
|
}
|
|
24208
24332
|
function classifySpawnError(err) {
|
|
@@ -24275,8 +24399,8 @@ var DEFAULT_MAX_BINARY_SIZE_BYTES = 50 * 1024 * 1024;
|
|
|
24275
24399
|
var DEFAULT_GRACE_PERIOD_DAYS = 7;
|
|
24276
24400
|
|
|
24277
24401
|
// src/binary-lifecycle/backend.ts
|
|
24278
|
-
import
|
|
24279
|
-
import
|
|
24402
|
+
import fsp2 from "fs/promises";
|
|
24403
|
+
import path24 from "path";
|
|
24280
24404
|
var FilesystemBackend = class {
|
|
24281
24405
|
type = "filesystem";
|
|
24282
24406
|
basePath;
|
|
@@ -24284,30 +24408,30 @@ var FilesystemBackend = class {
|
|
|
24284
24408
|
if (!basePath || basePath.trim().length === 0) {
|
|
24285
24409
|
throw new Error("FilesystemBackend requires a non-empty basePath");
|
|
24286
24410
|
}
|
|
24287
|
-
this.basePath =
|
|
24411
|
+
this.basePath = path24.resolve(basePath);
|
|
24288
24412
|
}
|
|
24289
24413
|
resolveRemotePath(remotePath) {
|
|
24290
|
-
const resolved =
|
|
24291
|
-
const relative =
|
|
24292
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
24414
|
+
const resolved = path24.isAbsolute(remotePath) ? path24.resolve(remotePath) : path24.resolve(this.basePath, remotePath);
|
|
24415
|
+
const relative = path24.relative(this.basePath, resolved);
|
|
24416
|
+
if (relative === ".." || relative.startsWith(`..${path24.sep}`) || path24.isAbsolute(relative)) {
|
|
24293
24417
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24294
24418
|
}
|
|
24295
24419
|
return resolved;
|
|
24296
24420
|
}
|
|
24297
24421
|
isInsideBase(candidate, realBase) {
|
|
24298
|
-
const relative =
|
|
24299
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
24422
|
+
const relative = path24.relative(realBase, candidate);
|
|
24423
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path24.sep}`) && !path24.isAbsolute(relative);
|
|
24300
24424
|
}
|
|
24301
24425
|
async realBasePathIfExists() {
|
|
24302
24426
|
try {
|
|
24303
|
-
const stat5 = await
|
|
24427
|
+
const stat5 = await fsp2.lstat(this.basePath);
|
|
24304
24428
|
if (stat5.isSymbolicLink()) {
|
|
24305
24429
|
throw new Error(`FilesystemBackend basePath must not be a symlink: ${this.basePath}`);
|
|
24306
24430
|
}
|
|
24307
24431
|
if (!stat5.isDirectory()) {
|
|
24308
24432
|
throw new Error(`FilesystemBackend basePath must be a directory: ${this.basePath}`);
|
|
24309
24433
|
}
|
|
24310
|
-
return await
|
|
24434
|
+
return await fsp2.realpath(this.basePath);
|
|
24311
24435
|
} catch (err) {
|
|
24312
24436
|
if (err.code === "ENOENT") {
|
|
24313
24437
|
return null;
|
|
@@ -24316,7 +24440,7 @@ var FilesystemBackend = class {
|
|
|
24316
24440
|
}
|
|
24317
24441
|
}
|
|
24318
24442
|
async ensureBaseDirectory() {
|
|
24319
|
-
await
|
|
24443
|
+
await fsp2.mkdir(this.basePath, { recursive: true });
|
|
24320
24444
|
const realBase = await this.realBasePathIfExists();
|
|
24321
24445
|
if (realBase === null) {
|
|
24322
24446
|
throw new Error(`FilesystemBackend failed to create basePath: ${this.basePath}`);
|
|
@@ -24325,15 +24449,15 @@ var FilesystemBackend = class {
|
|
|
24325
24449
|
}
|
|
24326
24450
|
async ensureSafeParentDirectory(dest) {
|
|
24327
24451
|
const realBase = await this.ensureBaseDirectory();
|
|
24328
|
-
const destDir =
|
|
24329
|
-
const relativeDir =
|
|
24330
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
24452
|
+
const destDir = path24.dirname(dest);
|
|
24453
|
+
const relativeDir = path24.relative(this.basePath, destDir);
|
|
24454
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path24.sep);
|
|
24331
24455
|
let current = this.basePath;
|
|
24332
24456
|
for (const segment of segments) {
|
|
24333
24457
|
if (segment === "." || segment === "") continue;
|
|
24334
|
-
current =
|
|
24458
|
+
current = path24.join(current, segment);
|
|
24335
24459
|
try {
|
|
24336
|
-
const stat5 = await
|
|
24460
|
+
const stat5 = await fsp2.lstat(current);
|
|
24337
24461
|
if (stat5.isSymbolicLink()) {
|
|
24338
24462
|
throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);
|
|
24339
24463
|
}
|
|
@@ -24344,10 +24468,10 @@ var FilesystemBackend = class {
|
|
|
24344
24468
|
if (err.code !== "ENOENT") {
|
|
24345
24469
|
throw err;
|
|
24346
24470
|
}
|
|
24347
|
-
await
|
|
24471
|
+
await fsp2.mkdir(current);
|
|
24348
24472
|
}
|
|
24349
24473
|
}
|
|
24350
|
-
const realParent = await
|
|
24474
|
+
const realParent = await fsp2.realpath(destDir);
|
|
24351
24475
|
if (!this.isInsideBase(realParent, realBase)) {
|
|
24352
24476
|
throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${dest}`);
|
|
24353
24477
|
}
|
|
@@ -24359,16 +24483,16 @@ var FilesystemBackend = class {
|
|
|
24359
24483
|
if (realBase === null) {
|
|
24360
24484
|
return null;
|
|
24361
24485
|
}
|
|
24362
|
-
const destDir =
|
|
24363
|
-
const relativeDir =
|
|
24364
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
24486
|
+
const destDir = path24.dirname(dest);
|
|
24487
|
+
const relativeDir = path24.relative(this.basePath, destDir);
|
|
24488
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path24.sep);
|
|
24365
24489
|
let current = this.basePath;
|
|
24366
24490
|
for (const segment of segments) {
|
|
24367
24491
|
if (segment === "." || segment === "") continue;
|
|
24368
|
-
current =
|
|
24492
|
+
current = path24.join(current, segment);
|
|
24369
24493
|
let stat5;
|
|
24370
24494
|
try {
|
|
24371
|
-
stat5 = await
|
|
24495
|
+
stat5 = await fsp2.lstat(current);
|
|
24372
24496
|
} catch (err) {
|
|
24373
24497
|
if (err.code === "ENOENT") {
|
|
24374
24498
|
return null;
|
|
@@ -24382,7 +24506,7 @@ var FilesystemBackend = class {
|
|
|
24382
24506
|
return null;
|
|
24383
24507
|
}
|
|
24384
24508
|
}
|
|
24385
|
-
const realParent = await
|
|
24509
|
+
const realParent = await fsp2.realpath(destDir).catch((err) => {
|
|
24386
24510
|
if (isErrnoCode(err, "ENOENT")) return null;
|
|
24387
24511
|
throw err;
|
|
24388
24512
|
});
|
|
@@ -24393,7 +24517,7 @@ var FilesystemBackend = class {
|
|
|
24393
24517
|
throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24394
24518
|
}
|
|
24395
24519
|
try {
|
|
24396
|
-
const stat5 = await
|
|
24520
|
+
const stat5 = await fsp2.lstat(dest);
|
|
24397
24521
|
if (stat5.isSymbolicLink()) {
|
|
24398
24522
|
throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);
|
|
24399
24523
|
}
|
|
@@ -24406,20 +24530,20 @@ var FilesystemBackend = class {
|
|
|
24406
24530
|
}
|
|
24407
24531
|
throw err;
|
|
24408
24532
|
}
|
|
24409
|
-
const realDest = await
|
|
24533
|
+
const realDest = await fsp2.realpath(dest);
|
|
24410
24534
|
if (!this.isInsideBase(realDest, realBase)) {
|
|
24411
24535
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24412
24536
|
}
|
|
24413
24537
|
return dest;
|
|
24414
24538
|
}
|
|
24415
24539
|
async upload(localPath, remotePath) {
|
|
24416
|
-
if (
|
|
24540
|
+
if (path24.isAbsolute(remotePath)) {
|
|
24417
24541
|
throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);
|
|
24418
24542
|
}
|
|
24419
24543
|
const dest = this.resolveRemotePath(remotePath);
|
|
24420
24544
|
const realBase = await this.ensureSafeParentDirectory(dest);
|
|
24421
24545
|
try {
|
|
24422
|
-
const stat5 = await
|
|
24546
|
+
const stat5 = await fsp2.lstat(dest);
|
|
24423
24547
|
if (stat5.isSymbolicLink()) {
|
|
24424
24548
|
throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);
|
|
24425
24549
|
}
|
|
@@ -24428,8 +24552,8 @@ var FilesystemBackend = class {
|
|
|
24428
24552
|
throw err;
|
|
24429
24553
|
}
|
|
24430
24554
|
}
|
|
24431
|
-
await
|
|
24432
|
-
const realDest = await
|
|
24555
|
+
await fsp2.copyFile(localPath, dest);
|
|
24556
|
+
const realDest = await fsp2.realpath(dest);
|
|
24433
24557
|
if (!this.isInsideBase(realDest, realBase)) {
|
|
24434
24558
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24435
24559
|
}
|
|
@@ -24445,7 +24569,7 @@ var FilesystemBackend = class {
|
|
|
24445
24569
|
return;
|
|
24446
24570
|
}
|
|
24447
24571
|
try {
|
|
24448
|
-
await
|
|
24572
|
+
await fsp2.unlink(dest);
|
|
24449
24573
|
} catch (err) {
|
|
24450
24574
|
if (err.code !== "ENOENT") throw err;
|
|
24451
24575
|
}
|
|
@@ -24485,8 +24609,8 @@ function createBackend(cfg) {
|
|
|
24485
24609
|
}
|
|
24486
24610
|
|
|
24487
24611
|
// src/binary-lifecycle/scanner.ts
|
|
24488
|
-
import
|
|
24489
|
-
import
|
|
24612
|
+
import fsp3 from "fs/promises";
|
|
24613
|
+
import path25 from "path";
|
|
24490
24614
|
import crypto from "crypto";
|
|
24491
24615
|
function matchesPatterns(filename, patterns) {
|
|
24492
24616
|
const lower = filename.toLowerCase();
|
|
@@ -24506,13 +24630,13 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24506
24630
|
async function walk(dir) {
|
|
24507
24631
|
let entries;
|
|
24508
24632
|
try {
|
|
24509
|
-
entries = await
|
|
24633
|
+
entries = await fsp3.readdir(dir, { withFileTypes: true });
|
|
24510
24634
|
} catch {
|
|
24511
24635
|
return;
|
|
24512
24636
|
}
|
|
24513
24637
|
for (const entry of entries) {
|
|
24514
|
-
const fullPath =
|
|
24515
|
-
const relativePath =
|
|
24638
|
+
const fullPath = path25.join(dir, entry.name);
|
|
24639
|
+
const relativePath = path25.relative(memoryDir, fullPath).split(path25.sep).join("/");
|
|
24516
24640
|
if (entry.isDirectory()) {
|
|
24517
24641
|
if (entry.name === ".binary-lifecycle") continue;
|
|
24518
24642
|
await walk(fullPath);
|
|
@@ -24521,7 +24645,7 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24521
24645
|
if (!entry.isFile()) continue;
|
|
24522
24646
|
if (!matchesPatterns(entry.name, config.scanPatterns)) continue;
|
|
24523
24647
|
try {
|
|
24524
|
-
const stat5 = await
|
|
24648
|
+
const stat5 = await fsp3.stat(fullPath);
|
|
24525
24649
|
if (stat5.size > config.maxBinarySizeBytes) continue;
|
|
24526
24650
|
if (stat5.size === 0) continue;
|
|
24527
24651
|
const existing = tracked.get(relativePath);
|
|
@@ -24546,27 +24670,27 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24546
24670
|
return results;
|
|
24547
24671
|
}
|
|
24548
24672
|
async function hashFile(filePath) {
|
|
24549
|
-
const content = await
|
|
24673
|
+
const content = await fsp3.readFile(filePath);
|
|
24550
24674
|
return crypto.createHash("sha256").update(content).digest("hex");
|
|
24551
24675
|
}
|
|
24552
24676
|
|
|
24553
24677
|
// src/binary-lifecycle/manifest.ts
|
|
24554
|
-
import
|
|
24555
|
-
import
|
|
24678
|
+
import fsp4 from "fs/promises";
|
|
24679
|
+
import path26 from "path";
|
|
24556
24680
|
import crypto2 from "crypto";
|
|
24557
24681
|
var MANIFEST_DIR = ".binary-lifecycle";
|
|
24558
24682
|
var MANIFEST_FILE = "manifest.json";
|
|
24559
24683
|
function manifestDir(memoryDir) {
|
|
24560
|
-
return
|
|
24684
|
+
return path26.join(memoryDir, MANIFEST_DIR);
|
|
24561
24685
|
}
|
|
24562
24686
|
function manifestPath(memoryDir) {
|
|
24563
|
-
return
|
|
24687
|
+
return path26.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
|
|
24564
24688
|
}
|
|
24565
24689
|
async function readManifest(memoryDir) {
|
|
24566
24690
|
const filePath = manifestPath(memoryDir);
|
|
24567
24691
|
let raw;
|
|
24568
24692
|
try {
|
|
24569
|
-
raw = await
|
|
24693
|
+
raw = await fsp4.readFile(filePath, "utf-8");
|
|
24570
24694
|
} catch (err) {
|
|
24571
24695
|
if (err.code === "ENOENT") {
|
|
24572
24696
|
return emptyManifest();
|
|
@@ -24590,17 +24714,17 @@ async function readManifest(memoryDir) {
|
|
|
24590
24714
|
}
|
|
24591
24715
|
async function writeManifest(memoryDir, manifest) {
|
|
24592
24716
|
const dir = manifestDir(memoryDir);
|
|
24593
|
-
await
|
|
24717
|
+
await fsp4.mkdir(dir, { recursive: true });
|
|
24594
24718
|
const dest = manifestPath(memoryDir);
|
|
24595
24719
|
const tmpSuffix = crypto2.randomBytes(8).toString("hex");
|
|
24596
24720
|
const tmpPath = `${dest}.${tmpSuffix}.tmp`;
|
|
24597
24721
|
const content = JSON.stringify(manifest, null, 2) + "\n";
|
|
24598
|
-
await
|
|
24722
|
+
await fsp4.writeFile(tmpPath, content, "utf-8");
|
|
24599
24723
|
try {
|
|
24600
|
-
await
|
|
24724
|
+
await fsp4.rename(tmpPath, dest);
|
|
24601
24725
|
} catch (renameErr) {
|
|
24602
24726
|
try {
|
|
24603
|
-
await
|
|
24727
|
+
await fsp4.unlink(tmpPath);
|
|
24604
24728
|
} catch {
|
|
24605
24729
|
}
|
|
24606
24730
|
throw renameErr;
|
|
@@ -24611,18 +24735,18 @@ function emptyManifest() {
|
|
|
24611
24735
|
}
|
|
24612
24736
|
|
|
24613
24737
|
// src/binary-lifecycle/pipeline.ts
|
|
24614
|
-
import
|
|
24615
|
-
import
|
|
24738
|
+
import fsp5 from "fs/promises";
|
|
24739
|
+
import path27 from "path";
|
|
24616
24740
|
import crypto3 from "crypto";
|
|
24617
24741
|
var historicalIdCache = new HistoricalEntityCanonicalIdCache();
|
|
24618
24742
|
function isRecallCorpusMarkdown(mdPath, memoryDir) {
|
|
24619
|
-
const rel =
|
|
24620
|
-
if (rel.startsWith("..") ||
|
|
24621
|
-
const top = rel.split(
|
|
24743
|
+
const rel = path27.relative(memoryDir, mdPath);
|
|
24744
|
+
if (rel.startsWith("..") || path27.isAbsolute(rel)) return false;
|
|
24745
|
+
const top = rel.split(path27.sep)[0];
|
|
24622
24746
|
return RECALL_FALLBACK_DIRS.includes(top);
|
|
24623
24747
|
}
|
|
24624
24748
|
async function hashFile2(filePath) {
|
|
24625
|
-
const content = await
|
|
24749
|
+
const content = await fsp5.readFile(filePath);
|
|
24626
24750
|
return crypto3.createHash("sha256").update(content).digest("hex");
|
|
24627
24751
|
}
|
|
24628
24752
|
function guessMimeType(ext) {
|
|
@@ -24642,13 +24766,13 @@ function escapeRegex(s) {
|
|
|
24642
24766
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
24643
24767
|
}
|
|
24644
24768
|
function resolveManifestAssetPath(memoryDir, originalPath) {
|
|
24645
|
-
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") ||
|
|
24769
|
+
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path27.isAbsolute(originalPath) || path27.win32.isAbsolute(originalPath)) {
|
|
24646
24770
|
return null;
|
|
24647
24771
|
}
|
|
24648
|
-
const memoryRoot =
|
|
24649
|
-
const fullPath =
|
|
24650
|
-
const relative =
|
|
24651
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
24772
|
+
const memoryRoot = path27.resolve(memoryDir);
|
|
24773
|
+
const fullPath = path27.resolve(memoryRoot, originalPath);
|
|
24774
|
+
const relative = path27.relative(memoryRoot, fullPath);
|
|
24775
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path27.sep}`) || path27.isAbsolute(relative)) {
|
|
24652
24776
|
return null;
|
|
24653
24777
|
}
|
|
24654
24778
|
return fullPath;
|
|
@@ -24659,7 +24783,7 @@ function validateBinaryLifecycleConfig(config) {
|
|
|
24659
24783
|
}
|
|
24660
24784
|
}
|
|
24661
24785
|
function remotePathForAsset(backend, relPath) {
|
|
24662
|
-
const normalized = relPath.split(
|
|
24786
|
+
const normalized = relPath.split(path27.sep).join("/");
|
|
24663
24787
|
if (backend.type === "filesystem") {
|
|
24664
24788
|
return `.binary-lifecycle/mirrors/${normalized}`;
|
|
24665
24789
|
}
|
|
@@ -24672,11 +24796,11 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
|
|
|
24672
24796
|
let mirrored = 0;
|
|
24673
24797
|
const errors = [];
|
|
24674
24798
|
for (const relPath of newPaths) {
|
|
24675
|
-
const fullPath =
|
|
24799
|
+
const fullPath = path27.join(memoryDir, relPath);
|
|
24676
24800
|
try {
|
|
24677
|
-
const stat5 = await
|
|
24801
|
+
const stat5 = await fsp5.stat(fullPath);
|
|
24678
24802
|
const contentHash = await hashFile2(fullPath);
|
|
24679
|
-
const ext =
|
|
24803
|
+
const ext = path27.extname(relPath);
|
|
24680
24804
|
const mimeType = guessMimeType(ext);
|
|
24681
24805
|
const remotePath = remotePathForAsset(backend, relPath);
|
|
24682
24806
|
let backendLocation = remotePath;
|
|
@@ -24827,7 +24951,7 @@ async function stageRedirect(memoryDir, assets, log2, dryRun, readMarkdownFile,
|
|
|
24827
24951
|
for (const update of updates) {
|
|
24828
24952
|
try {
|
|
24829
24953
|
await withRawEntityPageMutation(memoryDir, update.mdPath, async () => {
|
|
24830
|
-
const stateDir =
|
|
24954
|
+
const stateDir = path27.join(memoryDir, "state");
|
|
24831
24955
|
const kind = classifyEntityRefWritePath(memoryDir, update.mdPath);
|
|
24832
24956
|
if (kind === "memory") {
|
|
24833
24957
|
const idsAtWrite = historicalIdCache.get(stateDir);
|
|
@@ -24920,10 +25044,10 @@ async function countRemainingLocalReferences(memoryDir, asset, assetAbsolute, md
|
|
|
24920
25044
|
return { remaining, errors };
|
|
24921
25045
|
}
|
|
24922
25046
|
function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
24923
|
-
const mdDir =
|
|
25047
|
+
const mdDir = path27.dirname(mdPath);
|
|
24924
25048
|
const candidates = /* @__PURE__ */ new Set();
|
|
24925
25049
|
const addCandidate = (candidate) => {
|
|
24926
|
-
const normalized = candidate.split(
|
|
25050
|
+
const normalized = candidate.split(path27.sep).join("/");
|
|
24927
25051
|
if (normalized.length === 0) return;
|
|
24928
25052
|
candidates.add(normalized);
|
|
24929
25053
|
const isParentTraversal = normalized === ".." || normalized.startsWith("../");
|
|
@@ -24931,10 +25055,10 @@ function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
|
24931
25055
|
candidates.add(`./${normalized}`);
|
|
24932
25056
|
}
|
|
24933
25057
|
};
|
|
24934
|
-
addCandidate(
|
|
24935
|
-
const originalPath = asset.originalPath.split(
|
|
24936
|
-
const originalAsFileRelative =
|
|
24937
|
-
if (
|
|
25058
|
+
addCandidate(path27.relative(mdDir, assetAbsolute));
|
|
25059
|
+
const originalPath = asset.originalPath.split(path27.sep).join("/");
|
|
25060
|
+
const originalAsFileRelative = path27.resolve(mdDir, ...originalPath.split("/"));
|
|
25061
|
+
if (path27.resolve(originalAsFileRelative) === path27.resolve(assetAbsolute)) {
|
|
24938
25062
|
addCandidate(originalPath);
|
|
24939
25063
|
}
|
|
24940
25064
|
addCandidate(`/${originalPath}`);
|
|
@@ -24998,7 +25122,7 @@ async function stageClean(memoryDir, assets, backend, gracePeriodDays, log2, dry
|
|
|
24998
25122
|
continue;
|
|
24999
25123
|
}
|
|
25000
25124
|
if (!dryRun) {
|
|
25001
|
-
await
|
|
25125
|
+
await fsp5.unlink(fullPath);
|
|
25002
25126
|
asset.status = "cleaned";
|
|
25003
25127
|
asset.cleanedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25004
25128
|
}
|
|
@@ -25025,12 +25149,12 @@ async function findMarkdownFiles(dir) {
|
|
|
25025
25149
|
async function walk(current) {
|
|
25026
25150
|
let entries;
|
|
25027
25151
|
try {
|
|
25028
|
-
entries = await
|
|
25152
|
+
entries = await fsp5.readdir(current, { withFileTypes: true });
|
|
25029
25153
|
} catch {
|
|
25030
25154
|
return;
|
|
25031
25155
|
}
|
|
25032
25156
|
for (const entry of entries) {
|
|
25033
|
-
const full =
|
|
25157
|
+
const full = path27.join(current, entry.name);
|
|
25034
25158
|
if (entry.isDirectory()) {
|
|
25035
25159
|
if (entry.name === ".binary-lifecycle") continue;
|
|
25036
25160
|
await walk(full);
|
|
@@ -25072,8 +25196,8 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
|
|
|
25072
25196
|
manifest.assets,
|
|
25073
25197
|
log2,
|
|
25074
25198
|
dryRun,
|
|
25075
|
-
opts?.readMarkdownFile ?? ((filePath) =>
|
|
25076
|
-
opts?.writeMarkdownFile ?? ((filePath, content) =>
|
|
25199
|
+
opts?.readMarkdownFile ?? ((filePath) => fsp5.readFile(filePath, "utf-8")),
|
|
25200
|
+
opts?.writeMarkdownFile ?? ((filePath, content) => fsp5.writeFile(filePath, content, "utf-8"))
|
|
25077
25201
|
);
|
|
25078
25202
|
const cleanResult = await stageClean(
|
|
25079
25203
|
memoryDir,
|
|
@@ -25105,7 +25229,7 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
|
|
|
25105
25229
|
|
|
25106
25230
|
// src/projection/index.ts
|
|
25107
25231
|
import fs from "fs";
|
|
25108
|
-
import
|
|
25232
|
+
import path28 from "path";
|
|
25109
25233
|
var VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);
|
|
25110
25234
|
async function generateContextTree(options) {
|
|
25111
25235
|
const startTime = Date.now();
|
|
@@ -25120,8 +25244,8 @@ async function generateContextTree(options) {
|
|
|
25120
25244
|
let nodesGenerated = 0;
|
|
25121
25245
|
let nodesSkipped = 0;
|
|
25122
25246
|
const categoryCounts = {};
|
|
25123
|
-
const resolvedMemoryDir =
|
|
25124
|
-
const resolvedOutputDir =
|
|
25247
|
+
const resolvedMemoryDir = path28.resolve(memoryDir);
|
|
25248
|
+
const resolvedOutputDir = path28.resolve(outputDir);
|
|
25125
25249
|
const requestedCategories = validateProjectionCategories(filterCategories);
|
|
25126
25250
|
const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);
|
|
25127
25251
|
assertNotSymlink(resolvedOutputDir, "context tree outputDir");
|
|
@@ -25159,7 +25283,7 @@ async function generateContextTree(options) {
|
|
|
25159
25283
|
}
|
|
25160
25284
|
}
|
|
25161
25285
|
if (includeEntities) {
|
|
25162
|
-
const entitiesDir =
|
|
25286
|
+
const entitiesDir = path28.join(memoryDir, "entities");
|
|
25163
25287
|
if (fs.existsSync(entitiesDir)) {
|
|
25164
25288
|
assertSafeInputRoot(realMemoryDir, entitiesDir, "entities root");
|
|
25165
25289
|
categoryCounts["entity"] = 0;
|
|
@@ -25171,7 +25295,7 @@ async function generateContextTree(options) {
|
|
|
25171
25295
|
continue;
|
|
25172
25296
|
}
|
|
25173
25297
|
const content = fs.readFileSync(filePath, "utf8");
|
|
25174
|
-
const fileName =
|
|
25298
|
+
const fileName = path28.basename(filePath, ".md");
|
|
25175
25299
|
const node = projectEntityNode(fileName, content);
|
|
25176
25300
|
const outputPath = resolveContainedOutputPath(realOutputDir, "entities", `${fileName}.md`);
|
|
25177
25301
|
writeProjectedContent(realOutputDir, outputPath, node.content);
|
|
@@ -25183,7 +25307,7 @@ async function generateContextTree(options) {
|
|
|
25183
25307
|
}
|
|
25184
25308
|
const shouldIncludeQuestions = includeQuestions && (requestedCategories === void 0 || requestedCategories.includes("question"));
|
|
25185
25309
|
if (shouldIncludeQuestions) {
|
|
25186
|
-
const questionsDir =
|
|
25310
|
+
const questionsDir = path28.join(memoryDir, "questions");
|
|
25187
25311
|
if (fs.existsSync(questionsDir)) {
|
|
25188
25312
|
assertSafeInputRoot(realMemoryDir, questionsDir, "questions root");
|
|
25189
25313
|
categoryCounts["question"] = 0;
|
|
@@ -25224,8 +25348,8 @@ async function generateContextTree(options) {
|
|
|
25224
25348
|
};
|
|
25225
25349
|
}
|
|
25226
25350
|
function isPathInside(root, candidate) {
|
|
25227
|
-
const relative =
|
|
25228
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
25351
|
+
const relative = path28.relative(root, candidate);
|
|
25352
|
+
return relative === "" || !relative.startsWith("..") && !path28.isAbsolute(relative);
|
|
25229
25353
|
}
|
|
25230
25354
|
function assertNotSymlink(targetPath, label) {
|
|
25231
25355
|
try {
|
|
@@ -25262,12 +25386,12 @@ function assertSafeInputRoot(realMemoryDir, targetPath, label) {
|
|
|
25262
25386
|
}
|
|
25263
25387
|
function assertSafeOutputTarget(realOutputDir, outputPath) {
|
|
25264
25388
|
let current = realOutputDir;
|
|
25265
|
-
const relative =
|
|
25266
|
-
if (relative.startsWith("..") ||
|
|
25389
|
+
const relative = path28.relative(realOutputDir, outputPath);
|
|
25390
|
+
if (relative.startsWith("..") || path28.isAbsolute(relative)) {
|
|
25267
25391
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
25268
25392
|
}
|
|
25269
|
-
for (const segment of relative.split(
|
|
25270
|
-
current =
|
|
25393
|
+
for (const segment of relative.split(path28.sep).filter(Boolean)) {
|
|
25394
|
+
current = path28.join(current, segment);
|
|
25271
25395
|
try {
|
|
25272
25396
|
const stat5 = fs.lstatSync(current);
|
|
25273
25397
|
if (stat5.isSymbolicLink()) {
|
|
@@ -25297,17 +25421,17 @@ function validateProjectionCategories(categories) {
|
|
|
25297
25421
|
return validated;
|
|
25298
25422
|
}
|
|
25299
25423
|
function resolveContainedOutputPath(outputRoot, ...segments) {
|
|
25300
|
-
const resolved =
|
|
25301
|
-
const relative =
|
|
25302
|
-
if (relative === "" || !relative.startsWith("..") && !
|
|
25424
|
+
const resolved = path28.resolve(outputRoot, ...segments);
|
|
25425
|
+
const relative = path28.relative(outputRoot, resolved);
|
|
25426
|
+
if (relative === "" || !relative.startsWith("..") && !path28.isAbsolute(relative)) {
|
|
25303
25427
|
return resolved;
|
|
25304
25428
|
}
|
|
25305
25429
|
throw new Error(`context tree output path escapes outputDir: ${segments.join("/")}`);
|
|
25306
25430
|
}
|
|
25307
25431
|
function writeProjectedContent(realOutputDir, outputPath, generatedContent) {
|
|
25308
25432
|
assertSafeOutputTarget(realOutputDir, outputPath);
|
|
25309
|
-
fs.mkdirSync(
|
|
25310
|
-
const realParent = fs.realpathSync(
|
|
25433
|
+
fs.mkdirSync(path28.dirname(outputPath), { recursive: true });
|
|
25434
|
+
const realParent = fs.realpathSync(path28.dirname(outputPath));
|
|
25311
25435
|
if (!isPathInside(realOutputDir, realParent)) {
|
|
25312
25436
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
25313
25437
|
}
|
|
@@ -25346,7 +25470,7 @@ function walkR(dir, realMemoryDir) {
|
|
|
25346
25470
|
const results = [];
|
|
25347
25471
|
function walk(directory) {
|
|
25348
25472
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
25349
|
-
const fullPath =
|
|
25473
|
+
const fullPath = path28.join(directory, entry.name);
|
|
25350
25474
|
if (entry.isSymbolicLink()) {
|
|
25351
25475
|
throw new Error(`context tree input path contains symlink: ${fullPath}`);
|
|
25352
25476
|
}
|
|
@@ -25399,13 +25523,13 @@ function extractBody(content) {
|
|
|
25399
25523
|
}
|
|
25400
25524
|
function projectNode(filePath, category, fm, rawContent) {
|
|
25401
25525
|
const body = extractBody(rawContent);
|
|
25402
|
-
const fileName =
|
|
25403
|
-
const dateDir =
|
|
25526
|
+
const fileName = path28.basename(filePath, ".md");
|
|
25527
|
+
const dateDir = path28.basename(path28.dirname(filePath));
|
|
25404
25528
|
let relPath;
|
|
25405
25529
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateDir)) {
|
|
25406
|
-
relPath =
|
|
25530
|
+
relPath = path28.join(category, dateDir, `${fileName}.md`);
|
|
25407
25531
|
} else {
|
|
25408
|
-
relPath =
|
|
25532
|
+
relPath = path28.join(category, `${fileName}.md`);
|
|
25409
25533
|
}
|
|
25410
25534
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25411
25535
|
const md = `# ${fm.id}
|
|
@@ -25451,7 +25575,7 @@ function projectEntityNode(fileName, content) {
|
|
|
25451
25575
|
${content}
|
|
25452
25576
|
`;
|
|
25453
25577
|
return {
|
|
25454
|
-
path:
|
|
25578
|
+
path: path28.join("entities", `${fileName}.md`),
|
|
25455
25579
|
category: "entity",
|
|
25456
25580
|
title: fileName,
|
|
25457
25581
|
content: md,
|
|
@@ -25504,7 +25628,7 @@ function generateIndex(categoryCounts, outputDir) {
|
|
|
25504
25628
|
|
|
25505
25629
|
// src/onboarding/index.ts
|
|
25506
25630
|
import fs2 from "fs";
|
|
25507
|
-
import
|
|
25631
|
+
import path29 from "path";
|
|
25508
25632
|
var LANGUAGE_RULES = [
|
|
25509
25633
|
{
|
|
25510
25634
|
language: "TypeScript",
|
|
@@ -25606,7 +25730,7 @@ function onboard(options) {
|
|
|
25606
25730
|
maxDepth = 6,
|
|
25607
25731
|
excludeDirs = []
|
|
25608
25732
|
} = options;
|
|
25609
|
-
const directory =
|
|
25733
|
+
const directory = path29.resolve(options.directory ?? process.cwd());
|
|
25610
25734
|
let rootStat;
|
|
25611
25735
|
try {
|
|
25612
25736
|
rootStat = fs2.statSync(directory);
|
|
@@ -25648,7 +25772,7 @@ function walkDir(root, exclude, maxDepth) {
|
|
|
25648
25772
|
}
|
|
25649
25773
|
for (const entry of entries) {
|
|
25650
25774
|
if (exclude.has(entry.name)) continue;
|
|
25651
|
-
const fullPath =
|
|
25775
|
+
const fullPath = path29.join(dir, entry.name);
|
|
25652
25776
|
if (entry.isDirectory()) {
|
|
25653
25777
|
walk(fullPath, depth + 1);
|
|
25654
25778
|
} else if (entry.isFile()) {
|
|
@@ -25663,11 +25787,11 @@ function detectLanguages(files, root) {
|
|
|
25663
25787
|
const results = [];
|
|
25664
25788
|
const extCounts = /* @__PURE__ */ new Map();
|
|
25665
25789
|
for (const f of files) {
|
|
25666
|
-
const ext =
|
|
25790
|
+
const ext = path29.extname(f).toLowerCase();
|
|
25667
25791
|
if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
|
|
25668
25792
|
}
|
|
25669
25793
|
const rootFiles = new Set(
|
|
25670
|
-
files.filter((f) =>
|
|
25794
|
+
files.filter((f) => path29.dirname(f) === root).map((f) => path29.basename(f))
|
|
25671
25795
|
);
|
|
25672
25796
|
for (const rule of LANGUAGE_RULES) {
|
|
25673
25797
|
const evidence = [];
|
|
@@ -25711,7 +25835,7 @@ function detectLanguages(files, root) {
|
|
|
25711
25835
|
}
|
|
25712
25836
|
function detectShape(files, root) {
|
|
25713
25837
|
const rootFiles = new Set(
|
|
25714
|
-
files.filter((f) =>
|
|
25838
|
+
files.filter((f) => path29.dirname(f) === root).map((f) => path29.basename(f))
|
|
25715
25839
|
);
|
|
25716
25840
|
const rootDirs = /* @__PURE__ */ new Set();
|
|
25717
25841
|
try {
|
|
@@ -25722,7 +25846,7 @@ function detectShape(files, root) {
|
|
|
25722
25846
|
}
|
|
25723
25847
|
const evidence = [];
|
|
25724
25848
|
if (rootFiles.has("package.json")) {
|
|
25725
|
-
const pkg = readJsonSafe(
|
|
25849
|
+
const pkg = readJsonSafe(path29.join(root, "package.json"));
|
|
25726
25850
|
if (pkg?.workspaces) {
|
|
25727
25851
|
evidence.push("package.json has workspaces");
|
|
25728
25852
|
return { shape: "monorepo", evidence };
|
|
@@ -25736,13 +25860,13 @@ function detectShape(files, root) {
|
|
|
25736
25860
|
evidence.push("workspace manifest found");
|
|
25737
25861
|
return { shape: "workspace", evidence };
|
|
25738
25862
|
}
|
|
25739
|
-
const cargoToml = readTomlWorkspace(
|
|
25863
|
+
const cargoToml = readTomlWorkspace(path29.join(root, "Cargo.toml"));
|
|
25740
25864
|
if (cargoToml) {
|
|
25741
25865
|
evidence.push("Cargo.toml has workspace");
|
|
25742
25866
|
return { shape: "workspace", evidence };
|
|
25743
25867
|
}
|
|
25744
25868
|
if (rootFiles.has("package.json")) {
|
|
25745
|
-
const pkg = readJsonSafe(
|
|
25869
|
+
const pkg = readJsonSafe(path29.join(root, "package.json"));
|
|
25746
25870
|
if (pkg?.exports || pkg?.main) {
|
|
25747
25871
|
if (pkg?.bin) {
|
|
25748
25872
|
evidence.push("package.json has bin");
|
|
@@ -25776,8 +25900,8 @@ function discoverDocs(files, root) {
|
|
|
25776
25900
|
{ pattern: /^\.editorconfig$/i, kind: "config" }
|
|
25777
25901
|
];
|
|
25778
25902
|
for (const filePath of files) {
|
|
25779
|
-
const basename =
|
|
25780
|
-
const relPath =
|
|
25903
|
+
const basename = path29.basename(filePath).toLowerCase();
|
|
25904
|
+
const relPath = path29.relative(root, filePath);
|
|
25781
25905
|
let kind;
|
|
25782
25906
|
for (const { pattern, kind: k } of docPatterns) {
|
|
25783
25907
|
if (pattern.test(basename)) {
|
|
@@ -25789,7 +25913,7 @@ function discoverDocs(files, root) {
|
|
|
25789
25913
|
kind = "docs";
|
|
25790
25914
|
}
|
|
25791
25915
|
if (!kind && (basename.endsWith(".md") || basename.endsWith(".mdx"))) {
|
|
25792
|
-
if (
|
|
25916
|
+
if (path29.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
|
|
25793
25917
|
kind = "docs";
|
|
25794
25918
|
}
|
|
25795
25919
|
}
|
|
@@ -25810,7 +25934,7 @@ function discoverDocs(files, root) {
|
|
|
25810
25934
|
return docs;
|
|
25811
25935
|
}
|
|
25812
25936
|
function isUnderDocsDir(relPath) {
|
|
25813
|
-
const parts = relPath.split(
|
|
25937
|
+
const parts = relPath.split(path29.sep);
|
|
25814
25938
|
return parts[0] === "docs" || parts[0] === "doc" || parts[0] === "documentation";
|
|
25815
25939
|
}
|
|
25816
25940
|
function buildPlan(languages, shape, docs, _root) {
|
|
@@ -25854,7 +25978,7 @@ function readTomlWorkspace(filePath) {
|
|
|
25854
25978
|
|
|
25855
25979
|
// src/curation/index.ts
|
|
25856
25980
|
import fs3 from "fs";
|
|
25857
|
-
import
|
|
25981
|
+
import path30 from "path";
|
|
25858
25982
|
import crypto4 from "crypto";
|
|
25859
25983
|
async function curate(options) {
|
|
25860
25984
|
const startTime = Date.now();
|
|
@@ -25945,12 +26069,12 @@ function resolveTargets(targetPath) {
|
|
|
25945
26069
|
const extensions = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
25946
26070
|
function walk(dir) {
|
|
25947
26071
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
25948
|
-
const fullPath =
|
|
26072
|
+
const fullPath = path30.join(dir, entry.name);
|
|
25949
26073
|
if (entry.isDirectory()) {
|
|
25950
26074
|
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
25951
26075
|
walk(fullPath);
|
|
25952
26076
|
}
|
|
25953
|
-
} else if (extensions.has(
|
|
26077
|
+
} else if (extensions.has(path30.extname(entry.name).toLowerCase())) {
|
|
25954
26078
|
results.push(fullPath);
|
|
25955
26079
|
}
|
|
25956
26080
|
}
|
|
@@ -25959,12 +26083,12 @@ function resolveTargets(targetPath) {
|
|
|
25959
26083
|
return results;
|
|
25960
26084
|
}
|
|
25961
26085
|
function resolveProvenanceRoot(targetPath) {
|
|
25962
|
-
const resolvedTarget =
|
|
26086
|
+
const resolvedTarget = path30.resolve(targetPath);
|
|
25963
26087
|
const stat5 = fs3.statSync(resolvedTarget);
|
|
25964
|
-
return stat5.isFile() ?
|
|
26088
|
+
return stat5.isFile() ? path30.dirname(resolvedTarget) : resolvedTarget;
|
|
25965
26089
|
}
|
|
25966
26090
|
function extractStatements(content, filePath, projectRoot, source, sourceFileHash, categoryOverride, confidence, entityRef, tags) {
|
|
25967
|
-
const relativePath =
|
|
26091
|
+
const relativePath = path30.relative(projectRoot, path30.resolve(filePath)) || path30.basename(filePath);
|
|
25968
26092
|
const statements = [];
|
|
25969
26093
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25970
26094
|
const paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p.length > 20 && p.length < 2e3);
|
|
@@ -26058,7 +26182,7 @@ function loadExistingMemories(memoryDir) {
|
|
|
26058
26182
|
if (!fs3.existsSync(memoryDir)) return result;
|
|
26059
26183
|
const dirs = ALL_CATEGORY_DIRS;
|
|
26060
26184
|
for (const dir of dirs) {
|
|
26061
|
-
const fullDir =
|
|
26185
|
+
const fullDir = path30.join(memoryDir, dir);
|
|
26062
26186
|
if (!fs3.existsSync(fullDir)) continue;
|
|
26063
26187
|
walkFiles(fullDir, (filePath) => {
|
|
26064
26188
|
const content = readFileSafe(filePath);
|
|
@@ -26081,11 +26205,11 @@ function writeStatement(stmt, memoryDir) {
|
|
|
26081
26205
|
const now = /* @__PURE__ */ new Date();
|
|
26082
26206
|
const dateDir = now.toISOString().split("T")[0];
|
|
26083
26207
|
const categoryDir = getCategoryDir(memoryDir, stmt.category);
|
|
26084
|
-
const dir =
|
|
26208
|
+
const dir = path30.join(categoryDir, dateDir);
|
|
26085
26209
|
fs3.mkdirSync(dir, { recursive: true });
|
|
26086
26210
|
const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;
|
|
26087
|
-
const filePath =
|
|
26088
|
-
const historicalIds = historicalIdCache2.get(
|
|
26211
|
+
const filePath = path30.join(dir, fileName);
|
|
26212
|
+
const historicalIds = historicalIdCache2.get(path30.join(memoryDir, "state"));
|
|
26089
26213
|
const rawBody = `${[
|
|
26090
26214
|
"---",
|
|
26091
26215
|
`id: ${stmt.id}`,
|
|
@@ -26108,7 +26232,7 @@ ${stmt.content}
|
|
|
26108
26232
|
fs3.writeFileSync(filePath, body);
|
|
26109
26233
|
try {
|
|
26110
26234
|
repairContentAfterJournalMoveSync({
|
|
26111
|
-
stateDir:
|
|
26235
|
+
stateDir: path30.join(memoryDir, "state"),
|
|
26112
26236
|
cache: historicalIdCache2,
|
|
26113
26237
|
idsAtWrite: historicalIds,
|
|
26114
26238
|
rawContent: rawBody,
|
|
@@ -26169,7 +26293,7 @@ function extractBody2(content) {
|
|
|
26169
26293
|
}
|
|
26170
26294
|
function walkFiles(dir, callback) {
|
|
26171
26295
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
26172
|
-
const fullPath =
|
|
26296
|
+
const fullPath = path30.join(dir, entry.name);
|
|
26173
26297
|
if (entry.isDirectory()) {
|
|
26174
26298
|
walkFiles(fullPath, callback);
|
|
26175
26299
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -26181,7 +26305,7 @@ function walkFiles(dir, callback) {
|
|
|
26181
26305
|
// src/dedup/index.ts
|
|
26182
26306
|
import crypto5 from "crypto";
|
|
26183
26307
|
import fs4 from "fs";
|
|
26184
|
-
import
|
|
26308
|
+
import path31 from "path";
|
|
26185
26309
|
var DEFAULT_DEDUP_THRESHOLD = 0.85;
|
|
26186
26310
|
var DEFAULT_MAX_LOAD = 1e4;
|
|
26187
26311
|
function normalizeThreshold(value, defaultValue) {
|
|
@@ -26388,7 +26512,7 @@ function loadMemories(memoryDir, categories, maxLoad = 1e4) {
|
|
|
26388
26512
|
const memoryRootReal = fs4.realpathSync(memoryDir);
|
|
26389
26513
|
for (const category of allCategories) {
|
|
26390
26514
|
if (result.length >= maxLoad) break;
|
|
26391
|
-
const dir =
|
|
26515
|
+
const dir = path31.join(memoryDir, category);
|
|
26392
26516
|
if (!fs4.existsSync(dir)) continue;
|
|
26393
26517
|
const categoryStat = fs4.lstatSync(dir);
|
|
26394
26518
|
if (categoryStat.isSymbolicLink()) {
|
|
@@ -26449,15 +26573,15 @@ function extractBody3(content) {
|
|
|
26449
26573
|
return match ? match[1].trim() : content.trim();
|
|
26450
26574
|
}
|
|
26451
26575
|
function assertPathInsideRoot2(rootReal, targetReal, sourcePath) {
|
|
26452
|
-
const rel =
|
|
26453
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
26576
|
+
const rel = path31.relative(rootReal, targetReal);
|
|
26577
|
+
if (rel === "" || !rel.startsWith("..") && !path31.isAbsolute(rel)) {
|
|
26454
26578
|
return;
|
|
26455
26579
|
}
|
|
26456
26580
|
throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);
|
|
26457
26581
|
}
|
|
26458
26582
|
function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
26459
26583
|
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
26460
|
-
const fullPath =
|
|
26584
|
+
const fullPath = path31.join(dir, entry.name);
|
|
26461
26585
|
const entryStat = fs4.lstatSync(fullPath);
|
|
26462
26586
|
if (entryStat.isSymbolicLink()) {
|
|
26463
26587
|
throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);
|
|
@@ -26475,7 +26599,7 @@ function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
|
26475
26599
|
|
|
26476
26600
|
// src/sync/index.ts
|
|
26477
26601
|
import fs5 from "fs";
|
|
26478
|
-
import
|
|
26602
|
+
import path32 from "path";
|
|
26479
26603
|
import crypto6 from "crypto";
|
|
26480
26604
|
var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
26481
26605
|
var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
|
|
@@ -26497,7 +26621,7 @@ function syncChanges(options) {
|
|
|
26497
26621
|
} = options;
|
|
26498
26622
|
const extSet = new Set(extensions);
|
|
26499
26623
|
const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs]);
|
|
26500
|
-
const stateFilePath = options.stateFile ??
|
|
26624
|
+
const stateFilePath = options.stateFile ?? path32.join(memoryDir, ".sync-state.json");
|
|
26501
26625
|
const prevState = loadState(stateFilePath);
|
|
26502
26626
|
const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
|
|
26503
26627
|
const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);
|
|
@@ -26513,7 +26637,7 @@ function syncChanges(options) {
|
|
|
26513
26637
|
for (const [relPath, hash] of Object.entries(currentFiles)) {
|
|
26514
26638
|
newState.fileHashes[relPath] = hash;
|
|
26515
26639
|
}
|
|
26516
|
-
fs5.mkdirSync(
|
|
26640
|
+
fs5.mkdirSync(path32.dirname(stateFilePath), { recursive: true });
|
|
26517
26641
|
fs5.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
|
|
26518
26642
|
}
|
|
26519
26643
|
return {
|
|
@@ -26579,13 +26703,13 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26579
26703
|
}
|
|
26580
26704
|
for (const entry of entries) {
|
|
26581
26705
|
if (exclude.has(entry.name)) continue;
|
|
26582
|
-
const fullPath =
|
|
26706
|
+
const fullPath = path32.join(dir, entry.name);
|
|
26583
26707
|
if (entry.isDirectory()) {
|
|
26584
26708
|
walk(fullPath);
|
|
26585
26709
|
} else if (entry.isFile()) {
|
|
26586
|
-
const ext =
|
|
26710
|
+
const ext = path32.extname(entry.name).toLowerCase();
|
|
26587
26711
|
if (!extensions.has(ext)) continue;
|
|
26588
|
-
const relPath =
|
|
26712
|
+
const relPath = path32.relative(root, fullPath);
|
|
26589
26713
|
try {
|
|
26590
26714
|
const content = fs5.readFileSync(fullPath, "utf8");
|
|
26591
26715
|
result[relPath] = hashContent3(content);
|
|
@@ -26600,7 +26724,7 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26600
26724
|
function computeDiff(current, previous, sourceDir) {
|
|
26601
26725
|
const changes = [];
|
|
26602
26726
|
for (const [relPath, hash] of Object.entries(current)) {
|
|
26603
|
-
const fullPath =
|
|
26727
|
+
const fullPath = path32.join(sourceDir, relPath);
|
|
26604
26728
|
if (!(relPath in previous)) {
|
|
26605
26729
|
let size = 0;
|
|
26606
26730
|
try {
|
|
@@ -26633,7 +26757,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26633
26757
|
for (const relPath of Object.keys(previous)) {
|
|
26634
26758
|
if (!(relPath in current)) {
|
|
26635
26759
|
changes.push({
|
|
26636
|
-
filePath:
|
|
26760
|
+
filePath: path32.join(sourceDir, relPath),
|
|
26637
26761
|
relativePath: relPath,
|
|
26638
26762
|
type: "deleted",
|
|
26639
26763
|
currentHash: "",
|
|
@@ -26663,21 +26787,21 @@ function hashContent3(content) {
|
|
|
26663
26787
|
import { spawnSync } from "child_process";
|
|
26664
26788
|
import crypto7 from "crypto";
|
|
26665
26789
|
import fs6 from "fs";
|
|
26666
|
-
import
|
|
26790
|
+
import path33 from "path";
|
|
26667
26791
|
var historicalIdCache3 = new HistoricalEntityCanonicalIdCache();
|
|
26668
26792
|
var MANIFEST_VERSION = 1;
|
|
26669
26793
|
var MANIFEST_LOCK_STALE_MS = 3e4;
|
|
26670
26794
|
var MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 1e4;
|
|
26671
26795
|
var MANIFEST_LOCK_SLEEP_MS = 20;
|
|
26672
26796
|
function normalizeSpaceMemoryDir(memoryDir) {
|
|
26673
|
-
return
|
|
26797
|
+
return path33.resolve(memoryDir);
|
|
26674
26798
|
}
|
|
26675
26799
|
function getSpacesDir(baseDir) {
|
|
26676
26800
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
26677
|
-
return
|
|
26801
|
+
return path33.join(homeDir, ".config", "engram", "spaces");
|
|
26678
26802
|
}
|
|
26679
26803
|
function getManifestPath(baseDir) {
|
|
26680
|
-
return
|
|
26804
|
+
return path33.join(getSpacesDir(baseDir), "manifest.json");
|
|
26681
26805
|
}
|
|
26682
26806
|
function loadManifest(baseDir, memoryDirOverride) {
|
|
26683
26807
|
if (fs6.existsSync(getManifestPath(baseDir))) {
|
|
@@ -26724,9 +26848,9 @@ function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
|
|
|
26724
26848
|
}
|
|
26725
26849
|
function saveManifestUnlocked(manifest, baseDir) {
|
|
26726
26850
|
const manifestPath2 = getManifestPath(baseDir);
|
|
26727
|
-
const manifestDir2 =
|
|
26851
|
+
const manifestDir2 = path33.dirname(manifestPath2);
|
|
26728
26852
|
fs6.mkdirSync(manifestDir2, { recursive: true });
|
|
26729
|
-
const tempPath =
|
|
26853
|
+
const tempPath = path33.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto7.randomUUID()}.tmp`);
|
|
26730
26854
|
try {
|
|
26731
26855
|
fs6.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}
|
|
26732
26856
|
`, { flag: "wx" });
|
|
@@ -26741,7 +26865,7 @@ function saveManifestUnlocked(manifest, baseDir) {
|
|
|
26741
26865
|
}
|
|
26742
26866
|
function withManifestLock(baseDir, operation) {
|
|
26743
26867
|
const lockDir = `${getManifestPath(baseDir)}.lock`;
|
|
26744
|
-
fs6.mkdirSync(
|
|
26868
|
+
fs6.mkdirSync(path33.dirname(lockDir), { recursive: true });
|
|
26745
26869
|
const lockOwner = acquireManifestLock(lockDir);
|
|
26746
26870
|
try {
|
|
26747
26871
|
return operation();
|
|
@@ -26767,7 +26891,7 @@ function acquireManifestLock(lockDir) {
|
|
|
26767
26891
|
try {
|
|
26768
26892
|
fs6.mkdirSync(lockDir, { recursive: false });
|
|
26769
26893
|
try {
|
|
26770
|
-
fs6.writeFileSync(
|
|
26894
|
+
fs6.writeFileSync(path33.join(lockDir, "owner"), `${owner}
|
|
26771
26895
|
`, { flag: "wx" });
|
|
26772
26896
|
} catch (error) {
|
|
26773
26897
|
fs6.rmSync(lockDir, { recursive: true, force: true });
|
|
@@ -26797,7 +26921,7 @@ function acquireManifestLock(lockDir) {
|
|
|
26797
26921
|
}
|
|
26798
26922
|
function releaseManifestLock(lockDir, owner) {
|
|
26799
26923
|
try {
|
|
26800
|
-
const ownerPath =
|
|
26924
|
+
const ownerPath = path33.join(lockDir, "owner");
|
|
26801
26925
|
if (fs6.readFileSync(ownerPath, "utf8").trim() === owner) {
|
|
26802
26926
|
fs6.rmSync(lockDir, { recursive: true, force: true });
|
|
26803
26927
|
}
|
|
@@ -26813,7 +26937,7 @@ function removeStaleManifestLock(lockDir) {
|
|
|
26813
26937
|
try {
|
|
26814
26938
|
fs6.mkdirSync(reclaimDir, { recursive: false });
|
|
26815
26939
|
try {
|
|
26816
|
-
fs6.writeFileSync(
|
|
26940
|
+
fs6.writeFileSync(path33.join(reclaimDir, "owner"), `${reclaimOwner}
|
|
26817
26941
|
`, { flag: "wx" });
|
|
26818
26942
|
} catch (error) {
|
|
26819
26943
|
fs6.rmSync(reclaimDir, { recursive: true, force: true });
|
|
@@ -26888,7 +27012,7 @@ function readManifestLockSnapshot(lockDir) {
|
|
|
26888
27012
|
throw error;
|
|
26889
27013
|
}
|
|
26890
27014
|
try {
|
|
26891
|
-
const owner = fs6.readFileSync(
|
|
27015
|
+
const owner = fs6.readFileSync(path33.join(lockDir, "owner"), "utf8").trim();
|
|
26892
27016
|
return { mtimeMs: stat5.mtimeMs, owner };
|
|
26893
27017
|
} catch (error) {
|
|
26894
27018
|
if (error.code === "ENOENT") {
|
|
@@ -26960,8 +27084,8 @@ function sleepSync(ms) {
|
|
|
26960
27084
|
}
|
|
26961
27085
|
function createPersonalSpace(baseDir, memoryDirOverride) {
|
|
26962
27086
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
26963
|
-
const standalonePath =
|
|
26964
|
-
const openclawPath =
|
|
27087
|
+
const standalonePath = path33.join(homeDir, ".engram", "memory");
|
|
27088
|
+
const openclawPath = path33.join(homeDir, ".openclaw", "workspace", "memory", "local");
|
|
26965
27089
|
const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (fs6.existsSync(standalonePath) ? standalonePath : fs6.existsSync(openclawPath) ? openclawPath : standalonePath);
|
|
26966
27090
|
const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);
|
|
26967
27091
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -26990,7 +27114,7 @@ function createSpace(options) {
|
|
|
26990
27114
|
const id = options.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
|
26991
27115
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
26992
27116
|
const memoryDir = normalizeSpaceMemoryDir(
|
|
26993
|
-
options.memoryDir ??
|
|
27117
|
+
options.memoryDir ?? path33.join(getSpacesDir(options.baseDir), id, "memory")
|
|
26994
27118
|
);
|
|
26995
27119
|
const space = updateManifest(options.baseDir, (manifest) => {
|
|
26996
27120
|
if (manifest.spaces.some((s) => s.id === id)) {
|
|
@@ -27236,14 +27360,14 @@ async function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
|
|
|
27236
27360
|
};
|
|
27237
27361
|
}
|
|
27238
27362
|
function getAuditLog(baseDir) {
|
|
27239
|
-
const auditPath =
|
|
27363
|
+
const auditPath = path33.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
27240
27364
|
if (!fs6.existsSync(auditPath)) return [];
|
|
27241
27365
|
const lines = fs6.readFileSync(auditPath, "utf8").trim().split("\n");
|
|
27242
27366
|
return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
27243
27367
|
}
|
|
27244
27368
|
function appendAudit(entry, baseDir) {
|
|
27245
|
-
const auditPath =
|
|
27246
|
-
fs6.mkdirSync(
|
|
27369
|
+
const auditPath = path33.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
27370
|
+
fs6.mkdirSync(path33.dirname(auditPath), { recursive: true });
|
|
27247
27371
|
const full = {
|
|
27248
27372
|
id: crypto7.randomUUID(),
|
|
27249
27373
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -27264,11 +27388,11 @@ async function copyMemories(sourceDir, targetDir, options) {
|
|
|
27264
27388
|
sourceFiles.filter((p) => {
|
|
27265
27389
|
const rp = safeRealpath(p);
|
|
27266
27390
|
if (!rp || !isPathInsideRoot(rp, sourceRoot)) return false;
|
|
27267
|
-
const rel =
|
|
27268
|
-
const mapped =
|
|
27391
|
+
const rel = path33.relative(sourceRoot, rp);
|
|
27392
|
+
const mapped = path33.resolve(targetRoot, rel);
|
|
27269
27393
|
if (!isPathInsideRoot(mapped, targetRoot)) return false;
|
|
27270
27394
|
return classifyEntityRefWritePath(targetRoot, mapped) === "entity";
|
|
27271
|
-
}).map((p) =>
|
|
27395
|
+
}).map((p) => path33.basename(p, ".md"))
|
|
27272
27396
|
);
|
|
27273
27397
|
const firstEntityId = sourceEntityIds.values().next().value;
|
|
27274
27398
|
if (firstEntityId === void 0) {
|
|
@@ -27276,7 +27400,7 @@ async function copyMemories(sourceDir, targetDir, options) {
|
|
|
27276
27400
|
}
|
|
27277
27401
|
return withRawEntityPageMutation(
|
|
27278
27402
|
targetRoot,
|
|
27279
|
-
|
|
27403
|
+
path33.join(targetRoot, "entities", `${firstEntityId}.md`),
|
|
27280
27404
|
async () => copyPreparedMemories(
|
|
27281
27405
|
sourceFiles,
|
|
27282
27406
|
sourceRoot,
|
|
@@ -27303,14 +27427,14 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27303
27427
|
continue;
|
|
27304
27428
|
}
|
|
27305
27429
|
const content = fs6.readFileSync(sourcePath, "utf8");
|
|
27306
|
-
const relativePath =
|
|
27307
|
-
const targetPath =
|
|
27430
|
+
const relativePath = path33.relative(sourceRoot, sourceRealPath);
|
|
27431
|
+
const targetPath = path33.resolve(targetRoot, relativePath);
|
|
27308
27432
|
if (!isPathInsideRoot(targetPath, targetRoot)) {
|
|
27309
27433
|
skipped++;
|
|
27310
27434
|
continue;
|
|
27311
27435
|
}
|
|
27312
27436
|
const targetKind = classifyEntityRefWritePath(targetRoot, targetPath);
|
|
27313
|
-
const idsAtCompare = historicalIdCache3.get(
|
|
27437
|
+
const idsAtCompare = historicalIdCache3.get(path33.join(targetRoot, "state"));
|
|
27314
27438
|
const sourceRef = targetKind === "memory" ? readEntityRefFromFrontmatter(content) : null;
|
|
27315
27439
|
const refHasSourceClaimant = sourceRef !== null && sourceEntityIds.has(sourceRef);
|
|
27316
27440
|
const canonicalContent = targetKind === "memory" && !refHasSourceClaimant ? canonicalizeEntityRefFrontmatter(content, idsAtCompare) : content;
|
|
@@ -27337,7 +27461,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27337
27461
|
if (fs6.existsSync(targetPath) && !options?.force) {
|
|
27338
27462
|
const targetContent = fs6.readFileSync(targetPath, "utf8");
|
|
27339
27463
|
const targetHash = hashContent4(targetContent);
|
|
27340
|
-
if (hashContent4(canonicalContent) === targetHash && historicalIdCache3.get(
|
|
27464
|
+
if (hashContent4(canonicalContent) === targetHash && historicalIdCache3.get(path33.join(targetRoot, "state")) === idsAtCompare) {
|
|
27341
27465
|
skipped++;
|
|
27342
27466
|
continue;
|
|
27343
27467
|
}
|
|
@@ -27353,13 +27477,13 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27353
27477
|
continue;
|
|
27354
27478
|
}
|
|
27355
27479
|
}
|
|
27356
|
-
fs6.mkdirSync(
|
|
27357
|
-
const targetParentRealPath = safeRealpath(
|
|
27480
|
+
fs6.mkdirSync(path33.dirname(targetPath), { recursive: true });
|
|
27481
|
+
const targetParentRealPath = safeRealpath(path33.dirname(targetPath));
|
|
27358
27482
|
if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {
|
|
27359
27483
|
skipped++;
|
|
27360
27484
|
continue;
|
|
27361
27485
|
}
|
|
27362
|
-
const stateDir =
|
|
27486
|
+
const stateDir = path33.join(targetRoot, "state");
|
|
27363
27487
|
if (targetKind === "memory" && !refHasSourceClaimant) {
|
|
27364
27488
|
const idsAtWrite = historicalIdCache3.get(stateDir);
|
|
27365
27489
|
const written = canonicalizeEntityRefFrontmatter(content, idsAtWrite);
|
|
@@ -27403,7 +27527,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27403
27527
|
bumpMemoryCorpusVersionForDir(targetRoot);
|
|
27404
27528
|
}
|
|
27405
27529
|
if (reconcileNeeded) {
|
|
27406
|
-
requestEntityCanonicalIdReconcileSync(
|
|
27530
|
+
requestEntityCanonicalIdReconcileSync(path33.join(targetRoot, "state"));
|
|
27407
27531
|
}
|
|
27408
27532
|
return { merged, conflicts, skipped };
|
|
27409
27533
|
}
|
|
@@ -27414,7 +27538,7 @@ function walkMd(dir) {
|
|
|
27414
27538
|
const results = [];
|
|
27415
27539
|
function walk(d) {
|
|
27416
27540
|
for (const entry of fs6.readdirSync(d, { withFileTypes: true })) {
|
|
27417
|
-
const fullPath =
|
|
27541
|
+
const fullPath = path33.join(d, entry.name);
|
|
27418
27542
|
if (entry.isSymbolicLink()) {
|
|
27419
27543
|
continue;
|
|
27420
27544
|
}
|
|
@@ -27443,8 +27567,8 @@ function safeRealpath(filePath) {
|
|
|
27443
27567
|
}
|
|
27444
27568
|
}
|
|
27445
27569
|
function isPathInsideRoot(candidatePath, rootPath) {
|
|
27446
|
-
const relative =
|
|
27447
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
27570
|
+
const relative = path33.relative(rootPath, candidatePath);
|
|
27571
|
+
return relative === "" || !relative.startsWith("..") && !path33.isAbsolute(relative);
|
|
27448
27572
|
}
|
|
27449
27573
|
function parseSimpleFrontmatter(content) {
|
|
27450
27574
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -27565,7 +27689,7 @@ var REMNIC_RECALL_DECISION_RULES = `## When to Use Recall vs Direct Read
|
|
|
27565
27689
|
// src/memory-extension/codex-publisher.ts
|
|
27566
27690
|
import fs7 from "fs";
|
|
27567
27691
|
import os from "os";
|
|
27568
|
-
import
|
|
27692
|
+
import path34 from "path";
|
|
27569
27693
|
var REMNIC_EXTENSION_DIR_NAME = "remnic";
|
|
27570
27694
|
function resolveEnvHome(env) {
|
|
27571
27695
|
if (env === void 0) return resolveHomeDir();
|
|
@@ -27574,12 +27698,12 @@ function resolveEnvHome(env) {
|
|
|
27574
27698
|
function expandTildeWithHome(input, homeDir) {
|
|
27575
27699
|
if (input === "~") return homeDir;
|
|
27576
27700
|
if (input.startsWith("~/") || input.startsWith("~\\")) {
|
|
27577
|
-
return
|
|
27701
|
+
return path34.join(homeDir, input.slice(2));
|
|
27578
27702
|
}
|
|
27579
27703
|
return input;
|
|
27580
27704
|
}
|
|
27581
27705
|
function normalizeHostRoot(input, homeDir) {
|
|
27582
|
-
return
|
|
27706
|
+
return path34.resolve(expandTildeWithHome(input.trim(), homeDir));
|
|
27583
27707
|
}
|
|
27584
27708
|
var CodexMemoryExtensionPublisher = class {
|
|
27585
27709
|
hostId = "codex";
|
|
@@ -27593,12 +27717,12 @@ var CodexMemoryExtensionPublisher = class {
|
|
|
27593
27717
|
async resolveExtensionRoot(env) {
|
|
27594
27718
|
const homeDir = resolveEnvHome(env);
|
|
27595
27719
|
const codexHomeInput = env === void 0 ? readEnvVar("CODEX_HOME")?.trim() : env.CODEX_HOME?.trim();
|
|
27596
|
-
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) :
|
|
27597
|
-
return
|
|
27720
|
+
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) : path34.resolve(homeDir, ".codex");
|
|
27721
|
+
return path34.join(codexHome, "memories_extensions", REMNIC_EXTENSION_DIR_NAME);
|
|
27598
27722
|
}
|
|
27599
27723
|
async isHostAvailable() {
|
|
27600
27724
|
try {
|
|
27601
|
-
const home = readEnvVar("CODEX_HOME")?.trim() ||
|
|
27725
|
+
const home = readEnvVar("CODEX_HOME")?.trim() || path34.join(resolveHomeDir(), ".codex");
|
|
27602
27726
|
return fs7.existsSync(home);
|
|
27603
27727
|
} catch {
|
|
27604
27728
|
return false;
|
|
@@ -27649,7 +27773,7 @@ When running inside the Codex phase-2 consolidation sandbox:
|
|
|
27649
27773
|
}
|
|
27650
27774
|
async publish(ctx) {
|
|
27651
27775
|
const extensionRoot = await this.resolveExtensionRoot();
|
|
27652
|
-
const instructionsPath =
|
|
27776
|
+
const instructionsPath = path34.join(extensionRoot, "instructions.md");
|
|
27653
27777
|
const filesWritten = [];
|
|
27654
27778
|
const skipped = [];
|
|
27655
27779
|
ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);
|
|
@@ -28281,9 +28405,9 @@ function buildWeeklyActivitySummary(cards, options) {
|
|
|
28281
28405
|
// src/activity/timeline/weekly-persist.ts
|
|
28282
28406
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
28283
28407
|
import { mkdirSync, readFileSync as readFileSync2, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
28284
|
-
import
|
|
28408
|
+
import path35 from "path";
|
|
28285
28409
|
var WEEKLY_SNAPSHOT_FORMAT_VERSION = 1;
|
|
28286
|
-
var WEEKLY_SNAPSHOT_DIR =
|
|
28410
|
+
var WEEKLY_SNAPSHOT_DIR = path35.join("activity", "weekly");
|
|
28287
28411
|
function requireToken(value, name) {
|
|
28288
28412
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
28289
28413
|
throw new TypeError(`${name} must be a non-empty string`);
|
|
@@ -28306,8 +28430,8 @@ function weeklySnapshotPath(input) {
|
|
|
28306
28430
|
const identity = hashActivityBody(
|
|
28307
28431
|
`${input.summary.weekStartUtc}\0${input.summary.weekEndUtc}\0${sourceRevision}\0${configHash}`
|
|
28308
28432
|
);
|
|
28309
|
-
return
|
|
28310
|
-
|
|
28433
|
+
return path35.join(
|
|
28434
|
+
path35.resolve(memoryDir),
|
|
28311
28435
|
WEEKLY_SNAPSHOT_DIR,
|
|
28312
28436
|
namespaceIdentityToken(namespace),
|
|
28313
28437
|
`${weekDate}--${identity}.json`
|
|
@@ -28337,7 +28461,7 @@ function persistWeeklySnapshot(input) {
|
|
|
28337
28461
|
throw error;
|
|
28338
28462
|
}
|
|
28339
28463
|
}
|
|
28340
|
-
mkdirSync(
|
|
28464
|
+
mkdirSync(path35.dirname(filePath), { recursive: true, mode: 448 });
|
|
28341
28465
|
const tmpPath = `${filePath}.${process.pid}.${randomBytes3(8).toString("hex")}.tmp`;
|
|
28342
28466
|
writeFileSync(tmpPath, text, { encoding: "utf8", mode: 384 });
|
|
28343
28467
|
try {
|
|
@@ -28842,7 +28966,7 @@ function selectRecapForDay(input) {
|
|
|
28842
28966
|
|
|
28843
28967
|
// src/activity/journal-read.ts
|
|
28844
28968
|
import { closeSync, constants as fsConstants, fstatSync, lstatSync, openSync, readFileSync as readFileSync3, realpathSync, statSync as statSync2 } from "fs";
|
|
28845
|
-
import
|
|
28969
|
+
import path36 from "path";
|
|
28846
28970
|
|
|
28847
28971
|
// src/activity/journal-section.ts
|
|
28848
28972
|
function parseAtxHeading(line) {
|
|
@@ -29033,8 +29157,8 @@ function readJournalForDate(input) {
|
|
|
29033
29157
|
const relative = resolveVaultNotePath(input.vault.dailyNotePath, input.date, {
|
|
29034
29158
|
timezone: input.timezone
|
|
29035
29159
|
});
|
|
29036
|
-
const root =
|
|
29037
|
-
const filePath =
|
|
29160
|
+
const root = path36.resolve(expandTildePath(input.vault.vaultPath));
|
|
29161
|
+
const filePath = path36.join(root, relative);
|
|
29038
29162
|
try {
|
|
29039
29163
|
const rootStat = lstatSync(root);
|
|
29040
29164
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
|
@@ -29043,8 +29167,8 @@ function readJournalForDate(input) {
|
|
|
29043
29167
|
} catch {
|
|
29044
29168
|
return { ok: true, exists: false, reason: "missing_file", filePath };
|
|
29045
29169
|
}
|
|
29046
|
-
const lexical =
|
|
29047
|
-
if (lexical.length === 0 || lexical === ".." || lexical.startsWith(`..${
|
|
29170
|
+
const lexical = path36.relative(root, filePath);
|
|
29171
|
+
if (lexical.length === 0 || lexical === ".." || lexical.startsWith(`..${path36.sep}`) || path36.isAbsolute(lexical)) {
|
|
29048
29172
|
return { ok: false, reason: "path_escape", filePath };
|
|
29049
29173
|
}
|
|
29050
29174
|
if (!containedBySymlinks(root, filePath)) {
|
|
@@ -29077,11 +29201,11 @@ function containedBySymlinks(root, dest) {
|
|
|
29077
29201
|
try {
|
|
29078
29202
|
if (statSync2(probe).isFile() || statSync2(probe).isDirectory()) {
|
|
29079
29203
|
const real = realpathSync(probe);
|
|
29080
|
-
return real === realRoot || real.startsWith(`${realRoot}${
|
|
29204
|
+
return real === realRoot || real.startsWith(`${realRoot}${path36.sep}`);
|
|
29081
29205
|
}
|
|
29082
29206
|
} catch {
|
|
29083
29207
|
}
|
|
29084
|
-
const parent =
|
|
29208
|
+
const parent = path36.dirname(probe);
|
|
29085
29209
|
if (parent === probe) return false;
|
|
29086
29210
|
probe = parent;
|
|
29087
29211
|
}
|
|
@@ -29092,15 +29216,15 @@ function symlinkRejected() {
|
|
|
29092
29216
|
return err;
|
|
29093
29217
|
}
|
|
29094
29218
|
function readVerifiedDailyNote(root, filePath) {
|
|
29095
|
-
const relative =
|
|
29096
|
-
const parts = relative.split(
|
|
29219
|
+
const relative = path36.relative(root, filePath);
|
|
29220
|
+
const parts = relative.split(path36.sep).filter((part) => part.length > 0 && part !== ".");
|
|
29097
29221
|
let cursor = root;
|
|
29098
29222
|
for (const part of parts) {
|
|
29099
|
-
cursor =
|
|
29223
|
+
cursor = path36.join(cursor, part);
|
|
29100
29224
|
const st = lstatSync(cursor);
|
|
29101
29225
|
if (st.isSymbolicLink()) throw symlinkRejected();
|
|
29102
29226
|
}
|
|
29103
|
-
const parent =
|
|
29227
|
+
const parent = path36.dirname(filePath);
|
|
29104
29228
|
const parentLstat = lstatSync(parent);
|
|
29105
29229
|
if (parentLstat.isSymbolicLink() || !parentLstat.isDirectory()) throw symlinkRejected();
|
|
29106
29230
|
const nofollow = fsConstants.O_NOFOLLOW ?? 0;
|
|
@@ -29124,7 +29248,7 @@ function readVerifiedDailyNote(root, filePath) {
|
|
|
29124
29248
|
try {
|
|
29125
29249
|
const fdPath = realpathSync(`/proc/self/fd/${fd}`);
|
|
29126
29250
|
const realRoot = realpathSync(root);
|
|
29127
|
-
if (fdPath !== realRoot && !fdPath.startsWith(`${realRoot}${
|
|
29251
|
+
if (fdPath !== realRoot && !fdPath.startsWith(`${realRoot}${path36.sep}`)) {
|
|
29128
29252
|
throw symlinkRejected();
|
|
29129
29253
|
}
|
|
29130
29254
|
} catch (err) {
|
|
@@ -29139,11 +29263,11 @@ function readVerifiedDailyNote(root, filePath) {
|
|
|
29139
29263
|
// src/activity/journal-state.ts
|
|
29140
29264
|
import { createHash as createHash10, randomBytes as randomBytes4 } from "crypto";
|
|
29141
29265
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
29142
|
-
import
|
|
29266
|
+
import path37 from "path";
|
|
29143
29267
|
var STATE_DIR_NAME = "state";
|
|
29144
29268
|
var STATE_FILE_NAME = "timeline.json";
|
|
29145
29269
|
function timelineStatePath(memoryDir) {
|
|
29146
|
-
return
|
|
29270
|
+
return path37.join(memoryDir, STATE_DIR_NAME, STATE_FILE_NAME);
|
|
29147
29271
|
}
|
|
29148
29272
|
function hashJournalText(text) {
|
|
29149
29273
|
return createHash10("sha256").update(text, "utf8").digest("hex");
|
|
@@ -29169,14 +29293,14 @@ function readTimelineState(memoryDir) {
|
|
|
29169
29293
|
}
|
|
29170
29294
|
function writeTimelineState(memoryDir, state) {
|
|
29171
29295
|
const filePath = timelineStatePath(memoryDir);
|
|
29172
|
-
mkdirSync2(
|
|
29296
|
+
mkdirSync2(path37.dirname(filePath), { recursive: true });
|
|
29173
29297
|
const tempPath = `${filePath}.${process.pid}.${randomBytes4(8).toString("hex")}.tmp`;
|
|
29174
29298
|
writeFileSync2(tempPath, `${JSON.stringify(state, null, 2)}
|
|
29175
29299
|
`);
|
|
29176
29300
|
renameSync2(tempPath, filePath);
|
|
29177
29301
|
}
|
|
29178
29302
|
function journalDateLockPath(memoryDir, date) {
|
|
29179
|
-
return
|
|
29303
|
+
return path37.join(memoryDir, STATE_DIR_NAME, `journal-extract-${date}.lock`);
|
|
29180
29304
|
}
|
|
29181
29305
|
function timelineStateLockPath(memoryDir) {
|
|
29182
29306
|
return `${timelineStatePath(memoryDir)}.lock`;
|
|
@@ -29868,7 +29992,7 @@ function filterPrivacyWindow(items, options) {
|
|
|
29868
29992
|
}
|
|
29869
29993
|
|
|
29870
29994
|
// src/activity/vault-wikilink.ts
|
|
29871
|
-
import
|
|
29995
|
+
import path38 from "path";
|
|
29872
29996
|
function formatVaultWikilink(notePath) {
|
|
29873
29997
|
if (typeof notePath !== "string" || notePath.trim().length === 0) {
|
|
29874
29998
|
throw new RangeError("Vault wikilink path must be a non-empty relative path.");
|
|
@@ -29876,7 +30000,7 @@ function formatVaultWikilink(notePath) {
|
|
|
29876
30000
|
if (notePath.includes("\n") || notePath.includes("\r")) {
|
|
29877
30001
|
throw new RangeError("Vault wikilink path must not contain newlines.");
|
|
29878
30002
|
}
|
|
29879
|
-
if (
|
|
30003
|
+
if (path38.posix.isAbsolute(notePath) || path38.win32.isAbsolute(notePath)) {
|
|
29880
30004
|
throw new RangeError("Vault wikilink path must be relative; absolute paths are rejected.");
|
|
29881
30005
|
}
|
|
29882
30006
|
if (notePath.split(/[\\/]/).some((segment) => segment === "..")) {
|
|
@@ -29898,7 +30022,7 @@ function stripVaultMdSuffix(notePath) {
|
|
|
29898
30022
|
}
|
|
29899
30023
|
|
|
29900
30024
|
// src/activity/vault-join.ts
|
|
29901
|
-
import
|
|
30025
|
+
import path39 from "path";
|
|
29902
30026
|
function joinVaultSegments(parts) {
|
|
29903
30027
|
if (parts.length === 0) {
|
|
29904
30028
|
throw new RangeError("Vault path parts must be a non-empty list.");
|
|
@@ -29913,7 +30037,7 @@ function joinVaultSegments(parts) {
|
|
|
29913
30037
|
if (part.includes("\n") || part.includes("\r")) {
|
|
29914
30038
|
throw new RangeError("Vault path part must not contain a newline.");
|
|
29915
30039
|
}
|
|
29916
|
-
if (
|
|
30040
|
+
if (path39.posix.isAbsolute(part) || path39.win32.isAbsolute(part)) {
|
|
29917
30041
|
throw new RangeError("Vault path part must be relative.");
|
|
29918
30042
|
}
|
|
29919
30043
|
if (part.split("/").includes("..")) {
|
|
@@ -29968,7 +30092,7 @@ function planVaultDryRun(inputs) {
|
|
|
29968
30092
|
// src/session-summaries/index.ts
|
|
29969
30093
|
import { createHash as createHash11 } from "crypto";
|
|
29970
30094
|
import { lstat as lstat3, mkdir as mkdir7, readFile as readFile9, readdir as readdir4, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
|
|
29971
|
-
import
|
|
30095
|
+
import path40 from "path";
|
|
29972
30096
|
|
|
29973
30097
|
// src/session-summaries/adapters.ts
|
|
29974
30098
|
var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "other"]);
|
|
@@ -30473,7 +30597,7 @@ function shortHash(value, length = 16) {
|
|
|
30473
30597
|
async function listTranscriptFiles(root, maxFiles) {
|
|
30474
30598
|
const out = [];
|
|
30475
30599
|
let truncated = false;
|
|
30476
|
-
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${
|
|
30600
|
+
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path40.sep}` : entryName;
|
|
30477
30601
|
async function visit(dir) {
|
|
30478
30602
|
if (truncated) return;
|
|
30479
30603
|
const entries = (await readdir4(dir, { withFileTypes: true })).sort(
|
|
@@ -30483,13 +30607,13 @@ async function listTranscriptFiles(root, maxFiles) {
|
|
|
30483
30607
|
if (truncated) return;
|
|
30484
30608
|
if (entry.name.startsWith(".")) continue;
|
|
30485
30609
|
if (entry.isSymbolicLink()) continue;
|
|
30486
|
-
const fullPath =
|
|
30610
|
+
const fullPath = path40.join(dir, entry.name);
|
|
30487
30611
|
if (entry.isDirectory()) {
|
|
30488
30612
|
await visit(fullPath);
|
|
30489
30613
|
continue;
|
|
30490
30614
|
}
|
|
30491
30615
|
if (!entry.isFile()) continue;
|
|
30492
|
-
const ext =
|
|
30616
|
+
const ext = path40.extname(entry.name).toLowerCase();
|
|
30493
30617
|
if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
|
|
30494
30618
|
out.push(fullPath);
|
|
30495
30619
|
if (out.length > maxFiles) {
|
|
@@ -30516,7 +30640,7 @@ function normalizeInputDir(inputDir) {
|
|
|
30516
30640
|
if (typeof inputDir !== "string" || inputDir.trim().length === 0) {
|
|
30517
30641
|
throw new Error("inputDir must be a non-empty string");
|
|
30518
30642
|
}
|
|
30519
|
-
return
|
|
30643
|
+
return path40.resolve(expandTildePath(inputDir.trim()));
|
|
30520
30644
|
}
|
|
30521
30645
|
function initRoleCounts() {
|
|
30522
30646
|
return {
|
|
@@ -30673,11 +30797,11 @@ async function collectLocalSessionSummaries(options) {
|
|
|
30673
30797
|
continue;
|
|
30674
30798
|
}
|
|
30675
30799
|
seenFileHashes.add(fileHash);
|
|
30676
|
-
const fileExtension =
|
|
30800
|
+
const fileExtension = path40.extname(filePath).toLowerCase();
|
|
30677
30801
|
const parsed = await adapter.parseFile(
|
|
30678
30802
|
{
|
|
30679
30803
|
content,
|
|
30680
|
-
fileName:
|
|
30804
|
+
fileName: path40.basename(filePath),
|
|
30681
30805
|
fileExtension,
|
|
30682
30806
|
fileRef: fileHash
|
|
30683
30807
|
},
|
|
@@ -30733,7 +30857,7 @@ async function collectLocalSessionSummaries(options) {
|
|
|
30733
30857
|
}
|
|
30734
30858
|
async function readRedactionConfig(pathLike) {
|
|
30735
30859
|
if (!pathLike) return void 0;
|
|
30736
|
-
const raw = await readFile9(
|
|
30860
|
+
const raw = await readFile9(path40.resolve(expandTildePath(pathLike)), "utf-8");
|
|
30737
30861
|
const parsed = JSON.parse(raw);
|
|
30738
30862
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
30739
30863
|
throw new Error("redaction config must be a JSON object");
|
|
@@ -30746,15 +30870,15 @@ function toJsonl(drafts) {
|
|
|
30746
30870
|
}
|
|
30747
30871
|
function defaultDraftOutputPath(memoryDir, generatedAt) {
|
|
30748
30872
|
const stamp = generatedAt.replace(/[:.]/g, "-");
|
|
30749
|
-
return
|
|
30750
|
-
|
|
30873
|
+
return path40.join(
|
|
30874
|
+
path40.resolve(expandTildePath(memoryDir)),
|
|
30751
30875
|
"state",
|
|
30752
30876
|
"session-summary-drafts",
|
|
30753
30877
|
`session-summaries-${stamp}.jsonl`
|
|
30754
30878
|
);
|
|
30755
30879
|
}
|
|
30756
30880
|
async function writeDrafts(filePath, drafts) {
|
|
30757
|
-
await mkdir7(
|
|
30881
|
+
await mkdir7(path40.dirname(filePath), { recursive: true });
|
|
30758
30882
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
30759
30883
|
try {
|
|
30760
30884
|
await writeFile7(tempPath, toJsonl(drafts), "utf-8");
|
|
@@ -30772,7 +30896,7 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
30772
30896
|
});
|
|
30773
30897
|
const wroteFiles = [];
|
|
30774
30898
|
if (options.output) {
|
|
30775
|
-
const outputPath =
|
|
30899
|
+
const outputPath = path40.resolve(expandTildePath(options.output));
|
|
30776
30900
|
await writeDrafts(outputPath, report.drafts);
|
|
30777
30901
|
wroteFiles.push(outputPath);
|
|
30778
30902
|
}
|
|
@@ -30807,19 +30931,19 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
30807
30931
|
|
|
30808
30932
|
// src/transfer/capsule-fork.ts
|
|
30809
30933
|
import { lstat as lstat4, mkdir as mkdir8, readFile as readFile10, realpath as realpath3, writeFile as writeFile8 } from "fs/promises";
|
|
30810
|
-
import
|
|
30934
|
+
import path41 from "path";
|
|
30811
30935
|
async function forkCapsule(opts) {
|
|
30812
30936
|
validateForkId(opts.forkId);
|
|
30813
|
-
const rootAbs =
|
|
30937
|
+
const rootAbs = path41.resolve(opts.targetRoot);
|
|
30814
30938
|
await assertIsDirectoryNotSymlink(rootAbs, "forkCapsule", "targetRoot");
|
|
30815
|
-
const forkDirAbs =
|
|
30939
|
+
const forkDirAbs = path41.join(rootAbs, "forks", opts.forkId);
|
|
30816
30940
|
const forkEntryExists = await pathEntryExists(forkDirAbs);
|
|
30817
30941
|
if (forkEntryExists) {
|
|
30818
30942
|
throw new Error(
|
|
30819
30943
|
`forkCapsule: fork path already exists \u2014 forkId "${opts.forkId}" is already in use at: ${forkDirAbs}`
|
|
30820
30944
|
);
|
|
30821
30945
|
}
|
|
30822
|
-
const archiveAbs =
|
|
30946
|
+
const archiveAbs = path41.resolve(opts.sourceArchive);
|
|
30823
30947
|
const importResult = await importCapsule({
|
|
30824
30948
|
archivePath: archiveAbs,
|
|
30825
30949
|
root: rootAbs,
|
|
@@ -30841,10 +30965,10 @@ async function forkCapsule(opts) {
|
|
|
30841
30965
|
importedRecords: importResult.imported.length,
|
|
30842
30966
|
skippedRecords: importResult.skipped.length
|
|
30843
30967
|
};
|
|
30844
|
-
const lineagePath =
|
|
30968
|
+
const lineagePath = path41.join(forkDirAbs, "lineage.json");
|
|
30845
30969
|
const rootReal = await realpath3(rootAbs);
|
|
30846
30970
|
await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, "forkCapsule");
|
|
30847
|
-
await mkdir8(
|
|
30971
|
+
await mkdir8(path41.dirname(lineagePath), { recursive: true });
|
|
30848
30972
|
await writeFile8(lineagePath, JSON.stringify(lineage, null, 2) + "\n", "utf-8");
|
|
30849
30973
|
return {
|
|
30850
30974
|
archivePath: archiveAbs,
|
|
@@ -30858,11 +30982,11 @@ async function readForkLineage(targetRoot, forkId) {
|
|
|
30858
30982
|
if (typeof forkId !== "string" || forkId.length === 0 || forkId.length > 64 || !CAPSULE_ID_PATTERN.test(forkId)) {
|
|
30859
30983
|
return null;
|
|
30860
30984
|
}
|
|
30861
|
-
const rootAbs =
|
|
30985
|
+
const rootAbs = path41.resolve(targetRoot);
|
|
30862
30986
|
const rootReal = await realpath3(rootAbs).catch(() => rootAbs);
|
|
30863
|
-
const lineagePath =
|
|
30864
|
-
const rel =
|
|
30865
|
-
if (rel.startsWith("..") ||
|
|
30987
|
+
const lineagePath = path41.join(rootReal, "forks", forkId, "lineage.json");
|
|
30988
|
+
const rel = path41.relative(rootReal, lineagePath);
|
|
30989
|
+
if (rel.startsWith("..") || path41.isAbsolute(rel)) {
|
|
30866
30990
|
return null;
|
|
30867
30991
|
}
|
|
30868
30992
|
if (!await isLineagePathContained(rootReal, lineagePath)) {
|
|
@@ -30903,19 +31027,19 @@ async function pathEntryExists(absPath) {
|
|
|
30903
31027
|
async function isLineagePathContained(rootReal, lineagePath) {
|
|
30904
31028
|
let existing = lineagePath;
|
|
30905
31029
|
const suffix = [];
|
|
30906
|
-
while (existing !==
|
|
31030
|
+
while (existing !== path41.dirname(existing)) {
|
|
30907
31031
|
const st = await lstat4(existing).catch(() => null);
|
|
30908
31032
|
if (st !== null) break;
|
|
30909
|
-
suffix.unshift(
|
|
30910
|
-
existing =
|
|
31033
|
+
suffix.unshift(path41.basename(existing));
|
|
31034
|
+
existing = path41.dirname(existing);
|
|
30911
31035
|
}
|
|
30912
31036
|
const existingReal = await realpath3(existing).catch(() => existing);
|
|
30913
|
-
const targetReal = suffix.length > 0 ?
|
|
30914
|
-
const rel =
|
|
31037
|
+
const targetReal = suffix.length > 0 ? path41.join(existingReal, ...suffix) : existingReal;
|
|
31038
|
+
const rel = path41.relative(rootReal, targetReal);
|
|
30915
31039
|
if (rel === "") return true;
|
|
30916
31040
|
if (rel === "..") return false;
|
|
30917
|
-
if (rel.startsWith(`..${
|
|
30918
|
-
if (
|
|
31041
|
+
if (rel.startsWith(`..${path41.sep}`)) return false;
|
|
31042
|
+
if (path41.isAbsolute(rel)) return false;
|
|
30919
31043
|
return true;
|
|
30920
31044
|
}
|
|
30921
31045
|
|
|
@@ -31104,4 +31228,4 @@ export {
|
|
|
31104
31228
|
qmdStartupCollectionChecksWithTimeout,
|
|
31105
31229
|
Orchestrator
|
|
31106
31230
|
};
|
|
31107
|
-
//# sourceMappingURL=chunk-
|
|
31231
|
+
//# sourceMappingURL=chunk-K7FXR75S.js.map
|