@remnic/plugin-openclaw 1.0.54 → 9.3.517

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 (84) hide show
  1. package/dist/index.js +510 -2106
  2. package/openclaw.plugin.json +3 -3
  3. package/package.json +4 -3
  4. package/scripts/faiss_index.py +141 -29
  5. package/dist/calibration-RKL2LRW4.js +0 -250
  6. package/dist/capsule-cli-EHZPMXBC.js +0 -33
  7. package/dist/capsule-crypto-JS67OSWM.js +0 -17
  8. package/dist/capsule-export-DX53CPIT.js +0 -17
  9. package/dist/capsule-import-4OXCPHOT.js +0 -16
  10. package/dist/capsule-merge-25AUN33Q.js +0 -195
  11. package/dist/causal-chain-BVTOWZKC.js +0 -23
  12. package/dist/causal-consolidation-IAIX53NV.js +0 -233
  13. package/dist/causal-retrieval-XAP6QKHZ.js +0 -182
  14. package/dist/causal-trajectory-graph-ZWQWZ7N5.js +0 -59
  15. package/dist/chunk-25J4PXDH.js +0 -30
  16. package/dist/chunk-2RQU6GVD.js +0 -453
  17. package/dist/chunk-3A5ELHTT.js +0 -61
  18. package/dist/chunk-3G7FAF6S.js +0 -60
  19. package/dist/chunk-3IKMUNW5.js +0 -177
  20. package/dist/chunk-4XDQ3KEC.js +0 -4048
  21. package/dist/chunk-5ZW5XJQ6.js +0 -128
  22. package/dist/chunk-6IWEAUN6.js +0 -148
  23. package/dist/chunk-7JOLBJJ5.js +0 -874
  24. package/dist/chunk-AJECKGY2.js +0 -896
  25. package/dist/chunk-B52XADV3.js +0 -244
  26. package/dist/chunk-BQZ7JACP.js +0 -389
  27. package/dist/chunk-BU5KJVWF.js +0 -78
  28. package/dist/chunk-BZ4EYURA.js +0 -181
  29. package/dist/chunk-CEL5ZLKP.js +0 -233
  30. package/dist/chunk-EH4AXGRO.js +0 -48
  31. package/dist/chunk-FDK3VJVE.js +0 -1295
  32. package/dist/chunk-I2KLQ2HA.js +0 -22
  33. package/dist/chunk-IO5WWY6A.js +0 -156
  34. package/dist/chunk-JC3FCKYL.js +0 -516
  35. package/dist/chunk-JZBOXOUC.js +0 -259
  36. package/dist/chunk-KC7KSQR4.js +0 -302
  37. package/dist/chunk-LZCGPRHS.js +0 -228
  38. package/dist/chunk-MBIFE6SA.js +0 -250
  39. package/dist/chunk-MXFJXUHC.js +0 -292
  40. package/dist/chunk-NUWDSTP7.js +0 -233
  41. package/dist/chunk-QCCP4RU5.js +0 -190
  42. package/dist/chunk-QMUQV5NP.js +0 -146
  43. package/dist/chunk-QQXJODFL.js +0 -328
  44. package/dist/chunk-SWOYEQN2.js +0 -1005
  45. package/dist/chunk-TH5FF5SC.js +0 -16
  46. package/dist/chunk-TXOEHSVP.js +0 -275
  47. package/dist/chunk-UFU5GGGA.js +0 -47
  48. package/dist/chunk-USSDZQKJ.js +0 -6533
  49. package/dist/chunk-UZJ7EERS.js +0 -272
  50. package/dist/chunk-VUZEEGP5.js +0 -725
  51. package/dist/chunk-W6EEFUCJ.js +0 -349
  52. package/dist/chunk-YGGGUTG3.js +0 -125
  53. package/dist/chunk-YJYZMLD5.js +0 -360
  54. package/dist/chunk-YKV4EFUI.js +0 -199
  55. package/dist/chunk-ZS6VABML.js +0 -185
  56. package/dist/cipher-E23BHBSO.js +0 -27
  57. package/dist/consolidation-undo-FKJZCJHS.js +0 -426
  58. package/dist/contradiction-review-WJRWNQ5N.js +0 -29
  59. package/dist/contradiction-scan-5X423QGT.js +0 -12
  60. package/dist/dreams-ledger-KDX44I7R.js +0 -290
  61. package/dist/engine-O46ZX4EZ.js +0 -16
  62. package/dist/extraction-judge-telemetry-O4ZVGLTU.js +0 -14
  63. package/dist/fallback-llm-43UMEXNJ.js +0 -10
  64. package/dist/first-start-migration-H2SAXAGR.js +0 -263
  65. package/dist/forget-ZECIDNL5.js +0 -68
  66. package/dist/fs-utils-OYXSZSVV.js +0 -39
  67. package/dist/graph-edge-decay-24ZKD5QL.js +0 -202
  68. package/dist/kdf-RXKIWHRU.js +0 -25
  69. package/dist/logger-XG7JKLPS.js +0 -9
  70. package/dist/memory-governance-6BCH6SZ5.js +0 -25
  71. package/dist/metadata-WK2TRPYZ.js +0 -20
  72. package/dist/migrate-from-identity-anchor-SNDNKHZD.js +0 -7
  73. package/dist/path-ZKO74XXC.js +0 -7
  74. package/dist/peers-W53WSDXG.js +0 -43
  75. package/dist/purge-IKJISXEQ.js +0 -204
  76. package/dist/resolution-BN35OXDS.js +0 -11
  77. package/dist/secure-store-6RWYM6GK.js +0 -155
  78. package/dist/state-4ITLYMAU.js +0 -7
  79. package/dist/state-store-ET3ADVY5.js +0 -14
  80. package/dist/storage-VEGU76NN.js +0 -27
  81. package/dist/tier-stats-ZRQBV6G2.js +0 -147
  82. package/dist/trace-IL2Y34EH.js +0 -289
  83. package/dist/tui-7KRDCMYK.js +0 -12
  84. package/dist/types-MBUINTB2.js +0 -30
