@remnic/cli 9.7.15 → 9.8.0
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/index.js +1004 -638
- package/package.json +28 -28
package/dist/index.js
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
|
+
// src/enrichment-persist.ts
|
|
2
|
+
import { composeSalvagedEnvelope } from "@remnic/core/salvage-envelope";
|
|
3
|
+
async function persistEnrichmentCandidate(storage, entityName, candidate) {
|
|
4
|
+
await storage.writeSealedMemory(
|
|
5
|
+
composeSalvagedEnvelope(
|
|
6
|
+
"enrichment",
|
|
7
|
+
{
|
|
8
|
+
content: candidate.text,
|
|
9
|
+
category: candidate.category,
|
|
10
|
+
confidence: candidate.confidence,
|
|
11
|
+
tags: [...candidate.tags ?? [], "enrichment", candidate.source],
|
|
12
|
+
entityRef: entityName
|
|
13
|
+
},
|
|
14
|
+
{ source: `enrichment:${candidate.source}` }
|
|
15
|
+
),
|
|
16
|
+
{}
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
1
20
|
// src/index.ts
|
|
2
|
-
import
|
|
21
|
+
import fs9 from "fs";
|
|
3
22
|
import os from "os";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
23
|
+
import path12 from "path";
|
|
24
|
+
import { createHash as createHash2 } from "crypto";
|
|
6
25
|
import * as childProcess2 from "child_process";
|
|
7
26
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8
27
|
import { gzipSync } from "zlib";
|
|
9
28
|
import {
|
|
10
|
-
parseConfig,
|
|
29
|
+
parseConfig as parseConfig2,
|
|
11
30
|
isOpenaiApiKeyDisabled,
|
|
12
31
|
resolveEnvVars,
|
|
13
|
-
resolveRemnicConfigRecord,
|
|
32
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord2,
|
|
14
33
|
Orchestrator,
|
|
15
34
|
EngramAccessService,
|
|
16
35
|
initLogger,
|
|
@@ -85,18 +104,19 @@ import {
|
|
|
85
104
|
discoverMemoryExtensions,
|
|
86
105
|
resolveExtensionsRoot,
|
|
87
106
|
coerceInstallExtension,
|
|
88
|
-
StorageManager,
|
|
107
|
+
StorageManager as StorageManager2,
|
|
89
108
|
computeProcedureStats,
|
|
90
109
|
formatProcedureStatsText,
|
|
91
110
|
parseXrayCliOptions,
|
|
92
111
|
renderXray,
|
|
93
112
|
OFFLINE_SYNC_APPLY_MAX_BODY_BYTES,
|
|
94
113
|
OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
|
|
95
|
-
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
|
|
114
|
+
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES as OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2,
|
|
96
115
|
OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES,
|
|
97
116
|
applyOfflineSyncFileContentChunk,
|
|
98
117
|
applyOfflineSyncSnapshot,
|
|
99
118
|
buildOfflineSyncChangesetFromSnapshot,
|
|
119
|
+
drainPendingLifecycleForOfflineSync,
|
|
100
120
|
compileOfflineSyncExcludeGlobs,
|
|
101
121
|
buildOfflineSyncSnapshotFromBase,
|
|
102
122
|
defaultOfflineSyncStatePath,
|
|
@@ -118,24 +138,6 @@ import {
|
|
|
118
138
|
OPERATION_NAMES,
|
|
119
139
|
validateCapabilitiesForMint
|
|
120
140
|
} from "@remnic/core";
|
|
121
|
-
import {
|
|
122
|
-
AUTH_TAG_LENGTH,
|
|
123
|
-
ENVELOPE_HEADER_SIZE,
|
|
124
|
-
ENVELOPE_LAYOUT,
|
|
125
|
-
ENVELOPE_SALT_LENGTH,
|
|
126
|
-
ENVELOPE_VERSION,
|
|
127
|
-
FILE_FORMAT_FLAGS,
|
|
128
|
-
FILE_FORMAT_VERSION,
|
|
129
|
-
IV_LENGTH,
|
|
130
|
-
MAGIC_BYTES,
|
|
131
|
-
MAGIC_HEADER_SIZE,
|
|
132
|
-
SecureStoreLockedError,
|
|
133
|
-
filePathAad,
|
|
134
|
-
isEncryptedFile,
|
|
135
|
-
keyring,
|
|
136
|
-
readHeader,
|
|
137
|
-
secureStoreDir
|
|
138
|
-
} from "@remnic/core/secure-store";
|
|
139
141
|
|
|
140
142
|
// src/optional-module-loader.ts
|
|
141
143
|
function isSpecifierNotFoundError(err, specifier) {
|
|
@@ -186,6 +188,386 @@ async function loadWecloneExportModule() {
|
|
|
186
188
|
return cached;
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
// src/doctor-namespace-lint.ts
|
|
192
|
+
import { isNamespacePolicyCovered } from "@remnic/core";
|
|
193
|
+
function readConfiguredNamespace(remnicCfg) {
|
|
194
|
+
if (!("namespace" in remnicCfg)) return { invalid: false };
|
|
195
|
+
const value = remnicCfg.namespace;
|
|
196
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
197
|
+
return { configuredNamespace: value.trim(), invalid: false };
|
|
198
|
+
}
|
|
199
|
+
return { invalid: true };
|
|
200
|
+
}
|
|
201
|
+
function buildNamespacePolicyCheck(args) {
|
|
202
|
+
if (args.invalid) {
|
|
203
|
+
return {
|
|
204
|
+
name: "Namespace policy",
|
|
205
|
+
ok: false,
|
|
206
|
+
detail: "config `namespace` is set but is not a non-empty string",
|
|
207
|
+
remediation: "Set `namespace` to a non-empty string (a namespacePolicies name or the default namespace), or remove it."
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (!args.config || !args.configuredNamespace) return void 0;
|
|
211
|
+
const covered = isNamespacePolicyCovered(args.configuredNamespace, args.config);
|
|
212
|
+
return {
|
|
213
|
+
name: "Namespace policy",
|
|
214
|
+
ok: covered,
|
|
215
|
+
warn: !covered,
|
|
216
|
+
detail: covered ? `configured namespace "${args.configuredNamespace}" is writable` : `configured namespace "${args.configuredNamespace}" is writable by no one \u2014 its namespacePolicies entry grants no writer, or it has no entry and is not the default namespace`,
|
|
217
|
+
remediation: covered ? void 0 : `Give "${args.configuredNamespace}" a namespacePolicies entry with a non-blank writePrincipals value, or set namespace to a writable one \u2014 otherwise every write is rejected and dead-lettered.`
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/index.ts
|
|
222
|
+
import { WriteQuarantineStore } from "@remnic/core/write-quarantine.js";
|
|
223
|
+
|
|
224
|
+
// src/quarantine-cli.ts
|
|
225
|
+
function renderQuarantineList(records, format) {
|
|
226
|
+
if (format === "json") {
|
|
227
|
+
const summary = records.map((record) => ({
|
|
228
|
+
timestamp: record.timestamp,
|
|
229
|
+
operation: record.operation,
|
|
230
|
+
principal: record.principal,
|
|
231
|
+
attemptedNamespace: record.attemptedNamespace
|
|
232
|
+
}));
|
|
233
|
+
return JSON.stringify(summary, null, 2);
|
|
234
|
+
}
|
|
235
|
+
if (format !== "text") {
|
|
236
|
+
throw new Error(`Unsupported quarantine format: ${String(format)}`);
|
|
237
|
+
}
|
|
238
|
+
if (records.length === 0) return "No quarantined writes.";
|
|
239
|
+
const lines = [`Quarantined writes (${records.length}):`, ""];
|
|
240
|
+
for (const record of records) {
|
|
241
|
+
lines.push(
|
|
242
|
+
` ${record.timestamp} ${record.operation} principal=${record.principal ?? "-"} attemptedNamespace=${record.attemptedNamespace}`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
return lines.join("\n");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/offline-impression-rotation.ts
|
|
249
|
+
import fs from "fs";
|
|
250
|
+
import { parseConfig, resolveRemnicConfigRecord, drainPendingImpressionsForOfflineSync } from "@remnic/core";
|
|
251
|
+
import { LastRecallStore } from "@remnic/core/recall-state";
|
|
252
|
+
function parseConfigQuietly(raw) {
|
|
253
|
+
const originalWarn = console.warn;
|
|
254
|
+
console.warn = () => {
|
|
255
|
+
};
|
|
256
|
+
try {
|
|
257
|
+
return parseConfig(resolveRemnicConfigRecord(raw));
|
|
258
|
+
} finally {
|
|
259
|
+
console.warn = originalWarn;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
var OFFLINE_CONFIG_KEYS = [
|
|
263
|
+
"offlineSyncExcludes",
|
|
264
|
+
"secureStoreEncryptOnWrite",
|
|
265
|
+
"recallImpressionsRotateBytes",
|
|
266
|
+
"recallImpressionsRotateKeep"
|
|
267
|
+
];
|
|
268
|
+
function pickOfflineConfigRecord(raw) {
|
|
269
|
+
let resolved;
|
|
270
|
+
try {
|
|
271
|
+
resolved = resolveRemnicConfigRecord(raw);
|
|
272
|
+
} catch {
|
|
273
|
+
resolved = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
274
|
+
}
|
|
275
|
+
const picked = {};
|
|
276
|
+
for (const key of OFFLINE_CONFIG_KEYS) {
|
|
277
|
+
if (key in resolved) picked[key] = resolved[key];
|
|
278
|
+
}
|
|
279
|
+
return picked;
|
|
280
|
+
}
|
|
281
|
+
function resolveOfflineImpressionRotation(configPath) {
|
|
282
|
+
let raw;
|
|
283
|
+
try {
|
|
284
|
+
raw = fs.existsSync(configPath) ? JSON.parse(fs.readFileSync(configPath, "utf8")) : {};
|
|
285
|
+
} catch {
|
|
286
|
+
throw new Error(
|
|
287
|
+
`cannot read recall-impression rotation from ${configPath}: config file could not be read as JSON`
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
let config;
|
|
291
|
+
try {
|
|
292
|
+
config = parseConfigQuietly(pickOfflineConfigRecord(raw));
|
|
293
|
+
} catch {
|
|
294
|
+
throw new Error(
|
|
295
|
+
`cannot read recall-impression rotation from ${configPath}: config failed validation`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
impressionsRotateBytes: config.recallImpressionsRotateBytes,
|
|
300
|
+
impressionsRotateKeep: config.recallImpressionsRotateKeep
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
async function drainOfflineSyncImpressions(memoryDir, rotation) {
|
|
304
|
+
await drainPendingImpressionsForOfflineSync(
|
|
305
|
+
() => new LastRecallStore(memoryDir, {
|
|
306
|
+
impressionsRotateBytes: rotation.impressionsRotateBytes,
|
|
307
|
+
impressionsRotateKeep: rotation.impressionsRotateKeep
|
|
308
|
+
}).drainPendingImpressions()
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// src/offline-storage-io.ts
|
|
313
|
+
import { mkdtemp, readdir, lstat, rm } from "fs/promises";
|
|
314
|
+
import fs2 from "fs";
|
|
315
|
+
import path from "path";
|
|
316
|
+
import { createHash, createDecipheriv } from "crypto";
|
|
317
|
+
import {
|
|
318
|
+
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
|
|
319
|
+
StorageManager
|
|
320
|
+
} from "@remnic/core";
|
|
321
|
+
import { OFFLINE_DECRYPT_STAGING_DIR_PREFIX } from "@remnic/core/offline-sync-exclude-globs";
|
|
322
|
+
import {
|
|
323
|
+
AUTH_TAG_LENGTH,
|
|
324
|
+
ENVELOPE_HEADER_SIZE,
|
|
325
|
+
ENVELOPE_LAYOUT,
|
|
326
|
+
ENVELOPE_SALT_LENGTH,
|
|
327
|
+
ENVELOPE_VERSION,
|
|
328
|
+
FILE_FORMAT_FLAGS,
|
|
329
|
+
FILE_FORMAT_VERSION,
|
|
330
|
+
IV_LENGTH,
|
|
331
|
+
MAGIC_BYTES,
|
|
332
|
+
MAGIC_HEADER_SIZE,
|
|
333
|
+
SecureStoreLockedError,
|
|
334
|
+
filePathAad,
|
|
335
|
+
isEncryptedFile,
|
|
336
|
+
keyring,
|
|
337
|
+
readHeader,
|
|
338
|
+
secureStoreDir
|
|
339
|
+
} from "@remnic/core/secure-store";
|
|
340
|
+
async function createConfiguredOfflineStorage(memoryDir, secureStoreEncryptOnWrite = true) {
|
|
341
|
+
const storage = new StorageManager(memoryDir);
|
|
342
|
+
const header = await readHeader(memoryDir);
|
|
343
|
+
let secureStoreKey = null;
|
|
344
|
+
let secureStoreRequired = false;
|
|
345
|
+
if (header) {
|
|
346
|
+
secureStoreRequired = true;
|
|
347
|
+
storage.setSecureStoreRequired(true);
|
|
348
|
+
const key = keyring.getKey(secureStoreDir(memoryDir));
|
|
349
|
+
if (key) {
|
|
350
|
+
storage.setSecureStoreKey(key, secureStoreEncryptOnWrite);
|
|
351
|
+
secureStoreKey = key;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return { storage, secureStoreKey, secureStoreRequired };
|
|
355
|
+
}
|
|
356
|
+
function createOfflineStorageForPath(memoryDir, filePath, configured, secureStoreEncryptOnWrite) {
|
|
357
|
+
const memoryRoot = path.resolve(memoryDir);
|
|
358
|
+
const stateDir = path.dirname(filePath);
|
|
359
|
+
if (path.basename(stateDir) !== "state" || path.basename(filePath) !== "memory-lifecycle-ledger.jsonl") {
|
|
360
|
+
throw new Error(`invalid lifecycle ledger path: ${filePath}`);
|
|
361
|
+
}
|
|
362
|
+
const storageRoot = path.resolve(path.dirname(stateDir));
|
|
363
|
+
if (storageRoot !== memoryRoot && !storageRoot.startsWith(`${memoryRoot}${path.sep}`)) {
|
|
364
|
+
throw new Error(`lifecycle ledger path is outside the offline memory directory: ${filePath}`);
|
|
365
|
+
}
|
|
366
|
+
const storage = new StorageManager(storageRoot);
|
|
367
|
+
if (configured.secureStoreRequired) {
|
|
368
|
+
storage.setSecureStoreRequired(true);
|
|
369
|
+
}
|
|
370
|
+
if (configured.secureStoreKey) {
|
|
371
|
+
storage.setSecureStoreKey(configured.secureStoreKey, secureStoreEncryptOnWrite);
|
|
372
|
+
}
|
|
373
|
+
return storage;
|
|
374
|
+
}
|
|
375
|
+
async function createOfflineStorageIo(memoryDir, configuredStorage) {
|
|
376
|
+
await cleanupOrphanedOfflineDecryptStaging(memoryDir);
|
|
377
|
+
const { storage, secureStoreKey } = configuredStorage ?? await createConfiguredOfflineStorage(memoryDir);
|
|
378
|
+
return {
|
|
379
|
+
readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
|
|
380
|
+
readFileDigest: async ({ filePath }) => {
|
|
381
|
+
const hash = createHash("sha256");
|
|
382
|
+
let bytes = 0;
|
|
383
|
+
for await (const rawChunk of readOfflineSyncFileChunks({
|
|
384
|
+
filePath,
|
|
385
|
+
memoryDir,
|
|
386
|
+
secureStoreKey,
|
|
387
|
+
chunkSize: OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES
|
|
388
|
+
})) {
|
|
389
|
+
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
390
|
+
hash.update(chunk);
|
|
391
|
+
bytes += chunk.length;
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
sha256: hash.digest("hex"),
|
|
395
|
+
bytes
|
|
396
|
+
};
|
|
397
|
+
},
|
|
398
|
+
readFileChunks: ({ filePath, chunkSize }) => readOfflineSyncFileChunks({
|
|
399
|
+
filePath,
|
|
400
|
+
memoryDir,
|
|
401
|
+
secureStoreKey,
|
|
402
|
+
chunkSize
|
|
403
|
+
}),
|
|
404
|
+
writeFile: async ({ filePath, content }) => storage.writeOfflineSyncFile(filePath, content),
|
|
405
|
+
writeStagingFile: async ({ filePath, content }) => storage.writeOfflineSyncStagingFile(filePath, content),
|
|
406
|
+
writeFileChunks: async ({ filePath, chunks }) => storage.writeOfflineSyncFileChunks(filePath, chunks),
|
|
407
|
+
deleteFile: async ({ filePath }) => storage.deleteOfflineSyncFile(filePath)
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
var OFFLINE_DECRYPT_STAGING_ORPHAN_MS = 60 * 60 * 1e3;
|
|
411
|
+
async function cleanupOrphanedOfflineDecryptStaging(memoryDir) {
|
|
412
|
+
let entries;
|
|
413
|
+
try {
|
|
414
|
+
entries = await readdir(memoryDir);
|
|
415
|
+
} catch {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const now = Date.now();
|
|
419
|
+
for (const name of entries) {
|
|
420
|
+
if (!name.startsWith(OFFLINE_DECRYPT_STAGING_DIR_PREFIX)) continue;
|
|
421
|
+
const dir = path.join(memoryDir, name);
|
|
422
|
+
try {
|
|
423
|
+
const info = await lstat(dir);
|
|
424
|
+
if (!info.isDirectory() || info.isSymbolicLink()) continue;
|
|
425
|
+
if (now - info.mtimeMs < OFFLINE_DECRYPT_STAGING_ORPHAN_MS) continue;
|
|
426
|
+
await rm(dir, { recursive: true, force: true });
|
|
427
|
+
} catch {
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
async function* readOfflineSyncFileChunks(options) {
|
|
432
|
+
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE);
|
|
433
|
+
if (!isEncryptedFile(header)) {
|
|
434
|
+
yield* readPlainOfflineFileChunks(options.filePath, options.chunkSize);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (!options.secureStoreKey) {
|
|
438
|
+
throw new SecureStoreLockedError(
|
|
439
|
+
`secure-store is locked \u2014 cannot read encrypted file at ${options.filePath}. Run \`remnic secure-store unlock\` to decrypt.`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
yield* readEncryptedOfflineFileChunks({
|
|
443
|
+
filePath: options.filePath,
|
|
444
|
+
memoryDir: options.memoryDir,
|
|
445
|
+
key: options.secureStoreKey,
|
|
446
|
+
chunkSize: options.chunkSize
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
async function readFilePrefix(filePath, length) {
|
|
450
|
+
const handle = await fs2.promises.open(filePath, "r");
|
|
451
|
+
try {
|
|
452
|
+
const out = Buffer.alloc(length);
|
|
453
|
+
const { bytesRead } = await handle.read(out, 0, length, 0);
|
|
454
|
+
return out.subarray(0, bytesRead);
|
|
455
|
+
} finally {
|
|
456
|
+
await handle.close();
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async function* readPlainOfflineFileChunks(filePath, chunkSize) {
|
|
460
|
+
const stream = fs2.createReadStream(filePath, { highWaterMark: chunkSize });
|
|
461
|
+
for await (const chunk of stream) {
|
|
462
|
+
yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
async function* readEncryptedOfflineFileChunks(options) {
|
|
466
|
+
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
|
|
467
|
+
if (header.length < MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE || !isEncryptedFile(header)) {
|
|
468
|
+
throw new Error(`secure-store encrypted file is truncated: ${options.filePath}`);
|
|
469
|
+
}
|
|
470
|
+
const version = header.readUInt8(MAGIC_BYTES.length);
|
|
471
|
+
const flags = header.readUInt8(MAGIC_BYTES.length + 1);
|
|
472
|
+
if (version !== FILE_FORMAT_VERSION) {
|
|
473
|
+
throw new Error(`secure-store file has unsupported version ${version}: ${options.filePath}`);
|
|
474
|
+
}
|
|
475
|
+
if (flags !== FILE_FORMAT_FLAGS) {
|
|
476
|
+
throw new Error(`secure-store file has unsupported flags 0x${flags.toString(16)}: ${options.filePath}`);
|
|
477
|
+
}
|
|
478
|
+
const envelopeHeader = header.subarray(MAGIC_HEADER_SIZE);
|
|
479
|
+
const envelopeVersion = envelopeHeader.readUInt8(ENVELOPE_LAYOUT.version);
|
|
480
|
+
if (envelopeVersion !== ENVELOPE_VERSION) {
|
|
481
|
+
throw new Error(`secure-store envelope has unsupported version ${envelopeVersion}: ${options.filePath}`);
|
|
482
|
+
}
|
|
483
|
+
const salt = envelopeHeader.subarray(
|
|
484
|
+
ENVELOPE_LAYOUT.salt,
|
|
485
|
+
ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH
|
|
486
|
+
);
|
|
487
|
+
const iv = envelopeHeader.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);
|
|
488
|
+
const authTag = envelopeHeader.subarray(
|
|
489
|
+
ENVELOPE_LAYOUT.authTag,
|
|
490
|
+
ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
|
|
491
|
+
);
|
|
492
|
+
const aadCandidates = offlineFileAadCandidates(options.filePath, options.memoryDir);
|
|
493
|
+
let lastError;
|
|
494
|
+
for (const aad of aadCandidates) {
|
|
495
|
+
const tempDir = await mkdtemp(path.join(options.memoryDir, OFFLINE_DECRYPT_STAGING_DIR_PREFIX));
|
|
496
|
+
const tempPath = path.join(tempDir, "content");
|
|
497
|
+
try {
|
|
498
|
+
const decipher = createDecipheriv("aes-256-gcm", options.key, iv, {
|
|
499
|
+
authTagLength: AUTH_TAG_LENGTH
|
|
500
|
+
});
|
|
501
|
+
decipher.setAuthTag(authTag);
|
|
502
|
+
decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), aad]));
|
|
503
|
+
const output = fs2.createWriteStream(tempPath, { mode: 384 });
|
|
504
|
+
try {
|
|
505
|
+
const stream = fs2.createReadStream(options.filePath, {
|
|
506
|
+
start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
|
|
507
|
+
highWaterMark: options.chunkSize
|
|
508
|
+
});
|
|
509
|
+
for await (const encryptedChunk of stream) {
|
|
510
|
+
const plain = decipher.update(
|
|
511
|
+
Buffer.isBuffer(encryptedChunk) ? encryptedChunk : Buffer.from(encryptedChunk)
|
|
512
|
+
);
|
|
513
|
+
if (plain.length > 0 && !output.write(plain)) {
|
|
514
|
+
await new Promise((resolve, reject) => {
|
|
515
|
+
output.once("drain", resolve);
|
|
516
|
+
output.once("error", reject);
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
const finalPlain = decipher.final();
|
|
521
|
+
if (finalPlain.length > 0 && !output.write(finalPlain)) {
|
|
522
|
+
await new Promise((resolve, reject) => {
|
|
523
|
+
output.once("drain", resolve);
|
|
524
|
+
output.once("error", reject);
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
} finally {
|
|
528
|
+
await closeWriteStream(output);
|
|
529
|
+
}
|
|
530
|
+
yield* readPlainOfflineFileChunks(tempPath, options.chunkSize);
|
|
531
|
+
return;
|
|
532
|
+
} catch (error) {
|
|
533
|
+
lastError = error;
|
|
534
|
+
} finally {
|
|
535
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
throw lastError instanceof Error ? lastError : new Error(`secure-store could not decrypt file: ${options.filePath}`);
|
|
539
|
+
}
|
|
540
|
+
function offlineFileAadCandidates(filePath, memoryDir) {
|
|
541
|
+
const candidates = [filePathAad(filePath, memoryDir)];
|
|
542
|
+
const relative = path.relative(memoryDir, filePath);
|
|
543
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return candidates;
|
|
544
|
+
const parts = relative.split(path.sep);
|
|
545
|
+
if (parts[0] === "namespaces" && parts.length >= 3 && parts[1]) {
|
|
546
|
+
candidates.push(filePathAad(filePath, path.join(memoryDir, "namespaces", parts[1])));
|
|
547
|
+
}
|
|
548
|
+
const memoryParts = path.resolve(memoryDir).split(path.sep);
|
|
549
|
+
if (memoryParts.length >= 3 && memoryParts.at(-2) === "namespaces" && memoryParts.at(-1)) {
|
|
550
|
+
const topLevelRoot = memoryParts.slice(0, -2).join(path.sep) || path.sep;
|
|
551
|
+
const topRelative = path.relative(topLevelRoot, filePath);
|
|
552
|
+
if (topRelative && !topRelative.startsWith("..") && !path.isAbsolute(topRelative) && topRelative.split(path.sep)[0] === "namespaces" && topRelative.split(path.sep)[1] === memoryParts.at(-1)) {
|
|
553
|
+
candidates.push(filePathAad(filePath, topLevelRoot));
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return candidates;
|
|
557
|
+
}
|
|
558
|
+
async function closeWriteStream(stream) {
|
|
559
|
+
await new Promise((resolve, reject) => {
|
|
560
|
+
stream.once("error", reject);
|
|
561
|
+
stream.end(() => resolve());
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
function secureStoreEnvelopeHeaderAad(salt) {
|
|
565
|
+
const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
|
|
566
|
+
out.writeUInt8(ENVELOPE_VERSION, 0);
|
|
567
|
+
Buffer.from(salt).copy(out, 1);
|
|
568
|
+
return out;
|
|
569
|
+
}
|
|
570
|
+
|
|
189
571
|
// src/bench-build-freshness.ts
|
|
190
572
|
import {
|
|
191
573
|
existsSync,
|
|
@@ -194,15 +576,15 @@ import {
|
|
|
194
576
|
readFileSync,
|
|
195
577
|
statSync
|
|
196
578
|
} from "fs";
|
|
197
|
-
import
|
|
579
|
+
import path2 from "path";
|
|
198
580
|
import { fileURLToPath } from "url";
|
|
199
581
|
var STALE_BUILD_TOLERANCE_MS = 1e3;
|
|
200
582
|
function assertLocalBenchBuildFreshForDevelopment(currentModuleUrl) {
|
|
201
583
|
if (isTruthyEnv(process.env.REMNIC_BENCH_ALLOW_STALE_DIST)) {
|
|
202
584
|
return;
|
|
203
585
|
}
|
|
204
|
-
const currentDir =
|
|
205
|
-
const benchPackageDir =
|
|
586
|
+
const currentDir = path2.dirname(fileURLToPath(currentModuleUrl));
|
|
587
|
+
const benchPackageDir = path2.resolve(currentDir, "../../bench");
|
|
206
588
|
const freshness = checkBenchBuildFreshness(benchPackageDir);
|
|
207
589
|
if (!freshness.stale) {
|
|
208
590
|
return;
|
|
@@ -219,7 +601,7 @@ function assertLocalBenchBuildFreshForDevelopment(currentModuleUrl) {
|
|
|
219
601
|
);
|
|
220
602
|
}
|
|
221
603
|
function checkBenchBuildFreshness(benchPackageDir) {
|
|
222
|
-
const packageJsonPath =
|
|
604
|
+
const packageJsonPath = path2.join(benchPackageDir, "package.json");
|
|
223
605
|
if (!existsSync(packageJsonPath)) {
|
|
224
606
|
return { stale: false };
|
|
225
607
|
}
|
|
@@ -232,17 +614,17 @@ function checkBenchBuildFreshness(benchPackageDir) {
|
|
|
232
614
|
if (packageName !== "@remnic/bench") {
|
|
233
615
|
return { stale: false };
|
|
234
616
|
}
|
|
235
|
-
const srcDir =
|
|
617
|
+
const srcDir = path2.join(benchPackageDir, "src");
|
|
236
618
|
if (!isDirectory(srcDir)) {
|
|
237
619
|
return { stale: false };
|
|
238
620
|
}
|
|
239
621
|
const sourceRoots = [
|
|
240
622
|
srcDir,
|
|
241
623
|
packageJsonPath,
|
|
242
|
-
|
|
243
|
-
|
|
624
|
+
path2.join(benchPackageDir, "tsup.config.ts"),
|
|
625
|
+
path2.join(benchPackageDir, "tsconfig.json")
|
|
244
626
|
];
|
|
245
|
-
const distPath =
|
|
627
|
+
const distPath = path2.join(benchPackageDir, "dist", "index.js");
|
|
246
628
|
if (!existsSync(distPath)) {
|
|
247
629
|
return {
|
|
248
630
|
stale: true,
|
|
@@ -285,7 +667,7 @@ function newestMtime(roots) {
|
|
|
285
667
|
}
|
|
286
668
|
if (stat.isDirectory()) {
|
|
287
669
|
for (const child of readdirSync(entryPath)) {
|
|
288
|
-
visit(
|
|
670
|
+
visit(path2.join(entryPath, child));
|
|
289
671
|
}
|
|
290
672
|
return;
|
|
291
673
|
}
|
|
@@ -318,18 +700,18 @@ function isTruthyEnv(value) {
|
|
|
318
700
|
|
|
319
701
|
// src/optional-bench.ts
|
|
320
702
|
import { existsSync as existsSync2 } from "fs";
|
|
321
|
-
import
|
|
703
|
+
import path3 from "path";
|
|
322
704
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
323
705
|
var SPECIFIER2 = "@remnic/bench";
|
|
324
706
|
var TSX_ESM_API_SPECIFIER = "tsx/esm/api";
|
|
325
707
|
var cached2;
|
|
326
708
|
var cachedFromLocalWorkspaceBenchSource = false;
|
|
327
709
|
function resolveLocalWorkspaceBenchPaths() {
|
|
328
|
-
const currentDir =
|
|
329
|
-
const benchPackageDir =
|
|
710
|
+
const currentDir = path3.dirname(fileURLToPath2(import.meta.url));
|
|
711
|
+
const benchPackageDir = path3.resolve(currentDir, "../../bench");
|
|
330
712
|
return {
|
|
331
|
-
distEntry:
|
|
332
|
-
sourceEntry:
|
|
713
|
+
distEntry: path3.join(benchPackageDir, "dist", "index.js"),
|
|
714
|
+
sourceEntry: path3.join(benchPackageDir, "src", "index.ts")
|
|
333
715
|
};
|
|
334
716
|
}
|
|
335
717
|
async function tryImportLocalWorkspaceBenchSource(err) {
|
|
@@ -416,8 +798,8 @@ function assertBenchModuleFreshForDevelopment() {
|
|
|
416
798
|
}
|
|
417
799
|
|
|
418
800
|
// src/daemon-service-candidates.ts
|
|
419
|
-
import
|
|
420
|
-
import
|
|
801
|
+
import fs3 from "fs";
|
|
802
|
+
import path4 from "path";
|
|
421
803
|
var LAUNCHD_LABEL = "ai.remnic.daemon";
|
|
422
804
|
var LEGACY_REMNIC_SERVER_LAUNCHD_LABEL = "ai.remnic.server";
|
|
423
805
|
var LEGACY_LAUNCHD_LABEL = "ai.engram.daemon";
|
|
@@ -430,15 +812,15 @@ var SYSTEMD_SERVICE = "remnic.service";
|
|
|
430
812
|
var LEGACY_SYSTEMD_SERVICE = "engram.service";
|
|
431
813
|
var SYSTEMD_SERVICE_CANDIDATES = [SYSTEMD_SERVICE, LEGACY_SYSTEMD_SERVICE];
|
|
432
814
|
function launchdPlistPaths(homeDir) {
|
|
433
|
-
return LAUNCHD_LABEL_CANDIDATES.map((label) =>
|
|
815
|
+
return LAUNCHD_LABEL_CANDIDATES.map((label) => path4.join(homeDir, "Library", "LaunchAgents", `${label}.plist`));
|
|
434
816
|
}
|
|
435
817
|
function systemdUnitPaths(homeDir) {
|
|
436
|
-
return SYSTEMD_SERVICE_CANDIDATES.map((service) =>
|
|
818
|
+
return SYSTEMD_SERVICE_CANDIDATES.map((service) => path4.join(homeDir, ".config", "systemd", "user", service));
|
|
437
819
|
}
|
|
438
820
|
function anyFileExists(paths) {
|
|
439
821
|
return paths.some((candidate) => {
|
|
440
822
|
try {
|
|
441
|
-
return
|
|
823
|
+
return fs3.statSync(candidate).isFile();
|
|
442
824
|
} catch {
|
|
443
825
|
return false;
|
|
444
826
|
}
|
|
@@ -450,7 +832,7 @@ function commandNames(command) {
|
|
|
450
832
|
}
|
|
451
833
|
function isRunnableNodeScript(filePath) {
|
|
452
834
|
try {
|
|
453
|
-
const text =
|
|
835
|
+
const text = fs3.readFileSync(filePath, "utf8").slice(0, 4096);
|
|
454
836
|
const firstLine = text.split(/\r?\n/, 1)[0] ?? "";
|
|
455
837
|
if (/^#!.*\bnode\b/.test(firstLine)) return true;
|
|
456
838
|
if (firstLine.startsWith("#!")) return false;
|
|
@@ -463,20 +845,20 @@ function isRunnableNodeScript(filePath) {
|
|
|
463
845
|
function resolveShimNodeScript(filePath) {
|
|
464
846
|
let text;
|
|
465
847
|
try {
|
|
466
|
-
text =
|
|
848
|
+
text = fs3.readFileSync(filePath, "utf8").slice(0, 16384);
|
|
467
849
|
} catch {
|
|
468
850
|
return void 0;
|
|
469
851
|
}
|
|
470
|
-
const basedir =
|
|
852
|
+
const basedir = path4.dirname(filePath);
|
|
471
853
|
const jsReferencePattern = /"([^"]+\.js)"|'([^']+\.js)'|([^\s"'`]+\.js)/g;
|
|
472
854
|
for (const match of text.matchAll(jsReferencePattern)) {
|
|
473
855
|
const raw = match[1] ?? match[2] ?? match[3];
|
|
474
856
|
if (!raw) continue;
|
|
475
857
|
const candidate = raw.replaceAll("${basedir}", basedir).replaceAll("$basedir", basedir).replaceAll("\\ ", " ");
|
|
476
|
-
const resolved =
|
|
858
|
+
const resolved = path4.isAbsolute(candidate) ? candidate : path4.resolve(basedir, candidate);
|
|
477
859
|
try {
|
|
478
|
-
if (
|
|
479
|
-
return
|
|
860
|
+
if (fs3.statSync(resolved).isFile() && isRunnableNodeScript(resolved)) {
|
|
861
|
+
return fs3.realpathSync(resolved);
|
|
480
862
|
}
|
|
481
863
|
} catch {
|
|
482
864
|
}
|
|
@@ -484,19 +866,19 @@ function resolveShimNodeScript(filePath) {
|
|
|
484
866
|
return void 0;
|
|
485
867
|
}
|
|
486
868
|
function resolveRunnableNodeScript(filePath) {
|
|
487
|
-
const realPath =
|
|
869
|
+
const realPath = fs3.realpathSync(filePath);
|
|
488
870
|
if (isRunnableNodeScript(realPath)) return realPath;
|
|
489
871
|
return resolveShimNodeScript(realPath);
|
|
490
872
|
}
|
|
491
873
|
function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
|
|
492
|
-
for (const dir of pathEnv.split(
|
|
874
|
+
for (const dir of pathEnv.split(path4.delimiter)) {
|
|
493
875
|
if (!dir) continue;
|
|
494
876
|
for (const name of commandNames(command)) {
|
|
495
|
-
const candidate =
|
|
877
|
+
const candidate = path4.join(dir, name);
|
|
496
878
|
try {
|
|
497
|
-
const stat =
|
|
879
|
+
const stat = fs3.statSync(candidate);
|
|
498
880
|
if (!stat.isFile()) continue;
|
|
499
|
-
if (process.platform !== "win32")
|
|
881
|
+
if (process.platform !== "win32") fs3.accessSync(candidate, fs3.constants.X_OK);
|
|
500
882
|
const runnable = resolveRunnableNodeScript(candidate);
|
|
501
883
|
if (runnable) return runnable;
|
|
502
884
|
} catch {
|
|
@@ -506,11 +888,11 @@ function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
|
|
|
506
888
|
return void 0;
|
|
507
889
|
}
|
|
508
890
|
function serverBinWrapperRequiredPath(candidate) {
|
|
509
|
-
const filename =
|
|
891
|
+
const filename = path4.basename(candidate);
|
|
510
892
|
if (filename !== "remnic-server.js" && filename !== "engram-server.js") return void 0;
|
|
511
|
-
const binDir =
|
|
512
|
-
if (
|
|
513
|
-
return
|
|
893
|
+
const binDir = path4.dirname(candidate);
|
|
894
|
+
if (path4.basename(binDir) !== "bin") return void 0;
|
|
895
|
+
return path4.join(path4.dirname(binDir), "dist", "index.js");
|
|
514
896
|
}
|
|
515
897
|
|
|
516
898
|
// src/service-candidates.ts
|
|
@@ -532,7 +914,7 @@ function firstSuccessfulCandidate(candidates, attempt) {
|
|
|
532
914
|
}
|
|
533
915
|
|
|
534
916
|
// src/bench-args.ts
|
|
535
|
-
import
|
|
917
|
+
import path5 from "path";
|
|
536
918
|
|
|
537
919
|
// src/path-utils.ts
|
|
538
920
|
function resolveHomeDir() {
|
|
@@ -1632,13 +2014,13 @@ function parseBenchArgs(argv) {
|
|
|
1632
2014
|
mcpUrl,
|
|
1633
2015
|
mcpToolMap,
|
|
1634
2016
|
mcpDemo,
|
|
1635
|
-
datasetDir: datasetDir ?
|
|
1636
|
-
resultsDir: resultsDir ?
|
|
1637
|
-
baselinesDir: baselinesDir ?
|
|
2017
|
+
datasetDir: datasetDir ? path5.resolve(expandTilde(datasetDir)) : void 0,
|
|
2018
|
+
resultsDir: resultsDir ? path5.resolve(expandTilde(resultsDir)) : void 0,
|
|
2019
|
+
baselinesDir: baselinesDir ? path5.resolve(expandTilde(baselinesDir)) : void 0,
|
|
1638
2020
|
runtimeProfile,
|
|
1639
2021
|
matrixProfiles,
|
|
1640
|
-
remnicConfigPath: remnicConfigRaw ?
|
|
1641
|
-
openclawConfigPath: openclawConfigRaw ?
|
|
2022
|
+
remnicConfigPath: remnicConfigRaw ? path5.resolve(expandTilde(remnicConfigRaw)) : void 0,
|
|
2023
|
+
openclawConfigPath: openclawConfigRaw ? path5.resolve(expandTilde(openclawConfigRaw)) : void 0,
|
|
1642
2024
|
modelSource,
|
|
1643
2025
|
gatewayAgentId,
|
|
1644
2026
|
fastGatewayAgentId,
|
|
@@ -1661,13 +2043,13 @@ function parseBenchArgs(argv) {
|
|
|
1661
2043
|
internalDisableThinking: args.includes("--internal-disable-thinking"),
|
|
1662
2044
|
internalCodexReasoningEffort,
|
|
1663
2045
|
threshold,
|
|
1664
|
-
custom: customRaw ?
|
|
2046
|
+
custom: customRaw ? path5.resolve(expandTilde(customRaw)) : void 0,
|
|
1665
2047
|
baselineAction,
|
|
1666
2048
|
datasetAction,
|
|
1667
2049
|
providerAction,
|
|
1668
2050
|
runAction,
|
|
1669
2051
|
format,
|
|
1670
|
-
output: output ?
|
|
2052
|
+
output: output ? path5.resolve(expandTilde(output)) : void 0,
|
|
1671
2053
|
target,
|
|
1672
2054
|
publishedName,
|
|
1673
2055
|
publishedSeed,
|
|
@@ -1677,24 +2059,24 @@ function parseBenchArgs(argv) {
|
|
|
1677
2059
|
publishedIngestConcurrency,
|
|
1678
2060
|
publishedTaskFilter,
|
|
1679
2061
|
memcorrectAdapter,
|
|
1680
|
-
publishedOut: publishedOutRaw ?
|
|
2062
|
+
publishedOut: publishedOutRaw ? path5.resolve(expandTilde(publishedOutRaw)) : void 0,
|
|
1681
2063
|
publishedDryRun: args.includes("--dry-run"),
|
|
1682
2064
|
requestTimeout,
|
|
1683
2065
|
localJudgeRequestTimeout,
|
|
1684
2066
|
frontierJudgeRequestTimeout,
|
|
1685
|
-
calibrationDir: calibrationDirRaw ?
|
|
2067
|
+
calibrationDir: calibrationDirRaw ? path5.resolve(expandTilde(calibrationDirRaw)) : void 0,
|
|
1686
2068
|
calibrationLocalConfigSha256,
|
|
1687
2069
|
calibrationFrontierConfigSha256,
|
|
1688
2070
|
sourceResultId,
|
|
1689
2071
|
expectedAnswerSetSha256,
|
|
1690
2072
|
expectedQuestionIdListSha256,
|
|
1691
|
-
taskIdsFile: taskIdsFileRaw ?
|
|
2073
|
+
taskIdsFile: taskIdsFileRaw ? path5.resolve(expandTilde(taskIdsFileRaw)) : void 0,
|
|
1692
2074
|
expectedTaskIdListSha256,
|
|
1693
2075
|
drainTimeout,
|
|
1694
2076
|
// Issue #1573 PR1: surface judge-cache flags into the runner options.
|
|
1695
2077
|
noJudgeCache: args.includes("--no-judge-cache"),
|
|
1696
|
-
judgeCacheDir: judgeCacheDirRaw ?
|
|
1697
|
-
localLabManifestPath: localLabManifestRaw ?
|
|
2078
|
+
judgeCacheDir: judgeCacheDirRaw ? path5.resolve(expandTilde(judgeCacheDirRaw)) : void 0,
|
|
2079
|
+
localLabManifestPath: localLabManifestRaw ? path5.resolve(expandTilde(localLabManifestRaw)) : void 0,
|
|
1698
2080
|
max429WaitMs,
|
|
1699
2081
|
disableThinking: args.includes("--disable-thinking"),
|
|
1700
2082
|
amaBenchJudgeProtocol,
|
|
@@ -1709,23 +2091,23 @@ function parseBenchArgs(argv) {
|
|
|
1709
2091
|
}
|
|
1710
2092
|
|
|
1711
2093
|
// src/bench-status.ts
|
|
1712
|
-
import { mkdir, readFile, readdir, rename, writeFile } from "fs/promises";
|
|
1713
|
-
import
|
|
2094
|
+
import { mkdir, readFile, readdir as readdir2, rename, writeFile } from "fs/promises";
|
|
2095
|
+
import path6 from "path";
|
|
1714
2096
|
function createBenchStatusPath(resultsDir, pid, startedAtMs = Date.now()) {
|
|
1715
|
-
return
|
|
2097
|
+
return path6.join(resultsDir, `bench-status-${startedAtMs}-${pid}.json`);
|
|
1716
2098
|
}
|
|
1717
2099
|
var BENCH_STATUS_FILENAME = /^bench-status-\d+-\d+\.json$/;
|
|
1718
2100
|
var VALID_BENCH_ENTRY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "complete", "failed"]);
|
|
1719
2101
|
async function findLatestBenchStatusFile(resultsDir) {
|
|
1720
2102
|
let entries;
|
|
1721
2103
|
try {
|
|
1722
|
-
entries = await
|
|
2104
|
+
entries = await readdir2(resultsDir);
|
|
1723
2105
|
} catch {
|
|
1724
2106
|
return null;
|
|
1725
2107
|
}
|
|
1726
2108
|
const candidates = entries.filter((name) => BENCH_STATUS_FILENAME.test(name)).sort().reverse();
|
|
1727
2109
|
for (const name of candidates) {
|
|
1728
|
-
const filePath =
|
|
2110
|
+
const filePath = path6.join(resultsDir, name);
|
|
1729
2111
|
const status = await readBenchStatus(filePath);
|
|
1730
2112
|
if (status) {
|
|
1731
2113
|
return filePath;
|
|
@@ -1734,7 +2116,7 @@ async function findLatestBenchStatusFile(resultsDir) {
|
|
|
1734
2116
|
return null;
|
|
1735
2117
|
}
|
|
1736
2118
|
async function atomicWriteJSON(filePath, data) {
|
|
1737
|
-
await mkdir(
|
|
2119
|
+
await mkdir(path6.dirname(filePath), { recursive: true });
|
|
1738
2120
|
const tmp = `${filePath}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;
|
|
1739
2121
|
await writeFile(tmp, JSON.stringify(data, null, 2) + "\n");
|
|
1740
2122
|
await rename(tmp, filePath);
|
|
@@ -1851,8 +2233,8 @@ function finalizeBenchStatus(filePath) {
|
|
|
1851
2233
|
}
|
|
1852
2234
|
|
|
1853
2235
|
// src/bench-fallback.ts
|
|
1854
|
-
import
|
|
1855
|
-
import
|
|
2236
|
+
import fs4 from "fs";
|
|
2237
|
+
import path7 from "path";
|
|
1856
2238
|
var FALLBACK_RESULTS_DIRNAME = "fallback-runs";
|
|
1857
2239
|
function buildBenchRunnerArgs(parsed, benchmarkId, outputDir) {
|
|
1858
2240
|
const args = ["--benchmark", benchmarkId];
|
|
@@ -1916,34 +2298,34 @@ function findUnsupportedFallbackBenchOptions(parsed) {
|
|
|
1916
2298
|
return unsupported;
|
|
1917
2299
|
}
|
|
1918
2300
|
function createFallbackBenchOutputDir(resultsDir, benchmarkId, pid, startedAtMs = Date.now()) {
|
|
1919
|
-
return
|
|
2301
|
+
return path7.join(
|
|
1920
2302
|
resultsDir,
|
|
1921
2303
|
FALLBACK_RESULTS_DIRNAME,
|
|
1922
2304
|
`${benchmarkId}-${startedAtMs}-${pid}`
|
|
1923
2305
|
);
|
|
1924
2306
|
}
|
|
1925
2307
|
function resolveFallbackBenchResultPath(outputDir) {
|
|
1926
|
-
const entries =
|
|
2308
|
+
const entries = fs4.readdirSync(outputDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
|
|
1927
2309
|
if (entries.length === 0) {
|
|
1928
2310
|
throw new Error(`Fallback benchmark runner did not write a JSON result artifact in ${outputDir}`);
|
|
1929
2311
|
}
|
|
1930
|
-
return
|
|
2312
|
+
return path7.join(outputDir, entries[0]);
|
|
1931
2313
|
}
|
|
1932
2314
|
|
|
1933
2315
|
// src/openclaw-upgrade-swap.ts
|
|
1934
|
-
import
|
|
1935
|
-
import
|
|
2316
|
+
import fs5 from "fs";
|
|
2317
|
+
import path8 from "path";
|
|
1936
2318
|
function describeError(error) {
|
|
1937
2319
|
return error instanceof Error ? error.message : String(error);
|
|
1938
2320
|
}
|
|
1939
2321
|
function createSiblingTempFilePath(targetPath, label) {
|
|
1940
2322
|
const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
|
|
1941
|
-
return
|
|
2323
|
+
return path8.join(path8.dirname(targetPath), `.${path8.basename(targetPath)}.${label}.${nonce}.tmp`);
|
|
1942
2324
|
}
|
|
1943
2325
|
function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
1944
2326
|
if (explicitMode !== void 0) return explicitMode;
|
|
1945
2327
|
try {
|
|
1946
|
-
return
|
|
2328
|
+
return fs5.statSync(targetPath).mode & 4095;
|
|
1947
2329
|
} catch (error) {
|
|
1948
2330
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
1949
2331
|
return 384;
|
|
@@ -1953,8 +2335,8 @@ function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
|
1953
2335
|
}
|
|
1954
2336
|
function resolveAtomicReplacementPath(targetPath) {
|
|
1955
2337
|
try {
|
|
1956
|
-
if (
|
|
1957
|
-
return
|
|
2338
|
+
if (fs5.lstatSync(targetPath).isSymbolicLink()) {
|
|
2339
|
+
return fs5.realpathSync(targetPath);
|
|
1958
2340
|
}
|
|
1959
2341
|
} catch (error) {
|
|
1960
2342
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
@@ -1966,12 +2348,12 @@ function resolveAtomicReplacementPath(targetPath) {
|
|
|
1966
2348
|
}
|
|
1967
2349
|
function createSiblingSwapPath(targetDir, label) {
|
|
1968
2350
|
const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
|
|
1969
|
-
return
|
|
2351
|
+
return path8.join(path8.dirname(targetDir), `.${path8.basename(targetDir)}.${label}.${nonce}`);
|
|
1970
2352
|
}
|
|
1971
2353
|
function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
1972
2354
|
if (!displacedDir) return void 0;
|
|
1973
2355
|
try {
|
|
1974
|
-
|
|
2356
|
+
fs5.rmSync(displacedDir, { recursive: true, force: true });
|
|
1975
2357
|
return void 0;
|
|
1976
2358
|
} catch (error) {
|
|
1977
2359
|
return `Warning: ${context}, but failed to remove the displaced plugin copy at ${displacedDir}: ${describeError(error)}`;
|
|
@@ -1979,55 +2361,55 @@ function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
|
1979
2361
|
}
|
|
1980
2362
|
function atomicWriteFileSync(targetPath, data, options = {}) {
|
|
1981
2363
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
1982
|
-
|
|
2364
|
+
fs5.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
|
|
1983
2365
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "write");
|
|
1984
2366
|
const mode = resolveAtomicWriteMode(resolvedTargetPath, options.mode);
|
|
1985
2367
|
try {
|
|
1986
2368
|
if (options.hooks?.writeTempFileSync) {
|
|
1987
2369
|
options.hooks.writeTempFileSync(tempPath);
|
|
1988
2370
|
} else {
|
|
1989
|
-
|
|
2371
|
+
fs5.writeFileSync(tempPath, data, { mode });
|
|
1990
2372
|
}
|
|
1991
|
-
|
|
1992
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
2373
|
+
fs5.chmodSync(tempPath, mode);
|
|
2374
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs5.renameSync;
|
|
1993
2375
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
1994
2376
|
} catch (error) {
|
|
1995
|
-
|
|
2377
|
+
fs5.rmSync(tempPath, { force: true });
|
|
1996
2378
|
throw error;
|
|
1997
2379
|
}
|
|
1998
2380
|
}
|
|
1999
2381
|
function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
|
|
2000
|
-
if (!
|
|
2382
|
+
if (!fs5.existsSync(sourcePath)) return;
|
|
2001
2383
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
2002
|
-
|
|
2384
|
+
fs5.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
|
|
2003
2385
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "copy");
|
|
2004
|
-
const mode =
|
|
2386
|
+
const mode = fs5.statSync(sourcePath).mode & 4095;
|
|
2005
2387
|
try {
|
|
2006
|
-
const copyTempFileSync = options.hooks?.copyTempFileSync ??
|
|
2388
|
+
const copyTempFileSync = options.hooks?.copyTempFileSync ?? fs5.copyFileSync;
|
|
2007
2389
|
copyTempFileSync(sourcePath, tempPath);
|
|
2008
|
-
|
|
2009
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
2390
|
+
fs5.chmodSync(tempPath, mode);
|
|
2391
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs5.renameSync;
|
|
2010
2392
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
2011
2393
|
} catch (error) {
|
|
2012
|
-
|
|
2394
|
+
fs5.rmSync(tempPath, { force: true });
|
|
2013
2395
|
throw error;
|
|
2014
2396
|
}
|
|
2015
2397
|
}
|
|
2016
2398
|
function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
|
|
2017
2399
|
let hasRollbackCopy = false;
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
if (
|
|
2021
|
-
|
|
2400
|
+
fs5.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2401
|
+
fs5.rmSync(rollbackDir, { recursive: true, force: true });
|
|
2402
|
+
if (fs5.existsSync(targetDir)) {
|
|
2403
|
+
fs5.renameSync(targetDir, rollbackDir);
|
|
2022
2404
|
hasRollbackCopy = true;
|
|
2023
2405
|
}
|
|
2024
2406
|
try {
|
|
2025
|
-
|
|
2407
|
+
fs5.renameSync(stagedDir, targetDir);
|
|
2026
2408
|
} catch (swapError) {
|
|
2027
|
-
|
|
2028
|
-
if (hasRollbackCopy &&
|
|
2409
|
+
fs5.rmSync(targetDir, { recursive: true, force: true });
|
|
2410
|
+
if (hasRollbackCopy && fs5.existsSync(rollbackDir)) {
|
|
2029
2411
|
try {
|
|
2030
|
-
|
|
2412
|
+
fs5.renameSync(rollbackDir, targetDir);
|
|
2031
2413
|
hasRollbackCopy = false;
|
|
2032
2414
|
} catch (restoreError) {
|
|
2033
2415
|
throw new AggregateError(
|
|
@@ -2042,7 +2424,7 @@ function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
|
|
|
2042
2424
|
}
|
|
2043
2425
|
function cleanupRollbackDirectory(rollbackDir) {
|
|
2044
2426
|
if (!rollbackDir) return;
|
|
2045
|
-
|
|
2427
|
+
fs5.rmSync(rollbackDir, { recursive: true, force: true });
|
|
2046
2428
|
}
|
|
2047
2429
|
function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
2048
2430
|
if (!rollbackDir) return void 0;
|
|
@@ -2054,20 +2436,20 @@ function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
|
2054
2436
|
}
|
|
2055
2437
|
}
|
|
2056
2438
|
function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
2057
|
-
if (!
|
|
2439
|
+
if (!fs5.existsSync(rollbackDir)) {
|
|
2058
2440
|
throw new Error(`Rollback directory is missing: ${rollbackDir}`);
|
|
2059
2441
|
}
|
|
2060
|
-
|
|
2061
|
-
const displacedDir =
|
|
2442
|
+
fs5.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2443
|
+
const displacedDir = fs5.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
|
|
2062
2444
|
if (displacedDir) {
|
|
2063
|
-
|
|
2445
|
+
fs5.renameSync(targetDir, displacedDir);
|
|
2064
2446
|
}
|
|
2065
2447
|
try {
|
|
2066
|
-
|
|
2448
|
+
fs5.renameSync(rollbackDir, targetDir);
|
|
2067
2449
|
} catch (restoreError) {
|
|
2068
|
-
if (displacedDir &&
|
|
2450
|
+
if (displacedDir && fs5.existsSync(displacedDir)) {
|
|
2069
2451
|
try {
|
|
2070
|
-
|
|
2452
|
+
fs5.renameSync(displacedDir, targetDir);
|
|
2071
2453
|
} catch (revertError) {
|
|
2072
2454
|
throw new AggregateError(
|
|
2073
2455
|
[restoreError, revertError],
|
|
@@ -2086,23 +2468,23 @@ function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
|
2086
2468
|
);
|
|
2087
2469
|
}
|
|
2088
2470
|
function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
2089
|
-
if (!
|
|
2471
|
+
if (!fs5.existsSync(backupDir)) {
|
|
2090
2472
|
throw new Error(`Plugin backup directory is missing: ${backupDir}`);
|
|
2091
2473
|
}
|
|
2092
|
-
|
|
2474
|
+
fs5.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2093
2475
|
const stagedDir = createSiblingSwapPath(targetDir, "backup-restore");
|
|
2094
|
-
const displacedDir =
|
|
2095
|
-
|
|
2476
|
+
const displacedDir = fs5.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
|
|
2477
|
+
fs5.cpSync(backupDir, stagedDir, { recursive: true });
|
|
2096
2478
|
if (displacedDir) {
|
|
2097
|
-
|
|
2479
|
+
fs5.renameSync(targetDir, displacedDir);
|
|
2098
2480
|
}
|
|
2099
2481
|
try {
|
|
2100
|
-
|
|
2482
|
+
fs5.renameSync(stagedDir, targetDir);
|
|
2101
2483
|
} catch (restoreError) {
|
|
2102
|
-
|
|
2103
|
-
if (displacedDir &&
|
|
2484
|
+
fs5.rmSync(targetDir, { recursive: true, force: true });
|
|
2485
|
+
if (displacedDir && fs5.existsSync(displacedDir)) {
|
|
2104
2486
|
try {
|
|
2105
|
-
|
|
2487
|
+
fs5.renameSync(displacedDir, targetDir);
|
|
2106
2488
|
} catch (revertError) {
|
|
2107
2489
|
throw new AggregateError(
|
|
2108
2490
|
[restoreError, revertError],
|
|
@@ -2110,7 +2492,7 @@ function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
|
2110
2492
|
);
|
|
2111
2493
|
}
|
|
2112
2494
|
}
|
|
2113
|
-
|
|
2495
|
+
fs5.rmSync(stagedDir, { recursive: true, force: true });
|
|
2114
2496
|
throw new Error(
|
|
2115
2497
|
`Failed to restore the plugin backup into ${targetDir}. The durable backup remains preserved at ${backupDir}.`,
|
|
2116
2498
|
{ cause: restoreError }
|
|
@@ -2136,7 +2518,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2136
2518
|
let rollbackRestoreError;
|
|
2137
2519
|
let pluginRestored = false;
|
|
2138
2520
|
try {
|
|
2139
|
-
if (rollbackDir &&
|
|
2521
|
+
if (rollbackDir && fs5.existsSync(rollbackDir)) {
|
|
2140
2522
|
const cleanupWarning = restoreDirectoryFromRollback(pluginDir, rollbackDir);
|
|
2141
2523
|
notes.push(`Restored previous plugin from rollback copy at ${rollbackDir}`);
|
|
2142
2524
|
if (cleanupWarning) notes.push(cleanupWarning);
|
|
@@ -2146,7 +2528,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2146
2528
|
rollbackRestoreError = error instanceof Error ? error.message : String(error);
|
|
2147
2529
|
}
|
|
2148
2530
|
try {
|
|
2149
|
-
if (!pluginRestored && pluginBackupDir &&
|
|
2531
|
+
if (!pluginRestored && pluginBackupDir && fs5.existsSync(pluginBackupDir)) {
|
|
2150
2532
|
const cleanupWarning = restoreDirectoryFromBackup(pluginDir, pluginBackupDir);
|
|
2151
2533
|
if (rollbackRestoreError) {
|
|
2152
2534
|
notes.push(
|
|
@@ -2173,7 +2555,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2173
2555
|
notes.push("No previous plugin copy was available for automatic restore");
|
|
2174
2556
|
}
|
|
2175
2557
|
try {
|
|
2176
|
-
if (configBackupPath &&
|
|
2558
|
+
if (configBackupPath && fs5.existsSync(configBackupPath)) {
|
|
2177
2559
|
restoreFileFromBackup(configPath, configBackupPath);
|
|
2178
2560
|
notes.push(`Restored OpenClaw config from backup at ${configBackupPath}`);
|
|
2179
2561
|
}
|
|
@@ -2213,11 +2595,11 @@ Run this manually when you're ready:
|
|
|
2213
2595
|
}
|
|
2214
2596
|
|
|
2215
2597
|
// src/daemon-service.ts
|
|
2216
|
-
import
|
|
2217
|
-
import
|
|
2598
|
+
import fs6 from "fs";
|
|
2599
|
+
import path9 from "path";
|
|
2218
2600
|
import * as childProcess from "child_process";
|
|
2219
2601
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2220
|
-
var thisModuleDir =
|
|
2602
|
+
var thisModuleDir = path9.dirname(fileURLToPath3(import.meta.url));
|
|
2221
2603
|
function launchdLoadPlist(plistPath, processApi = childProcess) {
|
|
2222
2604
|
processApi.execFileSync("launchctl", ["load", "-w", plistPath], { stdio: "pipe" });
|
|
2223
2605
|
}
|
|
@@ -2225,7 +2607,7 @@ function launchdUnloadPlist(plistPath, processApi = childProcess) {
|
|
|
2225
2607
|
processApi.execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
|
|
2226
2608
|
}
|
|
2227
2609
|
function resolveServerBinDetails(options = {}) {
|
|
2228
|
-
const existsSync3 = options.existsSync ??
|
|
2610
|
+
const existsSync3 = options.existsSync ?? fs6.existsSync;
|
|
2229
2611
|
const findCommandOnPath2 = options.findCommandOnPath ?? findCommandOnPath;
|
|
2230
2612
|
const moduleDir = options.moduleDir ?? thisModuleDir;
|
|
2231
2613
|
const packageResolve = options.packageResolve ?? resolveImportSpecifier;
|
|
@@ -2239,8 +2621,8 @@ function resolveServerBinDetails(options = {}) {
|
|
|
2239
2621
|
});
|
|
2240
2622
|
} catch {
|
|
2241
2623
|
}
|
|
2242
|
-
const workspaceServerBin =
|
|
2243
|
-
const workspaceDistIndex =
|
|
2624
|
+
const workspaceServerBin = path9.resolve(moduleDir, "../../remnic-server/bin/remnic-server.js");
|
|
2625
|
+
const workspaceDistIndex = path9.resolve(moduleDir, "../../remnic-server/dist/index.js");
|
|
2244
2626
|
candidates.push(
|
|
2245
2627
|
{
|
|
2246
2628
|
path: workspaceServerBin,
|
|
@@ -2261,11 +2643,11 @@ function resolveServerBinDetails(options = {}) {
|
|
|
2261
2643
|
});
|
|
2262
2644
|
}
|
|
2263
2645
|
candidates.push({
|
|
2264
|
-
path:
|
|
2646
|
+
path: path9.resolve(moduleDir, "../../remnic-server/src/index.ts"),
|
|
2265
2647
|
source: "workspace-source"
|
|
2266
2648
|
});
|
|
2267
2649
|
const selected = candidates.find((candidate) => isCandidateReady(candidate, existsSync3)) ?? candidates.find((candidate) => existsSync3(candidate.path)) ?? candidates[0] ?? {
|
|
2268
|
-
path:
|
|
2650
|
+
path: path9.resolve(moduleDir, "../../remnic-server/dist/index.js"),
|
|
2269
2651
|
source: "workspace-dist"
|
|
2270
2652
|
};
|
|
2271
2653
|
const exists = existsSync3(selected.path);
|
|
@@ -2284,8 +2666,8 @@ function resolveServerBin(options = {}) {
|
|
|
2284
2666
|
return resolveServerBinDetails(options).path;
|
|
2285
2667
|
}
|
|
2286
2668
|
function readVerifiedDaemonPid(options) {
|
|
2287
|
-
const readFileSync3 = options.readFileSync ??
|
|
2288
|
-
const unlinkSync = options.unlinkSync ??
|
|
2669
|
+
const readFileSync3 = options.readFileSync ?? fs6.readFileSync;
|
|
2670
|
+
const unlinkSync = options.unlinkSync ?? fs6.unlinkSync;
|
|
2289
2671
|
const processKill = options.processKill ?? process.kill;
|
|
2290
2672
|
const platform = options.platform ?? process.platform;
|
|
2291
2673
|
const execFileSync3 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
|
|
@@ -2320,7 +2702,7 @@ function readVerifiedDaemonPid(options) {
|
|
|
2320
2702
|
}
|
|
2321
2703
|
function doesProcessCommandLookLikeRemnicDaemon(command, expectedServerBin) {
|
|
2322
2704
|
const normalizedCommand = command.trim();
|
|
2323
|
-
const normalizedExpected =
|
|
2705
|
+
const normalizedExpected = path9.resolve(expandTilde(expectedServerBin));
|
|
2324
2706
|
return normalizedCommand.includes(normalizedExpected) || /(?:^|\s|[/\\])(?:remnic-server|engram-server)(?:\.js)?(?:\s|$)/.test(normalizedCommand) || /@remnic[/\\]server[/\\]/.test(normalizedCommand) || /packages[/\\]remnic-server[/\\](?:bin[/\\]remnic-server\.js|dist[/\\]index\.js|src[/\\]index\.ts)/.test(normalizedCommand);
|
|
2325
2707
|
}
|
|
2326
2708
|
function parseDaemonPid(raw) {
|
|
@@ -2385,8 +2767,8 @@ function removePidFileBestEffort(file, unlinkSync) {
|
|
|
2385
2767
|
}
|
|
2386
2768
|
}
|
|
2387
2769
|
function inspectLaunchdPlist(plistPath, options = {}) {
|
|
2388
|
-
const existsSync3 = options.existsSync ??
|
|
2389
|
-
const readFileSync3 = options.readFileSync ??
|
|
2770
|
+
const existsSync3 = options.existsSync ?? fs6.existsSync;
|
|
2771
|
+
const readFileSync3 = options.readFileSync ?? fs6.readFileSync;
|
|
2390
2772
|
if (!existsSync3(plistPath)) {
|
|
2391
2773
|
return {
|
|
2392
2774
|
installed: false,
|
|
@@ -2425,7 +2807,7 @@ function inspectLaunchdPlist(plistPath, options = {}) {
|
|
|
2425
2807
|
};
|
|
2426
2808
|
}
|
|
2427
2809
|
const expandedServerArg = expandTilde(serverArg);
|
|
2428
|
-
if (!
|
|
2810
|
+
if (!path9.isAbsolute(expandedServerArg)) {
|
|
2429
2811
|
return {
|
|
2430
2812
|
installed: true,
|
|
2431
2813
|
ok: false,
|
|
@@ -2497,8 +2879,8 @@ function normalizeResolvedPath(resolved) {
|
|
|
2497
2879
|
return resolved;
|
|
2498
2880
|
}
|
|
2499
2881
|
function packageServerBinFromEntry(packageEntry) {
|
|
2500
|
-
if (
|
|
2501
|
-
return
|
|
2882
|
+
if (path9.basename(packageEntry) === "index.js" && path9.basename(path9.dirname(packageEntry)) === "dist") {
|
|
2883
|
+
return path9.join(path9.dirname(path9.dirname(packageEntry)), "bin", "remnic-server.js");
|
|
2502
2884
|
}
|
|
2503
2885
|
return packageEntry;
|
|
2504
2886
|
}
|
|
@@ -2620,7 +3002,7 @@ function stripConfigArgv(args) {
|
|
|
2620
3002
|
}
|
|
2621
3003
|
|
|
2622
3004
|
// src/import-dispatch.ts
|
|
2623
|
-
import
|
|
3005
|
+
import fs7 from "fs";
|
|
2624
3006
|
import {
|
|
2625
3007
|
runImporter,
|
|
2626
3008
|
validateImportBatchSize,
|
|
@@ -2629,9 +3011,9 @@ import {
|
|
|
2629
3011
|
|
|
2630
3012
|
// src/import-bundle-detect.ts
|
|
2631
3013
|
import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
2632
|
-
import
|
|
3014
|
+
import path10 from "path";
|
|
2633
3015
|
function detectBundleEntries(bundleDir, options = {}) {
|
|
2634
|
-
const
|
|
3016
|
+
const readdir3 = options.readdirImpl ?? defaultReaddir;
|
|
2635
3017
|
const readFileImpl = options.readFileImpl ?? defaultReadFile;
|
|
2636
3018
|
const isDirectory2 = options.isDirectoryImpl ?? defaultIsDirectory;
|
|
2637
3019
|
const isRegularFile = options.isRegularFileImpl ?? (options.readdirImpl !== void 0 || options.isDirectoryImpl !== void 0 ? (p) => !isDirectory2(p) : defaultIsRegularFile);
|
|
@@ -2651,7 +3033,7 @@ function detectBundleEntries(bundleDir, options = {}) {
|
|
|
2651
3033
|
}
|
|
2652
3034
|
const roots = collectCandidatePaths(
|
|
2653
3035
|
bundleDir,
|
|
2654
|
-
|
|
3036
|
+
readdir3,
|
|
2655
3037
|
isDirectory2,
|
|
2656
3038
|
isRegularFile
|
|
2657
3039
|
);
|
|
@@ -2660,7 +3042,7 @@ function detectBundleEntries(bundleDir, options = {}) {
|
|
|
2660
3042
|
for (const filePath of roots) {
|
|
2661
3043
|
if (seenFiles.has(filePath)) continue;
|
|
2662
3044
|
seenFiles.add(filePath);
|
|
2663
|
-
const name =
|
|
3045
|
+
const name = path10.basename(filePath);
|
|
2664
3046
|
const match = classifyFile(name, filePath, readFileImpl);
|
|
2665
3047
|
if (match) entries.push(match);
|
|
2666
3048
|
}
|
|
@@ -2680,9 +3062,9 @@ function detectBundleEntries(bundleDir, options = {}) {
|
|
|
2680
3062
|
return entries;
|
|
2681
3063
|
}
|
|
2682
3064
|
var MAX_WALK_DEPTH = 4;
|
|
2683
|
-
function collectCandidatePaths(root,
|
|
3065
|
+
function collectCandidatePaths(root, readdir3, isDirectory2, isRegularFile) {
|
|
2684
3066
|
try {
|
|
2685
|
-
|
|
3067
|
+
readdir3(root);
|
|
2686
3068
|
} catch {
|
|
2687
3069
|
throw new Error(
|
|
2688
3070
|
`Bundle directory '${root}' could not be read. Pass an existing directory.`
|
|
@@ -2693,12 +3075,12 @@ function collectCandidatePaths(root, readdir2, isDirectory2, isRegularFile) {
|
|
|
2693
3075
|
if (depth > MAX_WALK_DEPTH) return;
|
|
2694
3076
|
let entries;
|
|
2695
3077
|
try {
|
|
2696
|
-
entries =
|
|
3078
|
+
entries = readdir3(dir);
|
|
2697
3079
|
} catch {
|
|
2698
3080
|
return;
|
|
2699
3081
|
}
|
|
2700
3082
|
for (const entry of entries) {
|
|
2701
|
-
const full =
|
|
3083
|
+
const full = path10.join(dir, entry);
|
|
2702
3084
|
if (isDirectory2(full)) {
|
|
2703
3085
|
walk(full, depth + 1);
|
|
2704
3086
|
} else if (isRegularFile(full)) {
|
|
@@ -3134,7 +3516,7 @@ async function cmdImport(rest, targetFactory, disposeTarget, ioOverrides = {}) {
|
|
|
3134
3516
|
let materializedTarget;
|
|
3135
3517
|
let materializePromise;
|
|
3136
3518
|
const io = {
|
|
3137
|
-
readFile: ioOverrides.readFile ?? (async (p) =>
|
|
3519
|
+
readFile: ioOverrides.readFile ?? (async (p) => fs7.promises.readFile(p, "utf-8")),
|
|
3138
3520
|
loadAdapter: ioOverrides.loadAdapter ?? (async (name) => (await loadImporterModule(name)).adapter),
|
|
3139
3521
|
runImporter: ioOverrides.runImporter ?? runImporter,
|
|
3140
3522
|
getWriteTarget: async () => {
|
|
@@ -3207,8 +3589,8 @@ function takeOptionalValue(args, flag) {
|
|
|
3207
3589
|
}
|
|
3208
3590
|
|
|
3209
3591
|
// src/import-lossless-claw-cmd.ts
|
|
3210
|
-
import
|
|
3211
|
-
import
|
|
3592
|
+
import fs8 from "fs";
|
|
3593
|
+
import path11 from "path";
|
|
3212
3594
|
import {
|
|
3213
3595
|
applyLcmSchema,
|
|
3214
3596
|
ensureLcmStateDir,
|
|
@@ -3319,15 +3701,15 @@ async function loadImportLosslessClawModule() {
|
|
|
3319
3701
|
|
|
3320
3702
|
// src/import-lossless-claw-cmd.ts
|
|
3321
3703
|
function assertDirectoryOrAbsent(p, label) {
|
|
3322
|
-
if (
|
|
3704
|
+
if (fs8.existsSync(p) && !fs8.statSync(p).isDirectory()) {
|
|
3323
3705
|
throw new Error(`${label} is not a directory: ${p}`);
|
|
3324
3706
|
}
|
|
3325
3707
|
}
|
|
3326
3708
|
function assertFile(p, label) {
|
|
3327
|
-
if (!
|
|
3709
|
+
if (!fs8.existsSync(p)) {
|
|
3328
3710
|
throw new Error(`${label} does not exist: ${p}`);
|
|
3329
3711
|
}
|
|
3330
|
-
if (!
|
|
3712
|
+
if (!fs8.statSync(p).isFile()) {
|
|
3331
3713
|
throw new Error(`${label} is not a file: ${p}`);
|
|
3332
3714
|
}
|
|
3333
3715
|
}
|
|
@@ -3358,8 +3740,8 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
|
|
|
3358
3740
|
let destDb;
|
|
3359
3741
|
try {
|
|
3360
3742
|
if (parsed.dryRun) {
|
|
3361
|
-
const lcmPath =
|
|
3362
|
-
if (
|
|
3743
|
+
const lcmPath = path11.join(memoryDir, "state", "lcm.sqlite");
|
|
3744
|
+
if (fs8.existsSync(lcmPath)) {
|
|
3363
3745
|
destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
|
|
3364
3746
|
} else {
|
|
3365
3747
|
destDb = mod.openInMemoryDestinationDatabase();
|
|
@@ -3451,15 +3833,15 @@ registerPublisher("omp", () => new LazyPluginPiPublisher("omp", (mod) => mod.Omp
|
|
|
3451
3833
|
function readCompatEnv(primary, legacy) {
|
|
3452
3834
|
return process.env[primary] ?? process.env[legacy];
|
|
3453
3835
|
}
|
|
3454
|
-
var PID_DIR =
|
|
3455
|
-
var LEGACY_PID_DIR =
|
|
3456
|
-
var PID_FILE =
|
|
3457
|
-
var LEGACY_PID_FILE =
|
|
3458
|
-
var LOG_FILE =
|
|
3459
|
-
var LEGACY_LOG_FILE =
|
|
3460
|
-
var CLI_MODULE_DIR =
|
|
3461
|
-
var CLI_REPO_ROOT =
|
|
3462
|
-
var EVAL_RUNNER_PATH =
|
|
3836
|
+
var PID_DIR = path12.join(resolveHomeDir(), ".remnic");
|
|
3837
|
+
var LEGACY_PID_DIR = path12.join(resolveHomeDir(), ".engram");
|
|
3838
|
+
var PID_FILE = path12.join(PID_DIR, "server.pid");
|
|
3839
|
+
var LEGACY_PID_FILE = path12.join(LEGACY_PID_DIR, "server.pid");
|
|
3840
|
+
var LOG_FILE = path12.join(PID_DIR, "server.log");
|
|
3841
|
+
var LEGACY_LOG_FILE = path12.join(LEGACY_PID_DIR, "server.log");
|
|
3842
|
+
var CLI_MODULE_DIR = path12.dirname(fileURLToPath4(import.meta.url));
|
|
3843
|
+
var CLI_REPO_ROOT = path12.resolve(CLI_MODULE_DIR, "../../..");
|
|
3844
|
+
var EVAL_RUNNER_PATH = path12.join(CLI_REPO_ROOT, "evals", "run.ts");
|
|
3463
3845
|
var OPENCLAW_GATEWAY_LABEL = "ai.openclaw.gateway";
|
|
3464
3846
|
var CLI_SUCCESS_EXIT_GRACE_MS = 5e3;
|
|
3465
3847
|
var CLI_OUTPUT_FLUSH_GRACE_MS = 250;
|
|
@@ -3792,7 +4174,7 @@ async function resolveAllBenchmarks() {
|
|
|
3792
4174
|
if (packageBenchmarks) {
|
|
3793
4175
|
return packageBenchmarks.filter((entry) => entry.runnerAvailable).map((entry) => entry.id);
|
|
3794
4176
|
}
|
|
3795
|
-
if (!
|
|
4177
|
+
if (!fs9.existsSync(EVAL_RUNNER_PATH)) {
|
|
3796
4178
|
return [];
|
|
3797
4179
|
}
|
|
3798
4180
|
return BENCHMARK_CATALOG.filter((entry) => entry.category !== "ingestion").map((entry) => entry.id);
|
|
@@ -3840,17 +4222,17 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
3840
4222
|
`Fallback benchmark runner does not support provider-backed, gateway, or thinking/timeout flags (${unsupportedOptions.join(", ")}). Build/install @remnic/bench to use those options.`
|
|
3841
4223
|
);
|
|
3842
4224
|
}
|
|
3843
|
-
if (!
|
|
4225
|
+
if (!fs9.existsSync(EVAL_RUNNER_PATH)) {
|
|
3844
4226
|
console.error(
|
|
3845
4227
|
"Benchmark runner not found. Expected eval runner at evals/run.ts or a phase-1 @remnic/bench runtime export."
|
|
3846
4228
|
);
|
|
3847
4229
|
process.exit(1);
|
|
3848
4230
|
}
|
|
3849
4231
|
const tsxCandidates = [
|
|
3850
|
-
|
|
3851
|
-
|
|
4232
|
+
path12.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
|
|
4233
|
+
path12.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
|
|
3852
4234
|
];
|
|
3853
|
-
const tsxCmd = tsxCandidates.find((candidate) =>
|
|
4235
|
+
const tsxCmd = tsxCandidates.find((candidate) => fs9.existsSync(candidate)) ?? "tsx";
|
|
3854
4236
|
const fallbackOutputDir = createFallbackBenchOutputDir(
|
|
3855
4237
|
parsed.resultsDir ?? resolveBenchOutputDir(),
|
|
3856
4238
|
benchmarkId,
|
|
@@ -3867,7 +4249,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
3867
4249
|
return resolveFallbackBenchResultPath(fallbackOutputDir);
|
|
3868
4250
|
}
|
|
3869
4251
|
function resolveBenchOutputDir() {
|
|
3870
|
-
return
|
|
4252
|
+
return path12.join(resolveHomeDir(), ".remnic", "bench", "results");
|
|
3871
4253
|
}
|
|
3872
4254
|
var DOWNLOADABLE_BENCHMARK_DATASETS = [
|
|
3873
4255
|
"ama-bench",
|
|
@@ -3912,8 +4294,8 @@ var MEMORY_AGENT_BENCH_SPLIT_FILENAMES = [
|
|
|
3912
4294
|
];
|
|
3913
4295
|
var MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES = [
|
|
3914
4296
|
"entity2id.json",
|
|
3915
|
-
|
|
3916
|
-
|
|
4297
|
+
path12.join("processed_data", "Recsys_Redial", "entity2id.json"),
|
|
4298
|
+
path12.join("Recsys_Redial", "entity2id.json")
|
|
3917
4299
|
];
|
|
3918
4300
|
var DOWNLOADED_DATASET_MARKERS = {
|
|
3919
4301
|
"ama-bench": { anyOf: ["open_end_qa_set.jsonl"] },
|
|
@@ -3988,18 +4370,18 @@ var PERSONAMEM_DATASET_FILE_CANDIDATES = [
|
|
|
3988
4370
|
"benchmark/benchmark.csv",
|
|
3989
4371
|
"benchmark.csv"
|
|
3990
4372
|
];
|
|
3991
|
-
var PERSONAMEM_COMPLETION_MARKER =
|
|
4373
|
+
var PERSONAMEM_COMPLETION_MARKER = path12.join(
|
|
3992
4374
|
"data",
|
|
3993
4375
|
"chat_history_32k",
|
|
3994
4376
|
".download-complete"
|
|
3995
4377
|
);
|
|
3996
4378
|
function resolveRealpathWithinDataset(datasetPath, relativePath) {
|
|
3997
4379
|
try {
|
|
3998
|
-
const datasetRoot =
|
|
3999
|
-
const candidatePath =
|
|
4000
|
-
const candidateRealPath =
|
|
4001
|
-
const relativeToRoot =
|
|
4002
|
-
if (relativeToRoot.startsWith("..") ||
|
|
4380
|
+
const datasetRoot = fs9.realpathSync(datasetPath);
|
|
4381
|
+
const candidatePath = path12.resolve(datasetRoot, relativePath);
|
|
4382
|
+
const candidateRealPath = fs9.realpathSync(candidatePath);
|
|
4383
|
+
const relativeToRoot = path12.relative(datasetRoot, candidateRealPath);
|
|
4384
|
+
if (relativeToRoot.startsWith("..") || path12.isAbsolute(relativeToRoot)) {
|
|
4003
4385
|
return null;
|
|
4004
4386
|
}
|
|
4005
4387
|
return candidateRealPath;
|
|
@@ -4055,15 +4437,15 @@ function parseCsvRows(raw) {
|
|
|
4055
4437
|
}
|
|
4056
4438
|
function isPersonaMemDatasetComplete(datasetPath) {
|
|
4057
4439
|
try {
|
|
4058
|
-
const completionMarkerPath =
|
|
4059
|
-
if (
|
|
4440
|
+
const completionMarkerPath = path12.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
|
|
4441
|
+
if (fs9.statSync(completionMarkerPath).isFile()) {
|
|
4060
4442
|
return true;
|
|
4061
4443
|
}
|
|
4062
4444
|
} catch {
|
|
4063
4445
|
}
|
|
4064
4446
|
const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
|
|
4065
4447
|
try {
|
|
4066
|
-
return
|
|
4448
|
+
return fs9.statSync(path12.join(datasetPath, candidate)).isFile();
|
|
4067
4449
|
} catch {
|
|
4068
4450
|
return false;
|
|
4069
4451
|
}
|
|
@@ -4072,7 +4454,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4072
4454
|
return false;
|
|
4073
4455
|
}
|
|
4074
4456
|
try {
|
|
4075
|
-
const rows = parseCsvRows(
|
|
4457
|
+
const rows = parseCsvRows(fs9.readFileSync(path12.join(datasetPath, datasetFile), "utf8"));
|
|
4076
4458
|
if (rows.length < 2) {
|
|
4077
4459
|
return false;
|
|
4078
4460
|
}
|
|
@@ -4087,7 +4469,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4087
4469
|
}
|
|
4088
4470
|
return historyPaths.every((relativePath) => {
|
|
4089
4471
|
const resolvedPath = resolveRealpathWithinDataset(datasetPath, relativePath);
|
|
4090
|
-
return resolvedPath !== null &&
|
|
4472
|
+
return resolvedPath !== null && fs9.statSync(resolvedPath).isFile();
|
|
4091
4473
|
});
|
|
4092
4474
|
} catch {
|
|
4093
4475
|
return false;
|
|
@@ -4095,14 +4477,14 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4095
4477
|
}
|
|
4096
4478
|
function hasDatasetFile(datasetPath, relativePath) {
|
|
4097
4479
|
try {
|
|
4098
|
-
return
|
|
4480
|
+
return fs9.statSync(path12.join(datasetPath, relativePath)).isFile();
|
|
4099
4481
|
} catch {
|
|
4100
4482
|
return false;
|
|
4101
4483
|
}
|
|
4102
4484
|
}
|
|
4103
4485
|
function hasMemoryAgentBenchEntityMapping(datasetPath) {
|
|
4104
|
-
const absoluteDatasetPath =
|
|
4105
|
-
const roots = [absoluteDatasetPath,
|
|
4486
|
+
const absoluteDatasetPath = path12.resolve(datasetPath);
|
|
4487
|
+
const roots = [absoluteDatasetPath, path12.dirname(absoluteDatasetPath)];
|
|
4106
4488
|
return hasDatasetFile(absoluteDatasetPath, "entity2id.json") || roots.some(
|
|
4107
4489
|
(root) => MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES.filter((relativePath) => relativePath !== "entity2id.json").some((relativePath) => hasDatasetFile(root, relativePath))
|
|
4108
4490
|
);
|
|
@@ -4113,12 +4495,12 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
|
|
|
4113
4495
|
...MEMORY_AGENT_BENCH_SPLIT_FILENAMES
|
|
4114
4496
|
];
|
|
4115
4497
|
return candidateFilenames.some((filename) => {
|
|
4116
|
-
const filePath =
|
|
4498
|
+
const filePath = path12.join(datasetPath, filename);
|
|
4117
4499
|
try {
|
|
4118
|
-
if (!
|
|
4500
|
+
if (!fs9.statSync(filePath).isFile()) {
|
|
4119
4501
|
return false;
|
|
4120
4502
|
}
|
|
4121
|
-
const raw =
|
|
4503
|
+
const raw = fs9.readFileSync(filePath, "utf8");
|
|
4122
4504
|
return /"source"\s*:\s*"recsys[_-]/i.test(raw);
|
|
4123
4505
|
} catch {
|
|
4124
4506
|
return false;
|
|
@@ -4134,7 +4516,7 @@ function isMemoryAgentBenchDatasetComplete(datasetPath) {
|
|
|
4134
4516
|
function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
4135
4517
|
let stats;
|
|
4136
4518
|
try {
|
|
4137
|
-
stats =
|
|
4519
|
+
stats = fs9.statSync(datasetPath);
|
|
4138
4520
|
} catch {
|
|
4139
4521
|
return false;
|
|
4140
4522
|
}
|
|
@@ -4144,7 +4526,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4144
4526
|
const marker = DOWNLOADED_DATASET_MARKERS[benchmarkId];
|
|
4145
4527
|
if (!marker) {
|
|
4146
4528
|
try {
|
|
4147
|
-
return
|
|
4529
|
+
return fs9.readdirSync(datasetPath).length > 0;
|
|
4148
4530
|
} catch {
|
|
4149
4531
|
return false;
|
|
4150
4532
|
}
|
|
@@ -4152,7 +4534,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4152
4534
|
if (marker.allOf) {
|
|
4153
4535
|
const hasAllRequiredFiles = marker.allOf.every((name) => {
|
|
4154
4536
|
try {
|
|
4155
|
-
return
|
|
4537
|
+
return fs9.statSync(path12.join(datasetPath, name)).isFile();
|
|
4156
4538
|
} catch {
|
|
4157
4539
|
return false;
|
|
4158
4540
|
}
|
|
@@ -4164,7 +4546,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4164
4546
|
if (marker.anyOf) {
|
|
4165
4547
|
const hasMarkerFile = marker.anyOf.some((name) => {
|
|
4166
4548
|
try {
|
|
4167
|
-
return
|
|
4549
|
+
return fs9.statSync(path12.join(datasetPath, name)).isFile();
|
|
4168
4550
|
} catch {
|
|
4169
4551
|
return false;
|
|
4170
4552
|
}
|
|
@@ -4182,7 +4564,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4182
4564
|
}
|
|
4183
4565
|
if (marker.ext) {
|
|
4184
4566
|
try {
|
|
4185
|
-
return
|
|
4567
|
+
return fs9.readdirSync(datasetPath).some(
|
|
4186
4568
|
(name) => name.endsWith(marker.ext) && !marker.exclude?.includes(name)
|
|
4187
4569
|
);
|
|
4188
4570
|
} catch {
|
|
@@ -4192,9 +4574,9 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4192
4574
|
return false;
|
|
4193
4575
|
}
|
|
4194
4576
|
async function launchBenchUi(resultsDir) {
|
|
4195
|
-
const benchUiDir =
|
|
4577
|
+
const benchUiDir = path12.join(CLI_REPO_ROOT, "packages", "bench-ui");
|
|
4196
4578
|
const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
|
|
4197
|
-
if (!
|
|
4579
|
+
if (!fs9.existsSync(path12.join(benchUiDir, "package.json"))) {
|
|
4198
4580
|
console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
|
|
4199
4581
|
process.exit(1);
|
|
4200
4582
|
}
|
|
@@ -4221,24 +4603,24 @@ async function launchBenchUi(resultsDir) {
|
|
|
4221
4603
|
});
|
|
4222
4604
|
}
|
|
4223
4605
|
function resolveRepoDatasetRoot() {
|
|
4224
|
-
const repoCandidate =
|
|
4606
|
+
const repoCandidate = path12.join(CLI_REPO_ROOT, "evals", "datasets");
|
|
4225
4607
|
if (isRepoCheckout()) {
|
|
4226
4608
|
return repoCandidate;
|
|
4227
4609
|
}
|
|
4228
|
-
return
|
|
4610
|
+
return path12.join(resolveHomeDir(), ".remnic", "bench", "datasets");
|
|
4229
4611
|
}
|
|
4230
4612
|
function listDownloadableBenchmarks() {
|
|
4231
4613
|
return [...DOWNLOADABLE_BENCHMARK_DATASETS];
|
|
4232
4614
|
}
|
|
4233
4615
|
function resolveDatasetDownloadScriptPath() {
|
|
4234
|
-
const bundled =
|
|
4235
|
-
if (
|
|
4616
|
+
const bundled = path12.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
|
|
4617
|
+
if (fs9.existsSync(bundled)) {
|
|
4236
4618
|
return bundled;
|
|
4237
4619
|
}
|
|
4238
|
-
return
|
|
4620
|
+
return path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
|
|
4239
4621
|
}
|
|
4240
4622
|
function isRepoCheckout() {
|
|
4241
|
-
return
|
|
4623
|
+
return fs9.existsSync(path12.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs9.existsSync(path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
|
|
4242
4624
|
}
|
|
4243
4625
|
function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
|
|
4244
4626
|
const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
|
|
@@ -4289,7 +4671,7 @@ function resolveBenchDatasetDir(benchmarkId, quick, datasetDirOverride) {
|
|
|
4289
4671
|
if (quick) {
|
|
4290
4672
|
return void 0;
|
|
4291
4673
|
}
|
|
4292
|
-
const datasetDir =
|
|
4674
|
+
const datasetDir = path12.join(resolveRepoDatasetRoot(), benchmarkId);
|
|
4293
4675
|
if (isDatasetDownloaded(datasetDir, benchmarkId)) {
|
|
4294
4676
|
return datasetDir;
|
|
4295
4677
|
}
|
|
@@ -4607,13 +4989,13 @@ async function exportBenchPackageResult(parsed) {
|
|
|
4607
4989
|
process.exit(1);
|
|
4608
4990
|
}
|
|
4609
4991
|
const result = await loadBenchmarkResult(summary.path);
|
|
4610
|
-
const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(
|
|
4992
|
+
const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(path12.dirname(summary.path), result.meta.id) : void 0;
|
|
4611
4993
|
const rendered = renderBenchmarkResultExport(result, parsed.format, {
|
|
4612
4994
|
...reportCardProvenance ? { reportCardProvenance } : {}
|
|
4613
4995
|
});
|
|
4614
4996
|
if (parsed.output) {
|
|
4615
|
-
|
|
4616
|
-
|
|
4997
|
+
fs9.mkdirSync(path12.dirname(parsed.output), { recursive: true });
|
|
4998
|
+
fs9.writeFileSync(parsed.output, rendered);
|
|
4617
4999
|
console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
|
|
4618
5000
|
return;
|
|
4619
5001
|
}
|
|
@@ -4630,7 +5012,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
4630
5012
|
process.exit(1);
|
|
4631
5013
|
}
|
|
4632
5014
|
const status = supported.map((benchmarkId) => {
|
|
4633
|
-
const datasetPath =
|
|
5015
|
+
const datasetPath = path12.join(datasetRoot, benchmarkId);
|
|
4634
5016
|
return {
|
|
4635
5017
|
benchmark: benchmarkId,
|
|
4636
5018
|
downloaded: isDatasetDownloaded(datasetPath, benchmarkId),
|
|
@@ -4658,7 +5040,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
4658
5040
|
process.exit(1);
|
|
4659
5041
|
}
|
|
4660
5042
|
const scriptPath = resolveDatasetDownloadScriptPath();
|
|
4661
|
-
if (!
|
|
5043
|
+
if (!fs9.existsSync(scriptPath)) {
|
|
4662
5044
|
console.error(`ERROR: dataset download script not found: ${scriptPath}`);
|
|
4663
5045
|
process.exit(1);
|
|
4664
5046
|
}
|
|
@@ -4668,7 +5050,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
4668
5050
|
runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, parsed.json === true);
|
|
4669
5051
|
downloaded.push({
|
|
4670
5052
|
benchmark: benchmarkId,
|
|
4671
|
-
path:
|
|
5053
|
+
path: path12.join(datasetRoot, benchmarkId)
|
|
4672
5054
|
});
|
|
4673
5055
|
}
|
|
4674
5056
|
if (parsed.json) {
|
|
@@ -4807,10 +5189,10 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
4807
5189
|
}
|
|
4808
5190
|
const bench = await loadBenchModule();
|
|
4809
5191
|
const resultsDir = expandTilde(
|
|
4810
|
-
parsed.resultsDir ??
|
|
5192
|
+
parsed.resultsDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "results")
|
|
4811
5193
|
);
|
|
4812
5194
|
const calibrationDir = expandTilde(
|
|
4813
|
-
parsed.calibrationDir ??
|
|
5195
|
+
parsed.calibrationDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "calibration")
|
|
4814
5196
|
);
|
|
4815
5197
|
const stored = await bench.listBenchmarkResults(resultsDir);
|
|
4816
5198
|
const allForBenchmark = stored.filter((entry) => entry.benchmark === benchmarkId);
|
|
@@ -4858,7 +5240,7 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
4858
5240
|
);
|
|
4859
5241
|
process.exit(1);
|
|
4860
5242
|
}
|
|
4861
|
-
const sourceResultSha256 =
|
|
5243
|
+
const sourceResultSha256 = createHash2("sha256").update(fs9.readFileSync(latest.path)).digest("hex");
|
|
4862
5244
|
const expandedManifestPath = expandTilde(manifestPath);
|
|
4863
5245
|
if (!bench.resolveLocalLabJudgeProviderConfig) {
|
|
4864
5246
|
console.error(
|
|
@@ -5266,7 +5648,7 @@ function loadPinnedLoCoMoTaskSelector(parsed) {
|
|
|
5266
5648
|
}
|
|
5267
5649
|
let decoded;
|
|
5268
5650
|
try {
|
|
5269
|
-
decoded = JSON.parse(
|
|
5651
|
+
decoded = JSON.parse(fs9.readFileSync(parsed.taskIdsFile, "utf8"));
|
|
5270
5652
|
} catch (error) {
|
|
5271
5653
|
throw new Error(
|
|
5272
5654
|
`Unable to read --task-ids-file ${parsed.taskIdsFile}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -5363,7 +5745,7 @@ async function loadPublishedPromotionHelpers() {
|
|
|
5363
5745
|
return {
|
|
5364
5746
|
async promoteArtifactsToPublished(args) {
|
|
5365
5747
|
const { mkdirSync, readFileSync: readFileSync3, writeFileSync } = await import("fs");
|
|
5366
|
-
const
|
|
5748
|
+
const path13 = await import("path");
|
|
5367
5749
|
mkdirSync(args.publishedOutDir, { recursive: true });
|
|
5368
5750
|
if (args.artifactPaths.length === 0) {
|
|
5369
5751
|
console.warn(
|
|
@@ -5380,13 +5762,13 @@ async function loadPublishedPromotionHelpers() {
|
|
|
5380
5762
|
const modelSlug = args.model.replace(/[^a-zA-Z0-9_.-]/g, "-");
|
|
5381
5763
|
const rawProfile = parsedObj.config?.runtimeProfile;
|
|
5382
5764
|
const profileSlug = typeof rawProfile === "string" && rawProfile.length > 0 ? `-${rawProfile.replace(/[^a-zA-Z0-9_.-]/g, "-")}` : "";
|
|
5383
|
-
const target =
|
|
5765
|
+
const target = path13.join(
|
|
5384
5766
|
args.publishedOutDir,
|
|
5385
5767
|
`${today}-${args.benchmarkId}-${modelSlug}${profileSlug}-${gitShaShort}.json`
|
|
5386
5768
|
);
|
|
5387
5769
|
writeFileSync(target, raw, "utf8");
|
|
5388
5770
|
console.log(
|
|
5389
|
-
`[bench published] Promoted ${
|
|
5771
|
+
`[bench published] Promoted ${path13.basename(artifactPath)} \u2192 ${target}`
|
|
5390
5772
|
);
|
|
5391
5773
|
}
|
|
5392
5774
|
void benchModule;
|
|
@@ -5471,7 +5853,7 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
|
|
|
5471
5853
|
const previousCodexDiagnosticsDir = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV];
|
|
5472
5854
|
const previousCodexDiagnosticsMode = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_MODE_ENV];
|
|
5473
5855
|
if (!previousCodexDiagnosticsDir) {
|
|
5474
|
-
process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] =
|
|
5856
|
+
process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] = path12.join(
|
|
5475
5857
|
outputDir,
|
|
5476
5858
|
"codex-cli-diagnostics"
|
|
5477
5859
|
);
|
|
@@ -5609,7 +5991,7 @@ async function preparePersistedJudgeCalibrationAttachment(benchModule, benchmark
|
|
|
5609
5991
|
);
|
|
5610
5992
|
}
|
|
5611
5993
|
const calibrationDir = expandTilde(
|
|
5612
|
-
calibrationBinding.calibrationDir ??
|
|
5994
|
+
calibrationBinding.calibrationDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "calibration")
|
|
5613
5995
|
);
|
|
5614
5996
|
const state = await benchModule.loadJudgeCalibrationState?.(benchmarkId, calibrationDir);
|
|
5615
5997
|
if (!state) {
|
|
@@ -5683,7 +6065,7 @@ function attachPreparedJudgeCalibration(result, judgeCalibration) {
|
|
|
5683
6065
|
function hashCalibrationProviderConfig(config) {
|
|
5684
6066
|
const canonicalize = (value, key = "") => {
|
|
5685
6067
|
if (typeof value === "string" && /(?:api.?key|authorization|token|secret)/i.test(key)) {
|
|
5686
|
-
return { secretSha256:
|
|
6068
|
+
return { secretSha256: createHash2("sha256").update(value).digest("hex") };
|
|
5687
6069
|
}
|
|
5688
6070
|
if (Array.isArray(value)) return value.map((item) => canonicalize(item));
|
|
5689
6071
|
if (value && typeof value === "object") {
|
|
@@ -5694,7 +6076,7 @@ function hashCalibrationProviderConfig(config) {
|
|
|
5694
6076
|
}
|
|
5695
6077
|
return value;
|
|
5696
6078
|
};
|
|
5697
|
-
return
|
|
6079
|
+
return createHash2("sha256").update(JSON.stringify(canonicalize(config))).digest("hex");
|
|
5698
6080
|
}
|
|
5699
6081
|
function restoreOptionalEnv(key, previousValue) {
|
|
5700
6082
|
if (previousValue === void 0) {
|
|
@@ -5906,7 +6288,7 @@ function resolveBenchReproDatasetDir(datasetDir) {
|
|
|
5906
6288
|
return void 0;
|
|
5907
6289
|
}
|
|
5908
6290
|
try {
|
|
5909
|
-
return
|
|
6291
|
+
return fs9.realpathSync(datasetDir);
|
|
5910
6292
|
} catch {
|
|
5911
6293
|
return datasetDir;
|
|
5912
6294
|
}
|
|
@@ -5959,23 +6341,23 @@ async function writeBenchReproManifestForPackageRun(args) {
|
|
|
5959
6341
|
}
|
|
5960
6342
|
}
|
|
5961
6343
|
function resolveConfigPath(cliPath) {
|
|
5962
|
-
if (cliPath) return
|
|
6344
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
5963
6345
|
const envPath = readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH");
|
|
5964
|
-
if (envPath) return
|
|
6346
|
+
if (envPath) return path12.resolve(expandTilde(envPath));
|
|
5965
6347
|
const candidates = [
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
6348
|
+
path12.join(process.cwd(), "remnic.config.json"),
|
|
6349
|
+
path12.join(process.cwd(), "engram.config.json"),
|
|
6350
|
+
path12.join(resolveHomeDir(), ".config", "remnic", "config.json"),
|
|
6351
|
+
path12.join(resolveHomeDir(), ".config", "engram", "config.json")
|
|
5970
6352
|
];
|
|
5971
6353
|
for (const candidate of candidates) {
|
|
5972
|
-
if (
|
|
6354
|
+
if (fs9.existsSync(candidate)) return candidate;
|
|
5973
6355
|
}
|
|
5974
|
-
return
|
|
6356
|
+
return path12.join(resolveHomeDir(), ".config", "remnic", "config.json");
|
|
5975
6357
|
}
|
|
5976
6358
|
function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
5977
6359
|
const configPath = resolveConfigPath(cliPath);
|
|
5978
|
-
if (
|
|
6360
|
+
if (fs9.existsSync(configPath)) {
|
|
5979
6361
|
return configPath;
|
|
5980
6362
|
}
|
|
5981
6363
|
if (cliPath) {
|
|
@@ -5985,7 +6367,7 @@ function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
|
5985
6367
|
}
|
|
5986
6368
|
function resolveExistingBenchOpenclawConfigPath(cliPath) {
|
|
5987
6369
|
const configPath = resolveOpenclawConfigPath(cliPath);
|
|
5988
|
-
if (
|
|
6370
|
+
if (fs9.existsSync(configPath)) {
|
|
5989
6371
|
return configPath;
|
|
5990
6372
|
}
|
|
5991
6373
|
if (cliPath) {
|
|
@@ -6085,34 +6467,34 @@ async function resolvePackageBenchRuntime(benchModule, parsed, runtimeProfile) {
|
|
|
6085
6467
|
);
|
|
6086
6468
|
}
|
|
6087
6469
|
function normalizeMemoryDirPath(memoryDir) {
|
|
6088
|
-
return
|
|
6470
|
+
return path12.resolve(expandTilde(memoryDir));
|
|
6089
6471
|
}
|
|
6090
6472
|
function resolveMemoryDir() {
|
|
6091
6473
|
const configMemoryDir = (() => {
|
|
6092
6474
|
const envMemoryDir = readCompatEnv("REMNIC_MEMORY_DIR", "ENGRAM_MEMORY_DIR");
|
|
6093
6475
|
if (envMemoryDir) return normalizeMemoryDirPath(envMemoryDir);
|
|
6094
6476
|
const configPath = resolveConfigPath();
|
|
6095
|
-
const raw =
|
|
6096
|
-
const remnicCfg =
|
|
6477
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
6478
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
6097
6479
|
if (typeof remnicCfg.memoryDir === "string" && remnicCfg.memoryDir.length > 0) {
|
|
6098
6480
|
return normalizeMemoryDirPath(remnicCfg.memoryDir);
|
|
6099
6481
|
}
|
|
6100
6482
|
const home = resolveHomeDir();
|
|
6101
|
-
const standalonePath =
|
|
6102
|
-
const legacyStandalonePath =
|
|
6103
|
-
const openclawPath =
|
|
6104
|
-
if (
|
|
6105
|
-
if (
|
|
6483
|
+
const standalonePath = path12.join(home, ".remnic", "memory");
|
|
6484
|
+
const legacyStandalonePath = path12.join(home, ".engram", "memory");
|
|
6485
|
+
const openclawPath = path12.join(home, ".openclaw", "workspace", "memory", "local");
|
|
6486
|
+
if (fs9.existsSync(standalonePath)) return standalonePath;
|
|
6487
|
+
if (fs9.existsSync(legacyStandalonePath)) return legacyStandalonePath;
|
|
6106
6488
|
return openclawPath;
|
|
6107
6489
|
})();
|
|
6108
6490
|
const manifestPath = getManifestPath();
|
|
6109
|
-
if (
|
|
6491
|
+
if (fs9.existsSync(manifestPath)) {
|
|
6110
6492
|
try {
|
|
6111
6493
|
const active = getActiveSpace();
|
|
6112
6494
|
if (active?.memoryDir) {
|
|
6113
6495
|
const activeMemoryDir = normalizeMemoryDirPath(active.memoryDir);
|
|
6114
|
-
if (!
|
|
6115
|
-
|
|
6496
|
+
if (!fs9.existsSync(activeMemoryDir)) {
|
|
6497
|
+
fs9.mkdirSync(activeMemoryDir, { recursive: true });
|
|
6116
6498
|
}
|
|
6117
6499
|
return activeMemoryDir;
|
|
6118
6500
|
}
|
|
@@ -6151,20 +6533,20 @@ var REMNIC_OPENCLAW_LEGACY_PLUGIN_ID = "openclaw-engram";
|
|
|
6151
6533
|
var DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR = [
|
|
6152
6534
|
process.env.OPENCLAW_CONFIG_PATH,
|
|
6153
6535
|
process.env.OPENCLAW_ENGRAM_CONFIG_PATH,
|
|
6154
|
-
|
|
6536
|
+
path12.join(resolveHomeDir(), ".openclaw", "openclaw.json")
|
|
6155
6537
|
].filter(Boolean);
|
|
6156
6538
|
function resolveOpenclawConfigPath(cliPath) {
|
|
6157
|
-
if (cliPath) return
|
|
6539
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
6158
6540
|
const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
|
|
6159
|
-
if (envPath) return
|
|
6541
|
+
if (envPath) return path12.resolve(expandTilde(envPath));
|
|
6160
6542
|
for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
|
|
6161
|
-
if (
|
|
6543
|
+
if (fs9.existsSync(candidate)) return candidate;
|
|
6162
6544
|
}
|
|
6163
|
-
return
|
|
6545
|
+
return path12.join(resolveHomeDir(), ".openclaw", "openclaw.json");
|
|
6164
6546
|
}
|
|
6165
6547
|
function readOpenclawConfig(configPath) {
|
|
6166
|
-
if (!
|
|
6167
|
-
const raw =
|
|
6548
|
+
if (!fs9.existsSync(configPath)) return {};
|
|
6549
|
+
const raw = fs9.readFileSync(configPath, "utf-8");
|
|
6168
6550
|
let parsed;
|
|
6169
6551
|
try {
|
|
6170
6552
|
parsed = JSON.parse(raw);
|
|
@@ -6219,10 +6601,10 @@ function buildRemnicOpenclawHooksPolicy(legacyHooks, existingHooks) {
|
|
|
6219
6601
|
function resolveOpenclawInstallMemoryDir(args) {
|
|
6220
6602
|
const existingMemoryDir = (typeof args.existingNewEntryConfig.memoryDir === "string" ? args.existingNewEntryConfig.memoryDir : void 0) || (args.migrateLegacy && typeof args.legacyConfigToMerge.memoryDir === "string" ? args.legacyConfigToMerge.memoryDir : void 0);
|
|
6221
6603
|
if (args.requestedMemoryDir) {
|
|
6222
|
-
return
|
|
6604
|
+
return path12.resolve(expandTilde(args.requestedMemoryDir));
|
|
6223
6605
|
}
|
|
6224
6606
|
if (existingMemoryDir) {
|
|
6225
|
-
return
|
|
6607
|
+
return path12.resolve(expandTilde(existingMemoryDir));
|
|
6226
6608
|
}
|
|
6227
6609
|
return args.fallbackMemoryDir;
|
|
6228
6610
|
}
|
|
@@ -6240,18 +6622,18 @@ function resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir) {
|
|
|
6240
6622
|
if (!config || typeof config !== "object" || Array.isArray(config)) continue;
|
|
6241
6623
|
const memoryDir = config.memoryDir;
|
|
6242
6624
|
if (typeof memoryDir === "string" && memoryDir.trim().length > 0) {
|
|
6243
|
-
return
|
|
6625
|
+
return path12.resolve(expandTilde(memoryDir));
|
|
6244
6626
|
}
|
|
6245
6627
|
}
|
|
6246
6628
|
return fallbackMemoryDir;
|
|
6247
6629
|
}
|
|
6248
6630
|
function resolveOpenclawPluginDir(cliPath) {
|
|
6249
|
-
if (cliPath) return
|
|
6250
|
-
return
|
|
6631
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
6632
|
+
return path12.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
|
|
6251
6633
|
}
|
|
6252
6634
|
function resolveOpenclawLegacyPluginDir(cliPath) {
|
|
6253
|
-
if (cliPath) return
|
|
6254
|
-
return
|
|
6635
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
6636
|
+
return path12.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID);
|
|
6255
6637
|
}
|
|
6256
6638
|
function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
6257
6639
|
const yyyy = now.getFullYear().toString();
|
|
@@ -6263,14 +6645,14 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
|
6263
6645
|
return `${yyyy}${mm}${dd}-${hh}${min}${ss}`;
|
|
6264
6646
|
}
|
|
6265
6647
|
function backupPathIfPresent(sourcePath, backupPath) {
|
|
6266
|
-
if (!
|
|
6267
|
-
|
|
6268
|
-
|
|
6648
|
+
if (!fs9.existsSync(sourcePath)) return false;
|
|
6649
|
+
fs9.mkdirSync(path12.dirname(backupPath), { recursive: true });
|
|
6650
|
+
fs9.cpSync(sourcePath, backupPath, { recursive: true });
|
|
6269
6651
|
return true;
|
|
6270
6652
|
}
|
|
6271
6653
|
function assertDirectoryPathOrMissing(targetPath, label) {
|
|
6272
|
-
if (!
|
|
6273
|
-
const stat =
|
|
6654
|
+
if (!fs9.existsSync(targetPath)) return;
|
|
6655
|
+
const stat = fs9.statSync(targetPath);
|
|
6274
6656
|
if (!stat.isDirectory()) {
|
|
6275
6657
|
throw new Error(`${label} must be a directory when it already exists: ${targetPath}`);
|
|
6276
6658
|
}
|
|
@@ -6295,7 +6677,7 @@ var PublishedOpenclawPluginInstallError = class extends Error {
|
|
|
6295
6677
|
}
|
|
6296
6678
|
};
|
|
6297
6679
|
function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
6298
|
-
const tempRoot =
|
|
6680
|
+
const tempRoot = fs9.mkdtempSync(path12.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
|
|
6299
6681
|
const stagedDir = `${pluginDir}.next-${process.pid}-${Date.now()}`;
|
|
6300
6682
|
const rollbackDir = `${pluginDir}.rollback-${process.pid}-${Date.now()}`;
|
|
6301
6683
|
let swapRollbackDir;
|
|
@@ -6310,17 +6692,17 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6310
6692
|
if (!tarballName) {
|
|
6311
6693
|
throw new Error(`npm pack ${spec} did not return a tarball name`);
|
|
6312
6694
|
}
|
|
6313
|
-
const unpackDir =
|
|
6314
|
-
|
|
6315
|
-
childProcess2.execFileSync("tar", ["-xzf",
|
|
6695
|
+
const unpackDir = path12.join(tempRoot, "unpacked");
|
|
6696
|
+
fs9.mkdirSync(unpackDir, { recursive: true });
|
|
6697
|
+
childProcess2.execFileSync("tar", ["-xzf", path12.join(tempRoot, tarballName), "-C", unpackDir], {
|
|
6316
6698
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6317
6699
|
});
|
|
6318
|
-
const packagedDir =
|
|
6319
|
-
if (!
|
|
6700
|
+
const packagedDir = path12.join(unpackDir, "package");
|
|
6701
|
+
if (!fs9.existsSync(packagedDir)) {
|
|
6320
6702
|
throw new Error(`npm pack ${spec} did not contain a package/ directory`);
|
|
6321
6703
|
}
|
|
6322
|
-
|
|
6323
|
-
|
|
6704
|
+
fs9.rmSync(stagedDir, { recursive: true, force: true });
|
|
6705
|
+
fs9.cpSync(packagedDir, stagedDir, { recursive: true });
|
|
6324
6706
|
childProcess2.execFileSync("npm", ["install", "--omit=dev"], {
|
|
6325
6707
|
cwd: stagedDir,
|
|
6326
6708
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -6335,8 +6717,8 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6335
6717
|
}
|
|
6336
6718
|
})();
|
|
6337
6719
|
swapRollbackDir = swapResult.rollbackDir;
|
|
6338
|
-
const installedPackageJsonPath =
|
|
6339
|
-
const installedPackage =
|
|
6720
|
+
const installedPackageJsonPath = path12.join(pluginDir, "package.json");
|
|
6721
|
+
const installedPackage = fs9.existsSync(installedPackageJsonPath) ? JSON.parse(fs9.readFileSync(installedPackageJsonPath, "utf8")) : {};
|
|
6340
6722
|
return {
|
|
6341
6723
|
rollbackDir: swapRollbackDir,
|
|
6342
6724
|
version: typeof installedPackage.version === "string" ? installedPackage.version : void 0
|
|
@@ -6351,8 +6733,8 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6351
6733
|
}
|
|
6352
6734
|
);
|
|
6353
6735
|
} finally {
|
|
6354
|
-
|
|
6355
|
-
|
|
6736
|
+
fs9.rmSync(stagedDir, { recursive: true, force: true });
|
|
6737
|
+
fs9.rmSync(tempRoot, { recursive: true, force: true });
|
|
6356
6738
|
}
|
|
6357
6739
|
}
|
|
6358
6740
|
function restartOpenclawGateway() {
|
|
@@ -6370,15 +6752,15 @@ function restartOpenclawGateway() {
|
|
|
6370
6752
|
});
|
|
6371
6753
|
}
|
|
6372
6754
|
function cmdInit() {
|
|
6373
|
-
const configPath =
|
|
6374
|
-
if (
|
|
6755
|
+
const configPath = path12.join(process.cwd(), "remnic.config.json");
|
|
6756
|
+
if (fs9.existsSync(configPath)) {
|
|
6375
6757
|
console.log(`Config already exists: ${configPath}`);
|
|
6376
6758
|
return;
|
|
6377
6759
|
}
|
|
6378
6760
|
const template = {
|
|
6379
6761
|
remnic: {
|
|
6380
6762
|
openaiApiKey: "${OPENAI_API_KEY}",
|
|
6381
|
-
memoryDir:
|
|
6763
|
+
memoryDir: path12.join(process.cwd(), ".remnic", "memory"),
|
|
6382
6764
|
memoryOsPreset: "balanced"
|
|
6383
6765
|
},
|
|
6384
6766
|
server: {
|
|
@@ -6387,7 +6769,7 @@ function cmdInit() {
|
|
|
6387
6769
|
authToken: "${REMNIC_AUTH_TOKEN}"
|
|
6388
6770
|
}
|
|
6389
6771
|
};
|
|
6390
|
-
|
|
6772
|
+
fs9.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
|
|
6391
6773
|
console.log(`Created ${configPath}`);
|
|
6392
6774
|
console.log("\nSet these environment variables:");
|
|
6393
6775
|
console.log(" export OPENAI_API_KEY=sk-...");
|
|
@@ -6396,6 +6778,18 @@ function cmdInit() {
|
|
|
6396
6778
|
console.log("\nThen start the server:");
|
|
6397
6779
|
console.log(" npx --package @remnic/server remnic-server");
|
|
6398
6780
|
}
|
|
6781
|
+
function resolveStatusProbeToken() {
|
|
6782
|
+
const operatorToken = oauthResolveOperatorToken();
|
|
6783
|
+
if (operatorToken) return operatorToken;
|
|
6784
|
+
try {
|
|
6785
|
+
const usable = listTokens().find(
|
|
6786
|
+
(t) => t.connector !== "chatgpt" && typeof t.token === "string" && t.token.length > 0
|
|
6787
|
+
);
|
|
6788
|
+
if (usable) return usable.token;
|
|
6789
|
+
} catch {
|
|
6790
|
+
}
|
|
6791
|
+
}
|
|
6792
|
+
var __statusHealthTestHooks = { resolveStatusProbeToken };
|
|
6399
6793
|
async function cmdStatus(json) {
|
|
6400
6794
|
const { running, pid } = isServiceRunning();
|
|
6401
6795
|
if (json) {
|
|
@@ -6408,18 +6802,34 @@ async function cmdStatus(json) {
|
|
|
6408
6802
|
}
|
|
6409
6803
|
console.log(`Remnic server: running${pid ? ` (pid ${pid})` : ""}`);
|
|
6410
6804
|
const port = inferPort();
|
|
6805
|
+
const probeToken = resolveStatusProbeToken();
|
|
6411
6806
|
const controller = new AbortController();
|
|
6412
6807
|
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
6413
6808
|
try {
|
|
6414
6809
|
const response = await fetch(`http://127.0.0.1:${port}/engram/v1/health`, {
|
|
6415
|
-
signal: controller.signal
|
|
6810
|
+
signal: controller.signal,
|
|
6811
|
+
...probeToken ? { headers: { Authorization: `Bearer ${probeToken}` } } : {}
|
|
6416
6812
|
});
|
|
6417
6813
|
if (!response.ok) {
|
|
6418
|
-
|
|
6814
|
+
const hint = response.status === 401 && !probeToken ? " (daemon requires auth and no local token was found \u2014 set REMNIC_AUTH_TOKEN, configure server.authToken, or run 'remnic token generate')" : response.status === 401 ? " (local token rejected by the daemon)" : "";
|
|
6815
|
+
console.log(`Health: server responded with ${response.status} ${response.statusText}${hint}`);
|
|
6419
6816
|
} else {
|
|
6420
6817
|
const health = await response.json();
|
|
6421
6818
|
const status = typeof health.status === "string" ? health.status : "ok";
|
|
6422
6819
|
console.log(`Health: ${status}`);
|
|
6820
|
+
const qmd = health.qmd;
|
|
6821
|
+
if (qmd?.pendingEmbeddings != null) {
|
|
6822
|
+
console.log(` Pending embeddings: ${qmd.pendingEmbeddings}`);
|
|
6823
|
+
if (qmd.oldestPendingAgeMs != null) {
|
|
6824
|
+
console.log(` Oldest pending: ${Math.round(qmd.oldestPendingAgeMs / 6e4)}m`);
|
|
6825
|
+
}
|
|
6826
|
+
if (qmd.embeddingBacklogThreshold != null) {
|
|
6827
|
+
console.log(` Backlog threshold: ${qmd.embeddingBacklogThreshold}`);
|
|
6828
|
+
}
|
|
6829
|
+
}
|
|
6830
|
+
if (qmd?.degradedReason) {
|
|
6831
|
+
console.log(` Degraded: ${qmd.degradedReason}`);
|
|
6832
|
+
}
|
|
6423
6833
|
}
|
|
6424
6834
|
} catch {
|
|
6425
6835
|
console.log("Health: unable to reach server");
|
|
@@ -6429,7 +6839,7 @@ async function cmdStatus(json) {
|
|
|
6429
6839
|
}
|
|
6430
6840
|
function oauthReadConfigRecord(configPath) {
|
|
6431
6841
|
try {
|
|
6432
|
-
const parsed = JSON.parse(
|
|
6842
|
+
const parsed = JSON.parse(fs9.readFileSync(configPath, "utf8"));
|
|
6433
6843
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
6434
6844
|
return parsed;
|
|
6435
6845
|
}
|
|
@@ -6480,14 +6890,14 @@ function oauthResolveOperatorToken() {
|
|
|
6480
6890
|
const server = raw.server;
|
|
6481
6891
|
if (server && typeof server === "object" && "authToken" in server) {
|
|
6482
6892
|
const candidate = server.authToken;
|
|
6483
|
-
if (typeof candidate === "string" && candidate.length > 0) {
|
|
6893
|
+
if (typeof candidate === "string" && candidate.length > 0 && !candidate.includes("${")) {
|
|
6484
6894
|
return candidate;
|
|
6485
6895
|
}
|
|
6486
6896
|
}
|
|
6487
6897
|
}
|
|
6488
6898
|
return void 0;
|
|
6489
6899
|
}
|
|
6490
|
-
async function oauthFetch(method,
|
|
6900
|
+
async function oauthFetch(method, path13, token, body) {
|
|
6491
6901
|
const controller = new AbortController();
|
|
6492
6902
|
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
6493
6903
|
try {
|
|
@@ -6506,7 +6916,7 @@ async function oauthFetch(method, path12, token, body) {
|
|
|
6506
6916
|
if (body !== void 0) {
|
|
6507
6917
|
init.body = JSON.stringify(body);
|
|
6508
6918
|
}
|
|
6509
|
-
const response = await fetch(`${oauthResolveBaseUrl()}${
|
|
6919
|
+
const response = await fetch(`${oauthResolveBaseUrl()}${path13}`, init);
|
|
6510
6920
|
if (response.status === 401) {
|
|
6511
6921
|
throw new Error(
|
|
6512
6922
|
"operator token rejected by remnic-server (HTTP 401). Update `server.authToken` or `REMNIC_AUTH_TOKEN` to match the running daemon."
|
|
@@ -6845,9 +7255,9 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
6845
7255
|
}
|
|
6846
7256
|
initLogger();
|
|
6847
7257
|
const configPath = resolveConfigPath();
|
|
6848
|
-
const raw =
|
|
6849
|
-
const remnicCfg =
|
|
6850
|
-
const config =
|
|
7258
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
7259
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7260
|
+
const config = parseConfig2(remnicCfg);
|
|
6851
7261
|
const orchestrator = new Orchestrator(config);
|
|
6852
7262
|
await orchestrator.initialize();
|
|
6853
7263
|
const service = new EngramAccessService(orchestrator);
|
|
@@ -7016,9 +7426,9 @@ async function cmdXray(rest) {
|
|
|
7016
7426
|
parseXrayCliOptions(rawQuery, options);
|
|
7017
7427
|
initLogger();
|
|
7018
7428
|
const configPath = resolveConfigPath();
|
|
7019
|
-
const raw =
|
|
7020
|
-
const remnicCfg =
|
|
7021
|
-
const config =
|
|
7429
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
7430
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7431
|
+
const config = parseConfig2(remnicCfg);
|
|
7022
7432
|
const orchestrator = new Orchestrator(config);
|
|
7023
7433
|
await orchestrator.initialize();
|
|
7024
7434
|
await orchestrator.deferredReady;
|
|
@@ -7039,9 +7449,9 @@ async function cmdXray(rest) {
|
|
|
7039
7449
|
async function cmdVersions(rest) {
|
|
7040
7450
|
initLogger();
|
|
7041
7451
|
const configPath = resolveConfigPath();
|
|
7042
|
-
const raw =
|
|
7043
|
-
const remnicCfg =
|
|
7044
|
-
const config =
|
|
7452
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
7453
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7454
|
+
const config = parseConfig2(remnicCfg);
|
|
7045
7455
|
if (!config.versioningEnabled) {
|
|
7046
7456
|
console.error("Page versioning is disabled (versioningEnabled = false).");
|
|
7047
7457
|
process.exit(1);
|
|
@@ -7061,7 +7471,7 @@ async function cmdVersions(rest) {
|
|
|
7061
7471
|
console.error("Usage: remnic versions list <page-path>");
|
|
7062
7472
|
process.exit(1);
|
|
7063
7473
|
}
|
|
7064
|
-
const absPath =
|
|
7474
|
+
const absPath = path12.resolve(pagePath);
|
|
7065
7475
|
const history = await listVersions(absPath, versioningConfig, memDir);
|
|
7066
7476
|
if (json) {
|
|
7067
7477
|
console.log(JSON.stringify(history, null, 2));
|
|
@@ -7086,7 +7496,7 @@ async function cmdVersions(rest) {
|
|
|
7086
7496
|
console.error("Usage: remnic versions show <page-path> <version-id>");
|
|
7087
7497
|
process.exit(1);
|
|
7088
7498
|
}
|
|
7089
|
-
const absPath =
|
|
7499
|
+
const absPath = path12.resolve(pagePath);
|
|
7090
7500
|
try {
|
|
7091
7501
|
const content = await getVersion(absPath, versionId, versioningConfig, memDir);
|
|
7092
7502
|
console.log(content);
|
|
@@ -7104,7 +7514,7 @@ async function cmdVersions(rest) {
|
|
|
7104
7514
|
console.error("Usage: remnic versions diff <page-path> <v1> <v2>");
|
|
7105
7515
|
process.exit(1);
|
|
7106
7516
|
}
|
|
7107
|
-
const absPath =
|
|
7517
|
+
const absPath = path12.resolve(pagePath);
|
|
7108
7518
|
try {
|
|
7109
7519
|
const diffOutput = await diffVersions(absPath, v1, v2, versioningConfig, memDir);
|
|
7110
7520
|
console.log(diffOutput);
|
|
@@ -7121,7 +7531,7 @@ async function cmdVersions(rest) {
|
|
|
7121
7531
|
console.error("Usage: remnic versions revert <page-path> <version-id>");
|
|
7122
7532
|
process.exit(1);
|
|
7123
7533
|
}
|
|
7124
|
-
const absPath =
|
|
7534
|
+
const absPath = path12.resolve(pagePath);
|
|
7125
7535
|
try {
|
|
7126
7536
|
const version = await revertToVersion(absPath, versionId, versioningConfig, void 0, memDir);
|
|
7127
7537
|
if (json) {
|
|
@@ -7155,13 +7565,13 @@ Options:
|
|
|
7155
7565
|
async function cmdEnrich(rest) {
|
|
7156
7566
|
initLogger();
|
|
7157
7567
|
const configPath = resolveConfigPath();
|
|
7158
|
-
const raw =
|
|
7159
|
-
const remnicCfg =
|
|
7160
|
-
const config =
|
|
7568
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
7569
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7570
|
+
const config = parseConfig2(remnicCfg);
|
|
7161
7571
|
const subcommand = rest[0];
|
|
7162
7572
|
if (subcommand === "audit") {
|
|
7163
7573
|
const memoryDir2 = expandTilde(config.memoryDir);
|
|
7164
|
-
const auditDir2 =
|
|
7574
|
+
const auditDir2 = path12.join(memoryDir2, "enrichment");
|
|
7165
7575
|
const sinceFlag = resolveFlag(rest.slice(1), "--since");
|
|
7166
7576
|
const entries = await readAuditLog(auditDir2, sinceFlag ?? void 0);
|
|
7167
7577
|
if (entries.length === 0) {
|
|
@@ -7286,18 +7696,13 @@ Registered providers:`);
|
|
|
7286
7696
|
return;
|
|
7287
7697
|
}
|
|
7288
7698
|
const memoryDir = expandTilde(config.memoryDir);
|
|
7289
|
-
const auditDir =
|
|
7699
|
+
const auditDir = path12.join(memoryDir, "enrichment");
|
|
7290
7700
|
let totalPersisted = 0;
|
|
7291
7701
|
for (const result of results) {
|
|
7292
7702
|
for (const candidate of result.acceptedCandidates) {
|
|
7293
7703
|
let persisted = false;
|
|
7294
7704
|
try {
|
|
7295
|
-
await storage
|
|
7296
|
-
confidence: candidate.confidence,
|
|
7297
|
-
tags: [...candidate.tags ?? [], "enrichment", candidate.source],
|
|
7298
|
-
entityRef: result.entityName,
|
|
7299
|
-
source: `enrichment:${candidate.source}`
|
|
7300
|
-
});
|
|
7705
|
+
await persistEnrichmentCandidate(storage, result.entityName, candidate);
|
|
7301
7706
|
persisted = true;
|
|
7302
7707
|
totalPersisted++;
|
|
7303
7708
|
} catch (err) {
|
|
@@ -7405,13 +7810,13 @@ Shared with:
|
|
|
7405
7810
|
process.exit(1);
|
|
7406
7811
|
}
|
|
7407
7812
|
const configPath = resolveConfigPath();
|
|
7408
|
-
const raw =
|
|
7409
|
-
const remnicCfg =
|
|
7410
|
-
const config =
|
|
7813
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
7814
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7815
|
+
const config = parseConfig2(remnicCfg);
|
|
7411
7816
|
const memoryDir = expandTilde(
|
|
7412
7817
|
typeof memoryDirOverride === "string" && memoryDirOverride.length > 0 ? memoryDirOverride : config.memoryDir ?? resolveMemoryDir()
|
|
7413
7818
|
);
|
|
7414
|
-
const storage = new
|
|
7819
|
+
const storage = new StorageManager2(memoryDir);
|
|
7415
7820
|
const report = await computeProcedureStats({ storage, config });
|
|
7416
7821
|
if (format === "json") {
|
|
7417
7822
|
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
@@ -7422,9 +7827,9 @@ Shared with:
|
|
|
7422
7827
|
async function cmdExtensions(action, rest) {
|
|
7423
7828
|
initLogger();
|
|
7424
7829
|
const configPath = resolveConfigPath();
|
|
7425
|
-
const raw =
|
|
7426
|
-
const remnicCfg =
|
|
7427
|
-
const config =
|
|
7830
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
7831
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7832
|
+
const config = parseConfig2(remnicCfg);
|
|
7428
7833
|
const root = resolveExtensionsRoot(config);
|
|
7429
7834
|
const noopLog = { warn: () => {
|
|
7430
7835
|
}, debug: () => {
|
|
@@ -7473,7 +7878,7 @@ Root: ${root}`);
|
|
|
7473
7878
|
const extensions = await discoverMemoryExtensions(root, warnLog);
|
|
7474
7879
|
let entries = [];
|
|
7475
7880
|
try {
|
|
7476
|
-
entries =
|
|
7881
|
+
entries = fs9.readdirSync(root);
|
|
7477
7882
|
} catch {
|
|
7478
7883
|
console.log(`Extensions root does not exist: ${root}`);
|
|
7479
7884
|
process.exitCode = 0;
|
|
@@ -7482,9 +7887,9 @@ Root: ${root}`);
|
|
|
7482
7887
|
const validNames = new Set(extensions.map((e) => e.name));
|
|
7483
7888
|
let errors = 0;
|
|
7484
7889
|
for (const entry of entries) {
|
|
7485
|
-
const entryPath =
|
|
7890
|
+
const entryPath = path12.join(root, entry);
|
|
7486
7891
|
try {
|
|
7487
|
-
if (!
|
|
7892
|
+
if (!fs9.statSync(entryPath).isDirectory()) continue;
|
|
7488
7893
|
} catch {
|
|
7489
7894
|
continue;
|
|
7490
7895
|
}
|
|
@@ -7516,9 +7921,9 @@ Root: ${root}`);
|
|
|
7516
7921
|
async function cmdBriefing(rest) {
|
|
7517
7922
|
initLogger();
|
|
7518
7923
|
const configPath = resolveConfigPath();
|
|
7519
|
-
const raw =
|
|
7520
|
-
const remnicCfg =
|
|
7521
|
-
const config =
|
|
7924
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
7925
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7926
|
+
const config = parseConfig2(remnicCfg);
|
|
7522
7927
|
if (!config.briefing.enabled) {
|
|
7523
7928
|
console.error("Briefing is disabled in config (briefing.enabled = false).");
|
|
7524
7929
|
process.exit(1);
|
|
@@ -7596,10 +8001,10 @@ async function cmdBriefing(rest) {
|
|
|
7596
8001
|
if (save) {
|
|
7597
8002
|
try {
|
|
7598
8003
|
const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
|
|
7599
|
-
|
|
8004
|
+
fs9.mkdirSync(saveDir, { recursive: true });
|
|
7600
8005
|
const filename = briefingFilename(new Date(result.window.to), format);
|
|
7601
|
-
const filePath =
|
|
7602
|
-
|
|
8006
|
+
const filePath = path12.join(saveDir, filename);
|
|
8007
|
+
fs9.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
|
|
7603
8008
|
console.error(`Saved briefing: ${filePath}`);
|
|
7604
8009
|
} catch (err) {
|
|
7605
8010
|
console.error(`Failed to save briefing: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -7617,17 +8022,19 @@ async function cmdDoctor() {
|
|
|
7617
8022
|
detail: `${nodeVersion} (requires >= 22.12.0)`
|
|
7618
8023
|
});
|
|
7619
8024
|
const configPath = resolveConfigPath();
|
|
7620
|
-
const configExists =
|
|
8025
|
+
const configExists = fs9.existsSync(configPath);
|
|
7621
8026
|
checks.push({ name: "Config file", ok: configExists, detail: configPath });
|
|
7622
8027
|
let standaloneConfig;
|
|
7623
8028
|
let standaloneConfigError;
|
|
7624
8029
|
let standaloneOpenaiApiKeyExplicitlyFalse = false;
|
|
8030
|
+
let configuredNs = { invalid: false };
|
|
7625
8031
|
if (configExists) {
|
|
7626
8032
|
try {
|
|
7627
|
-
const raw = JSON.parse(
|
|
7628
|
-
const remnicCfg =
|
|
8033
|
+
const raw = JSON.parse(fs9.readFileSync(configPath, "utf8"));
|
|
8034
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
7629
8035
|
standaloneOpenaiApiKeyExplicitlyFalse = isOpenaiApiKeyDisabled(remnicCfg.openaiApiKey);
|
|
7630
|
-
|
|
8036
|
+
configuredNs = readConfiguredNamespace(remnicCfg);
|
|
8037
|
+
standaloneConfig = parseConfig2(remnicCfg);
|
|
7631
8038
|
} catch (err) {
|
|
7632
8039
|
standaloneConfigError = err instanceof Error ? err.message : String(err);
|
|
7633
8040
|
}
|
|
@@ -7636,16 +8043,39 @@ async function cmdDoctor() {
|
|
|
7636
8043
|
try {
|
|
7637
8044
|
memoryDir = resolveMemoryDir();
|
|
7638
8045
|
} catch {
|
|
7639
|
-
memoryDir =
|
|
8046
|
+
memoryDir = parseConfig2({}).memoryDir;
|
|
7640
8047
|
}
|
|
7641
8048
|
try {
|
|
7642
|
-
|
|
8049
|
+
fs9.mkdirSync(memoryDir, { recursive: true });
|
|
7643
8050
|
checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
|
|
7644
8051
|
} catch {
|
|
7645
8052
|
checks.push({ name: "Memory directory", ok: false, detail: `cannot create ${memoryDir}` });
|
|
7646
8053
|
}
|
|
8054
|
+
try {
|
|
8055
|
+
const quarantined = await new WriteQuarantineStore(memoryDir).count();
|
|
8056
|
+
checks.push({
|
|
8057
|
+
name: "Quarantined writes",
|
|
8058
|
+
ok: quarantined === 0,
|
|
8059
|
+
warn: quarantined > 0,
|
|
8060
|
+
detail: quarantined === 0 ? "none" : `${quarantined} parked`,
|
|
8061
|
+
remediation: quarantined > 0 ? "Inspect with `remnic quarantine list`, then fix the client's namespace config so writes are stored instead of parked." : void 0
|
|
8062
|
+
});
|
|
8063
|
+
} catch {
|
|
8064
|
+
checks.push({
|
|
8065
|
+
name: "Quarantined writes",
|
|
8066
|
+
ok: false,
|
|
8067
|
+
warn: true,
|
|
8068
|
+
detail: "unable to inspect quarantine store"
|
|
8069
|
+
});
|
|
8070
|
+
}
|
|
8071
|
+
const nsPolicyCheck = buildNamespacePolicyCheck({
|
|
8072
|
+
invalid: configuredNs.invalid,
|
|
8073
|
+
configuredNamespace: configuredNs.configuredNamespace,
|
|
8074
|
+
config: standaloneConfig
|
|
8075
|
+
});
|
|
8076
|
+
if (nsPolicyCheck) checks.push(nsPolicyCheck);
|
|
7647
8077
|
const openclawConfigPath = resolveOpenclawConfigPath();
|
|
7648
|
-
const openclawConfigExists =
|
|
8078
|
+
const openclawConfigExists = fs9.existsSync(openclawConfigPath);
|
|
7649
8079
|
let openclawConfig = {};
|
|
7650
8080
|
let openclawConfigValid = false;
|
|
7651
8081
|
let openclawPluginModeConfigured = false;
|
|
@@ -7653,7 +8083,7 @@ async function cmdDoctor() {
|
|
|
7653
8083
|
let activeOpenclawEntryConfig = null;
|
|
7654
8084
|
if (openclawConfigExists) {
|
|
7655
8085
|
try {
|
|
7656
|
-
const parsed = JSON.parse(
|
|
8086
|
+
const parsed = JSON.parse(fs9.readFileSync(openclawConfigPath, "utf-8"));
|
|
7657
8087
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
7658
8088
|
openclawConfig = parsed;
|
|
7659
8089
|
openclawConfigValid = true;
|
|
@@ -7729,13 +8159,13 @@ async function cmdDoctor() {
|
|
|
7729
8159
|
const rawMemoryDir = entryConfig?.memoryDir;
|
|
7730
8160
|
const configuredMemoryDir = typeof rawMemoryDir === "string" ? rawMemoryDir : void 0;
|
|
7731
8161
|
if (configuredMemoryDir) {
|
|
7732
|
-
const resolvedMemDir =
|
|
8162
|
+
const resolvedMemDir = path12.resolve(expandTilde(configuredMemoryDir));
|
|
7733
8163
|
let memDirOk = false;
|
|
7734
8164
|
let memDirDetail = `${resolvedMemDir} (not found)`;
|
|
7735
8165
|
let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
|
|
7736
|
-
if (
|
|
8166
|
+
if (fs9.existsSync(resolvedMemDir)) {
|
|
7737
8167
|
try {
|
|
7738
|
-
const stat =
|
|
8168
|
+
const stat = fs9.statSync(resolvedMemDir);
|
|
7739
8169
|
if (stat.isDirectory()) {
|
|
7740
8170
|
memDirOk = true;
|
|
7741
8171
|
memDirDetail = resolvedMemDir;
|
|
@@ -7877,12 +8307,12 @@ async function cmdDoctor() {
|
|
|
7877
8307
|
}
|
|
7878
8308
|
function cmdConfig() {
|
|
7879
8309
|
const configPath = resolveConfigPath();
|
|
7880
|
-
if (!
|
|
8310
|
+
if (!fs9.existsSync(configPath)) {
|
|
7881
8311
|
console.log("No config file found. Run `remnic init` to create one.");
|
|
7882
8312
|
return;
|
|
7883
8313
|
}
|
|
7884
8314
|
console.log(`Config: ${configPath}`);
|
|
7885
|
-
const rawConfig =
|
|
8315
|
+
const rawConfig = fs9.readFileSync(configPath, "utf8");
|
|
7886
8316
|
const redacted = rawConfig.replace(
|
|
7887
8317
|
/("(?:openaiApiKey|localLlmApiKey|authToken|apiKey|remoteSearchApiKey|meilisearchApiKey|opikApiKey)"\s*:\s*")([^"]*)(")/g,
|
|
7888
8318
|
"$1[REDACTED]$3"
|
|
@@ -7929,7 +8359,7 @@ async function cmdMigrate(json, rollback) {
|
|
|
7929
8359
|
console.log(` Rollback: ${result.rollbackCommand}`);
|
|
7930
8360
|
}
|
|
7931
8361
|
function cmdOnboard(dirPath, json) {
|
|
7932
|
-
const directory =
|
|
8362
|
+
const directory = path12.resolve(dirPath || process.cwd());
|
|
7933
8363
|
const result = onboard({ directory });
|
|
7934
8364
|
if (json) {
|
|
7935
8365
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -7948,7 +8378,7 @@ Suggested namespace: ${result.plan.suggestedNamespace}`);
|
|
|
7948
8378
|
async function cmdCurate(targetPath, json) {
|
|
7949
8379
|
const memoryDir = resolveMemoryDir();
|
|
7950
8380
|
const result = await curate({
|
|
7951
|
-
targetPath:
|
|
8381
|
+
targetPath: path12.resolve(targetPath),
|
|
7952
8382
|
memoryDir,
|
|
7953
8383
|
source: "curation",
|
|
7954
8384
|
checkDuplicates: true,
|
|
@@ -7986,13 +8416,13 @@ async function cmdReview(action, rest) {
|
|
|
7986
8416
|
console.error("Usage: remnic review <approve|dismiss|flag> <id>");
|
|
7987
8417
|
process.exit(1);
|
|
7988
8418
|
}
|
|
7989
|
-
const storage = new
|
|
8419
|
+
const storage = new StorageManager2(memoryDir);
|
|
7990
8420
|
const configPath = resolveConfigPath();
|
|
7991
8421
|
let tombstonesConfig = null;
|
|
7992
8422
|
try {
|
|
7993
|
-
const rawCfg =
|
|
7994
|
-
const remnicCfg =
|
|
7995
|
-
const config =
|
|
8423
|
+
const rawCfg = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
8424
|
+
const remnicCfg = resolveRemnicConfigRecord2(rawCfg);
|
|
8425
|
+
const config = parseConfig2(remnicCfg);
|
|
7996
8426
|
tombstonesConfig = {
|
|
7997
8427
|
enabled: config.tombstonesEnabled,
|
|
7998
8428
|
semanticMatch: config.tombstonesSemanticMatch,
|
|
@@ -8078,7 +8508,7 @@ async function cmdSync(action, rest, json) {
|
|
|
8078
8508
|
}
|
|
8079
8509
|
function localOfflineSourceId(memoryDir) {
|
|
8080
8510
|
const host = os.hostname() || "unknown-host";
|
|
8081
|
-
const dirHash =
|
|
8511
|
+
const dirHash = createHash2("sha256").update(path12.resolve(memoryDir)).digest("hex").slice(0, 16);
|
|
8082
8512
|
return `remnic-local:${host}:${dirHash}`;
|
|
8083
8513
|
}
|
|
8084
8514
|
function normalizeOfflineRemoteUrl(raw) {
|
|
@@ -8476,10 +8906,10 @@ var OFFLINE_SYNC_CONTENT_MISSING_RETRY_MAX = 3;
|
|
|
8476
8906
|
var OFFLINE_SYNC_CONTENT_MISSING_RETRY_DELAY_MS = 250;
|
|
8477
8907
|
var OfflineRemoteFileChangedError = class extends Error {
|
|
8478
8908
|
path;
|
|
8479
|
-
constructor(
|
|
8480
|
-
super(`remote file changed while fetching offline content: ${
|
|
8909
|
+
constructor(path13) {
|
|
8910
|
+
super(`remote file changed while fetching offline content: ${path13}`);
|
|
8481
8911
|
this.name = "OfflineRemoteFileChangedError";
|
|
8482
|
-
this.path =
|
|
8912
|
+
this.path = path13;
|
|
8483
8913
|
}
|
|
8484
8914
|
};
|
|
8485
8915
|
function isOfflineRemoteFileChangedError(error) {
|
|
@@ -8670,15 +9100,15 @@ function offlineDirectPushFiles(options) {
|
|
|
8670
9100
|
}).sort((left, right) => right.bytes - left.bytes || left.path.localeCompare(right.path));
|
|
8671
9101
|
}
|
|
8672
9102
|
function resolveOfflineDirectHydrationPath(memoryDir, relPath) {
|
|
8673
|
-
const base =
|
|
8674
|
-
const target =
|
|
8675
|
-
const relative =
|
|
8676
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
9103
|
+
const base = path12.resolve(memoryDir);
|
|
9104
|
+
const target = path12.resolve(base, relPath);
|
|
9105
|
+
const relative = path12.relative(base, target);
|
|
9106
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path12.sep}`) || path12.isAbsolute(relative)) {
|
|
8677
9107
|
throw new Error(`offline sync direct hydration path escapes memory dir: ${relPath}`);
|
|
8678
9108
|
}
|
|
8679
9109
|
return target;
|
|
8680
9110
|
}
|
|
8681
|
-
var OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES =
|
|
9111
|
+
var OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES = OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2;
|
|
8682
9112
|
async function pushOfflineFileContent(args) {
|
|
8683
9113
|
if (args.readFileChunks) {
|
|
8684
9114
|
return pushOfflineFileContentFromChunkReader(args);
|
|
@@ -8686,7 +9116,7 @@ async function pushOfflineFileContent(args) {
|
|
|
8686
9116
|
let offset = 0;
|
|
8687
9117
|
let finalResult = null;
|
|
8688
9118
|
let remoteSatisfiedResult = null;
|
|
8689
|
-
const hash =
|
|
9119
|
+
const hash = createHash2("sha256");
|
|
8690
9120
|
let bytes = 0;
|
|
8691
9121
|
while (offset < args.file.bytes || args.file.bytes === 0 && offset === 0) {
|
|
8692
9122
|
const chunk = await readOfflineSyncFileContentChunk({
|
|
@@ -8743,13 +9173,13 @@ async function pushOfflineFileContent(args) {
|
|
|
8743
9173
|
}
|
|
8744
9174
|
async function pushOfflineFileContentFromChunkReader(args) {
|
|
8745
9175
|
const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
|
|
8746
|
-
const stat =
|
|
9176
|
+
const stat = fs9.statSync(filePath);
|
|
8747
9177
|
if (stat.mtimeMs !== args.file.mtimeMs) {
|
|
8748
9178
|
throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
|
|
8749
9179
|
}
|
|
8750
|
-
const hash =
|
|
9180
|
+
const hash = createHash2("sha256");
|
|
8751
9181
|
const chunks = args.readFileChunks({
|
|
8752
|
-
root:
|
|
9182
|
+
root: path12.resolve(args.memoryDir),
|
|
8753
9183
|
path: args.file.path,
|
|
8754
9184
|
filePath,
|
|
8755
9185
|
chunkSize: OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES
|
|
@@ -9187,147 +9617,6 @@ function waitForOfflineInterval(ms, setCancel) {
|
|
|
9187
9617
|
});
|
|
9188
9618
|
});
|
|
9189
9619
|
}
|
|
9190
|
-
async function createOfflineStorageIo(memoryDir) {
|
|
9191
|
-
const storage = new StorageManager(memoryDir);
|
|
9192
|
-
const header = await readHeader(memoryDir);
|
|
9193
|
-
let secureStoreKey = null;
|
|
9194
|
-
if (header) {
|
|
9195
|
-
storage.setSecureStoreRequired(true);
|
|
9196
|
-
const key = keyring.getKey(secureStoreDir(memoryDir));
|
|
9197
|
-
if (key) {
|
|
9198
|
-
storage.setSecureStoreKey(key);
|
|
9199
|
-
secureStoreKey = key;
|
|
9200
|
-
}
|
|
9201
|
-
}
|
|
9202
|
-
return {
|
|
9203
|
-
readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
|
|
9204
|
-
readFileDigest: async ({ filePath }) => {
|
|
9205
|
-
const hash = createHash("sha256");
|
|
9206
|
-
let bytes = 0;
|
|
9207
|
-
for await (const rawChunk of readOfflineSyncFileChunks({
|
|
9208
|
-
filePath,
|
|
9209
|
-
memoryDir,
|
|
9210
|
-
secureStoreKey,
|
|
9211
|
-
chunkSize: OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES
|
|
9212
|
-
})) {
|
|
9213
|
-
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
9214
|
-
hash.update(chunk);
|
|
9215
|
-
bytes += chunk.length;
|
|
9216
|
-
}
|
|
9217
|
-
return {
|
|
9218
|
-
sha256: hash.digest("hex"),
|
|
9219
|
-
bytes
|
|
9220
|
-
};
|
|
9221
|
-
},
|
|
9222
|
-
readFileChunks: ({ filePath, chunkSize }) => readOfflineSyncFileChunks({
|
|
9223
|
-
filePath,
|
|
9224
|
-
memoryDir,
|
|
9225
|
-
secureStoreKey,
|
|
9226
|
-
chunkSize
|
|
9227
|
-
}),
|
|
9228
|
-
writeFile: async ({ filePath, content }) => storage.writeOfflineSyncFile(filePath, content),
|
|
9229
|
-
writeStagingFile: async ({ filePath, content }) => storage.writeOfflineSyncStagingFile(filePath, content),
|
|
9230
|
-
writeFileChunks: async ({ filePath, chunks }) => storage.writeOfflineSyncFileChunks(filePath, chunks),
|
|
9231
|
-
deleteFile: async ({ filePath }) => storage.deleteOfflineSyncFile(filePath)
|
|
9232
|
-
};
|
|
9233
|
-
}
|
|
9234
|
-
async function* readOfflineSyncFileChunks(options) {
|
|
9235
|
-
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE);
|
|
9236
|
-
if (!isEncryptedFile(header)) {
|
|
9237
|
-
yield* readPlainOfflineFileChunks(options.filePath, options.chunkSize);
|
|
9238
|
-
return;
|
|
9239
|
-
}
|
|
9240
|
-
if (!options.secureStoreKey) {
|
|
9241
|
-
throw new SecureStoreLockedError(
|
|
9242
|
-
`secure-store is locked \u2014 cannot read encrypted file at ${options.filePath}. Run \`remnic secure-store unlock\` to decrypt.`
|
|
9243
|
-
);
|
|
9244
|
-
}
|
|
9245
|
-
yield* readEncryptedOfflineFileChunks({
|
|
9246
|
-
filePath: options.filePath,
|
|
9247
|
-
memoryDir: options.memoryDir,
|
|
9248
|
-
key: options.secureStoreKey,
|
|
9249
|
-
chunkSize: options.chunkSize
|
|
9250
|
-
});
|
|
9251
|
-
}
|
|
9252
|
-
async function readFilePrefix(filePath, length) {
|
|
9253
|
-
const handle = await fs7.promises.open(filePath, "r");
|
|
9254
|
-
try {
|
|
9255
|
-
const out = Buffer.alloc(length);
|
|
9256
|
-
const { bytesRead } = await handle.read(out, 0, length, 0);
|
|
9257
|
-
return out.subarray(0, bytesRead);
|
|
9258
|
-
} finally {
|
|
9259
|
-
await handle.close();
|
|
9260
|
-
}
|
|
9261
|
-
}
|
|
9262
|
-
async function* readPlainOfflineFileChunks(filePath, chunkSize) {
|
|
9263
|
-
const stream = fs7.createReadStream(filePath, { highWaterMark: chunkSize });
|
|
9264
|
-
for await (const chunk of stream) {
|
|
9265
|
-
yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
9266
|
-
}
|
|
9267
|
-
}
|
|
9268
|
-
async function* readEncryptedOfflineFileChunks(options) {
|
|
9269
|
-
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
|
|
9270
|
-
if (header.length < MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE || !isEncryptedFile(header)) {
|
|
9271
|
-
throw new Error(`secure-store encrypted file is truncated: ${options.filePath}`);
|
|
9272
|
-
}
|
|
9273
|
-
const version = header.readUInt8(MAGIC_BYTES.length);
|
|
9274
|
-
const flags = header.readUInt8(MAGIC_BYTES.length + 1);
|
|
9275
|
-
if (version !== FILE_FORMAT_VERSION) {
|
|
9276
|
-
throw new Error(`secure-store file has unsupported version ${version}: ${options.filePath}`);
|
|
9277
|
-
}
|
|
9278
|
-
if (flags !== FILE_FORMAT_FLAGS) {
|
|
9279
|
-
throw new Error(`secure-store file has unsupported flags 0x${flags.toString(16)}: ${options.filePath}`);
|
|
9280
|
-
}
|
|
9281
|
-
const envelopeHeader = header.subarray(MAGIC_HEADER_SIZE);
|
|
9282
|
-
const envelopeVersion = envelopeHeader.readUInt8(ENVELOPE_LAYOUT.version);
|
|
9283
|
-
if (envelopeVersion !== ENVELOPE_VERSION) {
|
|
9284
|
-
throw new Error(`secure-store envelope has unsupported version ${envelopeVersion}: ${options.filePath}`);
|
|
9285
|
-
}
|
|
9286
|
-
const salt = envelopeHeader.subarray(
|
|
9287
|
-
ENVELOPE_LAYOUT.salt,
|
|
9288
|
-
ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH
|
|
9289
|
-
);
|
|
9290
|
-
const iv = envelopeHeader.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);
|
|
9291
|
-
const authTag = envelopeHeader.subarray(
|
|
9292
|
-
ENVELOPE_LAYOUT.authTag,
|
|
9293
|
-
ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
|
|
9294
|
-
);
|
|
9295
|
-
const decipher = createDecipheriv("aes-256-gcm", options.key, iv, {
|
|
9296
|
-
authTagLength: AUTH_TAG_LENGTH
|
|
9297
|
-
});
|
|
9298
|
-
decipher.setAuthTag(authTag);
|
|
9299
|
-
decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), filePathAad(options.filePath, options.memoryDir)]));
|
|
9300
|
-
let pending = Buffer.alloc(0);
|
|
9301
|
-
const stream = fs7.createReadStream(options.filePath, {
|
|
9302
|
-
start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
|
|
9303
|
-
highWaterMark: options.chunkSize
|
|
9304
|
-
});
|
|
9305
|
-
for await (const encryptedChunk of stream) {
|
|
9306
|
-
const plain = decipher.update(Buffer.isBuffer(encryptedChunk) ? encryptedChunk : Buffer.from(encryptedChunk));
|
|
9307
|
-
if (plain.length > 0) {
|
|
9308
|
-
pending = Buffer.concat([pending, plain], pending.length + plain.length);
|
|
9309
|
-
}
|
|
9310
|
-
while (pending.length >= options.chunkSize) {
|
|
9311
|
-
yield pending.subarray(0, options.chunkSize);
|
|
9312
|
-
pending = pending.subarray(options.chunkSize);
|
|
9313
|
-
}
|
|
9314
|
-
}
|
|
9315
|
-
const finalPlain = decipher.final();
|
|
9316
|
-
if (finalPlain.length > 0) {
|
|
9317
|
-
pending = Buffer.concat([pending, finalPlain], pending.length + finalPlain.length);
|
|
9318
|
-
}
|
|
9319
|
-
while (pending.length >= options.chunkSize) {
|
|
9320
|
-
yield pending.subarray(0, options.chunkSize);
|
|
9321
|
-
pending = pending.subarray(options.chunkSize);
|
|
9322
|
-
}
|
|
9323
|
-
if (pending.length > 0) yield pending;
|
|
9324
|
-
}
|
|
9325
|
-
function secureStoreEnvelopeHeaderAad(salt) {
|
|
9326
|
-
const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
|
|
9327
|
-
out.writeUInt8(ENVELOPE_VERSION, 0);
|
|
9328
|
-
Buffer.from(salt).copy(out, 1);
|
|
9329
|
-
return out;
|
|
9330
|
-
}
|
|
9331
9620
|
function formatOfflineLargeFilePushFailureMessage(failures) {
|
|
9332
9621
|
const paths = failures.slice(0, 5).map((failure) => `${failure.path}: ${failure.error}`).join("; ");
|
|
9333
9622
|
const suffix = failures.length > 5 ? `; +${failures.length - 5} more` : "";
|
|
@@ -9375,7 +9664,7 @@ function advanceOfflineBaseFilesForSuccessfulPush(options) {
|
|
|
9375
9664
|
return [...next.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
9376
9665
|
}
|
|
9377
9666
|
async function runOfflineSyncOnce(options) {
|
|
9378
|
-
|
|
9667
|
+
fs9.mkdirSync(options.memoryDir, { recursive: true });
|
|
9379
9668
|
let activeStatePath = options.statePath;
|
|
9380
9669
|
let priorState = await readOfflineSyncState(activeStatePath);
|
|
9381
9670
|
let syncNamespace = options.namespace ?? priorState?.namespace;
|
|
@@ -9413,8 +9702,22 @@ async function runOfflineSyncOnce(options) {
|
|
|
9413
9702
|
}
|
|
9414
9703
|
const baseFiles = priorState?.baseFiles ?? [];
|
|
9415
9704
|
const baseCapturedAt = priorState ? new Date(priorState.lastSyncedAt) : void 0;
|
|
9416
|
-
const
|
|
9705
|
+
const offlineStorage = await createConfiguredOfflineStorage(
|
|
9706
|
+
options.memoryDir,
|
|
9707
|
+
options.secureStoreEncryptOnWrite
|
|
9708
|
+
);
|
|
9709
|
+
const storageIo = await createOfflineStorageIo(options.memoryDir, offlineStorage);
|
|
9417
9710
|
const localSourceId = localOfflineSourceId(options.memoryDir);
|
|
9711
|
+
await drainOfflineSyncImpressions(options.memoryDir, options);
|
|
9712
|
+
await drainPendingLifecycleForOfflineSync(
|
|
9713
|
+
options.memoryDir,
|
|
9714
|
+
(ledgerPath) => createOfflineStorageForPath(
|
|
9715
|
+
options.memoryDir,
|
|
9716
|
+
ledgerPath,
|
|
9717
|
+
offlineStorage,
|
|
9718
|
+
options.secureStoreEncryptOnWrite ?? true
|
|
9719
|
+
).drainPendingMemoryLifecycleEventsForSyncAt(ledgerPath)
|
|
9720
|
+
);
|
|
9418
9721
|
const currentSnapshotForPush = await buildOfflineSyncSnapshotFromBase({
|
|
9419
9722
|
root: options.memoryDir,
|
|
9420
9723
|
sourceId: localSourceId,
|
|
@@ -9933,7 +10236,7 @@ function advanceOfflineLargeFileFailureCounts(options) {
|
|
|
9933
10236
|
}
|
|
9934
10237
|
return { counts: next, newlySkipped };
|
|
9935
10238
|
}
|
|
9936
|
-
function resolveOfflineSyncUserExcludes(rest) {
|
|
10239
|
+
function resolveOfflineSyncUserExcludes(rest, config) {
|
|
9937
10240
|
const globs = [];
|
|
9938
10241
|
for (let i = 0; i < rest.length; i += 1) {
|
|
9939
10242
|
if (rest[i] !== "--exclude") continue;
|
|
@@ -9944,27 +10247,17 @@ function resolveOfflineSyncUserExcludes(rest) {
|
|
|
9944
10247
|
globs.push(value.trim());
|
|
9945
10248
|
i += 1;
|
|
9946
10249
|
}
|
|
9947
|
-
const
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
const configured = remnicCfg.offlineSyncExcludes;
|
|
9952
|
-
if (configured !== void 0 && configured !== null) {
|
|
9953
|
-
if (!Array.isArray(configured)) {
|
|
9954
|
-
throw new Error("offlineSyncExcludes config must be an array of non-empty glob strings");
|
|
9955
|
-
}
|
|
9956
|
-
for (const entry of configured) {
|
|
9957
|
-
if (typeof entry !== "string" || entry.trim().length === 0) {
|
|
9958
|
-
throw new Error("offlineSyncExcludes config must contain only non-empty glob strings");
|
|
9959
|
-
}
|
|
9960
|
-
globs.push(entry.trim());
|
|
9961
|
-
}
|
|
10250
|
+
const configured = config.offlineSyncExcludes;
|
|
10251
|
+
if (configured !== void 0 && configured !== null) {
|
|
10252
|
+
if (!Array.isArray(configured)) {
|
|
10253
|
+
throw new Error("offlineSyncExcludes config must be an array of non-empty glob strings");
|
|
9962
10254
|
}
|
|
9963
|
-
|
|
9964
|
-
|
|
9965
|
-
|
|
10255
|
+
for (const entry of configured) {
|
|
10256
|
+
if (typeof entry !== "string" || entry.trim().length === 0) {
|
|
10257
|
+
throw new Error("offlineSyncExcludes config must contain only non-empty glob strings");
|
|
10258
|
+
}
|
|
10259
|
+
globs.push(entry.trim());
|
|
9966
10260
|
}
|
|
9967
|
-
throw error;
|
|
9968
10261
|
}
|
|
9969
10262
|
return compileOfflineSyncExcludeGlobs(globs);
|
|
9970
10263
|
}
|
|
@@ -9989,19 +10282,30 @@ Environment fallbacks:
|
|
|
9989
10282
|
REMNIC_OFFLINE_REMOTE_URL, REMNIC_OFFLINE_TOKEN, REMNIC_AUTH_TOKEN`);
|
|
9990
10283
|
return;
|
|
9991
10284
|
}
|
|
9992
|
-
const memoryDir =
|
|
10285
|
+
const memoryDir = path12.resolve(expandTilde(resolveRequiredValueFlag(rest, "--memory-dir") ?? resolveMemoryDir()));
|
|
9993
10286
|
const namespace = resolveRequiredValueFlag(rest, "--namespace");
|
|
9994
10287
|
const includeTranscripts = !hasFlag(rest, "--no-transcripts");
|
|
9995
10288
|
const stateOverride = resolveRequiredValueFlag(rest, "--state");
|
|
9996
10289
|
const statePathExplicit = stateOverride !== void 0;
|
|
9997
|
-
const
|
|
10290
|
+
const configPath = resolveConfigPath();
|
|
10291
|
+
let config;
|
|
10292
|
+
try {
|
|
10293
|
+
const rawConfig = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
10294
|
+
config = parseConfigQuietly(pickOfflineConfigRecord(rawConfig));
|
|
10295
|
+
} catch {
|
|
10296
|
+
throw new Error(
|
|
10297
|
+
"offline sync: failed to load the Remnic config \u2014 run `remnic doctor` and check the config file for errors"
|
|
10298
|
+
);
|
|
10299
|
+
}
|
|
10300
|
+
const userExcludeRegexps = resolveOfflineSyncUserExcludes(rest, config);
|
|
10301
|
+
const impressionRotation = resolveOfflineImpressionRotation(configPath);
|
|
9998
10302
|
const needsRemote = action === "prepare" || action === "sync" || action === "watch";
|
|
9999
10303
|
const remoteUrl = needsRemote ? resolveOfflineRemoteUrl(rest) : resolveOptionalOfflineRemoteUrl(rest);
|
|
10000
10304
|
const token = needsRemote ? resolveOfflineToken(rest) : void 0;
|
|
10001
|
-
const statePath = statePathExplicit ?
|
|
10305
|
+
const statePath = statePathExplicit ? path12.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
|
|
10002
10306
|
if (action === "prepare") {
|
|
10003
10307
|
if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
|
|
10004
|
-
|
|
10308
|
+
fs9.mkdirSync(memoryDir, { recursive: true });
|
|
10005
10309
|
const remoteSnapshot = await fetchOfflineSnapshot({
|
|
10006
10310
|
remoteUrl,
|
|
10007
10311
|
token,
|
|
@@ -10027,7 +10331,10 @@ Environment fallbacks:
|
|
|
10027
10331
|
statePath: existingState.statePath
|
|
10028
10332
|
});
|
|
10029
10333
|
}
|
|
10030
|
-
const storageIo = await createOfflineStorageIo(
|
|
10334
|
+
const storageIo = await createOfflineStorageIo(
|
|
10335
|
+
memoryDir,
|
|
10336
|
+
await createConfiguredOfflineStorage(memoryDir, config.secureStoreEncryptOnWrite)
|
|
10337
|
+
);
|
|
10031
10338
|
const pull = await applyOfflineSyncSnapshot({
|
|
10032
10339
|
root: memoryDir,
|
|
10033
10340
|
snapshot: remoteSnapshot,
|
|
@@ -10072,7 +10379,9 @@ Environment fallbacks:
|
|
|
10072
10379
|
includeTranscripts,
|
|
10073
10380
|
statePath,
|
|
10074
10381
|
statePathExplicit,
|
|
10075
|
-
userExcludeRegexps
|
|
10382
|
+
userExcludeRegexps,
|
|
10383
|
+
secureStoreEncryptOnWrite: config.secureStoreEncryptOnWrite,
|
|
10384
|
+
...impressionRotation
|
|
10076
10385
|
});
|
|
10077
10386
|
if (json) {
|
|
10078
10387
|
console.log(JSON.stringify(offlineSyncResultJsonSummary(result), null, 2));
|
|
@@ -10094,7 +10403,7 @@ Environment fallbacks:
|
|
|
10094
10403
|
return;
|
|
10095
10404
|
}
|
|
10096
10405
|
if (action === "status") {
|
|
10097
|
-
|
|
10406
|
+
fs9.mkdirSync(memoryDir, { recursive: true });
|
|
10098
10407
|
const state = statePath ? await readOfflineSyncState(statePath) : null;
|
|
10099
10408
|
if (state && remoteUrl && statePath) {
|
|
10100
10409
|
assertOfflineStateMatches({
|
|
@@ -10105,7 +10414,18 @@ Environment fallbacks:
|
|
|
10105
10414
|
statePath
|
|
10106
10415
|
});
|
|
10107
10416
|
}
|
|
10108
|
-
const
|
|
10417
|
+
const configuredStorage = await createConfiguredOfflineStorage(memoryDir, config.secureStoreEncryptOnWrite);
|
|
10418
|
+
const storageIo = await createOfflineStorageIo(memoryDir, configuredStorage);
|
|
10419
|
+
await drainOfflineSyncImpressions(memoryDir, impressionRotation);
|
|
10420
|
+
await drainPendingLifecycleForOfflineSync(
|
|
10421
|
+
memoryDir,
|
|
10422
|
+
(ledgerPath) => createOfflineStorageForPath(
|
|
10423
|
+
memoryDir,
|
|
10424
|
+
ledgerPath,
|
|
10425
|
+
configuredStorage,
|
|
10426
|
+
config.secureStoreEncryptOnWrite ?? true
|
|
10427
|
+
).drainPendingMemoryLifecycleEventsForSyncAt(ledgerPath)
|
|
10428
|
+
);
|
|
10109
10429
|
const summary = await summarizeOfflineSyncPendingChanges({
|
|
10110
10430
|
root: memoryDir,
|
|
10111
10431
|
sourceId: localOfflineSourceId(memoryDir),
|
|
@@ -10154,6 +10474,8 @@ Environment fallbacks:
|
|
|
10154
10474
|
statePath,
|
|
10155
10475
|
statePathExplicit,
|
|
10156
10476
|
userExcludeRegexps,
|
|
10477
|
+
secureStoreEncryptOnWrite: config.secureStoreEncryptOnWrite,
|
|
10478
|
+
...impressionRotation,
|
|
10157
10479
|
skipLargeFilePaths: skippedLargeFiles
|
|
10158
10480
|
});
|
|
10159
10481
|
const advanced = advanceOfflineLargeFileFailureCounts({
|
|
@@ -10161,11 +10483,11 @@ Environment fallbacks:
|
|
|
10161
10483
|
failures: result.largeFilePushFailures
|
|
10162
10484
|
});
|
|
10163
10485
|
largeFileFailureCounts = advanced.counts;
|
|
10164
|
-
for (const
|
|
10165
|
-
if (skippedLargeFiles.has(
|
|
10166
|
-
skippedLargeFiles.add(
|
|
10486
|
+
for (const path13 of advanced.newlySkipped) {
|
|
10487
|
+
if (skippedLargeFiles.has(path13)) continue;
|
|
10488
|
+
skippedLargeFiles.add(path13);
|
|
10167
10489
|
console.warn(
|
|
10168
|
-
`offline sync: permanently skipping ${
|
|
10490
|
+
`offline sync: permanently skipping ${path13} after ${OFFLINE_LARGE_FILE_SKIP_AFTER_FAILURES} failed large-file pushes for this watcher process (see issue #1786; use --exclude or offlineSyncExcludes to silence permanently)`
|
|
10169
10491
|
);
|
|
10170
10492
|
}
|
|
10171
10493
|
const pulled = result.pull ? result.pull.upserted + result.pull.deleted : 0;
|
|
@@ -10180,11 +10502,11 @@ Environment fallbacks:
|
|
|
10180
10502
|
failures: error.failures
|
|
10181
10503
|
});
|
|
10182
10504
|
largeFileFailureCounts = advanced.counts;
|
|
10183
|
-
for (const
|
|
10184
|
-
if (skippedLargeFiles.has(
|
|
10185
|
-
skippedLargeFiles.add(
|
|
10505
|
+
for (const path13 of advanced.newlySkipped) {
|
|
10506
|
+
if (skippedLargeFiles.has(path13)) continue;
|
|
10507
|
+
skippedLargeFiles.add(path13);
|
|
10186
10508
|
console.warn(
|
|
10187
|
-
`offline sync: permanently skipping ${
|
|
10509
|
+
`offline sync: permanently skipping ${path13} after ${OFFLINE_LARGE_FILE_SKIP_AFTER_FAILURES} failed large-file pushes for this watcher process (see issue #1786; use --exclude or offlineSyncExcludes to silence permanently)`
|
|
10188
10510
|
);
|
|
10189
10511
|
}
|
|
10190
10512
|
}
|
|
@@ -10219,7 +10541,7 @@ function cmdDedup(json) {
|
|
|
10219
10541
|
function readInstalledConnectorConfig(configPath, fallback) {
|
|
10220
10542
|
if (!configPath) return fallback;
|
|
10221
10543
|
try {
|
|
10222
|
-
const parsed = JSON.parse(
|
|
10544
|
+
const parsed = JSON.parse(fs9.readFileSync(configPath, "utf8"));
|
|
10223
10545
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fallback;
|
|
10224
10546
|
const { token: _token, ...config } = parsed;
|
|
10225
10547
|
return config;
|
|
@@ -10231,6 +10553,29 @@ function snapshotConnectorTokenEntry(connectorId) {
|
|
|
10231
10553
|
const entry = listTokens().find((candidate) => candidate.connector === connectorId);
|
|
10232
10554
|
return entry ? { ...entry } : null;
|
|
10233
10555
|
}
|
|
10556
|
+
async function cmdQuarantine(action, rest, json) {
|
|
10557
|
+
if (action !== "list") {
|
|
10558
|
+
process.stderr.write(`quarantine: unknown action "${action}". Use: list [--json].
|
|
10559
|
+
`);
|
|
10560
|
+
process.exitCode = 2;
|
|
10561
|
+
return;
|
|
10562
|
+
}
|
|
10563
|
+
const extra = rest.filter((a) => !a.startsWith("--"));
|
|
10564
|
+
if (extra.length > 0) {
|
|
10565
|
+
process.stderr.write(`quarantine list: unexpected argument(s): ${extra.join(", ")}. Use: list [--json].
|
|
10566
|
+
`);
|
|
10567
|
+
process.exitCode = 2;
|
|
10568
|
+
return;
|
|
10569
|
+
}
|
|
10570
|
+
const format = json ? "json" : "text";
|
|
10571
|
+
try {
|
|
10572
|
+
const store = new WriteQuarantineStore(resolveMemoryDir());
|
|
10573
|
+
console.log(renderQuarantineList(await store.list(), format));
|
|
10574
|
+
} catch {
|
|
10575
|
+
process.stderr.write("quarantine list: unable to inspect quarantine store\n");
|
|
10576
|
+
process.exitCode = 2;
|
|
10577
|
+
}
|
|
10578
|
+
}
|
|
10234
10579
|
async function cmdConnectors(action, rest, json) {
|
|
10235
10580
|
const rawNonFlagArgs = rest.filter((a) => !a.startsWith("--"));
|
|
10236
10581
|
const resolveConfigStrippedNonFlagArgs = () => {
|
|
@@ -10298,7 +10643,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10298
10643
|
const connectorDaemonUrl = typeof effectiveConnectorConfig.remnicDaemonUrl === "string" && effectiveConnectorConfig.remnicDaemonUrl.trim().length > 0 ? effectiveConnectorConfig.remnicDaemonUrl.trim() : void 0;
|
|
10299
10644
|
const pubResult = await pub.publish({
|
|
10300
10645
|
config: { memoryDir, namespace: connectorNamespace, daemonUrl: connectorDaemonUrl },
|
|
10301
|
-
skillsRoot:
|
|
10646
|
+
skillsRoot: path12.join(memoryDir, "skills"),
|
|
10302
10647
|
rollbackTokenEntry: preInstallTokenEntry,
|
|
10303
10648
|
log: { info: console.log, warn: console.warn, error: console.error }
|
|
10304
10649
|
});
|
|
@@ -10370,7 +10715,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10370
10715
|
const pub = factory();
|
|
10371
10716
|
const available = await pub.isHostAvailable();
|
|
10372
10717
|
const extRoot = available ? await pub.resolveExtensionRoot() : "(host not installed)";
|
|
10373
|
-
const extensionExists = available && extRoot ?
|
|
10718
|
+
const extensionExists = available && extRoot ? fs9.existsSync(extRoot) : false;
|
|
10374
10719
|
publisherChecks.push({
|
|
10375
10720
|
name: `Publisher: ${targetHostId}`,
|
|
10376
10721
|
ok: !available || extensionExists,
|
|
@@ -10441,17 +10786,30 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10441
10786
|
const memoryDir = resolveMemoryDir();
|
|
10442
10787
|
const states = await listLiveConnectorStates(memoryDir);
|
|
10443
10788
|
const stateMap = new Map(states.map((s) => [s.id, s]));
|
|
10789
|
+
let connectorsCfg;
|
|
10790
|
+
const configPath = resolveConfigPath();
|
|
10791
|
+
try {
|
|
10792
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
10793
|
+
connectorsCfg = parseConfigQuietly(raw).connectors;
|
|
10794
|
+
} catch {
|
|
10795
|
+
process.stderr.write(
|
|
10796
|
+
`connectors status: failed to read config at ${configPath}
|
|
10797
|
+
`
|
|
10798
|
+
);
|
|
10799
|
+
process.exitCode = 2;
|
|
10800
|
+
return;
|
|
10801
|
+
}
|
|
10444
10802
|
const rows = [
|
|
10445
10803
|
{
|
|
10446
10804
|
id: GDRIVE_ID,
|
|
10447
10805
|
displayName: "Google Drive",
|
|
10448
|
-
enabled:
|
|
10806
|
+
enabled: connectorsCfg.googleDrive.enabled,
|
|
10449
10807
|
state: stateMap.get(GDRIVE_ID) ?? null
|
|
10450
10808
|
},
|
|
10451
10809
|
{
|
|
10452
10810
|
id: NOTION_ID,
|
|
10453
10811
|
displayName: "Notion",
|
|
10454
|
-
enabled:
|
|
10812
|
+
enabled: connectorsCfg.notion.enabled,
|
|
10455
10813
|
state: stateMap.get(NOTION_ID) ?? null
|
|
10456
10814
|
}
|
|
10457
10815
|
];
|
|
@@ -10507,9 +10865,9 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10507
10865
|
}
|
|
10508
10866
|
initLogger();
|
|
10509
10867
|
const configPath = resolveConfigPath();
|
|
10510
|
-
const raw =
|
|
10511
|
-
const remnicCfg =
|
|
10512
|
-
const config =
|
|
10868
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
10869
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
10870
|
+
const config = parseConfig2(remnicCfg);
|
|
10513
10871
|
const orchestrator = new Orchestrator(config);
|
|
10514
10872
|
try {
|
|
10515
10873
|
await orchestrator.initialize();
|
|
@@ -10632,9 +10990,9 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
10632
10990
|
console.error(`connectors marketplace: ${err instanceof Error ? err.message : String(err)}`);
|
|
10633
10991
|
process.exit(1);
|
|
10634
10992
|
}
|
|
10635
|
-
const rawConfig =
|
|
10636
|
-
const pluginConfig =
|
|
10637
|
-
const config =
|
|
10993
|
+
const rawConfig = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
10994
|
+
const pluginConfig = resolveRemnicConfigRecord2(rawConfig);
|
|
10995
|
+
const config = parseConfig2(pluginConfig);
|
|
10638
10996
|
if (subAction === "generate") {
|
|
10639
10997
|
let outputDir;
|
|
10640
10998
|
try {
|
|
@@ -10645,22 +11003,22 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
10645
11003
|
}
|
|
10646
11004
|
const manifest = generateMarketplaceManifest();
|
|
10647
11005
|
await writeMarketplaceManifest(outputDir, manifest);
|
|
10648
|
-
const outPath =
|
|
11006
|
+
const outPath = path12.join(outputDir, "marketplace.json");
|
|
10649
11007
|
if (json) {
|
|
10650
11008
|
console.log(JSON.stringify({ status: "generated", path: outPath }, null, 2));
|
|
10651
11009
|
} else {
|
|
10652
11010
|
console.log(`Generated marketplace.json at ${outPath}`);
|
|
10653
11011
|
}
|
|
10654
11012
|
} else if (subAction === "validate") {
|
|
10655
|
-
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ??
|
|
10656
|
-
const resolved =
|
|
10657
|
-
if (!
|
|
11013
|
+
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path12.join(process.cwd(), "marketplace.json");
|
|
11014
|
+
const resolved = path12.resolve(targetPath);
|
|
11015
|
+
if (!fs9.existsSync(resolved)) {
|
|
10658
11016
|
console.error(`File not found: ${resolved}`);
|
|
10659
11017
|
process.exit(1);
|
|
10660
11018
|
}
|
|
10661
11019
|
let parsed;
|
|
10662
11020
|
try {
|
|
10663
|
-
parsed = JSON.parse(
|
|
11021
|
+
parsed = JSON.parse(fs9.readFileSync(resolved, "utf8"));
|
|
10664
11022
|
} catch {
|
|
10665
11023
|
console.error(`Invalid JSON in ${resolved}`);
|
|
10666
11024
|
process.exit(1);
|
|
@@ -10861,9 +11219,9 @@ async function cmdSpace(action, rest, json) {
|
|
|
10861
11219
|
async function cmdLegacyBenchmark(action, rest, json) {
|
|
10862
11220
|
initLogger();
|
|
10863
11221
|
const configPath = resolveConfigPath();
|
|
10864
|
-
const raw =
|
|
10865
|
-
const remnicCfg =
|
|
10866
|
-
const config =
|
|
11222
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
11223
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
11224
|
+
const config = parseConfig2(remnicCfg);
|
|
10867
11225
|
const orchestrator = new Orchestrator(config);
|
|
10868
11226
|
const service = new EngramAccessService(orchestrator);
|
|
10869
11227
|
const { runBenchSuite, loadBaseline, checkRegression } = await loadBenchModule();
|
|
@@ -11057,7 +11415,7 @@ async function cmdBench(rest) {
|
|
|
11057
11415
|
}
|
|
11058
11416
|
const completeCount = prevStatus.benchmarks.filter((b) => b.status === "complete").length;
|
|
11059
11417
|
const failedCount = prevStatus.benchmarks.filter((b) => b.status === "failed").length;
|
|
11060
|
-
printBenchStatusLine(parsed.json, `Resuming from: ${
|
|
11418
|
+
printBenchStatusLine(parsed.json, `Resuming from: ${path12.basename(latestStatusPath)}`);
|
|
11061
11419
|
printBenchStatusLine(parsed.json, ` Previous run: ${prevStatus.startedAt}`);
|
|
11062
11420
|
printBenchStatusLine(parsed.json, ` Benchmarks: ${prevStatus.benchmarks.length} total, ${completeCount} complete, ${failedCount} failed`);
|
|
11063
11421
|
const before = selectedBenchmarks.length;
|
|
@@ -11219,9 +11577,9 @@ Options:
|
|
|
11219
11577
|
);
|
|
11220
11578
|
process.exit(1);
|
|
11221
11579
|
} else {
|
|
11222
|
-
fixturePath =
|
|
11580
|
+
fixturePath = path12.resolve(expandTilde(fixturePathRaw));
|
|
11223
11581
|
}
|
|
11224
|
-
const outPath =
|
|
11582
|
+
const outPath = path12.resolve(expandTilde(outPathRaw));
|
|
11225
11583
|
const benchModule = await loadBenchModule();
|
|
11226
11584
|
const runner = benchModule.runProceduralAblationCli;
|
|
11227
11585
|
if (typeof runner !== "function") {
|
|
@@ -11240,7 +11598,7 @@ Options:
|
|
|
11240
11598
|
);
|
|
11241
11599
|
console.log(`wrote ${outPath}`);
|
|
11242
11600
|
}
|
|
11243
|
-
var LOGS_DIR =
|
|
11601
|
+
var LOGS_DIR = path12.join(PID_DIR, "logs");
|
|
11244
11602
|
var LAUNCHD_PLIST_PATHS = launchdPlistPaths(resolveHomeDir());
|
|
11245
11603
|
var [LAUNCHD_PLIST_PATH] = LAUNCHD_PLIST_PATHS;
|
|
11246
11604
|
var SYSTEMD_UNIT_PATHS = systemdUnitPaths(resolveHomeDir());
|
|
@@ -11254,7 +11612,7 @@ function readPid() {
|
|
|
11254
11612
|
function inferPort() {
|
|
11255
11613
|
try {
|
|
11256
11614
|
const configPath = resolveConfigPath();
|
|
11257
|
-
const raw = JSON.parse(
|
|
11615
|
+
const raw = JSON.parse(fs9.readFileSync(configPath, "utf8"));
|
|
11258
11616
|
return raw.server?.port ?? 4318;
|
|
11259
11617
|
} catch {
|
|
11260
11618
|
return 4318;
|
|
@@ -11317,7 +11675,7 @@ function selectLaunchdInspection(openclawPluginModeConfigured) {
|
|
|
11317
11675
|
for (const plistPath of LAUNCHD_PLIST_PATHS.slice(1)) {
|
|
11318
11676
|
const legacy = inspectLaunchdPlist(plistPath);
|
|
11319
11677
|
if (!legacy.installed) continue;
|
|
11320
|
-
const label =
|
|
11678
|
+
const label = path12.basename(plistPath, ".plist");
|
|
11321
11679
|
return legacy.ok ? {
|
|
11322
11680
|
...legacy,
|
|
11323
11681
|
warn: true,
|
|
@@ -11349,13 +11707,13 @@ function daemonInstall() {
|
|
|
11349
11707
|
process.exit(1);
|
|
11350
11708
|
}
|
|
11351
11709
|
const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
|
|
11352
|
-
|
|
11710
|
+
fs9.mkdirSync(LOGS_DIR, { recursive: true });
|
|
11353
11711
|
if (isMacOS()) {
|
|
11354
|
-
const templatePath =
|
|
11355
|
-
const template =
|
|
11712
|
+
const templatePath = path12.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
|
|
11713
|
+
const template = fs9.readFileSync(templatePath, "utf8");
|
|
11356
11714
|
const plist = renderTemplate(template, vars);
|
|
11357
|
-
|
|
11358
|
-
|
|
11715
|
+
fs9.mkdirSync(path12.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
|
|
11716
|
+
fs9.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
11359
11717
|
try {
|
|
11360
11718
|
launchdLoadPlist(LAUNCHD_PLIST_PATH);
|
|
11361
11719
|
} catch (err) {
|
|
@@ -11371,11 +11729,11 @@ function daemonInstall() {
|
|
|
11371
11729
|
console.log(` RunAtLoad: true, KeepAlive: true`);
|
|
11372
11730
|
console.log(` Logs: ${LOGS_DIR}/daemon.log`);
|
|
11373
11731
|
} else if (isLinux()) {
|
|
11374
|
-
const templatePath =
|
|
11375
|
-
const template =
|
|
11732
|
+
const templatePath = path12.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
|
|
11733
|
+
const template = fs9.readFileSync(templatePath, "utf8");
|
|
11376
11734
|
const unit = renderTemplate(template, vars);
|
|
11377
|
-
|
|
11378
|
-
|
|
11735
|
+
fs9.mkdirSync(path12.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
|
|
11736
|
+
fs9.writeFileSync(SYSTEMD_UNIT_PATH, unit);
|
|
11379
11737
|
try {
|
|
11380
11738
|
childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
11381
11739
|
} catch (err) {
|
|
@@ -11411,7 +11769,7 @@ function daemonUninstall() {
|
|
|
11411
11769
|
} catch {
|
|
11412
11770
|
}
|
|
11413
11771
|
try {
|
|
11414
|
-
|
|
11772
|
+
fs9.unlinkSync(plistPath);
|
|
11415
11773
|
removed = true;
|
|
11416
11774
|
console.log(`Removed launchd service: ${plistPath}`);
|
|
11417
11775
|
} catch {
|
|
@@ -11431,7 +11789,7 @@ function daemonUninstall() {
|
|
|
11431
11789
|
let removed = false;
|
|
11432
11790
|
for (const unitPath of SYSTEMD_UNIT_PATHS) {
|
|
11433
11791
|
try {
|
|
11434
|
-
|
|
11792
|
+
fs9.unlinkSync(unitPath);
|
|
11435
11793
|
removed = true;
|
|
11436
11794
|
console.log(`Removed systemd service: ${unitPath}`);
|
|
11437
11795
|
} catch {
|
|
@@ -11498,13 +11856,13 @@ async function daemonStatus() {
|
|
|
11498
11856
|
console.log(` Port: ${port}`);
|
|
11499
11857
|
console.log(` Service: ${serviceInstalled ? "installed" : "not installed"}`);
|
|
11500
11858
|
console.log(` Platform: ${process.platform}`);
|
|
11501
|
-
console.log(` PID file: ${
|
|
11502
|
-
console.log(` Log file: ${
|
|
11859
|
+
console.log(` PID file: ${fs9.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
|
|
11860
|
+
console.log(` Log file: ${fs9.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
|
|
11503
11861
|
try {
|
|
11504
11862
|
const configPath = resolveConfigPath();
|
|
11505
|
-
const raw =
|
|
11506
|
-
const remnicCfg =
|
|
11507
|
-
const config =
|
|
11863
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
11864
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
11865
|
+
const config = parseConfig2(remnicCfg);
|
|
11508
11866
|
const extRoot = resolveExtensionsRoot(config);
|
|
11509
11867
|
const noopLog = { warn: () => {
|
|
11510
11868
|
}, debug: () => {
|
|
@@ -11543,9 +11901,9 @@ function daemonStart() {
|
|
|
11543
11901
|
return;
|
|
11544
11902
|
}
|
|
11545
11903
|
}
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
const logStream =
|
|
11904
|
+
fs9.mkdirSync(PID_DIR, { recursive: true });
|
|
11905
|
+
fs9.mkdirSync(LOGS_DIR, { recursive: true });
|
|
11906
|
+
const logStream = fs9.openSync(LOG_FILE, "a");
|
|
11549
11907
|
const serverBin = resolveServerBin();
|
|
11550
11908
|
const isSource = serverBin.endsWith(".ts");
|
|
11551
11909
|
let cmd;
|
|
@@ -11567,7 +11925,7 @@ function daemonStart() {
|
|
|
11567
11925
|
}
|
|
11568
11926
|
});
|
|
11569
11927
|
child.unref();
|
|
11570
|
-
|
|
11928
|
+
fs9.writeFileSync(PID_FILE, String(child.pid));
|
|
11571
11929
|
console.log(`Started remnic server (pid ${child.pid})`);
|
|
11572
11930
|
console.log(` Log: ${LOG_FILE}`);
|
|
11573
11931
|
}
|
|
@@ -11601,11 +11959,11 @@ function daemonStop() {
|
|
|
11601
11959
|
console.log("Process not found (cleaning up PID file)");
|
|
11602
11960
|
}
|
|
11603
11961
|
try {
|
|
11604
|
-
|
|
11962
|
+
fs9.unlinkSync(PID_FILE);
|
|
11605
11963
|
} catch {
|
|
11606
11964
|
}
|
|
11607
11965
|
try {
|
|
11608
|
-
|
|
11966
|
+
fs9.unlinkSync(LEGACY_PID_FILE);
|
|
11609
11967
|
} catch {
|
|
11610
11968
|
}
|
|
11611
11969
|
}
|
|
@@ -11733,9 +12091,9 @@ async function promptYesNo(question, defaultYes = true) {
|
|
|
11733
12091
|
async function cmdBinary(rest) {
|
|
11734
12092
|
initLogger();
|
|
11735
12093
|
const configPath = resolveConfigPath();
|
|
11736
|
-
const raw =
|
|
11737
|
-
const remnicCfg =
|
|
11738
|
-
const config =
|
|
12094
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
12095
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
12096
|
+
const config = parseConfig2(remnicCfg);
|
|
11739
12097
|
const memoryDir = resolveMemoryDir();
|
|
11740
12098
|
const blConfig = {
|
|
11741
12099
|
enabled: config.binaryLifecycleEnabled,
|
|
@@ -11853,7 +12211,7 @@ Clean complete: cleaned=${result.cleaned}`
|
|
|
11853
12211
|
}
|
|
11854
12212
|
async function cmdOpenclawInstall(opts) {
|
|
11855
12213
|
const configPath = resolveOpenclawConfigPath(opts.configPath);
|
|
11856
|
-
const fallbackMemoryDir =
|
|
12214
|
+
const fallbackMemoryDir = path12.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
|
|
11857
12215
|
console.log(`OpenClaw config: ${configPath}`);
|
|
11858
12216
|
const existingConfig = readOpenclawConfig(configPath);
|
|
11859
12217
|
const { plugins, entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
|
|
@@ -11924,7 +12282,7 @@ async function cmdOpenclawInstall(opts) {
|
|
|
11924
12282
|
} else if (slotIsActiveLegacy) {
|
|
11925
12283
|
changes.push(` Slot left as "${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}" \u2014 re-run with --yes to activate the new entry`);
|
|
11926
12284
|
}
|
|
11927
|
-
if (!
|
|
12285
|
+
if (!fs9.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
|
|
11928
12286
|
if (hasLegacy && migrateLegacy) {
|
|
11929
12287
|
changes.push(`~ Legacy '${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}' entry retained (safe to remove after verifying hooks fire)`);
|
|
11930
12288
|
}
|
|
@@ -11944,8 +12302,8 @@ async function cmdOpenclawInstall(opts) {
|
|
|
11944
12302
|
Resulting plugins.slots.memory: ${dryRunPlugins.slots?.memory ?? "(unset)"}`);
|
|
11945
12303
|
return;
|
|
11946
12304
|
}
|
|
11947
|
-
if (
|
|
11948
|
-
const st =
|
|
12305
|
+
if (fs9.existsSync(memoryDir)) {
|
|
12306
|
+
const st = fs9.statSync(memoryDir);
|
|
11949
12307
|
if (!st.isDirectory()) {
|
|
11950
12308
|
throw new Error(
|
|
11951
12309
|
`Cannot use ${memoryDir} as the memory directory \u2014 a file already exists at that path.
|
|
@@ -11953,12 +12311,12 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
|
|
|
11953
12311
|
);
|
|
11954
12312
|
}
|
|
11955
12313
|
} else {
|
|
11956
|
-
|
|
12314
|
+
fs9.mkdirSync(memoryDir, { recursive: true });
|
|
11957
12315
|
console.log(`Created memory directory: ${memoryDir}`);
|
|
11958
12316
|
}
|
|
11959
|
-
const configDir =
|
|
11960
|
-
if (!
|
|
11961
|
-
|
|
12317
|
+
const configDir = path12.dirname(configPath);
|
|
12318
|
+
if (!fs9.existsSync(configDir)) {
|
|
12319
|
+
fs9.mkdirSync(configDir, { recursive: true });
|
|
11962
12320
|
}
|
|
11963
12321
|
atomicWriteFileSync(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
11964
12322
|
console.log("\nDone! Summary of changes:");
|
|
@@ -11984,11 +12342,11 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
11984
12342
|
const configPath = resolveOpenclawConfigPath(opts.configPath);
|
|
11985
12343
|
const pluginDir = resolveOpenclawPluginDir(opts.pluginDir);
|
|
11986
12344
|
const legacyPluginDirForBackup = opts.legacyPluginDirForBackup ? resolveOpenclawLegacyPluginDir(opts.legacyPluginDirForBackup) : void 0;
|
|
11987
|
-
const fallbackMemoryDir =
|
|
12345
|
+
const fallbackMemoryDir = path12.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
|
|
11988
12346
|
const packageSpec = `@remnic/plugin-openclaw@${opts.version ?? "latest"}`;
|
|
11989
12347
|
const existingConfig = readOpenclawConfig(configPath);
|
|
11990
12348
|
const { entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
|
|
11991
|
-
const preservedMemoryDir = opts.memoryDir ?
|
|
12349
|
+
const preservedMemoryDir = opts.memoryDir ? path12.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
|
|
11992
12350
|
assertDirectoryPathOrMissing(pluginDir, "OpenClaw plugin dir");
|
|
11993
12351
|
if (legacyPluginDirForBackup) {
|
|
11994
12352
|
assertDirectoryPathOrMissing(legacyPluginDirForBackup, "Legacy OpenClaw plugin dir");
|
|
@@ -12000,7 +12358,7 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
12000
12358
|
}
|
|
12001
12359
|
console.log(`Memory dir: ${preservedMemoryDir}`);
|
|
12002
12360
|
console.log(`Package spec: ${packageSpec}`);
|
|
12003
|
-
console.log(`Backup root: ${
|
|
12361
|
+
console.log(`Backup root: ${path12.join(resolveHomeDir(), ".openclaw", "backups")}`);
|
|
12004
12362
|
const plannedActions = [
|
|
12005
12363
|
`backup openclaw.json and the existing ${REMNIC_OPENCLAW_PLUGIN_ID} extension`,
|
|
12006
12364
|
...legacyPluginDirForBackup ? [`backup the existing ${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID} extension without modifying it`] : [],
|
|
@@ -12026,9 +12384,9 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
12026
12384
|
}
|
|
12027
12385
|
}
|
|
12028
12386
|
const backupDir = createOpenclawUpgradeBackupDir();
|
|
12029
|
-
const configBackupPath =
|
|
12030
|
-
const pluginBackupDir =
|
|
12031
|
-
const legacyPluginBackupDir = legacyPluginDirForBackup ?
|
|
12387
|
+
const configBackupPath = path12.join(backupDir, "openclaw.json");
|
|
12388
|
+
const pluginBackupDir = path12.join(backupDir, "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
|
|
12389
|
+
const legacyPluginBackupDir = legacyPluginDirForBackup ? path12.join(backupDir, "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID) : void 0;
|
|
12032
12390
|
const backupNotes = [];
|
|
12033
12391
|
if (backupPathIfPresent(configPath, configBackupPath)) {
|
|
12034
12392
|
backupNotes.push(`+ Backed up config to ${configBackupPath}`);
|
|
@@ -12129,16 +12487,16 @@ async function cmdOpenclawMigrateEngram(opts) {
|
|
|
12129
12487
|
console.log(" - Re-apply any local source patches to the new package only after verifying the published build.");
|
|
12130
12488
|
}
|
|
12131
12489
|
function createOpenclawUpgradeBackupDir() {
|
|
12132
|
-
const backupsRoot =
|
|
12133
|
-
|
|
12134
|
-
return
|
|
12490
|
+
const backupsRoot = path12.join(resolveHomeDir(), ".openclaw", "backups");
|
|
12491
|
+
fs9.mkdirSync(backupsRoot, { recursive: true });
|
|
12492
|
+
return fs9.mkdtempSync(path12.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
|
|
12135
12493
|
}
|
|
12136
12494
|
async function cmdTaxonomy(rest) {
|
|
12137
12495
|
initLogger();
|
|
12138
12496
|
const configPath = resolveConfigPath();
|
|
12139
|
-
const raw =
|
|
12140
|
-
const remnicCfg =
|
|
12141
|
-
const config =
|
|
12497
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
12498
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
12499
|
+
const config = parseConfig2(remnicCfg);
|
|
12142
12500
|
if (!config.taxonomyEnabled) {
|
|
12143
12501
|
console.error(
|
|
12144
12502
|
"Taxonomy is disabled in config (taxonomyEnabled = false). Enable it to use taxonomy commands."
|
|
@@ -12173,9 +12531,9 @@ async function cmdTaxonomy(rest) {
|
|
|
12173
12531
|
const doc = generateResolverDocument(taxonomy);
|
|
12174
12532
|
console.log(doc);
|
|
12175
12533
|
if (config.taxonomyAutoGenResolver) {
|
|
12176
|
-
const resolverPath =
|
|
12177
|
-
|
|
12178
|
-
|
|
12534
|
+
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12535
|
+
fs9.mkdirSync(path12.dirname(resolverPath), { recursive: true });
|
|
12536
|
+
fs9.writeFileSync(resolverPath, doc);
|
|
12179
12537
|
console.error(`Written: ${resolverPath}`);
|
|
12180
12538
|
}
|
|
12181
12539
|
break;
|
|
@@ -12220,8 +12578,8 @@ async function cmdTaxonomy(rest) {
|
|
|
12220
12578
|
console.log(`Added category "${id}" (${name}).`);
|
|
12221
12579
|
if (config.taxonomyAutoGenResolver) {
|
|
12222
12580
|
const doc = generateResolverDocument(taxonomy);
|
|
12223
|
-
const resolverPath =
|
|
12224
|
-
|
|
12581
|
+
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12582
|
+
fs9.writeFileSync(resolverPath, doc);
|
|
12225
12583
|
console.error(`Regenerated: ${resolverPath}`);
|
|
12226
12584
|
}
|
|
12227
12585
|
break;
|
|
@@ -12251,8 +12609,8 @@ async function cmdTaxonomy(rest) {
|
|
|
12251
12609
|
console.log(`Removed category "${id}".`);
|
|
12252
12610
|
if (config.taxonomyAutoGenResolver) {
|
|
12253
12611
|
const doc = generateResolverDocument(taxonomy);
|
|
12254
|
-
const resolverPath =
|
|
12255
|
-
|
|
12612
|
+
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12613
|
+
fs9.writeFileSync(resolverPath, doc);
|
|
12256
12614
|
console.error(`Regenerated: ${resolverPath}`);
|
|
12257
12615
|
}
|
|
12258
12616
|
break;
|
|
@@ -12443,12 +12801,12 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
12443
12801
|
`Unknown training-export format "${args.format}". ${validList}`
|
|
12444
12802
|
);
|
|
12445
12803
|
}
|
|
12446
|
-
if (!
|
|
12804
|
+
if (!fs9.existsSync(args.memoryDir)) {
|
|
12447
12805
|
throw new Error(
|
|
12448
12806
|
`--memory-dir "${args.memoryDir}" does not exist. Provide the path to an existing memory directory.`
|
|
12449
12807
|
);
|
|
12450
12808
|
}
|
|
12451
|
-
if (!
|
|
12809
|
+
if (!fs9.statSync(args.memoryDir).isDirectory()) {
|
|
12452
12810
|
throw new Error(
|
|
12453
12811
|
`--memory-dir "${args.memoryDir}" is not a directory. Provide the path to a memory directory, not a file.`
|
|
12454
12812
|
);
|
|
@@ -12533,11 +12891,11 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
12533
12891
|
);
|
|
12534
12892
|
}
|
|
12535
12893
|
const formatted = adapter.formatRecords(records);
|
|
12536
|
-
const outDir =
|
|
12537
|
-
|
|
12894
|
+
const outDir = path12.dirname(args.output);
|
|
12895
|
+
fs9.mkdirSync(outDir, { recursive: true });
|
|
12538
12896
|
const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
|
|
12539
|
-
|
|
12540
|
-
|
|
12897
|
+
fs9.writeFileSync(tmpPath, formatted, "utf-8");
|
|
12898
|
+
fs9.renameSync(tmpPath, args.output);
|
|
12541
12899
|
stdout.write(
|
|
12542
12900
|
`Exported ${records.length} records to ${args.output} (${adapter.name} format)
|
|
12543
12901
|
`
|
|
@@ -12641,7 +12999,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12641
12999
|
case "tree": {
|
|
12642
13000
|
const subAction = rest[0];
|
|
12643
13001
|
const json = rest.includes("--json");
|
|
12644
|
-
const outputDir = resolveFlag(rest, "--output") ??
|
|
13002
|
+
const outputDir = resolveFlag(rest, "--output") ?? path12.join(process.cwd(), ".remnic", "context-tree");
|
|
12645
13003
|
const categoriesFlag = resolveFlag(rest, "--categories");
|
|
12646
13004
|
const categories = categoriesFlag ? categoriesFlag.split(",") : void 0;
|
|
12647
13005
|
const maxPerCategoryRaw = resolveFlag(rest, "--max-per-category");
|
|
@@ -12706,7 +13064,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12706
13064
|
}
|
|
12707
13065
|
}, 500);
|
|
12708
13066
|
};
|
|
12709
|
-
|
|
13067
|
+
fs9.watch(memoryDir, { recursive: true }, (_event, filename) => {
|
|
12710
13068
|
if (filename && filename.startsWith(".")) return;
|
|
12711
13069
|
rebuild();
|
|
12712
13070
|
});
|
|
@@ -12714,12 +13072,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12714
13072
|
});
|
|
12715
13073
|
} else if (subAction === "validate") {
|
|
12716
13074
|
const treeDir = outputDir;
|
|
12717
|
-
if (!
|
|
13075
|
+
if (!fs9.existsSync(treeDir)) {
|
|
12718
13076
|
console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
|
|
12719
13077
|
process.exit(1);
|
|
12720
13078
|
}
|
|
12721
|
-
const indexPath =
|
|
12722
|
-
if (!
|
|
13079
|
+
const indexPath = path12.join(treeDir, "INDEX.md");
|
|
13080
|
+
if (!fs9.existsSync(indexPath)) {
|
|
12723
13081
|
console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
|
|
12724
13082
|
process.exit(1);
|
|
12725
13083
|
}
|
|
@@ -12788,6 +13146,12 @@ Options:
|
|
|
12788
13146
|
await cmdConnectors(action, rest.slice(1), json);
|
|
12789
13147
|
break;
|
|
12790
13148
|
}
|
|
13149
|
+
case "quarantine": {
|
|
13150
|
+
const action = rest[0] ?? "list";
|
|
13151
|
+
const json = rest.includes("--json");
|
|
13152
|
+
await cmdQuarantine(action, rest.slice(1), json);
|
|
13153
|
+
break;
|
|
13154
|
+
}
|
|
12791
13155
|
case "space": {
|
|
12792
13156
|
const action = rest[0] ?? "list";
|
|
12793
13157
|
const json = rest.includes("--json");
|
|
@@ -12883,9 +13247,9 @@ Other:
|
|
|
12883
13247
|
let wearablesService;
|
|
12884
13248
|
try {
|
|
12885
13249
|
const configPath = resolveConfigPath();
|
|
12886
|
-
const raw =
|
|
12887
|
-
const remnicCfg =
|
|
12888
|
-
const config =
|
|
13250
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
13251
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
13252
|
+
const config = parseConfig2(remnicCfg);
|
|
12889
13253
|
wearablesOrchestrator = new Orchestrator(config);
|
|
12890
13254
|
await wearablesOrchestrator.initialize();
|
|
12891
13255
|
await wearablesOrchestrator.deferredReady;
|
|
@@ -12927,9 +13291,9 @@ Other:
|
|
|
12927
13291
|
const targetFactory = async () => {
|
|
12928
13292
|
if (!orchestratorSingleton) {
|
|
12929
13293
|
const configPath = resolveConfigPath();
|
|
12930
|
-
const raw =
|
|
12931
|
-
const remnicCfg =
|
|
12932
|
-
const config =
|
|
13294
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
13295
|
+
const remnicCfg = resolveRemnicConfigRecord2(raw);
|
|
13296
|
+
const config = parseConfig2(remnicCfg);
|
|
12933
13297
|
orchestratorSingleton = new Orchestrator(config);
|
|
12934
13298
|
await orchestratorSingleton.initialize();
|
|
12935
13299
|
await orchestratorSingleton.deferredReady;
|
|
@@ -13143,6 +13507,7 @@ Usage:
|
|
|
13143
13507
|
marketplace generate Generate marketplace.json for Codex
|
|
13144
13508
|
marketplace validate Validate a marketplace.json file
|
|
13145
13509
|
marketplace install Install from a marketplace source
|
|
13510
|
+
remnic quarantine list [--json] Inspect writes the namespace ACL rejected
|
|
13146
13511
|
remnic extensions <list|show|validate|reload> Manage memory extensions
|
|
13147
13512
|
remnic space <list|switch|create|delete|push|pull|share|promote|audit> Manage spaces
|
|
13148
13513
|
create accepts --parent <id> to set parent-child relationship
|
|
@@ -13261,6 +13626,7 @@ export {
|
|
|
13261
13626
|
TAXONOMY_RESOLVE_BOOLEAN_FLAGS,
|
|
13262
13627
|
TAXONOMY_RESOLVE_VALUE_FLAGS,
|
|
13263
13628
|
__benchDatasetTestHooks,
|
|
13629
|
+
__statusHealthTestHooks,
|
|
13264
13630
|
advanceOfflineBaseFilesForSuccessfulPush,
|
|
13265
13631
|
advanceOfflineLargeFileFailureCounts,
|
|
13266
13632
|
attachPreparedJudgeCalibration,
|