@remnic/plugin-openclaw 1.0.34 → 1.0.36

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.
Files changed (87) hide show
  1. package/README.md +59 -10
  2. package/dist/{calibration-JD4AU7FB.js → calibration-RKL2LRW4.js} +4 -4
  3. package/dist/{capsule-cli-GBM3WPAM.js → capsule-cli-EHZPMXBC.js} +2 -2
  4. package/dist/{capsule-crypto-K3IRTKRH.js → capsule-crypto-JS67OSWM.js} +3 -3
  5. package/dist/capsule-export-YPDWRB3C.js +17 -0
  6. package/dist/capsule-import-SWPOFG6F.js +16 -0
  7. package/dist/{capsule-merge-IWOQ34KL.js → capsule-merge-YXAF7ZJW.js} +7 -7
  8. package/dist/{causal-chain-WYN5QOPS.js → causal-chain-BVTOWZKC.js} +4 -4
  9. package/dist/{causal-consolidation-DSLFN64P.js → causal-consolidation-DRPM2KOE.js} +13 -10
  10. package/dist/{causal-retrieval-NZHQOZOE.js → causal-retrieval-XAP6QKHZ.js} +4 -5
  11. package/dist/{causal-trajectory-graph-VBPE2WPM.js → causal-trajectory-graph-ZWQWZ7N5.js} +2 -2
  12. package/dist/{chunk-5LE4HTVL.js → chunk-25J4PXDH.js} +0 -18
  13. package/dist/{chunk-FGTYFLL5.js → chunk-3IHGISUN.js} +29 -32
  14. package/dist/{chunk-6UFI73TJ.js → chunk-3IKMUNW5.js} +53 -46
  15. package/dist/{chunk-EXDYWXMB.js → chunk-4XDQ3KEC.js} +1 -2
  16. package/dist/{chunk-4UA6KMRO.js → chunk-6O3H3DPL.js} +2 -2
  17. package/dist/{chunk-7NMHI4IC.js → chunk-BLC3RQNV.js} +5 -555
  18. package/dist/{chunk-4G2XCSD2.js → chunk-BZ4EYURA.js} +0 -5
  19. package/dist/{chunk-4LYQ4ONL.js → chunk-E4RM7637.js} +1 -1
  20. package/dist/{chunk-TDRJVMUP.js → chunk-EH4AXGRO.js} +0 -12
  21. package/dist/{chunk-ZXLYEVOP.js → chunk-G3CZA4SD.js} +60 -362
  22. package/dist/chunk-I2KLQ2HA.js +22 -0
  23. package/dist/chunk-IO5WWY6A.js +156 -0
  24. package/dist/{contradiction-scan-U3QKHWQN.js → chunk-JC3FCKYL.js} +191 -87
  25. package/dist/{chunk-SVSQAG6M.js → chunk-KC7KSQR4.js} +47 -28
  26. package/dist/chunk-LZCGPRHS.js +228 -0
  27. package/dist/{chunk-CXM7EBAO.js → chunk-MXFJXUHC.js} +1 -1
  28. package/dist/{chunk-L6I4MQKO.js → chunk-NNAN63QK.js} +6 -6
  29. package/dist/{chunk-VRGUUHBV.js → chunk-NUWDSTP7.js} +1 -1
  30. package/dist/{chunk-6OJAU466.js → chunk-QMUQV5NP.js} +0 -1
  31. package/dist/{chunk-LLUROTZJ.js → chunk-QQXJODFL.js} +9 -9
  32. package/dist/{chunk-6F6EKSVP.js → chunk-QXXEF7VI.js} +1 -1
  33. package/dist/{chunk-NDZNURDM.js → chunk-SEGEX7W4.js} +73 -241
  34. package/dist/{chunk-7NUFIRM3.js → chunk-SWOYEQN2.js} +97 -21
  35. package/dist/chunk-TH5FF5SC.js +16 -0
  36. package/dist/chunk-UZJ7EERS.js +272 -0
  37. package/dist/chunk-YJYZMLD5.js +360 -0
  38. package/dist/{chunk-NKVIN6RD.js → chunk-YKV4EFUI.js} +84 -2
  39. package/dist/{chunk-SSFTU6LP.js → chunk-ZS6VABML.js} +4 -4
  40. package/dist/{cipher-VHAFCG7Z.js → cipher-E23BHBSO.js} +1 -1
  41. package/dist/{consolidation-undo-5ZSX4MWO.js → consolidation-undo-FKJZCJHS.js} +2 -2
  42. package/dist/contradiction-review-WJRWNQ5N.js +29 -0
  43. package/dist/contradiction-scan-5X423QGT.js +12 -0
  44. package/dist/{dreams-ledger-3I52ISYR.js → dreams-ledger-KDX44I7R.js} +1 -1
  45. package/dist/{engine-57HLTQBN.js → engine-5P774HTZ.js} +6 -6
  46. package/dist/{extraction-judge-telemetry-GHOTVYMP.js → extraction-judge-telemetry-O4ZVGLTU.js} +1 -1
  47. package/dist/{fallback-llm-33SPYXQY.js → fallback-llm-43UMEXNJ.js} +3 -3
  48. package/dist/{first-start-migration-I24M2JEE.js → first-start-migration-H2SAXAGR.js} +4 -4
  49. package/dist/{forget-NI4RBDPB.js → forget-ZECIDNL5.js} +1 -1
  50. package/dist/{fs-utils-PZRI2HDZ.js → fs-utils-OYXSZSVV.js} +12 -2
  51. package/dist/{graph-edge-decay-5CVKWBYH.js → graph-edge-decay-24ZKD5QL.js} +5 -5
  52. package/dist/index.js +7187 -71983
  53. package/dist/{kdf-H5B23ZM2.js → kdf-RXKIWHRU.js} +1 -1
  54. package/dist/legacy-hook-compat-QHHKF4GK.js +2 -0
  55. package/dist/{logger-TNOKCH7X.js → logger-XG7JKLPS.js} +1 -1
  56. package/dist/{memory-governance-FEQCA35V.js → memory-governance-6K4M4YXD.js} +5 -5
  57. package/dist/{metadata-JAGIWHEA.js → metadata-WK2TRPYZ.js} +1 -1
  58. package/dist/{migrate-from-identity-anchor-7MMSPEUM.js → migrate-from-identity-anchor-SNDNKHZD.js} +1 -1
  59. package/dist/path-ZKO74XXC.js +7 -0
  60. package/dist/{peers-KRFXWRQ6.js → peers-W53WSDXG.js} +1 -1
  61. package/dist/{purge-XN2VSPZ2.js → purge-IKJISXEQ.js} +1 -1
  62. package/dist/resolution-BN35OXDS.js +11 -0
  63. package/dist/{secure-store-A4NGCNXV.js → secure-store-F75I54O5.js} +3 -3
  64. package/dist/{state-PVISYXRH.js → state-4ITLYMAU.js} +1 -1
  65. package/dist/{state-store-N6TFBFSP.js → state-store-ET3ADVY5.js} +3 -3
  66. package/dist/{storage-R3V6ZFQT.js → storage-5EY6T7ON.js} +3 -3
  67. package/dist/{tier-stats-IZNW66NC.js → tier-stats-ZRQBV6G2.js} +4 -4
  68. package/dist/{trace-NJESSGH7.js → trace-IL2Y34EH.js} +1 -1
  69. package/dist/{tui-MGK2LYJY.js → tui-7KRDCMYK.js} +1 -1
  70. package/dist/{types-R4DO7AKM.js → types-7L34HYDW.js} +3 -3
  71. package/openclaw.plugin.json +153 -20
  72. package/package.json +18 -9
  73. package/scripts/faiss_index.py +756 -0
  74. package/scripts/faiss_requirements.txt +3 -0
  75. package/dist/capsule-export-IXVERCQG.js +0 -17
  76. package/dist/capsule-import-IA6VIOPQ.js +0 -16
  77. package/dist/chunk-3GUF7RQI.js +0 -559
  78. package/dist/chunk-7OQEPGQF.js +0 -533
  79. package/dist/chunk-DIZW6H5J.js +0 -136
  80. package/dist/chunk-FQRSVYY4.js +0 -110
  81. package/dist/chunk-GUSMRW4H.js +0 -12
  82. package/dist/chunk-MLKGABMK.js +0 -9
  83. package/dist/chunk-WPINX4MF.js +0 -380
  84. package/dist/contradiction-review-SVGBS3V5.js +0 -21
  85. package/dist/legacy-hook-compat-XQ7FP6FV.js +0 -35
  86. package/dist/path-JIEGNWFL.js +0 -7
  87. package/dist/resolution-YITUVUTH.js +0 -100
