@remnic/core 9.69.53 → 9.69.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-cli.js +5 -5
- package/dist/active-recall.js +1 -1
- package/dist/{chunk-SEQ6DWXD.js → chunk-5IKW2VP6.js} +2 -2
- package/dist/{chunk-UVZBDIJX.js → chunk-KGY6F4VJ.js} +488 -48
- package/dist/chunk-KGY6F4VJ.js.map +1 -0
- package/dist/{chunk-K7FXR75S.js → chunk-OKOG5MXF.js} +355 -573
- package/dist/chunk-OKOG5MXF.js.map +1 -0
- package/dist/{chunk-JE4H2QBO.js → chunk-WJ5KWJLK.js} +2 -2
- package/dist/{chunk-TS66MUUJ.js → chunk-ZHV6FGVF.js} +4 -4
- package/dist/cli.js +4 -4
- package/dist/config.js +1 -1
- package/dist/index.d.ts +139 -41
- package/dist/index.js +17 -7
- package/dist/operator-toolkit.js +2 -2
- package/dist/orchestrator.js +5 -5
- package/dist/resume-bundles.js +2 -2
- package/package.json +2 -2
- package/src/activity/index.ts +2 -0
- package/src/activity/timeline/index.ts +1 -0
- package/src/activity/timeline/week-dashboard.test.ts +362 -0
- package/src/activity/timeline/week-dashboard.ts +273 -0
- package/src/activity/timeline/weekly.ts +2 -1
- package/src/lifecycle/seed-graduation.test.ts +209 -0
- package/src/lifecycle/seed-graduation.ts +94 -11
- package/dist/chunk-K7FXR75S.js.map +0 -1
- package/dist/chunk-UVZBDIJX.js.map +0 -1
- /package/dist/{chunk-SEQ6DWXD.js.map → chunk-5IKW2VP6.js.map} +0 -0
- /package/dist/{chunk-JE4H2QBO.js.map → chunk-WJ5KWJLK.js.map} +0 -0
- /package/dist/{chunk-TS66MUUJ.js.map → chunk-ZHV6FGVF.js.map} +0 -0
|
@@ -231,7 +231,7 @@ import {
|
|
|
231
231
|
runTimelinePublishCli,
|
|
232
232
|
screenCandidateFact,
|
|
233
233
|
summarizeVaultPublish
|
|
234
|
-
} from "./chunk-
|
|
234
|
+
} from "./chunk-ZHV6FGVF.js";
|
|
235
235
|
import {
|
|
236
236
|
normalizeReplaySessionKey
|
|
237
237
|
} from "./chunk-AJVLDJU6.js";
|
|
@@ -261,7 +261,7 @@ import {
|
|
|
261
261
|
import {
|
|
262
262
|
runNamespaceMaintenanceFanout,
|
|
263
263
|
summarizeNamespaceMaintenanceHealth
|
|
264
|
-
} from "./chunk-
|
|
264
|
+
} from "./chunk-5IKW2VP6.js";
|
|
265
265
|
import {
|
|
266
266
|
planNamespaceMaintenance
|
|
267
267
|
} from "./chunk-7RKAE6Y4.js";
|
|
@@ -325,13 +325,14 @@ import {
|
|
|
325
325
|
import {
|
|
326
326
|
REFUSED_MERGE_CATEGORIES,
|
|
327
327
|
applyNoveltyGate,
|
|
328
|
+
buildMergeFrontmatterUpdate,
|
|
328
329
|
connectorMatchesScope,
|
|
329
330
|
decideSemanticMerge,
|
|
330
331
|
detectMeetings,
|
|
331
332
|
embeddingsFromCosineHits,
|
|
332
333
|
normalizeConnectorScope,
|
|
333
334
|
runSeedGraduationPass
|
|
334
|
-
} from "./chunk-
|
|
335
|
+
} from "./chunk-KGY6F4VJ.js";
|
|
335
336
|
import {
|
|
336
337
|
compileCorrectionRule,
|
|
337
338
|
correctionsFilePath,
|
|
@@ -666,9 +667,6 @@ import {
|
|
|
666
667
|
import {
|
|
667
668
|
fallbackLlmRuntimeContextFromConfig
|
|
668
669
|
} from "./chunk-EP6BA7VV.js";
|
|
669
|
-
import {
|
|
670
|
-
normalizeRecallTokenSet
|
|
671
|
-
} from "./chunk-YCVB7X56.js";
|
|
672
670
|
import {
|
|
673
671
|
graphemeUnits,
|
|
674
672
|
truncateGraphemeSafe
|
|
@@ -2413,7 +2411,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2413
2411
|
namespaces,
|
|
2414
2412
|
{
|
|
2415
2413
|
readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
|
|
2416
|
-
readMemoryFrontmatter: async (
|
|
2414
|
+
readMemoryFrontmatter: async (path41, preferredNamespace) => {
|
|
2417
2415
|
if (!fallbackReader) {
|
|
2418
2416
|
for (const ns of namespaces) {
|
|
2419
2417
|
try {
|
|
@@ -2425,7 +2423,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2425
2423
|
}
|
|
2426
2424
|
if (!fallbackReader) return null;
|
|
2427
2425
|
const memory = await this.readQmdResultMemory(
|
|
2428
|
-
|
|
2426
|
+
path41,
|
|
2429
2427
|
fallbackReader,
|
|
2430
2428
|
namespaces,
|
|
2431
2429
|
preferredNamespace
|
|
@@ -5605,93 +5603,6 @@ async function persistRepairedContentHash(storage, targetId, committedContent, c
|
|
|
5605
5603
|
}
|
|
5606
5604
|
}
|
|
5607
5605
|
|
|
5608
|
-
// src/dedup/merge-provenance.ts
|
|
5609
|
-
var MERGE_DERIVED_VIA = "merge";
|
|
5610
|
-
var ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
5611
|
-
function assertIsoInstant(value, field) {
|
|
5612
|
-
if (typeof value !== "string" || !ISO_TIMESTAMP.test(value)) {
|
|
5613
|
-
throw new RangeError(`${field} must be a full ISO 8601 instant, got ${JSON.stringify(value)}`);
|
|
5614
|
-
}
|
|
5615
|
-
const ms = Date.parse(value);
|
|
5616
|
-
if (Number.isNaN(ms)) {
|
|
5617
|
-
throw new RangeError(`${field} must be a full ISO 8601 instant, got ${JSON.stringify(value)}`);
|
|
5618
|
-
}
|
|
5619
|
-
if (!new Date(ms).toISOString().startsWith(value.slice(0, 10))) {
|
|
5620
|
-
throw new RangeError(`${field} is not a real calendar date: ${JSON.stringify(value)}`);
|
|
5621
|
-
}
|
|
5622
|
-
return value;
|
|
5623
|
-
}
|
|
5624
|
-
function assertOffset(value, field) {
|
|
5625
|
-
if (value === void 0) return;
|
|
5626
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
5627
|
-
throw new RangeError(`${field} must be a non-negative integer when present, got ${String(value)}`);
|
|
5628
|
-
}
|
|
5629
|
-
}
|
|
5630
|
-
function normalizeSource(source, index) {
|
|
5631
|
-
const label = `sources[${index}]`;
|
|
5632
|
-
for (const field of ["sessionKey", "quote"]) {
|
|
5633
|
-
const value = source[field];
|
|
5634
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
5635
|
-
throw new RangeError(`${label}.${field} must be a non-blank string`);
|
|
5636
|
-
}
|
|
5637
|
-
}
|
|
5638
|
-
assertIsoInstant(source.observedAt, `${label}.observedAt`);
|
|
5639
|
-
if (source.turnId !== void 0 && (typeof source.turnId !== "string" || source.turnId.trim() === "")) {
|
|
5640
|
-
throw new RangeError(`${label}.turnId must be a non-blank string when present`);
|
|
5641
|
-
}
|
|
5642
|
-
assertOffset(source.charStart, `${label}.charStart`);
|
|
5643
|
-
assertOffset(source.charEnd, `${label}.charEnd`);
|
|
5644
|
-
if (source.charStart !== void 0 && source.charEnd !== void 0 && source.charEnd < source.charStart) {
|
|
5645
|
-
throw new RangeError(`${label}.charEnd must be >= charStart`);
|
|
5646
|
-
}
|
|
5647
|
-
const copy = {
|
|
5648
|
-
sessionKey: source.sessionKey,
|
|
5649
|
-
observedAt: source.observedAt,
|
|
5650
|
-
quote: source.quote
|
|
5651
|
-
};
|
|
5652
|
-
if (source.turnId !== void 0) copy.turnId = source.turnId;
|
|
5653
|
-
if (source.charStart !== void 0) copy.charStart = source.charStart;
|
|
5654
|
-
if (source.charEnd !== void 0) copy.charEnd = source.charEnd;
|
|
5655
|
-
return copy;
|
|
5656
|
-
}
|
|
5657
|
-
function sourceKey(source) {
|
|
5658
|
-
return JSON.stringify([
|
|
5659
|
-
source.sessionKey,
|
|
5660
|
-
source.turnId ?? null,
|
|
5661
|
-
source.observedAt,
|
|
5662
|
-
source.quote,
|
|
5663
|
-
source.charStart ?? null,
|
|
5664
|
-
source.charEnd ?? null
|
|
5665
|
-
]);
|
|
5666
|
-
}
|
|
5667
|
-
function buildMergeFrontmatterUpdate(input) {
|
|
5668
|
-
const updated = assertIsoInstant(input.nowIso, "nowIso");
|
|
5669
|
-
const previous = input.targetReinforcementCount;
|
|
5670
|
-
if (previous !== void 0 && (typeof previous !== "number" || !Number.isInteger(previous) || previous < 0)) {
|
|
5671
|
-
throw new RangeError(
|
|
5672
|
-
`reinforcement_count must be a non-negative integer when supplied, got ${String(previous)}`
|
|
5673
|
-
);
|
|
5674
|
-
}
|
|
5675
|
-
const seen = /* @__PURE__ */ new Set();
|
|
5676
|
-
const sources = [];
|
|
5677
|
-
const append = (source, index) => {
|
|
5678
|
-
const copy = normalizeSource(source, index);
|
|
5679
|
-
const key = sourceKey(copy);
|
|
5680
|
-
if (seen.has(key)) return;
|
|
5681
|
-
seen.add(key);
|
|
5682
|
-
sources.push(copy);
|
|
5683
|
-
};
|
|
5684
|
-
const target = input.targetSources ?? [];
|
|
5685
|
-
target.forEach(append);
|
|
5686
|
-
input.incomingSources.forEach((source, i) => append(source, target.length + i));
|
|
5687
|
-
return {
|
|
5688
|
-
updated,
|
|
5689
|
-
derived_via: MERGE_DERIVED_VIA,
|
|
5690
|
-
reinforcement_count: (previous ?? 0) + 1,
|
|
5691
|
-
sources
|
|
5692
|
-
};
|
|
5693
|
-
}
|
|
5694
|
-
|
|
5695
5606
|
// src/dedup/merge-judge.ts
|
|
5696
5607
|
import { z } from "zod";
|
|
5697
5608
|
var MERGE_JUDGE_SYSTEM_PROMPT = `You maintain a long-term memory store. Given a NEW memory and up to N EXISTING
|
|
@@ -24324,9 +24235,9 @@ function readStructuralSymbol(entry) {
|
|
|
24324
24235
|
const rec = entry;
|
|
24325
24236
|
const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
|
|
24326
24237
|
if (!symbol) return null;
|
|
24327
|
-
const
|
|
24238
|
+
const path41 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
|
|
24328
24239
|
const kind = typeof rec.kind === "string" && rec.kind.length > 0 ? rec.kind : void 0;
|
|
24329
|
-
const item =
|
|
24240
|
+
const item = path41 !== void 0 && kind !== void 0 ? { symbol, path: path41, kind } : path41 !== void 0 ? { symbol, path: path41 } : kind !== void 0 ? { symbol, kind } : { symbol };
|
|
24330
24241
|
return item;
|
|
24331
24242
|
}
|
|
24332
24243
|
function classifySpawnError(err) {
|
|
@@ -26302,305 +26213,10 @@ function walkFiles(dir, callback) {
|
|
|
26302
26213
|
}
|
|
26303
26214
|
}
|
|
26304
26215
|
|
|
26305
|
-
// src/
|
|
26306
|
-
import crypto5 from "crypto";
|
|
26216
|
+
// src/sync/index.ts
|
|
26307
26217
|
import fs4 from "fs";
|
|
26308
26218
|
import path31 from "path";
|
|
26309
|
-
|
|
26310
|
-
var DEFAULT_MAX_LOAD = 1e4;
|
|
26311
|
-
function normalizeThreshold(value, defaultValue) {
|
|
26312
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1 ? value : defaultValue;
|
|
26313
|
-
}
|
|
26314
|
-
function normalizeMaxLoad(value, defaultValue) {
|
|
26315
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : defaultValue;
|
|
26316
|
-
}
|
|
26317
|
-
function findDuplicates(options) {
|
|
26318
|
-
const startTime = Date.now();
|
|
26319
|
-
const { memoryDir } = options;
|
|
26320
|
-
const threshold = normalizeThreshold(options.threshold, DEFAULT_DEDUP_THRESHOLD);
|
|
26321
|
-
const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);
|
|
26322
|
-
const memories = loadMemories(memoryDir, options.categories, maxLoad);
|
|
26323
|
-
const duplicates = [];
|
|
26324
|
-
for (let i = 0; i < memories.length; i++) {
|
|
26325
|
-
for (let j = i + 1; j < memories.length; j++) {
|
|
26326
|
-
const sim = computeSimilarity(memories[i].content, memories[j].content);
|
|
26327
|
-
if (sim >= threshold) {
|
|
26328
|
-
duplicates.push({
|
|
26329
|
-
left: memories[i],
|
|
26330
|
-
right: memories[j],
|
|
26331
|
-
similarity: sim,
|
|
26332
|
-
action: sim >= 0.98 ? "merge" : sim >= 0.9 ? "keep_right" : "keep_left"
|
|
26333
|
-
});
|
|
26334
|
-
}
|
|
26335
|
-
}
|
|
26336
|
-
}
|
|
26337
|
-
return {
|
|
26338
|
-
scanned: memories.length,
|
|
26339
|
-
duplicates,
|
|
26340
|
-
durationMs: Date.now() - startTime
|
|
26341
|
-
};
|
|
26342
|
-
}
|
|
26343
|
-
function findContradictions(options) {
|
|
26344
|
-
const startTime = Date.now();
|
|
26345
|
-
const { memoryDir } = options;
|
|
26346
|
-
const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);
|
|
26347
|
-
const memories = loadMemories(memoryDir, options.categories, maxLoad);
|
|
26348
|
-
const contradictions = [];
|
|
26349
|
-
for (let i = 0; i < memories.length; i++) {
|
|
26350
|
-
for (let j = i + 1; j < memories.length; j++) {
|
|
26351
|
-
const contra = detectContradiction(memories[i], memories[j]);
|
|
26352
|
-
if (contra) {
|
|
26353
|
-
contradictions.push(contra);
|
|
26354
|
-
}
|
|
26355
|
-
}
|
|
26356
|
-
}
|
|
26357
|
-
return {
|
|
26358
|
-
scanned: memories.length,
|
|
26359
|
-
contradictions,
|
|
26360
|
-
durationMs: Date.now() - startTime
|
|
26361
|
-
};
|
|
26362
|
-
}
|
|
26363
|
-
function computeSimilarity(a, b) {
|
|
26364
|
-
const normA = normalize(a);
|
|
26365
|
-
const normB = normalize(b);
|
|
26366
|
-
const punctuationBoundariesA = embeddedPunctuationSignature(a);
|
|
26367
|
-
const punctuationBoundariesB = embeddedPunctuationSignature(b);
|
|
26368
|
-
if (punctuationBoundariesA !== punctuationBoundariesB) return 0;
|
|
26369
|
-
if (normA === normB) return 1;
|
|
26370
|
-
if (hashContent2(normA) === hashContent2(normB)) return 0.99;
|
|
26371
|
-
if (normA.length > 50 && normB.length > 50) {
|
|
26372
|
-
if (normA.includes(normB.slice(0, 40)) || normB.includes(normA.slice(0, 40))) {
|
|
26373
|
-
return 0.9;
|
|
26374
|
-
}
|
|
26375
|
-
}
|
|
26376
|
-
const wordsA = tokenizeForSimilarity(normA);
|
|
26377
|
-
const wordsB = tokenizeForSimilarity(normB);
|
|
26378
|
-
const intersection = new Set([...wordsA].filter((w) => wordsB.has(w)));
|
|
26379
|
-
const union = /* @__PURE__ */ new Set([...wordsA, ...wordsB]);
|
|
26380
|
-
if (union.size === 0) return 0;
|
|
26381
|
-
return intersection.size / union.size;
|
|
26382
|
-
}
|
|
26383
|
-
function embeddedPunctuationSignature(text) {
|
|
26384
|
-
const chars = [...text.normalize("NFC")];
|
|
26385
|
-
const significant = /[\p{L}\p{M}\p{N}]/u;
|
|
26386
|
-
const ignored = /[\s']/u;
|
|
26387
|
-
const boundaries = [];
|
|
26388
|
-
let position = 0;
|
|
26389
|
-
for (let index = 0; index < chars.length; ) {
|
|
26390
|
-
const char = chars[index];
|
|
26391
|
-
if (char === void 0) break;
|
|
26392
|
-
if (significant.test(char)) {
|
|
26393
|
-
position++;
|
|
26394
|
-
index++;
|
|
26395
|
-
continue;
|
|
26396
|
-
}
|
|
26397
|
-
if (ignored.test(char)) {
|
|
26398
|
-
index++;
|
|
26399
|
-
continue;
|
|
26400
|
-
}
|
|
26401
|
-
const start = index;
|
|
26402
|
-
while (index < chars.length) {
|
|
26403
|
-
const next = chars[index];
|
|
26404
|
-
if (next === void 0 || significant.test(next) || ignored.test(next)) break;
|
|
26405
|
-
index++;
|
|
26406
|
-
}
|
|
26407
|
-
const before = chars[start - 1];
|
|
26408
|
-
const after = chars[index];
|
|
26409
|
-
if (before && after && significant.test(before) && significant.test(after)) {
|
|
26410
|
-
boundaries.push(`${position}:${chars.slice(start, index).join("")}`);
|
|
26411
|
-
}
|
|
26412
|
-
}
|
|
26413
|
-
return boundaries.join("\0");
|
|
26414
|
-
}
|
|
26415
|
-
function normalize(text) {
|
|
26416
|
-
return text.normalize("NFC").toLowerCase().replace(/[^\p{ASCII}\p{L}\p{M}\p{N}\s']/gu, " ").replace(/[^\p{L}\p{M}\p{N}\s']/gu, "").replace(/\s+/g, " ").trim();
|
|
26417
|
-
}
|
|
26418
|
-
function tokenizeForSimilarity(text) {
|
|
26419
|
-
if (/\p{Script=Hangul}/u.test(text)) {
|
|
26420
|
-
const tokens = normalizeRecallTokenSet(text);
|
|
26421
|
-
for (const segment of text.match(/\p{Script=Hangul}+/gu) ?? []) {
|
|
26422
|
-
const chars = [...segment];
|
|
26423
|
-
for (const size of [1, 2, 3, 4]) {
|
|
26424
|
-
for (let index = 0; index <= chars.length - size; index += 1) {
|
|
26425
|
-
tokens.add(chars.slice(index, index + size).join(""));
|
|
26426
|
-
}
|
|
26427
|
-
}
|
|
26428
|
-
}
|
|
26429
|
-
return tokens;
|
|
26430
|
-
}
|
|
26431
|
-
if (/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(text)) {
|
|
26432
|
-
return normalizeRecallTokenSet(text);
|
|
26433
|
-
}
|
|
26434
|
-
return text.length === 0 ? /* @__PURE__ */ new Set() : new Set(text.split(/\s+/));
|
|
26435
|
-
}
|
|
26436
|
-
var NEGATION_WORDS = /* @__PURE__ */ new Set([
|
|
26437
|
-
"not",
|
|
26438
|
-
"don't",
|
|
26439
|
-
"doesn't",
|
|
26440
|
-
"isn't",
|
|
26441
|
-
"aren't",
|
|
26442
|
-
"won't",
|
|
26443
|
-
"can't",
|
|
26444
|
-
"cannot",
|
|
26445
|
-
"never",
|
|
26446
|
-
"no",
|
|
26447
|
-
"none",
|
|
26448
|
-
"neither",
|
|
26449
|
-
"nor",
|
|
26450
|
-
"nothing",
|
|
26451
|
-
"nowhere"
|
|
26452
|
-
]);
|
|
26453
|
-
function detectContradiction(a, b) {
|
|
26454
|
-
const normA = normalize(a.content);
|
|
26455
|
-
const normB = normalize(b.content);
|
|
26456
|
-
const aHasNegation = containsNegation(normA);
|
|
26457
|
-
const bHasNegation = containsNegation(normB);
|
|
26458
|
-
if (aHasNegation === bHasNegation) return null;
|
|
26459
|
-
const strippedA = stripNegation(normA);
|
|
26460
|
-
const strippedB = stripNegation(normB);
|
|
26461
|
-
const sim = computeSimilarity(strippedA, strippedB);
|
|
26462
|
-
if (sim < 0.7) return null;
|
|
26463
|
-
const oppQuantifiers = [
|
|
26464
|
-
["always", "never"],
|
|
26465
|
-
["all", "none"],
|
|
26466
|
-
["every", "no"],
|
|
26467
|
-
["must", "must not"],
|
|
26468
|
-
["should", "should not"],
|
|
26469
|
-
["can", "cannot"]
|
|
26470
|
-
];
|
|
26471
|
-
for (const [pos, neg] of oppQuantifiers) {
|
|
26472
|
-
if (a.content.toLowerCase().includes(pos) && b.content.toLowerCase().includes(neg) || a.content.toLowerCase().includes(neg) && b.content.toLowerCase().includes(pos)) {
|
|
26473
|
-
return {
|
|
26474
|
-
left: a,
|
|
26475
|
-
right: b,
|
|
26476
|
-
severity: "high",
|
|
26477
|
-
reason: `Opposite quantifiers: "${pos}" vs "${neg}"`
|
|
26478
|
-
};
|
|
26479
|
-
}
|
|
26480
|
-
}
|
|
26481
|
-
return {
|
|
26482
|
-
left: a,
|
|
26483
|
-
right: b,
|
|
26484
|
-
severity: sim >= 0.85 ? "high" : "medium",
|
|
26485
|
-
reason: "Negated version of similar content"
|
|
26486
|
-
};
|
|
26487
|
-
}
|
|
26488
|
-
function containsNegation(text) {
|
|
26489
|
-
const words = text.split(/\s+/);
|
|
26490
|
-
return words.some((w) => NEGATION_WORDS.has(w));
|
|
26491
|
-
}
|
|
26492
|
-
function escapeRegExp(value) {
|
|
26493
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26494
|
-
}
|
|
26495
|
-
var stripNegationPattern = null;
|
|
26496
|
-
var stripNegationPatternSource = null;
|
|
26497
|
-
function stripNegationRegex() {
|
|
26498
|
-
const alternation = [...NEGATION_WORDS].sort((a, b) => b.length - a.length).map(escapeRegExp).join("|");
|
|
26499
|
-
if (stripNegationPattern === null || stripNegationPatternSource !== alternation) {
|
|
26500
|
-
stripNegationPattern = new RegExp(`\\b(?:${alternation})\\b`, "gi");
|
|
26501
|
-
stripNegationPatternSource = alternation;
|
|
26502
|
-
}
|
|
26503
|
-
return stripNegationPattern;
|
|
26504
|
-
}
|
|
26505
|
-
function stripNegation(text) {
|
|
26506
|
-
return text.replace(stripNegationRegex(), "").replace(/\s+/g, " ").trim();
|
|
26507
|
-
}
|
|
26508
|
-
function loadMemories(memoryDir, categories, maxLoad = 1e4) {
|
|
26509
|
-
const result = [];
|
|
26510
|
-
const allCategories = categories ?? ALL_CATEGORY_DIRS;
|
|
26511
|
-
if (!fs4.existsSync(memoryDir)) return result;
|
|
26512
|
-
const memoryRootReal = fs4.realpathSync(memoryDir);
|
|
26513
|
-
for (const category of allCategories) {
|
|
26514
|
-
if (result.length >= maxLoad) break;
|
|
26515
|
-
const dir = path31.join(memoryDir, category);
|
|
26516
|
-
if (!fs4.existsSync(dir)) continue;
|
|
26517
|
-
const categoryStat = fs4.lstatSync(dir);
|
|
26518
|
-
if (categoryStat.isSymbolicLink()) {
|
|
26519
|
-
throw new Error(`Refusing to scan symlinked memory category directory: ${dir}`);
|
|
26520
|
-
}
|
|
26521
|
-
if (!categoryStat.isDirectory()) continue;
|
|
26522
|
-
const categoryRootReal = fs4.realpathSync(dir);
|
|
26523
|
-
assertPathInsideRoot2(memoryRootReal, categoryRootReal, dir);
|
|
26524
|
-
walkMdFiles(dir, memoryRootReal, categoryRootReal, (filePath) => {
|
|
26525
|
-
if (result.length >= maxLoad) return;
|
|
26526
|
-
const content = readFileSafe2(filePath, memoryRootReal, categoryRootReal);
|
|
26527
|
-
if (!content) return;
|
|
26528
|
-
const fm = parseFrontmatter3(content);
|
|
26529
|
-
const body = extractBody3(content);
|
|
26530
|
-
if (!fm?.id || !body) return;
|
|
26531
|
-
result.push({
|
|
26532
|
-
id: fm.id,
|
|
26533
|
-
content: body,
|
|
26534
|
-
category: fm.category ?? category.slice(0, -1),
|
|
26535
|
-
filePath
|
|
26536
|
-
});
|
|
26537
|
-
});
|
|
26538
|
-
}
|
|
26539
|
-
return result;
|
|
26540
|
-
}
|
|
26541
|
-
function hashContent2(content) {
|
|
26542
|
-
return crypto5.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
26543
|
-
}
|
|
26544
|
-
function readFileSafe2(filePath, memoryRootReal, categoryRootReal) {
|
|
26545
|
-
try {
|
|
26546
|
-
const fileStat = fs4.lstatSync(filePath);
|
|
26547
|
-
if (fileStat.isSymbolicLink()) {
|
|
26548
|
-
throw new Error(`Refusing to read symlinked memory file: ${filePath}`);
|
|
26549
|
-
}
|
|
26550
|
-
const fileReal = fs4.realpathSync(filePath);
|
|
26551
|
-
assertPathInsideRoot2(memoryRootReal, fileReal, filePath);
|
|
26552
|
-
assertPathInsideRoot2(categoryRootReal, fileReal, filePath);
|
|
26553
|
-
return fs4.readFileSync(filePath, "utf8");
|
|
26554
|
-
} catch {
|
|
26555
|
-
return null;
|
|
26556
|
-
}
|
|
26557
|
-
}
|
|
26558
|
-
function parseFrontmatter3(content) {
|
|
26559
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
26560
|
-
if (!match) return null;
|
|
26561
|
-
const fm = {};
|
|
26562
|
-
for (const line of match[1].split("\n")) {
|
|
26563
|
-
const colonIdx = line.indexOf(":");
|
|
26564
|
-
if (colonIdx === -1) continue;
|
|
26565
|
-
const key = line.slice(0, colonIdx).trim();
|
|
26566
|
-
const value = line.slice(colonIdx + 1).trim();
|
|
26567
|
-
fm[key] = value;
|
|
26568
|
-
}
|
|
26569
|
-
return fm;
|
|
26570
|
-
}
|
|
26571
|
-
function extractBody3(content) {
|
|
26572
|
-
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)/);
|
|
26573
|
-
return match ? match[1].trim() : content.trim();
|
|
26574
|
-
}
|
|
26575
|
-
function assertPathInsideRoot2(rootReal, targetReal, sourcePath) {
|
|
26576
|
-
const rel = path31.relative(rootReal, targetReal);
|
|
26577
|
-
if (rel === "" || !rel.startsWith("..") && !path31.isAbsolute(rel)) {
|
|
26578
|
-
return;
|
|
26579
|
-
}
|
|
26580
|
-
throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);
|
|
26581
|
-
}
|
|
26582
|
-
function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
26583
|
-
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
26584
|
-
const fullPath = path31.join(dir, entry.name);
|
|
26585
|
-
const entryStat = fs4.lstatSync(fullPath);
|
|
26586
|
-
if (entryStat.isSymbolicLink()) {
|
|
26587
|
-
throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);
|
|
26588
|
-
}
|
|
26589
|
-
const entryReal = fs4.realpathSync(fullPath);
|
|
26590
|
-
assertPathInsideRoot2(memoryRootReal, entryReal, fullPath);
|
|
26591
|
-
assertPathInsideRoot2(categoryRootReal, entryReal, fullPath);
|
|
26592
|
-
if (entryStat.isDirectory()) {
|
|
26593
|
-
walkMdFiles(fullPath, memoryRootReal, categoryRootReal, callback);
|
|
26594
|
-
} else if (entry.name.endsWith(".md")) {
|
|
26595
|
-
callback(fullPath);
|
|
26596
|
-
}
|
|
26597
|
-
}
|
|
26598
|
-
}
|
|
26599
|
-
|
|
26600
|
-
// src/sync/index.ts
|
|
26601
|
-
import fs5 from "fs";
|
|
26602
|
-
import path32 from "path";
|
|
26603
|
-
import crypto6 from "crypto";
|
|
26219
|
+
import crypto5 from "crypto";
|
|
26604
26220
|
var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
26605
26221
|
var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
|
|
26606
26222
|
"node_modules",
|
|
@@ -26621,7 +26237,7 @@ function syncChanges(options) {
|
|
|
26621
26237
|
} = options;
|
|
26622
26238
|
const extSet = new Set(extensions);
|
|
26623
26239
|
const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs]);
|
|
26624
|
-
const stateFilePath = options.stateFile ??
|
|
26240
|
+
const stateFilePath = options.stateFile ?? path31.join(memoryDir, ".sync-state.json");
|
|
26625
26241
|
const prevState = loadState(stateFilePath);
|
|
26626
26242
|
const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
|
|
26627
26243
|
const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);
|
|
@@ -26637,8 +26253,8 @@ function syncChanges(options) {
|
|
|
26637
26253
|
for (const [relPath, hash] of Object.entries(currentFiles)) {
|
|
26638
26254
|
newState.fileHashes[relPath] = hash;
|
|
26639
26255
|
}
|
|
26640
|
-
|
|
26641
|
-
|
|
26256
|
+
fs4.mkdirSync(path31.dirname(stateFilePath), { recursive: true });
|
|
26257
|
+
fs4.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
|
|
26642
26258
|
}
|
|
26643
26259
|
return {
|
|
26644
26260
|
scanned: Object.keys(currentFiles).length,
|
|
@@ -26692,7 +26308,7 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26692
26308
|
function walk(dir, isRoot = false) {
|
|
26693
26309
|
let entries;
|
|
26694
26310
|
try {
|
|
26695
|
-
entries =
|
|
26311
|
+
entries = fs4.readdirSync(dir, { withFileTypes: true });
|
|
26696
26312
|
} catch (err) {
|
|
26697
26313
|
if (isRoot) {
|
|
26698
26314
|
throw new Error(
|
|
@@ -26703,16 +26319,16 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26703
26319
|
}
|
|
26704
26320
|
for (const entry of entries) {
|
|
26705
26321
|
if (exclude.has(entry.name)) continue;
|
|
26706
|
-
const fullPath =
|
|
26322
|
+
const fullPath = path31.join(dir, entry.name);
|
|
26707
26323
|
if (entry.isDirectory()) {
|
|
26708
26324
|
walk(fullPath);
|
|
26709
26325
|
} else if (entry.isFile()) {
|
|
26710
|
-
const ext =
|
|
26326
|
+
const ext = path31.extname(entry.name).toLowerCase();
|
|
26711
26327
|
if (!extensions.has(ext)) continue;
|
|
26712
|
-
const relPath =
|
|
26328
|
+
const relPath = path31.relative(root, fullPath);
|
|
26713
26329
|
try {
|
|
26714
|
-
const content =
|
|
26715
|
-
result[relPath] =
|
|
26330
|
+
const content = fs4.readFileSync(fullPath, "utf8");
|
|
26331
|
+
result[relPath] = hashContent2(content);
|
|
26716
26332
|
} catch {
|
|
26717
26333
|
}
|
|
26718
26334
|
}
|
|
@@ -26724,11 +26340,11 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26724
26340
|
function computeDiff(current, previous, sourceDir) {
|
|
26725
26341
|
const changes = [];
|
|
26726
26342
|
for (const [relPath, hash] of Object.entries(current)) {
|
|
26727
|
-
const fullPath =
|
|
26343
|
+
const fullPath = path31.join(sourceDir, relPath);
|
|
26728
26344
|
if (!(relPath in previous)) {
|
|
26729
26345
|
let size = 0;
|
|
26730
26346
|
try {
|
|
26731
|
-
size =
|
|
26347
|
+
size = fs4.statSync(fullPath).size;
|
|
26732
26348
|
} catch {
|
|
26733
26349
|
}
|
|
26734
26350
|
changes.push({
|
|
@@ -26741,7 +26357,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26741
26357
|
} else if (previous[relPath] !== hash) {
|
|
26742
26358
|
let size = 0;
|
|
26743
26359
|
try {
|
|
26744
|
-
size =
|
|
26360
|
+
size = fs4.statSync(fullPath).size;
|
|
26745
26361
|
} catch {
|
|
26746
26362
|
}
|
|
26747
26363
|
changes.push({
|
|
@@ -26757,7 +26373,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26757
26373
|
for (const relPath of Object.keys(previous)) {
|
|
26758
26374
|
if (!(relPath in current)) {
|
|
26759
26375
|
changes.push({
|
|
26760
|
-
filePath:
|
|
26376
|
+
filePath: path31.join(sourceDir, relPath),
|
|
26761
26377
|
relativePath: relPath,
|
|
26762
26378
|
type: "deleted",
|
|
26763
26379
|
currentHash: "",
|
|
@@ -26769,7 +26385,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26769
26385
|
}
|
|
26770
26386
|
function loadState(stateFilePath) {
|
|
26771
26387
|
try {
|
|
26772
|
-
const raw =
|
|
26388
|
+
const raw = fs4.readFileSync(stateFilePath, "utf8");
|
|
26773
26389
|
return JSON.parse(raw);
|
|
26774
26390
|
} catch {
|
|
26775
26391
|
return {
|
|
@@ -26779,32 +26395,32 @@ function loadState(stateFilePath) {
|
|
|
26779
26395
|
};
|
|
26780
26396
|
}
|
|
26781
26397
|
}
|
|
26782
|
-
function
|
|
26783
|
-
return
|
|
26398
|
+
function hashContent2(content) {
|
|
26399
|
+
return crypto5.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
26784
26400
|
}
|
|
26785
26401
|
|
|
26786
26402
|
// src/spaces/index.ts
|
|
26787
26403
|
import { spawnSync } from "child_process";
|
|
26788
|
-
import
|
|
26789
|
-
import
|
|
26790
|
-
import
|
|
26404
|
+
import crypto6 from "crypto";
|
|
26405
|
+
import fs5 from "fs";
|
|
26406
|
+
import path32 from "path";
|
|
26791
26407
|
var historicalIdCache3 = new HistoricalEntityCanonicalIdCache();
|
|
26792
26408
|
var MANIFEST_VERSION = 1;
|
|
26793
26409
|
var MANIFEST_LOCK_STALE_MS = 3e4;
|
|
26794
26410
|
var MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 1e4;
|
|
26795
26411
|
var MANIFEST_LOCK_SLEEP_MS = 20;
|
|
26796
26412
|
function normalizeSpaceMemoryDir(memoryDir) {
|
|
26797
|
-
return
|
|
26413
|
+
return path32.resolve(memoryDir);
|
|
26798
26414
|
}
|
|
26799
26415
|
function getSpacesDir(baseDir) {
|
|
26800
26416
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
26801
|
-
return
|
|
26417
|
+
return path32.join(homeDir, ".config", "engram", "spaces");
|
|
26802
26418
|
}
|
|
26803
26419
|
function getManifestPath(baseDir) {
|
|
26804
|
-
return
|
|
26420
|
+
return path32.join(getSpacesDir(baseDir), "manifest.json");
|
|
26805
26421
|
}
|
|
26806
26422
|
function loadManifest(baseDir, memoryDirOverride) {
|
|
26807
|
-
if (
|
|
26423
|
+
if (fs5.existsSync(getManifestPath(baseDir))) {
|
|
26808
26424
|
try {
|
|
26809
26425
|
return readManifestUnlocked(baseDir, memoryDirOverride, { bootstrapIfMissing: false });
|
|
26810
26426
|
} catch (error) {
|
|
@@ -26830,7 +26446,7 @@ function updateManifest(baseDir, updater, memoryDirOverride) {
|
|
|
26830
26446
|
}
|
|
26831
26447
|
function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
|
|
26832
26448
|
const manifestPath2 = getManifestPath(baseDir);
|
|
26833
|
-
if (!
|
|
26449
|
+
if (!fs5.existsSync(manifestPath2)) {
|
|
26834
26450
|
if (options.bootstrapIfMissing === false) {
|
|
26835
26451
|
const error = new Error(`Spaces manifest not found: ${manifestPath2}`);
|
|
26836
26452
|
error.code = "ENOENT";
|
|
@@ -26843,21 +26459,21 @@ function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
|
|
|
26843
26459
|
version: MANIFEST_VERSION
|
|
26844
26460
|
};
|
|
26845
26461
|
}
|
|
26846
|
-
const raw = JSON.parse(
|
|
26462
|
+
const raw = JSON.parse(fs5.readFileSync(manifestPath2, "utf8"));
|
|
26847
26463
|
return raw;
|
|
26848
26464
|
}
|
|
26849
26465
|
function saveManifestUnlocked(manifest, baseDir) {
|
|
26850
26466
|
const manifestPath2 = getManifestPath(baseDir);
|
|
26851
|
-
const manifestDir2 =
|
|
26852
|
-
|
|
26853
|
-
const tempPath =
|
|
26467
|
+
const manifestDir2 = path32.dirname(manifestPath2);
|
|
26468
|
+
fs5.mkdirSync(manifestDir2, { recursive: true });
|
|
26469
|
+
const tempPath = path32.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto6.randomUUID()}.tmp`);
|
|
26854
26470
|
try {
|
|
26855
|
-
|
|
26471
|
+
fs5.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}
|
|
26856
26472
|
`, { flag: "wx" });
|
|
26857
|
-
|
|
26473
|
+
fs5.renameSync(tempPath, manifestPath2);
|
|
26858
26474
|
} catch (error) {
|
|
26859
26475
|
try {
|
|
26860
|
-
|
|
26476
|
+
fs5.rmSync(tempPath, { force: true });
|
|
26861
26477
|
} catch {
|
|
26862
26478
|
}
|
|
26863
26479
|
throw error;
|
|
@@ -26865,7 +26481,7 @@ function saveManifestUnlocked(manifest, baseDir) {
|
|
|
26865
26481
|
}
|
|
26866
26482
|
function withManifestLock(baseDir, operation) {
|
|
26867
26483
|
const lockDir = `${getManifestPath(baseDir)}.lock`;
|
|
26868
|
-
|
|
26484
|
+
fs5.mkdirSync(path32.dirname(lockDir), { recursive: true });
|
|
26869
26485
|
const lockOwner = acquireManifestLock(lockDir);
|
|
26870
26486
|
try {
|
|
26871
26487
|
return operation();
|
|
@@ -26878,10 +26494,10 @@ function acquireManifestLock(lockDir) {
|
|
|
26878
26494
|
const owner = createManifestLockOwner();
|
|
26879
26495
|
const reclaimDir = getManifestLockReclaimDir(lockDir);
|
|
26880
26496
|
while (true) {
|
|
26881
|
-
if (
|
|
26497
|
+
if (fs5.existsSync(reclaimDir)) {
|
|
26882
26498
|
removeStaleManifestReclaimLock(reclaimDir);
|
|
26883
26499
|
}
|
|
26884
|
-
if (
|
|
26500
|
+
if (fs5.existsSync(reclaimDir)) {
|
|
26885
26501
|
if (Date.now() >= deadline) {
|
|
26886
26502
|
throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);
|
|
26887
26503
|
}
|
|
@@ -26889,15 +26505,15 @@ function acquireManifestLock(lockDir) {
|
|
|
26889
26505
|
continue;
|
|
26890
26506
|
}
|
|
26891
26507
|
try {
|
|
26892
|
-
|
|
26508
|
+
fs5.mkdirSync(lockDir, { recursive: false });
|
|
26893
26509
|
try {
|
|
26894
|
-
|
|
26510
|
+
fs5.writeFileSync(path32.join(lockDir, "owner"), `${owner}
|
|
26895
26511
|
`, { flag: "wx" });
|
|
26896
26512
|
} catch (error) {
|
|
26897
|
-
|
|
26513
|
+
fs5.rmSync(lockDir, { recursive: true, force: true });
|
|
26898
26514
|
throw error;
|
|
26899
26515
|
}
|
|
26900
|
-
if (
|
|
26516
|
+
if (fs5.existsSync(reclaimDir)) {
|
|
26901
26517
|
releaseManifestLock(lockDir, owner);
|
|
26902
26518
|
if (Date.now() >= deadline) {
|
|
26903
26519
|
throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);
|
|
@@ -26921,9 +26537,9 @@ function acquireManifestLock(lockDir) {
|
|
|
26921
26537
|
}
|
|
26922
26538
|
function releaseManifestLock(lockDir, owner) {
|
|
26923
26539
|
try {
|
|
26924
|
-
const ownerPath =
|
|
26925
|
-
if (
|
|
26926
|
-
|
|
26540
|
+
const ownerPath = path32.join(lockDir, "owner");
|
|
26541
|
+
if (fs5.readFileSync(ownerPath, "utf8").trim() === owner) {
|
|
26542
|
+
fs5.rmSync(lockDir, { recursive: true, force: true });
|
|
26927
26543
|
}
|
|
26928
26544
|
} catch (error) {
|
|
26929
26545
|
if (error.code !== "ENOENT") {
|
|
@@ -26935,12 +26551,12 @@ function removeStaleManifestLock(lockDir) {
|
|
|
26935
26551
|
const reclaimDir = getManifestLockReclaimDir(lockDir);
|
|
26936
26552
|
const reclaimOwner = createManifestLockOwner();
|
|
26937
26553
|
try {
|
|
26938
|
-
|
|
26554
|
+
fs5.mkdirSync(reclaimDir, { recursive: false });
|
|
26939
26555
|
try {
|
|
26940
|
-
|
|
26556
|
+
fs5.writeFileSync(path32.join(reclaimDir, "owner"), `${reclaimOwner}
|
|
26941
26557
|
`, { flag: "wx" });
|
|
26942
26558
|
} catch (error) {
|
|
26943
|
-
|
|
26559
|
+
fs5.rmSync(reclaimDir, { recursive: true, force: true });
|
|
26944
26560
|
throw error;
|
|
26945
26561
|
}
|
|
26946
26562
|
} catch (error) {
|
|
@@ -26958,18 +26574,18 @@ function removeStaleManifestLock(lockDir) {
|
|
|
26958
26574
|
if (isManifestLockOwnerActive(snapshot.owner)) {
|
|
26959
26575
|
return;
|
|
26960
26576
|
}
|
|
26961
|
-
const tombstoneDir = `${lockDir}.stale.${process.pid}.${
|
|
26577
|
+
const tombstoneDir = `${lockDir}.stale.${process.pid}.${crypto6.randomUUID()}`;
|
|
26962
26578
|
try {
|
|
26963
|
-
|
|
26579
|
+
fs5.renameSync(lockDir, tombstoneDir);
|
|
26964
26580
|
} catch (error) {
|
|
26965
26581
|
if (error.code !== "ENOENT") {
|
|
26966
26582
|
throw error;
|
|
26967
26583
|
}
|
|
26968
26584
|
return;
|
|
26969
26585
|
}
|
|
26970
|
-
|
|
26586
|
+
fs5.rmSync(tombstoneDir, { recursive: true, force: true });
|
|
26971
26587
|
} finally {
|
|
26972
|
-
|
|
26588
|
+
fs5.rmSync(reclaimDir, { recursive: true, force: true });
|
|
26973
26589
|
}
|
|
26974
26590
|
}
|
|
26975
26591
|
function getManifestLockReclaimDir(lockDir) {
|
|
@@ -26979,7 +26595,7 @@ function createManifestLockOwner() {
|
|
|
26979
26595
|
return JSON.stringify({
|
|
26980
26596
|
pid: process.pid,
|
|
26981
26597
|
startKey: readProcessStartKey(process.pid),
|
|
26982
|
-
token:
|
|
26598
|
+
token: crypto6.randomUUID()
|
|
26983
26599
|
});
|
|
26984
26600
|
}
|
|
26985
26601
|
function removeStaleManifestReclaimLock(reclaimDir) {
|
|
@@ -26990,21 +26606,21 @@ function removeStaleManifestReclaimLock(reclaimDir) {
|
|
|
26990
26606
|
if (isManifestLockOwnerActive(snapshot.owner)) {
|
|
26991
26607
|
return;
|
|
26992
26608
|
}
|
|
26993
|
-
const tombstoneDir = `${reclaimDir}.stale.${process.pid}.${
|
|
26609
|
+
const tombstoneDir = `${reclaimDir}.stale.${process.pid}.${crypto6.randomUUID()}`;
|
|
26994
26610
|
try {
|
|
26995
|
-
|
|
26611
|
+
fs5.renameSync(reclaimDir, tombstoneDir);
|
|
26996
26612
|
} catch (error) {
|
|
26997
26613
|
if (error.code !== "ENOENT") {
|
|
26998
26614
|
throw error;
|
|
26999
26615
|
}
|
|
27000
26616
|
return;
|
|
27001
26617
|
}
|
|
27002
|
-
|
|
26618
|
+
fs5.rmSync(tombstoneDir, { recursive: true, force: true });
|
|
27003
26619
|
}
|
|
27004
26620
|
function readManifestLockSnapshot(lockDir) {
|
|
27005
26621
|
let stat5;
|
|
27006
26622
|
try {
|
|
27007
|
-
stat5 =
|
|
26623
|
+
stat5 = fs5.statSync(lockDir);
|
|
27008
26624
|
} catch (error) {
|
|
27009
26625
|
if (error.code === "ENOENT") {
|
|
27010
26626
|
return void 0;
|
|
@@ -27012,7 +26628,7 @@ function readManifestLockSnapshot(lockDir) {
|
|
|
27012
26628
|
throw error;
|
|
27013
26629
|
}
|
|
27014
26630
|
try {
|
|
27015
|
-
const owner =
|
|
26631
|
+
const owner = fs5.readFileSync(path32.join(lockDir, "owner"), "utf8").trim();
|
|
27016
26632
|
return { mtimeMs: stat5.mtimeMs, owner };
|
|
27017
26633
|
} catch (error) {
|
|
27018
26634
|
if (error.code === "ENOENT") {
|
|
@@ -27084,9 +26700,9 @@ function sleepSync(ms) {
|
|
|
27084
26700
|
}
|
|
27085
26701
|
function createPersonalSpace(baseDir, memoryDirOverride) {
|
|
27086
26702
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
27087
|
-
const standalonePath =
|
|
27088
|
-
const openclawPath =
|
|
27089
|
-
const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (
|
|
26703
|
+
const standalonePath = path32.join(homeDir, ".engram", "memory");
|
|
26704
|
+
const openclawPath = path32.join(homeDir, ".openclaw", "workspace", "memory", "local");
|
|
26705
|
+
const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (fs5.existsSync(standalonePath) ? standalonePath : fs5.existsSync(openclawPath) ? openclawPath : standalonePath);
|
|
27090
26706
|
const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);
|
|
27091
26707
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
27092
26708
|
return {
|
|
@@ -27114,7 +26730,7 @@ function createSpace(options) {
|
|
|
27114
26730
|
const id = options.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
|
27115
26731
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
27116
26732
|
const memoryDir = normalizeSpaceMemoryDir(
|
|
27117
|
-
options.memoryDir ??
|
|
26733
|
+
options.memoryDir ?? path32.join(getSpacesDir(options.baseDir), id, "memory")
|
|
27118
26734
|
);
|
|
27119
26735
|
const space = updateManifest(options.baseDir, (manifest) => {
|
|
27120
26736
|
if (manifest.spaces.some((s) => s.id === id)) {
|
|
@@ -27134,7 +26750,7 @@ function createSpace(options) {
|
|
|
27134
26750
|
owner: readEnvVar("USER"),
|
|
27135
26751
|
parentSpaceId: options.parentSpaceId
|
|
27136
26752
|
};
|
|
27137
|
-
|
|
26753
|
+
fs5.mkdirSync(memoryDir, { recursive: true });
|
|
27138
26754
|
manifest.spaces.push(created);
|
|
27139
26755
|
manifest.updatedAt = now;
|
|
27140
26756
|
return created;
|
|
@@ -27292,9 +26908,9 @@ async function promoteSpace(sourceSpaceId, targetSpaceId, options) {
|
|
|
27292
26908
|
const subjectWarnings = [];
|
|
27293
26909
|
const warnedMemoryIds = [];
|
|
27294
26910
|
if (target.kind === "team") {
|
|
27295
|
-
const sourceFiles =
|
|
26911
|
+
const sourceFiles = fs5.existsSync(source.memoryDir) ? walkMd(fs5.realpathSync(source.memoryDir)) : [];
|
|
27296
26912
|
for (const file of sourceFiles) {
|
|
27297
|
-
const fm = parseSimpleFrontmatter(
|
|
26913
|
+
const fm = parseSimpleFrontmatter(fs5.readFileSync(file, "utf8"));
|
|
27298
26914
|
if (!fm?.id) continue;
|
|
27299
26915
|
if (options?.memoryIds?.length && !options.memoryIds.includes(fm.id)) continue;
|
|
27300
26916
|
const decision = evaluateSubjectGuard({
|
|
@@ -27360,39 +26976,39 @@ async function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
|
|
|
27360
26976
|
};
|
|
27361
26977
|
}
|
|
27362
26978
|
function getAuditLog(baseDir) {
|
|
27363
|
-
const auditPath =
|
|
27364
|
-
if (!
|
|
27365
|
-
const lines =
|
|
26979
|
+
const auditPath = path32.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
26980
|
+
if (!fs5.existsSync(auditPath)) return [];
|
|
26981
|
+
const lines = fs5.readFileSync(auditPath, "utf8").trim().split("\n");
|
|
27366
26982
|
return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
27367
26983
|
}
|
|
27368
26984
|
function appendAudit(entry, baseDir) {
|
|
27369
|
-
const auditPath =
|
|
27370
|
-
|
|
26985
|
+
const auditPath = path32.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
26986
|
+
fs5.mkdirSync(path32.dirname(auditPath), { recursive: true });
|
|
27371
26987
|
const full = {
|
|
27372
|
-
id:
|
|
26988
|
+
id: crypto6.randomUUID(),
|
|
27373
26989
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27374
26990
|
...entry
|
|
27375
26991
|
};
|
|
27376
|
-
|
|
26992
|
+
fs5.appendFileSync(auditPath, `${JSON.stringify(full)}
|
|
27377
26993
|
`);
|
|
27378
26994
|
}
|
|
27379
26995
|
async function copyMemories(sourceDir, targetDir, options) {
|
|
27380
|
-
if (!
|
|
26996
|
+
if (!fs5.existsSync(sourceDir)) {
|
|
27381
26997
|
return { merged: 0, conflicts: [], skipped: 0 };
|
|
27382
26998
|
}
|
|
27383
|
-
const sourceRoot =
|
|
27384
|
-
|
|
27385
|
-
const targetRoot =
|
|
26999
|
+
const sourceRoot = fs5.realpathSync(sourceDir);
|
|
27000
|
+
fs5.mkdirSync(targetDir, { recursive: true });
|
|
27001
|
+
const targetRoot = fs5.realpathSync(targetDir);
|
|
27386
27002
|
const sourceFiles = walkMd(sourceRoot);
|
|
27387
27003
|
const sourceEntityIds = new Set(
|
|
27388
27004
|
sourceFiles.filter((p) => {
|
|
27389
27005
|
const rp = safeRealpath(p);
|
|
27390
27006
|
if (!rp || !isPathInsideRoot(rp, sourceRoot)) return false;
|
|
27391
|
-
const rel =
|
|
27392
|
-
const mapped =
|
|
27007
|
+
const rel = path32.relative(sourceRoot, rp);
|
|
27008
|
+
const mapped = path32.resolve(targetRoot, rel);
|
|
27393
27009
|
if (!isPathInsideRoot(mapped, targetRoot)) return false;
|
|
27394
27010
|
return classifyEntityRefWritePath(targetRoot, mapped) === "entity";
|
|
27395
|
-
}).map((p) =>
|
|
27011
|
+
}).map((p) => path32.basename(p, ".md"))
|
|
27396
27012
|
);
|
|
27397
27013
|
const firstEntityId = sourceEntityIds.values().next().value;
|
|
27398
27014
|
if (firstEntityId === void 0) {
|
|
@@ -27400,7 +27016,7 @@ async function copyMemories(sourceDir, targetDir, options) {
|
|
|
27400
27016
|
}
|
|
27401
27017
|
return withRawEntityPageMutation(
|
|
27402
27018
|
targetRoot,
|
|
27403
|
-
|
|
27019
|
+
path32.join(targetRoot, "entities", `${firstEntityId}.md`),
|
|
27404
27020
|
async () => copyPreparedMemories(
|
|
27405
27021
|
sourceFiles,
|
|
27406
27022
|
sourceRoot,
|
|
@@ -27426,19 +27042,19 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27426
27042
|
skipped++;
|
|
27427
27043
|
continue;
|
|
27428
27044
|
}
|
|
27429
|
-
const content =
|
|
27430
|
-
const relativePath =
|
|
27431
|
-
const targetPath =
|
|
27045
|
+
const content = fs5.readFileSync(sourcePath, "utf8");
|
|
27046
|
+
const relativePath = path32.relative(sourceRoot, sourceRealPath);
|
|
27047
|
+
const targetPath = path32.resolve(targetRoot, relativePath);
|
|
27432
27048
|
if (!isPathInsideRoot(targetPath, targetRoot)) {
|
|
27433
27049
|
skipped++;
|
|
27434
27050
|
continue;
|
|
27435
27051
|
}
|
|
27436
27052
|
const targetKind = classifyEntityRefWritePath(targetRoot, targetPath);
|
|
27437
|
-
const idsAtCompare = historicalIdCache3.get(
|
|
27053
|
+
const idsAtCompare = historicalIdCache3.get(path32.join(targetRoot, "state"));
|
|
27438
27054
|
const sourceRef = targetKind === "memory" ? readEntityRefFromFrontmatter(content) : null;
|
|
27439
27055
|
const refHasSourceClaimant = sourceRef !== null && sourceEntityIds.has(sourceRef);
|
|
27440
27056
|
const canonicalContent = targetKind === "memory" && !refHasSourceClaimant ? canonicalizeEntityRefFrontmatter(content, idsAtCompare) : content;
|
|
27441
|
-
const sourceHash =
|
|
27057
|
+
const sourceHash = hashContent3(content);
|
|
27442
27058
|
if (options?.filterIds?.length) {
|
|
27443
27059
|
const fm = parseSimpleFrontmatter(content);
|
|
27444
27060
|
if (!fm?.id || !options.filterIds.includes(fm.id)) {
|
|
@@ -27446,7 +27062,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27446
27062
|
continue;
|
|
27447
27063
|
}
|
|
27448
27064
|
}
|
|
27449
|
-
if (
|
|
27065
|
+
if (fs5.existsSync(targetPath)) {
|
|
27450
27066
|
const targetStat = safeLstat(targetPath);
|
|
27451
27067
|
if (!targetStat?.isFile() || targetStat.isSymbolicLink()) {
|
|
27452
27068
|
skipped++;
|
|
@@ -27458,14 +27074,14 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27458
27074
|
continue;
|
|
27459
27075
|
}
|
|
27460
27076
|
}
|
|
27461
|
-
if (
|
|
27462
|
-
const targetContent =
|
|
27463
|
-
const targetHash =
|
|
27464
|
-
if (
|
|
27077
|
+
if (fs5.existsSync(targetPath) && !options?.force) {
|
|
27078
|
+
const targetContent = fs5.readFileSync(targetPath, "utf8");
|
|
27079
|
+
const targetHash = hashContent3(targetContent);
|
|
27080
|
+
if (hashContent3(canonicalContent) === targetHash && historicalIdCache3.get(path32.join(targetRoot, "state")) === idsAtCompare) {
|
|
27465
27081
|
skipped++;
|
|
27466
27082
|
continue;
|
|
27467
27083
|
}
|
|
27468
|
-
if (
|
|
27084
|
+
if (hashContent3(canonicalContent) !== targetHash && sourceHash !== targetHash) {
|
|
27469
27085
|
conflicts.push({
|
|
27470
27086
|
memoryId: parseSimpleFrontmatter(content)?.id ?? relativePath,
|
|
27471
27087
|
sourcePath,
|
|
@@ -27477,23 +27093,23 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27477
27093
|
continue;
|
|
27478
27094
|
}
|
|
27479
27095
|
}
|
|
27480
|
-
|
|
27481
|
-
const targetParentRealPath = safeRealpath(
|
|
27096
|
+
fs5.mkdirSync(path32.dirname(targetPath), { recursive: true });
|
|
27097
|
+
const targetParentRealPath = safeRealpath(path32.dirname(targetPath));
|
|
27482
27098
|
if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {
|
|
27483
27099
|
skipped++;
|
|
27484
27100
|
continue;
|
|
27485
27101
|
}
|
|
27486
|
-
const stateDir =
|
|
27102
|
+
const stateDir = path32.join(targetRoot, "state");
|
|
27487
27103
|
if (targetKind === "memory" && !refHasSourceClaimant) {
|
|
27488
27104
|
const idsAtWrite = historicalIdCache3.get(stateDir);
|
|
27489
27105
|
const written = canonicalizeEntityRefFrontmatter(content, idsAtWrite);
|
|
27490
27106
|
let priorTarget = null;
|
|
27491
27107
|
try {
|
|
27492
|
-
priorTarget =
|
|
27108
|
+
priorTarget = fs5.readFileSync(targetPath, "utf8");
|
|
27493
27109
|
} catch {
|
|
27494
27110
|
priorTarget = null;
|
|
27495
27111
|
}
|
|
27496
|
-
|
|
27112
|
+
fs5.writeFileSync(targetPath, written);
|
|
27497
27113
|
try {
|
|
27498
27114
|
repairContentAfterJournalMoveSync({
|
|
27499
27115
|
stateDir,
|
|
@@ -27501,24 +27117,24 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27501
27117
|
idsAtWrite,
|
|
27502
27118
|
rawContent: content,
|
|
27503
27119
|
lastWritten: written,
|
|
27504
|
-
rewrite: (next) =>
|
|
27120
|
+
rewrite: (next) => fs5.writeFileSync(targetPath, next)
|
|
27505
27121
|
});
|
|
27506
27122
|
} catch (err) {
|
|
27507
27123
|
try {
|
|
27508
27124
|
if (priorTarget === null) {
|
|
27509
|
-
|
|
27125
|
+
fs5.unlinkSync(targetPath);
|
|
27510
27126
|
} else {
|
|
27511
|
-
|
|
27127
|
+
fs5.writeFileSync(targetPath, priorTarget);
|
|
27512
27128
|
}
|
|
27513
27129
|
} catch {
|
|
27514
27130
|
}
|
|
27515
27131
|
throw err;
|
|
27516
27132
|
}
|
|
27517
27133
|
} else if (targetKind === "memory") {
|
|
27518
|
-
|
|
27134
|
+
fs5.writeFileSync(targetPath, content);
|
|
27519
27135
|
reconcileNeeded = true;
|
|
27520
27136
|
} else {
|
|
27521
|
-
|
|
27137
|
+
fs5.writeFileSync(targetPath, content);
|
|
27522
27138
|
if (targetKind === "entity") {
|
|
27523
27139
|
reconcileNeeded = true;
|
|
27524
27140
|
}
|
|
@@ -27527,18 +27143,18 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27527
27143
|
bumpMemoryCorpusVersionForDir(targetRoot);
|
|
27528
27144
|
}
|
|
27529
27145
|
if (reconcileNeeded) {
|
|
27530
|
-
requestEntityCanonicalIdReconcileSync(
|
|
27146
|
+
requestEntityCanonicalIdReconcileSync(path32.join(targetRoot, "state"));
|
|
27531
27147
|
}
|
|
27532
27148
|
return { merged, conflicts, skipped };
|
|
27533
27149
|
}
|
|
27534
|
-
function
|
|
27535
|
-
return
|
|
27150
|
+
function hashContent3(content) {
|
|
27151
|
+
return crypto6.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
27536
27152
|
}
|
|
27537
27153
|
function walkMd(dir) {
|
|
27538
27154
|
const results = [];
|
|
27539
27155
|
function walk(d) {
|
|
27540
|
-
for (const entry of
|
|
27541
|
-
const fullPath =
|
|
27156
|
+
for (const entry of fs5.readdirSync(d, { withFileTypes: true })) {
|
|
27157
|
+
const fullPath = path32.join(d, entry.name);
|
|
27542
27158
|
if (entry.isSymbolicLink()) {
|
|
27543
27159
|
continue;
|
|
27544
27160
|
}
|
|
@@ -27554,21 +27170,21 @@ function walkMd(dir) {
|
|
|
27554
27170
|
}
|
|
27555
27171
|
function safeLstat(filePath) {
|
|
27556
27172
|
try {
|
|
27557
|
-
return
|
|
27173
|
+
return fs5.lstatSync(filePath);
|
|
27558
27174
|
} catch {
|
|
27559
27175
|
return null;
|
|
27560
27176
|
}
|
|
27561
27177
|
}
|
|
27562
27178
|
function safeRealpath(filePath) {
|
|
27563
27179
|
try {
|
|
27564
|
-
return
|
|
27180
|
+
return fs5.realpathSync(filePath);
|
|
27565
27181
|
} catch {
|
|
27566
27182
|
return null;
|
|
27567
27183
|
}
|
|
27568
27184
|
}
|
|
27569
27185
|
function isPathInsideRoot(candidatePath, rootPath) {
|
|
27570
|
-
const relative =
|
|
27571
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
27186
|
+
const relative = path32.relative(rootPath, candidatePath);
|
|
27187
|
+
return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
|
|
27572
27188
|
}
|
|
27573
27189
|
function parseSimpleFrontmatter(content) {
|
|
27574
27190
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -27687,9 +27303,9 @@ var REMNIC_RECALL_DECISION_RULES = `## When to Use Recall vs Direct Read
|
|
|
27687
27303
|
`;
|
|
27688
27304
|
|
|
27689
27305
|
// src/memory-extension/codex-publisher.ts
|
|
27690
|
-
import
|
|
27306
|
+
import fs6 from "fs";
|
|
27691
27307
|
import os from "os";
|
|
27692
|
-
import
|
|
27308
|
+
import path33 from "path";
|
|
27693
27309
|
var REMNIC_EXTENSION_DIR_NAME = "remnic";
|
|
27694
27310
|
function resolveEnvHome(env) {
|
|
27695
27311
|
if (env === void 0) return resolveHomeDir();
|
|
@@ -27698,12 +27314,12 @@ function resolveEnvHome(env) {
|
|
|
27698
27314
|
function expandTildeWithHome(input, homeDir) {
|
|
27699
27315
|
if (input === "~") return homeDir;
|
|
27700
27316
|
if (input.startsWith("~/") || input.startsWith("~\\")) {
|
|
27701
|
-
return
|
|
27317
|
+
return path33.join(homeDir, input.slice(2));
|
|
27702
27318
|
}
|
|
27703
27319
|
return input;
|
|
27704
27320
|
}
|
|
27705
27321
|
function normalizeHostRoot(input, homeDir) {
|
|
27706
|
-
return
|
|
27322
|
+
return path33.resolve(expandTildeWithHome(input.trim(), homeDir));
|
|
27707
27323
|
}
|
|
27708
27324
|
var CodexMemoryExtensionPublisher = class {
|
|
27709
27325
|
hostId = "codex";
|
|
@@ -27717,13 +27333,13 @@ var CodexMemoryExtensionPublisher = class {
|
|
|
27717
27333
|
async resolveExtensionRoot(env) {
|
|
27718
27334
|
const homeDir = resolveEnvHome(env);
|
|
27719
27335
|
const codexHomeInput = env === void 0 ? readEnvVar("CODEX_HOME")?.trim() : env.CODEX_HOME?.trim();
|
|
27720
|
-
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) :
|
|
27721
|
-
return
|
|
27336
|
+
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) : path33.resolve(homeDir, ".codex");
|
|
27337
|
+
return path33.join(codexHome, "memories_extensions", REMNIC_EXTENSION_DIR_NAME);
|
|
27722
27338
|
}
|
|
27723
27339
|
async isHostAvailable() {
|
|
27724
27340
|
try {
|
|
27725
|
-
const home = readEnvVar("CODEX_HOME")?.trim() ||
|
|
27726
|
-
return
|
|
27341
|
+
const home = readEnvVar("CODEX_HOME")?.trim() || path33.join(resolveHomeDir(), ".codex");
|
|
27342
|
+
return fs6.existsSync(home);
|
|
27727
27343
|
} catch {
|
|
27728
27344
|
return false;
|
|
27729
27345
|
}
|
|
@@ -27773,22 +27389,22 @@ When running inside the Codex phase-2 consolidation sandbox:
|
|
|
27773
27389
|
}
|
|
27774
27390
|
async publish(ctx) {
|
|
27775
27391
|
const extensionRoot = await this.resolveExtensionRoot();
|
|
27776
|
-
const instructionsPath =
|
|
27392
|
+
const instructionsPath = path33.join(extensionRoot, "instructions.md");
|
|
27777
27393
|
const filesWritten = [];
|
|
27778
27394
|
const skipped = [];
|
|
27779
27395
|
ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);
|
|
27780
|
-
|
|
27396
|
+
fs6.mkdirSync(extensionRoot, { recursive: true });
|
|
27781
27397
|
const content = await this.renderInstructions(ctx);
|
|
27782
27398
|
const tmpPath = `${instructionsPath}.tmp-${process.pid}-${Date.now()}`;
|
|
27783
27399
|
try {
|
|
27784
|
-
|
|
27785
|
-
|
|
27400
|
+
fs6.writeFileSync(tmpPath, content, "utf-8");
|
|
27401
|
+
fs6.renameSync(tmpPath, instructionsPath);
|
|
27786
27402
|
filesWritten.push(instructionsPath);
|
|
27787
27403
|
ctx.log.info(`Wrote ${instructionsPath}`);
|
|
27788
27404
|
} catch (err) {
|
|
27789
27405
|
try {
|
|
27790
|
-
if (
|
|
27791
|
-
|
|
27406
|
+
if (fs6.existsSync(tmpPath)) {
|
|
27407
|
+
fs6.unlinkSync(tmpPath);
|
|
27792
27408
|
}
|
|
27793
27409
|
} catch {
|
|
27794
27410
|
}
|
|
@@ -27803,8 +27419,8 @@ When running inside the Codex phase-2 consolidation sandbox:
|
|
|
27803
27419
|
}
|
|
27804
27420
|
async unpublish() {
|
|
27805
27421
|
const extensionRoot = await this.resolveExtensionRoot();
|
|
27806
|
-
if (
|
|
27807
|
-
|
|
27422
|
+
if (fs6.existsSync(extensionRoot)) {
|
|
27423
|
+
fs6.rmSync(extensionRoot, { recursive: true, force: true });
|
|
27808
27424
|
}
|
|
27809
27425
|
}
|
|
27810
27426
|
};
|
|
@@ -28405,9 +28021,9 @@ function buildWeeklyActivitySummary(cards, options) {
|
|
|
28405
28021
|
// src/activity/timeline/weekly-persist.ts
|
|
28406
28022
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
28407
28023
|
import { mkdirSync, readFileSync as readFileSync2, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
28408
|
-
import
|
|
28024
|
+
import path34 from "path";
|
|
28409
28025
|
var WEEKLY_SNAPSHOT_FORMAT_VERSION = 1;
|
|
28410
|
-
var WEEKLY_SNAPSHOT_DIR =
|
|
28026
|
+
var WEEKLY_SNAPSHOT_DIR = path34.join("activity", "weekly");
|
|
28411
28027
|
function requireToken(value, name) {
|
|
28412
28028
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
28413
28029
|
throw new TypeError(`${name} must be a non-empty string`);
|
|
@@ -28430,8 +28046,8 @@ function weeklySnapshotPath(input) {
|
|
|
28430
28046
|
const identity = hashActivityBody(
|
|
28431
28047
|
`${input.summary.weekStartUtc}\0${input.summary.weekEndUtc}\0${sourceRevision}\0${configHash}`
|
|
28432
28048
|
);
|
|
28433
|
-
return
|
|
28434
|
-
|
|
28049
|
+
return path34.join(
|
|
28050
|
+
path34.resolve(memoryDir),
|
|
28435
28051
|
WEEKLY_SNAPSHOT_DIR,
|
|
28436
28052
|
namespaceIdentityToken(namespace),
|
|
28437
28053
|
`${weekDate}--${identity}.json`
|
|
@@ -28461,7 +28077,7 @@ function persistWeeklySnapshot(input) {
|
|
|
28461
28077
|
throw error;
|
|
28462
28078
|
}
|
|
28463
28079
|
}
|
|
28464
|
-
mkdirSync(
|
|
28080
|
+
mkdirSync(path34.dirname(filePath), { recursive: true, mode: 448 });
|
|
28465
28081
|
const tmpPath = `${filePath}.${process.pid}.${randomBytes3(8).toString("hex")}.tmp`;
|
|
28466
28082
|
writeFileSync(tmpPath, text, { encoding: "utf8", mode: 384 });
|
|
28467
28083
|
try {
|
|
@@ -28734,6 +28350,153 @@ function findRecurringPatterns(input) {
|
|
|
28734
28350
|
return patterns;
|
|
28735
28351
|
}
|
|
28736
28352
|
|
|
28353
|
+
// src/activity/timeline/week-dashboard.ts
|
|
28354
|
+
var WEEKLY_DASHBOARD_FORMAT_VERSION = 1;
|
|
28355
|
+
var DEFAULT_TOP_SOURCE_LIMIT = 10;
|
|
28356
|
+
var DAY_MS2 = 864e5;
|
|
28357
|
+
var WEEK_DAYS_MS = 7 * DAY_MS2;
|
|
28358
|
+
function clippedInWeek(cards, weekStartMs, weekEndMs) {
|
|
28359
|
+
const clipped = [];
|
|
28360
|
+
for (const card of cards) {
|
|
28361
|
+
const startMs = Date.parse(card.startUtc);
|
|
28362
|
+
const endMs = Date.parse(card.endUtc);
|
|
28363
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs <= startMs) continue;
|
|
28364
|
+
const clipStartMs = Math.max(startMs, weekStartMs);
|
|
28365
|
+
const clipEndMs = Math.min(endMs, weekEndMs);
|
|
28366
|
+
if (clipEndMs > clipStartMs) {
|
|
28367
|
+
clipped.push({ card, startMs, endMs, clipStartMs, clipEndMs });
|
|
28368
|
+
}
|
|
28369
|
+
}
|
|
28370
|
+
return clipped;
|
|
28371
|
+
}
|
|
28372
|
+
function normalizedAttribution(cardId, attributions) {
|
|
28373
|
+
const attribution = attributions?.get(cardId);
|
|
28374
|
+
if (attribution === void 0) return null;
|
|
28375
|
+
if (typeof attribution.app !== "string" || attribution.app.trim() === "") {
|
|
28376
|
+
throw new RangeError(`attribution for card ${cardId} must have a non-blank app`);
|
|
28377
|
+
}
|
|
28378
|
+
const app = attribution.app.trim();
|
|
28379
|
+
if (attribution.domain === void 0) return { app };
|
|
28380
|
+
if (typeof attribution.domain !== "string" || attribution.domain.trim() === "") {
|
|
28381
|
+
throw new RangeError(`attribution for card ${cardId} must have a non-blank domain when present`);
|
|
28382
|
+
}
|
|
28383
|
+
return { app, domain: attribution.domain.trim().toLowerCase() };
|
|
28384
|
+
}
|
|
28385
|
+
function rankTotals(totals, limit) {
|
|
28386
|
+
return [...totals.entries()].map(([key, durationMs]) => ({ key, durationMs })).sort(
|
|
28387
|
+
(a, b) => b.durationMs - a.durationMs || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0)
|
|
28388
|
+
).slice(0, limit);
|
|
28389
|
+
}
|
|
28390
|
+
function buildWeeklyDashboard(cards, options) {
|
|
28391
|
+
const summary = buildWeeklyActivitySummary(cards, options);
|
|
28392
|
+
const topSourceLimit = options.topSourceLimit ?? DEFAULT_TOP_SOURCE_LIMIT;
|
|
28393
|
+
if (!Number.isInteger(topSourceLimit) || topSourceLimit < 1) {
|
|
28394
|
+
throw new RangeError(`topSourceLimit must be an integer >= 1; got ${topSourceLimit}`);
|
|
28395
|
+
}
|
|
28396
|
+
const weekStartMs = Date.parse(summary.weekStartUtc);
|
|
28397
|
+
const weekEndMs = Date.parse(summary.weekEndUtc);
|
|
28398
|
+
const inWeek = clippedInWeek(cards, weekStartMs, weekEndMs);
|
|
28399
|
+
const applicationTotals = /* @__PURE__ */ new Map();
|
|
28400
|
+
const domainTotals = /* @__PURE__ */ new Map();
|
|
28401
|
+
const applicationOccurrences = [];
|
|
28402
|
+
const categoryOccurrences = [];
|
|
28403
|
+
const evidence = {
|
|
28404
|
+
activityCardCount: 0,
|
|
28405
|
+
idleCardCount: 0,
|
|
28406
|
+
pauseCardCount: 0,
|
|
28407
|
+
evidenceCount: 0,
|
|
28408
|
+
distinctEvidenceCount: 0
|
|
28409
|
+
};
|
|
28410
|
+
const uncertainty = {
|
|
28411
|
+
clippedCardCount: 0,
|
|
28412
|
+
manualEditCount: 0,
|
|
28413
|
+
unclassifiedCardCount: 0
|
|
28414
|
+
};
|
|
28415
|
+
const distinctEvidence = /* @__PURE__ */ new Set();
|
|
28416
|
+
const dayWindows = summary.days.map((day) => ({
|
|
28417
|
+
date: day.date,
|
|
28418
|
+
startMs: Date.parse(day.startUtc),
|
|
28419
|
+
endMs: Date.parse(day.endUtc)
|
|
28420
|
+
}));
|
|
28421
|
+
for (const day of summary.days) {
|
|
28422
|
+
for (const total of day.categories) {
|
|
28423
|
+
if (total.durationMs > 0) {
|
|
28424
|
+
categoryOccurrences.push({ date: day.date, key: total.categoryId, durationMs: total.durationMs });
|
|
28425
|
+
}
|
|
28426
|
+
}
|
|
28427
|
+
}
|
|
28428
|
+
for (const { card, startMs, endMs, clipStartMs, clipEndMs } of inWeek) {
|
|
28429
|
+
if (startMs < weekStartMs || endMs > weekEndMs) {
|
|
28430
|
+
uncertainty.clippedCardCount++;
|
|
28431
|
+
}
|
|
28432
|
+
if (card.kind === "idle") {
|
|
28433
|
+
evidence.idleCardCount++;
|
|
28434
|
+
continue;
|
|
28435
|
+
}
|
|
28436
|
+
if (card.kind === "pause") {
|
|
28437
|
+
evidence.pauseCardCount++;
|
|
28438
|
+
continue;
|
|
28439
|
+
}
|
|
28440
|
+
evidence.activityCardCount++;
|
|
28441
|
+
for (const id of card.evidenceIds) {
|
|
28442
|
+
evidence.evidenceCount++;
|
|
28443
|
+
distinctEvidence.add(id);
|
|
28444
|
+
}
|
|
28445
|
+
if (card.manualEdit !== void 0) uncertainty.manualEditCount++;
|
|
28446
|
+
if (card.confidence === 0) uncertainty.unclassifiedCardCount++;
|
|
28447
|
+
const attribution = normalizedAttribution(card.id, options.attributions);
|
|
28448
|
+
if (attribution === null) continue;
|
|
28449
|
+
const durationMs = clipEndMs - clipStartMs;
|
|
28450
|
+
applicationTotals.set(attribution.app, (applicationTotals.get(attribution.app) ?? 0) + durationMs);
|
|
28451
|
+
if (attribution.domain !== void 0) {
|
|
28452
|
+
domainTotals.set(attribution.domain, (domainTotals.get(attribution.domain) ?? 0) + durationMs);
|
|
28453
|
+
}
|
|
28454
|
+
for (const day of dayWindows) {
|
|
28455
|
+
const dayStartMs = Math.max(clipStartMs, day.startMs);
|
|
28456
|
+
const dayEndMs = Math.min(clipEndMs, day.endMs);
|
|
28457
|
+
if (dayEndMs > dayStartMs) {
|
|
28458
|
+
applicationOccurrences.push({ date: day.date, key: attribution.app, durationMs: dayEndMs - dayStartMs });
|
|
28459
|
+
}
|
|
28460
|
+
}
|
|
28461
|
+
}
|
|
28462
|
+
evidence.distinctEvidenceCount = distinctEvidence.size;
|
|
28463
|
+
let previousPeriod = { available: false };
|
|
28464
|
+
if (options.previousWeekCards !== void 0) {
|
|
28465
|
+
const previousSummary = buildWeeklyActivitySummary(options.previousWeekCards, {
|
|
28466
|
+
...options,
|
|
28467
|
+
weekStartUtc: new Date(weekStartMs - WEEK_DAYS_MS).toISOString(),
|
|
28468
|
+
weekEndUtc: summary.weekStartUtc
|
|
28469
|
+
});
|
|
28470
|
+
previousPeriod = compareWeeklyPreviousPeriod({
|
|
28471
|
+
previous: previousSummary,
|
|
28472
|
+
current: summary,
|
|
28473
|
+
previousStartUtc: previousSummary.weekStartUtc,
|
|
28474
|
+
previousEndUtc: previousSummary.weekEndUtc
|
|
28475
|
+
});
|
|
28476
|
+
}
|
|
28477
|
+
return {
|
|
28478
|
+
...summary,
|
|
28479
|
+
previousPeriod,
|
|
28480
|
+
dashboardFormatVersion: WEEKLY_DASHBOARD_FORMAT_VERSION,
|
|
28481
|
+
sources: {
|
|
28482
|
+
applications: rankTotals(applicationTotals, topSourceLimit),
|
|
28483
|
+
domains: rankTotals(domainTotals, topSourceLimit)
|
|
28484
|
+
},
|
|
28485
|
+
recurring: {
|
|
28486
|
+
categories: findRecurringPatterns({
|
|
28487
|
+
occurrences: categoryOccurrences,
|
|
28488
|
+
minDays: options.recurrenceMinDays
|
|
28489
|
+
}),
|
|
28490
|
+
applications: findRecurringPatterns({
|
|
28491
|
+
occurrences: applicationOccurrences,
|
|
28492
|
+
minDays: options.recurrenceMinDays
|
|
28493
|
+
})
|
|
28494
|
+
},
|
|
28495
|
+
evidence,
|
|
28496
|
+
uncertainty
|
|
28497
|
+
};
|
|
28498
|
+
}
|
|
28499
|
+
|
|
28737
28500
|
// src/activity/timeline/week-config-hash.ts
|
|
28738
28501
|
var WEEK_START_DAYS = Object.freeze([
|
|
28739
28502
|
"monday",
|
|
@@ -28966,7 +28729,7 @@ function selectRecapForDay(input) {
|
|
|
28966
28729
|
|
|
28967
28730
|
// src/activity/journal-read.ts
|
|
28968
28731
|
import { closeSync, constants as fsConstants, fstatSync, lstatSync, openSync, readFileSync as readFileSync3, realpathSync, statSync as statSync2 } from "fs";
|
|
28969
|
-
import
|
|
28732
|
+
import path35 from "path";
|
|
28970
28733
|
|
|
28971
28734
|
// src/activity/journal-section.ts
|
|
28972
28735
|
function parseAtxHeading(line) {
|
|
@@ -29157,8 +28920,8 @@ function readJournalForDate(input) {
|
|
|
29157
28920
|
const relative = resolveVaultNotePath(input.vault.dailyNotePath, input.date, {
|
|
29158
28921
|
timezone: input.timezone
|
|
29159
28922
|
});
|
|
29160
|
-
const root =
|
|
29161
|
-
const filePath =
|
|
28923
|
+
const root = path35.resolve(expandTildePath(input.vault.vaultPath));
|
|
28924
|
+
const filePath = path35.join(root, relative);
|
|
29162
28925
|
try {
|
|
29163
28926
|
const rootStat = lstatSync(root);
|
|
29164
28927
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
|
@@ -29167,8 +28930,8 @@ function readJournalForDate(input) {
|
|
|
29167
28930
|
} catch {
|
|
29168
28931
|
return { ok: true, exists: false, reason: "missing_file", filePath };
|
|
29169
28932
|
}
|
|
29170
|
-
const lexical =
|
|
29171
|
-
if (lexical.length === 0 || lexical === ".." || lexical.startsWith(`..${
|
|
28933
|
+
const lexical = path35.relative(root, filePath);
|
|
28934
|
+
if (lexical.length === 0 || lexical === ".." || lexical.startsWith(`..${path35.sep}`) || path35.isAbsolute(lexical)) {
|
|
29172
28935
|
return { ok: false, reason: "path_escape", filePath };
|
|
29173
28936
|
}
|
|
29174
28937
|
if (!containedBySymlinks(root, filePath)) {
|
|
@@ -29201,11 +28964,11 @@ function containedBySymlinks(root, dest) {
|
|
|
29201
28964
|
try {
|
|
29202
28965
|
if (statSync2(probe).isFile() || statSync2(probe).isDirectory()) {
|
|
29203
28966
|
const real = realpathSync(probe);
|
|
29204
|
-
return real === realRoot || real.startsWith(`${realRoot}${
|
|
28967
|
+
return real === realRoot || real.startsWith(`${realRoot}${path35.sep}`);
|
|
29205
28968
|
}
|
|
29206
28969
|
} catch {
|
|
29207
28970
|
}
|
|
29208
|
-
const parent =
|
|
28971
|
+
const parent = path35.dirname(probe);
|
|
29209
28972
|
if (parent === probe) return false;
|
|
29210
28973
|
probe = parent;
|
|
29211
28974
|
}
|
|
@@ -29216,15 +28979,15 @@ function symlinkRejected() {
|
|
|
29216
28979
|
return err;
|
|
29217
28980
|
}
|
|
29218
28981
|
function readVerifiedDailyNote(root, filePath) {
|
|
29219
|
-
const relative =
|
|
29220
|
-
const parts = relative.split(
|
|
28982
|
+
const relative = path35.relative(root, filePath);
|
|
28983
|
+
const parts = relative.split(path35.sep).filter((part) => part.length > 0 && part !== ".");
|
|
29221
28984
|
let cursor = root;
|
|
29222
28985
|
for (const part of parts) {
|
|
29223
|
-
cursor =
|
|
28986
|
+
cursor = path35.join(cursor, part);
|
|
29224
28987
|
const st = lstatSync(cursor);
|
|
29225
28988
|
if (st.isSymbolicLink()) throw symlinkRejected();
|
|
29226
28989
|
}
|
|
29227
|
-
const parent =
|
|
28990
|
+
const parent = path35.dirname(filePath);
|
|
29228
28991
|
const parentLstat = lstatSync(parent);
|
|
29229
28992
|
if (parentLstat.isSymbolicLink() || !parentLstat.isDirectory()) throw symlinkRejected();
|
|
29230
28993
|
const nofollow = fsConstants.O_NOFOLLOW ?? 0;
|
|
@@ -29248,7 +29011,7 @@ function readVerifiedDailyNote(root, filePath) {
|
|
|
29248
29011
|
try {
|
|
29249
29012
|
const fdPath = realpathSync(`/proc/self/fd/${fd}`);
|
|
29250
29013
|
const realRoot = realpathSync(root);
|
|
29251
|
-
if (fdPath !== realRoot && !fdPath.startsWith(`${realRoot}${
|
|
29014
|
+
if (fdPath !== realRoot && !fdPath.startsWith(`${realRoot}${path35.sep}`)) {
|
|
29252
29015
|
throw symlinkRejected();
|
|
29253
29016
|
}
|
|
29254
29017
|
} catch (err) {
|
|
@@ -29263,11 +29026,11 @@ function readVerifiedDailyNote(root, filePath) {
|
|
|
29263
29026
|
// src/activity/journal-state.ts
|
|
29264
29027
|
import { createHash as createHash10, randomBytes as randomBytes4 } from "crypto";
|
|
29265
29028
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
29266
|
-
import
|
|
29029
|
+
import path36 from "path";
|
|
29267
29030
|
var STATE_DIR_NAME = "state";
|
|
29268
29031
|
var STATE_FILE_NAME = "timeline.json";
|
|
29269
29032
|
function timelineStatePath(memoryDir) {
|
|
29270
|
-
return
|
|
29033
|
+
return path36.join(memoryDir, STATE_DIR_NAME, STATE_FILE_NAME);
|
|
29271
29034
|
}
|
|
29272
29035
|
function hashJournalText(text) {
|
|
29273
29036
|
return createHash10("sha256").update(text, "utf8").digest("hex");
|
|
@@ -29293,14 +29056,14 @@ function readTimelineState(memoryDir) {
|
|
|
29293
29056
|
}
|
|
29294
29057
|
function writeTimelineState(memoryDir, state) {
|
|
29295
29058
|
const filePath = timelineStatePath(memoryDir);
|
|
29296
|
-
mkdirSync2(
|
|
29059
|
+
mkdirSync2(path36.dirname(filePath), { recursive: true });
|
|
29297
29060
|
const tempPath = `${filePath}.${process.pid}.${randomBytes4(8).toString("hex")}.tmp`;
|
|
29298
29061
|
writeFileSync2(tempPath, `${JSON.stringify(state, null, 2)}
|
|
29299
29062
|
`);
|
|
29300
29063
|
renameSync2(tempPath, filePath);
|
|
29301
29064
|
}
|
|
29302
29065
|
function journalDateLockPath(memoryDir, date) {
|
|
29303
|
-
return
|
|
29066
|
+
return path36.join(memoryDir, STATE_DIR_NAME, `journal-extract-${date}.lock`);
|
|
29304
29067
|
}
|
|
29305
29068
|
function timelineStateLockPath(memoryDir) {
|
|
29306
29069
|
return `${timelineStatePath(memoryDir)}.lock`;
|
|
@@ -29991,8 +29754,24 @@ function filterPrivacyWindow(items, options) {
|
|
|
29991
29754
|
});
|
|
29992
29755
|
}
|
|
29993
29756
|
|
|
29757
|
+
// src/activity/privacy-redact.ts
|
|
29758
|
+
function redactActivityFields(item, options) {
|
|
29759
|
+
const result = { ...item };
|
|
29760
|
+
for (const key of options.dropKeys) {
|
|
29761
|
+
delete result[key];
|
|
29762
|
+
}
|
|
29763
|
+
return result;
|
|
29764
|
+
}
|
|
29765
|
+
|
|
29766
|
+
// src/activity/privacy-keys.ts
|
|
29767
|
+
function normalizeDropKeys(keys) {
|
|
29768
|
+
const unique = [...new Set(keys.map((key) => key.trim()).filter((key) => key.length > 0))];
|
|
29769
|
+
unique.sort((a, b) => a.localeCompare(b));
|
|
29770
|
+
return unique;
|
|
29771
|
+
}
|
|
29772
|
+
|
|
29994
29773
|
// src/activity/vault-wikilink.ts
|
|
29995
|
-
import
|
|
29774
|
+
import path37 from "path";
|
|
29996
29775
|
function formatVaultWikilink(notePath) {
|
|
29997
29776
|
if (typeof notePath !== "string" || notePath.trim().length === 0) {
|
|
29998
29777
|
throw new RangeError("Vault wikilink path must be a non-empty relative path.");
|
|
@@ -30000,7 +29779,7 @@ function formatVaultWikilink(notePath) {
|
|
|
30000
29779
|
if (notePath.includes("\n") || notePath.includes("\r")) {
|
|
30001
29780
|
throw new RangeError("Vault wikilink path must not contain newlines.");
|
|
30002
29781
|
}
|
|
30003
|
-
if (
|
|
29782
|
+
if (path37.posix.isAbsolute(notePath) || path37.win32.isAbsolute(notePath)) {
|
|
30004
29783
|
throw new RangeError("Vault wikilink path must be relative; absolute paths are rejected.");
|
|
30005
29784
|
}
|
|
30006
29785
|
if (notePath.split(/[\\/]/).some((segment) => segment === "..")) {
|
|
@@ -30022,7 +29801,7 @@ function stripVaultMdSuffix(notePath) {
|
|
|
30022
29801
|
}
|
|
30023
29802
|
|
|
30024
29803
|
// src/activity/vault-join.ts
|
|
30025
|
-
import
|
|
29804
|
+
import path38 from "path";
|
|
30026
29805
|
function joinVaultSegments(parts) {
|
|
30027
29806
|
if (parts.length === 0) {
|
|
30028
29807
|
throw new RangeError("Vault path parts must be a non-empty list.");
|
|
@@ -30037,7 +29816,7 @@ function joinVaultSegments(parts) {
|
|
|
30037
29816
|
if (part.includes("\n") || part.includes("\r")) {
|
|
30038
29817
|
throw new RangeError("Vault path part must not contain a newline.");
|
|
30039
29818
|
}
|
|
30040
|
-
if (
|
|
29819
|
+
if (path38.posix.isAbsolute(part) || path38.win32.isAbsolute(part)) {
|
|
30041
29820
|
throw new RangeError("Vault path part must be relative.");
|
|
30042
29821
|
}
|
|
30043
29822
|
if (part.split("/").includes("..")) {
|
|
@@ -30092,7 +29871,7 @@ function planVaultDryRun(inputs) {
|
|
|
30092
29871
|
// src/session-summaries/index.ts
|
|
30093
29872
|
import { createHash as createHash11 } from "crypto";
|
|
30094
29873
|
import { lstat as lstat3, mkdir as mkdir7, readFile as readFile9, readdir as readdir4, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
|
|
30095
|
-
import
|
|
29874
|
+
import path39 from "path";
|
|
30096
29875
|
|
|
30097
29876
|
// src/session-summaries/adapters.ts
|
|
30098
29877
|
var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "other"]);
|
|
@@ -30597,7 +30376,7 @@ function shortHash(value, length = 16) {
|
|
|
30597
30376
|
async function listTranscriptFiles(root, maxFiles) {
|
|
30598
30377
|
const out = [];
|
|
30599
30378
|
let truncated = false;
|
|
30600
|
-
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${
|
|
30379
|
+
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path39.sep}` : entryName;
|
|
30601
30380
|
async function visit(dir) {
|
|
30602
30381
|
if (truncated) return;
|
|
30603
30382
|
const entries = (await readdir4(dir, { withFileTypes: true })).sort(
|
|
@@ -30607,13 +30386,13 @@ async function listTranscriptFiles(root, maxFiles) {
|
|
|
30607
30386
|
if (truncated) return;
|
|
30608
30387
|
if (entry.name.startsWith(".")) continue;
|
|
30609
30388
|
if (entry.isSymbolicLink()) continue;
|
|
30610
|
-
const fullPath =
|
|
30389
|
+
const fullPath = path39.join(dir, entry.name);
|
|
30611
30390
|
if (entry.isDirectory()) {
|
|
30612
30391
|
await visit(fullPath);
|
|
30613
30392
|
continue;
|
|
30614
30393
|
}
|
|
30615
30394
|
if (!entry.isFile()) continue;
|
|
30616
|
-
const ext =
|
|
30395
|
+
const ext = path39.extname(entry.name).toLowerCase();
|
|
30617
30396
|
if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
|
|
30618
30397
|
out.push(fullPath);
|
|
30619
30398
|
if (out.length > maxFiles) {
|
|
@@ -30640,7 +30419,7 @@ function normalizeInputDir(inputDir) {
|
|
|
30640
30419
|
if (typeof inputDir !== "string" || inputDir.trim().length === 0) {
|
|
30641
30420
|
throw new Error("inputDir must be a non-empty string");
|
|
30642
30421
|
}
|
|
30643
|
-
return
|
|
30422
|
+
return path39.resolve(expandTildePath(inputDir.trim()));
|
|
30644
30423
|
}
|
|
30645
30424
|
function initRoleCounts() {
|
|
30646
30425
|
return {
|
|
@@ -30797,11 +30576,11 @@ async function collectLocalSessionSummaries(options) {
|
|
|
30797
30576
|
continue;
|
|
30798
30577
|
}
|
|
30799
30578
|
seenFileHashes.add(fileHash);
|
|
30800
|
-
const fileExtension =
|
|
30579
|
+
const fileExtension = path39.extname(filePath).toLowerCase();
|
|
30801
30580
|
const parsed = await adapter.parseFile(
|
|
30802
30581
|
{
|
|
30803
30582
|
content,
|
|
30804
|
-
fileName:
|
|
30583
|
+
fileName: path39.basename(filePath),
|
|
30805
30584
|
fileExtension,
|
|
30806
30585
|
fileRef: fileHash
|
|
30807
30586
|
},
|
|
@@ -30857,7 +30636,7 @@ async function collectLocalSessionSummaries(options) {
|
|
|
30857
30636
|
}
|
|
30858
30637
|
async function readRedactionConfig(pathLike) {
|
|
30859
30638
|
if (!pathLike) return void 0;
|
|
30860
|
-
const raw = await readFile9(
|
|
30639
|
+
const raw = await readFile9(path39.resolve(expandTildePath(pathLike)), "utf-8");
|
|
30861
30640
|
const parsed = JSON.parse(raw);
|
|
30862
30641
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
30863
30642
|
throw new Error("redaction config must be a JSON object");
|
|
@@ -30870,15 +30649,15 @@ function toJsonl(drafts) {
|
|
|
30870
30649
|
}
|
|
30871
30650
|
function defaultDraftOutputPath(memoryDir, generatedAt) {
|
|
30872
30651
|
const stamp = generatedAt.replace(/[:.]/g, "-");
|
|
30873
|
-
return
|
|
30874
|
-
|
|
30652
|
+
return path39.join(
|
|
30653
|
+
path39.resolve(expandTildePath(memoryDir)),
|
|
30875
30654
|
"state",
|
|
30876
30655
|
"session-summary-drafts",
|
|
30877
30656
|
`session-summaries-${stamp}.jsonl`
|
|
30878
30657
|
);
|
|
30879
30658
|
}
|
|
30880
30659
|
async function writeDrafts(filePath, drafts) {
|
|
30881
|
-
await mkdir7(
|
|
30660
|
+
await mkdir7(path39.dirname(filePath), { recursive: true });
|
|
30882
30661
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
30883
30662
|
try {
|
|
30884
30663
|
await writeFile7(tempPath, toJsonl(drafts), "utf-8");
|
|
@@ -30896,7 +30675,7 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
30896
30675
|
});
|
|
30897
30676
|
const wroteFiles = [];
|
|
30898
30677
|
if (options.output) {
|
|
30899
|
-
const outputPath =
|
|
30678
|
+
const outputPath = path39.resolve(expandTildePath(options.output));
|
|
30900
30679
|
await writeDrafts(outputPath, report.drafts);
|
|
30901
30680
|
wroteFiles.push(outputPath);
|
|
30902
30681
|
}
|
|
@@ -30931,19 +30710,19 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
30931
30710
|
|
|
30932
30711
|
// src/transfer/capsule-fork.ts
|
|
30933
30712
|
import { lstat as lstat4, mkdir as mkdir8, readFile as readFile10, realpath as realpath3, writeFile as writeFile8 } from "fs/promises";
|
|
30934
|
-
import
|
|
30713
|
+
import path40 from "path";
|
|
30935
30714
|
async function forkCapsule(opts) {
|
|
30936
30715
|
validateForkId(opts.forkId);
|
|
30937
|
-
const rootAbs =
|
|
30716
|
+
const rootAbs = path40.resolve(opts.targetRoot);
|
|
30938
30717
|
await assertIsDirectoryNotSymlink(rootAbs, "forkCapsule", "targetRoot");
|
|
30939
|
-
const forkDirAbs =
|
|
30718
|
+
const forkDirAbs = path40.join(rootAbs, "forks", opts.forkId);
|
|
30940
30719
|
const forkEntryExists = await pathEntryExists(forkDirAbs);
|
|
30941
30720
|
if (forkEntryExists) {
|
|
30942
30721
|
throw new Error(
|
|
30943
30722
|
`forkCapsule: fork path already exists \u2014 forkId "${opts.forkId}" is already in use at: ${forkDirAbs}`
|
|
30944
30723
|
);
|
|
30945
30724
|
}
|
|
30946
|
-
const archiveAbs =
|
|
30725
|
+
const archiveAbs = path40.resolve(opts.sourceArchive);
|
|
30947
30726
|
const importResult = await importCapsule({
|
|
30948
30727
|
archivePath: archiveAbs,
|
|
30949
30728
|
root: rootAbs,
|
|
@@ -30965,10 +30744,10 @@ async function forkCapsule(opts) {
|
|
|
30965
30744
|
importedRecords: importResult.imported.length,
|
|
30966
30745
|
skippedRecords: importResult.skipped.length
|
|
30967
30746
|
};
|
|
30968
|
-
const lineagePath =
|
|
30747
|
+
const lineagePath = path40.join(forkDirAbs, "lineage.json");
|
|
30969
30748
|
const rootReal = await realpath3(rootAbs);
|
|
30970
30749
|
await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, "forkCapsule");
|
|
30971
|
-
await mkdir8(
|
|
30750
|
+
await mkdir8(path40.dirname(lineagePath), { recursive: true });
|
|
30972
30751
|
await writeFile8(lineagePath, JSON.stringify(lineage, null, 2) + "\n", "utf-8");
|
|
30973
30752
|
return {
|
|
30974
30753
|
archivePath: archiveAbs,
|
|
@@ -30982,11 +30761,11 @@ async function readForkLineage(targetRoot, forkId) {
|
|
|
30982
30761
|
if (typeof forkId !== "string" || forkId.length === 0 || forkId.length > 64 || !CAPSULE_ID_PATTERN.test(forkId)) {
|
|
30983
30762
|
return null;
|
|
30984
30763
|
}
|
|
30985
|
-
const rootAbs =
|
|
30764
|
+
const rootAbs = path40.resolve(targetRoot);
|
|
30986
30765
|
const rootReal = await realpath3(rootAbs).catch(() => rootAbs);
|
|
30987
|
-
const lineagePath =
|
|
30988
|
-
const rel =
|
|
30989
|
-
if (rel.startsWith("..") ||
|
|
30766
|
+
const lineagePath = path40.join(rootReal, "forks", forkId, "lineage.json");
|
|
30767
|
+
const rel = path40.relative(rootReal, lineagePath);
|
|
30768
|
+
if (rel.startsWith("..") || path40.isAbsolute(rel)) {
|
|
30990
30769
|
return null;
|
|
30991
30770
|
}
|
|
30992
30771
|
if (!await isLineagePathContained(rootReal, lineagePath)) {
|
|
@@ -31027,19 +30806,19 @@ async function pathEntryExists(absPath) {
|
|
|
31027
30806
|
async function isLineagePathContained(rootReal, lineagePath) {
|
|
31028
30807
|
let existing = lineagePath;
|
|
31029
30808
|
const suffix = [];
|
|
31030
|
-
while (existing !==
|
|
30809
|
+
while (existing !== path40.dirname(existing)) {
|
|
31031
30810
|
const st = await lstat4(existing).catch(() => null);
|
|
31032
30811
|
if (st !== null) break;
|
|
31033
|
-
suffix.unshift(
|
|
31034
|
-
existing =
|
|
30812
|
+
suffix.unshift(path40.basename(existing));
|
|
30813
|
+
existing = path40.dirname(existing);
|
|
31035
30814
|
}
|
|
31036
30815
|
const existingReal = await realpath3(existing).catch(() => existing);
|
|
31037
|
-
const targetReal = suffix.length > 0 ?
|
|
31038
|
-
const rel =
|
|
30816
|
+
const targetReal = suffix.length > 0 ? path40.join(existingReal, ...suffix) : existingReal;
|
|
30817
|
+
const rel = path40.relative(rootReal, targetReal);
|
|
31039
30818
|
if (rel === "") return true;
|
|
31040
30819
|
if (rel === "..") return false;
|
|
31041
|
-
if (rel.startsWith(`..${
|
|
31042
|
-
if (
|
|
30820
|
+
if (rel.startsWith(`..${path40.sep}`)) return false;
|
|
30821
|
+
if (path40.isAbsolute(rel)) return false;
|
|
31043
30822
|
return true;
|
|
31044
30823
|
}
|
|
31045
30824
|
|
|
@@ -31082,8 +30861,6 @@ export {
|
|
|
31082
30861
|
generateContextTree,
|
|
31083
30862
|
onboard,
|
|
31084
30863
|
curate,
|
|
31085
|
-
findDuplicates,
|
|
31086
|
-
findContradictions,
|
|
31087
30864
|
decideSemanticDedup,
|
|
31088
30865
|
syncChanges,
|
|
31089
30866
|
watchForChanges,
|
|
@@ -31149,6 +30926,9 @@ export {
|
|
|
31149
30926
|
DEFAULT_RECURRENCE_MIN_DAYS,
|
|
31150
30927
|
MIN_RECURRENCE_MIN_DAYS,
|
|
31151
30928
|
findRecurringPatterns,
|
|
30929
|
+
WEEKLY_DASHBOARD_FORMAT_VERSION,
|
|
30930
|
+
DEFAULT_TOP_SOURCE_LIMIT,
|
|
30931
|
+
buildWeeklyDashboard,
|
|
31152
30932
|
WEEK_START_DAYS,
|
|
31153
30933
|
computeWeeklyConfigHash,
|
|
31154
30934
|
batchObservations,
|
|
@@ -31190,6 +30970,8 @@ export {
|
|
|
31190
30970
|
ACTIVITY_FEATURE_GATES,
|
|
31191
30971
|
resolveActivityGates,
|
|
31192
30972
|
filterPrivacyWindow,
|
|
30973
|
+
redactActivityFields,
|
|
30974
|
+
normalizeDropKeys,
|
|
31193
30975
|
formatVaultWikilink,
|
|
31194
30976
|
stripVaultMdSuffix,
|
|
31195
30977
|
joinVaultSegments,
|
|
@@ -31228,4 +31010,4 @@ export {
|
|
|
31228
31010
|
qmdStartupCollectionChecksWithTimeout,
|
|
31229
31011
|
Orchestrator
|
|
31230
31012
|
};
|
|
31231
|
-
//# sourceMappingURL=chunk-
|
|
31013
|
+
//# sourceMappingURL=chunk-OKOG5MXF.js.map
|