@remnic/cli 9.41.0 → 9.43.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.
Files changed (2) hide show
  1. package/dist/index.js +1638 -897
  2. package/package.json +29 -29
package/dist/index.js CHANGED
@@ -18,15 +18,15 @@ async function persistEnrichmentCandidate(storage, entityName, candidate) {
18
18
  }
19
19
 
20
20
  // src/index.ts
21
- import fs11 from "fs";
21
+ import fs12 from "fs";
22
22
  import os from "os";
23
- import path14 from "path";
24
- import { createHash as createHash2 } from "crypto";
23
+ import path15 from "path";
24
+ import { createHash as createHash3 } from "crypto";
25
25
  import * as childProcess2 from "child_process";
26
26
  import { fileURLToPath as fileURLToPath4 } from "url";
27
27
  import { gzipSync } from "zlib";
28
28
  import {
29
- parseConfig as parseConfig4,
29
+ parseConfig as parseConfig5,
30
30
  isOpenaiApiKeyDisabled,
31
31
  resolveEnvVars,
32
32
  resolveRemnicConfigRecord as resolveRemnicConfigRecord4,
@@ -110,15 +110,15 @@ import {
110
110
  parseXrayCliOptions,
111
111
  renderXray,
112
112
  OFFLINE_SYNC_APPLY_MAX_BODY_BYTES,
113
- OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
114
- OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES as OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2,
113
+ OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES as OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES2,
114
+ OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES as OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES3,
115
115
  OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES,
116
- applyOfflineSyncFileContentChunk,
116
+ applyOfflineSyncFileContentChunk as applyOfflineSyncFileContentChunk2,
117
117
  applyOfflineSyncSnapshot,
118
118
  buildOfflineSyncChangesetFromSnapshot,
119
119
  drainPendingLifecycleForOfflineSync,
120
120
  compileOfflineSyncExcludeGlobs,
121
- buildOfflineSyncSnapshotFromBase,
121
+ buildOfflineSyncSnapshotFromBase as buildOfflineSyncSnapshotFromBase2,
122
122
  defaultOfflineSyncStatePath,
123
123
  normalizeOfflineSyncSnapshot,
124
124
  offlineSyncStateFromSnapshot,
@@ -238,121 +238,1115 @@ async function loadWecloneExportModule() {
238
238
  return cached;
239
239
  }
240
240
 
241
- // src/doctor-namespace-lint.ts
242
- import { isNamespacePolicyCovered } from "@remnic/core";
243
- function readConfiguredNamespace(remnicCfg) {
244
- if (!("namespace" in remnicCfg)) return { invalid: false };
245
- const value = remnicCfg.namespace;
246
- if (typeof value === "string" && value.trim().length > 0) {
247
- return { configuredNamespace: value.trim(), invalid: false };
241
+ // src/converge.ts
242
+ import * as fs3 from "fs";
243
+ import { createHash as createHash2 } from "crypto";
244
+ import * as path2 from "path";
245
+ import {
246
+ parseConfig as parseConfig2,
247
+ buildOfflineSyncSnapshotFromBase,
248
+ OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
249
+ OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES as OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2,
250
+ applyOfflineSyncFileContentChunk
251
+ } from "@remnic/core";
252
+ import { resolveCorpusNamespaceRoots } from "@remnic/core/corpus-watermark.js";
253
+ import { listNamespaces } from "@remnic/core/namespaces/migrate.js";
254
+ import {
255
+ planReconciliation
256
+ } from "@remnic/core/reconcile/plan.js";
257
+ import {
258
+ defaultConvergeCursorPath,
259
+ readConvergeCursor,
260
+ writeConvergeCursor
261
+ } from "@remnic/core/reconcile/cursor.js";
262
+
263
+ // src/offline-storage-io.ts
264
+ import { mkdtemp, readdir, lstat, rm } from "fs/promises";
265
+ import fs2 from "fs";
266
+ import path from "path";
267
+ import { createHash, createDecipheriv } from "crypto";
268
+ import {
269
+ OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
270
+ StorageManager
271
+ } from "@remnic/core";
272
+ import { OFFLINE_DECRYPT_STAGING_DIR_PREFIX } from "@remnic/core/offline-sync-exclude-globs";
273
+ import {
274
+ AUTH_TAG_LENGTH,
275
+ ENVELOPE_HEADER_SIZE,
276
+ ENVELOPE_LAYOUT,
277
+ ENVELOPE_SALT_LENGTH,
278
+ ENVELOPE_VERSION,
279
+ FILE_FORMAT_FLAGS,
280
+ FILE_FORMAT_VERSION,
281
+ IV_LENGTH,
282
+ MAGIC_BYTES,
283
+ MAGIC_HEADER_SIZE,
284
+ SecureStoreLockedError,
285
+ filePathAad,
286
+ isEncryptedFile,
287
+ keyring,
288
+ readHeader,
289
+ secureStoreDir
290
+ } from "@remnic/core/secure-store";
291
+ async function createConfiguredOfflineStorage(memoryDir, secureStoreEncryptOnWrite = true) {
292
+ const storage = new StorageManager(memoryDir);
293
+ const header = await readHeader(memoryDir);
294
+ let secureStoreKey = null;
295
+ let secureStoreRequired = false;
296
+ if (header) {
297
+ secureStoreRequired = true;
298
+ storage.setSecureStoreRequired(true);
299
+ const key = keyring.getKey(secureStoreDir(memoryDir));
300
+ if (key) {
301
+ await storage.setSecureStoreKeyAndWait(key, secureStoreEncryptOnWrite);
302
+ secureStoreKey = key;
303
+ }
248
304
  }
249
- return { invalid: true };
305
+ return { storage, secureStoreKey, secureStoreRequired };
250
306
  }
251
- function buildNamespacePolicyCheck(args) {
252
- if (args.invalid) {
253
- return {
254
- name: "Namespace policy",
255
- ok: false,
256
- detail: "config `namespace` is set but is not a non-empty string",
257
- remediation: "Set `namespace` to a non-empty string (a namespacePolicies name or the default namespace), or remove it."
258
- };
307
+ async function createOfflineStorageForPath(memoryDir, filePath, configured, secureStoreEncryptOnWrite) {
308
+ const memoryRoot = path.resolve(memoryDir);
309
+ const stateDir = path.dirname(filePath);
310
+ if (path.basename(stateDir) !== "state" || path.basename(filePath) !== "memory-lifecycle-ledger.jsonl") {
311
+ throw new Error(`invalid lifecycle ledger path: ${filePath}`);
259
312
  }
260
- if (!args.config || !args.configuredNamespace) return void 0;
261
- const covered = isNamespacePolicyCovered(args.configuredNamespace, args.config);
313
+ const storageRoot = path.resolve(path.dirname(stateDir));
314
+ if (storageRoot !== memoryRoot && !storageRoot.startsWith(`${memoryRoot}${path.sep}`)) {
315
+ throw new Error(`lifecycle ledger path is outside the offline memory directory: ${filePath}`);
316
+ }
317
+ const storage = new StorageManager(storageRoot);
318
+ if (configured.secureStoreRequired) {
319
+ storage.setSecureStoreRequired(true);
320
+ }
321
+ if (configured.secureStoreKey) {
322
+ await storage.setSecureStoreKeyAndWait(configured.secureStoreKey, secureStoreEncryptOnWrite);
323
+ }
324
+ return storage;
325
+ }
326
+ async function createOfflineStorageIo(memoryDir, configuredStorage) {
327
+ await cleanupOrphanedOfflineDecryptStaging(memoryDir);
328
+ const { storage, secureStoreKey } = configuredStorage ?? await createConfiguredOfflineStorage(memoryDir);
262
329
  return {
263
- name: "Namespace policy",
264
- ok: covered,
265
- warn: !covered,
266
- 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`,
267
- 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.`
330
+ readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
331
+ readFileDigest: async ({ filePath }) => {
332
+ const hash = createHash("sha256");
333
+ let bytes = 0;
334
+ for await (const rawChunk of readOfflineSyncFileChunks({
335
+ filePath,
336
+ memoryDir,
337
+ secureStoreKey,
338
+ chunkSize: OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES
339
+ })) {
340
+ const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
341
+ hash.update(chunk);
342
+ bytes += chunk.length;
343
+ }
344
+ return {
345
+ sha256: hash.digest("hex"),
346
+ bytes
347
+ };
348
+ },
349
+ readFileChunks: ({ filePath, chunkSize }) => readOfflineSyncFileChunks({
350
+ filePath,
351
+ memoryDir,
352
+ secureStoreKey,
353
+ chunkSize
354
+ }),
355
+ writeFile: async ({ filePath, content }) => storage.writeOfflineSyncFile(filePath, content),
356
+ writeStagingFile: async ({ filePath, content }) => storage.writeOfflineSyncStagingFile(filePath, content),
357
+ writeFileChunks: async ({ filePath, chunks }) => storage.writeOfflineSyncFileChunks(filePath, chunks),
358
+ deleteFile: async ({ filePath }) => storage.deleteOfflineSyncFile(filePath)
268
359
  };
269
360
  }
270
-
271
- // src/index.ts
272
- import { WriteQuarantineStore as WriteQuarantineStore2 } from "@remnic/core/write-quarantine.js";
273
-
274
- // src/quarantine-cli.ts
275
- import { basename } from "path";
276
- function renderQuarantineList(records, format) {
277
- if (format === "json") {
278
- const summary = records.map((record) => ({
279
- timestamp: record.timestamp,
280
- operation: record.operation,
281
- principal: record.principal,
282
- attemptedNamespace: record.attemptedNamespace
283
- }));
284
- return JSON.stringify(summary, null, 2);
361
+ var OFFLINE_DECRYPT_STAGING_ORPHAN_MS = 60 * 60 * 1e3;
362
+ async function cleanupOrphanedOfflineDecryptStaging(memoryDir) {
363
+ let entries;
364
+ try {
365
+ entries = await readdir(memoryDir);
366
+ } catch {
367
+ return;
285
368
  }
286
- if (format !== "text") {
287
- throw new Error(`Unsupported quarantine format: ${String(format)}`);
369
+ const now = Date.now();
370
+ for (const name of entries) {
371
+ if (!name.startsWith(OFFLINE_DECRYPT_STAGING_DIR_PREFIX)) continue;
372
+ const dir = path.join(memoryDir, name);
373
+ try {
374
+ const info = await lstat(dir);
375
+ if (!info.isDirectory() || info.isSymbolicLink()) continue;
376
+ if (now - info.mtimeMs < OFFLINE_DECRYPT_STAGING_ORPHAN_MS) continue;
377
+ await rm(dir, { recursive: true, force: true });
378
+ } catch {
379
+ }
288
380
  }
289
- if (records.length === 0) return "No quarantined writes.";
290
- const lines = [`Quarantined writes (${records.length}):`, ""];
291
- for (const record of records) {
292
- lines.push(
293
- ` ${record.timestamp} ${record.operation} principal=${record.principal ?? "-"} attemptedNamespace=${record.attemptedNamespace}`
381
+ }
382
+ async function* readOfflineSyncFileChunks(options) {
383
+ const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE);
384
+ if (!isEncryptedFile(header)) {
385
+ yield* readPlainOfflineFileChunks(options.filePath, options.chunkSize);
386
+ return;
387
+ }
388
+ if (!options.secureStoreKey) {
389
+ throw new SecureStoreLockedError(
390
+ `secure-store is locked \u2014 cannot read encrypted file at ${options.filePath}. Run \`remnic secure-store unlock\` to decrypt.`
294
391
  );
295
392
  }
296
- return lines.join("\n");
393
+ yield* readEncryptedOfflineFileChunks({
394
+ filePath: options.filePath,
395
+ memoryDir: options.memoryDir,
396
+ key: options.secureStoreKey,
397
+ chunkSize: options.chunkSize
398
+ });
297
399
  }
298
- async function replayQuarantine(opts) {
299
- const result = { replayed: 0, failures: [], deleteFailures: [] };
300
- for (const entry of await opts.store.entries()) {
301
- const { record } = entry;
302
- const basePayload = record.payload;
303
- const principal = opts.principal ?? record.principal ?? void 0;
304
- const idempotencyKey = typeof basePayload.idempotencyKey === "string" && basePayload.idempotencyKey.length > 0 ? basePayload.idempotencyKey : `quarantine-replay:${basename(entry.path)}`;
305
- const request = {
306
- ...basePayload,
307
- namespace: opts.targetNamespace,
308
- suppressQuarantine: true,
309
- idempotencyKey,
310
- ...principal ? { authenticatedPrincipal: principal } : {}
311
- };
312
- try {
313
- await opts.submit(record.operation, request);
314
- } catch (err) {
315
- result.failures.push({
316
- operation: record.operation,
317
- attemptedNamespace: opts.targetNamespace,
318
- error: err instanceof Error ? err.message : String(err)
319
- });
320
- continue;
321
- }
322
- try {
323
- const removed = await opts.store.removeEntry(entry.path);
324
- if (removed) {
325
- result.replayed += 1;
326
- } else {
327
- result.deleteFailures.push({
328
- path: entry.path,
329
- error: "entry not removed (outside quarantine root or already absent)"
330
- });
331
- }
332
- } catch (err) {
333
- result.deleteFailures.push({
334
- path: entry.path,
335
- error: err instanceof Error ? err.message : String(err)
336
- });
337
- }
400
+ async function readFilePrefix(filePath, length) {
401
+ const handle = await fs2.promises.open(filePath, "r");
402
+ try {
403
+ const out = Buffer.alloc(length);
404
+ const { bytesRead } = await handle.read(out, 0, length, 0);
405
+ return out.subarray(0, bytesRead);
406
+ } finally {
407
+ await handle.close();
338
408
  }
339
- return result;
340
409
  }
341
- function renderReplayResult(result, targetNamespace, format) {
342
- if (format === "json") {
343
- return JSON.stringify(
344
- {
345
- targetNamespace,
346
- replayed: result.replayed,
347
- failures: result.failures,
348
- deleteFailures: result.deleteFailures
349
- },
350
- null,
351
- 2
352
- );
410
+ async function* readPlainOfflineFileChunks(filePath, chunkSize) {
411
+ const stream = fs2.createReadStream(filePath, { highWaterMark: chunkSize });
412
+ for await (const chunk of stream) {
413
+ yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
353
414
  }
354
- if (format !== "text") {
355
- throw new Error(`Unsupported quarantine format: ${String(format)}`);
415
+ }
416
+ async function* readEncryptedOfflineFileChunks(options) {
417
+ const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
418
+ if (header.length < MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE || !isEncryptedFile(header)) {
419
+ throw new Error(`secure-store encrypted file is truncated: ${options.filePath}`);
420
+ }
421
+ const version = header.readUInt8(MAGIC_BYTES.length);
422
+ const flags = header.readUInt8(MAGIC_BYTES.length + 1);
423
+ if (version !== FILE_FORMAT_VERSION) {
424
+ throw new Error(`secure-store file has unsupported version ${version}: ${options.filePath}`);
425
+ }
426
+ if (flags !== FILE_FORMAT_FLAGS) {
427
+ throw new Error(`secure-store file has unsupported flags 0x${flags.toString(16)}: ${options.filePath}`);
428
+ }
429
+ const envelopeHeader = header.subarray(MAGIC_HEADER_SIZE);
430
+ const envelopeVersion = envelopeHeader.readUInt8(ENVELOPE_LAYOUT.version);
431
+ if (envelopeVersion !== ENVELOPE_VERSION) {
432
+ throw new Error(`secure-store envelope has unsupported version ${envelopeVersion}: ${options.filePath}`);
433
+ }
434
+ const salt = envelopeHeader.subarray(
435
+ ENVELOPE_LAYOUT.salt,
436
+ ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH
437
+ );
438
+ const iv = envelopeHeader.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);
439
+ const authTag = envelopeHeader.subarray(
440
+ ENVELOPE_LAYOUT.authTag,
441
+ ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
442
+ );
443
+ const aadCandidates = offlineFileAadCandidates(options.filePath, options.memoryDir);
444
+ let lastError;
445
+ for (const aad of aadCandidates) {
446
+ const tempDir = await mkdtemp(path.join(options.memoryDir, OFFLINE_DECRYPT_STAGING_DIR_PREFIX));
447
+ const tempPath = path.join(tempDir, "content");
448
+ try {
449
+ const decipher = createDecipheriv("aes-256-gcm", options.key, iv, {
450
+ authTagLength: AUTH_TAG_LENGTH
451
+ });
452
+ decipher.setAuthTag(authTag);
453
+ decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), aad]));
454
+ const output = fs2.createWriteStream(tempPath, { mode: 384 });
455
+ try {
456
+ const stream = fs2.createReadStream(options.filePath, {
457
+ start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
458
+ highWaterMark: options.chunkSize
459
+ });
460
+ for await (const encryptedChunk of stream) {
461
+ const plain = decipher.update(
462
+ Buffer.isBuffer(encryptedChunk) ? encryptedChunk : Buffer.from(encryptedChunk)
463
+ );
464
+ if (plain.length > 0 && !output.write(plain)) {
465
+ await new Promise((resolve, reject) => {
466
+ output.once("drain", resolve);
467
+ output.once("error", reject);
468
+ });
469
+ }
470
+ }
471
+ const finalPlain = decipher.final();
472
+ if (finalPlain.length > 0 && !output.write(finalPlain)) {
473
+ await new Promise((resolve, reject) => {
474
+ output.once("drain", resolve);
475
+ output.once("error", reject);
476
+ });
477
+ }
478
+ } finally {
479
+ await closeWriteStream(output);
480
+ }
481
+ yield* readPlainOfflineFileChunks(tempPath, options.chunkSize);
482
+ return;
483
+ } catch (error) {
484
+ lastError = error;
485
+ } finally {
486
+ await rm(tempDir, { recursive: true, force: true });
487
+ }
488
+ }
489
+ throw lastError instanceof Error ? lastError : new Error(`secure-store could not decrypt file: ${options.filePath}`);
490
+ }
491
+ function offlineFileAadCandidates(filePath, memoryDir) {
492
+ const candidates = [filePathAad(filePath, memoryDir)];
493
+ const relative = path.relative(memoryDir, filePath);
494
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return candidates;
495
+ const parts = relative.split(path.sep);
496
+ if (parts[0] === "namespaces" && parts.length >= 3 && parts[1]) {
497
+ candidates.push(filePathAad(filePath, path.join(memoryDir, "namespaces", parts[1])));
498
+ }
499
+ const memoryParts = path.resolve(memoryDir).split(path.sep);
500
+ if (memoryParts.length >= 3 && memoryParts.at(-2) === "namespaces" && memoryParts.at(-1)) {
501
+ const topLevelRoot = memoryParts.slice(0, -2).join(path.sep) || path.sep;
502
+ const topRelative = path.relative(topLevelRoot, filePath);
503
+ if (topRelative && !topRelative.startsWith("..") && !path.isAbsolute(topRelative) && topRelative.split(path.sep)[0] === "namespaces" && topRelative.split(path.sep)[1] === memoryParts.at(-1)) {
504
+ candidates.push(filePathAad(filePath, topLevelRoot));
505
+ }
506
+ }
507
+ return candidates;
508
+ }
509
+ async function closeWriteStream(stream) {
510
+ await new Promise((resolve, reject) => {
511
+ stream.once("error", reject);
512
+ stream.end(() => resolve());
513
+ });
514
+ }
515
+ function secureStoreEnvelopeHeaderAad(salt) {
516
+ const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
517
+ out.writeUInt8(ENVELOPE_VERSION, 0);
518
+ Buffer.from(salt).copy(out, 1);
519
+ return out;
520
+ }
521
+
522
+ // src/converge.ts
523
+ import { resolveAgentAccessAuthToken } from "@remnic/core/resolve-auth-token.js";
524
+ async function readLocalTombstones(rootDir) {
525
+ const shaSet = /* @__PURE__ */ new Set();
526
+ const candidates = [
527
+ path2.join(rootDir, "state", "tombstones.jsonl"),
528
+ path2.join(rootDir, "tombstones.jsonl")
529
+ ];
530
+ for (const tombPath of candidates) {
531
+ try {
532
+ const content = await fs3.promises.readFile(tombPath, "utf-8");
533
+ for (const line of content.split("\n")) {
534
+ const trimmed = line.trim();
535
+ if (!trimmed) continue;
536
+ try {
537
+ const record = JSON.parse(trimmed);
538
+ if (typeof record.contentHash === "string" && /^[0-9a-f]{64}$/i.test(record.contentHash)) {
539
+ shaSet.add(record.contentHash.toLowerCase());
540
+ }
541
+ if (typeof record.fileSha256 === "string" && /^[0-9a-f]{64}$/i.test(record.fileSha256)) {
542
+ shaSet.add(record.fileSha256.toLowerCase());
543
+ }
544
+ } catch {
545
+ }
546
+ }
547
+ } catch {
548
+ }
549
+ }
550
+ return shaSet;
551
+ }
552
+ async function fetchPeerSnapshot(peerUrl, namespace, token, fetchImpl = globalThis.fetch) {
553
+ let base = peerUrl;
554
+ while (base.endsWith("/")) {
555
+ base = base.slice(0, -1);
556
+ }
557
+ const routes = [
558
+ `/remnic/v1/offline-sync/snapshot?namespace=${encodeURIComponent(namespace)}&content=false`,
559
+ `/engram/v1/offline-sync/snapshot?namespace=${encodeURIComponent(namespace)}&content=false`
560
+ ];
561
+ const headers = token ? { authorization: `Bearer ${token}` } : {};
562
+ let lastFailure = "no snapshot route responded";
563
+ for (const route of routes) {
564
+ let response;
565
+ try {
566
+ response = await fetchImpl(`${base}${route}`, { headers });
567
+ } catch (error) {
568
+ lastFailure = error instanceof Error ? error.message : String(error);
569
+ continue;
570
+ }
571
+ if (!response.ok) {
572
+ lastFailure = `HTTP ${response.status}`;
573
+ continue;
574
+ }
575
+ let data;
576
+ try {
577
+ data = await response.json();
578
+ } catch {
579
+ throw new Error(`invalid peer snapshot for namespace ${namespace}: response was not JSON`);
580
+ }
581
+ if (!data || typeof data !== "object" || !("files" in data) || !Array.isArray(data.files)) {
582
+ throw new Error(`invalid peer snapshot for namespace ${namespace}: files must be an array`);
583
+ }
584
+ const files = data.files.map((item, index) => {
585
+ if (!item || typeof item !== "object" || !("path" in item) || typeof item.path !== "string" || !("sha256" in item) || typeof item.sha256 !== "string") {
586
+ throw new Error(`invalid peer snapshot for namespace ${namespace}: malformed file at index ${index}`);
587
+ }
588
+ return {
589
+ path: item.path,
590
+ sha256: item.sha256,
591
+ mtimeMs: "mtimeMs" in item && typeof item.mtimeMs === "number" ? item.mtimeMs : void 0,
592
+ bytes: "bytes" in item && typeof item.bytes === "number" ? item.bytes : void 0
593
+ };
594
+ });
595
+ const rawTombstones = "tombstones" in data ? data.tombstones : void 0;
596
+ if (rawTombstones !== void 0 && !Array.isArray(rawTombstones)) {
597
+ throw new Error(`invalid peer snapshot for namespace ${namespace}: tombstones must be an array`);
598
+ }
599
+ const tombstones = /* @__PURE__ */ new Set();
600
+ for (const tombstone of rawTombstones ?? []) {
601
+ if (typeof tombstone !== "string" || !/^[0-9a-f]{64}$/i.test(tombstone)) {
602
+ throw new Error(`invalid peer snapshot for namespace ${namespace}: malformed tombstone`);
603
+ }
604
+ tombstones.add(tombstone.toLowerCase());
605
+ }
606
+ return { files, tombstones };
607
+ }
608
+ throw new Error(`failed to fetch peer snapshot for namespace ${namespace}: ${lastFailure}`);
609
+ }
610
+ function requiredResponseNumber(response, name) {
611
+ const raw = response.headers.get(name);
612
+ const value = raw === null ? Number.NaN : Number(raw);
613
+ if (!Number.isFinite(value) || value < 0) {
614
+ throw new Error(`offline file content response had invalid ${name}`);
615
+ }
616
+ return value;
617
+ }
618
+ async function fetchPeerFileContent(peerUrl, namespace, filePath, token, fetchImpl = globalThis.fetch) {
619
+ const base = peerUrl.replace(/\/+$/, "");
620
+ const routes = [
621
+ "/remnic/v1/offline-sync/file-content",
622
+ "/engram/v1/offline-sync/file-content"
623
+ ];
624
+ const headers = {
625
+ "content-type": "application/json",
626
+ ...token ? { authorization: `Bearer ${token}` } : {}
627
+ };
628
+ for (const route of routes) {
629
+ try {
630
+ const chunks = [];
631
+ const hash = createHash2("sha256");
632
+ let offset = 0;
633
+ let expectedBytes;
634
+ let expectedSha256;
635
+ let mtimeMs;
636
+ do {
637
+ const response = await fetchImpl(`${base}${route}`, {
638
+ method: "POST",
639
+ headers,
640
+ body: JSON.stringify({
641
+ namespace,
642
+ includeTranscripts: false,
643
+ path: filePath,
644
+ offset,
645
+ length: OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES
646
+ })
647
+ });
648
+ if (!response.ok) throw new Error(`offline file content request failed: ${response.status}`);
649
+ const content = Buffer.from(await response.arrayBuffer());
650
+ const chunkOffset = requiredResponseNumber(response, "x-remnic-chunk-offset");
651
+ const chunkBytes = requiredResponseNumber(response, "x-remnic-chunk-bytes");
652
+ const totalBytes = requiredResponseNumber(response, "x-remnic-file-bytes");
653
+ const responseMtimeMs = requiredResponseNumber(response, "x-remnic-file-mtime-ms");
654
+ const sha256 = response.headers.get("x-remnic-file-sha256");
655
+ const encodedPath = response.headers.get("x-remnic-file-path");
656
+ if (!sha256 || chunkOffset !== offset || chunkBytes !== content.length || encodedPath !== null && decodeURIComponent(encodedPath) !== filePath || expectedBytes !== void 0 && expectedBytes !== totalBytes || expectedSha256 !== void 0 && expectedSha256 !== sha256) {
657
+ throw new Error(`offline file content response changed during transfer: ${filePath}`);
658
+ }
659
+ if (content.length === 0 && offset < totalBytes) {
660
+ throw new Error(`offline file content chunk was empty before EOF: ${filePath}`);
661
+ }
662
+ expectedBytes = totalBytes;
663
+ expectedSha256 = sha256;
664
+ mtimeMs = responseMtimeMs;
665
+ chunks.push(content);
666
+ hash.update(content);
667
+ offset += content.length;
668
+ } while (expectedBytes === void 0 || offset < expectedBytes);
669
+ if (expectedBytes === void 0 || expectedSha256 === void 0 || mtimeMs === void 0 || offset !== expectedBytes || hash.digest("hex") !== expectedSha256) {
670
+ throw new Error(`offline file content checksum mismatch: ${filePath}`);
671
+ }
672
+ return {
673
+ content: Buffer.concat(chunks, expectedBytes),
674
+ sha256: expectedSha256,
675
+ bytes: expectedBytes,
676
+ mtimeMs
677
+ };
678
+ } catch {
679
+ }
680
+ }
681
+ return null;
682
+ }
683
+ async function postPeerFileContent(peerUrl, namespace, filePath, content, metadata, token, fetchImpl = globalThis.fetch) {
684
+ const base = peerUrl.replace(/\/+$/, "");
685
+ const routes = [
686
+ `/remnic/v1/offline-sync/apply-file-content?namespace=${encodeURIComponent(namespace)}`,
687
+ `/engram/v1/offline-sync/apply-file-content?namespace=${encodeURIComponent(namespace)}`
688
+ ];
689
+ for (const route of routes) {
690
+ try {
691
+ let offset = 0;
692
+ do {
693
+ const chunk = content.subarray(
694
+ offset,
695
+ Math.min(content.length, offset + OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2)
696
+ );
697
+ const headers = {
698
+ "content-type": "application/octet-stream",
699
+ "x-remnic-include-transcripts": "false",
700
+ "x-remnic-source-id": encodeURIComponent("remnic-converge"),
701
+ "x-remnic-file-path": encodeURIComponent(filePath),
702
+ "x-remnic-file-sha256": metadata.sha256,
703
+ "x-remnic-file-bytes": String(content.length),
704
+ "x-remnic-file-mtime-ms": String(metadata.mtimeMs),
705
+ "x-remnic-chunk-offset": String(offset),
706
+ ...metadata.baseSha256 ? { "x-remnic-base-sha256": metadata.baseSha256 } : {},
707
+ ...token ? { authorization: `Bearer ${token}` } : {}
708
+ };
709
+ const response = await fetchImpl(`${base}${route}`, {
710
+ method: "POST",
711
+ headers,
712
+ body: new Uint8Array(chunk)
713
+ });
714
+ if (!response.ok) throw new Error(`offline apply-file-content request failed: ${response.status}`);
715
+ const result = await response.json().catch(() => null);
716
+ if (!result || typeof result !== "object" || !("done" in result) || typeof result.done !== "boolean" || !("applied" in result) || typeof result.applied !== "boolean" || !("skipped" in result) || typeof result.skipped !== "boolean" || "conflict" in result && result.conflict) {
717
+ return false;
718
+ }
719
+ if (result.done) {
720
+ return result.skipped || result.applied && offset + chunk.length === content.length;
721
+ }
722
+ if (result.applied || result.skipped || chunk.length === 0) {
723
+ return false;
724
+ }
725
+ offset += chunk.length;
726
+ } while (offset < content.length);
727
+ return false;
728
+ } catch {
729
+ }
730
+ }
731
+ return false;
732
+ }
733
+ async function computeConvergePlan(options = {}) {
734
+ const baseMap = /* @__PURE__ */ new Map();
735
+ const namespacesToPlan = /* @__PURE__ */ new Set();
736
+ const localMap = /* @__PURE__ */ new Map();
737
+ const localTombstones = /* @__PURE__ */ new Map();
738
+ const peerMap = /* @__PURE__ */ new Map();
739
+ const peerTombstones = /* @__PURE__ */ new Map();
740
+ if (options.baseFilesByNamespace) {
741
+ for (const [ns, files] of options.baseFilesByNamespace) {
742
+ namespacesToPlan.add(ns);
743
+ baseMap.set(ns, files);
744
+ }
745
+ }
746
+ if (options.localFilesByNamespace) {
747
+ for (const [ns, files] of options.localFilesByNamespace) {
748
+ namespacesToPlan.add(ns);
749
+ localMap.set(ns, files);
750
+ }
751
+ }
752
+ if (options.localTombstonesByNamespace) {
753
+ for (const [ns, tombstones] of options.localTombstonesByNamespace) {
754
+ localTombstones.set(ns, new Set(tombstones));
755
+ }
756
+ }
757
+ if (options.peerFilesByNamespace) {
758
+ for (const [ns, files] of options.peerFilesByNamespace) {
759
+ namespacesToPlan.add(ns);
760
+ peerMap.set(ns, files);
761
+ }
762
+ }
763
+ if (options.peerTombstonesByNamespace) {
764
+ for (const [ns, tombstones] of options.peerTombstonesByNamespace) {
765
+ peerTombstones.set(ns, new Set(tombstones));
766
+ }
767
+ }
768
+ let config = options.config;
769
+ if (!config) {
770
+ try {
771
+ config = parseConfig2({});
772
+ } catch {
773
+ }
774
+ }
775
+ if (!options.localFilesByNamespace && config) {
776
+ const roots = await resolveCorpusNamespaceRoots({ config });
777
+ const discovered = await listNamespaces({ config });
778
+ for (const entry of discovered) {
779
+ namespacesToPlan.add(entry.namespace);
780
+ }
781
+ for (const rootInfo of roots) {
782
+ const ns = rootInfo.namespace;
783
+ namespacesToPlan.add(ns);
784
+ try {
785
+ const snapshot = await buildOfflineSyncSnapshotFromBase({
786
+ root: rootInfo.rootDir,
787
+ sourceId: "local",
788
+ includeContent: false
789
+ });
790
+ const files = snapshot.files.map((record) => ({
791
+ path: record.path,
792
+ sha256: record.sha256,
793
+ mtimeMs: record.mtimeMs,
794
+ bytes: record.bytes
795
+ }));
796
+ localMap.set(ns, files);
797
+ const tombstones = await readLocalTombstones(rootInfo.rootDir);
798
+ localTombstones.set(ns, tombstones);
799
+ } catch {
800
+ localMap.set(ns, []);
801
+ }
802
+ }
803
+ }
804
+ if (!options.peerFilesByNamespace && options.peerUrl) {
805
+ let resolvedToken;
806
+ if (options.peerToken) {
807
+ try {
808
+ resolvedToken = await resolveAgentAccessAuthToken(options.peerToken, {
809
+ resolveSecretRef: options.resolveSecretRef
810
+ });
811
+ } catch {
812
+ resolvedToken = options.peerToken;
813
+ }
814
+ }
815
+ const fetchFn = options.fetchImpl ?? globalThis.fetch;
816
+ for (const ns of namespacesToPlan) {
817
+ const peerData = await fetchPeerSnapshot(options.peerUrl, ns, resolvedToken, fetchFn);
818
+ peerMap.set(ns, peerData.files);
819
+ peerTombstones.set(ns, peerData.tombstones);
820
+ }
821
+ }
822
+ const memoryDir = options.cursorDir ?? config?.memoryDir;
823
+ if (!options.baseFilesByNamespace && memoryDir && options.peerUrl) {
824
+ for (const ns of namespacesToPlan) {
825
+ const cursorPath = defaultConvergeCursorPath(memoryDir, options.peerUrl, ns);
826
+ const cursor = await readConvergeCursor(cursorPath);
827
+ if (cursor?.baseFiles && cursor.baseFiles.length > 0) {
828
+ baseMap.set(ns, cursor.baseFiles);
829
+ }
830
+ }
831
+ }
832
+ const inputs = [];
833
+ for (const ns of [...namespacesToPlan].sort()) {
834
+ inputs.push({
835
+ namespace: ns,
836
+ local: localMap.get(ns) ?? [],
837
+ peer: peerMap.get(ns) ?? [],
838
+ base: baseMap.get(ns),
839
+ tombstonedFileSha256: localTombstones.get(ns) ?? [],
840
+ peerTombstonedFileSha256: peerTombstones.get(ns) ?? []
841
+ });
842
+ }
843
+ return planReconciliation(inputs, { conflictPolicy: options.conflictPolicy });
844
+ }
845
+ async function executeConvergeApply(options = {}) {
846
+ const conflictPolicy = options.conflictPolicy ?? "manual";
847
+ const plan = await computeConvergePlan({ ...options, conflictPolicy });
848
+ if (plan.converged && !options.dryRun) {
849
+ await updateCursorsForPlan(plan, options);
850
+ return {
851
+ converged: true,
852
+ status: "converged",
853
+ plan,
854
+ transfers: { pulled: 0, pushed: 0, conflictsResolved: 0, suppressed: 0, failed: 0 },
855
+ cursorUpdated: true
856
+ };
857
+ }
858
+ const unresolvedCount = plan.byNamespace.reduce((acc, report) => acc + report.unresolved, 0);
859
+ if (unresolvedCount > 0 && conflictPolicy === "manual") {
860
+ return {
861
+ converged: false,
862
+ status: "stopped_unresolved_conflicts",
863
+ plan,
864
+ transfers: { pulled: 0, pushed: 0, conflictsResolved: 0, suppressed: 0, failed: 0 },
865
+ cursorUpdated: false
866
+ };
867
+ }
868
+ const plannedTransfers = {
869
+ pulled: 0,
870
+ pushed: 0,
871
+ conflictsResolved: 0,
872
+ suppressed: 0,
873
+ failed: 0
874
+ };
875
+ for (const entry of plan.entries) {
876
+ if (entry.action === "pull") plannedTransfers.pulled += 1;
877
+ else if (entry.action === "push") plannedTransfers.pushed += 1;
878
+ else if (entry.action === "conflict") plannedTransfers.conflictsResolved += 1;
879
+ else if (entry.action === "suppress") plannedTransfers.suppressed += 1;
880
+ }
881
+ if (options.dryRun) {
882
+ return {
883
+ converged: false,
884
+ status: "dry_run",
885
+ plan,
886
+ transfers: plannedTransfers,
887
+ cursorUpdated: false
888
+ };
889
+ }
890
+ const actualTransfers = {
891
+ pulled: 0,
892
+ pushed: 0,
893
+ conflictsResolved: 0,
894
+ suppressed: 0,
895
+ failed: 0
896
+ };
897
+ let resolvedToken;
898
+ if (options.peerToken) {
899
+ try {
900
+ resolvedToken = await resolveAgentAccessAuthToken(options.peerToken, {
901
+ resolveSecretRef: options.resolveSecretRef
902
+ });
903
+ } catch {
904
+ resolvedToken = options.peerToken;
905
+ }
906
+ }
907
+ const fetchFn = options.fetchImpl ?? globalThis.fetch;
908
+ let config = options.config;
909
+ if (!config) {
910
+ try {
911
+ config = parseConfig2({});
912
+ } catch {
913
+ }
914
+ }
915
+ const rootMap = /* @__PURE__ */ new Map();
916
+ if (config) {
917
+ try {
918
+ const roots = await resolveCorpusNamespaceRoots({ config });
919
+ for (const r of roots) {
920
+ rootMap.set(r.namespace, r.rootDir);
921
+ }
922
+ } catch {
923
+ }
924
+ }
925
+ for (const entry of plan.entries) {
926
+ if (entry.action === "identical") continue;
927
+ let transferType = "none";
928
+ if (entry.action === "pull") {
929
+ transferType = "pull";
930
+ } else if (entry.action === "push") {
931
+ transferType = "push";
932
+ } else if (entry.action === "suppress") {
933
+ transferType = "suppress";
934
+ } else if (entry.action === "conflict") {
935
+ if (entry.resolution === "peer-wins") {
936
+ transferType = "pull";
937
+ } else if (entry.resolution === "local-wins") {
938
+ transferType = "push";
939
+ } else if (entry.resolution === "supersede-link") {
940
+ if (entry.newerSide === "peer") transferType = "pull";
941
+ else if (entry.newerSide === "local") transferType = "push";
942
+ }
943
+ }
944
+ if (transferType === "pull") {
945
+ let remoteFile = null;
946
+ const buffered = options.peerFileBuffers?.get(entry.namespace)?.get(entry.path);
947
+ if (buffered) {
948
+ const state = options.peerFilesByNamespace?.get(entry.namespace)?.find((file) => file.path === entry.path);
949
+ remoteFile = {
950
+ content: buffered,
951
+ sha256: state?.sha256 ?? entry.peerSha256 ?? createHash2("sha256").update(buffered).digest("hex"),
952
+ bytes: buffered.length,
953
+ mtimeMs: state?.mtimeMs ?? 0
954
+ };
955
+ } else if (options.peerUrl) {
956
+ remoteFile = await fetchPeerFileContent(
957
+ options.peerUrl,
958
+ entry.namespace,
959
+ entry.path,
960
+ resolvedToken,
961
+ fetchFn
962
+ );
963
+ }
964
+ if (remoteFile !== null && (!entry.peerSha256 || remoteFile.sha256 === entry.peerSha256)) {
965
+ if (options.localFileBuffers) {
966
+ let nsMap = options.localFileBuffers.get(entry.namespace);
967
+ if (!nsMap) {
968
+ nsMap = /* @__PURE__ */ new Map();
969
+ options.localFileBuffers.set(entry.namespace, nsMap);
970
+ }
971
+ nsMap.set(entry.path, remoteFile.content);
972
+ if (entry.action === "conflict") actualTransfers.conflictsResolved += 1;
973
+ else actualTransfers.pulled += 1;
974
+ } else {
975
+ const rootDir = rootMap.get(entry.namespace);
976
+ if (rootDir) {
977
+ const io = await createOfflineStorageIo(rootDir);
978
+ const expectedLocalSha256 = entry.action === "conflict" ? entry.localSha256 : entry.baseSha256;
979
+ let offset = 0;
980
+ let transferComplete = false;
981
+ do {
982
+ const chunk = remoteFile.content.subarray(
983
+ offset,
984
+ Math.min(
985
+ remoteFile.content.length,
986
+ offset + OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2
987
+ )
988
+ );
989
+ const chunkResult = await applyOfflineSyncFileContentChunk({
990
+ root: rootDir,
991
+ sourceId: "remnic-converge",
992
+ path: entry.path,
993
+ sha256: remoteFile.sha256,
994
+ bytes: remoteFile.bytes,
995
+ mtimeMs: remoteFile.mtimeMs,
996
+ offset,
997
+ content: chunk,
998
+ ...expectedLocalSha256 ? { baseSha256: expectedLocalSha256 } : {},
999
+ readFile: io.readFile,
1000
+ readFileDigest: io.readFileDigest,
1001
+ writeFile: io.writeFile,
1002
+ writeStagingFile: io.writeStagingFile,
1003
+ writeFileChunks: io.writeFileChunks
1004
+ });
1005
+ if (chunkResult.conflict) {
1006
+ break;
1007
+ }
1008
+ if (chunkResult.done) {
1009
+ transferComplete = chunkResult.applied || chunkResult.skipped;
1010
+ break;
1011
+ }
1012
+ if (chunkResult.applied || chunkResult.skipped || chunk.length === 0) {
1013
+ break;
1014
+ }
1015
+ offset += chunk.length;
1016
+ } while (offset < remoteFile.content.length);
1017
+ if (transferComplete) {
1018
+ if (entry.action === "conflict") actualTransfers.conflictsResolved += 1;
1019
+ else actualTransfers.pulled += 1;
1020
+ } else {
1021
+ actualTransfers.failed += 1;
1022
+ }
1023
+ } else {
1024
+ actualTransfers.failed += 1;
1025
+ }
1026
+ }
1027
+ } else {
1028
+ actualTransfers.failed += 1;
1029
+ }
1030
+ } else if (transferType === "push") {
1031
+ let content = null;
1032
+ let mtimeMs = options.localFilesByNamespace?.get(entry.namespace)?.find((file) => file.path === entry.path)?.mtimeMs;
1033
+ if (options.localFileBuffers?.get(entry.namespace)?.has(entry.path)) {
1034
+ content = options.localFileBuffers.get(entry.namespace).get(entry.path);
1035
+ } else {
1036
+ const rootDir = rootMap.get(entry.namespace);
1037
+ if (rootDir) {
1038
+ const filePath = path2.join(rootDir, entry.path);
1039
+ try {
1040
+ const io = await createOfflineStorageIo(rootDir);
1041
+ content = await io.readFile({ root: rootDir, path: entry.path, filePath });
1042
+ mtimeMs ??= (await fs3.promises.stat(filePath)).mtimeMs;
1043
+ } catch {
1044
+ content = null;
1045
+ }
1046
+ }
1047
+ }
1048
+ if (content !== null) {
1049
+ if (options.peerFileBuffers) {
1050
+ let nsMap = options.peerFileBuffers.get(entry.namespace);
1051
+ if (!nsMap) {
1052
+ nsMap = /* @__PURE__ */ new Map();
1053
+ options.peerFileBuffers.set(entry.namespace, nsMap);
1054
+ }
1055
+ nsMap.set(entry.path, content);
1056
+ if (entry.action === "conflict") actualTransfers.conflictsResolved += 1;
1057
+ else actualTransfers.pushed += 1;
1058
+ } else if (options.peerUrl && entry.localSha256) {
1059
+ const expectedPeerSha256 = entry.action === "conflict" ? entry.peerSha256 : entry.baseSha256;
1060
+ const ok = await postPeerFileContent(
1061
+ options.peerUrl,
1062
+ entry.namespace,
1063
+ entry.path,
1064
+ content,
1065
+ {
1066
+ sha256: entry.localSha256,
1067
+ mtimeMs: mtimeMs ?? 0,
1068
+ ...expectedPeerSha256 ? { baseSha256: expectedPeerSha256 } : {}
1069
+ },
1070
+ resolvedToken,
1071
+ fetchFn
1072
+ );
1073
+ if (ok) {
1074
+ if (entry.action === "conflict") actualTransfers.conflictsResolved += 1;
1075
+ else actualTransfers.pushed += 1;
1076
+ } else {
1077
+ actualTransfers.failed += 1;
1078
+ }
1079
+ } else {
1080
+ actualTransfers.failed += 1;
1081
+ }
1082
+ } else {
1083
+ actualTransfers.failed += 1;
1084
+ }
1085
+ } else if (transferType === "suppress") {
1086
+ actualTransfers.suppressed += 1;
1087
+ }
1088
+ }
1089
+ let cursorUpdated = false;
1090
+ if (actualTransfers.failed === 0) {
1091
+ await updateCursorsForPlan(plan, options);
1092
+ cursorUpdated = true;
1093
+ }
1094
+ return {
1095
+ converged: actualTransfers.failed === 0,
1096
+ status: "applied",
1097
+ plan,
1098
+ transfers: actualTransfers,
1099
+ cursorUpdated
1100
+ };
1101
+ }
1102
+ async function updateCursorsForPlan(plan, options) {
1103
+ const peerUrl = options.peerUrl ?? "local";
1104
+ let memoryDir;
1105
+ if (options.cursorDir) {
1106
+ memoryDir = options.cursorDir;
1107
+ } else if (options.config) {
1108
+ memoryDir = options.config.memoryDir;
1109
+ }
1110
+ if (!memoryDir) return;
1111
+ const namespaces = new Set(plan.byNamespace.map((n) => n.namespace));
1112
+ for (const ns of namespaces) {
1113
+ const cursorPath = defaultConvergeCursorPath(memoryDir, peerUrl, ns);
1114
+ const nsEntries = plan.entries.filter((e) => e.namespace === ns);
1115
+ const baseFiles = nsEntries.map((e) => ({
1116
+ path: e.path,
1117
+ sha256: e.localSha256 ?? e.peerSha256 ?? "unknown"
1118
+ }));
1119
+ const cursorState = {
1120
+ version: 1,
1121
+ peerUrl,
1122
+ namespace: ns,
1123
+ lastConvergedAt: (/* @__PURE__ */ new Date()).toISOString(),
1124
+ baseFiles
1125
+ };
1126
+ try {
1127
+ await writeConvergeCursor(cursorPath, cursorState);
1128
+ } catch {
1129
+ }
1130
+ }
1131
+ }
1132
+ function formatConvergeReport(plan) {
1133
+ const lines = [];
1134
+ lines.push(`Convergence Status: ${plan.converged ? "CONVERGED" : "DIVERGED"}`);
1135
+ lines.push("");
1136
+ lines.push("Per-Namespace Summary:");
1137
+ if (plan.byNamespace.length === 0) {
1138
+ lines.push(" (no namespaces evaluated)");
1139
+ } else {
1140
+ for (const report of plan.byNamespace) {
1141
+ lines.push(` [${report.namespace}]`);
1142
+ lines.push(` identical: ${report.identical}`);
1143
+ lines.push(` pull: ${report.pull}`);
1144
+ lines.push(` push: ${report.push}`);
1145
+ lines.push(` conflict: ${report.conflict}`);
1146
+ lines.push(` suppress: ${report.suppress}`);
1147
+ lines.push(` unresolved: ${report.unresolved}`);
1148
+ }
1149
+ }
1150
+ return lines.join("\n");
1151
+ }
1152
+ function formatConvergeApplyReport(result) {
1153
+ const lines = [];
1154
+ lines.push(`Convergence Execution Status: ${result.status.toUpperCase()}`);
1155
+ lines.push(`Converged: ${result.converged ? "YES" : "NO"}`);
1156
+ lines.push("");
1157
+ lines.push("Transfers Executed:");
1158
+ lines.push(` pulled: ${result.transfers.pulled}`);
1159
+ lines.push(` pushed: ${result.transfers.pushed}`);
1160
+ lines.push(` conflictsResolved: ${result.transfers.conflictsResolved}`);
1161
+ lines.push(` suppressed: ${result.transfers.suppressed}`);
1162
+ lines.push(` failed: ${result.transfers.failed}`);
1163
+ lines.push("");
1164
+ lines.push(formatConvergeReport(result.plan));
1165
+ return lines.join("\n");
1166
+ }
1167
+ async function cmdConverge(action, rest, json) {
1168
+ if (action === "help" || action === "--help" || action === "-h" || rest.includes("--help") || rest.includes("-h")) {
1169
+ console.log(`Usage: remnic converge <plan|apply> [options]
1170
+
1171
+ Subcommands:
1172
+ plan Compute and display reconciliation plan
1173
+ apply Execute bidirectional converge transport (alias: transport, sync)
1174
+
1175
+ Options:
1176
+ --peer <url> Peer server URL (or --remote-url / --remote)
1177
+ --token <token> Bearer token or SecretRef for peer authentication
1178
+ --conflict-policy <policy>
1179
+ Conflict resolution policy (manual|newest-wins|keep-both)
1180
+ --dry-run Simulate transfers without mutating disk or remote peer
1181
+ --json Output detailed JSON plan report
1182
+ `);
1183
+ return;
1184
+ }
1185
+ if (action !== "plan" && action !== "apply" && action !== "transport" && action !== "sync") {
1186
+ process.stderr.write(`converge: unknown action "${action}". Use: plan or apply [options].
1187
+ `);
1188
+ process.exitCode = 2;
1189
+ return;
1190
+ }
1191
+ let peerUrl;
1192
+ let peerToken;
1193
+ let dryRun = false;
1194
+ let conflictPolicy;
1195
+ for (let i = 0; i < rest.length; i += 1) {
1196
+ const arg = rest[i];
1197
+ if ((arg === "--peer" || arg === "--remote-url" || arg === "--remote") && rest[i + 1]) {
1198
+ peerUrl = rest[i + 1];
1199
+ i += 1;
1200
+ } else if (arg === "--token" && rest[i + 1]) {
1201
+ peerToken = rest[i + 1];
1202
+ i += 1;
1203
+ } else if (arg === "--dry-run") {
1204
+ dryRun = true;
1205
+ } else if (arg === "--conflict-policy" && rest[i + 1]) {
1206
+ const pol = rest[i + 1];
1207
+ if (pol === "manual" || pol === "newest-wins" || pol === "keep-both") {
1208
+ conflictPolicy = pol;
1209
+ }
1210
+ i += 1;
1211
+ }
1212
+ }
1213
+ if (action === "plan") {
1214
+ const plan = await computeConvergePlan({ peerUrl, peerToken, conflictPolicy });
1215
+ if (json) {
1216
+ console.log(JSON.stringify(plan, null, 2));
1217
+ } else {
1218
+ console.log(formatConvergeReport(plan));
1219
+ }
1220
+ return;
1221
+ }
1222
+ const result = await executeConvergeApply({
1223
+ peerUrl,
1224
+ peerToken,
1225
+ dryRun,
1226
+ conflictPolicy
1227
+ });
1228
+ if (json) {
1229
+ console.log(JSON.stringify(result, null, 2));
1230
+ } else {
1231
+ console.log(formatConvergeApplyReport(result));
1232
+ }
1233
+ }
1234
+
1235
+ // src/doctor-namespace-lint.ts
1236
+ import { isNamespacePolicyCovered } from "@remnic/core";
1237
+ function readConfiguredNamespace(remnicCfg) {
1238
+ if (!("namespace" in remnicCfg)) return { invalid: false };
1239
+ const value = remnicCfg.namespace;
1240
+ if (typeof value === "string" && value.trim().length > 0) {
1241
+ return { configuredNamespace: value.trim(), invalid: false };
1242
+ }
1243
+ return { invalid: true };
1244
+ }
1245
+ function buildNamespacePolicyCheck(args) {
1246
+ if (args.invalid) {
1247
+ return {
1248
+ name: "Namespace policy",
1249
+ ok: false,
1250
+ detail: "config `namespace` is set but is not a non-empty string",
1251
+ remediation: "Set `namespace` to a non-empty string (a namespacePolicies name or the default namespace), or remove it."
1252
+ };
1253
+ }
1254
+ if (!args.config || !args.configuredNamespace) return void 0;
1255
+ const covered = isNamespacePolicyCovered(args.configuredNamespace, args.config);
1256
+ return {
1257
+ name: "Namespace policy",
1258
+ ok: covered,
1259
+ warn: !covered,
1260
+ 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`,
1261
+ 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.`
1262
+ };
1263
+ }
1264
+
1265
+ // src/index.ts
1266
+ import { WriteQuarantineStore as WriteQuarantineStore2 } from "@remnic/core/write-quarantine.js";
1267
+
1268
+ // src/quarantine-cli.ts
1269
+ import { basename } from "path";
1270
+ function renderQuarantineList(records, format) {
1271
+ if (format === "json") {
1272
+ const summary = records.map((record) => ({
1273
+ timestamp: record.timestamp,
1274
+ operation: record.operation,
1275
+ principal: record.principal,
1276
+ attemptedNamespace: record.attemptedNamespace
1277
+ }));
1278
+ return JSON.stringify(summary, null, 2);
1279
+ }
1280
+ if (format !== "text") {
1281
+ throw new Error(`Unsupported quarantine format: ${String(format)}`);
1282
+ }
1283
+ if (records.length === 0) return "No quarantined writes.";
1284
+ const lines = [`Quarantined writes (${records.length}):`, ""];
1285
+ for (const record of records) {
1286
+ lines.push(
1287
+ ` ${record.timestamp} ${record.operation} principal=${record.principal ?? "-"} attemptedNamespace=${record.attemptedNamespace}`
1288
+ );
1289
+ }
1290
+ return lines.join("\n");
1291
+ }
1292
+ async function replayQuarantine(opts) {
1293
+ const result = { replayed: 0, failures: [], deleteFailures: [] };
1294
+ for (const entry of await opts.store.entries()) {
1295
+ const { record } = entry;
1296
+ const basePayload = record.payload;
1297
+ const principal = opts.principal ?? record.principal ?? void 0;
1298
+ const idempotencyKey = typeof basePayload.idempotencyKey === "string" && basePayload.idempotencyKey.length > 0 ? basePayload.idempotencyKey : `quarantine-replay:${basename(entry.path)}`;
1299
+ const request = {
1300
+ ...basePayload,
1301
+ namespace: opts.targetNamespace,
1302
+ suppressQuarantine: true,
1303
+ idempotencyKey,
1304
+ ...principal ? { authenticatedPrincipal: principal } : {}
1305
+ };
1306
+ try {
1307
+ await opts.submit(record.operation, request);
1308
+ } catch (err) {
1309
+ result.failures.push({
1310
+ operation: record.operation,
1311
+ attemptedNamespace: opts.targetNamespace,
1312
+ error: err instanceof Error ? err.message : String(err)
1313
+ });
1314
+ continue;
1315
+ }
1316
+ try {
1317
+ const removed = await opts.store.removeEntry(entry.path);
1318
+ if (removed) {
1319
+ result.replayed += 1;
1320
+ } else {
1321
+ result.deleteFailures.push({
1322
+ path: entry.path,
1323
+ error: "entry not removed (outside quarantine root or already absent)"
1324
+ });
1325
+ }
1326
+ } catch (err) {
1327
+ result.deleteFailures.push({
1328
+ path: entry.path,
1329
+ error: err instanceof Error ? err.message : String(err)
1330
+ });
1331
+ }
1332
+ }
1333
+ return result;
1334
+ }
1335
+ function renderReplayResult(result, targetNamespace, format) {
1336
+ if (format === "json") {
1337
+ return JSON.stringify(
1338
+ {
1339
+ targetNamespace,
1340
+ replayed: result.replayed,
1341
+ failures: result.failures,
1342
+ deleteFailures: result.deleteFailures
1343
+ },
1344
+ null,
1345
+ 2
1346
+ );
1347
+ }
1348
+ if (format !== "text") {
1349
+ throw new Error(`Unsupported quarantine format: ${String(format)}`);
356
1350
  }
357
1351
  const lines = [`Replayed ${result.replayed} quarantined write(s) into namespace ${targetNamespace}.`];
358
1352
  if (result.failures.length > 0) {
@@ -371,8 +1365,8 @@ function renderReplayResult(result, targetNamespace, format) {
371
1365
  }
372
1366
 
373
1367
  // src/quarantine-replay.ts
374
- import * as fs2 from "fs";
375
- import { EngramAccessService, Orchestrator as Orchestrator2, initLogger, parseConfig as parseConfig2, resolveRemnicConfigRecord as resolveRemnicConfigRecord2 } from "@remnic/core";
1368
+ import * as fs4 from "fs";
1369
+ import { EngramAccessService, Orchestrator as Orchestrator2, initLogger, parseConfig as parseConfig3, resolveRemnicConfigRecord as resolveRemnicConfigRecord2 } from "@remnic/core";
376
1370
  import { WriteQuarantineStore } from "@remnic/core/write-quarantine.js";
377
1371
  function valueFlag(args, flag) {
378
1372
  const occurrences = args.filter((a) => a === flag).length;
@@ -394,384 +1388,125 @@ async function runQuarantineReplay(rest, format, resolveConfigPath2) {
394
1388
  let principal;
395
1389
  try {
396
1390
  targetNamespace = valueFlag(rest, "--namespace");
397
- principal = valueFlag(rest, "--principal");
398
- } catch (err) {
399
- process.stderr.write(`quarantine replay: ${err instanceof Error ? err.message : String(err)}
400
- `);
401
- process.exitCode = 2;
402
- return;
403
- }
404
- if (!targetNamespace || targetNamespace.trim().length === 0) {
405
- process.stderr.write("quarantine replay: --namespace <ns> is required.\n");
406
- process.exitCode = 2;
407
- return;
408
- }
409
- const valued = /* @__PURE__ */ new Set(["--namespace", "--principal"]);
410
- const bad = rest.filter((a, i) => a.startsWith("--") ? a !== "--json" && !valued.has(a) : !valued.has(rest[i - 1]));
411
- if (bad.length > 0) {
412
- process.stderr.write(
413
- `quarantine replay: unexpected argument(s): ${bad.join(", ")}. Use: replay --namespace <ns> [--principal <p>] [--json].
414
- `
415
- );
416
- process.exitCode = 2;
417
- return;
418
- }
419
- initLogger();
420
- let orchestrator;
421
- try {
422
- const configPath = resolveConfigPath2();
423
- const raw = fs2.existsSync(configPath) ? JSON.parse(fs2.readFileSync(configPath, "utf8")) : {};
424
- const config = parseConfig2(resolveRemnicConfigRecord2(raw));
425
- orchestrator = new Orchestrator2(config);
426
- await orchestrator.initialize();
427
- await orchestrator.deferredReady;
428
- const service = new EngramAccessService(orchestrator);
429
- const store = new WriteQuarantineStore(config.memoryDir);
430
- const result = await replayQuarantine({
431
- store,
432
- targetNamespace,
433
- principal,
434
- submit: async (operation, request) => {
435
- if (operation === "observe") {
436
- await service.observe(request);
437
- } else if (operation === "memory_store") {
438
- await service.memoryStore(request);
439
- } else {
440
- await service.suggestionSubmit(request);
441
- }
442
- }
443
- });
444
- console.log(renderReplayResult(result, targetNamespace, format));
445
- if (result.failures.length > 0 || result.deleteFailures.length > 0) process.exitCode = 1;
446
- } catch {
447
- process.stderr.write("quarantine replay: unable to replay quarantine store\n");
448
- process.exitCode = 2;
449
- } finally {
450
- if (orchestrator) await orchestrator.destroy();
451
- }
452
- }
453
-
454
- // src/offline-impression-rotation.ts
455
- import fs3 from "fs";
456
- import { parseConfig as parseConfig3, resolveRemnicConfigRecord as resolveRemnicConfigRecord3, drainPendingImpressionsForOfflineSync } from "@remnic/core";
457
- import { LastRecallStore } from "@remnic/core/recall-state";
458
- function parseConfigQuietly(raw) {
459
- const originalWarn = console.warn;
460
- console.warn = () => {
461
- };
462
- try {
463
- return parseConfig3(resolveRemnicConfigRecord3(raw));
464
- } finally {
465
- console.warn = originalWarn;
466
- }
467
- }
468
- var OFFLINE_CONFIG_KEYS = [
469
- "offlineSyncExcludes",
470
- "secureStoreEncryptOnWrite",
471
- "recallImpressionsRotateBytes",
472
- "recallImpressionsRotateKeep"
473
- ];
474
- function pickOfflineConfigRecord(raw) {
475
- let resolved;
476
- try {
477
- resolved = resolveRemnicConfigRecord3(raw);
478
- } catch {
479
- resolved = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
480
- }
481
- const picked = {};
482
- for (const key of OFFLINE_CONFIG_KEYS) {
483
- if (key in resolved) picked[key] = resolved[key];
484
- }
485
- return picked;
486
- }
487
- function resolveOfflineImpressionRotation(configPath) {
488
- let raw;
489
- try {
490
- raw = fs3.existsSync(configPath) ? JSON.parse(fs3.readFileSync(configPath, "utf8")) : {};
491
- } catch {
492
- throw new Error(
493
- `cannot read recall-impression rotation from ${configPath}: config file could not be read as JSON`
494
- );
495
- }
496
- let config;
497
- try {
498
- config = parseConfigQuietly(pickOfflineConfigRecord(raw));
499
- } catch {
500
- throw new Error(
501
- `cannot read recall-impression rotation from ${configPath}: config failed validation`
502
- );
503
- }
504
- return {
505
- impressionsRotateBytes: config.recallImpressionsRotateBytes,
506
- impressionsRotateKeep: config.recallImpressionsRotateKeep
507
- };
508
- }
509
- async function drainOfflineSyncImpressions(memoryDir, rotation) {
510
- await drainPendingImpressionsForOfflineSync(
511
- () => new LastRecallStore(memoryDir, {
512
- impressionsRotateBytes: rotation.impressionsRotateBytes,
513
- impressionsRotateKeep: rotation.impressionsRotateKeep
514
- }).drainPendingImpressions()
515
- );
516
- }
517
-
518
- // src/offline-storage-io.ts
519
- import { mkdtemp, readdir, lstat, rm } from "fs/promises";
520
- import fs4 from "fs";
521
- import path from "path";
522
- import { createHash, createDecipheriv } from "crypto";
523
- import {
524
- OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
525
- StorageManager
526
- } from "@remnic/core";
527
- import { OFFLINE_DECRYPT_STAGING_DIR_PREFIX } from "@remnic/core/offline-sync-exclude-globs";
528
- import {
529
- AUTH_TAG_LENGTH,
530
- ENVELOPE_HEADER_SIZE,
531
- ENVELOPE_LAYOUT,
532
- ENVELOPE_SALT_LENGTH,
533
- ENVELOPE_VERSION,
534
- FILE_FORMAT_FLAGS,
535
- FILE_FORMAT_VERSION,
536
- IV_LENGTH,
537
- MAGIC_BYTES,
538
- MAGIC_HEADER_SIZE,
539
- SecureStoreLockedError,
540
- filePathAad,
541
- isEncryptedFile,
542
- keyring,
543
- readHeader,
544
- secureStoreDir
545
- } from "@remnic/core/secure-store";
546
- async function createConfiguredOfflineStorage(memoryDir, secureStoreEncryptOnWrite = true) {
547
- const storage = new StorageManager(memoryDir);
548
- const header = await readHeader(memoryDir);
549
- let secureStoreKey = null;
550
- let secureStoreRequired = false;
551
- if (header) {
552
- secureStoreRequired = true;
553
- storage.setSecureStoreRequired(true);
554
- const key = keyring.getKey(secureStoreDir(memoryDir));
555
- if (key) {
556
- await storage.setSecureStoreKeyAndWait(key, secureStoreEncryptOnWrite);
557
- secureStoreKey = key;
558
- }
559
- }
560
- return { storage, secureStoreKey, secureStoreRequired };
561
- }
562
- async function createOfflineStorageForPath(memoryDir, filePath, configured, secureStoreEncryptOnWrite) {
563
- const memoryRoot = path.resolve(memoryDir);
564
- const stateDir = path.dirname(filePath);
565
- if (path.basename(stateDir) !== "state" || path.basename(filePath) !== "memory-lifecycle-ledger.jsonl") {
566
- throw new Error(`invalid lifecycle ledger path: ${filePath}`);
567
- }
568
- const storageRoot = path.resolve(path.dirname(stateDir));
569
- if (storageRoot !== memoryRoot && !storageRoot.startsWith(`${memoryRoot}${path.sep}`)) {
570
- throw new Error(`lifecycle ledger path is outside the offline memory directory: ${filePath}`);
571
- }
572
- const storage = new StorageManager(storageRoot);
573
- if (configured.secureStoreRequired) {
574
- storage.setSecureStoreRequired(true);
575
- }
576
- if (configured.secureStoreKey) {
577
- await storage.setSecureStoreKeyAndWait(configured.secureStoreKey, secureStoreEncryptOnWrite);
578
- }
579
- return storage;
580
- }
581
- async function createOfflineStorageIo(memoryDir, configuredStorage) {
582
- await cleanupOrphanedOfflineDecryptStaging(memoryDir);
583
- const { storage, secureStoreKey } = configuredStorage ?? await createConfiguredOfflineStorage(memoryDir);
584
- return {
585
- readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
586
- readFileDigest: async ({ filePath }) => {
587
- const hash = createHash("sha256");
588
- let bytes = 0;
589
- for await (const rawChunk of readOfflineSyncFileChunks({
590
- filePath,
591
- memoryDir,
592
- secureStoreKey,
593
- chunkSize: OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES
594
- })) {
595
- const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
596
- hash.update(chunk);
597
- bytes += chunk.length;
598
- }
599
- return {
600
- sha256: hash.digest("hex"),
601
- bytes
602
- };
603
- },
604
- readFileChunks: ({ filePath, chunkSize }) => readOfflineSyncFileChunks({
605
- filePath,
606
- memoryDir,
607
- secureStoreKey,
608
- chunkSize
609
- }),
610
- writeFile: async ({ filePath, content }) => storage.writeOfflineSyncFile(filePath, content),
611
- writeStagingFile: async ({ filePath, content }) => storage.writeOfflineSyncStagingFile(filePath, content),
612
- writeFileChunks: async ({ filePath, chunks }) => storage.writeOfflineSyncFileChunks(filePath, chunks),
613
- deleteFile: async ({ filePath }) => storage.deleteOfflineSyncFile(filePath)
614
- };
615
- }
616
- var OFFLINE_DECRYPT_STAGING_ORPHAN_MS = 60 * 60 * 1e3;
617
- async function cleanupOrphanedOfflineDecryptStaging(memoryDir) {
618
- let entries;
619
- try {
620
- entries = await readdir(memoryDir);
621
- } catch {
622
- return;
623
- }
624
- const now = Date.now();
625
- for (const name of entries) {
626
- if (!name.startsWith(OFFLINE_DECRYPT_STAGING_DIR_PREFIX)) continue;
627
- const dir = path.join(memoryDir, name);
628
- try {
629
- const info = await lstat(dir);
630
- if (!info.isDirectory() || info.isSymbolicLink()) continue;
631
- if (now - info.mtimeMs < OFFLINE_DECRYPT_STAGING_ORPHAN_MS) continue;
632
- await rm(dir, { recursive: true, force: true });
633
- } catch {
634
- }
1391
+ principal = valueFlag(rest, "--principal");
1392
+ } catch (err) {
1393
+ process.stderr.write(`quarantine replay: ${err instanceof Error ? err.message : String(err)}
1394
+ `);
1395
+ process.exitCode = 2;
1396
+ return;
635
1397
  }
636
- }
637
- async function* readOfflineSyncFileChunks(options) {
638
- const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE);
639
- if (!isEncryptedFile(header)) {
640
- yield* readPlainOfflineFileChunks(options.filePath, options.chunkSize);
1398
+ if (!targetNamespace || targetNamespace.trim().length === 0) {
1399
+ process.stderr.write("quarantine replay: --namespace <ns> is required.\n");
1400
+ process.exitCode = 2;
641
1401
  return;
642
1402
  }
643
- if (!options.secureStoreKey) {
644
- throw new SecureStoreLockedError(
645
- `secure-store is locked \u2014 cannot read encrypted file at ${options.filePath}. Run \`remnic secure-store unlock\` to decrypt.`
1403
+ const valued = /* @__PURE__ */ new Set(["--namespace", "--principal"]);
1404
+ const bad = rest.filter((a, i) => a.startsWith("--") ? a !== "--json" && !valued.has(a) : !valued.has(rest[i - 1]));
1405
+ if (bad.length > 0) {
1406
+ process.stderr.write(
1407
+ `quarantine replay: unexpected argument(s): ${bad.join(", ")}. Use: replay --namespace <ns> [--principal <p>] [--json].
1408
+ `
646
1409
  );
1410
+ process.exitCode = 2;
1411
+ return;
647
1412
  }
648
- yield* readEncryptedOfflineFileChunks({
649
- filePath: options.filePath,
650
- memoryDir: options.memoryDir,
651
- key: options.secureStoreKey,
652
- chunkSize: options.chunkSize
653
- });
654
- }
655
- async function readFilePrefix(filePath, length) {
656
- const handle = await fs4.promises.open(filePath, "r");
1413
+ initLogger();
1414
+ let orchestrator;
657
1415
  try {
658
- const out = Buffer.alloc(length);
659
- const { bytesRead } = await handle.read(out, 0, length, 0);
660
- return out.subarray(0, bytesRead);
1416
+ const configPath = resolveConfigPath2();
1417
+ const raw = fs4.existsSync(configPath) ? JSON.parse(fs4.readFileSync(configPath, "utf8")) : {};
1418
+ const config = parseConfig3(resolveRemnicConfigRecord2(raw));
1419
+ orchestrator = new Orchestrator2(config);
1420
+ await orchestrator.initialize();
1421
+ await orchestrator.deferredReady;
1422
+ const service = new EngramAccessService(orchestrator);
1423
+ const store = new WriteQuarantineStore(config.memoryDir);
1424
+ const result = await replayQuarantine({
1425
+ store,
1426
+ targetNamespace,
1427
+ principal,
1428
+ submit: async (operation, request) => {
1429
+ if (operation === "observe") {
1430
+ await service.observe(request);
1431
+ } else if (operation === "memory_store") {
1432
+ await service.memoryStore(request);
1433
+ } else {
1434
+ await service.suggestionSubmit(request);
1435
+ }
1436
+ }
1437
+ });
1438
+ console.log(renderReplayResult(result, targetNamespace, format));
1439
+ if (result.failures.length > 0 || result.deleteFailures.length > 0) process.exitCode = 1;
1440
+ } catch {
1441
+ process.stderr.write("quarantine replay: unable to replay quarantine store\n");
1442
+ process.exitCode = 2;
661
1443
  } finally {
662
- await handle.close();
1444
+ if (orchestrator) await orchestrator.destroy();
663
1445
  }
664
1446
  }
665
- async function* readPlainOfflineFileChunks(filePath, chunkSize) {
666
- const stream = fs4.createReadStream(filePath, { highWaterMark: chunkSize });
667
- for await (const chunk of stream) {
668
- yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1447
+
1448
+ // src/offline-impression-rotation.ts
1449
+ import fs5 from "fs";
1450
+ import { parseConfig as parseConfig4, resolveRemnicConfigRecord as resolveRemnicConfigRecord3, drainPendingImpressionsForOfflineSync } from "@remnic/core";
1451
+ import { LastRecallStore } from "@remnic/core/recall-state";
1452
+ function parseConfigQuietly(raw) {
1453
+ const originalWarn = console.warn;
1454
+ console.warn = () => {
1455
+ };
1456
+ try {
1457
+ return parseConfig4(resolveRemnicConfigRecord3(raw));
1458
+ } finally {
1459
+ console.warn = originalWarn;
669
1460
  }
670
1461
  }
671
- async function* readEncryptedOfflineFileChunks(options) {
672
- const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
673
- if (header.length < MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE || !isEncryptedFile(header)) {
674
- throw new Error(`secure-store encrypted file is truncated: ${options.filePath}`);
675
- }
676
- const version = header.readUInt8(MAGIC_BYTES.length);
677
- const flags = header.readUInt8(MAGIC_BYTES.length + 1);
678
- if (version !== FILE_FORMAT_VERSION) {
679
- throw new Error(`secure-store file has unsupported version ${version}: ${options.filePath}`);
680
- }
681
- if (flags !== FILE_FORMAT_FLAGS) {
682
- throw new Error(`secure-store file has unsupported flags 0x${flags.toString(16)}: ${options.filePath}`);
683
- }
684
- const envelopeHeader = header.subarray(MAGIC_HEADER_SIZE);
685
- const envelopeVersion = envelopeHeader.readUInt8(ENVELOPE_LAYOUT.version);
686
- if (envelopeVersion !== ENVELOPE_VERSION) {
687
- throw new Error(`secure-store envelope has unsupported version ${envelopeVersion}: ${options.filePath}`);
1462
+ var OFFLINE_CONFIG_KEYS = [
1463
+ "offlineSyncExcludes",
1464
+ "secureStoreEncryptOnWrite",
1465
+ "recallImpressionsRotateBytes",
1466
+ "recallImpressionsRotateKeep"
1467
+ ];
1468
+ function pickOfflineConfigRecord(raw) {
1469
+ let resolved;
1470
+ try {
1471
+ resolved = resolveRemnicConfigRecord3(raw);
1472
+ } catch {
1473
+ resolved = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
688
1474
  }
689
- const salt = envelopeHeader.subarray(
690
- ENVELOPE_LAYOUT.salt,
691
- ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH
692
- );
693
- const iv = envelopeHeader.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);
694
- const authTag = envelopeHeader.subarray(
695
- ENVELOPE_LAYOUT.authTag,
696
- ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
697
- );
698
- const aadCandidates = offlineFileAadCandidates(options.filePath, options.memoryDir);
699
- let lastError;
700
- for (const aad of aadCandidates) {
701
- const tempDir = await mkdtemp(path.join(options.memoryDir, OFFLINE_DECRYPT_STAGING_DIR_PREFIX));
702
- const tempPath = path.join(tempDir, "content");
703
- try {
704
- const decipher = createDecipheriv("aes-256-gcm", options.key, iv, {
705
- authTagLength: AUTH_TAG_LENGTH
706
- });
707
- decipher.setAuthTag(authTag);
708
- decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), aad]));
709
- const output = fs4.createWriteStream(tempPath, { mode: 384 });
710
- try {
711
- const stream = fs4.createReadStream(options.filePath, {
712
- start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
713
- highWaterMark: options.chunkSize
714
- });
715
- for await (const encryptedChunk of stream) {
716
- const plain = decipher.update(
717
- Buffer.isBuffer(encryptedChunk) ? encryptedChunk : Buffer.from(encryptedChunk)
718
- );
719
- if (plain.length > 0 && !output.write(plain)) {
720
- await new Promise((resolve, reject) => {
721
- output.once("drain", resolve);
722
- output.once("error", reject);
723
- });
724
- }
725
- }
726
- const finalPlain = decipher.final();
727
- if (finalPlain.length > 0 && !output.write(finalPlain)) {
728
- await new Promise((resolve, reject) => {
729
- output.once("drain", resolve);
730
- output.once("error", reject);
731
- });
732
- }
733
- } finally {
734
- await closeWriteStream(output);
735
- }
736
- yield* readPlainOfflineFileChunks(tempPath, options.chunkSize);
737
- return;
738
- } catch (error) {
739
- lastError = error;
740
- } finally {
741
- await rm(tempDir, { recursive: true, force: true });
742
- }
1475
+ const picked = {};
1476
+ for (const key of OFFLINE_CONFIG_KEYS) {
1477
+ if (key in resolved) picked[key] = resolved[key];
743
1478
  }
744
- throw lastError instanceof Error ? lastError : new Error(`secure-store could not decrypt file: ${options.filePath}`);
1479
+ return picked;
745
1480
  }
746
- function offlineFileAadCandidates(filePath, memoryDir) {
747
- const candidates = [filePathAad(filePath, memoryDir)];
748
- const relative = path.relative(memoryDir, filePath);
749
- if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return candidates;
750
- const parts = relative.split(path.sep);
751
- if (parts[0] === "namespaces" && parts.length >= 3 && parts[1]) {
752
- candidates.push(filePathAad(filePath, path.join(memoryDir, "namespaces", parts[1])));
1481
+ function resolveOfflineImpressionRotation(configPath) {
1482
+ let raw;
1483
+ try {
1484
+ raw = fs5.existsSync(configPath) ? JSON.parse(fs5.readFileSync(configPath, "utf8")) : {};
1485
+ } catch {
1486
+ throw new Error(
1487
+ `cannot read recall-impression rotation from ${configPath}: config file could not be read as JSON`
1488
+ );
753
1489
  }
754
- const memoryParts = path.resolve(memoryDir).split(path.sep);
755
- if (memoryParts.length >= 3 && memoryParts.at(-2) === "namespaces" && memoryParts.at(-1)) {
756
- const topLevelRoot = memoryParts.slice(0, -2).join(path.sep) || path.sep;
757
- const topRelative = path.relative(topLevelRoot, filePath);
758
- if (topRelative && !topRelative.startsWith("..") && !path.isAbsolute(topRelative) && topRelative.split(path.sep)[0] === "namespaces" && topRelative.split(path.sep)[1] === memoryParts.at(-1)) {
759
- candidates.push(filePathAad(filePath, topLevelRoot));
760
- }
1490
+ let config;
1491
+ try {
1492
+ config = parseConfigQuietly(pickOfflineConfigRecord(raw));
1493
+ } catch {
1494
+ throw new Error(
1495
+ `cannot read recall-impression rotation from ${configPath}: config failed validation`
1496
+ );
761
1497
  }
762
- return candidates;
763
- }
764
- async function closeWriteStream(stream) {
765
- await new Promise((resolve, reject) => {
766
- stream.once("error", reject);
767
- stream.end(() => resolve());
768
- });
1498
+ return {
1499
+ impressionsRotateBytes: config.recallImpressionsRotateBytes,
1500
+ impressionsRotateKeep: config.recallImpressionsRotateKeep
1501
+ };
769
1502
  }
770
- function secureStoreEnvelopeHeaderAad(salt) {
771
- const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
772
- out.writeUInt8(ENVELOPE_VERSION, 0);
773
- Buffer.from(salt).copy(out, 1);
774
- return out;
1503
+ async function drainOfflineSyncImpressions(memoryDir, rotation) {
1504
+ await drainPendingImpressionsForOfflineSync(
1505
+ () => new LastRecallStore(memoryDir, {
1506
+ impressionsRotateBytes: rotation.impressionsRotateBytes,
1507
+ impressionsRotateKeep: rotation.impressionsRotateKeep
1508
+ }).drainPendingImpressions()
1509
+ );
775
1510
  }
776
1511
 
777
1512
  // src/bench-build-freshness.ts
@@ -782,15 +1517,15 @@ import {
782
1517
  readFileSync as readFileSync2,
783
1518
  statSync
784
1519
  } from "fs";
785
- import path2 from "path";
1520
+ import path3 from "path";
786
1521
  import { fileURLToPath } from "url";
787
1522
  var STALE_BUILD_TOLERANCE_MS = 1e3;
788
1523
  function assertLocalBenchBuildFreshForDevelopment(currentModuleUrl) {
789
1524
  if (isTruthyEnv(process.env.REMNIC_BENCH_ALLOW_STALE_DIST)) {
790
1525
  return;
791
1526
  }
792
- const currentDir = path2.dirname(fileURLToPath(currentModuleUrl));
793
- const benchPackageDir = path2.resolve(currentDir, "../../bench");
1527
+ const currentDir = path3.dirname(fileURLToPath(currentModuleUrl));
1528
+ const benchPackageDir = path3.resolve(currentDir, "../../bench");
794
1529
  const freshness = checkBenchBuildFreshness(benchPackageDir);
795
1530
  if (!freshness.stale) {
796
1531
  return;
@@ -807,7 +1542,7 @@ function assertLocalBenchBuildFreshForDevelopment(currentModuleUrl) {
807
1542
  );
808
1543
  }
809
1544
  function checkBenchBuildFreshness(benchPackageDir) {
810
- const packageJsonPath = path2.join(benchPackageDir, "package.json");
1545
+ const packageJsonPath = path3.join(benchPackageDir, "package.json");
811
1546
  if (!existsSync2(packageJsonPath)) {
812
1547
  return { stale: false };
813
1548
  }
@@ -820,17 +1555,17 @@ function checkBenchBuildFreshness(benchPackageDir) {
820
1555
  if (packageName !== "@remnic/bench") {
821
1556
  return { stale: false };
822
1557
  }
823
- const srcDir = path2.join(benchPackageDir, "src");
1558
+ const srcDir = path3.join(benchPackageDir, "src");
824
1559
  if (!isDirectory(srcDir)) {
825
1560
  return { stale: false };
826
1561
  }
827
1562
  const sourceRoots = [
828
1563
  srcDir,
829
1564
  packageJsonPath,
830
- path2.join(benchPackageDir, "tsup.config.ts"),
831
- path2.join(benchPackageDir, "tsconfig.json")
1565
+ path3.join(benchPackageDir, "tsup.config.ts"),
1566
+ path3.join(benchPackageDir, "tsconfig.json")
832
1567
  ];
833
- const distPath = path2.join(benchPackageDir, "dist", "index.js");
1568
+ const distPath = path3.join(benchPackageDir, "dist", "index.js");
834
1569
  if (!existsSync2(distPath)) {
835
1570
  return {
836
1571
  stale: true,
@@ -873,7 +1608,7 @@ function newestMtime(roots) {
873
1608
  }
874
1609
  if (stat.isDirectory()) {
875
1610
  for (const child of readdirSync(entryPath)) {
876
- visit(path2.join(entryPath, child));
1611
+ visit(path3.join(entryPath, child));
877
1612
  }
878
1613
  return;
879
1614
  }
@@ -906,18 +1641,18 @@ function isTruthyEnv(value) {
906
1641
 
907
1642
  // src/optional-bench.ts
908
1643
  import { existsSync as existsSync3 } from "fs";
909
- import path3 from "path";
1644
+ import path4 from "path";
910
1645
  import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
911
1646
  var SPECIFIER2 = "@remnic/bench";
912
1647
  var TSX_ESM_API_SPECIFIER = "tsx/esm/api";
913
1648
  var cached2;
914
1649
  var cachedFromLocalWorkspaceBenchSource = false;
915
1650
  function resolveLocalWorkspaceBenchPaths() {
916
- const currentDir = path3.dirname(fileURLToPath2(import.meta.url));
917
- const benchPackageDir = path3.resolve(currentDir, "../../bench");
1651
+ const currentDir = path4.dirname(fileURLToPath2(import.meta.url));
1652
+ const benchPackageDir = path4.resolve(currentDir, "../../bench");
918
1653
  return {
919
- distEntry: path3.join(benchPackageDir, "dist", "index.js"),
920
- sourceEntry: path3.join(benchPackageDir, "src", "index.ts")
1654
+ distEntry: path4.join(benchPackageDir, "dist", "index.js"),
1655
+ sourceEntry: path4.join(benchPackageDir, "src", "index.ts")
921
1656
  };
922
1657
  }
923
1658
  async function tryImportLocalWorkspaceBenchSource(err) {
@@ -1004,8 +1739,8 @@ function assertBenchModuleFreshForDevelopment() {
1004
1739
  }
1005
1740
 
1006
1741
  // src/daemon-service-candidates.ts
1007
- import fs5 from "fs";
1008
- import path4 from "path";
1742
+ import fs6 from "fs";
1743
+ import path5 from "path";
1009
1744
  var LAUNCHD_LABEL = "ai.remnic.daemon";
1010
1745
  var LEGACY_REMNIC_SERVER_LAUNCHD_LABEL = "ai.remnic.server";
1011
1746
  var LEGACY_LAUNCHD_LABEL = "ai.engram.daemon";
@@ -1018,15 +1753,15 @@ var SYSTEMD_SERVICE = "remnic.service";
1018
1753
  var LEGACY_SYSTEMD_SERVICE = "engram.service";
1019
1754
  var SYSTEMD_SERVICE_CANDIDATES = [SYSTEMD_SERVICE, LEGACY_SYSTEMD_SERVICE];
1020
1755
  function launchdPlistPaths(homeDir) {
1021
- return LAUNCHD_LABEL_CANDIDATES.map((label) => path4.join(homeDir, "Library", "LaunchAgents", `${label}.plist`));
1756
+ return LAUNCHD_LABEL_CANDIDATES.map((label) => path5.join(homeDir, "Library", "LaunchAgents", `${label}.plist`));
1022
1757
  }
1023
1758
  function systemdUnitPaths(homeDir) {
1024
- return SYSTEMD_SERVICE_CANDIDATES.map((service) => path4.join(homeDir, ".config", "systemd", "user", service));
1759
+ return SYSTEMD_SERVICE_CANDIDATES.map((service) => path5.join(homeDir, ".config", "systemd", "user", service));
1025
1760
  }
1026
1761
  function anyFileExists(paths) {
1027
1762
  return paths.some((candidate) => {
1028
1763
  try {
1029
- return fs5.statSync(candidate).isFile();
1764
+ return fs6.statSync(candidate).isFile();
1030
1765
  } catch {
1031
1766
  return false;
1032
1767
  }
@@ -1038,7 +1773,7 @@ function commandNames(command) {
1038
1773
  }
1039
1774
  function isRunnableNodeScript(filePath) {
1040
1775
  try {
1041
- const text = fs5.readFileSync(filePath, "utf8").slice(0, 4096);
1776
+ const text = fs6.readFileSync(filePath, "utf8").slice(0, 4096);
1042
1777
  const firstLine = text.split(/\r?\n/, 1)[0] ?? "";
1043
1778
  if (/^#!.*\bnode\b/.test(firstLine)) return true;
1044
1779
  if (firstLine.startsWith("#!")) return false;
@@ -1051,20 +1786,20 @@ function isRunnableNodeScript(filePath) {
1051
1786
  function resolveShimNodeScript(filePath) {
1052
1787
  let text;
1053
1788
  try {
1054
- text = fs5.readFileSync(filePath, "utf8").slice(0, 16384);
1789
+ text = fs6.readFileSync(filePath, "utf8").slice(0, 16384);
1055
1790
  } catch {
1056
1791
  return void 0;
1057
1792
  }
1058
- const basedir = path4.dirname(filePath);
1793
+ const basedir = path5.dirname(filePath);
1059
1794
  const jsReferencePattern = /"([^"]+\.js)"|'([^']+\.js)'|([^\s"'`]+\.js)/g;
1060
1795
  for (const match of text.matchAll(jsReferencePattern)) {
1061
1796
  const raw = match[1] ?? match[2] ?? match[3];
1062
1797
  if (!raw) continue;
1063
1798
  const candidate = raw.replaceAll("${basedir}", basedir).replaceAll("$basedir", basedir).replaceAll("\\ ", " ");
1064
- const resolved = path4.isAbsolute(candidate) ? candidate : path4.resolve(basedir, candidate);
1799
+ const resolved = path5.isAbsolute(candidate) ? candidate : path5.resolve(basedir, candidate);
1065
1800
  try {
1066
- if (fs5.statSync(resolved).isFile() && isRunnableNodeScript(resolved)) {
1067
- return fs5.realpathSync(resolved);
1801
+ if (fs6.statSync(resolved).isFile() && isRunnableNodeScript(resolved)) {
1802
+ return fs6.realpathSync(resolved);
1068
1803
  }
1069
1804
  } catch {
1070
1805
  }
@@ -1072,19 +1807,19 @@ function resolveShimNodeScript(filePath) {
1072
1807
  return void 0;
1073
1808
  }
1074
1809
  function resolveRunnableNodeScript(filePath) {
1075
- const realPath = fs5.realpathSync(filePath);
1810
+ const realPath = fs6.realpathSync(filePath);
1076
1811
  if (isRunnableNodeScript(realPath)) return realPath;
1077
1812
  return resolveShimNodeScript(realPath);
1078
1813
  }
1079
1814
  function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
1080
- for (const dir of pathEnv.split(path4.delimiter)) {
1815
+ for (const dir of pathEnv.split(path5.delimiter)) {
1081
1816
  if (!dir) continue;
1082
1817
  for (const name of commandNames(command)) {
1083
- const candidate = path4.join(dir, name);
1818
+ const candidate = path5.join(dir, name);
1084
1819
  try {
1085
- const stat = fs5.statSync(candidate);
1820
+ const stat = fs6.statSync(candidate);
1086
1821
  if (!stat.isFile()) continue;
1087
- if (process.platform !== "win32") fs5.accessSync(candidate, fs5.constants.X_OK);
1822
+ if (process.platform !== "win32") fs6.accessSync(candidate, fs6.constants.X_OK);
1088
1823
  const runnable = resolveRunnableNodeScript(candidate);
1089
1824
  if (runnable) return runnable;
1090
1825
  } catch {
@@ -1094,11 +1829,11 @@ function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
1094
1829
  return void 0;
1095
1830
  }
1096
1831
  function serverBinWrapperRequiredPath(candidate) {
1097
- const filename = path4.basename(candidate);
1832
+ const filename = path5.basename(candidate);
1098
1833
  if (filename !== "remnic-server.js" && filename !== "engram-server.js") return void 0;
1099
- const binDir = path4.dirname(candidate);
1100
- if (path4.basename(binDir) !== "bin") return void 0;
1101
- return path4.join(path4.dirname(binDir), "dist", "index.js");
1834
+ const binDir = path5.dirname(candidate);
1835
+ if (path5.basename(binDir) !== "bin") return void 0;
1836
+ return path5.join(path5.dirname(binDir), "dist", "index.js");
1102
1837
  }
1103
1838
 
1104
1839
  // src/service-candidates.ts
@@ -1120,7 +1855,7 @@ function firstSuccessfulCandidate(candidates, attempt) {
1120
1855
  }
1121
1856
 
1122
1857
  // src/bench-args.ts
1123
- import path6 from "path";
1858
+ import path7 from "path";
1124
1859
 
1125
1860
  // src/bench-flags.ts
1126
1861
  function readBenchOptionValue(argv, flag) {
@@ -1498,7 +2233,7 @@ function expandTilde(p) {
1498
2233
  }
1499
2234
 
1500
2235
  // src/bench-args-research.ts
1501
- import path5 from "path";
2236
+ import path6 from "path";
1502
2237
  function readPositiveInteger(args, flag) {
1503
2238
  const raw = readBenchOptionValue(args, flag);
1504
2239
  if (raw === void 0) return void 0;
@@ -1536,7 +2271,7 @@ function parseBenchResearchArgs(action, args) {
1536
2271
  }
1537
2272
  const outRaw = readBenchOptionValue(args, "--out");
1538
2273
  if (outRaw !== void 0) {
1539
- out = path5.resolve(expandTilde(outRaw));
2274
+ out = path6.resolve(expandTilde(outRaw));
1540
2275
  }
1541
2276
  }
1542
2277
  const epochs = readPositiveInteger(args, "--epochs");
@@ -1550,7 +2285,7 @@ function parseBenchResearchArgs(action, args) {
1550
2285
  }
1551
2286
  return {
1552
2287
  runRef,
1553
- memoryDir: memoryDirRaw ? path5.resolve(expandTilde(memoryDirRaw)) : void 0,
2288
+ memoryDir: memoryDirRaw ? path6.resolve(expandTilde(memoryDirRaw)) : void 0,
1554
2289
  users: readPositiveInteger(args, "--users"),
1555
2290
  epochs,
1556
2291
  seed,
@@ -1769,7 +2504,7 @@ function parseBenchArgs(argv) {
1769
2504
  }
1770
2505
  validateBenchFlags(action, args);
1771
2506
  const driftGenPositionals = action === "drift-gen" && driftGenAction === "validate" ? collectBenchmarks(args.slice(1)) : [];
1772
- const driftGenDir = driftGenPositionals[0] ? path6.resolve(expandTilde(driftGenPositionals[0])) : void 0;
2507
+ const driftGenDir = driftGenPositionals[0] ? path7.resolve(expandTilde(driftGenPositionals[0])) : void 0;
1773
2508
  const benchmarkArgs = action === "baseline" || action === "datasets" || action === "providers" || action === "runs" || action === "drift-gen" && (args[0] === "validate" || args[0] === "generate") ? args.slice(1) : args;
1774
2509
  const benchmarks = collectBenchmarks(benchmarkArgs);
1775
2510
  const datasetDir = readBenchOptionValue(args, "--dataset-dir") ?? readBenchOptionValue(args, "--dataset");
@@ -2319,13 +3054,13 @@ function parseBenchArgs(argv) {
2319
3054
  mcpUrl,
2320
3055
  mcpToolMap,
2321
3056
  mcpDemo,
2322
- datasetDir: datasetDir ? path6.resolve(expandTilde(datasetDir)) : void 0,
2323
- resultsDir: resultsDir ? path6.resolve(expandTilde(resultsDir)) : void 0,
2324
- baselinesDir: baselinesDir ? path6.resolve(expandTilde(baselinesDir)) : void 0,
3057
+ datasetDir: datasetDir ? path7.resolve(expandTilde(datasetDir)) : void 0,
3058
+ resultsDir: resultsDir ? path7.resolve(expandTilde(resultsDir)) : void 0,
3059
+ baselinesDir: baselinesDir ? path7.resolve(expandTilde(baselinesDir)) : void 0,
2325
3060
  runtimeProfile,
2326
3061
  matrixProfiles,
2327
- remnicConfigPath: remnicConfigRaw ? path6.resolve(expandTilde(remnicConfigRaw)) : void 0,
2328
- openclawConfigPath: openclawConfigRaw ? path6.resolve(expandTilde(openclawConfigRaw)) : void 0,
3062
+ remnicConfigPath: remnicConfigRaw ? path7.resolve(expandTilde(remnicConfigRaw)) : void 0,
3063
+ openclawConfigPath: openclawConfigRaw ? path7.resolve(expandTilde(openclawConfigRaw)) : void 0,
2329
3064
  modelSource,
2330
3065
  gatewayAgentId,
2331
3066
  fastGatewayAgentId,
@@ -2348,13 +3083,13 @@ function parseBenchArgs(argv) {
2348
3083
  internalDisableThinking: args.includes("--internal-disable-thinking"),
2349
3084
  internalCodexReasoningEffort,
2350
3085
  threshold,
2351
- custom: customRaw ? path6.resolve(expandTilde(customRaw)) : void 0,
3086
+ custom: customRaw ? path7.resolve(expandTilde(customRaw)) : void 0,
2352
3087
  baselineAction,
2353
3088
  datasetAction,
2354
3089
  providerAction,
2355
3090
  runAction,
2356
3091
  format,
2357
- output: output ? path6.resolve(expandTilde(output)) : void 0,
3092
+ output: output ? path7.resolve(expandTilde(output)) : void 0,
2358
3093
  target,
2359
3094
  publishedName,
2360
3095
  publishedSeed,
@@ -2364,24 +3099,24 @@ function parseBenchArgs(argv) {
2364
3099
  publishedIngestConcurrency,
2365
3100
  publishedTaskFilter,
2366
3101
  memcorrectAdapter,
2367
- publishedOut: publishedOutRaw ? path6.resolve(expandTilde(publishedOutRaw)) : void 0,
3102
+ publishedOut: publishedOutRaw ? path7.resolve(expandTilde(publishedOutRaw)) : void 0,
2368
3103
  publishedDryRun: args.includes("--dry-run"),
2369
3104
  requestTimeout,
2370
3105
  localJudgeRequestTimeout,
2371
3106
  frontierJudgeRequestTimeout,
2372
- calibrationDir: calibrationDirRaw ? path6.resolve(expandTilde(calibrationDirRaw)) : void 0,
3107
+ calibrationDir: calibrationDirRaw ? path7.resolve(expandTilde(calibrationDirRaw)) : void 0,
2373
3108
  calibrationLocalConfigSha256,
2374
3109
  calibrationFrontierConfigSha256,
2375
3110
  sourceResultId,
2376
3111
  expectedAnswerSetSha256,
2377
3112
  expectedQuestionIdListSha256,
2378
- taskIdsFile: taskIdsFileRaw ? path6.resolve(expandTilde(taskIdsFileRaw)) : void 0,
3113
+ taskIdsFile: taskIdsFileRaw ? path7.resolve(expandTilde(taskIdsFileRaw)) : void 0,
2379
3114
  expectedTaskIdListSha256,
2380
3115
  drainTimeout,
2381
3116
  // Issue #1573 PR1: surface judge-cache flags into the runner options.
2382
3117
  noJudgeCache: args.includes("--no-judge-cache"),
2383
- judgeCacheDir: judgeCacheDirRaw ? path6.resolve(expandTilde(judgeCacheDirRaw)) : void 0,
2384
- localLabManifestPath: localLabManifestRaw ? path6.resolve(expandTilde(localLabManifestRaw)) : void 0,
3118
+ judgeCacheDir: judgeCacheDirRaw ? path7.resolve(expandTilde(judgeCacheDirRaw)) : void 0,
3119
+ localLabManifestPath: localLabManifestRaw ? path7.resolve(expandTilde(localLabManifestRaw)) : void 0,
2385
3120
  max429WaitMs,
2386
3121
  disableThinking: args.includes("--disable-thinking"),
2387
3122
  amaBenchJudgeProtocol,
@@ -2400,9 +3135,9 @@ function parseBenchArgs(argv) {
2400
3135
 
2401
3136
  // src/bench-status.ts
2402
3137
  import { mkdir, readFile, readdir as readdir2, rename, writeFile } from "fs/promises";
2403
- import path7 from "path";
3138
+ import path8 from "path";
2404
3139
  function createBenchStatusPath(resultsDir, pid, startedAtMs = Date.now()) {
2405
- return path7.join(resultsDir, `bench-status-${startedAtMs}-${pid}.json`);
3140
+ return path8.join(resultsDir, `bench-status-${startedAtMs}-${pid}.json`);
2406
3141
  }
2407
3142
  var BENCH_STATUS_FILENAME = /^bench-status-\d+-\d+\.json$/;
2408
3143
  var VALID_BENCH_ENTRY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "complete", "failed"]);
@@ -2415,7 +3150,7 @@ async function findLatestBenchStatusFile(resultsDir) {
2415
3150
  }
2416
3151
  const candidates = entries.filter((name) => BENCH_STATUS_FILENAME.test(name)).sort().reverse();
2417
3152
  for (const name of candidates) {
2418
- const filePath = path7.join(resultsDir, name);
3153
+ const filePath = path8.join(resultsDir, name);
2419
3154
  const status = await readBenchStatus(filePath);
2420
3155
  if (status) {
2421
3156
  return filePath;
@@ -2424,7 +3159,7 @@ async function findLatestBenchStatusFile(resultsDir) {
2424
3159
  return null;
2425
3160
  }
2426
3161
  async function atomicWriteJSON(filePath, data) {
2427
- await mkdir(path7.dirname(filePath), { recursive: true });
3162
+ await mkdir(path8.dirname(filePath), { recursive: true });
2428
3163
  const tmp = `${filePath}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;
2429
3164
  await writeFile(tmp, JSON.stringify(data, null, 2) + "\n");
2430
3165
  await rename(tmp, filePath);
@@ -2541,8 +3276,8 @@ function finalizeBenchStatus(filePath) {
2541
3276
  }
2542
3277
 
2543
3278
  // src/bench-fallback.ts
2544
- import fs6 from "fs";
2545
- import path8 from "path";
3279
+ import fs7 from "fs";
3280
+ import path9 from "path";
2546
3281
  var FALLBACK_RESULTS_DIRNAME = "fallback-runs";
2547
3282
  function buildBenchRunnerArgs(parsed, benchmarkId, outputDir) {
2548
3283
  const args = ["--benchmark", benchmarkId];
@@ -2606,34 +3341,34 @@ function findUnsupportedFallbackBenchOptions(parsed) {
2606
3341
  return unsupported;
2607
3342
  }
2608
3343
  function createFallbackBenchOutputDir(resultsDir, benchmarkId, pid, startedAtMs = Date.now()) {
2609
- return path8.join(
3344
+ return path9.join(
2610
3345
  resultsDir,
2611
3346
  FALLBACK_RESULTS_DIRNAME,
2612
3347
  `${benchmarkId}-${startedAtMs}-${pid}`
2613
3348
  );
2614
3349
  }
2615
3350
  function resolveFallbackBenchResultPath(outputDir) {
2616
- const entries = fs6.readdirSync(outputDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
3351
+ const entries = fs7.readdirSync(outputDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
2617
3352
  if (entries.length === 0) {
2618
3353
  throw new Error(`Fallback benchmark runner did not write a JSON result artifact in ${outputDir}`);
2619
3354
  }
2620
- return path8.join(outputDir, entries[0]);
3355
+ return path9.join(outputDir, entries[0]);
2621
3356
  }
2622
3357
 
2623
3358
  // src/openclaw-upgrade-swap.ts
2624
- import fs7 from "fs";
2625
- import path9 from "path";
3359
+ import fs8 from "fs";
3360
+ import path10 from "path";
2626
3361
  function describeError(error) {
2627
3362
  return error instanceof Error ? error.message : String(error);
2628
3363
  }
2629
3364
  function createSiblingTempFilePath(targetPath, label) {
2630
3365
  const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
2631
- return path9.join(path9.dirname(targetPath), `.${path9.basename(targetPath)}.${label}.${nonce}.tmp`);
3366
+ return path10.join(path10.dirname(targetPath), `.${path10.basename(targetPath)}.${label}.${nonce}.tmp`);
2632
3367
  }
2633
3368
  function resolveAtomicWriteMode(targetPath, explicitMode) {
2634
3369
  if (explicitMode !== void 0) return explicitMode;
2635
3370
  try {
2636
- return fs7.statSync(targetPath).mode & 4095;
3371
+ return fs8.statSync(targetPath).mode & 4095;
2637
3372
  } catch (error) {
2638
3373
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
2639
3374
  return 384;
@@ -2643,8 +3378,8 @@ function resolveAtomicWriteMode(targetPath, explicitMode) {
2643
3378
  }
2644
3379
  function resolveAtomicReplacementPath(targetPath) {
2645
3380
  try {
2646
- if (fs7.lstatSync(targetPath).isSymbolicLink()) {
2647
- return fs7.realpathSync(targetPath);
3381
+ if (fs8.lstatSync(targetPath).isSymbolicLink()) {
3382
+ return fs8.realpathSync(targetPath);
2648
3383
  }
2649
3384
  } catch (error) {
2650
3385
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -2656,12 +3391,12 @@ function resolveAtomicReplacementPath(targetPath) {
2656
3391
  }
2657
3392
  function createSiblingSwapPath(targetDir, label) {
2658
3393
  const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
2659
- return path9.join(path9.dirname(targetDir), `.${path9.basename(targetDir)}.${label}.${nonce}`);
3394
+ return path10.join(path10.dirname(targetDir), `.${path10.basename(targetDir)}.${label}.${nonce}`);
2660
3395
  }
2661
3396
  function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
2662
3397
  if (!displacedDir) return void 0;
2663
3398
  try {
2664
- fs7.rmSync(displacedDir, { recursive: true, force: true });
3399
+ fs8.rmSync(displacedDir, { recursive: true, force: true });
2665
3400
  return void 0;
2666
3401
  } catch (error) {
2667
3402
  return `Warning: ${context}, but failed to remove the displaced plugin copy at ${displacedDir}: ${describeError(error)}`;
@@ -2669,55 +3404,55 @@ function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
2669
3404
  }
2670
3405
  function atomicWriteFileSync(targetPath, data, options = {}) {
2671
3406
  const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
2672
- fs7.mkdirSync(path9.dirname(resolvedTargetPath), { recursive: true });
3407
+ fs8.mkdirSync(path10.dirname(resolvedTargetPath), { recursive: true });
2673
3408
  const tempPath = createSiblingTempFilePath(resolvedTargetPath, "write");
2674
3409
  const mode = resolveAtomicWriteMode(resolvedTargetPath, options.mode);
2675
3410
  try {
2676
3411
  if (options.hooks?.writeTempFileSync) {
2677
3412
  options.hooks.writeTempFileSync(tempPath);
2678
3413
  } else {
2679
- fs7.writeFileSync(tempPath, data, { mode });
3414
+ fs8.writeFileSync(tempPath, data, { mode });
2680
3415
  }
2681
- fs7.chmodSync(tempPath, mode);
2682
- const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs7.renameSync;
3416
+ fs8.chmodSync(tempPath, mode);
3417
+ const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs8.renameSync;
2683
3418
  renameTempFileSync(tempPath, resolvedTargetPath);
2684
3419
  } catch (error) {
2685
- fs7.rmSync(tempPath, { force: true });
3420
+ fs8.rmSync(tempPath, { force: true });
2686
3421
  throw error;
2687
3422
  }
2688
3423
  }
2689
3424
  function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
2690
- if (!fs7.existsSync(sourcePath)) return;
3425
+ if (!fs8.existsSync(sourcePath)) return;
2691
3426
  const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
2692
- fs7.mkdirSync(path9.dirname(resolvedTargetPath), { recursive: true });
3427
+ fs8.mkdirSync(path10.dirname(resolvedTargetPath), { recursive: true });
2693
3428
  const tempPath = createSiblingTempFilePath(resolvedTargetPath, "copy");
2694
- const mode = fs7.statSync(sourcePath).mode & 4095;
3429
+ const mode = fs8.statSync(sourcePath).mode & 4095;
2695
3430
  try {
2696
- const copyTempFileSync = options.hooks?.copyTempFileSync ?? fs7.copyFileSync;
3431
+ const copyTempFileSync = options.hooks?.copyTempFileSync ?? fs8.copyFileSync;
2697
3432
  copyTempFileSync(sourcePath, tempPath);
2698
- fs7.chmodSync(tempPath, mode);
2699
- const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs7.renameSync;
3433
+ fs8.chmodSync(tempPath, mode);
3434
+ const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs8.renameSync;
2700
3435
  renameTempFileSync(tempPath, resolvedTargetPath);
2701
3436
  } catch (error) {
2702
- fs7.rmSync(tempPath, { force: true });
3437
+ fs8.rmSync(tempPath, { force: true });
2703
3438
  throw error;
2704
3439
  }
2705
3440
  }
2706
3441
  function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
2707
3442
  let hasRollbackCopy = false;
2708
- fs7.mkdirSync(path9.dirname(targetDir), { recursive: true });
2709
- fs7.rmSync(rollbackDir, { recursive: true, force: true });
2710
- if (fs7.existsSync(targetDir)) {
2711
- fs7.renameSync(targetDir, rollbackDir);
3443
+ fs8.mkdirSync(path10.dirname(targetDir), { recursive: true });
3444
+ fs8.rmSync(rollbackDir, { recursive: true, force: true });
3445
+ if (fs8.existsSync(targetDir)) {
3446
+ fs8.renameSync(targetDir, rollbackDir);
2712
3447
  hasRollbackCopy = true;
2713
3448
  }
2714
3449
  try {
2715
- fs7.renameSync(stagedDir, targetDir);
3450
+ fs8.renameSync(stagedDir, targetDir);
2716
3451
  } catch (swapError) {
2717
- fs7.rmSync(targetDir, { recursive: true, force: true });
2718
- if (hasRollbackCopy && fs7.existsSync(rollbackDir)) {
3452
+ fs8.rmSync(targetDir, { recursive: true, force: true });
3453
+ if (hasRollbackCopy && fs8.existsSync(rollbackDir)) {
2719
3454
  try {
2720
- fs7.renameSync(rollbackDir, targetDir);
3455
+ fs8.renameSync(rollbackDir, targetDir);
2721
3456
  hasRollbackCopy = false;
2722
3457
  } catch (restoreError) {
2723
3458
  throw new AggregateError(
@@ -2732,7 +3467,7 @@ function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
2732
3467
  }
2733
3468
  function cleanupRollbackDirectory(rollbackDir) {
2734
3469
  if (!rollbackDir) return;
2735
- fs7.rmSync(rollbackDir, { recursive: true, force: true });
3470
+ fs8.rmSync(rollbackDir, { recursive: true, force: true });
2736
3471
  }
2737
3472
  function cleanupRollbackDirectoryBestEffort(rollbackDir) {
2738
3473
  if (!rollbackDir) return void 0;
@@ -2744,20 +3479,20 @@ function cleanupRollbackDirectoryBestEffort(rollbackDir) {
2744
3479
  }
2745
3480
  }
2746
3481
  function restoreDirectoryFromRollback(targetDir, rollbackDir) {
2747
- if (!fs7.existsSync(rollbackDir)) {
3482
+ if (!fs8.existsSync(rollbackDir)) {
2748
3483
  throw new Error(`Rollback directory is missing: ${rollbackDir}`);
2749
3484
  }
2750
- fs7.mkdirSync(path9.dirname(targetDir), { recursive: true });
2751
- const displacedDir = fs7.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
3485
+ fs8.mkdirSync(path10.dirname(targetDir), { recursive: true });
3486
+ const displacedDir = fs8.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
2752
3487
  if (displacedDir) {
2753
- fs7.renameSync(targetDir, displacedDir);
3488
+ fs8.renameSync(targetDir, displacedDir);
2754
3489
  }
2755
3490
  try {
2756
- fs7.renameSync(rollbackDir, targetDir);
3491
+ fs8.renameSync(rollbackDir, targetDir);
2757
3492
  } catch (restoreError) {
2758
- if (displacedDir && fs7.existsSync(displacedDir)) {
3493
+ if (displacedDir && fs8.existsSync(displacedDir)) {
2759
3494
  try {
2760
- fs7.renameSync(displacedDir, targetDir);
3495
+ fs8.renameSync(displacedDir, targetDir);
2761
3496
  } catch (revertError) {
2762
3497
  throw new AggregateError(
2763
3498
  [restoreError, revertError],
@@ -2776,23 +3511,23 @@ function restoreDirectoryFromRollback(targetDir, rollbackDir) {
2776
3511
  );
2777
3512
  }
2778
3513
  function restoreDirectoryFromBackup(targetDir, backupDir) {
2779
- if (!fs7.existsSync(backupDir)) {
3514
+ if (!fs8.existsSync(backupDir)) {
2780
3515
  throw new Error(`Plugin backup directory is missing: ${backupDir}`);
2781
3516
  }
2782
- fs7.mkdirSync(path9.dirname(targetDir), { recursive: true });
3517
+ fs8.mkdirSync(path10.dirname(targetDir), { recursive: true });
2783
3518
  const stagedDir = createSiblingSwapPath(targetDir, "backup-restore");
2784
- const displacedDir = fs7.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
2785
- fs7.cpSync(backupDir, stagedDir, { recursive: true });
3519
+ const displacedDir = fs8.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
3520
+ fs8.cpSync(backupDir, stagedDir, { recursive: true });
2786
3521
  if (displacedDir) {
2787
- fs7.renameSync(targetDir, displacedDir);
3522
+ fs8.renameSync(targetDir, displacedDir);
2788
3523
  }
2789
3524
  try {
2790
- fs7.renameSync(stagedDir, targetDir);
3525
+ fs8.renameSync(stagedDir, targetDir);
2791
3526
  } catch (restoreError) {
2792
- fs7.rmSync(targetDir, { recursive: true, force: true });
2793
- if (displacedDir && fs7.existsSync(displacedDir)) {
3527
+ fs8.rmSync(targetDir, { recursive: true, force: true });
3528
+ if (displacedDir && fs8.existsSync(displacedDir)) {
2794
3529
  try {
2795
- fs7.renameSync(displacedDir, targetDir);
3530
+ fs8.renameSync(displacedDir, targetDir);
2796
3531
  } catch (revertError) {
2797
3532
  throw new AggregateError(
2798
3533
  [restoreError, revertError],
@@ -2800,7 +3535,7 @@ function restoreDirectoryFromBackup(targetDir, backupDir) {
2800
3535
  );
2801
3536
  }
2802
3537
  }
2803
- fs7.rmSync(stagedDir, { recursive: true, force: true });
3538
+ fs8.rmSync(stagedDir, { recursive: true, force: true });
2804
3539
  throw new Error(
2805
3540
  `Failed to restore the plugin backup into ${targetDir}. The durable backup remains preserved at ${backupDir}.`,
2806
3541
  { cause: restoreError }
@@ -2826,7 +3561,7 @@ function rollbackOpenclawUpgrade({
2826
3561
  let rollbackRestoreError;
2827
3562
  let pluginRestored = false;
2828
3563
  try {
2829
- if (rollbackDir && fs7.existsSync(rollbackDir)) {
3564
+ if (rollbackDir && fs8.existsSync(rollbackDir)) {
2830
3565
  const cleanupWarning = restoreDirectoryFromRollback(pluginDir, rollbackDir);
2831
3566
  notes.push(`Restored previous plugin from rollback copy at ${rollbackDir}`);
2832
3567
  if (cleanupWarning) notes.push(cleanupWarning);
@@ -2836,7 +3571,7 @@ function rollbackOpenclawUpgrade({
2836
3571
  rollbackRestoreError = error instanceof Error ? error.message : String(error);
2837
3572
  }
2838
3573
  try {
2839
- if (!pluginRestored && pluginBackupDir && fs7.existsSync(pluginBackupDir)) {
3574
+ if (!pluginRestored && pluginBackupDir && fs8.existsSync(pluginBackupDir)) {
2840
3575
  const cleanupWarning = restoreDirectoryFromBackup(pluginDir, pluginBackupDir);
2841
3576
  if (rollbackRestoreError) {
2842
3577
  notes.push(
@@ -2863,7 +3598,7 @@ function rollbackOpenclawUpgrade({
2863
3598
  notes.push("No previous plugin copy was available for automatic restore");
2864
3599
  }
2865
3600
  try {
2866
- if (configBackupPath && fs7.existsSync(configBackupPath)) {
3601
+ if (configBackupPath && fs8.existsSync(configBackupPath)) {
2867
3602
  restoreFileFromBackup(configPath, configBackupPath);
2868
3603
  notes.push(`Restored OpenClaw config from backup at ${configBackupPath}`);
2869
3604
  }
@@ -2903,11 +3638,11 @@ Run this manually when you're ready:
2903
3638
  }
2904
3639
 
2905
3640
  // src/daemon-service.ts
2906
- import fs8 from "fs";
2907
- import path10 from "path";
3641
+ import fs9 from "fs";
3642
+ import path11 from "path";
2908
3643
  import * as childProcess from "child_process";
2909
3644
  import { fileURLToPath as fileURLToPath3 } from "url";
2910
- var thisModuleDir = path10.dirname(fileURLToPath3(import.meta.url));
3645
+ var thisModuleDir = path11.dirname(fileURLToPath3(import.meta.url));
2911
3646
  function launchdLoadPlist(plistPath, processApi = childProcess) {
2912
3647
  processApi.execFileSync("launchctl", ["load", "-w", plistPath], { stdio: "pipe" });
2913
3648
  }
@@ -2915,7 +3650,7 @@ function launchdUnloadPlist(plistPath, processApi = childProcess) {
2915
3650
  processApi.execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
2916
3651
  }
2917
3652
  function resolveServerBinDetails(options = {}) {
2918
- const existsSync4 = options.existsSync ?? fs8.existsSync;
3653
+ const existsSync4 = options.existsSync ?? fs9.existsSync;
2919
3654
  const findCommandOnPath2 = options.findCommandOnPath ?? findCommandOnPath;
2920
3655
  const moduleDir = options.moduleDir ?? thisModuleDir;
2921
3656
  const packageResolve = options.packageResolve ?? resolveImportSpecifier;
@@ -2929,8 +3664,8 @@ function resolveServerBinDetails(options = {}) {
2929
3664
  });
2930
3665
  } catch {
2931
3666
  }
2932
- const workspaceServerBin = path10.resolve(moduleDir, "../../remnic-server/bin/remnic-server.js");
2933
- const workspaceDistIndex = path10.resolve(moduleDir, "../../remnic-server/dist/index.js");
3667
+ const workspaceServerBin = path11.resolve(moduleDir, "../../remnic-server/bin/remnic-server.js");
3668
+ const workspaceDistIndex = path11.resolve(moduleDir, "../../remnic-server/dist/index.js");
2934
3669
  candidates.push(
2935
3670
  {
2936
3671
  path: workspaceServerBin,
@@ -2951,11 +3686,11 @@ function resolveServerBinDetails(options = {}) {
2951
3686
  });
2952
3687
  }
2953
3688
  candidates.push({
2954
- path: path10.resolve(moduleDir, "../../remnic-server/src/index.ts"),
3689
+ path: path11.resolve(moduleDir, "../../remnic-server/src/index.ts"),
2955
3690
  source: "workspace-source"
2956
3691
  });
2957
3692
  const selected = candidates.find((candidate) => isCandidateReady(candidate, existsSync4)) ?? candidates.find((candidate) => existsSync4(candidate.path)) ?? candidates[0] ?? {
2958
- path: path10.resolve(moduleDir, "../../remnic-server/dist/index.js"),
3693
+ path: path11.resolve(moduleDir, "../../remnic-server/dist/index.js"),
2959
3694
  source: "workspace-dist"
2960
3695
  };
2961
3696
  const exists = existsSync4(selected.path);
@@ -2974,8 +3709,8 @@ function resolveServerBin(options = {}) {
2974
3709
  return resolveServerBinDetails(options).path;
2975
3710
  }
2976
3711
  function readVerifiedDaemonPid(options) {
2977
- const readFileSync4 = options.readFileSync ?? fs8.readFileSync;
2978
- const unlinkSync = options.unlinkSync ?? fs8.unlinkSync;
3712
+ const readFileSync4 = options.readFileSync ?? fs9.readFileSync;
3713
+ const unlinkSync = options.unlinkSync ?? fs9.unlinkSync;
2979
3714
  const processKill = options.processKill ?? process.kill;
2980
3715
  const platform = options.platform ?? process.platform;
2981
3716
  const execFileSync3 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
@@ -3010,7 +3745,7 @@ function readVerifiedDaemonPid(options) {
3010
3745
  }
3011
3746
  function doesProcessCommandLookLikeRemnicDaemon(command, expectedServerBin) {
3012
3747
  const normalizedCommand = command.trim();
3013
- const normalizedExpected = path10.resolve(expandTilde(expectedServerBin));
3748
+ const normalizedExpected = path11.resolve(expandTilde(expectedServerBin));
3014
3749
  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);
3015
3750
  }
3016
3751
  function parseDaemonPid(raw) {
@@ -3075,8 +3810,8 @@ function removePidFileBestEffort(file, unlinkSync) {
3075
3810
  }
3076
3811
  }
3077
3812
  function inspectLaunchdPlist(plistPath, options = {}) {
3078
- const existsSync4 = options.existsSync ?? fs8.existsSync;
3079
- const readFileSync4 = options.readFileSync ?? fs8.readFileSync;
3813
+ const existsSync4 = options.existsSync ?? fs9.existsSync;
3814
+ const readFileSync4 = options.readFileSync ?? fs9.readFileSync;
3080
3815
  if (!existsSync4(plistPath)) {
3081
3816
  return {
3082
3817
  installed: false,
@@ -3115,7 +3850,7 @@ function inspectLaunchdPlist(plistPath, options = {}) {
3115
3850
  };
3116
3851
  }
3117
3852
  const expandedServerArg = expandTilde(serverArg);
3118
- if (!path10.isAbsolute(expandedServerArg)) {
3853
+ if (!path11.isAbsolute(expandedServerArg)) {
3119
3854
  return {
3120
3855
  installed: true,
3121
3856
  ok: false,
@@ -3187,8 +3922,8 @@ function normalizeResolvedPath(resolved) {
3187
3922
  return resolved;
3188
3923
  }
3189
3924
  function packageServerBinFromEntry(packageEntry) {
3190
- if (path10.basename(packageEntry) === "index.js" && path10.basename(path10.dirname(packageEntry)) === "dist") {
3191
- return path10.join(path10.dirname(path10.dirname(packageEntry)), "bin", "remnic-server.js");
3925
+ if (path11.basename(packageEntry) === "index.js" && path11.basename(path11.dirname(packageEntry)) === "dist") {
3926
+ return path11.join(path11.dirname(path11.dirname(packageEntry)), "bin", "remnic-server.js");
3192
3927
  }
3193
3928
  return packageEntry;
3194
3929
  }
@@ -3310,7 +4045,7 @@ function stripConfigArgv(args) {
3310
4045
  }
3311
4046
 
3312
4047
  // src/import-dispatch.ts
3313
- import fs9 from "fs";
4048
+ import fs10 from "fs";
3314
4049
  import {
3315
4050
  runImporter,
3316
4051
  validateImportBatchSize,
@@ -3319,7 +4054,7 @@ import {
3319
4054
 
3320
4055
  // src/import-bundle-detect.ts
3321
4056
  import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
3322
- import path11 from "path";
4057
+ import path12 from "path";
3323
4058
  function detectBundleEntries(bundleDir, options = {}) {
3324
4059
  const readdir3 = options.readdirImpl ?? defaultReaddir;
3325
4060
  const readFileImpl = options.readFileImpl ?? defaultReadFile;
@@ -3350,7 +4085,7 @@ function detectBundleEntries(bundleDir, options = {}) {
3350
4085
  for (const filePath of roots) {
3351
4086
  if (seenFiles.has(filePath)) continue;
3352
4087
  seenFiles.add(filePath);
3353
- const name = path11.basename(filePath);
4088
+ const name = path12.basename(filePath);
3354
4089
  const match = classifyFile(name, filePath, readFileImpl);
3355
4090
  if (match) entries.push(match);
3356
4091
  }
@@ -3388,7 +4123,7 @@ function collectCandidatePaths(root, readdir3, isDirectory2, isRegularFile) {
3388
4123
  return;
3389
4124
  }
3390
4125
  for (const entry of entries) {
3391
- const full = path11.join(dir, entry);
4126
+ const full = path12.join(dir, entry);
3392
4127
  if (isDirectory2(full)) {
3393
4128
  walk(full, depth + 1);
3394
4129
  } else if (isRegularFile(full)) {
@@ -3824,7 +4559,7 @@ async function cmdImport(rest, targetFactory, disposeTarget, ioOverrides = {}) {
3824
4559
  let materializedTarget;
3825
4560
  let materializePromise;
3826
4561
  const io = {
3827
- readFile: ioOverrides.readFile ?? (async (p) => fs9.promises.readFile(p, "utf-8")),
4562
+ readFile: ioOverrides.readFile ?? (async (p) => fs10.promises.readFile(p, "utf-8")),
3828
4563
  loadAdapter: ioOverrides.loadAdapter ?? (async (name) => (await loadImporterModule(name)).adapter),
3829
4564
  runImporter: ioOverrides.runImporter ?? runImporter,
3830
4565
  getWriteTarget: async () => {
@@ -3937,8 +4672,8 @@ async function cmdCapture(rest, io) {
3937
4672
  }
3938
4673
 
3939
4674
  // src/import-lossless-claw-cmd.ts
3940
- import fs10 from "fs";
3941
- import path12 from "path";
4675
+ import fs11 from "fs";
4676
+ import path13 from "path";
3942
4677
  import {
3943
4678
  applyLcmSchema,
3944
4679
  ensureLcmStateDir,
@@ -4049,15 +4784,15 @@ async function loadImportLosslessClawModule() {
4049
4784
 
4050
4785
  // src/import-lossless-claw-cmd.ts
4051
4786
  function assertDirectoryOrAbsent(p, label) {
4052
- if (fs10.existsSync(p) && !fs10.statSync(p).isDirectory()) {
4787
+ if (fs11.existsSync(p) && !fs11.statSync(p).isDirectory()) {
4053
4788
  throw new Error(`${label} is not a directory: ${p}`);
4054
4789
  }
4055
4790
  }
4056
4791
  function assertFile(p, label) {
4057
- if (!fs10.existsSync(p)) {
4792
+ if (!fs11.existsSync(p)) {
4058
4793
  throw new Error(`${label} does not exist: ${p}`);
4059
4794
  }
4060
- if (!fs10.statSync(p).isFile()) {
4795
+ if (!fs11.statSync(p).isFile()) {
4061
4796
  throw new Error(`${label} is not a file: ${p}`);
4062
4797
  }
4063
4798
  }
@@ -4088,8 +4823,8 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
4088
4823
  let destDb;
4089
4824
  try {
4090
4825
  if (parsed.dryRun) {
4091
- const lcmPath = path12.join(memoryDir, "state", "lcm.sqlite");
4092
- if (fs10.existsSync(lcmPath)) {
4826
+ const lcmPath = path13.join(memoryDir, "state", "lcm.sqlite");
4827
+ if (fs11.existsSync(lcmPath)) {
4093
4828
  destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
4094
4829
  } else {
4095
4830
  destDb = mod.openInMemoryDestinationDatabase();
@@ -4207,7 +4942,7 @@ function printBenchComparisonSummary(comparison, baseline, candidate) {
4207
4942
  }
4208
4943
 
4209
4944
  // src/bench-research-commands.ts
4210
- import path13 from "path";
4945
+ import path14 from "path";
4211
4946
  function emit(result) {
4212
4947
  if (result.output) {
4213
4948
  console.log(result.output);
@@ -4225,7 +4960,7 @@ async function runBenchResearchCommand(parsed) {
4225
4960
  emit(
4226
4961
  await runAttributeCliCommand({
4227
4962
  runRef: parsed.runRef,
4228
- resultsDir: parsed.resultsDir ?? path13.join(resolveHomeDir(), ".remnic", "bench", "results"),
4963
+ resultsDir: parsed.resultsDir ?? path14.join(resolveHomeDir(), ".remnic", "bench", "results"),
4229
4964
  memoryDir: parsed.memoryDir,
4230
4965
  threshold: parsed.threshold,
4231
4966
  json: parsed.json
@@ -4480,15 +5215,15 @@ registerPublisher("omp", () => new LazyPluginPiPublisher("omp", (mod) => mod.Omp
4480
5215
  function readCompatEnv(primary, legacy) {
4481
5216
  return process.env[primary] ?? process.env[legacy];
4482
5217
  }
4483
- var PID_DIR = path14.join(resolveHomeDir(), ".remnic");
4484
- var LEGACY_PID_DIR = path14.join(resolveHomeDir(), ".engram");
4485
- var PID_FILE = path14.join(PID_DIR, "server.pid");
4486
- var LEGACY_PID_FILE = path14.join(LEGACY_PID_DIR, "server.pid");
4487
- var LOG_FILE = path14.join(PID_DIR, "server.log");
4488
- var LEGACY_LOG_FILE = path14.join(LEGACY_PID_DIR, "server.log");
4489
- var CLI_MODULE_DIR = path14.dirname(fileURLToPath4(import.meta.url));
4490
- var CLI_REPO_ROOT = path14.resolve(CLI_MODULE_DIR, "../../..");
4491
- var EVAL_RUNNER_PATH = path14.join(CLI_REPO_ROOT, "evals", "run.ts");
5218
+ var PID_DIR = path15.join(resolveHomeDir(), ".remnic");
5219
+ var LEGACY_PID_DIR = path15.join(resolveHomeDir(), ".engram");
5220
+ var PID_FILE = path15.join(PID_DIR, "server.pid");
5221
+ var LEGACY_PID_FILE = path15.join(LEGACY_PID_DIR, "server.pid");
5222
+ var LOG_FILE = path15.join(PID_DIR, "server.log");
5223
+ var LEGACY_LOG_FILE = path15.join(LEGACY_PID_DIR, "server.log");
5224
+ var CLI_MODULE_DIR = path15.dirname(fileURLToPath4(import.meta.url));
5225
+ var CLI_REPO_ROOT = path15.resolve(CLI_MODULE_DIR, "../../..");
5226
+ var EVAL_RUNNER_PATH = path15.join(CLI_REPO_ROOT, "evals", "run.ts");
4492
5227
  var OPENCLAW_GATEWAY_LABEL = "ai.openclaw.gateway";
4493
5228
  var CLI_SUCCESS_EXIT_GRACE_MS = 5e3;
4494
5229
  var CLI_OUTPUT_FLUSH_GRACE_MS = 250;
@@ -4653,7 +5388,7 @@ async function resolveAllBenchmarks() {
4653
5388
  if (packageBenchmarks) {
4654
5389
  return packageBenchmarks.filter((entry) => entry.runnerAvailable).map((entry) => entry.id);
4655
5390
  }
4656
- if (!fs11.existsSync(EVAL_RUNNER_PATH)) {
5391
+ if (!fs12.existsSync(EVAL_RUNNER_PATH)) {
4657
5392
  return [];
4658
5393
  }
4659
5394
  return BENCHMARK_CATALOG.filter((entry) => entry.category !== "ingestion").map((entry) => entry.id);
@@ -4701,17 +5436,17 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
4701
5436
  `Fallback benchmark runner does not support provider-backed, gateway, or thinking/timeout flags (${unsupportedOptions.join(", ")}). Build/install @remnic/bench to use those options.`
4702
5437
  );
4703
5438
  }
4704
- if (!fs11.existsSync(EVAL_RUNNER_PATH)) {
5439
+ if (!fs12.existsSync(EVAL_RUNNER_PATH)) {
4705
5440
  console.error(
4706
5441
  "Benchmark runner not found. Expected eval runner at evals/run.ts or a phase-1 @remnic/bench runtime export."
4707
5442
  );
4708
5443
  process.exit(1);
4709
5444
  }
4710
5445
  const tsxCandidates = [
4711
- path14.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
4712
- path14.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
5446
+ path15.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
5447
+ path15.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
4713
5448
  ];
4714
- const tsxCmd = tsxCandidates.find((candidate) => fs11.existsSync(candidate)) ?? "tsx";
5449
+ const tsxCmd = tsxCandidates.find((candidate) => fs12.existsSync(candidate)) ?? "tsx";
4715
5450
  const fallbackOutputDir = createFallbackBenchOutputDir(
4716
5451
  parsed.resultsDir ?? resolveBenchOutputDir(),
4717
5452
  benchmarkId,
@@ -4728,7 +5463,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
4728
5463
  return resolveFallbackBenchResultPath(fallbackOutputDir);
4729
5464
  }
4730
5465
  function resolveBenchOutputDir() {
4731
- return path14.join(resolveHomeDir(), ".remnic", "bench", "results");
5466
+ return path15.join(resolveHomeDir(), ".remnic", "bench", "results");
4732
5467
  }
4733
5468
  var DOWNLOADABLE_BENCHMARK_DATASETS = [
4734
5469
  "ama-bench",
@@ -4773,8 +5508,8 @@ var MEMORY_AGENT_BENCH_SPLIT_FILENAMES = [
4773
5508
  ];
4774
5509
  var MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES = [
4775
5510
  "entity2id.json",
4776
- path14.join("processed_data", "Recsys_Redial", "entity2id.json"),
4777
- path14.join("Recsys_Redial", "entity2id.json")
5511
+ path15.join("processed_data", "Recsys_Redial", "entity2id.json"),
5512
+ path15.join("Recsys_Redial", "entity2id.json")
4778
5513
  ];
4779
5514
  var DOWNLOADED_DATASET_MARKERS = {
4780
5515
  "ama-bench": { anyOf: ["open_end_qa_set.jsonl"] },
@@ -4849,18 +5584,18 @@ var PERSONAMEM_DATASET_FILE_CANDIDATES = [
4849
5584
  "benchmark/benchmark.csv",
4850
5585
  "benchmark.csv"
4851
5586
  ];
4852
- var PERSONAMEM_COMPLETION_MARKER = path14.join(
5587
+ var PERSONAMEM_COMPLETION_MARKER = path15.join(
4853
5588
  "data",
4854
5589
  "chat_history_32k",
4855
5590
  ".download-complete"
4856
5591
  );
4857
5592
  function resolveRealpathWithinDataset(datasetPath, relativePath) {
4858
5593
  try {
4859
- const datasetRoot = fs11.realpathSync(datasetPath);
4860
- const candidatePath = path14.resolve(datasetRoot, relativePath);
4861
- const candidateRealPath = fs11.realpathSync(candidatePath);
4862
- const relativeToRoot = path14.relative(datasetRoot, candidateRealPath);
4863
- if (relativeToRoot.startsWith("..") || path14.isAbsolute(relativeToRoot)) {
5594
+ const datasetRoot = fs12.realpathSync(datasetPath);
5595
+ const candidatePath = path15.resolve(datasetRoot, relativePath);
5596
+ const candidateRealPath = fs12.realpathSync(candidatePath);
5597
+ const relativeToRoot = path15.relative(datasetRoot, candidateRealPath);
5598
+ if (relativeToRoot.startsWith("..") || path15.isAbsolute(relativeToRoot)) {
4864
5599
  return null;
4865
5600
  }
4866
5601
  return candidateRealPath;
@@ -4916,15 +5651,15 @@ function parseCsvRows(raw) {
4916
5651
  }
4917
5652
  function isPersonaMemDatasetComplete(datasetPath) {
4918
5653
  try {
4919
- const completionMarkerPath = path14.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
4920
- if (fs11.statSync(completionMarkerPath).isFile()) {
5654
+ const completionMarkerPath = path15.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
5655
+ if (fs12.statSync(completionMarkerPath).isFile()) {
4921
5656
  return true;
4922
5657
  }
4923
5658
  } catch {
4924
5659
  }
4925
5660
  const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
4926
5661
  try {
4927
- return fs11.statSync(path14.join(datasetPath, candidate)).isFile();
5662
+ return fs12.statSync(path15.join(datasetPath, candidate)).isFile();
4928
5663
  } catch {
4929
5664
  return false;
4930
5665
  }
@@ -4933,7 +5668,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
4933
5668
  return false;
4934
5669
  }
4935
5670
  try {
4936
- const rows = parseCsvRows(fs11.readFileSync(path14.join(datasetPath, datasetFile), "utf8"));
5671
+ const rows = parseCsvRows(fs12.readFileSync(path15.join(datasetPath, datasetFile), "utf8"));
4937
5672
  if (rows.length < 2) {
4938
5673
  return false;
4939
5674
  }
@@ -4948,7 +5683,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
4948
5683
  }
4949
5684
  return historyPaths.every((relativePath) => {
4950
5685
  const resolvedPath = resolveRealpathWithinDataset(datasetPath, relativePath);
4951
- return resolvedPath !== null && fs11.statSync(resolvedPath).isFile();
5686
+ return resolvedPath !== null && fs12.statSync(resolvedPath).isFile();
4952
5687
  });
4953
5688
  } catch {
4954
5689
  return false;
@@ -4956,14 +5691,14 @@ function isPersonaMemDatasetComplete(datasetPath) {
4956
5691
  }
4957
5692
  function hasDatasetFile(datasetPath, relativePath) {
4958
5693
  try {
4959
- return fs11.statSync(path14.join(datasetPath, relativePath)).isFile();
5694
+ return fs12.statSync(path15.join(datasetPath, relativePath)).isFile();
4960
5695
  } catch {
4961
5696
  return false;
4962
5697
  }
4963
5698
  }
4964
5699
  function hasMemoryAgentBenchEntityMapping(datasetPath) {
4965
- const absoluteDatasetPath = path14.resolve(datasetPath);
4966
- const roots = [absoluteDatasetPath, path14.dirname(absoluteDatasetPath)];
5700
+ const absoluteDatasetPath = path15.resolve(datasetPath);
5701
+ const roots = [absoluteDatasetPath, path15.dirname(absoluteDatasetPath)];
4967
5702
  return hasDatasetFile(absoluteDatasetPath, "entity2id.json") || roots.some(
4968
5703
  (root) => MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES.filter((relativePath) => relativePath !== "entity2id.json").some((relativePath) => hasDatasetFile(root, relativePath))
4969
5704
  );
@@ -4974,12 +5709,12 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
4974
5709
  ...MEMORY_AGENT_BENCH_SPLIT_FILENAMES
4975
5710
  ];
4976
5711
  return candidateFilenames.some((filename) => {
4977
- const filePath = path14.join(datasetPath, filename);
5712
+ const filePath = path15.join(datasetPath, filename);
4978
5713
  try {
4979
- if (!fs11.statSync(filePath).isFile()) {
5714
+ if (!fs12.statSync(filePath).isFile()) {
4980
5715
  return false;
4981
5716
  }
4982
- const raw = fs11.readFileSync(filePath, "utf8");
5717
+ const raw = fs12.readFileSync(filePath, "utf8");
4983
5718
  return /"source"\s*:\s*"recsys[_-]/i.test(raw);
4984
5719
  } catch {
4985
5720
  return false;
@@ -4995,7 +5730,7 @@ function isMemoryAgentBenchDatasetComplete(datasetPath) {
4995
5730
  function isDatasetDownloaded(datasetPath, benchmarkId) {
4996
5731
  let stats;
4997
5732
  try {
4998
- stats = fs11.statSync(datasetPath);
5733
+ stats = fs12.statSync(datasetPath);
4999
5734
  } catch {
5000
5735
  return false;
5001
5736
  }
@@ -5005,7 +5740,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
5005
5740
  const marker = DOWNLOADED_DATASET_MARKERS[benchmarkId];
5006
5741
  if (!marker) {
5007
5742
  try {
5008
- return fs11.readdirSync(datasetPath).length > 0;
5743
+ return fs12.readdirSync(datasetPath).length > 0;
5009
5744
  } catch {
5010
5745
  return false;
5011
5746
  }
@@ -5013,7 +5748,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
5013
5748
  if (marker.allOf) {
5014
5749
  const hasAllRequiredFiles = marker.allOf.every((name) => {
5015
5750
  try {
5016
- return fs11.statSync(path14.join(datasetPath, name)).isFile();
5751
+ return fs12.statSync(path15.join(datasetPath, name)).isFile();
5017
5752
  } catch {
5018
5753
  return false;
5019
5754
  }
@@ -5025,7 +5760,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
5025
5760
  if (marker.anyOf) {
5026
5761
  const hasMarkerFile = marker.anyOf.some((name) => {
5027
5762
  try {
5028
- return fs11.statSync(path14.join(datasetPath, name)).isFile();
5763
+ return fs12.statSync(path15.join(datasetPath, name)).isFile();
5029
5764
  } catch {
5030
5765
  return false;
5031
5766
  }
@@ -5043,7 +5778,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
5043
5778
  }
5044
5779
  if (marker.ext) {
5045
5780
  try {
5046
- return fs11.readdirSync(datasetPath).some(
5781
+ return fs12.readdirSync(datasetPath).some(
5047
5782
  (name) => name.endsWith(marker.ext) && !marker.exclude?.includes(name)
5048
5783
  );
5049
5784
  } catch {
@@ -5053,9 +5788,9 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
5053
5788
  return false;
5054
5789
  }
5055
5790
  async function launchBenchUi(resultsDir) {
5056
- const benchUiDir = path14.join(CLI_REPO_ROOT, "packages", "bench-ui");
5791
+ const benchUiDir = path15.join(CLI_REPO_ROOT, "packages", "bench-ui");
5057
5792
  const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
5058
- if (!fs11.existsSync(path14.join(benchUiDir, "package.json"))) {
5793
+ if (!fs12.existsSync(path15.join(benchUiDir, "package.json"))) {
5059
5794
  console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
5060
5795
  process.exit(1);
5061
5796
  }
@@ -5082,24 +5817,24 @@ async function launchBenchUi(resultsDir) {
5082
5817
  });
5083
5818
  }
5084
5819
  function resolveRepoDatasetRoot() {
5085
- const repoCandidate = path14.join(CLI_REPO_ROOT, "evals", "datasets");
5820
+ const repoCandidate = path15.join(CLI_REPO_ROOT, "evals", "datasets");
5086
5821
  if (isRepoCheckout()) {
5087
5822
  return repoCandidate;
5088
5823
  }
5089
- return path14.join(resolveHomeDir(), ".remnic", "bench", "datasets");
5824
+ return path15.join(resolveHomeDir(), ".remnic", "bench", "datasets");
5090
5825
  }
5091
5826
  function listDownloadableBenchmarks() {
5092
5827
  return [...DOWNLOADABLE_BENCHMARK_DATASETS];
5093
5828
  }
5094
5829
  function resolveDatasetDownloadScriptPath() {
5095
- const bundled = path14.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
5096
- if (fs11.existsSync(bundled)) {
5830
+ const bundled = path15.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
5831
+ if (fs12.existsSync(bundled)) {
5097
5832
  return bundled;
5098
5833
  }
5099
- return path14.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
5834
+ return path15.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
5100
5835
  }
5101
5836
  function isRepoCheckout() {
5102
- return fs11.existsSync(path14.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs11.existsSync(path14.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
5837
+ return fs12.existsSync(path15.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs12.existsSync(path15.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
5103
5838
  }
5104
5839
  function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
5105
5840
  const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
@@ -5150,7 +5885,7 @@ function resolveBenchDatasetDir(benchmarkId, quick, datasetDirOverride) {
5150
5885
  if (quick) {
5151
5886
  return void 0;
5152
5887
  }
5153
- const datasetDir = path14.join(resolveRepoDatasetRoot(), benchmarkId);
5888
+ const datasetDir = path15.join(resolveRepoDatasetRoot(), benchmarkId);
5154
5889
  if (isDatasetDownloaded(datasetDir, benchmarkId)) {
5155
5890
  return datasetDir;
5156
5891
  }
@@ -5407,13 +6142,13 @@ async function exportBenchPackageResult(parsed) {
5407
6142
  process.exit(1);
5408
6143
  }
5409
6144
  const result = await loadBenchmarkResult(summary.path);
5410
- const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(path14.dirname(summary.path), result.meta.id) : void 0;
6145
+ const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(path15.dirname(summary.path), result.meta.id) : void 0;
5411
6146
  const rendered = renderBenchmarkResultExport(result, parsed.format, {
5412
6147
  ...reportCardProvenance ? { reportCardProvenance } : {}
5413
6148
  });
5414
6149
  if (parsed.output) {
5415
- fs11.mkdirSync(path14.dirname(parsed.output), { recursive: true });
5416
- fs11.writeFileSync(parsed.output, rendered);
6150
+ fs12.mkdirSync(path15.dirname(parsed.output), { recursive: true });
6151
+ fs12.writeFileSync(parsed.output, rendered);
5417
6152
  console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
5418
6153
  return;
5419
6154
  }
@@ -5430,7 +6165,7 @@ async function manageBenchDatasets(parsed) {
5430
6165
  process.exit(1);
5431
6166
  }
5432
6167
  const status = supported.map((benchmarkId) => {
5433
- const datasetPath = path14.join(datasetRoot, benchmarkId);
6168
+ const datasetPath = path15.join(datasetRoot, benchmarkId);
5434
6169
  return {
5435
6170
  benchmark: benchmarkId,
5436
6171
  downloaded: isDatasetDownloaded(datasetPath, benchmarkId),
@@ -5458,7 +6193,7 @@ async function manageBenchDatasets(parsed) {
5458
6193
  process.exit(1);
5459
6194
  }
5460
6195
  const scriptPath = resolveDatasetDownloadScriptPath();
5461
- if (!fs11.existsSync(scriptPath)) {
6196
+ if (!fs12.existsSync(scriptPath)) {
5462
6197
  console.error(`ERROR: dataset download script not found: ${scriptPath}`);
5463
6198
  process.exit(1);
5464
6199
  }
@@ -5468,7 +6203,7 @@ async function manageBenchDatasets(parsed) {
5468
6203
  runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, parsed.json === true);
5469
6204
  downloaded.push({
5470
6205
  benchmark: benchmarkId,
5471
- path: path14.join(datasetRoot, benchmarkId)
6206
+ path: path15.join(datasetRoot, benchmarkId)
5472
6207
  });
5473
6208
  }
5474
6209
  if (parsed.json) {
@@ -5607,10 +6342,10 @@ async function calibrateBenchJudges(parsed, rawArgs) {
5607
6342
  }
5608
6343
  const bench = await loadBenchModule();
5609
6344
  const resultsDir = expandTilde(
5610
- parsed.resultsDir ?? path14.join(resolveHomeDir(), ".remnic", "bench", "results")
6345
+ parsed.resultsDir ?? path15.join(resolveHomeDir(), ".remnic", "bench", "results")
5611
6346
  );
5612
6347
  const calibrationDir = expandTilde(
5613
- parsed.calibrationDir ?? path14.join(resolveHomeDir(), ".remnic", "bench", "calibration")
6348
+ parsed.calibrationDir ?? path15.join(resolveHomeDir(), ".remnic", "bench", "calibration")
5614
6349
  );
5615
6350
  const stored = await bench.listBenchmarkResults(resultsDir);
5616
6351
  const allForBenchmark = stored.filter((entry) => entry.benchmark === benchmarkId);
@@ -5658,7 +6393,7 @@ async function calibrateBenchJudges(parsed, rawArgs) {
5658
6393
  );
5659
6394
  process.exit(1);
5660
6395
  }
5661
- const sourceResultSha256 = createHash2("sha256").update(fs11.readFileSync(latest.path)).digest("hex");
6396
+ const sourceResultSha256 = createHash3("sha256").update(fs12.readFileSync(latest.path)).digest("hex");
5662
6397
  const expandedManifestPath = expandTilde(manifestPath);
5663
6398
  if (!bench.resolveLocalLabJudgeProviderConfig) {
5664
6399
  console.error(
@@ -6073,7 +6808,7 @@ function loadPinnedLoCoMoTaskSelector(parsed) {
6073
6808
  }
6074
6809
  let decoded;
6075
6810
  try {
6076
- decoded = JSON.parse(fs11.readFileSync(parsed.taskIdsFile, "utf8"));
6811
+ decoded = JSON.parse(fs12.readFileSync(parsed.taskIdsFile, "utf8"));
6077
6812
  } catch (error) {
6078
6813
  throw new Error(
6079
6814
  `Unable to read --task-ids-file ${parsed.taskIdsFile}: ${error instanceof Error ? error.message : String(error)}`
@@ -6170,7 +6905,7 @@ async function loadPublishedPromotionHelpers() {
6170
6905
  return {
6171
6906
  async promoteArtifactsToPublished(args) {
6172
6907
  const { mkdirSync, readFileSync: readFileSync4, writeFileSync } = await import("fs");
6173
- const path15 = await import("path");
6908
+ const path16 = await import("path");
6174
6909
  mkdirSync(args.publishedOutDir, { recursive: true });
6175
6910
  if (args.artifactPaths.length === 0) {
6176
6911
  console.warn(
@@ -6187,13 +6922,13 @@ async function loadPublishedPromotionHelpers() {
6187
6922
  const modelSlug = args.model.replace(/[^a-zA-Z0-9_.-]/g, "-");
6188
6923
  const rawProfile = parsedObj.config?.runtimeProfile;
6189
6924
  const profileSlug = typeof rawProfile === "string" && rawProfile.length > 0 ? `-${rawProfile.replace(/[^a-zA-Z0-9_.-]/g, "-")}` : "";
6190
- const target = path15.join(
6925
+ const target = path16.join(
6191
6926
  args.publishedOutDir,
6192
6927
  `${today}-${args.benchmarkId}-${modelSlug}${profileSlug}-${gitShaShort}.json`
6193
6928
  );
6194
6929
  writeFileSync(target, raw, "utf8");
6195
6930
  console.log(
6196
- `[bench published] Promoted ${path15.basename(artifactPath)} \u2192 ${target}`
6931
+ `[bench published] Promoted ${path16.basename(artifactPath)} \u2192 ${target}`
6197
6932
  );
6198
6933
  }
6199
6934
  void benchModule;
@@ -6300,7 +7035,7 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
6300
7035
  const previousCodexDiagnosticsDir = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV];
6301
7036
  const previousCodexDiagnosticsMode = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_MODE_ENV];
6302
7037
  if (!previousCodexDiagnosticsDir) {
6303
- process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] = path14.join(
7038
+ process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] = path15.join(
6304
7039
  outputDir,
6305
7040
  "codex-cli-diagnostics"
6306
7041
  );
@@ -6448,7 +7183,7 @@ async function preparePersistedJudgeCalibrationAttachment(benchModule, benchmark
6448
7183
  );
6449
7184
  }
6450
7185
  const calibrationDir = expandTilde(
6451
- calibrationBinding.calibrationDir ?? path14.join(resolveHomeDir(), ".remnic", "bench", "calibration")
7186
+ calibrationBinding.calibrationDir ?? path15.join(resolveHomeDir(), ".remnic", "bench", "calibration")
6452
7187
  );
6453
7188
  const state = await benchModule.loadJudgeCalibrationState?.(benchmarkId, calibrationDir);
6454
7189
  if (!state) {
@@ -6522,7 +7257,7 @@ function attachPreparedJudgeCalibration(result, judgeCalibration) {
6522
7257
  function hashCalibrationProviderConfig(config) {
6523
7258
  const canonicalize = (value, key = "") => {
6524
7259
  if (typeof value === "string" && /(?:api.?key|authorization|token|secret)/i.test(key)) {
6525
- return { secretSha256: createHash2("sha256").update(value).digest("hex") };
7260
+ return { secretSha256: createHash3("sha256").update(value).digest("hex") };
6526
7261
  }
6527
7262
  if (Array.isArray(value)) return value.map((item) => canonicalize(item));
6528
7263
  if (value && typeof value === "object") {
@@ -6533,7 +7268,7 @@ function hashCalibrationProviderConfig(config) {
6533
7268
  }
6534
7269
  return value;
6535
7270
  };
6536
- return createHash2("sha256").update(JSON.stringify(canonicalize(config))).digest("hex");
7271
+ return createHash3("sha256").update(JSON.stringify(canonicalize(config))).digest("hex");
6537
7272
  }
6538
7273
  function restoreOptionalEnv(key, previousValue) {
6539
7274
  if (previousValue === void 0) {
@@ -6745,7 +7480,7 @@ function resolveBenchReproDatasetDir(datasetDir) {
6745
7480
  return void 0;
6746
7481
  }
6747
7482
  try {
6748
- return fs11.realpathSync(datasetDir);
7483
+ return fs12.realpathSync(datasetDir);
6749
7484
  } catch {
6750
7485
  return datasetDir;
6751
7486
  }
@@ -6798,23 +7533,23 @@ async function writeBenchReproManifestForPackageRun(args) {
6798
7533
  }
6799
7534
  }
6800
7535
  function resolveConfigPath(cliPath) {
6801
- if (cliPath) return path14.resolve(expandTilde(cliPath));
7536
+ if (cliPath) return path15.resolve(expandTilde(cliPath));
6802
7537
  const envPath = readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH");
6803
- if (envPath) return path14.resolve(expandTilde(envPath));
7538
+ if (envPath) return path15.resolve(expandTilde(envPath));
6804
7539
  const candidates = [
6805
- path14.join(process.cwd(), "remnic.config.json"),
6806
- path14.join(process.cwd(), "engram.config.json"),
6807
- path14.join(resolveHomeDir(), ".config", "remnic", "config.json"),
6808
- path14.join(resolveHomeDir(), ".config", "engram", "config.json")
7540
+ path15.join(process.cwd(), "remnic.config.json"),
7541
+ path15.join(process.cwd(), "engram.config.json"),
7542
+ path15.join(resolveHomeDir(), ".config", "remnic", "config.json"),
7543
+ path15.join(resolveHomeDir(), ".config", "engram", "config.json")
6809
7544
  ];
6810
7545
  for (const candidate of candidates) {
6811
- if (fs11.existsSync(candidate)) return candidate;
7546
+ if (fs12.existsSync(candidate)) return candidate;
6812
7547
  }
6813
- return path14.join(resolveHomeDir(), ".config", "remnic", "config.json");
7548
+ return path15.join(resolveHomeDir(), ".config", "remnic", "config.json");
6814
7549
  }
6815
7550
  function resolveExistingBenchRemnicConfigPath(cliPath) {
6816
7551
  const configPath = resolveConfigPath(cliPath);
6817
- if (fs11.existsSync(configPath)) {
7552
+ if (fs12.existsSync(configPath)) {
6818
7553
  return configPath;
6819
7554
  }
6820
7555
  if (cliPath) {
@@ -6824,7 +7559,7 @@ function resolveExistingBenchRemnicConfigPath(cliPath) {
6824
7559
  }
6825
7560
  function resolveExistingBenchOpenclawConfigPath(cliPath) {
6826
7561
  const configPath = resolveOpenclawConfigPath(cliPath);
6827
- if (fs11.existsSync(configPath)) {
7562
+ if (fs12.existsSync(configPath)) {
6828
7563
  return configPath;
6829
7564
  }
6830
7565
  if (cliPath) {
@@ -6924,34 +7659,34 @@ async function resolvePackageBenchRuntime(benchModule, parsed, runtimeProfile) {
6924
7659
  );
6925
7660
  }
6926
7661
  function normalizeMemoryDirPath(memoryDir) {
6927
- return path14.resolve(expandTilde(memoryDir));
7662
+ return path15.resolve(expandTilde(memoryDir));
6928
7663
  }
6929
7664
  function resolveMemoryDir() {
6930
7665
  const configMemoryDir = (() => {
6931
7666
  const envMemoryDir = readCompatEnv("REMNIC_MEMORY_DIR", "ENGRAM_MEMORY_DIR");
6932
7667
  if (envMemoryDir) return normalizeMemoryDirPath(envMemoryDir);
6933
7668
  const configPath = resolveConfigPath();
6934
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
7669
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
6935
7670
  const remnicCfg = resolveRemnicConfigRecord4(raw);
6936
7671
  if (typeof remnicCfg.memoryDir === "string" && remnicCfg.memoryDir.length > 0) {
6937
7672
  return normalizeMemoryDirPath(remnicCfg.memoryDir);
6938
7673
  }
6939
7674
  const home = resolveHomeDir();
6940
- const standalonePath = path14.join(home, ".remnic", "memory");
6941
- const legacyStandalonePath = path14.join(home, ".engram", "memory");
6942
- const openclawPath = path14.join(home, ".openclaw", "workspace", "memory", "local");
6943
- if (fs11.existsSync(standalonePath)) return standalonePath;
6944
- if (fs11.existsSync(legacyStandalonePath)) return legacyStandalonePath;
7675
+ const standalonePath = path15.join(home, ".remnic", "memory");
7676
+ const legacyStandalonePath = path15.join(home, ".engram", "memory");
7677
+ const openclawPath = path15.join(home, ".openclaw", "workspace", "memory", "local");
7678
+ if (fs12.existsSync(standalonePath)) return standalonePath;
7679
+ if (fs12.existsSync(legacyStandalonePath)) return legacyStandalonePath;
6945
7680
  return openclawPath;
6946
7681
  })();
6947
7682
  const manifestPath = getManifestPath();
6948
- if (fs11.existsSync(manifestPath)) {
7683
+ if (fs12.existsSync(manifestPath)) {
6949
7684
  try {
6950
7685
  const active = getActiveSpace();
6951
7686
  if (active?.memoryDir) {
6952
7687
  const activeMemoryDir = normalizeMemoryDirPath(active.memoryDir);
6953
- if (!fs11.existsSync(activeMemoryDir)) {
6954
- fs11.mkdirSync(activeMemoryDir, { recursive: true });
7688
+ if (!fs12.existsSync(activeMemoryDir)) {
7689
+ fs12.mkdirSync(activeMemoryDir, { recursive: true });
6955
7690
  }
6956
7691
  return activeMemoryDir;
6957
7692
  }
@@ -6990,20 +7725,20 @@ var REMNIC_OPENCLAW_LEGACY_PLUGIN_ID = "openclaw-engram";
6990
7725
  var DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR = [
6991
7726
  process.env.OPENCLAW_CONFIG_PATH,
6992
7727
  process.env.OPENCLAW_ENGRAM_CONFIG_PATH,
6993
- path14.join(resolveHomeDir(), ".openclaw", "openclaw.json")
7728
+ path15.join(resolveHomeDir(), ".openclaw", "openclaw.json")
6994
7729
  ].filter(Boolean);
6995
7730
  function resolveOpenclawConfigPath(cliPath) {
6996
- if (cliPath) return path14.resolve(expandTilde(cliPath));
7731
+ if (cliPath) return path15.resolve(expandTilde(cliPath));
6997
7732
  const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
6998
- if (envPath) return path14.resolve(expandTilde(envPath));
7733
+ if (envPath) return path15.resolve(expandTilde(envPath));
6999
7734
  for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
7000
- if (fs11.existsSync(candidate)) return candidate;
7735
+ if (fs12.existsSync(candidate)) return candidate;
7001
7736
  }
7002
- return path14.join(resolveHomeDir(), ".openclaw", "openclaw.json");
7737
+ return path15.join(resolveHomeDir(), ".openclaw", "openclaw.json");
7003
7738
  }
7004
7739
  function readOpenclawConfig(configPath) {
7005
- if (!fs11.existsSync(configPath)) return {};
7006
- const raw = fs11.readFileSync(configPath, "utf-8");
7740
+ if (!fs12.existsSync(configPath)) return {};
7741
+ const raw = fs12.readFileSync(configPath, "utf-8");
7007
7742
  let parsed;
7008
7743
  try {
7009
7744
  parsed = JSON.parse(raw);
@@ -7058,10 +7793,10 @@ function buildRemnicOpenclawHooksPolicy(legacyHooks, existingHooks) {
7058
7793
  function resolveOpenclawInstallMemoryDir(args) {
7059
7794
  const existingMemoryDir = (typeof args.existingNewEntryConfig.memoryDir === "string" ? args.existingNewEntryConfig.memoryDir : void 0) || (args.migrateLegacy && typeof args.legacyConfigToMerge.memoryDir === "string" ? args.legacyConfigToMerge.memoryDir : void 0);
7060
7795
  if (args.requestedMemoryDir) {
7061
- return path14.resolve(expandTilde(args.requestedMemoryDir));
7796
+ return path15.resolve(expandTilde(args.requestedMemoryDir));
7062
7797
  }
7063
7798
  if (existingMemoryDir) {
7064
- return path14.resolve(expandTilde(existingMemoryDir));
7799
+ return path15.resolve(expandTilde(existingMemoryDir));
7065
7800
  }
7066
7801
  return args.fallbackMemoryDir;
7067
7802
  }
@@ -7079,18 +7814,18 @@ function resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir) {
7079
7814
  if (!config || typeof config !== "object" || Array.isArray(config)) continue;
7080
7815
  const memoryDir = config.memoryDir;
7081
7816
  if (typeof memoryDir === "string" && memoryDir.trim().length > 0) {
7082
- return path14.resolve(expandTilde(memoryDir));
7817
+ return path15.resolve(expandTilde(memoryDir));
7083
7818
  }
7084
7819
  }
7085
7820
  return fallbackMemoryDir;
7086
7821
  }
7087
7822
  function resolveOpenclawPluginDir(cliPath) {
7088
- if (cliPath) return path14.resolve(expandTilde(cliPath));
7089
- return path14.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
7823
+ if (cliPath) return path15.resolve(expandTilde(cliPath));
7824
+ return path15.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
7090
7825
  }
7091
7826
  function resolveOpenclawLegacyPluginDir(cliPath) {
7092
- if (cliPath) return path14.resolve(expandTilde(cliPath));
7093
- return path14.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID);
7827
+ if (cliPath) return path15.resolve(expandTilde(cliPath));
7828
+ return path15.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID);
7094
7829
  }
7095
7830
  function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
7096
7831
  const yyyy = now.getFullYear().toString();
@@ -7102,14 +7837,14 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
7102
7837
  return `${yyyy}${mm}${dd}-${hh}${min}${ss}`;
7103
7838
  }
7104
7839
  function backupPathIfPresent(sourcePath, backupPath) {
7105
- if (!fs11.existsSync(sourcePath)) return false;
7106
- fs11.mkdirSync(path14.dirname(backupPath), { recursive: true });
7107
- fs11.cpSync(sourcePath, backupPath, { recursive: true });
7840
+ if (!fs12.existsSync(sourcePath)) return false;
7841
+ fs12.mkdirSync(path15.dirname(backupPath), { recursive: true });
7842
+ fs12.cpSync(sourcePath, backupPath, { recursive: true });
7108
7843
  return true;
7109
7844
  }
7110
7845
  function assertDirectoryPathOrMissing(targetPath, label) {
7111
- if (!fs11.existsSync(targetPath)) return;
7112
- const stat = fs11.statSync(targetPath);
7846
+ if (!fs12.existsSync(targetPath)) return;
7847
+ const stat = fs12.statSync(targetPath);
7113
7848
  if (!stat.isDirectory()) {
7114
7849
  throw new Error(`${label} must be a directory when it already exists: ${targetPath}`);
7115
7850
  }
@@ -7134,7 +7869,7 @@ var PublishedOpenclawPluginInstallError = class extends Error {
7134
7869
  }
7135
7870
  };
7136
7871
  function installPublishedOpenclawPlugin(spec, pluginDir) {
7137
- const tempRoot = fs11.mkdtempSync(path14.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
7872
+ const tempRoot = fs12.mkdtempSync(path15.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
7138
7873
  const stagedDir = `${pluginDir}.next-${process.pid}-${Date.now()}`;
7139
7874
  const rollbackDir = `${pluginDir}.rollback-${process.pid}-${Date.now()}`;
7140
7875
  let swapRollbackDir;
@@ -7149,17 +7884,17 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
7149
7884
  if (!tarballName) {
7150
7885
  throw new Error(`npm pack ${spec} did not return a tarball name`);
7151
7886
  }
7152
- const unpackDir = path14.join(tempRoot, "unpacked");
7153
- fs11.mkdirSync(unpackDir, { recursive: true });
7154
- childProcess2.execFileSync("tar", ["-xzf", path14.join(tempRoot, tarballName), "-C", unpackDir], {
7887
+ const unpackDir = path15.join(tempRoot, "unpacked");
7888
+ fs12.mkdirSync(unpackDir, { recursive: true });
7889
+ childProcess2.execFileSync("tar", ["-xzf", path15.join(tempRoot, tarballName), "-C", unpackDir], {
7155
7890
  stdio: ["ignore", "pipe", "pipe"]
7156
7891
  });
7157
- const packagedDir = path14.join(unpackDir, "package");
7158
- if (!fs11.existsSync(packagedDir)) {
7892
+ const packagedDir = path15.join(unpackDir, "package");
7893
+ if (!fs12.existsSync(packagedDir)) {
7159
7894
  throw new Error(`npm pack ${spec} did not contain a package/ directory`);
7160
7895
  }
7161
- fs11.rmSync(stagedDir, { recursive: true, force: true });
7162
- fs11.cpSync(packagedDir, stagedDir, { recursive: true });
7896
+ fs12.rmSync(stagedDir, { recursive: true, force: true });
7897
+ fs12.cpSync(packagedDir, stagedDir, { recursive: true });
7163
7898
  childProcess2.execFileSync("npm", ["install", "--omit=dev"], {
7164
7899
  cwd: stagedDir,
7165
7900
  stdio: ["ignore", "pipe", "pipe"]
@@ -7174,8 +7909,8 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
7174
7909
  }
7175
7910
  })();
7176
7911
  swapRollbackDir = swapResult.rollbackDir;
7177
- const installedPackageJsonPath = path14.join(pluginDir, "package.json");
7178
- const installedPackage = fs11.existsSync(installedPackageJsonPath) ? JSON.parse(fs11.readFileSync(installedPackageJsonPath, "utf8")) : {};
7912
+ const installedPackageJsonPath = path15.join(pluginDir, "package.json");
7913
+ const installedPackage = fs12.existsSync(installedPackageJsonPath) ? JSON.parse(fs12.readFileSync(installedPackageJsonPath, "utf8")) : {};
7179
7914
  return {
7180
7915
  rollbackDir: swapRollbackDir,
7181
7916
  version: typeof installedPackage.version === "string" ? installedPackage.version : void 0
@@ -7190,8 +7925,8 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
7190
7925
  }
7191
7926
  );
7192
7927
  } finally {
7193
- fs11.rmSync(stagedDir, { recursive: true, force: true });
7194
- fs11.rmSync(tempRoot, { recursive: true, force: true });
7928
+ fs12.rmSync(stagedDir, { recursive: true, force: true });
7929
+ fs12.rmSync(tempRoot, { recursive: true, force: true });
7195
7930
  }
7196
7931
  }
7197
7932
  function restartOpenclawGateway() {
@@ -7209,15 +7944,15 @@ function restartOpenclawGateway() {
7209
7944
  });
7210
7945
  }
7211
7946
  function cmdInit() {
7212
- const configPath = path14.join(process.cwd(), "remnic.config.json");
7213
- if (fs11.existsSync(configPath)) {
7947
+ const configPath = path15.join(process.cwd(), "remnic.config.json");
7948
+ if (fs12.existsSync(configPath)) {
7214
7949
  console.log(`Config already exists: ${configPath}`);
7215
7950
  return;
7216
7951
  }
7217
7952
  const template = {
7218
7953
  remnic: {
7219
7954
  openaiApiKey: "${OPENAI_API_KEY}",
7220
- memoryDir: path14.join(process.cwd(), ".remnic", "memory"),
7955
+ memoryDir: path15.join(process.cwd(), ".remnic", "memory"),
7221
7956
  memoryOsPreset: "balanced"
7222
7957
  },
7223
7958
  server: {
@@ -7226,7 +7961,7 @@ function cmdInit() {
7226
7961
  authToken: "${REMNIC_AUTH_TOKEN}"
7227
7962
  }
7228
7963
  };
7229
- fs11.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
7964
+ fs12.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
7230
7965
  console.log(`Created ${configPath}`);
7231
7966
  console.log("\nSet these environment variables:");
7232
7967
  console.log(" export OPENAI_API_KEY=sk-...");
@@ -7296,7 +8031,7 @@ async function cmdStatus(json) {
7296
8031
  }
7297
8032
  function oauthReadConfigRecord(configPath) {
7298
8033
  try {
7299
- const parsed = JSON.parse(fs11.readFileSync(configPath, "utf8"));
8034
+ const parsed = JSON.parse(fs12.readFileSync(configPath, "utf8"));
7300
8035
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
7301
8036
  return parsed;
7302
8037
  }
@@ -7354,7 +8089,7 @@ function oauthResolveOperatorToken() {
7354
8089
  }
7355
8090
  return void 0;
7356
8091
  }
7357
- async function oauthFetch(method, path15, token, body) {
8092
+ async function oauthFetch(method, path16, token, body) {
7358
8093
  const controller = new AbortController();
7359
8094
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
7360
8095
  try {
@@ -7373,7 +8108,7 @@ async function oauthFetch(method, path15, token, body) {
7373
8108
  if (body !== void 0) {
7374
8109
  init.body = JSON.stringify(body);
7375
8110
  }
7376
- const response = await fetch(`${oauthResolveBaseUrl()}${path15}`, init);
8111
+ const response = await fetch(`${oauthResolveBaseUrl()}${path16}`, init);
7377
8112
  if (response.status === 401) {
7378
8113
  throw new Error(
7379
8114
  "operator token rejected by remnic-server (HTTP 401). Update `server.authToken` or `REMNIC_AUTH_TOKEN` to match the running daemon."
@@ -7712,9 +8447,9 @@ async function cmdQuery(queryText, json, explain) {
7712
8447
  }
7713
8448
  initLogger2();
7714
8449
  const configPath = resolveConfigPath();
7715
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
8450
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
7716
8451
  const remnicCfg = resolveRemnicConfigRecord4(raw);
7717
- const config = parseConfig4(remnicCfg);
8452
+ const config = parseConfig5(remnicCfg);
7718
8453
  const orchestrator = new Orchestrator3(config);
7719
8454
  await orchestrator.initialize();
7720
8455
  const service = new EngramAccessService2(orchestrator);
@@ -7883,9 +8618,9 @@ async function cmdXray(rest) {
7883
8618
  parseXrayCliOptions(rawQuery, options);
7884
8619
  initLogger2();
7885
8620
  const configPath = resolveConfigPath();
7886
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
8621
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
7887
8622
  const remnicCfg = resolveRemnicConfigRecord4(raw);
7888
- const config = parseConfig4(remnicCfg);
8623
+ const config = parseConfig5(remnicCfg);
7889
8624
  const orchestrator = new Orchestrator3(config);
7890
8625
  await orchestrator.initialize();
7891
8626
  await orchestrator.deferredReady;
@@ -7906,9 +8641,9 @@ async function cmdXray(rest) {
7906
8641
  async function cmdVersions(rest) {
7907
8642
  initLogger2();
7908
8643
  const configPath = resolveConfigPath();
7909
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
8644
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
7910
8645
  const remnicCfg = resolveRemnicConfigRecord4(raw);
7911
- const config = parseConfig4(remnicCfg);
8646
+ const config = parseConfig5(remnicCfg);
7912
8647
  if (!config.versioningEnabled) {
7913
8648
  console.error("Page versioning is disabled (versioningEnabled = false).");
7914
8649
  process.exit(1);
@@ -7928,7 +8663,7 @@ async function cmdVersions(rest) {
7928
8663
  console.error("Usage: remnic versions list <page-path>");
7929
8664
  process.exit(1);
7930
8665
  }
7931
- const absPath = path14.resolve(pagePath);
8666
+ const absPath = path15.resolve(pagePath);
7932
8667
  const history = await listVersions(absPath, versioningConfig, memDir);
7933
8668
  if (json) {
7934
8669
  console.log(JSON.stringify(history, null, 2));
@@ -7953,7 +8688,7 @@ async function cmdVersions(rest) {
7953
8688
  console.error("Usage: remnic versions show <page-path> <version-id>");
7954
8689
  process.exit(1);
7955
8690
  }
7956
- const absPath = path14.resolve(pagePath);
8691
+ const absPath = path15.resolve(pagePath);
7957
8692
  try {
7958
8693
  const content = await getVersion(absPath, versionId, versioningConfig, memDir);
7959
8694
  console.log(content);
@@ -7971,7 +8706,7 @@ async function cmdVersions(rest) {
7971
8706
  console.error("Usage: remnic versions diff <page-path> <v1> <v2>");
7972
8707
  process.exit(1);
7973
8708
  }
7974
- const absPath = path14.resolve(pagePath);
8709
+ const absPath = path15.resolve(pagePath);
7975
8710
  try {
7976
8711
  const diffOutput = await diffVersions(absPath, v1, v2, versioningConfig, memDir);
7977
8712
  console.log(diffOutput);
@@ -7988,7 +8723,7 @@ async function cmdVersions(rest) {
7988
8723
  console.error("Usage: remnic versions revert <page-path> <version-id>");
7989
8724
  process.exit(1);
7990
8725
  }
7991
- const absPath = path14.resolve(pagePath);
8726
+ const absPath = path15.resolve(pagePath);
7992
8727
  try {
7993
8728
  const version = await revertToVersion(absPath, versionId, versioningConfig, void 0, memDir);
7994
8729
  if (json) {
@@ -8022,13 +8757,13 @@ Options:
8022
8757
  async function cmdEnrich(rest) {
8023
8758
  initLogger2();
8024
8759
  const configPath = resolveConfigPath();
8025
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
8760
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
8026
8761
  const remnicCfg = resolveRemnicConfigRecord4(raw);
8027
- const config = parseConfig4(remnicCfg);
8762
+ const config = parseConfig5(remnicCfg);
8028
8763
  const subcommand = rest[0];
8029
8764
  if (subcommand === "audit") {
8030
8765
  const memoryDir2 = expandTilde(config.memoryDir);
8031
- const auditDir2 = path14.join(memoryDir2, "enrichment");
8766
+ const auditDir2 = path15.join(memoryDir2, "enrichment");
8032
8767
  const sinceFlag = resolveFlag(rest.slice(1), "--since");
8033
8768
  const entries = await readAuditLog(auditDir2, sinceFlag ?? void 0);
8034
8769
  if (entries.length === 0) {
@@ -8153,7 +8888,7 @@ Registered providers:`);
8153
8888
  return;
8154
8889
  }
8155
8890
  const memoryDir = expandTilde(config.memoryDir);
8156
- const auditDir = path14.join(memoryDir, "enrichment");
8891
+ const auditDir = path15.join(memoryDir, "enrichment");
8157
8892
  let totalPersisted = 0;
8158
8893
  for (const result of results) {
8159
8894
  for (const candidate of result.acceptedCandidates) {
@@ -8267,9 +9002,9 @@ Shared with:
8267
9002
  process.exit(1);
8268
9003
  }
8269
9004
  const configPath = resolveConfigPath();
8270
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
9005
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
8271
9006
  const remnicCfg = resolveRemnicConfigRecord4(raw);
8272
- const config = parseConfig4(remnicCfg);
9007
+ const config = parseConfig5(remnicCfg);
8273
9008
  const memoryDir = expandTilde(
8274
9009
  typeof memoryDirOverride === "string" && memoryDirOverride.length > 0 ? memoryDirOverride : config.memoryDir ?? resolveMemoryDir()
8275
9010
  );
@@ -8284,9 +9019,9 @@ Shared with:
8284
9019
  async function cmdExtensions(action, rest) {
8285
9020
  initLogger2();
8286
9021
  const configPath = resolveConfigPath();
8287
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
9022
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
8288
9023
  const remnicCfg = resolveRemnicConfigRecord4(raw);
8289
- const config = parseConfig4(remnicCfg);
9024
+ const config = parseConfig5(remnicCfg);
8290
9025
  const root = resolveExtensionsRoot(config);
8291
9026
  const noopLog = { warn: () => {
8292
9027
  }, debug: () => {
@@ -8335,7 +9070,7 @@ Root: ${root}`);
8335
9070
  const extensions = await discoverMemoryExtensions(root, warnLog);
8336
9071
  let entries = [];
8337
9072
  try {
8338
- entries = fs11.readdirSync(root);
9073
+ entries = fs12.readdirSync(root);
8339
9074
  } catch {
8340
9075
  console.log(`Extensions root does not exist: ${root}`);
8341
9076
  process.exitCode = 0;
@@ -8344,9 +9079,9 @@ Root: ${root}`);
8344
9079
  const validNames = new Set(extensions.map((e) => e.name));
8345
9080
  let errors = 0;
8346
9081
  for (const entry of entries) {
8347
- const entryPath = path14.join(root, entry);
9082
+ const entryPath = path15.join(root, entry);
8348
9083
  try {
8349
- if (!fs11.statSync(entryPath).isDirectory()) continue;
9084
+ if (!fs12.statSync(entryPath).isDirectory()) continue;
8350
9085
  } catch {
8351
9086
  continue;
8352
9087
  }
@@ -8378,9 +9113,9 @@ Root: ${root}`);
8378
9113
  async function cmdBriefing(rest) {
8379
9114
  initLogger2();
8380
9115
  const configPath = resolveConfigPath();
8381
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
9116
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
8382
9117
  const remnicCfg = resolveRemnicConfigRecord4(raw);
8383
- const config = parseConfig4(remnicCfg);
9118
+ const config = parseConfig5(remnicCfg);
8384
9119
  if (!config.briefing.enabled) {
8385
9120
  console.error("Briefing is disabled in config (briefing.enabled = false).");
8386
9121
  process.exit(1);
@@ -8458,10 +9193,10 @@ async function cmdBriefing(rest) {
8458
9193
  if (save) {
8459
9194
  try {
8460
9195
  const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
8461
- fs11.mkdirSync(saveDir, { recursive: true });
9196
+ fs12.mkdirSync(saveDir, { recursive: true });
8462
9197
  const filename = briefingFilename(new Date(result.window.to), format);
8463
- const filePath = path14.join(saveDir, filename);
8464
- fs11.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
9198
+ const filePath = path15.join(saveDir, filename);
9199
+ fs12.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
8465
9200
  console.error(`Saved briefing: ${filePath}`);
8466
9201
  } catch (err) {
8467
9202
  console.error(`Failed to save briefing: ${err instanceof Error ? err.message : String(err)}`);
@@ -8479,7 +9214,7 @@ async function cmdDoctor() {
8479
9214
  detail: `${nodeVersion} (requires >= 22.12.0)`
8480
9215
  });
8481
9216
  const configPath = resolveConfigPath();
8482
- const configExists = fs11.existsSync(configPath);
9217
+ const configExists = fs12.existsSync(configPath);
8483
9218
  checks.push({ name: "Config file", ok: configExists, detail: configPath });
8484
9219
  let standaloneConfig;
8485
9220
  let standaloneConfigError;
@@ -8487,11 +9222,11 @@ async function cmdDoctor() {
8487
9222
  let configuredNs = { invalid: false };
8488
9223
  if (configExists) {
8489
9224
  try {
8490
- const raw = JSON.parse(fs11.readFileSync(configPath, "utf8"));
9225
+ const raw = JSON.parse(fs12.readFileSync(configPath, "utf8"));
8491
9226
  const remnicCfg = resolveRemnicConfigRecord4(raw);
8492
9227
  standaloneOpenaiApiKeyExplicitlyFalse = isOpenaiApiKeyDisabled(remnicCfg.openaiApiKey);
8493
9228
  configuredNs = readConfiguredNamespace(remnicCfg);
8494
- standaloneConfig = parseConfig4(remnicCfg);
9229
+ standaloneConfig = parseConfig5(remnicCfg);
8495
9230
  } catch (err) {
8496
9231
  standaloneConfigError = err instanceof Error ? err.message : String(err);
8497
9232
  }
@@ -8500,10 +9235,10 @@ async function cmdDoctor() {
8500
9235
  try {
8501
9236
  memoryDir = resolveMemoryDir();
8502
9237
  } catch {
8503
- memoryDir = parseConfig4({}).memoryDir;
9238
+ memoryDir = parseConfig5({}).memoryDir;
8504
9239
  }
8505
9240
  try {
8506
- fs11.mkdirSync(memoryDir, { recursive: true });
9241
+ fs12.mkdirSync(memoryDir, { recursive: true });
8507
9242
  checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
8508
9243
  } catch {
8509
9244
  checks.push({ name: "Memory directory", ok: false, detail: `cannot create ${memoryDir}` });
@@ -8532,7 +9267,7 @@ async function cmdDoctor() {
8532
9267
  });
8533
9268
  if (nsPolicyCheck) checks.push(nsPolicyCheck);
8534
9269
  const openclawConfigPath = resolveOpenclawConfigPath();
8535
- const openclawConfigExists = fs11.existsSync(openclawConfigPath);
9270
+ const openclawConfigExists = fs12.existsSync(openclawConfigPath);
8536
9271
  let openclawConfig = {};
8537
9272
  let openclawConfigValid = false;
8538
9273
  let openclawPluginModeConfigured = false;
@@ -8540,7 +9275,7 @@ async function cmdDoctor() {
8540
9275
  let activeOpenclawEntryConfig = null;
8541
9276
  if (openclawConfigExists) {
8542
9277
  try {
8543
- const parsed = JSON.parse(fs11.readFileSync(openclawConfigPath, "utf-8"));
9278
+ const parsed = JSON.parse(fs12.readFileSync(openclawConfigPath, "utf-8"));
8544
9279
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
8545
9280
  openclawConfig = parsed;
8546
9281
  openclawConfigValid = true;
@@ -8616,13 +9351,13 @@ async function cmdDoctor() {
8616
9351
  const rawMemoryDir = entryConfig?.memoryDir;
8617
9352
  const configuredMemoryDir = typeof rawMemoryDir === "string" ? rawMemoryDir : void 0;
8618
9353
  if (configuredMemoryDir) {
8619
- const resolvedMemDir = path14.resolve(expandTilde(configuredMemoryDir));
9354
+ const resolvedMemDir = path15.resolve(expandTilde(configuredMemoryDir));
8620
9355
  let memDirOk = false;
8621
9356
  let memDirDetail = `${resolvedMemDir} (not found)`;
8622
9357
  let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
8623
- if (fs11.existsSync(resolvedMemDir)) {
9358
+ if (fs12.existsSync(resolvedMemDir)) {
8624
9359
  try {
8625
- const stat = fs11.statSync(resolvedMemDir);
9360
+ const stat = fs12.statSync(resolvedMemDir);
8626
9361
  if (stat.isDirectory()) {
8627
9362
  memDirOk = true;
8628
9363
  memDirDetail = resolvedMemDir;
@@ -8764,12 +9499,12 @@ async function cmdDoctor() {
8764
9499
  }
8765
9500
  function cmdConfig() {
8766
9501
  const configPath = resolveConfigPath();
8767
- if (!fs11.existsSync(configPath)) {
9502
+ if (!fs12.existsSync(configPath)) {
8768
9503
  console.log("No config file found. Run `remnic init` to create one.");
8769
9504
  return;
8770
9505
  }
8771
9506
  console.log(`Config: ${configPath}`);
8772
- const rawConfig = fs11.readFileSync(configPath, "utf8");
9507
+ const rawConfig = fs12.readFileSync(configPath, "utf8");
8773
9508
  const redacted = rawConfig.replace(
8774
9509
  /("(?:openaiApiKey|localLlmApiKey|authToken|apiKey|remoteSearchApiKey|meilisearchApiKey|opikApiKey)"\s*:\s*")([^"]*)(")/g,
8775
9510
  "$1[REDACTED]$3"
@@ -8816,7 +9551,7 @@ async function cmdMigrate(json, rollback) {
8816
9551
  console.log(` Rollback: ${result.rollbackCommand}`);
8817
9552
  }
8818
9553
  function cmdOnboard(dirPath, json) {
8819
- const directory = path14.resolve(dirPath || process.cwd());
9554
+ const directory = path15.resolve(dirPath || process.cwd());
8820
9555
  const result = onboard({ directory });
8821
9556
  if (json) {
8822
9557
  console.log(JSON.stringify(result, null, 2));
@@ -8835,7 +9570,7 @@ Suggested namespace: ${result.plan.suggestedNamespace}`);
8835
9570
  async function cmdCurate(targetPath, json) {
8836
9571
  const memoryDir = resolveMemoryDir();
8837
9572
  const result = await curate({
8838
- targetPath: path14.resolve(targetPath),
9573
+ targetPath: path15.resolve(targetPath),
8839
9574
  memoryDir,
8840
9575
  source: "curation",
8841
9576
  checkDuplicates: true,
@@ -8877,9 +9612,9 @@ async function cmdReview(action, rest) {
8877
9612
  const configPath = resolveConfigPath();
8878
9613
  let tombstonesConfig = null;
8879
9614
  try {
8880
- const rawCfg = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
9615
+ const rawCfg = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
8881
9616
  const remnicCfg = resolveRemnicConfigRecord4(rawCfg);
8882
- const config = parseConfig4(remnicCfg);
9617
+ const config = parseConfig5(remnicCfg);
8883
9618
  tombstonesConfig = {
8884
9619
  enabled: config.tombstonesEnabled,
8885
9620
  semanticMatch: config.tombstonesSemanticMatch,
@@ -8965,7 +9700,7 @@ async function cmdSync(action, rest, json) {
8965
9700
  }
8966
9701
  function localOfflineSourceId(memoryDir) {
8967
9702
  const host = os.hostname() || "unknown-host";
8968
- const dirHash = createHash2("sha256").update(path14.resolve(memoryDir)).digest("hex").slice(0, 16);
9703
+ const dirHash = createHash3("sha256").update(path15.resolve(memoryDir)).digest("hex").slice(0, 16);
8969
9704
  return `remnic-local:${host}:${dirHash}`;
8970
9705
  }
8971
9706
  function normalizeOfflineRemoteUrl(raw) {
@@ -9363,10 +10098,10 @@ var OFFLINE_SYNC_CONTENT_MISSING_RETRY_MAX = 3;
9363
10098
  var OFFLINE_SYNC_CONTENT_MISSING_RETRY_DELAY_MS = 250;
9364
10099
  var OfflineRemoteFileChangedError = class extends Error {
9365
10100
  path;
9366
- constructor(path15) {
9367
- super(`remote file changed while fetching offline content: ${path15}`);
10101
+ constructor(path16) {
10102
+ super(`remote file changed while fetching offline content: ${path16}`);
9368
10103
  this.name = "OfflineRemoteFileChangedError";
9369
- this.path = path15;
10104
+ this.path = path16;
9370
10105
  }
9371
10106
  };
9372
10107
  function isOfflineRemoteFileChangedError(error) {
@@ -9557,15 +10292,15 @@ function offlineDirectPushFiles(options) {
9557
10292
  }).sort((left, right) => right.bytes - left.bytes || left.path.localeCompare(right.path));
9558
10293
  }
9559
10294
  function resolveOfflineDirectHydrationPath(memoryDir, relPath) {
9560
- const base = path14.resolve(memoryDir);
9561
- const target = path14.resolve(base, relPath);
9562
- const relative = path14.relative(base, target);
9563
- if (relative === "" || relative === ".." || relative.startsWith(`..${path14.sep}`) || path14.isAbsolute(relative)) {
10295
+ const base = path15.resolve(memoryDir);
10296
+ const target = path15.resolve(base, relPath);
10297
+ const relative = path15.relative(base, target);
10298
+ if (relative === "" || relative === ".." || relative.startsWith(`..${path15.sep}`) || path15.isAbsolute(relative)) {
9564
10299
  throw new Error(`offline sync direct hydration path escapes memory dir: ${relPath}`);
9565
10300
  }
9566
10301
  return target;
9567
10302
  }
9568
- var OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES = OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2;
10303
+ var OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES = OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES3;
9569
10304
  async function pushOfflineFileContent(args) {
9570
10305
  if (args.readFileChunks) {
9571
10306
  return pushOfflineFileContentFromChunkReader(args);
@@ -9573,7 +10308,7 @@ async function pushOfflineFileContent(args) {
9573
10308
  let offset = 0;
9574
10309
  let finalResult = null;
9575
10310
  let remoteSatisfiedResult = null;
9576
- const hash = createHash2("sha256");
10311
+ const hash = createHash3("sha256");
9577
10312
  let bytes = 0;
9578
10313
  while (offset < args.file.bytes || args.file.bytes === 0 && offset === 0) {
9579
10314
  const chunk = await readOfflineSyncFileContentChunk({
@@ -9630,13 +10365,13 @@ async function pushOfflineFileContent(args) {
9630
10365
  }
9631
10366
  async function pushOfflineFileContentFromChunkReader(args) {
9632
10367
  const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
9633
- const stat = fs11.statSync(filePath);
10368
+ const stat = fs12.statSync(filePath);
9634
10369
  if (stat.mtimeMs !== args.file.mtimeMs) {
9635
10370
  throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
9636
10371
  }
9637
- const hash = createHash2("sha256");
10372
+ const hash = createHash3("sha256");
9638
10373
  const chunks = args.readFileChunks({
9639
- root: path14.resolve(args.memoryDir),
10374
+ root: path15.resolve(args.memoryDir),
9640
10375
  path: args.file.path,
9641
10376
  filePath,
9642
10377
  chunkSize: OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES
@@ -9648,7 +10383,7 @@ async function pushOfflineFileContentFromChunkReader(args) {
9648
10383
  for await (const rawChunk of chunks) {
9649
10384
  const chunk = Buffer.from(rawChunk);
9650
10385
  if (chunk.length === 0) continue;
9651
- if (chunk.length > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {
10386
+ if (chunk.length > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES2) {
9652
10387
  throw new Error(`local offline content chunk exceeds max size: ${args.file.path}`);
9653
10388
  }
9654
10389
  if (pending) {
@@ -9733,7 +10468,7 @@ async function hydrateOfflineFileContent(args) {
9733
10468
  path: args.expected.path,
9734
10469
  offset,
9735
10470
  length: Math.min(
9736
- OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
10471
+ OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES2,
9737
10472
  Math.max(1, args.expected.bytes - offset)
9738
10473
  )
9739
10474
  });
@@ -9744,7 +10479,7 @@ async function hydrateOfflineFileContent(args) {
9744
10479
  throw new Error(`remote offline content chunk was empty before EOF: ${args.expected.path}`);
9745
10480
  }
9746
10481
  try {
9747
- finalResult = await applyOfflineSyncFileContentChunk({
10482
+ finalResult = await applyOfflineSyncFileContentChunk2({
9748
10483
  root: args.memoryDir,
9749
10484
  sourceId: args.sourceId,
9750
10485
  path: args.expected.path,
@@ -10121,7 +10856,7 @@ function advanceOfflineBaseFilesForSuccessfulPush(options) {
10121
10856
  return [...next.values()].sort((left, right) => left.path.localeCompare(right.path));
10122
10857
  }
10123
10858
  async function runOfflineSyncOnce(options) {
10124
- fs11.mkdirSync(options.memoryDir, { recursive: true });
10859
+ fs12.mkdirSync(options.memoryDir, { recursive: true });
10125
10860
  let activeStatePath = options.statePath;
10126
10861
  let priorState = await readOfflineSyncState(activeStatePath);
10127
10862
  let syncNamespace = options.namespace ?? priorState?.namespace;
@@ -10175,7 +10910,7 @@ async function runOfflineSyncOnce(options) {
10175
10910
  options.secureStoreEncryptOnWrite ?? true
10176
10911
  )).drainPendingMemoryLifecycleEventsForSyncAt(ledgerPath)
10177
10912
  );
10178
- const currentSnapshotForPush = await buildOfflineSyncSnapshotFromBase({
10913
+ const currentSnapshotForPush = await buildOfflineSyncSnapshotFromBase2({
10179
10914
  root: options.memoryDir,
10180
10915
  sourceId: localSourceId,
10181
10916
  baseFiles,
@@ -10324,7 +11059,7 @@ async function runOfflineSyncOnce(options) {
10324
11059
  if (pushed) return writePartialPushState(error);
10325
11060
  throw error;
10326
11061
  }
10327
- let currentSnapshotForChangeset = directPushedPaths.size > 0 ? await buildOfflineSyncSnapshotFromBase({
11062
+ let currentSnapshotForChangeset = directPushedPaths.size > 0 ? await buildOfflineSyncSnapshotFromBase2({
10328
11063
  root: options.memoryDir,
10329
11064
  sourceId: localSourceId,
10330
11065
  baseFiles,
@@ -10377,7 +11112,7 @@ async function runOfflineSyncOnce(options) {
10377
11112
  }
10378
11113
  changesetRetryCount += 1;
10379
11114
  directPushDeferredPaths.add(changedPath);
10380
- currentSnapshotForChangeset = await buildOfflineSyncSnapshotFromBase({
11115
+ currentSnapshotForChangeset = await buildOfflineSyncSnapshotFromBase2({
10381
11116
  root: options.memoryDir,
10382
11117
  sourceId: localSourceId,
10383
11118
  baseFiles,
@@ -10432,7 +11167,7 @@ async function runOfflineSyncOnce(options) {
10432
11167
  }
10433
11168
  let currentSnapshot;
10434
11169
  try {
10435
- currentSnapshot = await buildOfflineSyncSnapshotFromBase({
11170
+ currentSnapshot = await buildOfflineSyncSnapshotFromBase2({
10436
11171
  root: options.memoryDir,
10437
11172
  sourceId: localSourceId,
10438
11173
  baseFiles,
@@ -10495,7 +11230,7 @@ async function runOfflineSyncOnce(options) {
10495
11230
  resolvedNamespace: resolvedOfflineSnapshotNamespace(remoteSnapshotMetadata, syncNamespace),
10496
11231
  remoteFileCount: remoteSnapshotMetadata.files.length
10497
11232
  };
10498
- const buildCurrentSnapshotForApply = async () => buildOfflineSyncSnapshotFromBase({
11233
+ const buildCurrentSnapshotForApply = async () => buildOfflineSyncSnapshotFromBase2({
10499
11234
  root: options.memoryDir,
10500
11235
  sourceId: localSourceId,
10501
11236
  baseFiles,
@@ -10739,7 +11474,7 @@ Environment fallbacks:
10739
11474
  REMNIC_OFFLINE_REMOTE_URL, REMNIC_OFFLINE_TOKEN, REMNIC_AUTH_TOKEN`);
10740
11475
  return;
10741
11476
  }
10742
- const memoryDir = path14.resolve(expandTilde(resolveRequiredValueFlag(rest, "--memory-dir") ?? resolveMemoryDir()));
11477
+ const memoryDir = path15.resolve(expandTilde(resolveRequiredValueFlag(rest, "--memory-dir") ?? resolveMemoryDir()));
10743
11478
  const namespace = resolveRequiredValueFlag(rest, "--namespace");
10744
11479
  const includeTranscripts = !hasFlag(rest, "--no-transcripts");
10745
11480
  const stateOverride = resolveRequiredValueFlag(rest, "--state");
@@ -10747,7 +11482,7 @@ Environment fallbacks:
10747
11482
  const configPath = resolveConfigPath();
10748
11483
  let config;
10749
11484
  try {
10750
- const rawConfig = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
11485
+ const rawConfig = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
10751
11486
  config = parseConfigQuietly(pickOfflineConfigRecord(rawConfig));
10752
11487
  } catch {
10753
11488
  throw new Error(
@@ -10759,10 +11494,10 @@ Environment fallbacks:
10759
11494
  const needsRemote = action === "prepare" || action === "sync" || action === "watch";
10760
11495
  const remoteUrl = needsRemote ? resolveOfflineRemoteUrl(rest) : resolveOptionalOfflineRemoteUrl(rest);
10761
11496
  const token = needsRemote ? resolveOfflineToken(rest) : void 0;
10762
- const statePath = statePathExplicit ? path14.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
11497
+ const statePath = statePathExplicit ? path15.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
10763
11498
  if (action === "prepare") {
10764
11499
  if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
10765
- fs11.mkdirSync(memoryDir, { recursive: true });
11500
+ fs12.mkdirSync(memoryDir, { recursive: true });
10766
11501
  const remoteSnapshot = await fetchOfflineSnapshot({
10767
11502
  remoteUrl,
10768
11503
  token,
@@ -10860,7 +11595,7 @@ Environment fallbacks:
10860
11595
  return;
10861
11596
  }
10862
11597
  if (action === "status") {
10863
- fs11.mkdirSync(memoryDir, { recursive: true });
11598
+ fs12.mkdirSync(memoryDir, { recursive: true });
10864
11599
  const state = statePath ? await readOfflineSyncState(statePath) : null;
10865
11600
  if (state && remoteUrl && statePath) {
10866
11601
  assertOfflineStateMatches({
@@ -10940,11 +11675,11 @@ Environment fallbacks:
10940
11675
  failures: result.largeFilePushFailures
10941
11676
  });
10942
11677
  largeFileFailureCounts = advanced.counts;
10943
- for (const path15 of advanced.newlySkipped) {
10944
- if (skippedLargeFiles.has(path15)) continue;
10945
- skippedLargeFiles.add(path15);
11678
+ for (const path16 of advanced.newlySkipped) {
11679
+ if (skippedLargeFiles.has(path16)) continue;
11680
+ skippedLargeFiles.add(path16);
10946
11681
  console.warn(
10947
- `offline sync: permanently skipping ${path15} 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)`
11682
+ `offline sync: permanently skipping ${path16} 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)`
10948
11683
  );
10949
11684
  }
10950
11685
  const pulled = result.pull ? result.pull.upserted + result.pull.deleted : 0;
@@ -10959,11 +11694,11 @@ Environment fallbacks:
10959
11694
  failures: error.failures
10960
11695
  });
10961
11696
  largeFileFailureCounts = advanced.counts;
10962
- for (const path15 of advanced.newlySkipped) {
10963
- if (skippedLargeFiles.has(path15)) continue;
10964
- skippedLargeFiles.add(path15);
11697
+ for (const path16 of advanced.newlySkipped) {
11698
+ if (skippedLargeFiles.has(path16)) continue;
11699
+ skippedLargeFiles.add(path16);
10965
11700
  console.warn(
10966
- `offline sync: permanently skipping ${path15} 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)`
11701
+ `offline sync: permanently skipping ${path16} 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)`
10967
11702
  );
10968
11703
  }
10969
11704
  }
@@ -10998,7 +11733,7 @@ function cmdDedup(json) {
10998
11733
  function readInstalledConnectorConfig(configPath, fallback) {
10999
11734
  if (!configPath) return fallback;
11000
11735
  try {
11001
- const parsed = JSON.parse(fs11.readFileSync(configPath, "utf8"));
11736
+ const parsed = JSON.parse(fs12.readFileSync(configPath, "utf8"));
11002
11737
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fallback;
11003
11738
  const { token: _token, ...config } = parsed;
11004
11739
  return config;
@@ -11104,7 +11839,7 @@ async function cmdConnectors(action, rest, json) {
11104
11839
  const connectorDaemonUrl = typeof effectiveConnectorConfig.remnicDaemonUrl === "string" && effectiveConnectorConfig.remnicDaemonUrl.trim().length > 0 ? effectiveConnectorConfig.remnicDaemonUrl.trim() : void 0;
11105
11840
  const pubResult = await pub.publish({
11106
11841
  config: { memoryDir, namespace: connectorNamespace, daemonUrl: connectorDaemonUrl },
11107
- skillsRoot: path14.join(memoryDir, "skills"),
11842
+ skillsRoot: path15.join(memoryDir, "skills"),
11108
11843
  rollbackTokenEntry: preInstallTokenEntry,
11109
11844
  log: { info: console.log, warn: console.warn, error: console.error }
11110
11845
  });
@@ -11176,7 +11911,7 @@ async function cmdConnectors(action, rest, json) {
11176
11911
  const pub = factory();
11177
11912
  const available = await pub.isHostAvailable();
11178
11913
  const extRoot = available ? await pub.resolveExtensionRoot() : "(host not installed)";
11179
- const extensionExists = available && extRoot ? fs11.existsSync(extRoot) : false;
11914
+ const extensionExists = available && extRoot ? fs12.existsSync(extRoot) : false;
11180
11915
  publisherChecks.push({
11181
11916
  name: `Publisher: ${targetHostId}`,
11182
11917
  ok: !available || extensionExists,
@@ -11250,7 +11985,7 @@ async function cmdConnectors(action, rest, json) {
11250
11985
  let connectorsCfg;
11251
11986
  const configPath = resolveConfigPath();
11252
11987
  try {
11253
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
11988
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
11254
11989
  connectorsCfg = parseConfigQuietly(raw).connectors;
11255
11990
  } catch {
11256
11991
  process.stderr.write(
@@ -11326,9 +12061,9 @@ async function cmdConnectors(action, rest, json) {
11326
12061
  }
11327
12062
  initLogger2();
11328
12063
  const configPath = resolveConfigPath();
11329
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
12064
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
11330
12065
  const remnicCfg = resolveRemnicConfigRecord4(raw);
11331
- const config = parseConfig4(remnicCfg);
12066
+ const config = parseConfig5(remnicCfg);
11332
12067
  const orchestrator = new Orchestrator3(config);
11333
12068
  try {
11334
12069
  await orchestrator.initialize();
@@ -11451,9 +12186,9 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
11451
12186
  console.error(`connectors marketplace: ${err instanceof Error ? err.message : String(err)}`);
11452
12187
  process.exit(1);
11453
12188
  }
11454
- const rawConfig = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
12189
+ const rawConfig = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
11455
12190
  const pluginConfig = resolveRemnicConfigRecord4(rawConfig);
11456
- const config = parseConfig4(pluginConfig);
12191
+ const config = parseConfig5(pluginConfig);
11457
12192
  if (subAction === "generate") {
11458
12193
  let outputDir;
11459
12194
  try {
@@ -11464,22 +12199,22 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
11464
12199
  }
11465
12200
  const manifest = generateMarketplaceManifest();
11466
12201
  await writeMarketplaceManifest(outputDir, manifest);
11467
- const outPath = path14.join(outputDir, "marketplace.json");
12202
+ const outPath = path15.join(outputDir, "marketplace.json");
11468
12203
  if (json) {
11469
12204
  console.log(JSON.stringify({ status: "generated", path: outPath }, null, 2));
11470
12205
  } else {
11471
12206
  console.log(`Generated marketplace.json at ${outPath}`);
11472
12207
  }
11473
12208
  } else if (subAction === "validate") {
11474
- const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path14.join(process.cwd(), "marketplace.json");
11475
- const resolved = path14.resolve(targetPath);
11476
- if (!fs11.existsSync(resolved)) {
12209
+ const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path15.join(process.cwd(), "marketplace.json");
12210
+ const resolved = path15.resolve(targetPath);
12211
+ if (!fs12.existsSync(resolved)) {
11477
12212
  console.error(`File not found: ${resolved}`);
11478
12213
  process.exit(1);
11479
12214
  }
11480
12215
  let parsed;
11481
12216
  try {
11482
- parsed = JSON.parse(fs11.readFileSync(resolved, "utf8"));
12217
+ parsed = JSON.parse(fs12.readFileSync(resolved, "utf8"));
11483
12218
  } catch {
11484
12219
  console.error(`Invalid JSON in ${resolved}`);
11485
12220
  process.exit(1);
@@ -11680,9 +12415,9 @@ async function cmdSpace(action, rest, json) {
11680
12415
  async function cmdLegacyBenchmark(action, rest, json) {
11681
12416
  initLogger2();
11682
12417
  const configPath = resolveConfigPath();
11683
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
12418
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
11684
12419
  const remnicCfg = resolveRemnicConfigRecord4(raw);
11685
- const config = parseConfig4(remnicCfg);
12420
+ const config = parseConfig5(remnicCfg);
11686
12421
  const orchestrator = new Orchestrator3(config);
11687
12422
  const service = new EngramAccessService2(orchestrator);
11688
12423
  const { runBenchSuite, loadBaseline, checkRegression } = await loadBenchModule();
@@ -11880,7 +12615,7 @@ async function cmdBench(rest) {
11880
12615
  }
11881
12616
  const completeCount = prevStatus.benchmarks.filter((b) => b.status === "complete").length;
11882
12617
  const failedCount = prevStatus.benchmarks.filter((b) => b.status === "failed").length;
11883
- printBenchStatusLine(parsed.json, `Resuming from: ${path14.basename(latestStatusPath)}`);
12618
+ printBenchStatusLine(parsed.json, `Resuming from: ${path15.basename(latestStatusPath)}`);
11884
12619
  printBenchStatusLine(parsed.json, ` Previous run: ${prevStatus.startedAt}`);
11885
12620
  printBenchStatusLine(parsed.json, ` Benchmarks: ${prevStatus.benchmarks.length} total, ${completeCount} complete, ${failedCount} failed`);
11886
12621
  const before = selectedBenchmarks.length;
@@ -12048,9 +12783,9 @@ Options:
12048
12783
  );
12049
12784
  process.exit(1);
12050
12785
  } else {
12051
- fixturePath = path14.resolve(expandTilde(fixturePathRaw));
12786
+ fixturePath = path15.resolve(expandTilde(fixturePathRaw));
12052
12787
  }
12053
- const outPath = path14.resolve(expandTilde(outPathRaw));
12788
+ const outPath = path15.resolve(expandTilde(outPathRaw));
12054
12789
  const benchModule = await loadBenchModule();
12055
12790
  const runner = benchModule.runProceduralAblationCli;
12056
12791
  if (typeof runner !== "function") {
@@ -12069,7 +12804,7 @@ Options:
12069
12804
  );
12070
12805
  console.log(`wrote ${outPath}`);
12071
12806
  }
12072
- var LOGS_DIR = path14.join(PID_DIR, "logs");
12807
+ var LOGS_DIR = path15.join(PID_DIR, "logs");
12073
12808
  var LAUNCHD_PLIST_PATHS = launchdPlistPaths(resolveHomeDir());
12074
12809
  var [LAUNCHD_PLIST_PATH] = LAUNCHD_PLIST_PATHS;
12075
12810
  var SYSTEMD_UNIT_PATHS = systemdUnitPaths(resolveHomeDir());
@@ -12083,7 +12818,7 @@ function readPid() {
12083
12818
  function inferPort() {
12084
12819
  try {
12085
12820
  const configPath = resolveConfigPath();
12086
- const raw = JSON.parse(fs11.readFileSync(configPath, "utf8"));
12821
+ const raw = JSON.parse(fs12.readFileSync(configPath, "utf8"));
12087
12822
  return raw.server?.port ?? 4318;
12088
12823
  } catch {
12089
12824
  return 4318;
@@ -12146,7 +12881,7 @@ function selectLaunchdInspection(openclawPluginModeConfigured) {
12146
12881
  for (const plistPath of LAUNCHD_PLIST_PATHS.slice(1)) {
12147
12882
  const legacy = inspectLaunchdPlist(plistPath);
12148
12883
  if (!legacy.installed) continue;
12149
- const label = path14.basename(plistPath, ".plist");
12884
+ const label = path15.basename(plistPath, ".plist");
12150
12885
  return legacy.ok ? {
12151
12886
  ...legacy,
12152
12887
  warn: true,
@@ -12178,13 +12913,13 @@ function daemonInstall() {
12178
12913
  process.exit(1);
12179
12914
  }
12180
12915
  const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
12181
- fs11.mkdirSync(LOGS_DIR, { recursive: true });
12916
+ fs12.mkdirSync(LOGS_DIR, { recursive: true });
12182
12917
  if (isMacOS()) {
12183
- const templatePath = path14.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
12184
- const template = fs11.readFileSync(templatePath, "utf8");
12918
+ const templatePath = path15.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
12919
+ const template = fs12.readFileSync(templatePath, "utf8");
12185
12920
  const plist = renderTemplate(template, vars);
12186
- fs11.mkdirSync(path14.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
12187
- fs11.writeFileSync(LAUNCHD_PLIST_PATH, plist);
12921
+ fs12.mkdirSync(path15.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
12922
+ fs12.writeFileSync(LAUNCHD_PLIST_PATH, plist);
12188
12923
  try {
12189
12924
  launchdLoadPlist(LAUNCHD_PLIST_PATH);
12190
12925
  } catch (err) {
@@ -12200,11 +12935,11 @@ function daemonInstall() {
12200
12935
  console.log(` RunAtLoad: true, KeepAlive: true`);
12201
12936
  console.log(` Logs: ${LOGS_DIR}/daemon.log`);
12202
12937
  } else if (isLinux()) {
12203
- const templatePath = path14.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
12204
- const template = fs11.readFileSync(templatePath, "utf8");
12938
+ const templatePath = path15.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
12939
+ const template = fs12.readFileSync(templatePath, "utf8");
12205
12940
  const unit = renderTemplate(template, vars);
12206
- fs11.mkdirSync(path14.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
12207
- fs11.writeFileSync(SYSTEMD_UNIT_PATH, unit);
12941
+ fs12.mkdirSync(path15.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
12942
+ fs12.writeFileSync(SYSTEMD_UNIT_PATH, unit);
12208
12943
  try {
12209
12944
  childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
12210
12945
  } catch (err) {
@@ -12240,7 +12975,7 @@ function daemonUninstall() {
12240
12975
  } catch {
12241
12976
  }
12242
12977
  try {
12243
- fs11.unlinkSync(plistPath);
12978
+ fs12.unlinkSync(plistPath);
12244
12979
  removed = true;
12245
12980
  console.log(`Removed launchd service: ${plistPath}`);
12246
12981
  } catch {
@@ -12260,7 +12995,7 @@ function daemonUninstall() {
12260
12995
  let removed = false;
12261
12996
  for (const unitPath of SYSTEMD_UNIT_PATHS) {
12262
12997
  try {
12263
- fs11.unlinkSync(unitPath);
12998
+ fs12.unlinkSync(unitPath);
12264
12999
  removed = true;
12265
13000
  console.log(`Removed systemd service: ${unitPath}`);
12266
13001
  } catch {
@@ -12327,13 +13062,13 @@ async function daemonStatus() {
12327
13062
  console.log(` Port: ${port}`);
12328
13063
  console.log(` Service: ${serviceInstalled ? "installed" : "not installed"}`);
12329
13064
  console.log(` Platform: ${process.platform}`);
12330
- console.log(` PID file: ${fs11.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
12331
- console.log(` Log file: ${fs11.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
13065
+ console.log(` PID file: ${fs12.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
13066
+ console.log(` Log file: ${fs12.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
12332
13067
  try {
12333
13068
  const configPath = resolveConfigPath();
12334
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
13069
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
12335
13070
  const remnicCfg = resolveRemnicConfigRecord4(raw);
12336
- const config = parseConfig4(remnicCfg);
13071
+ const config = parseConfig5(remnicCfg);
12337
13072
  const extRoot = resolveExtensionsRoot(config);
12338
13073
  const noopLog = { warn: () => {
12339
13074
  }, debug: () => {
@@ -12372,9 +13107,9 @@ function daemonStart() {
12372
13107
  return;
12373
13108
  }
12374
13109
  }
12375
- fs11.mkdirSync(PID_DIR, { recursive: true });
12376
- fs11.mkdirSync(LOGS_DIR, { recursive: true });
12377
- const logStream = fs11.openSync(LOG_FILE, "a");
13110
+ fs12.mkdirSync(PID_DIR, { recursive: true });
13111
+ fs12.mkdirSync(LOGS_DIR, { recursive: true });
13112
+ const logStream = fs12.openSync(LOG_FILE, "a");
12378
13113
  const serverBin = resolveServerBin();
12379
13114
  const isSource = serverBin.endsWith(".ts");
12380
13115
  let cmd;
@@ -12396,7 +13131,7 @@ function daemonStart() {
12396
13131
  }
12397
13132
  });
12398
13133
  child.unref();
12399
- fs11.writeFileSync(PID_FILE, String(child.pid));
13134
+ fs12.writeFileSync(PID_FILE, String(child.pid));
12400
13135
  console.log(`Started remnic server (pid ${child.pid})`);
12401
13136
  console.log(` Log: ${LOG_FILE}`);
12402
13137
  }
@@ -12430,11 +13165,11 @@ function daemonStop() {
12430
13165
  console.log("Process not found (cleaning up PID file)");
12431
13166
  }
12432
13167
  try {
12433
- fs11.unlinkSync(PID_FILE);
13168
+ fs12.unlinkSync(PID_FILE);
12434
13169
  } catch {
12435
13170
  }
12436
13171
  try {
12437
- fs11.unlinkSync(LEGACY_PID_FILE);
13172
+ fs12.unlinkSync(LEGACY_PID_FILE);
12438
13173
  } catch {
12439
13174
  }
12440
13175
  }
@@ -12562,9 +13297,9 @@ async function promptYesNo(question, defaultYes = true) {
12562
13297
  async function cmdBinary(rest) {
12563
13298
  initLogger2();
12564
13299
  const configPath = resolveConfigPath();
12565
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
13300
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
12566
13301
  const remnicCfg = resolveRemnicConfigRecord4(raw);
12567
- const config = parseConfig4(remnicCfg);
13302
+ const config = parseConfig5(remnicCfg);
12568
13303
  const memoryDir = resolveMemoryDir();
12569
13304
  const blConfig = {
12570
13305
  enabled: config.binaryLifecycleEnabled,
@@ -12682,7 +13417,7 @@ Clean complete: cleaned=${result.cleaned}`
12682
13417
  }
12683
13418
  async function cmdOpenclawInstall(opts) {
12684
13419
  const configPath = resolveOpenclawConfigPath(opts.configPath);
12685
- const fallbackMemoryDir = path14.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
13420
+ const fallbackMemoryDir = path15.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
12686
13421
  console.log(`OpenClaw config: ${configPath}`);
12687
13422
  const existingConfig = readOpenclawConfig(configPath);
12688
13423
  const { plugins, entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
@@ -12753,7 +13488,7 @@ async function cmdOpenclawInstall(opts) {
12753
13488
  } else if (slotIsActiveLegacy) {
12754
13489
  changes.push(` Slot left as "${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}" \u2014 re-run with --yes to activate the new entry`);
12755
13490
  }
12756
- if (!fs11.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
13491
+ if (!fs12.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
12757
13492
  if (hasLegacy && migrateLegacy) {
12758
13493
  changes.push(`~ Legacy '${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}' entry retained (safe to remove after verifying hooks fire)`);
12759
13494
  }
@@ -12773,8 +13508,8 @@ async function cmdOpenclawInstall(opts) {
12773
13508
  Resulting plugins.slots.memory: ${dryRunPlugins.slots?.memory ?? "(unset)"}`);
12774
13509
  return;
12775
13510
  }
12776
- if (fs11.existsSync(memoryDir)) {
12777
- const st = fs11.statSync(memoryDir);
13511
+ if (fs12.existsSync(memoryDir)) {
13512
+ const st = fs12.statSync(memoryDir);
12778
13513
  if (!st.isDirectory()) {
12779
13514
  throw new Error(
12780
13515
  `Cannot use ${memoryDir} as the memory directory \u2014 a file already exists at that path.
@@ -12782,12 +13517,12 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
12782
13517
  );
12783
13518
  }
12784
13519
  } else {
12785
- fs11.mkdirSync(memoryDir, { recursive: true });
13520
+ fs12.mkdirSync(memoryDir, { recursive: true });
12786
13521
  console.log(`Created memory directory: ${memoryDir}`);
12787
13522
  }
12788
- const configDir = path14.dirname(configPath);
12789
- if (!fs11.existsSync(configDir)) {
12790
- fs11.mkdirSync(configDir, { recursive: true });
13523
+ const configDir = path15.dirname(configPath);
13524
+ if (!fs12.existsSync(configDir)) {
13525
+ fs12.mkdirSync(configDir, { recursive: true });
12791
13526
  }
12792
13527
  atomicWriteFileSync(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
12793
13528
  console.log("\nDone! Summary of changes:");
@@ -12813,11 +13548,11 @@ async function cmdOpenclawUpgrade(opts) {
12813
13548
  const configPath = resolveOpenclawConfigPath(opts.configPath);
12814
13549
  const pluginDir = resolveOpenclawPluginDir(opts.pluginDir);
12815
13550
  const legacyPluginDirForBackup = opts.legacyPluginDirForBackup ? resolveOpenclawLegacyPluginDir(opts.legacyPluginDirForBackup) : void 0;
12816
- const fallbackMemoryDir = path14.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
13551
+ const fallbackMemoryDir = path15.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
12817
13552
  const packageSpec = `@remnic/plugin-openclaw@${opts.version ?? "latest"}`;
12818
13553
  const existingConfig = readOpenclawConfig(configPath);
12819
13554
  const { entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
12820
- const preservedMemoryDir = opts.memoryDir ? path14.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
13555
+ const preservedMemoryDir = opts.memoryDir ? path15.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
12821
13556
  assertDirectoryPathOrMissing(pluginDir, "OpenClaw plugin dir");
12822
13557
  if (legacyPluginDirForBackup) {
12823
13558
  assertDirectoryPathOrMissing(legacyPluginDirForBackup, "Legacy OpenClaw plugin dir");
@@ -12829,7 +13564,7 @@ async function cmdOpenclawUpgrade(opts) {
12829
13564
  }
12830
13565
  console.log(`Memory dir: ${preservedMemoryDir}`);
12831
13566
  console.log(`Package spec: ${packageSpec}`);
12832
- console.log(`Backup root: ${path14.join(resolveHomeDir(), ".openclaw", "backups")}`);
13567
+ console.log(`Backup root: ${path15.join(resolveHomeDir(), ".openclaw", "backups")}`);
12833
13568
  const plannedActions = [
12834
13569
  `backup openclaw.json and the existing ${REMNIC_OPENCLAW_PLUGIN_ID} extension`,
12835
13570
  ...legacyPluginDirForBackup ? [`backup the existing ${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID} extension without modifying it`] : [],
@@ -12855,9 +13590,9 @@ async function cmdOpenclawUpgrade(opts) {
12855
13590
  }
12856
13591
  }
12857
13592
  const backupDir = createOpenclawUpgradeBackupDir();
12858
- const configBackupPath = path14.join(backupDir, "openclaw.json");
12859
- const pluginBackupDir = path14.join(backupDir, "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
12860
- const legacyPluginBackupDir = legacyPluginDirForBackup ? path14.join(backupDir, "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID) : void 0;
13593
+ const configBackupPath = path15.join(backupDir, "openclaw.json");
13594
+ const pluginBackupDir = path15.join(backupDir, "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
13595
+ const legacyPluginBackupDir = legacyPluginDirForBackup ? path15.join(backupDir, "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID) : void 0;
12861
13596
  const backupNotes = [];
12862
13597
  if (backupPathIfPresent(configPath, configBackupPath)) {
12863
13598
  backupNotes.push(`+ Backed up config to ${configBackupPath}`);
@@ -12958,16 +13693,16 @@ async function cmdOpenclawMigrateEngram(opts) {
12958
13693
  console.log(" - Re-apply any local source patches to the new package only after verifying the published build.");
12959
13694
  }
12960
13695
  function createOpenclawUpgradeBackupDir() {
12961
- const backupsRoot = path14.join(resolveHomeDir(), ".openclaw", "backups");
12962
- fs11.mkdirSync(backupsRoot, { recursive: true });
12963
- return fs11.mkdtempSync(path14.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
13696
+ const backupsRoot = path15.join(resolveHomeDir(), ".openclaw", "backups");
13697
+ fs12.mkdirSync(backupsRoot, { recursive: true });
13698
+ return fs12.mkdtempSync(path15.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
12964
13699
  }
12965
13700
  async function cmdTaxonomy(rest) {
12966
13701
  initLogger2();
12967
13702
  const configPath = resolveConfigPath();
12968
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
13703
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
12969
13704
  const remnicCfg = resolveRemnicConfigRecord4(raw);
12970
- const config = parseConfig4(remnicCfg);
13705
+ const config = parseConfig5(remnicCfg);
12971
13706
  if (!config.taxonomyEnabled) {
12972
13707
  console.error(
12973
13708
  "Taxonomy is disabled in config (taxonomyEnabled = false). Enable it to use taxonomy commands."
@@ -13002,9 +13737,9 @@ async function cmdTaxonomy(rest) {
13002
13737
  const doc = generateResolverDocument(taxonomy);
13003
13738
  console.log(doc);
13004
13739
  if (config.taxonomyAutoGenResolver) {
13005
- const resolverPath = path14.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13006
- fs11.mkdirSync(path14.dirname(resolverPath), { recursive: true });
13007
- fs11.writeFileSync(resolverPath, doc);
13740
+ const resolverPath = path15.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13741
+ fs12.mkdirSync(path15.dirname(resolverPath), { recursive: true });
13742
+ fs12.writeFileSync(resolverPath, doc);
13008
13743
  console.error(`Written: ${resolverPath}`);
13009
13744
  }
13010
13745
  break;
@@ -13049,8 +13784,8 @@ async function cmdTaxonomy(rest) {
13049
13784
  console.log(`Added category "${id}" (${name}).`);
13050
13785
  if (config.taxonomyAutoGenResolver) {
13051
13786
  const doc = generateResolverDocument(taxonomy);
13052
- const resolverPath = path14.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13053
- fs11.writeFileSync(resolverPath, doc);
13787
+ const resolverPath = path15.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13788
+ fs12.writeFileSync(resolverPath, doc);
13054
13789
  console.error(`Regenerated: ${resolverPath}`);
13055
13790
  }
13056
13791
  break;
@@ -13080,8 +13815,8 @@ async function cmdTaxonomy(rest) {
13080
13815
  console.log(`Removed category "${id}".`);
13081
13816
  if (config.taxonomyAutoGenResolver) {
13082
13817
  const doc = generateResolverDocument(taxonomy);
13083
- const resolverPath = path14.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13084
- fs11.writeFileSync(resolverPath, doc);
13818
+ const resolverPath = path15.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13819
+ fs12.writeFileSync(resolverPath, doc);
13085
13820
  console.error(`Regenerated: ${resolverPath}`);
13086
13821
  }
13087
13822
  break;
@@ -13272,12 +14007,12 @@ async function runTrainingExport(args, stdout = process.stdout) {
13272
14007
  `Unknown training-export format "${args.format}". ${validList}`
13273
14008
  );
13274
14009
  }
13275
- if (!fs11.existsSync(args.memoryDir)) {
14010
+ if (!fs12.existsSync(args.memoryDir)) {
13276
14011
  throw new Error(
13277
14012
  `--memory-dir "${args.memoryDir}" does not exist. Provide the path to an existing memory directory.`
13278
14013
  );
13279
14014
  }
13280
- if (!fs11.statSync(args.memoryDir).isDirectory()) {
14015
+ if (!fs12.statSync(args.memoryDir).isDirectory()) {
13281
14016
  throw new Error(
13282
14017
  `--memory-dir "${args.memoryDir}" is not a directory. Provide the path to a memory directory, not a file.`
13283
14018
  );
@@ -13362,11 +14097,11 @@ async function runTrainingExport(args, stdout = process.stdout) {
13362
14097
  );
13363
14098
  }
13364
14099
  const formatted = adapter.formatRecords(records);
13365
- const outDir = path14.dirname(args.output);
13366
- fs11.mkdirSync(outDir, { recursive: true });
14100
+ const outDir = path15.dirname(args.output);
14101
+ fs12.mkdirSync(outDir, { recursive: true });
13367
14102
  const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
13368
- fs11.writeFileSync(tmpPath, formatted, "utf-8");
13369
- fs11.renameSync(tmpPath, args.output);
14103
+ fs12.writeFileSync(tmpPath, formatted, "utf-8");
14104
+ fs12.renameSync(tmpPath, args.output);
13370
14105
  stdout.write(
13371
14106
  `Exported ${records.length} records to ${args.output} (${adapter.name} format)
13372
14107
  `
@@ -13470,7 +14205,7 @@ async function main(argv = process.argv.slice(2)) {
13470
14205
  case "tree": {
13471
14206
  const subAction = rest[0];
13472
14207
  const json = rest.includes("--json");
13473
- const outputDir = resolveFlag(rest, "--output") ?? path14.join(process.cwd(), ".remnic", "context-tree");
14208
+ const outputDir = resolveFlag(rest, "--output") ?? path15.join(process.cwd(), ".remnic", "context-tree");
13474
14209
  const categoriesFlag = resolveFlag(rest, "--categories");
13475
14210
  const categories = categoriesFlag ? categoriesFlag.split(",") : void 0;
13476
14211
  const maxPerCategoryRaw = resolveFlag(rest, "--max-per-category");
@@ -13535,7 +14270,7 @@ async function main(argv = process.argv.slice(2)) {
13535
14270
  }
13536
14271
  }, 500);
13537
14272
  };
13538
- fs11.watch(memoryDir, { recursive: true }, (_event, filename) => {
14273
+ fs12.watch(memoryDir, { recursive: true }, (_event, filename) => {
13539
14274
  if (filename && filename.startsWith(".")) return;
13540
14275
  rebuild();
13541
14276
  });
@@ -13543,12 +14278,12 @@ async function main(argv = process.argv.slice(2)) {
13543
14278
  });
13544
14279
  } else if (subAction === "validate") {
13545
14280
  const treeDir = outputDir;
13546
- if (!fs11.existsSync(treeDir)) {
14281
+ if (!fs12.existsSync(treeDir)) {
13547
14282
  console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
13548
14283
  process.exit(1);
13549
14284
  }
13550
- const indexPath = path14.join(treeDir, "INDEX.md");
13551
- if (!fs11.existsSync(indexPath)) {
14285
+ const indexPath = path15.join(treeDir, "INDEX.md");
14286
+ if (!fs12.existsSync(indexPath)) {
13552
14287
  console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
13553
14288
  process.exit(1);
13554
14289
  }
@@ -13602,6 +14337,12 @@ Options:
13602
14337
  await cmdOffline(action, rest.slice(1), json);
13603
14338
  break;
13604
14339
  }
14340
+ case "converge": {
14341
+ const action = rest[0] ?? "plan";
14342
+ const json = rest.includes("--json");
14343
+ await cmdConverge(action, rest.slice(1), json);
14344
+ break;
14345
+ }
13605
14346
  case "oauth": {
13606
14347
  await cmdOAuth(rest);
13607
14348
  break;
@@ -13718,9 +14459,9 @@ Other:
13718
14459
  let wearablesService;
13719
14460
  try {
13720
14461
  const configPath = resolveConfigPath();
13721
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
14462
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
13722
14463
  const remnicCfg = resolveRemnicConfigRecord4(raw);
13723
- const config = parseConfig4(remnicCfg);
14464
+ const config = parseConfig5(remnicCfg);
13724
14465
  wearablesOrchestrator = new Orchestrator3(config);
13725
14466
  await wearablesOrchestrator.initialize();
13726
14467
  await wearablesOrchestrator.deferredReady;
@@ -13769,9 +14510,9 @@ Other:
13769
14510
  const targetFactory = async () => {
13770
14511
  if (!orchestratorSingleton) {
13771
14512
  const configPath = resolveConfigPath();
13772
- const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
14513
+ const raw = fs12.existsSync(configPath) ? JSON.parse(fs12.readFileSync(configPath, "utf8")) : {};
13773
14514
  const remnicCfg = resolveRemnicConfigRecord4(raw);
13774
- const config = parseConfig4(remnicCfg);
14515
+ const config = parseConfig5(remnicCfg);
13775
14516
  orchestratorSingleton = new Orchestrator3(config);
13776
14517
  await orchestratorSingleton.initialize();
13777
14518
  await orchestratorSingleton.deferredReady;