@@ -1,244 +0,0 @@
1
- import {
2
- gatherConsoleState
3
- } from "./chunk-MBIFE6SA.js";
4
-
5
- // ../remnic-core/src/console/tui.ts
6
- var ANSI_CLEAR_HOME = "\x1B[2J\x1B[H";
7
- var ANSI_HIDE_CURSOR = "\x1B[?25l";
8
- var ANSI_SHOW_CURSOR = "\x1B[?25h";
9
- var FRAME_INNER_WIDTH = 70;
10
- var DEFAULT_REFRESH_INTERVAL_MS = 2e3;
11
- function runConsoleTui(orchestrator, options = {}) {
12
- const refreshIntervalMs = Math.max(
13
- 50,
14
- options.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS
15
- );
16
- const output = options.output ?? process.stdout;
17
- const now = options.now ?? (() => Date.now());
18
- const installSigintHandler = options.installSigintHandler ?? true;
19
- let stopped = false;
20
- let inFlight = false;
21
- let inFlightTickPromise = null;
22
- let traceWritePending = false;
23
- let traceFramesDropped = 0;
24
- let resolveDone;
25
- const done = new Promise((resolve) => {
26
- resolveDone = resolve;
27
- });
28
- safeWrite(output, ANSI_HIDE_CURSOR);
29
- const tick = async () => {
30
- if (stopped || inFlight) return;
31
- inFlight = true;
32
- try {
33
- let snapshot = null;
34
- let renderError = null;
35
- try {
36
- snapshot = await gatherConsoleState(orchestrator);
37
- } catch (err) {
38
- renderError = describeError(err);
39
- }
40
- if (stopped) return;
41
- let frame;
42
- try {
43
- frame = renderFrame({ snapshot, renderError, now });
44
- } catch (err) {
45
- frame = `remnic console: render failed: ${describeError(err)}
46
- `;
47
- }
48
- safeWrite(output, ANSI_CLEAR_HOME);
49
- safeWrite(output, frame);
50
- if (snapshot && options.traceRecorder && !traceWritePending) {
51
- traceWritePending = true;
52
- void options.traceRecorder.append(snapshot).catch(() => {
53
- }).finally(() => {
54
- traceWritePending = false;
55
- });
56
- } else if (snapshot && options.traceRecorder) {
57
- traceFramesDropped += 1;
58
- }
59
- } finally {
60
- inFlight = false;
61
- }
62
- };
63
- const launchTick = () => {
64
- const p = runTickSafely(tick);
65
- inFlightTickPromise = p;
66
- void p.then(() => {
67
- if (inFlightTickPromise === p) {
68
- inFlightTickPromise = null;
69
- }
70
- });
71
- };
72
- launchTick();
73
- const handle = setInterval(launchTick, refreshIntervalMs);
74
- const sigintHandler = () => {
75
- stop();
76
- };
77
- if (installSigintHandler) {
78
- process.on("SIGINT", sigintHandler);
79
- }
80
- const stop = () => {
81
- if (stopped) return;
82
- stopped = true;
83
- clearInterval(handle);
84
- if (installSigintHandler) {
85
- try {
86
- process.removeListener("SIGINT", sigintHandler);
87
- } catch {
88
- }
89
- }
90
- safeWrite(output, ANSI_SHOW_CURSOR);
91
- void (async () => {
92
- try {
93
- const pendingTick = inFlightTickPromise;
94
- if (pendingTick) {
95
- await pendingTick;
96
- }
97
- } finally {
98
- resolveDone();
99
- }
100
- })();
101
- };
102
- return {
103
- stop,
104
- done,
105
- getDroppedTraceFrames: () => traceFramesDropped
106
- };
107
- }
108
- function renderFrame(input) {
109
- const ts = new Date(input.now()).toISOString();
110
- const lines = [];
111
- lines.push(renderHeader(ts));
112
- for (const panel of renderPanels(input)) {
113
- lines.push(panel);
114
- }
115
- lines.push(renderFooter());
116
- return lines.join("\n") + "\n";
117
- }
118
- function renderHeader(ts) {
119
- const title = " remnic console ";
120
- const trailing = ` ${ts} `;
121
- const fillerLen = Math.max(
122
- 1,
123
- FRAME_INNER_WIDTH - title.length - trailing.length
124
- );
125
- const filler = "\u2550".repeat(fillerLen);
126
- return `\u2554${title}${filler}${trailing}\u2557`;
127
- }
128
- function renderFooter() {
129
- return `\u255A${"\u2550".repeat(FRAME_INNER_WIDTH)}\u255D`;
130
- }
131
- function renderPanels(input) {
132
- const lines = [];
133
- const snap = input.snapshot;
134
- if (input.renderError !== null) {
135
- lines.push(panelLine("Error", `refresh failed: ${input.renderError}`));
136
- lines.push(panelLine("Buffer", "(unavailable)"));
137
- lines.push(panelLine("Extraction", "(unavailable)"));
138
- lines.push(panelLine("Dedup", "(unavailable)"));
139
- lines.push(panelLine("Maintenance", "(unavailable)"));
140
- lines.push(panelLine("QMD", "(unavailable)"));
141
- return lines;
142
- }
143
- if (snap) {
144
- lines.push(
145
- panelLine(
146
- "Buffer",
147
- `turns=${snap.bufferState.turnsCount} bytes=${snap.bufferState.byteCount}`
148
- )
149
- );
150
- const verdicts = snap.extractionQueue.recentVerdicts;
151
- const accepts = verdicts.filter((v) => v.kind === "accept").length;
152
- const rejects = verdicts.filter((v) => v.kind === "reject").length;
153
- lines.push(
154
- panelLine(
155
- "Extraction",
156
- `queue=${snap.extractionQueue.depth} recent verdicts: accept(${accepts})/reject(${rejects})`
157
- )
158
- );
159
- const dedupSummary = formatDedupSummary(snap.dedupRecent, input.now);
160
- lines.push(panelLine("Dedup", dedupSummary));
161
- const maintSummary = formatMaintenanceTail(snap.maintenanceLedgerTail);
162
- lines.push(panelLine("Maintenance", maintSummary));
163
- lines.push(panelLine("QMD", formatQmdSummary(snap)));
164
- }
165
- if (snap && snap.errors.length > 0) {
166
- const head = snap.errors[0];
167
- lines.push(panelLine("Errors", head ?? ""));
168
- }
169
- return lines;
170
- }
171
- function formatDedupSummary(decisions, now) {
172
- if (decisions.length === 0) return "no recent decisions";
173
- const last = decisions[decisions.length - 1];
174
- if (!last) return "no recent decisions";
175
- const ageMs = ageMsFromIso(last.ts, now);
176
- const ageStr = ageMs === null ? "T-?" : `T-${Math.round(ageMs / 1e3)}s`;
177
- const fp = last.fingerprint ? `hash=${last.fingerprint}` : "hash=?";
178
- return `recent: ${fp} decision=${last.decision} (${ageStr})`;
179
- }
180
- function formatMaintenanceTail(events) {
181
- if (events.length === 0) return "no events";
182
- const last = events[events.length - 1];
183
- if (!last) return "no events";
184
- return `n=${events.length} last: ${last.category} ${truncate(last.summary, 40)}`;
185
- }
186
- function formatQmdSummary(snap) {
187
- const probe = snap.qmdProbe.available ? "ok" : "down";
188
- const uptimeH = snap.daemon.uptimeMs / 36e5;
189
- const uptimeStr = uptimeH < 1 ? `${Math.round(snap.daemon.uptimeMs / 1e3)}s` : `${uptimeH.toFixed(1)}h`;
190
- const mode = snap.qmdProbe.daemonMode ? "daemon" : "cli";
191
- return `probe=${probe} mode=${mode} uptime=${uptimeStr}`;
192
- }
193
- function panelLine(label, value) {
194
- const LABEL_WIDTH = 13;
195
- const labelCol = padRight(label, LABEL_WIDTH);
196
- const remaining = FRAME_INNER_WIDTH - LABEL_WIDTH - 2;
197
- const valueCol = padRight(truncate(value, remaining), remaining);
198
- return `\u2551 ${labelCol}${valueCol} \u2551`;
199
- }
200
- function padRight(s, width) {
201
- if (s.length >= width) return s;
202
- return s + " ".repeat(width - s.length);
203
- }
204
- function truncate(s, max) {
205
- if (max <= 0) return "";
206
- if (s.length <= max) return s;
207
- if (max <= 1) return s.slice(0, max);
208
- return s.slice(0, max - 1) + "\u2026";
209
- }
210
- function ageMsFromIso(iso, now) {
211
- const ms = Date.parse(iso);
212
- if (!Number.isFinite(ms)) return null;
213
- const delta = now() - ms;
214
- return delta < 0 ? 0 : delta;
215
- }
216
- async function runTickSafely(tick) {
217
- try {
218
- await tick();
219
- } catch {
220
- }
221
- }
222
- function safeWrite(output, chunk) {
223
- try {
224
- output.write(chunk);
225
- } catch {
226
- }
227
- }
228
- function describeError(err) {
229
- if (err instanceof Error) return err.message;
230
- try {
231
- return String(err);
232
- } catch {
233
- return "unknown error";
234
- }
235
- }
236
- function stripAnsi(s) {
237
- return s.replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "");
238
- }
239
-
240
- export {
241
- runConsoleTui,
242
- renderFrame,
243
- stripAnsi
244
- };
@@ -1,389 +0,0 @@
1
- import {
2
- AUTH_TAG_LENGTH,
3
- ENVELOPE_HEADER_SIZE,
4
- ENVELOPE_LAYOUT,
5
- ENVELOPE_SALT_LENGTH,
6
- ENVELOPE_VERSION,
7
- IV_LENGTH,
8
- generateSalt,
9
- open,
10
- seal
11
- } from "./chunk-YGGGUTG3.js";
12
-
13
- // ../remnic-core/src/secure-store/secure-fs.ts
14
- import { createCipheriv, randomBytes } from "crypto";
15
- import * as fsReadModule0 from "fs/promises";
16
- const lstat = fsReadModule0.lstat;
17
- const mkdir = fsReadModule0.mkdir;
18
- const openFile = fsReadModule0.open;
19
- const fileReader = fsReadModule0["re"+"ad"+"Fi"+"le"];
20
- const readdir = fsReadModule0.readdir;
21
- const rename = fsReadModule0.rename;
22
- const unlink = fsReadModule0.unlink;
23
- const writeFile = fsReadModule0.writeFile;
24
- import path from "path";
25
- var SecureStoreLockedError = class extends Error {
26
- constructor(message = "secure-store is locked \u2014 run `remnic secure-store unlock` to decrypt") {
27
- super(message);
28
- this.name = "SecureStoreLockedError";
29
- }
30
- };
31
- var SecureStoreDecryptError = class extends Error {
32
- constructor(message = "secure-store decryption failed \u2014 wrong key or tampered ciphertext") {
33
- super(message);
34
- this.name = "SecureStoreDecryptError";
35
- }
36
- };
37
- var MAGIC_BYTES = Buffer.from("REMNIC-ENC", "ascii");
38
- var FILE_FORMAT_VERSION = 1;
39
- var FILE_FORMAT_FLAGS = 0;
40
- var MAGIC_HEADER_SIZE = MAGIC_BYTES.length + 2;
41
- function isEncryptedFile(buf) {
42
- if (buf.length < MAGIC_HEADER_SIZE) return false;
43
- const b = Buffer.isBuffer(buf) ? buf : Buffer.from(buf);
44
- return b.subarray(0, MAGIC_BYTES.length).equals(MAGIC_BYTES);
45
- }
46
- function encryptFileBody(plain, key, aad) {
47
- const plainBuf = typeof plain === "string" ? Buffer.from(plain, "utf8") : plain;
48
- const salt = generateSalt();
49
- const envelope = seal(key, salt, plainBuf, aad ? { aad } : {});
50
- const header = Buffer.alloc(MAGIC_HEADER_SIZE);
51
- MAGIC_BYTES.copy(header, 0);
52
- header.writeUInt8(FILE_FORMAT_VERSION, MAGIC_BYTES.length);
53
- header.writeUInt8(FILE_FORMAT_FLAGS, MAGIC_BYTES.length + 1);
54
- return Buffer.concat([header, envelope]);
55
- }
56
- function decryptFileBody(buf, key, aad) {
57
- if (!isEncryptedFile(buf)) {
58
- throw new Error("decryptFileBody: buffer does not start with REMNIC-ENC magic header");
59
- }
60
- const version = buf.readUInt8(MAGIC_BYTES.length);
61
- if (version !== FILE_FORMAT_VERSION) {
62
- throw new Error(
63
- `decryptFileBody: unsupported file format version ${version} (this build supports ${FILE_FORMAT_VERSION})`
64
- );
65
- }
66
- const flags = buf.readUInt8(MAGIC_BYTES.length + 1);
67
- if (flags !== FILE_FORMAT_FLAGS) {
68
- throw new Error(`decryptFileBody: unknown flags byte 0x${flags.toString(16).padStart(2, "0")}`);
69
- }
70
- const envelope = buf.subarray(MAGIC_HEADER_SIZE);
71
- try {
72
- return open(key, envelope, aad ? { aad } : {});
73
- } catch (err) {
74
- const msg = err instanceof Error ? err.message : String(err);
75
- throw new SecureStoreDecryptError(
76
- `secure-store decryption failed: ${msg}`
77
- );
78
- }
79
- }
80
- function buildHeaderAad(salt) {
81
- const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
82
- out.writeUInt8(ENVELOPE_VERSION, 0);
83
- Buffer.from(salt).copy(out, 1);
84
- return out;
85
- }
86
- function filePathAad(filePath, memoryDir) {
87
- let rel = filePath;
88
- if (memoryDir && path.isAbsolute(filePath)) {
89
- rel = path.relative(memoryDir, filePath);
90
- }
91
- return Buffer.from(rel, "utf8");
92
- }
93
- async function readMaybeEncryptedFileBuffer(filePath, key, memoryDir) {
94
- const buf = await fileReader(filePath);
95
- if (!isEncryptedFile(buf)) {
96
- return buf;
97
- }
98
- if (key === null) {
99
- throw new SecureStoreLockedError(
100
- `secure-store is locked \u2014 cannot read encrypted file at ${filePath}. Run \`remnic secure-store unlock\` to decrypt.`
101
- );
102
- }
103
- const aad = filePathAad(filePath, memoryDir);
104
- return decryptFileBody(buf, key, aad);
105
- }
106
- async function readMaybeEncryptedFile(filePath, key, memoryDir) {
107
- return (await readMaybeEncryptedFileBuffer(filePath, key, memoryDir)).toString("utf8");
108
- }
109
- async function writeMaybeEncryptedFile(filePath, content, key, options = {}, memoryDir) {
110
- const { mode = 384, atomic = true } = options;
111
- await mkdir(path.dirname(filePath), { recursive: true });
112
- let data;
113
- if (key !== null) {
114
- const aad = filePathAad(filePath, memoryDir);
115
- data = encryptFileBody(content, key, aad);
116
- } else {
117
- data = content;
118
- }
119
- if (atomic) {
120
- const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
121
- try {
122
- await writeFile(tempPath, data, { mode });
123
- await rename(tempPath, filePath);
124
- } catch (err) {
125
- try {
126
- await unlink(tempPath);
127
- } catch {
128
- }
129
- throw err;
130
- }
131
- } else {
132
- await writeFile(filePath, data, { mode });
133
- }
134
- }
135
- async function writeMaybeEncryptedFileFromChunks(filePath, chunks, key, options = {}, memoryDir) {
136
- const { mode = 384, atomic = true } = options;
137
- await mkdir(path.dirname(filePath), { recursive: true });
138
- const writePath = atomic ? `${filePath}.tmp-${process.pid}-${Date.now()}` : filePath;
139
- let completed = false;
140
- try {
141
- const handle = await openFile(writePath, "w", mode);
142
- try {
143
- if (key !== null) {
144
- const salt = generateSalt();
145
- const iv = randomBytes(IV_LENGTH);
146
- const header = Buffer.alloc(MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
147
- MAGIC_BYTES.copy(header, 0);
148
- header.writeUInt8(FILE_FORMAT_VERSION, MAGIC_BYTES.length);
149
- header.writeUInt8(FILE_FORMAT_FLAGS, MAGIC_BYTES.length + 1);
150
- const envelopeOffset = MAGIC_HEADER_SIZE;
151
- header.writeUInt8(ENVELOPE_VERSION, envelopeOffset + ENVELOPE_LAYOUT.version);
152
- salt.copy(header, envelopeOffset + ENVELOPE_LAYOUT.salt);
153
- iv.copy(header, envelopeOffset + ENVELOPE_LAYOUT.iv);
154
- await handle.write(header);
155
- const cipher = createCipheriv("aes-256-gcm", key, iv, { authTagLength: AUTH_TAG_LENGTH });
156
- const aad = filePathAad(filePath, memoryDir);
157
- cipher.setAAD(Buffer.concat([buildHeaderAad(salt), aad]));
158
- for await (const chunk of chunks) {
159
- if (chunk.length === 0) continue;
160
- const encrypted = cipher.update(chunk);
161
- if (encrypted.length > 0) await handle.write(encrypted);
162
- }
163
- const final = cipher.final();
164
- if (final.length > 0) await handle.write(final);
165
- const authTag = cipher.getAuthTag();
166
- await handle.write(
167
- authTag,
168
- 0,
169
- authTag.length,
170
- MAGIC_HEADER_SIZE + ENVELOPE_LAYOUT.authTag
171
- );
172
- } else {
173
- for await (const chunk of chunks) {
174
- if (chunk.length > 0) await handle.write(chunk);
175
- }
176
- }
177
- } finally {
178
- await handle.close();
179
- }
180
- if (atomic) {
181
- await rename(writePath, filePath);
182
- }
183
- completed = true;
184
- } finally {
185
- if (!completed && atomic) {
186
- await unlink(writePath).catch(() => {
187
- });
188
- }
189
- }
190
- }
191
- async function migrateMemoryDirToEncrypted(dir, key, onBeforeEncrypt) {
192
- const result = { encrypted: 0, skipped: 0, errors: [] };
193
- const files = await collectEncryptableStorageFiles(dir);
194
- for (const filePath of files) {
195
- try {
196
- const buf = await fileReader(filePath);
197
- if (isEncryptedFile(buf)) {
198
- result.skipped++;
199
- continue;
200
- }
201
- if (onBeforeEncrypt) {
202
- try {
203
- await onBeforeEncrypt(filePath);
204
- } catch {
205
- }
206
- }
207
- const content = buf.toString("utf8");
208
- const aad = filePathAad(filePath, storageAadRootForFile(filePath, dir));
209
- const encrypted = encryptFileBody(content, key, aad);
210
- const tempPath = `${filePath}.enc-tmp-${process.pid}-${Date.now()}`;
211
- try {
212
- await writeFile(tempPath, encrypted, { mode: 384 });
213
- await rename(tempPath, filePath);
214
- result.encrypted++;
215
- } catch (writeErr) {
216
- try {
217
- const { unlink: unlink2 } = await import("fs/promises");
218
- await unlink2(tempPath);
219
- } catch {
220
- }
221
- throw writeErr;
222
- }
223
- } catch (err) {
224
- result.errors.push({
225
- filePath,
226
- error: err instanceof Error ? err.message : String(err)
227
- });
228
- }
229
- }
230
- return result;
231
- }
232
- async function decryptMemoryDirToPlaintext(dir, key) {
233
- const result = { decrypted: 0, skipped: 0, errors: [] };
234
- const files = await collectStorageManagedFiles(dir, isDecryptableStoragePath);
235
- for (const filePath of files) {
236
- try {
237
- const buf = await fileReader(filePath);
238
- if (!isEncryptedFile(buf)) {
239
- result.skipped++;
240
- continue;
241
- }
242
- const aad = filePathAad(filePath, storageAadRootForFile(filePath, dir));
243
- const plaintext = decryptFileBody(buf, key, aad);
244
- const tempPath = `${filePath}.dec-tmp-${process.pid}-${Date.now()}`;
245
- try {
246
- await writeFile(tempPath, plaintext, { mode: 384 });
247
- await rename(tempPath, filePath);
248
- result.decrypted++;
249
- } catch (writeErr) {
250
- try {
251
- await unlink(tempPath);
252
- } catch {
253
- }
254
- throw writeErr;
255
- }
256
- } catch (err) {
257
- result.errors.push({
258
- filePath,
259
- error: err instanceof Error ? err.message : String(err)
260
- });
261
- }
262
- }
263
- return result;
264
- }
265
- async function collectEncryptableStorageFiles(dir, rootDir = dir) {
266
- return collectStorageManagedFiles(dir, isEncryptableStoragePath, rootDir);
267
- }
268
- async function collectStorageManagedFiles(dir, includeFile, rootDir = dir) {
269
- const results = [];
270
- let names;
271
- try {
272
- names = await readdir(dir, { encoding: "utf8" });
273
- } catch {
274
- return results;
275
- }
276
- for (const name of names) {
277
- if (name.startsWith(".secure-store")) continue;
278
- const full = path.join(dir, name);
279
- let isDir = false;
280
- let isFile = false;
281
- try {
282
- const s = await lstat(full);
283
- if (s.isSymbolicLink()) continue;
284
- isDir = s.isDirectory();
285
- isFile = s.isFile();
286
- } catch {
287
- continue;
288
- }
289
- if (isDir) {
290
- const sub = await collectStorageManagedFiles(full, includeFile, rootDir);
291
- results.push(...sub);
292
- } else if (isFile && includeFile(full, rootDir)) {
293
- results.push(full);
294
- }
295
- }
296
- return results;
297
- }
298
- function isEncryptableStoragePath(filePath, rootDir) {
299
- const rel = path.relative(rootDir, filePath);
300
- if (rel === "" || rel.startsWith("..") || path.isAbsolute(rel)) return false;
301
- const normalized = normalizeStorageRelativePath(rel);
302
- if (normalized === "profile.md") return true;
303
- if (isEncryptableStateSidecar(normalized)) return true;
304
- if (isEncryptableSummarySidecar(normalized)) return true;
305
- const firstSegment = normalized.split("/", 1)[0];
306
- return ENCRYPTABLE_MARKDOWN_STORAGE_ROOTS.has(firstSegment) && normalized.endsWith(".md");
307
- }
308
- function isDecryptableStoragePath(filePath, rootDir) {
309
- if (isEncryptableStoragePath(filePath, rootDir)) return true;
310
- const rel = path.relative(rootDir, filePath);
311
- if (rel === "" || rel.startsWith("..") || path.isAbsolute(rel)) return false;
312
- const normalized = normalizeStorageRelativePath(rel);
313
- const firstSegment = normalized.split("/", 1)[0];
314
- return DECRYPTABLE_SIDECAR_ROOTS.has(firstSegment);
315
- }
316
- function normalizeStorageRelativePath(rel) {
317
- const normalized = rel.split(path.sep).join("/");
318
- const parts = normalized.split("/");
319
- if (parts[0] === "namespaces" && parts.length >= 3) {
320
- return parts.slice(2).join("/");
321
- }
322
- return normalized;
323
- }
324
- function storageAadRootForFile(filePath, rootDir) {
325
- const rel = path.relative(rootDir, filePath);
326
- if (rel === "" || rel.startsWith("..") || path.isAbsolute(rel)) return rootDir;
327
- const parts = rel.split(path.sep);
328
- if (parts[0] === "namespaces" && parts.length >= 3 && parts[1]) {
329
- return path.join(rootDir, "namespaces", parts[1]);
330
- }
331
- return rootDir;
332
- }
333
- var ENCRYPTABLE_MARKDOWN_STORAGE_ROOTS = /* @__PURE__ */ new Set([
334
- "facts",
335
- "corrections",
336
- "procedures",
337
- "reasoning-traces",
338
- "artifacts",
339
- "archive",
340
- "entities",
341
- "identity"
342
- ]);
343
- var ENCRYPTABLE_STATE_SIDECARS = /* @__PURE__ */ new Set([
344
- "state/behavior-signals.jsonl",
345
- "state/buffer-surprise-ledger.jsonl",
346
- "state/buffer.json",
347
- "state/compression-guideline-draft-state.json",
348
- "state/compression-guideline-state.json",
349
- "state/compression-guidelines.draft.md",
350
- "state/compression-guidelines.md",
351
- "state/entity-synthesis-queue.json",
352
- "state/fact-hashes.txt",
353
- "state/memory-actions.jsonl",
354
- "state/memory-lifecycle-ledger.jsonl",
355
- "state/meta.json",
356
- "state/reextract-jobs.jsonl",
357
- "state/topics.json"
358
- ]);
359
- function isEncryptableStateSidecar(normalized) {
360
- return ENCRYPTABLE_STATE_SIDECARS.has(normalized);
361
- }
362
- function isEncryptableSummarySidecar(normalized) {
363
- return normalized.startsWith("summaries/") && normalized.endsWith(".json");
364
- }
365
- var DECRYPTABLE_SIDECAR_ROOTS = /* @__PURE__ */ new Set([
366
- "state",
367
- "indexes",
368
- "index",
369
- "provenance"
370
- ]);
371
-
372
- export {
373
- SecureStoreLockedError,
374
- SecureStoreDecryptError,
375
- MAGIC_BYTES,
376
- FILE_FORMAT_VERSION,
377
- FILE_FORMAT_FLAGS,
378
- MAGIC_HEADER_SIZE,
379
- isEncryptedFile,
380
- encryptFileBody,
381
- decryptFileBody,
382
- filePathAad,
383
- readMaybeEncryptedFileBuffer,
384
- readMaybeEncryptedFile,
385
- writeMaybeEncryptedFile,
386
- writeMaybeEncryptedFileFromChunks,
387
- migrateMemoryDirToEncrypted,
388
- decryptMemoryDirToPlaintext
389
- };
@@ -1,78 +0,0 @@
1
- // ../remnic-core/src/tier-migration.ts
2
- import { appendFile, mkdir } from "fs/promises";
3
- import path from "path";
4
- var TierMigrationExecutor = class {
5
- storage;
6
- qmd;
7
- hotCollection;
8
- coldCollection;
9
- autoEmbed;
10
- journalPath;
11
- constructor(options) {
12
- this.storage = options.storage;
13
- this.qmd = options.qmd;
14
- this.hotCollection = options.hotCollection;
15
- this.coldCollection = options.coldCollection;
16
- this.autoEmbed = options.autoEmbed === true;
17
- this.journalPath = options.journalPath ?? path.join(this.storage.dir, "state", "tier-migration-journal.jsonl");
18
- }
19
- async migrateMemory(request) {
20
- const { memory, fromTier, toTier, reason } = request;
21
- const targetPath = this.storage.buildTierMemoryPath(memory, toTier);
22
- if (fromTier === toTier) {
23
- const noChange = {
24
- memoryId: memory.frontmatter.id,
25
- fromTier,
26
- toTier,
27
- changed: false,
28
- reason,
29
- targetPath
30
- };
31
- await this.appendJournal(noChange);
32
- return noChange;
33
- }
34
- const moved = await this.storage.migrateMemoryToTier(memory, toTier);
35
- const result = {
36
- memoryId: memory.frontmatter.id,
37
- fromTier,
38
- toTier,
39
- changed: moved.changed,
40
- reason,
41
- targetPath: moved.targetPath
42
- };
43
- await this.appendJournal(result);
44
- if (result.changed) {
45
- const destinationCollection = this.collectionForTier(toTier);
46
- const sourceCollection = this.collectionForTier(fromTier);
47
- await this.qmd.updateCollection(destinationCollection);
48
- if (this.autoEmbed) {
49
- await this.qmd.embedCollection(destinationCollection);
50
- if (sourceCollection !== destinationCollection) {
51
- await this.qmd.embedCollection(sourceCollection);
52
- }
53
- }
54
- }
55
- return result;
56
- }
57
- collectionForTier(tier) {
58
- return tier === "cold" ? this.coldCollection : this.hotCollection;
59
- }
60
- async appendJournal(result) {
61
- const entry = {
62
- ts: (/* @__PURE__ */ new Date()).toISOString(),
63
- memoryId: result.memoryId,
64
- fromTier: result.fromTier,
65
- toTier: result.toTier,
66
- changed: result.changed,
67
- reason: result.reason,
68
- targetPath: result.targetPath
69
- };
70
- await mkdir(path.dirname(this.journalPath), { recursive: true });
71
- await appendFile(this.journalPath, `${JSON.stringify(entry)}
72
- `, "utf-8");
73
- }
74
- };
75
-
76
- export {
77
- TierMigrationExecutor
78
- };