@@ -1,110 +0,0 @@
1
- // ../remnic-core/src/routing/engine.ts
2
- var DEFAULT_CATEGORIES = [
3
- "fact",
4
- "preference",
5
- "correction",
6
- "entity",
7
- "decision",
8
- "relationship",
9
- "principle",
10
- "commitment",
11
- "moment",
12
- "skill",
13
- "rule",
14
- "procedure",
15
- "reasoning_trace"
16
- ];
17
- function normalizeNamespace(namespace) {
18
- return namespace.trim();
19
- }
20
- function isLikelyUnsafeRegex(pattern) {
21
- const value = pattern.trim();
22
- if (value.length === 0) return true;
23
- if (value.length > 120) return true;
24
- if (/\\[1-9]/.test(value)) return true;
25
- if (/\(\?<?[=!]/.test(value)) return true;
26
- if (/\((?:[^()\\]|\\.)*[+*](?:[^()\\]|\\.)*\)[+*{]/.test(value)) return true;
27
- if (/(^|[^\\])[()|]/.test(value)) return true;
28
- const quantifierCount = (value.match(/(^|[^\\])[*+?]/g)?.length ?? 0) + (value.match(/(^|[^\\])\{/g)?.length ?? 0);
29
- if (quantifierCount > 1) return true;
30
- return false;
31
- }
32
- function isSafeRouteNamespace(namespace) {
33
- const value = normalizeNamespace(namespace);
34
- if (value.length === 0) return false;
35
- if (value === ".") return false;
36
- if (value.includes("/") || value.includes("\\")) return false;
37
- if (value.includes("..")) return false;
38
- return /^[A-Za-z0-9._-]{1,64}$/.test(value);
39
- }
40
- function validateRouteTarget(target, options) {
41
- if (!target || typeof target !== "object") {
42
- return { ok: false, error: "target must be an object" };
43
- }
44
- const allowedCategories = new Set(options?.allowedCategories ?? DEFAULT_CATEGORIES);
45
- const allowedNamespaces = options?.allowedNamespaces ? new Set(options.allowedNamespaces.map((v) => v.trim()).filter((v) => v.length > 0)) : null;
46
- const normalized = {};
47
- if (typeof target.category === "string") {
48
- if (!allowedCategories.has(target.category)) {
49
- return { ok: false, error: `invalid category: ${target.category}` };
50
- }
51
- normalized.category = target.category;
52
- }
53
- if (typeof target.namespace === "string") {
54
- const namespace = normalizeNamespace(target.namespace);
55
- if (!isSafeRouteNamespace(namespace)) {
56
- return { ok: false, error: `invalid namespace: ${target.namespace}` };
57
- }
58
- if (allowedNamespaces && !allowedNamespaces.has(namespace)) {
59
- return { ok: false, error: `namespace not allowed: ${namespace}` };
60
- }
61
- normalized.namespace = namespace;
62
- }
63
- if (!normalized.category && !normalized.namespace) {
64
- return { ok: false, error: "target must include category or namespace" };
65
- }
66
- return { ok: true, target: normalized };
67
- }
68
- function doesRuleMatch(rule, text) {
69
- if (!rule || typeof rule !== "object") return false;
70
- if (rule.enabled === false) return false;
71
- if (typeof rule.pattern !== "string") return false;
72
- const pattern = rule.pattern.trim();
73
- if (pattern.length === 0) return false;
74
- if (rule.patternType === "keyword") {
75
- return text.toLowerCase().includes(pattern.toLowerCase());
76
- }
77
- if (rule.patternType !== "regex") {
78
- return false;
79
- }
80
- if (isLikelyUnsafeRegex(pattern)) {
81
- return false;
82
- }
83
- try {
84
- return new RegExp(pattern, "i").test(text);
85
- } catch {
86
- return false;
87
- }
88
- }
89
- function selectRouteRule(text, rules, options) {
90
- const ranked = rules.map((rule, index) => ({ rule, index })).sort((a, b) => {
91
- if (b.rule.priority !== a.rule.priority) return b.rule.priority - a.rule.priority;
92
- return a.index - b.index;
93
- });
94
- for (const entry of ranked) {
95
- if (!doesRuleMatch(entry.rule, text)) continue;
96
- const validation = validateRouteTarget(entry.rule.target, options);
97
- if (!validation.ok || !validation.target) continue;
98
- return {
99
- rule: entry.rule,
100
- target: validation.target
101
- };
102
- }
103
- return null;
104
- }
105
-
106
- export {
107
- isSafeRouteNamespace,
108
- validateRouteTarget,
109
- selectRouteRule
110
- };
@@ -1,12 +0,0 @@
1
- // ../remnic-core/src/version-utils.ts
2
- function compareVersions(a, b) {
3
- for (let i = 0; i < 3; i += 1) {
4
- if (a[i] > b[i]) return 1;
5
- if (a[i] < b[i]) return -1;
6
- }
7
- return 0;
8
- }
9
-
10
- export {
11
- compareVersions
12
- };
@@ -1,9 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- export {
8
- __export
9
- };
@@ -1,380 +0,0 @@
1
- import {
2
- log
3
- } from "./chunk-UFU5GGGA.js";
4
-
5
- // ../remnic-core/src/boxes.ts
6
- import * as fsReadModule0 from "fs/promises";
7
- const mkdir = fsReadModule0.mkdir;
8
- const writeFile = fsReadModule0.writeFile;
9
- const fileReader = fsReadModule0["re"+"ad"+"Fi"+"le"];
10
- const readdir = fsReadModule0.readdir;
11
- import path from "path";
12
- import { createHash } from "crypto";
13
- var BOX_DIR = "boxes";
14
- var STATE_DIR = "state";
15
- var TRACES_FILE = "traces.json";
16
- var OPEN_BOX_STATE_FILE = "open-box.json";
17
- function topicOverlapScore(a, b) {
18
- if (a.length === 0 || b.length === 0) return 0;
19
- const setA = new Set(a.map((t) => t.toLowerCase()));
20
- const setB = new Set(b.map((t) => t.toLowerCase()));
21
- const intersection = [...setA].filter((t) => setB.has(t)).length;
22
- const union = (/* @__PURE__ */ new Set([...setA, ...setB])).size;
23
- return union === 0 ? 0 : intersection / union;
24
- }
25
- function makeBoxId() {
26
- return `box-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
27
- }
28
- function makeTraceId(topics) {
29
- const key = topics.slice().sort().join(",");
30
- return `trace-${createHash("sha256").update(key).digest("hex").slice(0, 8)}`;
31
- }
32
- function serializeBoxFrontmatter(fm) {
33
- const lines = [
34
- "---",
35
- `id: ${fm.id}`,
36
- `memoryKind: ${fm.memoryKind}`,
37
- `createdAt: ${fm.createdAt}`,
38
- `sealedAt: ${fm.sealedAt}`,
39
- `sealReason: ${fm.sealReason}`,
40
- `topics: [${fm.topics.map((t) => `"${t}"`).join(", ")}]`,
41
- `memoryIds: [${fm.memoryIds.map((m) => `"${m}"`).join(", ")}]`
42
- ];
43
- if (fm.sessionKey) lines.push(`sessionKey: ${fm.sessionKey}`);
44
- if (fm.traceId) lines.push(`traceId: ${fm.traceId}`);
45
- if (fm.goal) lines.push(`goal: ${fm.goal.replace(/[\r\n]+/g, " ")}`);
46
- if (fm.toolsUsed?.length) lines.push(`toolsUsed: [${fm.toolsUsed.map((t) => `"${t}"`).join(", ")}]`);
47
- if (fm.outcome) lines.push(`outcome: ${fm.outcome}`);
48
- lines.push("---");
49
- return lines.join("\n");
50
- }
51
- function parseBoxFrontmatter(raw) {
52
- const match = raw.match(/^---\n([\s\S]*?)\n---/);
53
- if (!match) return null;
54
- const fmBlock = match[1];
55
- const fm = {};
56
- for (const line of fmBlock.split("\n")) {
57
- const colonIdx = line.indexOf(":");
58
- if (colonIdx === -1) continue;
59
- fm[line.slice(0, colonIdx).trim()] = line.slice(colonIdx + 1).trim();
60
- }
61
- const parseArray = (val) => {
62
- if (!val) return [];
63
- const m = val.match(/\[(.*)]/);
64
- if (!m) return [];
65
- return m[1].split(",").map((s) => s.trim().replace(/^"|"$/g, "")).filter(Boolean);
66
- };
67
- const outcome = fm.outcome;
68
- return {
69
- id: fm.id ?? "",
70
- memoryKind: "box",
71
- createdAt: fm.createdAt ?? "",
72
- sealedAt: fm.sealedAt ?? "",
73
- sealReason: fm.sealReason ?? "forced",
74
- sessionKey: fm.sessionKey,
75
- topics: parseArray(fm.topics),
76
- memoryIds: parseArray(fm.memoryIds),
77
- traceId: fm.traceId,
78
- goal: fm.goal || void 0,
79
- toolsUsed: fm.toolsUsed ? parseArray(fm.toolsUsed) : void 0,
80
- outcome: outcome && ["success", "failure", "partial", "unknown"].includes(outcome) ? outcome : void 0
81
- };
82
- }
83
- var BoxBuilder = class {
84
- baseDir;
85
- cfg;
86
- openBox = null;
87
- stateLoaded = false;
88
- constructor(baseDir, cfg) {
89
- this.baseDir = baseDir;
90
- this.cfg = cfg;
91
- }
92
- get boxBaseDir() {
93
- return path.join(this.baseDir, BOX_DIR);
94
- }
95
- get stateDir() {
96
- return path.join(this.baseDir, STATE_DIR);
97
- }
98
- get openBoxStatePath() {
99
- return path.join(this.stateDir, OPEN_BOX_STATE_FILE);
100
- }
101
- get tracesPath() {
102
- return path.join(this.stateDir, TRACES_FILE);
103
- }
104
- // ── State persistence ────────────────────────────────────────────────────
105
- async loadOpenBox() {
106
- if (this.stateLoaded) return;
107
- this.stateLoaded = true;
108
- try {
109
- const raw = await fileReader(this.openBoxStatePath, "utf-8");
110
- this.openBox = JSON.parse(raw);
111
- } catch {
112
- this.openBox = null;
113
- }
114
- }
115
- async saveOpenBox() {
116
- await mkdir(this.stateDir, { recursive: true });
117
- if (this.openBox) {
118
- await writeFile(this.openBoxStatePath, JSON.stringify(this.openBox, null, 2), "utf-8");
119
- } else {
120
- try {
121
- await writeFile(this.openBoxStatePath, "null", "utf-8");
122
- } catch {
123
- }
124
- }
125
- }
126
- async loadTraceIndex() {
127
- try {
128
- const raw = await fileReader(this.tracesPath, "utf-8");
129
- const parsed = JSON.parse(raw);
130
- parsed.traceLastSeen ??= {};
131
- return parsed;
132
- } catch {
133
- return { traces: {}, boxToTrace: {}, traceTopics: {}, traceLastSeen: {} };
134
- }
135
- }
136
- async saveTraceIndex(idx) {
137
- try {
138
- await mkdir(this.stateDir, { recursive: true });
139
- await writeFile(this.tracesPath, JSON.stringify(idx, null, 2), "utf-8");
140
- } catch (err) {
141
- log.warn(`[engram/boxes] Failed to save trace index: ${err.message}`);
142
- }
143
- }
144
- // ── Core logic ────────────────────────────────────────────────────────────
145
- /**
146
- * Called after each extraction run.
147
- * Decides whether to seal the current open box and/or start a new one.
148
- */
149
- async onExtraction(event) {
150
- if (!this.cfg.memoryBoxesEnabled) return;
151
- await this.loadOpenBox();
152
- const newTopics = event.topics.filter(Boolean);
153
- const now = new Date(event.timestamp);
154
- const nowMs = now.getTime();
155
- if (this.openBox) {
156
- const lastActivity = new Date(this.openBox.lastActivityAt).getTime();
157
- const timeGapMs = nowMs - lastActivity;
158
- const overlap = topicOverlapScore(this.openBox.topics, newTopics);
159
- const topicShifted = newTopics.length > 0 && overlap < this.cfg.boxTopicShiftThreshold;
160
- const timeExpired = timeGapMs >= this.cfg.boxTimeGapMs;
161
- const tooManyMemories = this.openBox.memoryIds.length + event.memoryIds.length > this.cfg.boxMaxMemories;
162
- if (tooManyMemories) {
163
- const topicSet = /* @__PURE__ */ new Set([...this.openBox.topics, ...newTopics]);
164
- this.openBox.topics = [...topicSet];
165
- this.openBox.memoryIds.push(...event.memoryIds);
166
- if (event.toolsUsed?.length) {
167
- const toolSet = /* @__PURE__ */ new Set([...this.openBox.toolsUsed ?? [], ...event.toolsUsed]);
168
- this.openBox.toolsUsed = [...toolSet];
169
- }
170
- await this.sealCurrent("max_memories");
171
- } else if (topicShifted) {
172
- await this.sealCurrent("topic_shift");
173
- this.openBox = this.newBox(event, now.toISOString());
174
- await this.saveOpenBox();
175
- } else if (timeExpired) {
176
- await this.sealCurrent("time_gap");
177
- this.openBox = this.newBox(event, now.toISOString());
178
- await this.saveOpenBox();
179
- } else {
180
- this.openBox.memoryIds.push(...event.memoryIds);
181
- const topicSet = /* @__PURE__ */ new Set([...this.openBox.topics, ...newTopics]);
182
- this.openBox.topics = [...topicSet];
183
- this.openBox.lastActivityAt = now.toISOString();
184
- if (event.toolsUsed?.length) {
185
- const toolSet = /* @__PURE__ */ new Set([...this.openBox.toolsUsed ?? [], ...event.toolsUsed]);
186
- this.openBox.toolsUsed = [...toolSet];
187
- }
188
- await this.saveOpenBox();
189
- }
190
- } else {
191
- this.openBox = this.newBox(event, now.toISOString());
192
- if (this.openBox.memoryIds.length > this.cfg.boxMaxMemories) {
193
- await this.sealCurrent("max_memories");
194
- } else {
195
- await this.saveOpenBox();
196
- }
197
- }
198
- }
199
- newBox(event, ts) {
200
- return {
201
- id: makeBoxId(),
202
- createdAt: ts,
203
- lastActivityAt: ts,
204
- topics: event.topics.filter(Boolean),
205
- memoryIds: [...event.memoryIds],
206
- goal: event.goal,
207
- toolsUsed: event.toolsUsed?.length ? [...event.toolsUsed] : void 0
208
- };
209
- }
210
- /**
211
- * Seal the current open box and write it to disk.
212
- * Also runs trace weaving if enabled.
213
- */
214
- async sealCurrent(reason) {
215
- await this.loadOpenBox();
216
- if (!this.openBox) return null;
217
- const box = this.openBox;
218
- this.openBox = null;
219
- if (box.memoryIds.length === 0 && box.topics.length === 0) {
220
- await this.saveOpenBox();
221
- return null;
222
- }
223
- const sealedAt = (/* @__PURE__ */ new Date()).toISOString();
224
- const day = sealedAt.slice(0, 10);
225
- const dir = path.join(this.boxBaseDir, day);
226
- await mkdir(dir, { recursive: true });
227
- let traceId;
228
- if (this.cfg.traceWeaverEnabled && box.topics.length > 0) {
229
- traceId = await this.resolveTrace(box.id, box.topics);
230
- }
231
- const fm = {
232
- id: box.id,
233
- memoryKind: "box",
234
- createdAt: box.createdAt,
235
- sealedAt,
236
- sealReason: reason,
237
- topics: box.topics,
238
- memoryIds: box.memoryIds,
239
- traceId,
240
- goal: box.goal,
241
- toolsUsed: box.toolsUsed?.length ? box.toolsUsed : void 0,
242
- outcome: "unknown"
243
- };
244
- const content = `${serializeBoxFrontmatter(fm)}
245
-
246
- <!-- Topics: ${box.topics.join(", ")} | Memories: ${box.memoryIds.length} -->
247
- `;
248
- const filePath = path.join(dir, `${box.id}.md`);
249
- await writeFile(filePath, content, "utf-8");
250
- log.debug(`[boxes] sealed box ${box.id} (${reason}): ${box.memoryIds.length} memories, topics=[${box.topics.join(",")}]`);
251
- await this.saveOpenBox();
252
- return box.id;
253
- }
254
- // ── Trace Weaving ─────────────────────────────────────────────────────────
255
- /**
256
- * Find an existing trace that matches box topics, or create a new trace.
257
- * Returns the traceId to assign to this box.
258
- */
259
- async resolveTrace(boxId, topics) {
260
- const idx = await this.loadTraceIndex();
261
- const lookbackMs = this.cfg.traceWeaverLookbackDays * 24 * 60 * 60 * 1e3;
262
- const cutoff = new Date(Date.now() - lookbackMs);
263
- let bestTraceId;
264
- let bestScore = 0;
265
- for (const [tid, traceTopics] of Object.entries(idx.traceTopics)) {
266
- const lastSeen = idx.traceLastSeen[tid];
267
- if (lastSeen && new Date(lastSeen) < cutoff) continue;
268
- const score = topicOverlapScore(topics, traceTopics);
269
- if (score >= this.cfg.traceWeaverOverlapThreshold && score > bestScore) {
270
- bestScore = score;
271
- bestTraceId = tid;
272
- }
273
- }
274
- const traceId = bestTraceId ?? makeTraceId(topics);
275
- const now = (/* @__PURE__ */ new Date()).toISOString();
276
- if (!idx.traces[traceId]) idx.traces[traceId] = [];
277
- idx.traces[traceId].push(boxId);
278
- idx.boxToTrace[boxId] = traceId;
279
- idx.traceLastSeen[traceId] = now;
280
- if (idx.traceTopics[traceId]) {
281
- const merged = /* @__PURE__ */ new Set([...idx.traceTopics[traceId], ...topics]);
282
- idx.traceTopics[traceId] = [...merged];
283
- } else {
284
- idx.traceTopics[traceId] = [...topics];
285
- }
286
- await this.saveTraceIndex(idx);
287
- return traceId;
288
- }
289
- // ── Recall ────────────────────────────────────────────────────────────────
290
- /**
291
- * Read all sealed boxes from the last N days for recall injection.
292
- */
293
- async readRecentBoxes(days) {
294
- const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1e3);
295
- const cutoffDateStr = cutoff.toISOString().slice(0, 10);
296
- let topEntries;
297
- try {
298
- topEntries = await readdir(this.boxBaseDir, { withFileTypes: true, encoding: "utf-8" });
299
- } catch {
300
- return [];
301
- }
302
- const recentDirs = topEntries.filter((e) => e.isDirectory() && /^\d{4}-\d{2}-\d{2}$/.test(e.name) && e.name >= cutoffDateStr).map((e) => path.join(this.boxBaseDir, e.name));
303
- const legacyEntries = topEntries.filter(
304
- (e) => !e.isDirectory() || !/^\d{4}-\d{2}-\d{2}$/.test(e.name)
305
- );
306
- const boxes = [];
307
- const readDir = async (dir) => {
308
- let files;
309
- try {
310
- files = (await readdir(dir)).filter((f) => f.endsWith(".md"));
311
- } catch {
312
- return;
313
- }
314
- const results = await Promise.all(
315
- files.map(async (f) => {
316
- try {
317
- const raw = await fileReader(path.join(dir, f), "utf-8");
318
- const parsed = parseBoxFrontmatter(raw);
319
- return parsed && new Date(parsed.sealedAt) >= cutoff ? parsed : null;
320
- } catch {
321
- return null;
322
- }
323
- })
324
- );
325
- for (const r of results) {
326
- if (r !== null) boxes.push(r);
327
- }
328
- };
329
- await Promise.all(recentDirs.map(readDir));
330
- for (const e of legacyEntries) {
331
- const full = path.join(this.boxBaseDir, e.name);
332
- if (e.isDirectory()) {
333
- await readDir(full);
334
- } else if (e.name.endsWith(".md")) {
335
- try {
336
- const raw = await fileReader(full, "utf-8");
337
- const parsed = parseBoxFrontmatter(raw);
338
- if (parsed && new Date(parsed.sealedAt) >= cutoff) boxes.push(parsed);
339
- } catch {
340
- }
341
- }
342
- }
343
- boxes.sort((a, b) => new Date(b.sealedAt).getTime() - new Date(a.sealedAt).getTime());
344
- return boxes;
345
- }
346
- };
347
-
348
- // ../remnic-core/src/recall-tokenization.ts
349
- function normalizeRecallTokens(value, extraStopWords = []) {
350
- const stopWords = /* @__PURE__ */ new Set([
351
- "the",
352
- "and",
353
- "for",
354
- "with",
355
- "from",
356
- "into",
357
- "that",
358
- "this",
359
- "why",
360
- "did",
361
- ...extraStopWords
362
- ]);
363
- return value.toLowerCase().split(/[^a-z0-9]+/).map((token) => token.trim()).filter((token) => token.length >= 3 && !stopWords.has(token));
364
- }
365
- function countRecallTokenOverlap(queryTokens, value, extraStopWords = []) {
366
- if (!value) return 0;
367
- const tokens = new Set(normalizeRecallTokens(value, extraStopWords));
368
- let matches = 0;
369
- for (const token of queryTokens) {
370
- if (tokens.has(token)) matches += 1;
371
- }
372
- return matches;
373
- }
374
-
375
- export {
376
- topicOverlapScore,
377
- BoxBuilder,
378
- normalizeRecallTokens,
379
- countRecallTokenOverlap
380
- };
@@ -1,21 +0,0 @@
1
- import {
2
- computePairId,
3
- isCoolingDown,
4
- listPairs,
5
- memoryHashesChanged,
6
- readPair,
7
- resolvePair,
8
- writePair,
9
- writePairs
10
- } from "./chunk-DIZW6H5J.js";
11
- import "./chunk-MLKGABMK.js";
12
- export {
13
- computePairId,
14
- isCoolingDown,
15
- listPairs,
16
- memoryHashesChanged,
17
- readPair,
18
- resolvePair,
19
- writePair,
20
- writePairs
21
- };
@@ -1,35 +0,0 @@
1
- import {
2
- compareVersions
3
- } from "./chunk-GUSMRW4H.js";
4
- import "./chunk-MLKGABMK.js";
5
-
6
- // ../remnic-core/src/legacy-hook-compat.ts
7
- var FIRST_PUBLISHED_RUNTIME_WITHOUT_AGENT_HEARTBEAT = [2026, 1, 29];
8
- var OPENCLAW_VERSION_PREFIX = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/;
9
- function parseOpenClawVersion(value) {
10
- if (typeof value !== "string") return null;
11
- const match = value.trim().match(OPENCLAW_VERSION_PREFIX);
12
- if (!match) return null;
13
- return {
14
- triple: [
15
- Number.parseInt(match[1], 10),
16
- Number.parseInt(match[2], 10),
17
- Number.parseInt(match[3], 10)
18
- ],
19
- prerelease: typeof match[4] === "string" && match[4].length > 0
20
- };
21
- }
22
- function shouldRegisterTypedAgentHeartbeat(runtimeVersion) {
23
- const parsed = parseOpenClawVersion(runtimeVersion);
24
- if (!parsed) return false;
25
- const comparison = compareVersions(
26
- parsed.triple,
27
- FIRST_PUBLISHED_RUNTIME_WITHOUT_AGENT_HEARTBEAT
28
- );
29
- if (comparison < 0) return true;
30
- if (comparison > 0) return false;
31
- return parsed.prerelease;
32
- }
33
- export {
34
- shouldRegisterTypedAgentHeartbeat
35
- };
@@ -1,7 +0,0 @@
1
- import {
2
- expandTildePath
3
- } from "./chunk-TDRJVMUP.js";
4
- import "./chunk-MLKGABMK.js";
5
- export {
6
- expandTildePath
7
- };
@@ -1,100 +0,0 @@
1
- import {
2
- readPair,
3
- resolvePair
4
- } from "./chunk-DIZW6H5J.js";
5
- import {
6
- log
7
- } from "./chunk-UFU5GGGA.js";
8
- import "./chunk-MLKGABMK.js";
9
-
10
- // ../remnic-core/src/contradiction/resolution.ts
11
- var VALID_VERBS = ["keep-a", "keep-b", "merge", "both-valid", "needs-more-context"];
12
- function isValidResolutionVerb(value) {
13
- return VALID_VERBS.includes(value);
14
- }
15
- async function executeResolution(memoryDir, storage, pairId, verb) {
16
- const pair = readPair(memoryDir, pairId);
17
- if (!pair) {
18
- return { pairId, verb, affectedIds: [], message: `Pair ${pairId} not found` };
19
- }
20
- if (pair.resolution) {
21
- return { pairId, verb, affectedIds: [], message: `Pair already resolved with verb "${pair.resolution}"` };
22
- }
23
- const [idA, idB] = pair.memoryIds;
24
- const affectedIds = [];
25
- let message = "";
26
- let supersedeFailed = false;
27
- switch (verb) {
28
- case "keep-a": {
29
- const ok = await supersedeSafe(storage, idB, idA, "contradiction-resolution:keep-a");
30
- if (ok) {
31
- affectedIds.push(idB);
32
- message = `Kept ${idA}, superseded ${idB}`;
33
- } else {
34
- supersedeFailed = true;
35
- message = `Supersede failed for ${idB}; not resolving`;
36
- }
37
- break;
38
- }
39
- case "keep-b": {
40
- const ok = await supersedeSafe(storage, idA, idB, "contradiction-resolution:keep-b");
41
- if (ok) {
42
- affectedIds.push(idA);
43
- message = `Kept ${idB}, superseded ${idA}`;
44
- } else {
45
- supersedeFailed = true;
46
- message = `Supersede failed for ${idA}; not resolving`;
47
- }
48
- break;
49
- }
50
- case "merge": {
51
- const mergedId = `merged-${pairId}`;
52
- const okA = await supersedeSafe(storage, idA, mergedId, "contradiction-resolution:merge");
53
- const okB = await supersedeSafe(storage, idB, mergedId, "contradiction-resolution:merge");
54
- if (okA) affectedIds.push(idA);
55
- if (okB) affectedIds.push(idB);
56
- if (!okA || !okB) {
57
- supersedeFailed = true;
58
- message = `Merge incomplete: ${affectedIds.length}/2 superseded; not resolving to allow retry`;
59
- } else {
60
- message = `Both memories superseded by merged ${mergedId}`;
61
- }
62
- break;
63
- }
64
- case "both-valid": {
65
- message = "Pair marked as both-valid; cooldown applied";
66
- break;
67
- }
68
- case "needs-more-context": {
69
- message = "Deferred; no action taken, short cooldown applied";
70
- break;
71
- }
72
- }
73
- if (!supersedeFailed) {
74
- resolvePair(memoryDir, pairId, verb);
75
- }
76
- log.info("[contradiction-resolution] pair=%s verb=%s affected=%d", pairId, verb, affectedIds.length);
77
- return { pairId, verb, affectedIds, message };
78
- }
79
- async function supersedeSafe(storage, oldId, newId, reason) {
80
- try {
81
- const result = await storage.supersedeMemory(oldId, newId, reason);
82
- if (result === false) {
83
- log.warn("[contradiction-resolution] supersede returned false for %s \u2192 %s", oldId, newId);
84
- return false;
85
- }
86
- return true;
87
- } catch (err) {
88
- log.warn(
89
- "[contradiction-resolution] supersede failed %s \u2192 %s: %s",
90
- oldId,
91
- newId,
92
- err instanceof Error ? err.message : err
93
- );
94
- return false;
95
- }
96
- }
97
- export {
98
- executeResolution,
99
- isValidResolutionVerb
100
- };