@remnic/cli 9.7.15 → 9.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1223 -697
- package/package.json +28 -28
package/dist/index.js
CHANGED
|
@@ -1,19 +1,38 @@
|
|
|
1
|
+
// src/enrichment-persist.ts
|
|
2
|
+
import { composeSalvagedEnvelope } from "@remnic/core/salvage-envelope";
|
|
3
|
+
async function persistEnrichmentCandidate(storage, entityName, candidate) {
|
|
4
|
+
await storage.writeSealedMemory(
|
|
5
|
+
composeSalvagedEnvelope(
|
|
6
|
+
"enrichment",
|
|
7
|
+
{
|
|
8
|
+
content: candidate.text,
|
|
9
|
+
category: candidate.category,
|
|
10
|
+
confidence: candidate.confidence,
|
|
11
|
+
tags: [...candidate.tags ?? [], "enrichment", candidate.source],
|
|
12
|
+
entityRef: entityName
|
|
13
|
+
},
|
|
14
|
+
{ source: `enrichment:${candidate.source}` }
|
|
15
|
+
),
|
|
16
|
+
{}
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
1
20
|
// src/index.ts
|
|
2
|
-
import
|
|
21
|
+
import fs10 from "fs";
|
|
3
22
|
import os from "os";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
23
|
+
import path12 from "path";
|
|
24
|
+
import { createHash as createHash2 } from "crypto";
|
|
6
25
|
import * as childProcess2 from "child_process";
|
|
7
26
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8
27
|
import { gzipSync } from "zlib";
|
|
9
28
|
import {
|
|
10
|
-
parseConfig,
|
|
29
|
+
parseConfig as parseConfig3,
|
|
11
30
|
isOpenaiApiKeyDisabled,
|
|
12
31
|
resolveEnvVars,
|
|
13
|
-
resolveRemnicConfigRecord,
|
|
14
|
-
Orchestrator,
|
|
15
|
-
EngramAccessService,
|
|
16
|
-
initLogger,
|
|
32
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord3,
|
|
33
|
+
Orchestrator as Orchestrator2,
|
|
34
|
+
EngramAccessService as EngramAccessService2,
|
|
35
|
+
initLogger as initLogger2,
|
|
17
36
|
onboard,
|
|
18
37
|
curate,
|
|
19
38
|
listReviewItems,
|
|
@@ -85,18 +104,19 @@ import {
|
|
|
85
104
|
discoverMemoryExtensions,
|
|
86
105
|
resolveExtensionsRoot,
|
|
87
106
|
coerceInstallExtension,
|
|
88
|
-
StorageManager,
|
|
107
|
+
StorageManager as StorageManager2,
|
|
89
108
|
computeProcedureStats,
|
|
90
109
|
formatProcedureStatsText,
|
|
91
110
|
parseXrayCliOptions,
|
|
92
111
|
renderXray,
|
|
93
112
|
OFFLINE_SYNC_APPLY_MAX_BODY_BYTES,
|
|
94
113
|
OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
|
|
95
|
-
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
|
|
114
|
+
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES as OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2,
|
|
96
115
|
OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES,
|
|
97
116
|
applyOfflineSyncFileContentChunk,
|
|
98
117
|
applyOfflineSyncSnapshot,
|
|
99
118
|
buildOfflineSyncChangesetFromSnapshot,
|
|
119
|
+
drainPendingLifecycleForOfflineSync,
|
|
100
120
|
compileOfflineSyncExcludeGlobs,
|
|
101
121
|
buildOfflineSyncSnapshotFromBase,
|
|
102
122
|
defaultOfflineSyncStatePath,
|
|
@@ -118,24 +138,6 @@ import {
|
|
|
118
138
|
OPERATION_NAMES,
|
|
119
139
|
validateCapabilitiesForMint
|
|
120
140
|
} from "@remnic/core";
|
|
121
|
-
import {
|
|
122
|
-
AUTH_TAG_LENGTH,
|
|
123
|
-
ENVELOPE_HEADER_SIZE,
|
|
124
|
-
ENVELOPE_LAYOUT,
|
|
125
|
-
ENVELOPE_SALT_LENGTH,
|
|
126
|
-
ENVELOPE_VERSION,
|
|
127
|
-
FILE_FORMAT_FLAGS,
|
|
128
|
-
FILE_FORMAT_VERSION,
|
|
129
|
-
IV_LENGTH,
|
|
130
|
-
MAGIC_BYTES,
|
|
131
|
-
MAGIC_HEADER_SIZE,
|
|
132
|
-
SecureStoreLockedError,
|
|
133
|
-
filePathAad,
|
|
134
|
-
isEncryptedFile,
|
|
135
|
-
keyring,
|
|
136
|
-
readHeader,
|
|
137
|
-
secureStoreDir
|
|
138
|
-
} from "@remnic/core/secure-store";
|
|
139
141
|
|
|
140
142
|
// src/optional-module-loader.ts
|
|
141
143
|
function isSpecifierNotFoundError(err, specifier) {
|
|
@@ -171,38 +173,574 @@ async function tryImportWecloneExport() {
|
|
|
171
173
|
if (isSpecifierNotFoundError(err, SPECIFIER)) {
|
|
172
174
|
return null;
|
|
173
175
|
}
|
|
174
|
-
throw err;
|
|
176
|
+
throw err;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function loadWecloneExportModule() {
|
|
180
|
+
if (cached === void 0) {
|
|
181
|
+
cached = await tryImportWecloneExport();
|
|
182
|
+
}
|
|
183
|
+
if (!cached) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
"The weclone training-export adapter requires the optional @remnic/export-weclone package.\n\nInstall it alongside the CLI:\n npm install -g @remnic/export-weclone\n\nOr add it to a project:\n pnpm add @remnic/export-weclone\n"
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return cached;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/doctor-namespace-lint.ts
|
|
192
|
+
import { isNamespacePolicyCovered } from "@remnic/core";
|
|
193
|
+
function readConfiguredNamespace(remnicCfg) {
|
|
194
|
+
if (!("namespace" in remnicCfg)) return { invalid: false };
|
|
195
|
+
const value = remnicCfg.namespace;
|
|
196
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
197
|
+
return { configuredNamespace: value.trim(), invalid: false };
|
|
198
|
+
}
|
|
199
|
+
return { invalid: true };
|
|
200
|
+
}
|
|
201
|
+
function buildNamespacePolicyCheck(args) {
|
|
202
|
+
if (args.invalid) {
|
|
203
|
+
return {
|
|
204
|
+
name: "Namespace policy",
|
|
205
|
+
ok: false,
|
|
206
|
+
detail: "config `namespace` is set but is not a non-empty string",
|
|
207
|
+
remediation: "Set `namespace` to a non-empty string (a namespacePolicies name or the default namespace), or remove it."
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (!args.config || !args.configuredNamespace) return void 0;
|
|
211
|
+
const covered = isNamespacePolicyCovered(args.configuredNamespace, args.config);
|
|
212
|
+
return {
|
|
213
|
+
name: "Namespace policy",
|
|
214
|
+
ok: covered,
|
|
215
|
+
warn: !covered,
|
|
216
|
+
detail: covered ? `configured namespace "${args.configuredNamespace}" is writable` : `configured namespace "${args.configuredNamespace}" is writable by no one \u2014 its namespacePolicies entry grants no writer, or it has no entry and is not the default namespace`,
|
|
217
|
+
remediation: covered ? void 0 : `Give "${args.configuredNamespace}" a namespacePolicies entry with a non-blank writePrincipals value, or set namespace to a writable one \u2014 otherwise every write is rejected and dead-lettered.`
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/index.ts
|
|
222
|
+
import { WriteQuarantineStore as WriteQuarantineStore2 } from "@remnic/core/write-quarantine.js";
|
|
223
|
+
|
|
224
|
+
// src/quarantine-cli.ts
|
|
225
|
+
import { basename } from "path";
|
|
226
|
+
function renderQuarantineList(records, format) {
|
|
227
|
+
if (format === "json") {
|
|
228
|
+
const summary = records.map((record) => ({
|
|
229
|
+
timestamp: record.timestamp,
|
|
230
|
+
operation: record.operation,
|
|
231
|
+
principal: record.principal,
|
|
232
|
+
attemptedNamespace: record.attemptedNamespace
|
|
233
|
+
}));
|
|
234
|
+
return JSON.stringify(summary, null, 2);
|
|
235
|
+
}
|
|
236
|
+
if (format !== "text") {
|
|
237
|
+
throw new Error(`Unsupported quarantine format: ${String(format)}`);
|
|
238
|
+
}
|
|
239
|
+
if (records.length === 0) return "No quarantined writes.";
|
|
240
|
+
const lines = [`Quarantined writes (${records.length}):`, ""];
|
|
241
|
+
for (const record of records) {
|
|
242
|
+
lines.push(
|
|
243
|
+
` ${record.timestamp} ${record.operation} principal=${record.principal ?? "-"} attemptedNamespace=${record.attemptedNamespace}`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
return lines.join("\n");
|
|
247
|
+
}
|
|
248
|
+
async function replayQuarantine(opts) {
|
|
249
|
+
const result = { replayed: 0, failures: [], deleteFailures: [] };
|
|
250
|
+
for (const entry of await opts.store.entries()) {
|
|
251
|
+
const { record } = entry;
|
|
252
|
+
const basePayload = record.payload;
|
|
253
|
+
const principal = opts.principal ?? record.principal ?? void 0;
|
|
254
|
+
const idempotencyKey = typeof basePayload.idempotencyKey === "string" && basePayload.idempotencyKey.length > 0 ? basePayload.idempotencyKey : `quarantine-replay:${basename(entry.path)}`;
|
|
255
|
+
const request = {
|
|
256
|
+
...basePayload,
|
|
257
|
+
namespace: opts.targetNamespace,
|
|
258
|
+
suppressQuarantine: true,
|
|
259
|
+
idempotencyKey,
|
|
260
|
+
...principal ? { authenticatedPrincipal: principal } : {}
|
|
261
|
+
};
|
|
262
|
+
try {
|
|
263
|
+
await opts.submit(record.operation, request);
|
|
264
|
+
} catch (err) {
|
|
265
|
+
result.failures.push({
|
|
266
|
+
operation: record.operation,
|
|
267
|
+
attemptedNamespace: opts.targetNamespace,
|
|
268
|
+
error: err instanceof Error ? err.message : String(err)
|
|
269
|
+
});
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
const removed = await opts.store.removeEntry(entry.path);
|
|
274
|
+
if (removed) {
|
|
275
|
+
result.replayed += 1;
|
|
276
|
+
} else {
|
|
277
|
+
result.deleteFailures.push({
|
|
278
|
+
path: entry.path,
|
|
279
|
+
error: "entry not removed (outside quarantine root or already absent)"
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
} catch (err) {
|
|
283
|
+
result.deleteFailures.push({
|
|
284
|
+
path: entry.path,
|
|
285
|
+
error: err instanceof Error ? err.message : String(err)
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
function renderReplayResult(result, targetNamespace, format) {
|
|
292
|
+
if (format === "json") {
|
|
293
|
+
return JSON.stringify(
|
|
294
|
+
{
|
|
295
|
+
targetNamespace,
|
|
296
|
+
replayed: result.replayed,
|
|
297
|
+
failures: result.failures,
|
|
298
|
+
deleteFailures: result.deleteFailures
|
|
299
|
+
},
|
|
300
|
+
null,
|
|
301
|
+
2
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
if (format !== "text") {
|
|
305
|
+
throw new Error(`Unsupported quarantine format: ${String(format)}`);
|
|
306
|
+
}
|
|
307
|
+
const lines = [`Replayed ${result.replayed} quarantined write(s) into namespace ${targetNamespace}.`];
|
|
308
|
+
if (result.failures.length > 0) {
|
|
309
|
+
lines.push("", `Failures (${result.failures.length}); left parked:`);
|
|
310
|
+
for (const failure of result.failures) {
|
|
311
|
+
lines.push(` ${failure.operation} attemptedNamespace=${failure.attemptedNamespace} error=${failure.error}`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (result.deleteFailures.length > 0) {
|
|
315
|
+
lines.push("", `Delete failures (${result.deleteFailures.length}); re-submitted but still parked:`);
|
|
316
|
+
for (const del of result.deleteFailures) {
|
|
317
|
+
lines.push(` ${del.path} error=${del.error}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return lines.join("\n");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/quarantine-replay.ts
|
|
324
|
+
import * as fs from "fs";
|
|
325
|
+
import { EngramAccessService, Orchestrator, initLogger, parseConfig, resolveRemnicConfigRecord } from "@remnic/core";
|
|
326
|
+
import { WriteQuarantineStore } from "@remnic/core/write-quarantine.js";
|
|
327
|
+
function valueFlag(args, flag) {
|
|
328
|
+
const occurrences = args.filter((a) => a === flag).length;
|
|
329
|
+
if (occurrences === 0) return void 0;
|
|
330
|
+
if (occurrences > 1) {
|
|
331
|
+
throw new Error(`${flag} may be given at most once.`);
|
|
332
|
+
}
|
|
333
|
+
const value = args[args.indexOf(flag) + 1];
|
|
334
|
+
if (value === void 0 || value.startsWith("--")) {
|
|
335
|
+
throw new Error(`${flag} requires a value. Provide it as \`${flag} <value>\`, not a bare flag.`);
|
|
336
|
+
}
|
|
337
|
+
if (value.trim().length === 0) {
|
|
338
|
+
throw new Error(`${flag} requires a non-empty value.`);
|
|
339
|
+
}
|
|
340
|
+
return value;
|
|
341
|
+
}
|
|
342
|
+
async function runQuarantineReplay(rest, format, resolveConfigPath2) {
|
|
343
|
+
let targetNamespace;
|
|
344
|
+
let principal;
|
|
345
|
+
try {
|
|
346
|
+
targetNamespace = valueFlag(rest, "--namespace");
|
|
347
|
+
principal = valueFlag(rest, "--principal");
|
|
348
|
+
} catch (err) {
|
|
349
|
+
process.stderr.write(`quarantine replay: ${err instanceof Error ? err.message : String(err)}
|
|
350
|
+
`);
|
|
351
|
+
process.exitCode = 2;
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (!targetNamespace || targetNamespace.trim().length === 0) {
|
|
355
|
+
process.stderr.write("quarantine replay: --namespace <ns> is required.\n");
|
|
356
|
+
process.exitCode = 2;
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const valued = /* @__PURE__ */ new Set(["--namespace", "--principal"]);
|
|
360
|
+
const bad = rest.filter((a, i) => a.startsWith("--") ? a !== "--json" && !valued.has(a) : !valued.has(rest[i - 1]));
|
|
361
|
+
if (bad.length > 0) {
|
|
362
|
+
process.stderr.write(
|
|
363
|
+
`quarantine replay: unexpected argument(s): ${bad.join(", ")}. Use: replay --namespace <ns> [--principal <p>] [--json].
|
|
364
|
+
`
|
|
365
|
+
);
|
|
366
|
+
process.exitCode = 2;
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
initLogger();
|
|
370
|
+
let orchestrator;
|
|
371
|
+
try {
|
|
372
|
+
const configPath = resolveConfigPath2();
|
|
373
|
+
const raw = fs.existsSync(configPath) ? JSON.parse(fs.readFileSync(configPath, "utf8")) : {};
|
|
374
|
+
const config = parseConfig(resolveRemnicConfigRecord(raw));
|
|
375
|
+
orchestrator = new Orchestrator(config);
|
|
376
|
+
await orchestrator.initialize();
|
|
377
|
+
await orchestrator.deferredReady;
|
|
378
|
+
const service = new EngramAccessService(orchestrator);
|
|
379
|
+
const store = new WriteQuarantineStore(config.memoryDir);
|
|
380
|
+
const result = await replayQuarantine({
|
|
381
|
+
store,
|
|
382
|
+
targetNamespace,
|
|
383
|
+
principal,
|
|
384
|
+
submit: async (operation, request) => {
|
|
385
|
+
if (operation === "observe") {
|
|
386
|
+
await service.observe(request);
|
|
387
|
+
} else if (operation === "memory_store") {
|
|
388
|
+
await service.memoryStore(request);
|
|
389
|
+
} else {
|
|
390
|
+
await service.suggestionSubmit(request);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
console.log(renderReplayResult(result, targetNamespace, format));
|
|
395
|
+
if (result.failures.length > 0 || result.deleteFailures.length > 0) process.exitCode = 1;
|
|
396
|
+
} catch {
|
|
397
|
+
process.stderr.write("quarantine replay: unable to replay quarantine store\n");
|
|
398
|
+
process.exitCode = 2;
|
|
399
|
+
} finally {
|
|
400
|
+
if (orchestrator) await orchestrator.destroy();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/offline-impression-rotation.ts
|
|
405
|
+
import fs2 from "fs";
|
|
406
|
+
import { parseConfig as parseConfig2, resolveRemnicConfigRecord as resolveRemnicConfigRecord2, drainPendingImpressionsForOfflineSync } from "@remnic/core";
|
|
407
|
+
import { LastRecallStore } from "@remnic/core/recall-state";
|
|
408
|
+
function parseConfigQuietly(raw) {
|
|
409
|
+
const originalWarn = console.warn;
|
|
410
|
+
console.warn = () => {
|
|
411
|
+
};
|
|
412
|
+
try {
|
|
413
|
+
return parseConfig2(resolveRemnicConfigRecord2(raw));
|
|
414
|
+
} finally {
|
|
415
|
+
console.warn = originalWarn;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
var OFFLINE_CONFIG_KEYS = [
|
|
419
|
+
"offlineSyncExcludes",
|
|
420
|
+
"secureStoreEncryptOnWrite",
|
|
421
|
+
"recallImpressionsRotateBytes",
|
|
422
|
+
"recallImpressionsRotateKeep"
|
|
423
|
+
];
|
|
424
|
+
function pickOfflineConfigRecord(raw) {
|
|
425
|
+
let resolved;
|
|
426
|
+
try {
|
|
427
|
+
resolved = resolveRemnicConfigRecord2(raw);
|
|
428
|
+
} catch {
|
|
429
|
+
resolved = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
430
|
+
}
|
|
431
|
+
const picked = {};
|
|
432
|
+
for (const key of OFFLINE_CONFIG_KEYS) {
|
|
433
|
+
if (key in resolved) picked[key] = resolved[key];
|
|
434
|
+
}
|
|
435
|
+
return picked;
|
|
436
|
+
}
|
|
437
|
+
function resolveOfflineImpressionRotation(configPath) {
|
|
438
|
+
let raw;
|
|
439
|
+
try {
|
|
440
|
+
raw = fs2.existsSync(configPath) ? JSON.parse(fs2.readFileSync(configPath, "utf8")) : {};
|
|
441
|
+
} catch {
|
|
442
|
+
throw new Error(
|
|
443
|
+
`cannot read recall-impression rotation from ${configPath}: config file could not be read as JSON`
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
let config;
|
|
447
|
+
try {
|
|
448
|
+
config = parseConfigQuietly(pickOfflineConfigRecord(raw));
|
|
449
|
+
} catch {
|
|
450
|
+
throw new Error(
|
|
451
|
+
`cannot read recall-impression rotation from ${configPath}: config failed validation`
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
impressionsRotateBytes: config.recallImpressionsRotateBytes,
|
|
456
|
+
impressionsRotateKeep: config.recallImpressionsRotateKeep
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
async function drainOfflineSyncImpressions(memoryDir, rotation) {
|
|
460
|
+
await drainPendingImpressionsForOfflineSync(
|
|
461
|
+
() => new LastRecallStore(memoryDir, {
|
|
462
|
+
impressionsRotateBytes: rotation.impressionsRotateBytes,
|
|
463
|
+
impressionsRotateKeep: rotation.impressionsRotateKeep
|
|
464
|
+
}).drainPendingImpressions()
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// src/offline-storage-io.ts
|
|
469
|
+
import { mkdtemp, readdir, lstat, rm } from "fs/promises";
|
|
470
|
+
import fs3 from "fs";
|
|
471
|
+
import path from "path";
|
|
472
|
+
import { createHash, createDecipheriv } from "crypto";
|
|
473
|
+
import {
|
|
474
|
+
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
|
|
475
|
+
StorageManager
|
|
476
|
+
} from "@remnic/core";
|
|
477
|
+
import { OFFLINE_DECRYPT_STAGING_DIR_PREFIX } from "@remnic/core/offline-sync-exclude-globs";
|
|
478
|
+
import {
|
|
479
|
+
AUTH_TAG_LENGTH,
|
|
480
|
+
ENVELOPE_HEADER_SIZE,
|
|
481
|
+
ENVELOPE_LAYOUT,
|
|
482
|
+
ENVELOPE_SALT_LENGTH,
|
|
483
|
+
ENVELOPE_VERSION,
|
|
484
|
+
FILE_FORMAT_FLAGS,
|
|
485
|
+
FILE_FORMAT_VERSION,
|
|
486
|
+
IV_LENGTH,
|
|
487
|
+
MAGIC_BYTES,
|
|
488
|
+
MAGIC_HEADER_SIZE,
|
|
489
|
+
SecureStoreLockedError,
|
|
490
|
+
filePathAad,
|
|
491
|
+
isEncryptedFile,
|
|
492
|
+
keyring,
|
|
493
|
+
readHeader,
|
|
494
|
+
secureStoreDir
|
|
495
|
+
} from "@remnic/core/secure-store";
|
|
496
|
+
async function createConfiguredOfflineStorage(memoryDir, secureStoreEncryptOnWrite = true) {
|
|
497
|
+
const storage = new StorageManager(memoryDir);
|
|
498
|
+
const header = await readHeader(memoryDir);
|
|
499
|
+
let secureStoreKey = null;
|
|
500
|
+
let secureStoreRequired = false;
|
|
501
|
+
if (header) {
|
|
502
|
+
secureStoreRequired = true;
|
|
503
|
+
storage.setSecureStoreRequired(true);
|
|
504
|
+
const key = keyring.getKey(secureStoreDir(memoryDir));
|
|
505
|
+
if (key) {
|
|
506
|
+
storage.setSecureStoreKey(key, secureStoreEncryptOnWrite);
|
|
507
|
+
secureStoreKey = key;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return { storage, secureStoreKey, secureStoreRequired };
|
|
511
|
+
}
|
|
512
|
+
function createOfflineStorageForPath(memoryDir, filePath, configured, secureStoreEncryptOnWrite) {
|
|
513
|
+
const memoryRoot = path.resolve(memoryDir);
|
|
514
|
+
const stateDir = path.dirname(filePath);
|
|
515
|
+
if (path.basename(stateDir) !== "state" || path.basename(filePath) !== "memory-lifecycle-ledger.jsonl") {
|
|
516
|
+
throw new Error(`invalid lifecycle ledger path: ${filePath}`);
|
|
517
|
+
}
|
|
518
|
+
const storageRoot = path.resolve(path.dirname(stateDir));
|
|
519
|
+
if (storageRoot !== memoryRoot && !storageRoot.startsWith(`${memoryRoot}${path.sep}`)) {
|
|
520
|
+
throw new Error(`lifecycle ledger path is outside the offline memory directory: ${filePath}`);
|
|
521
|
+
}
|
|
522
|
+
const storage = new StorageManager(storageRoot);
|
|
523
|
+
if (configured.secureStoreRequired) {
|
|
524
|
+
storage.setSecureStoreRequired(true);
|
|
525
|
+
}
|
|
526
|
+
if (configured.secureStoreKey) {
|
|
527
|
+
storage.setSecureStoreKey(configured.secureStoreKey, secureStoreEncryptOnWrite);
|
|
528
|
+
}
|
|
529
|
+
return storage;
|
|
530
|
+
}
|
|
531
|
+
async function createOfflineStorageIo(memoryDir, configuredStorage) {
|
|
532
|
+
await cleanupOrphanedOfflineDecryptStaging(memoryDir);
|
|
533
|
+
const { storage, secureStoreKey } = configuredStorage ?? await createConfiguredOfflineStorage(memoryDir);
|
|
534
|
+
return {
|
|
535
|
+
readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
|
|
536
|
+
readFileDigest: async ({ filePath }) => {
|
|
537
|
+
const hash = createHash("sha256");
|
|
538
|
+
let bytes = 0;
|
|
539
|
+
for await (const rawChunk of readOfflineSyncFileChunks({
|
|
540
|
+
filePath,
|
|
541
|
+
memoryDir,
|
|
542
|
+
secureStoreKey,
|
|
543
|
+
chunkSize: OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES
|
|
544
|
+
})) {
|
|
545
|
+
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
546
|
+
hash.update(chunk);
|
|
547
|
+
bytes += chunk.length;
|
|
548
|
+
}
|
|
549
|
+
return {
|
|
550
|
+
sha256: hash.digest("hex"),
|
|
551
|
+
bytes
|
|
552
|
+
};
|
|
553
|
+
},
|
|
554
|
+
readFileChunks: ({ filePath, chunkSize }) => readOfflineSyncFileChunks({
|
|
555
|
+
filePath,
|
|
556
|
+
memoryDir,
|
|
557
|
+
secureStoreKey,
|
|
558
|
+
chunkSize
|
|
559
|
+
}),
|
|
560
|
+
writeFile: async ({ filePath, content }) => storage.writeOfflineSyncFile(filePath, content),
|
|
561
|
+
writeStagingFile: async ({ filePath, content }) => storage.writeOfflineSyncStagingFile(filePath, content),
|
|
562
|
+
writeFileChunks: async ({ filePath, chunks }) => storage.writeOfflineSyncFileChunks(filePath, chunks),
|
|
563
|
+
deleteFile: async ({ filePath }) => storage.deleteOfflineSyncFile(filePath)
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
var OFFLINE_DECRYPT_STAGING_ORPHAN_MS = 60 * 60 * 1e3;
|
|
567
|
+
async function cleanupOrphanedOfflineDecryptStaging(memoryDir) {
|
|
568
|
+
let entries;
|
|
569
|
+
try {
|
|
570
|
+
entries = await readdir(memoryDir);
|
|
571
|
+
} catch {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
const now = Date.now();
|
|
575
|
+
for (const name of entries) {
|
|
576
|
+
if (!name.startsWith(OFFLINE_DECRYPT_STAGING_DIR_PREFIX)) continue;
|
|
577
|
+
const dir = path.join(memoryDir, name);
|
|
578
|
+
try {
|
|
579
|
+
const info = await lstat(dir);
|
|
580
|
+
if (!info.isDirectory() || info.isSymbolicLink()) continue;
|
|
581
|
+
if (now - info.mtimeMs < OFFLINE_DECRYPT_STAGING_ORPHAN_MS) continue;
|
|
582
|
+
await rm(dir, { recursive: true, force: true });
|
|
583
|
+
} catch {
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
async function* readOfflineSyncFileChunks(options) {
|
|
588
|
+
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE);
|
|
589
|
+
if (!isEncryptedFile(header)) {
|
|
590
|
+
yield* readPlainOfflineFileChunks(options.filePath, options.chunkSize);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
if (!options.secureStoreKey) {
|
|
594
|
+
throw new SecureStoreLockedError(
|
|
595
|
+
`secure-store is locked \u2014 cannot read encrypted file at ${options.filePath}. Run \`remnic secure-store unlock\` to decrypt.`
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
yield* readEncryptedOfflineFileChunks({
|
|
599
|
+
filePath: options.filePath,
|
|
600
|
+
memoryDir: options.memoryDir,
|
|
601
|
+
key: options.secureStoreKey,
|
|
602
|
+
chunkSize: options.chunkSize
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
async function readFilePrefix(filePath, length) {
|
|
606
|
+
const handle = await fs3.promises.open(filePath, "r");
|
|
607
|
+
try {
|
|
608
|
+
const out = Buffer.alloc(length);
|
|
609
|
+
const { bytesRead } = await handle.read(out, 0, length, 0);
|
|
610
|
+
return out.subarray(0, bytesRead);
|
|
611
|
+
} finally {
|
|
612
|
+
await handle.close();
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async function* readPlainOfflineFileChunks(filePath, chunkSize) {
|
|
616
|
+
const stream = fs3.createReadStream(filePath, { highWaterMark: chunkSize });
|
|
617
|
+
for await (const chunk of stream) {
|
|
618
|
+
yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
async function* readEncryptedOfflineFileChunks(options) {
|
|
622
|
+
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
|
|
623
|
+
if (header.length < MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE || !isEncryptedFile(header)) {
|
|
624
|
+
throw new Error(`secure-store encrypted file is truncated: ${options.filePath}`);
|
|
625
|
+
}
|
|
626
|
+
const version = header.readUInt8(MAGIC_BYTES.length);
|
|
627
|
+
const flags = header.readUInt8(MAGIC_BYTES.length + 1);
|
|
628
|
+
if (version !== FILE_FORMAT_VERSION) {
|
|
629
|
+
throw new Error(`secure-store file has unsupported version ${version}: ${options.filePath}`);
|
|
630
|
+
}
|
|
631
|
+
if (flags !== FILE_FORMAT_FLAGS) {
|
|
632
|
+
throw new Error(`secure-store file has unsupported flags 0x${flags.toString(16)}: ${options.filePath}`);
|
|
633
|
+
}
|
|
634
|
+
const envelopeHeader = header.subarray(MAGIC_HEADER_SIZE);
|
|
635
|
+
const envelopeVersion = envelopeHeader.readUInt8(ENVELOPE_LAYOUT.version);
|
|
636
|
+
if (envelopeVersion !== ENVELOPE_VERSION) {
|
|
637
|
+
throw new Error(`secure-store envelope has unsupported version ${envelopeVersion}: ${options.filePath}`);
|
|
638
|
+
}
|
|
639
|
+
const salt = envelopeHeader.subarray(
|
|
640
|
+
ENVELOPE_LAYOUT.salt,
|
|
641
|
+
ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH
|
|
642
|
+
);
|
|
643
|
+
const iv = envelopeHeader.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);
|
|
644
|
+
const authTag = envelopeHeader.subarray(
|
|
645
|
+
ENVELOPE_LAYOUT.authTag,
|
|
646
|
+
ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
|
|
647
|
+
);
|
|
648
|
+
const aadCandidates = offlineFileAadCandidates(options.filePath, options.memoryDir);
|
|
649
|
+
let lastError;
|
|
650
|
+
for (const aad of aadCandidates) {
|
|
651
|
+
const tempDir = await mkdtemp(path.join(options.memoryDir, OFFLINE_DECRYPT_STAGING_DIR_PREFIX));
|
|
652
|
+
const tempPath = path.join(tempDir, "content");
|
|
653
|
+
try {
|
|
654
|
+
const decipher = createDecipheriv("aes-256-gcm", options.key, iv, {
|
|
655
|
+
authTagLength: AUTH_TAG_LENGTH
|
|
656
|
+
});
|
|
657
|
+
decipher.setAuthTag(authTag);
|
|
658
|
+
decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), aad]));
|
|
659
|
+
const output = fs3.createWriteStream(tempPath, { mode: 384 });
|
|
660
|
+
try {
|
|
661
|
+
const stream = fs3.createReadStream(options.filePath, {
|
|
662
|
+
start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
|
|
663
|
+
highWaterMark: options.chunkSize
|
|
664
|
+
});
|
|
665
|
+
for await (const encryptedChunk of stream) {
|
|
666
|
+
const plain = decipher.update(
|
|
667
|
+
Buffer.isBuffer(encryptedChunk) ? encryptedChunk : Buffer.from(encryptedChunk)
|
|
668
|
+
);
|
|
669
|
+
if (plain.length > 0 && !output.write(plain)) {
|
|
670
|
+
await new Promise((resolve, reject) => {
|
|
671
|
+
output.once("drain", resolve);
|
|
672
|
+
output.once("error", reject);
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
const finalPlain = decipher.final();
|
|
677
|
+
if (finalPlain.length > 0 && !output.write(finalPlain)) {
|
|
678
|
+
await new Promise((resolve, reject) => {
|
|
679
|
+
output.once("drain", resolve);
|
|
680
|
+
output.once("error", reject);
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
} finally {
|
|
684
|
+
await closeWriteStream(output);
|
|
685
|
+
}
|
|
686
|
+
yield* readPlainOfflineFileChunks(tempPath, options.chunkSize);
|
|
687
|
+
return;
|
|
688
|
+
} catch (error) {
|
|
689
|
+
lastError = error;
|
|
690
|
+
} finally {
|
|
691
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
692
|
+
}
|
|
175
693
|
}
|
|
694
|
+
throw lastError instanceof Error ? lastError : new Error(`secure-store could not decrypt file: ${options.filePath}`);
|
|
176
695
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
696
|
+
function offlineFileAadCandidates(filePath, memoryDir) {
|
|
697
|
+
const candidates = [filePathAad(filePath, memoryDir)];
|
|
698
|
+
const relative = path.relative(memoryDir, filePath);
|
|
699
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return candidates;
|
|
700
|
+
const parts = relative.split(path.sep);
|
|
701
|
+
if (parts[0] === "namespaces" && parts.length >= 3 && parts[1]) {
|
|
702
|
+
candidates.push(filePathAad(filePath, path.join(memoryDir, "namespaces", parts[1])));
|
|
180
703
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
);
|
|
704
|
+
const memoryParts = path.resolve(memoryDir).split(path.sep);
|
|
705
|
+
if (memoryParts.length >= 3 && memoryParts.at(-2) === "namespaces" && memoryParts.at(-1)) {
|
|
706
|
+
const topLevelRoot = memoryParts.slice(0, -2).join(path.sep) || path.sep;
|
|
707
|
+
const topRelative = path.relative(topLevelRoot, filePath);
|
|
708
|
+
if (topRelative && !topRelative.startsWith("..") && !path.isAbsolute(topRelative) && topRelative.split(path.sep)[0] === "namespaces" && topRelative.split(path.sep)[1] === memoryParts.at(-1)) {
|
|
709
|
+
candidates.push(filePathAad(filePath, topLevelRoot));
|
|
710
|
+
}
|
|
185
711
|
}
|
|
186
|
-
return
|
|
712
|
+
return candidates;
|
|
713
|
+
}
|
|
714
|
+
async function closeWriteStream(stream) {
|
|
715
|
+
await new Promise((resolve, reject) => {
|
|
716
|
+
stream.once("error", reject);
|
|
717
|
+
stream.end(() => resolve());
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
function secureStoreEnvelopeHeaderAad(salt) {
|
|
721
|
+
const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
|
|
722
|
+
out.writeUInt8(ENVELOPE_VERSION, 0);
|
|
723
|
+
Buffer.from(salt).copy(out, 1);
|
|
724
|
+
return out;
|
|
187
725
|
}
|
|
188
726
|
|
|
189
727
|
// src/bench-build-freshness.ts
|
|
190
728
|
import {
|
|
191
|
-
existsSync,
|
|
729
|
+
existsSync as existsSync2,
|
|
192
730
|
lstatSync,
|
|
193
731
|
readdirSync,
|
|
194
|
-
readFileSync,
|
|
732
|
+
readFileSync as readFileSync2,
|
|
195
733
|
statSync
|
|
196
734
|
} from "fs";
|
|
197
|
-
import
|
|
735
|
+
import path2 from "path";
|
|
198
736
|
import { fileURLToPath } from "url";
|
|
199
737
|
var STALE_BUILD_TOLERANCE_MS = 1e3;
|
|
200
738
|
function assertLocalBenchBuildFreshForDevelopment(currentModuleUrl) {
|
|
201
739
|
if (isTruthyEnv(process.env.REMNIC_BENCH_ALLOW_STALE_DIST)) {
|
|
202
740
|
return;
|
|
203
741
|
}
|
|
204
|
-
const currentDir =
|
|
205
|
-
const benchPackageDir =
|
|
742
|
+
const currentDir = path2.dirname(fileURLToPath(currentModuleUrl));
|
|
743
|
+
const benchPackageDir = path2.resolve(currentDir, "../../bench");
|
|
206
744
|
const freshness = checkBenchBuildFreshness(benchPackageDir);
|
|
207
745
|
if (!freshness.stale) {
|
|
208
746
|
return;
|
|
@@ -219,31 +757,31 @@ function assertLocalBenchBuildFreshForDevelopment(currentModuleUrl) {
|
|
|
219
757
|
);
|
|
220
758
|
}
|
|
221
759
|
function checkBenchBuildFreshness(benchPackageDir) {
|
|
222
|
-
const packageJsonPath =
|
|
223
|
-
if (!
|
|
760
|
+
const packageJsonPath = path2.join(benchPackageDir, "package.json");
|
|
761
|
+
if (!existsSync2(packageJsonPath)) {
|
|
224
762
|
return { stale: false };
|
|
225
763
|
}
|
|
226
764
|
let packageName;
|
|
227
765
|
try {
|
|
228
|
-
packageName = JSON.parse(
|
|
766
|
+
packageName = JSON.parse(readFileSync2(packageJsonPath, "utf8")).name;
|
|
229
767
|
} catch {
|
|
230
768
|
return { stale: false };
|
|
231
769
|
}
|
|
232
770
|
if (packageName !== "@remnic/bench") {
|
|
233
771
|
return { stale: false };
|
|
234
772
|
}
|
|
235
|
-
const srcDir =
|
|
773
|
+
const srcDir = path2.join(benchPackageDir, "src");
|
|
236
774
|
if (!isDirectory(srcDir)) {
|
|
237
775
|
return { stale: false };
|
|
238
776
|
}
|
|
239
777
|
const sourceRoots = [
|
|
240
778
|
srcDir,
|
|
241
779
|
packageJsonPath,
|
|
242
|
-
|
|
243
|
-
|
|
780
|
+
path2.join(benchPackageDir, "tsup.config.ts"),
|
|
781
|
+
path2.join(benchPackageDir, "tsconfig.json")
|
|
244
782
|
];
|
|
245
|
-
const distPath =
|
|
246
|
-
if (!
|
|
783
|
+
const distPath = path2.join(benchPackageDir, "dist", "index.js");
|
|
784
|
+
if (!existsSync2(distPath)) {
|
|
247
785
|
return {
|
|
248
786
|
stale: true,
|
|
249
787
|
reason: `Missing build output: ${distPath}`,
|
|
@@ -276,7 +814,7 @@ function checkBenchBuildFreshness(benchPackageDir) {
|
|
|
276
814
|
function newestMtime(roots) {
|
|
277
815
|
let newest;
|
|
278
816
|
const visit = (entryPath) => {
|
|
279
|
-
if (!
|
|
817
|
+
if (!existsSync2(entryPath)) {
|
|
280
818
|
return;
|
|
281
819
|
}
|
|
282
820
|
const stat = lstatSync(entryPath);
|
|
@@ -285,7 +823,7 @@ function newestMtime(roots) {
|
|
|
285
823
|
}
|
|
286
824
|
if (stat.isDirectory()) {
|
|
287
825
|
for (const child of readdirSync(entryPath)) {
|
|
288
|
-
visit(
|
|
826
|
+
visit(path2.join(entryPath, child));
|
|
289
827
|
}
|
|
290
828
|
return;
|
|
291
829
|
}
|
|
@@ -317,19 +855,19 @@ function isTruthyEnv(value) {
|
|
|
317
855
|
}
|
|
318
856
|
|
|
319
857
|
// src/optional-bench.ts
|
|
320
|
-
import { existsSync as
|
|
321
|
-
import
|
|
858
|
+
import { existsSync as existsSync3 } from "fs";
|
|
859
|
+
import path3 from "path";
|
|
322
860
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
323
861
|
var SPECIFIER2 = "@remnic/bench";
|
|
324
862
|
var TSX_ESM_API_SPECIFIER = "tsx/esm/api";
|
|
325
863
|
var cached2;
|
|
326
864
|
var cachedFromLocalWorkspaceBenchSource = false;
|
|
327
865
|
function resolveLocalWorkspaceBenchPaths() {
|
|
328
|
-
const currentDir =
|
|
329
|
-
const benchPackageDir =
|
|
866
|
+
const currentDir = path3.dirname(fileURLToPath2(import.meta.url));
|
|
867
|
+
const benchPackageDir = path3.resolve(currentDir, "../../bench");
|
|
330
868
|
return {
|
|
331
|
-
distEntry:
|
|
332
|
-
sourceEntry:
|
|
869
|
+
distEntry: path3.join(benchPackageDir, "dist", "index.js"),
|
|
870
|
+
sourceEntry: path3.join(benchPackageDir, "src", "index.ts")
|
|
333
871
|
};
|
|
334
872
|
}
|
|
335
873
|
async function tryImportLocalWorkspaceBenchSource(err) {
|
|
@@ -337,7 +875,7 @@ async function tryImportLocalWorkspaceBenchSource(err) {
|
|
|
337
875
|
return null;
|
|
338
876
|
}
|
|
339
877
|
const { sourceEntry } = resolveLocalWorkspaceBenchPaths();
|
|
340
|
-
if (!
|
|
878
|
+
if (!existsSync3(sourceEntry)) {
|
|
341
879
|
return null;
|
|
342
880
|
}
|
|
343
881
|
const { tsImport } = await import(TSX_ESM_API_SPECIFIER);
|
|
@@ -355,7 +893,7 @@ function isMissingLocalWorkspaceBenchDistError(err) {
|
|
|
355
893
|
return false;
|
|
356
894
|
}
|
|
357
895
|
const { distEntry, sourceEntry } = resolveLocalWorkspaceBenchPaths();
|
|
358
|
-
if (
|
|
896
|
+
if (existsSync3(distEntry) || !existsSync3(sourceEntry)) {
|
|
359
897
|
return false;
|
|
360
898
|
}
|
|
361
899
|
const message = err.message;
|
|
@@ -416,8 +954,8 @@ function assertBenchModuleFreshForDevelopment() {
|
|
|
416
954
|
}
|
|
417
955
|
|
|
418
956
|
// src/daemon-service-candidates.ts
|
|
419
|
-
import
|
|
420
|
-
import
|
|
957
|
+
import fs4 from "fs";
|
|
958
|
+
import path4 from "path";
|
|
421
959
|
var LAUNCHD_LABEL = "ai.remnic.daemon";
|
|
422
960
|
var LEGACY_REMNIC_SERVER_LAUNCHD_LABEL = "ai.remnic.server";
|
|
423
961
|
var LEGACY_LAUNCHD_LABEL = "ai.engram.daemon";
|
|
@@ -430,15 +968,15 @@ var SYSTEMD_SERVICE = "remnic.service";
|
|
|
430
968
|
var LEGACY_SYSTEMD_SERVICE = "engram.service";
|
|
431
969
|
var SYSTEMD_SERVICE_CANDIDATES = [SYSTEMD_SERVICE, LEGACY_SYSTEMD_SERVICE];
|
|
432
970
|
function launchdPlistPaths(homeDir) {
|
|
433
|
-
return LAUNCHD_LABEL_CANDIDATES.map((label) =>
|
|
971
|
+
return LAUNCHD_LABEL_CANDIDATES.map((label) => path4.join(homeDir, "Library", "LaunchAgents", `${label}.plist`));
|
|
434
972
|
}
|
|
435
973
|
function systemdUnitPaths(homeDir) {
|
|
436
|
-
return SYSTEMD_SERVICE_CANDIDATES.map((service) =>
|
|
974
|
+
return SYSTEMD_SERVICE_CANDIDATES.map((service) => path4.join(homeDir, ".config", "systemd", "user", service));
|
|
437
975
|
}
|
|
438
976
|
function anyFileExists(paths) {
|
|
439
977
|
return paths.some((candidate) => {
|
|
440
978
|
try {
|
|
441
|
-
return
|
|
979
|
+
return fs4.statSync(candidate).isFile();
|
|
442
980
|
} catch {
|
|
443
981
|
return false;
|
|
444
982
|
}
|
|
@@ -450,7 +988,7 @@ function commandNames(command) {
|
|
|
450
988
|
}
|
|
451
989
|
function isRunnableNodeScript(filePath) {
|
|
452
990
|
try {
|
|
453
|
-
const text =
|
|
991
|
+
const text = fs4.readFileSync(filePath, "utf8").slice(0, 4096);
|
|
454
992
|
const firstLine = text.split(/\r?\n/, 1)[0] ?? "";
|
|
455
993
|
if (/^#!.*\bnode\b/.test(firstLine)) return true;
|
|
456
994
|
if (firstLine.startsWith("#!")) return false;
|
|
@@ -463,20 +1001,20 @@ function isRunnableNodeScript(filePath) {
|
|
|
463
1001
|
function resolveShimNodeScript(filePath) {
|
|
464
1002
|
let text;
|
|
465
1003
|
try {
|
|
466
|
-
text =
|
|
1004
|
+
text = fs4.readFileSync(filePath, "utf8").slice(0, 16384);
|
|
467
1005
|
} catch {
|
|
468
1006
|
return void 0;
|
|
469
1007
|
}
|
|
470
|
-
const basedir =
|
|
1008
|
+
const basedir = path4.dirname(filePath);
|
|
471
1009
|
const jsReferencePattern = /"([^"]+\.js)"|'([^']+\.js)'|([^\s"'`]+\.js)/g;
|
|
472
1010
|
for (const match of text.matchAll(jsReferencePattern)) {
|
|
473
1011
|
const raw = match[1] ?? match[2] ?? match[3];
|
|
474
1012
|
if (!raw) continue;
|
|
475
1013
|
const candidate = raw.replaceAll("${basedir}", basedir).replaceAll("$basedir", basedir).replaceAll("\\ ", " ");
|
|
476
|
-
const resolved =
|
|
1014
|
+
const resolved = path4.isAbsolute(candidate) ? candidate : path4.resolve(basedir, candidate);
|
|
477
1015
|
try {
|
|
478
|
-
if (
|
|
479
|
-
return
|
|
1016
|
+
if (fs4.statSync(resolved).isFile() && isRunnableNodeScript(resolved)) {
|
|
1017
|
+
return fs4.realpathSync(resolved);
|
|
480
1018
|
}
|
|
481
1019
|
} catch {
|
|
482
1020
|
}
|
|
@@ -484,19 +1022,19 @@ function resolveShimNodeScript(filePath) {
|
|
|
484
1022
|
return void 0;
|
|
485
1023
|
}
|
|
486
1024
|
function resolveRunnableNodeScript(filePath) {
|
|
487
|
-
const realPath =
|
|
1025
|
+
const realPath = fs4.realpathSync(filePath);
|
|
488
1026
|
if (isRunnableNodeScript(realPath)) return realPath;
|
|
489
1027
|
return resolveShimNodeScript(realPath);
|
|
490
1028
|
}
|
|
491
1029
|
function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
|
|
492
|
-
for (const dir of pathEnv.split(
|
|
1030
|
+
for (const dir of pathEnv.split(path4.delimiter)) {
|
|
493
1031
|
if (!dir) continue;
|
|
494
1032
|
for (const name of commandNames(command)) {
|
|
495
|
-
const candidate =
|
|
1033
|
+
const candidate = path4.join(dir, name);
|
|
496
1034
|
try {
|
|
497
|
-
const stat =
|
|
1035
|
+
const stat = fs4.statSync(candidate);
|
|
498
1036
|
if (!stat.isFile()) continue;
|
|
499
|
-
if (process.platform !== "win32")
|
|
1037
|
+
if (process.platform !== "win32") fs4.accessSync(candidate, fs4.constants.X_OK);
|
|
500
1038
|
const runnable = resolveRunnableNodeScript(candidate);
|
|
501
1039
|
if (runnable) return runnable;
|
|
502
1040
|
} catch {
|
|
@@ -506,11 +1044,11 @@ function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
|
|
|
506
1044
|
return void 0;
|
|
507
1045
|
}
|
|
508
1046
|
function serverBinWrapperRequiredPath(candidate) {
|
|
509
|
-
const filename =
|
|
1047
|
+
const filename = path4.basename(candidate);
|
|
510
1048
|
if (filename !== "remnic-server.js" && filename !== "engram-server.js") return void 0;
|
|
511
|
-
const binDir =
|
|
512
|
-
if (
|
|
513
|
-
return
|
|
1049
|
+
const binDir = path4.dirname(candidate);
|
|
1050
|
+
if (path4.basename(binDir) !== "bin") return void 0;
|
|
1051
|
+
return path4.join(path4.dirname(binDir), "dist", "index.js");
|
|
514
1052
|
}
|
|
515
1053
|
|
|
516
1054
|
// src/service-candidates.ts
|
|
@@ -532,7 +1070,7 @@ function firstSuccessfulCandidate(candidates, attempt) {
|
|
|
532
1070
|
}
|
|
533
1071
|
|
|
534
1072
|
// src/bench-args.ts
|
|
535
|
-
import
|
|
1073
|
+
import path5 from "path";
|
|
536
1074
|
|
|
537
1075
|
// src/path-utils.ts
|
|
538
1076
|
function resolveHomeDir() {
|
|
@@ -1632,13 +2170,13 @@ function parseBenchArgs(argv) {
|
|
|
1632
2170
|
mcpUrl,
|
|
1633
2171
|
mcpToolMap,
|
|
1634
2172
|
mcpDemo,
|
|
1635
|
-
datasetDir: datasetDir ?
|
|
1636
|
-
resultsDir: resultsDir ?
|
|
1637
|
-
baselinesDir: baselinesDir ?
|
|
2173
|
+
datasetDir: datasetDir ? path5.resolve(expandTilde(datasetDir)) : void 0,
|
|
2174
|
+
resultsDir: resultsDir ? path5.resolve(expandTilde(resultsDir)) : void 0,
|
|
2175
|
+
baselinesDir: baselinesDir ? path5.resolve(expandTilde(baselinesDir)) : void 0,
|
|
1638
2176
|
runtimeProfile,
|
|
1639
2177
|
matrixProfiles,
|
|
1640
|
-
remnicConfigPath: remnicConfigRaw ?
|
|
1641
|
-
openclawConfigPath: openclawConfigRaw ?
|
|
2178
|
+
remnicConfigPath: remnicConfigRaw ? path5.resolve(expandTilde(remnicConfigRaw)) : void 0,
|
|
2179
|
+
openclawConfigPath: openclawConfigRaw ? path5.resolve(expandTilde(openclawConfigRaw)) : void 0,
|
|
1642
2180
|
modelSource,
|
|
1643
2181
|
gatewayAgentId,
|
|
1644
2182
|
fastGatewayAgentId,
|
|
@@ -1661,13 +2199,13 @@ function parseBenchArgs(argv) {
|
|
|
1661
2199
|
internalDisableThinking: args.includes("--internal-disable-thinking"),
|
|
1662
2200
|
internalCodexReasoningEffort,
|
|
1663
2201
|
threshold,
|
|
1664
|
-
custom: customRaw ?
|
|
2202
|
+
custom: customRaw ? path5.resolve(expandTilde(customRaw)) : void 0,
|
|
1665
2203
|
baselineAction,
|
|
1666
2204
|
datasetAction,
|
|
1667
2205
|
providerAction,
|
|
1668
2206
|
runAction,
|
|
1669
2207
|
format,
|
|
1670
|
-
output: output ?
|
|
2208
|
+
output: output ? path5.resolve(expandTilde(output)) : void 0,
|
|
1671
2209
|
target,
|
|
1672
2210
|
publishedName,
|
|
1673
2211
|
publishedSeed,
|
|
@@ -1677,24 +2215,24 @@ function parseBenchArgs(argv) {
|
|
|
1677
2215
|
publishedIngestConcurrency,
|
|
1678
2216
|
publishedTaskFilter,
|
|
1679
2217
|
memcorrectAdapter,
|
|
1680
|
-
publishedOut: publishedOutRaw ?
|
|
2218
|
+
publishedOut: publishedOutRaw ? path5.resolve(expandTilde(publishedOutRaw)) : void 0,
|
|
1681
2219
|
publishedDryRun: args.includes("--dry-run"),
|
|
1682
2220
|
requestTimeout,
|
|
1683
2221
|
localJudgeRequestTimeout,
|
|
1684
2222
|
frontierJudgeRequestTimeout,
|
|
1685
|
-
calibrationDir: calibrationDirRaw ?
|
|
2223
|
+
calibrationDir: calibrationDirRaw ? path5.resolve(expandTilde(calibrationDirRaw)) : void 0,
|
|
1686
2224
|
calibrationLocalConfigSha256,
|
|
1687
2225
|
calibrationFrontierConfigSha256,
|
|
1688
2226
|
sourceResultId,
|
|
1689
2227
|
expectedAnswerSetSha256,
|
|
1690
2228
|
expectedQuestionIdListSha256,
|
|
1691
|
-
taskIdsFile: taskIdsFileRaw ?
|
|
2229
|
+
taskIdsFile: taskIdsFileRaw ? path5.resolve(expandTilde(taskIdsFileRaw)) : void 0,
|
|
1692
2230
|
expectedTaskIdListSha256,
|
|
1693
2231
|
drainTimeout,
|
|
1694
2232
|
// Issue #1573 PR1: surface judge-cache flags into the runner options.
|
|
1695
2233
|
noJudgeCache: args.includes("--no-judge-cache"),
|
|
1696
|
-
judgeCacheDir: judgeCacheDirRaw ?
|
|
1697
|
-
localLabManifestPath: localLabManifestRaw ?
|
|
2234
|
+
judgeCacheDir: judgeCacheDirRaw ? path5.resolve(expandTilde(judgeCacheDirRaw)) : void 0,
|
|
2235
|
+
localLabManifestPath: localLabManifestRaw ? path5.resolve(expandTilde(localLabManifestRaw)) : void 0,
|
|
1698
2236
|
max429WaitMs,
|
|
1699
2237
|
disableThinking: args.includes("--disable-thinking"),
|
|
1700
2238
|
amaBenchJudgeProtocol,
|
|
@@ -1709,23 +2247,23 @@ function parseBenchArgs(argv) {
|
|
|
1709
2247
|
}
|
|
1710
2248
|
|
|
1711
2249
|
// src/bench-status.ts
|
|
1712
|
-
import { mkdir, readFile, readdir, rename, writeFile } from "fs/promises";
|
|
1713
|
-
import
|
|
2250
|
+
import { mkdir, readFile, readdir as readdir2, rename, writeFile } from "fs/promises";
|
|
2251
|
+
import path6 from "path";
|
|
1714
2252
|
function createBenchStatusPath(resultsDir, pid, startedAtMs = Date.now()) {
|
|
1715
|
-
return
|
|
2253
|
+
return path6.join(resultsDir, `bench-status-${startedAtMs}-${pid}.json`);
|
|
1716
2254
|
}
|
|
1717
2255
|
var BENCH_STATUS_FILENAME = /^bench-status-\d+-\d+\.json$/;
|
|
1718
2256
|
var VALID_BENCH_ENTRY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "complete", "failed"]);
|
|
1719
2257
|
async function findLatestBenchStatusFile(resultsDir) {
|
|
1720
2258
|
let entries;
|
|
1721
2259
|
try {
|
|
1722
|
-
entries = await
|
|
2260
|
+
entries = await readdir2(resultsDir);
|
|
1723
2261
|
} catch {
|
|
1724
2262
|
return null;
|
|
1725
2263
|
}
|
|
1726
2264
|
const candidates = entries.filter((name) => BENCH_STATUS_FILENAME.test(name)).sort().reverse();
|
|
1727
2265
|
for (const name of candidates) {
|
|
1728
|
-
const filePath =
|
|
2266
|
+
const filePath = path6.join(resultsDir, name);
|
|
1729
2267
|
const status = await readBenchStatus(filePath);
|
|
1730
2268
|
if (status) {
|
|
1731
2269
|
return filePath;
|
|
@@ -1734,7 +2272,7 @@ async function findLatestBenchStatusFile(resultsDir) {
|
|
|
1734
2272
|
return null;
|
|
1735
2273
|
}
|
|
1736
2274
|
async function atomicWriteJSON(filePath, data) {
|
|
1737
|
-
await mkdir(
|
|
2275
|
+
await mkdir(path6.dirname(filePath), { recursive: true });
|
|
1738
2276
|
const tmp = `${filePath}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;
|
|
1739
2277
|
await writeFile(tmp, JSON.stringify(data, null, 2) + "\n");
|
|
1740
2278
|
await rename(tmp, filePath);
|
|
@@ -1851,8 +2389,8 @@ function finalizeBenchStatus(filePath) {
|
|
|
1851
2389
|
}
|
|
1852
2390
|
|
|
1853
2391
|
// src/bench-fallback.ts
|
|
1854
|
-
import
|
|
1855
|
-
import
|
|
2392
|
+
import fs5 from "fs";
|
|
2393
|
+
import path7 from "path";
|
|
1856
2394
|
var FALLBACK_RESULTS_DIRNAME = "fallback-runs";
|
|
1857
2395
|
function buildBenchRunnerArgs(parsed, benchmarkId, outputDir) {
|
|
1858
2396
|
const args = ["--benchmark", benchmarkId];
|
|
@@ -1916,34 +2454,34 @@ function findUnsupportedFallbackBenchOptions(parsed) {
|
|
|
1916
2454
|
return unsupported;
|
|
1917
2455
|
}
|
|
1918
2456
|
function createFallbackBenchOutputDir(resultsDir, benchmarkId, pid, startedAtMs = Date.now()) {
|
|
1919
|
-
return
|
|
2457
|
+
return path7.join(
|
|
1920
2458
|
resultsDir,
|
|
1921
2459
|
FALLBACK_RESULTS_DIRNAME,
|
|
1922
2460
|
`${benchmarkId}-${startedAtMs}-${pid}`
|
|
1923
2461
|
);
|
|
1924
2462
|
}
|
|
1925
2463
|
function resolveFallbackBenchResultPath(outputDir) {
|
|
1926
|
-
const entries =
|
|
2464
|
+
const entries = fs5.readdirSync(outputDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
|
|
1927
2465
|
if (entries.length === 0) {
|
|
1928
2466
|
throw new Error(`Fallback benchmark runner did not write a JSON result artifact in ${outputDir}`);
|
|
1929
2467
|
}
|
|
1930
|
-
return
|
|
2468
|
+
return path7.join(outputDir, entries[0]);
|
|
1931
2469
|
}
|
|
1932
2470
|
|
|
1933
2471
|
// src/openclaw-upgrade-swap.ts
|
|
1934
|
-
import
|
|
1935
|
-
import
|
|
2472
|
+
import fs6 from "fs";
|
|
2473
|
+
import path8 from "path";
|
|
1936
2474
|
function describeError(error) {
|
|
1937
2475
|
return error instanceof Error ? error.message : String(error);
|
|
1938
2476
|
}
|
|
1939
2477
|
function createSiblingTempFilePath(targetPath, label) {
|
|
1940
2478
|
const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
|
|
1941
|
-
return
|
|
2479
|
+
return path8.join(path8.dirname(targetPath), `.${path8.basename(targetPath)}.${label}.${nonce}.tmp`);
|
|
1942
2480
|
}
|
|
1943
2481
|
function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
1944
2482
|
if (explicitMode !== void 0) return explicitMode;
|
|
1945
2483
|
try {
|
|
1946
|
-
return
|
|
2484
|
+
return fs6.statSync(targetPath).mode & 4095;
|
|
1947
2485
|
} catch (error) {
|
|
1948
2486
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
1949
2487
|
return 384;
|
|
@@ -1953,8 +2491,8 @@ function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
|
1953
2491
|
}
|
|
1954
2492
|
function resolveAtomicReplacementPath(targetPath) {
|
|
1955
2493
|
try {
|
|
1956
|
-
if (
|
|
1957
|
-
return
|
|
2494
|
+
if (fs6.lstatSync(targetPath).isSymbolicLink()) {
|
|
2495
|
+
return fs6.realpathSync(targetPath);
|
|
1958
2496
|
}
|
|
1959
2497
|
} catch (error) {
|
|
1960
2498
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
@@ -1966,12 +2504,12 @@ function resolveAtomicReplacementPath(targetPath) {
|
|
|
1966
2504
|
}
|
|
1967
2505
|
function createSiblingSwapPath(targetDir, label) {
|
|
1968
2506
|
const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
|
|
1969
|
-
return
|
|
2507
|
+
return path8.join(path8.dirname(targetDir), `.${path8.basename(targetDir)}.${label}.${nonce}`);
|
|
1970
2508
|
}
|
|
1971
2509
|
function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
1972
2510
|
if (!displacedDir) return void 0;
|
|
1973
2511
|
try {
|
|
1974
|
-
|
|
2512
|
+
fs6.rmSync(displacedDir, { recursive: true, force: true });
|
|
1975
2513
|
return void 0;
|
|
1976
2514
|
} catch (error) {
|
|
1977
2515
|
return `Warning: ${context}, but failed to remove the displaced plugin copy at ${displacedDir}: ${describeError(error)}`;
|
|
@@ -1979,55 +2517,55 @@ function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
|
1979
2517
|
}
|
|
1980
2518
|
function atomicWriteFileSync(targetPath, data, options = {}) {
|
|
1981
2519
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
1982
|
-
|
|
2520
|
+
fs6.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
|
|
1983
2521
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "write");
|
|
1984
2522
|
const mode = resolveAtomicWriteMode(resolvedTargetPath, options.mode);
|
|
1985
2523
|
try {
|
|
1986
2524
|
if (options.hooks?.writeTempFileSync) {
|
|
1987
2525
|
options.hooks.writeTempFileSync(tempPath);
|
|
1988
2526
|
} else {
|
|
1989
|
-
|
|
2527
|
+
fs6.writeFileSync(tempPath, data, { mode });
|
|
1990
2528
|
}
|
|
1991
|
-
|
|
1992
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
2529
|
+
fs6.chmodSync(tempPath, mode);
|
|
2530
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs6.renameSync;
|
|
1993
2531
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
1994
2532
|
} catch (error) {
|
|
1995
|
-
|
|
2533
|
+
fs6.rmSync(tempPath, { force: true });
|
|
1996
2534
|
throw error;
|
|
1997
2535
|
}
|
|
1998
2536
|
}
|
|
1999
2537
|
function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
|
|
2000
|
-
if (!
|
|
2538
|
+
if (!fs6.existsSync(sourcePath)) return;
|
|
2001
2539
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
2002
|
-
|
|
2540
|
+
fs6.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
|
|
2003
2541
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "copy");
|
|
2004
|
-
const mode =
|
|
2542
|
+
const mode = fs6.statSync(sourcePath).mode & 4095;
|
|
2005
2543
|
try {
|
|
2006
|
-
const copyTempFileSync = options.hooks?.copyTempFileSync ??
|
|
2544
|
+
const copyTempFileSync = options.hooks?.copyTempFileSync ?? fs6.copyFileSync;
|
|
2007
2545
|
copyTempFileSync(sourcePath, tempPath);
|
|
2008
|
-
|
|
2009
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
2546
|
+
fs6.chmodSync(tempPath, mode);
|
|
2547
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs6.renameSync;
|
|
2010
2548
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
2011
2549
|
} catch (error) {
|
|
2012
|
-
|
|
2550
|
+
fs6.rmSync(tempPath, { force: true });
|
|
2013
2551
|
throw error;
|
|
2014
2552
|
}
|
|
2015
2553
|
}
|
|
2016
2554
|
function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
|
|
2017
2555
|
let hasRollbackCopy = false;
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
if (
|
|
2021
|
-
|
|
2556
|
+
fs6.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2557
|
+
fs6.rmSync(rollbackDir, { recursive: true, force: true });
|
|
2558
|
+
if (fs6.existsSync(targetDir)) {
|
|
2559
|
+
fs6.renameSync(targetDir, rollbackDir);
|
|
2022
2560
|
hasRollbackCopy = true;
|
|
2023
2561
|
}
|
|
2024
2562
|
try {
|
|
2025
|
-
|
|
2563
|
+
fs6.renameSync(stagedDir, targetDir);
|
|
2026
2564
|
} catch (swapError) {
|
|
2027
|
-
|
|
2028
|
-
if (hasRollbackCopy &&
|
|
2565
|
+
fs6.rmSync(targetDir, { recursive: true, force: true });
|
|
2566
|
+
if (hasRollbackCopy && fs6.existsSync(rollbackDir)) {
|
|
2029
2567
|
try {
|
|
2030
|
-
|
|
2568
|
+
fs6.renameSync(rollbackDir, targetDir);
|
|
2031
2569
|
hasRollbackCopy = false;
|
|
2032
2570
|
} catch (restoreError) {
|
|
2033
2571
|
throw new AggregateError(
|
|
@@ -2042,7 +2580,7 @@ function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
|
|
|
2042
2580
|
}
|
|
2043
2581
|
function cleanupRollbackDirectory(rollbackDir) {
|
|
2044
2582
|
if (!rollbackDir) return;
|
|
2045
|
-
|
|
2583
|
+
fs6.rmSync(rollbackDir, { recursive: true, force: true });
|
|
2046
2584
|
}
|
|
2047
2585
|
function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
2048
2586
|
if (!rollbackDir) return void 0;
|
|
@@ -2054,20 +2592,20 @@ function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
|
2054
2592
|
}
|
|
2055
2593
|
}
|
|
2056
2594
|
function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
2057
|
-
if (!
|
|
2595
|
+
if (!fs6.existsSync(rollbackDir)) {
|
|
2058
2596
|
throw new Error(`Rollback directory is missing: ${rollbackDir}`);
|
|
2059
2597
|
}
|
|
2060
|
-
|
|
2061
|
-
const displacedDir =
|
|
2598
|
+
fs6.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2599
|
+
const displacedDir = fs6.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
|
|
2062
2600
|
if (displacedDir) {
|
|
2063
|
-
|
|
2601
|
+
fs6.renameSync(targetDir, displacedDir);
|
|
2064
2602
|
}
|
|
2065
2603
|
try {
|
|
2066
|
-
|
|
2604
|
+
fs6.renameSync(rollbackDir, targetDir);
|
|
2067
2605
|
} catch (restoreError) {
|
|
2068
|
-
if (displacedDir &&
|
|
2606
|
+
if (displacedDir && fs6.existsSync(displacedDir)) {
|
|
2069
2607
|
try {
|
|
2070
|
-
|
|
2608
|
+
fs6.renameSync(displacedDir, targetDir);
|
|
2071
2609
|
} catch (revertError) {
|
|
2072
2610
|
throw new AggregateError(
|
|
2073
2611
|
[restoreError, revertError],
|
|
@@ -2086,23 +2624,23 @@ function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
|
2086
2624
|
);
|
|
2087
2625
|
}
|
|
2088
2626
|
function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
2089
|
-
if (!
|
|
2627
|
+
if (!fs6.existsSync(backupDir)) {
|
|
2090
2628
|
throw new Error(`Plugin backup directory is missing: ${backupDir}`);
|
|
2091
2629
|
}
|
|
2092
|
-
|
|
2630
|
+
fs6.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2093
2631
|
const stagedDir = createSiblingSwapPath(targetDir, "backup-restore");
|
|
2094
|
-
const displacedDir =
|
|
2095
|
-
|
|
2632
|
+
const displacedDir = fs6.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
|
|
2633
|
+
fs6.cpSync(backupDir, stagedDir, { recursive: true });
|
|
2096
2634
|
if (displacedDir) {
|
|
2097
|
-
|
|
2635
|
+
fs6.renameSync(targetDir, displacedDir);
|
|
2098
2636
|
}
|
|
2099
2637
|
try {
|
|
2100
|
-
|
|
2638
|
+
fs6.renameSync(stagedDir, targetDir);
|
|
2101
2639
|
} catch (restoreError) {
|
|
2102
|
-
|
|
2103
|
-
if (displacedDir &&
|
|
2640
|
+
fs6.rmSync(targetDir, { recursive: true, force: true });
|
|
2641
|
+
if (displacedDir && fs6.existsSync(displacedDir)) {
|
|
2104
2642
|
try {
|
|
2105
|
-
|
|
2643
|
+
fs6.renameSync(displacedDir, targetDir);
|
|
2106
2644
|
} catch (revertError) {
|
|
2107
2645
|
throw new AggregateError(
|
|
2108
2646
|
[restoreError, revertError],
|
|
@@ -2110,7 +2648,7 @@ function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
|
2110
2648
|
);
|
|
2111
2649
|
}
|
|
2112
2650
|
}
|
|
2113
|
-
|
|
2651
|
+
fs6.rmSync(stagedDir, { recursive: true, force: true });
|
|
2114
2652
|
throw new Error(
|
|
2115
2653
|
`Failed to restore the plugin backup into ${targetDir}. The durable backup remains preserved at ${backupDir}.`,
|
|
2116
2654
|
{ cause: restoreError }
|
|
@@ -2136,7 +2674,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2136
2674
|
let rollbackRestoreError;
|
|
2137
2675
|
let pluginRestored = false;
|
|
2138
2676
|
try {
|
|
2139
|
-
if (rollbackDir &&
|
|
2677
|
+
if (rollbackDir && fs6.existsSync(rollbackDir)) {
|
|
2140
2678
|
const cleanupWarning = restoreDirectoryFromRollback(pluginDir, rollbackDir);
|
|
2141
2679
|
notes.push(`Restored previous plugin from rollback copy at ${rollbackDir}`);
|
|
2142
2680
|
if (cleanupWarning) notes.push(cleanupWarning);
|
|
@@ -2146,7 +2684,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2146
2684
|
rollbackRestoreError = error instanceof Error ? error.message : String(error);
|
|
2147
2685
|
}
|
|
2148
2686
|
try {
|
|
2149
|
-
if (!pluginRestored && pluginBackupDir &&
|
|
2687
|
+
if (!pluginRestored && pluginBackupDir && fs6.existsSync(pluginBackupDir)) {
|
|
2150
2688
|
const cleanupWarning = restoreDirectoryFromBackup(pluginDir, pluginBackupDir);
|
|
2151
2689
|
if (rollbackRestoreError) {
|
|
2152
2690
|
notes.push(
|
|
@@ -2173,7 +2711,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2173
2711
|
notes.push("No previous plugin copy was available for automatic restore");
|
|
2174
2712
|
}
|
|
2175
2713
|
try {
|
|
2176
|
-
if (configBackupPath &&
|
|
2714
|
+
if (configBackupPath && fs6.existsSync(configBackupPath)) {
|
|
2177
2715
|
restoreFileFromBackup(configPath, configBackupPath);
|
|
2178
2716
|
notes.push(`Restored OpenClaw config from backup at ${configBackupPath}`);
|
|
2179
2717
|
}
|
|
@@ -2213,11 +2751,11 @@ Run this manually when you're ready:
|
|
|
2213
2751
|
}
|
|
2214
2752
|
|
|
2215
2753
|
// src/daemon-service.ts
|
|
2216
|
-
import
|
|
2217
|
-
import
|
|
2754
|
+
import fs7 from "fs";
|
|
2755
|
+
import path9 from "path";
|
|
2218
2756
|
import * as childProcess from "child_process";
|
|
2219
2757
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2220
|
-
var thisModuleDir =
|
|
2758
|
+
var thisModuleDir = path9.dirname(fileURLToPath3(import.meta.url));
|
|
2221
2759
|
function launchdLoadPlist(plistPath, processApi = childProcess) {
|
|
2222
2760
|
processApi.execFileSync("launchctl", ["load", "-w", plistPath], { stdio: "pipe" });
|
|
2223
2761
|
}
|
|
@@ -2225,7 +2763,7 @@ function launchdUnloadPlist(plistPath, processApi = childProcess) {
|
|
|
2225
2763
|
processApi.execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
|
|
2226
2764
|
}
|
|
2227
2765
|
function resolveServerBinDetails(options = {}) {
|
|
2228
|
-
const
|
|
2766
|
+
const existsSync4 = options.existsSync ?? fs7.existsSync;
|
|
2229
2767
|
const findCommandOnPath2 = options.findCommandOnPath ?? findCommandOnPath;
|
|
2230
2768
|
const moduleDir = options.moduleDir ?? thisModuleDir;
|
|
2231
2769
|
const packageResolve = options.packageResolve ?? resolveImportSpecifier;
|
|
@@ -2239,8 +2777,8 @@ function resolveServerBinDetails(options = {}) {
|
|
|
2239
2777
|
});
|
|
2240
2778
|
} catch {
|
|
2241
2779
|
}
|
|
2242
|
-
const workspaceServerBin =
|
|
2243
|
-
const workspaceDistIndex =
|
|
2780
|
+
const workspaceServerBin = path9.resolve(moduleDir, "../../remnic-server/bin/remnic-server.js");
|
|
2781
|
+
const workspaceDistIndex = path9.resolve(moduleDir, "../../remnic-server/dist/index.js");
|
|
2244
2782
|
candidates.push(
|
|
2245
2783
|
{
|
|
2246
2784
|
path: workspaceServerBin,
|
|
@@ -2261,15 +2799,15 @@ function resolveServerBinDetails(options = {}) {
|
|
|
2261
2799
|
});
|
|
2262
2800
|
}
|
|
2263
2801
|
candidates.push({
|
|
2264
|
-
path:
|
|
2802
|
+
path: path9.resolve(moduleDir, "../../remnic-server/src/index.ts"),
|
|
2265
2803
|
source: "workspace-source"
|
|
2266
2804
|
});
|
|
2267
|
-
const selected = candidates.find((candidate) => isCandidateReady(candidate,
|
|
2268
|
-
path:
|
|
2805
|
+
const selected = candidates.find((candidate) => isCandidateReady(candidate, existsSync4)) ?? candidates.find((candidate) => existsSync4(candidate.path)) ?? candidates[0] ?? {
|
|
2806
|
+
path: path9.resolve(moduleDir, "../../remnic-server/dist/index.js"),
|
|
2269
2807
|
source: "workspace-dist"
|
|
2270
2808
|
};
|
|
2271
|
-
const exists =
|
|
2272
|
-
const requiredExists = selected.requiredPath ?
|
|
2809
|
+
const exists = existsSync4(selected.path);
|
|
2810
|
+
const requiredExists = selected.requiredPath ? existsSync4(selected.requiredPath) : true;
|
|
2273
2811
|
const { requiredPath: _requiredPath, ...publicSelected } = selected;
|
|
2274
2812
|
return {
|
|
2275
2813
|
...publicSelected,
|
|
@@ -2277,22 +2815,22 @@ function resolveServerBinDetails(options = {}) {
|
|
|
2277
2815
|
loadableByNode: exists && requiredExists && !selected.path.endsWith(".ts")
|
|
2278
2816
|
};
|
|
2279
2817
|
}
|
|
2280
|
-
function isCandidateReady(candidate,
|
|
2281
|
-
return
|
|
2818
|
+
function isCandidateReady(candidate, existsSync4) {
|
|
2819
|
+
return existsSync4(candidate.path) && (candidate.requiredPath ? existsSync4(candidate.requiredPath) : true);
|
|
2282
2820
|
}
|
|
2283
2821
|
function resolveServerBin(options = {}) {
|
|
2284
2822
|
return resolveServerBinDetails(options).path;
|
|
2285
2823
|
}
|
|
2286
2824
|
function readVerifiedDaemonPid(options) {
|
|
2287
|
-
const
|
|
2288
|
-
const unlinkSync = options.unlinkSync ??
|
|
2825
|
+
const readFileSync4 = options.readFileSync ?? fs7.readFileSync;
|
|
2826
|
+
const unlinkSync = options.unlinkSync ?? fs7.unlinkSync;
|
|
2289
2827
|
const processKill = options.processKill ?? process.kill;
|
|
2290
2828
|
const platform = options.platform ?? process.platform;
|
|
2291
2829
|
const execFileSync3 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
|
|
2292
2830
|
for (const file of options.pidFiles) {
|
|
2293
2831
|
let pid;
|
|
2294
2832
|
try {
|
|
2295
|
-
pid = parseDaemonPid(
|
|
2833
|
+
pid = parseDaemonPid(readFileSync4(file, "utf8"));
|
|
2296
2834
|
} catch {
|
|
2297
2835
|
continue;
|
|
2298
2836
|
}
|
|
@@ -2320,7 +2858,7 @@ function readVerifiedDaemonPid(options) {
|
|
|
2320
2858
|
}
|
|
2321
2859
|
function doesProcessCommandLookLikeRemnicDaemon(command, expectedServerBin) {
|
|
2322
2860
|
const normalizedCommand = command.trim();
|
|
2323
|
-
const normalizedExpected =
|
|
2861
|
+
const normalizedExpected = path9.resolve(expandTilde(expectedServerBin));
|
|
2324
2862
|
return normalizedCommand.includes(normalizedExpected) || /(?:^|\s|[/\\])(?:remnic-server|engram-server)(?:\.js)?(?:\s|$)/.test(normalizedCommand) || /@remnic[/\\]server[/\\]/.test(normalizedCommand) || /packages[/\\]remnic-server[/\\](?:bin[/\\]remnic-server\.js|dist[/\\]index\.js|src[/\\]index\.ts)/.test(normalizedCommand);
|
|
2325
2863
|
}
|
|
2326
2864
|
function parseDaemonPid(raw) {
|
|
@@ -2385,9 +2923,9 @@ function removePidFileBestEffort(file, unlinkSync) {
|
|
|
2385
2923
|
}
|
|
2386
2924
|
}
|
|
2387
2925
|
function inspectLaunchdPlist(plistPath, options = {}) {
|
|
2388
|
-
const
|
|
2389
|
-
const
|
|
2390
|
-
if (!
|
|
2926
|
+
const existsSync4 = options.existsSync ?? fs7.existsSync;
|
|
2927
|
+
const readFileSync4 = options.readFileSync ?? fs7.readFileSync;
|
|
2928
|
+
if (!existsSync4(plistPath)) {
|
|
2391
2929
|
return {
|
|
2392
2930
|
installed: false,
|
|
2393
2931
|
ok: true,
|
|
@@ -2397,7 +2935,7 @@ function inspectLaunchdPlist(plistPath, options = {}) {
|
|
|
2397
2935
|
}
|
|
2398
2936
|
let content;
|
|
2399
2937
|
try {
|
|
2400
|
-
content =
|
|
2938
|
+
content = readFileSync4(plistPath, "utf8");
|
|
2401
2939
|
} catch {
|
|
2402
2940
|
return {
|
|
2403
2941
|
installed: true,
|
|
@@ -2425,7 +2963,7 @@ function inspectLaunchdPlist(plistPath, options = {}) {
|
|
|
2425
2963
|
};
|
|
2426
2964
|
}
|
|
2427
2965
|
const expandedServerArg = expandTilde(serverArg);
|
|
2428
|
-
if (!
|
|
2966
|
+
if (!path9.isAbsolute(expandedServerArg)) {
|
|
2429
2967
|
return {
|
|
2430
2968
|
installed: true,
|
|
2431
2969
|
ok: false,
|
|
@@ -2433,7 +2971,7 @@ function inspectLaunchdPlist(plistPath, options = {}) {
|
|
|
2433
2971
|
remediation: "Run `remnic daemon install` so launchd uses an absolute Remnic server path."
|
|
2434
2972
|
};
|
|
2435
2973
|
}
|
|
2436
|
-
if (!
|
|
2974
|
+
if (!existsSync4(expandedServerArg)) {
|
|
2437
2975
|
return {
|
|
2438
2976
|
installed: true,
|
|
2439
2977
|
ok: false,
|
|
@@ -2497,8 +3035,8 @@ function normalizeResolvedPath(resolved) {
|
|
|
2497
3035
|
return resolved;
|
|
2498
3036
|
}
|
|
2499
3037
|
function packageServerBinFromEntry(packageEntry) {
|
|
2500
|
-
if (
|
|
2501
|
-
return
|
|
3038
|
+
if (path9.basename(packageEntry) === "index.js" && path9.basename(path9.dirname(packageEntry)) === "dist") {
|
|
3039
|
+
return path9.join(path9.dirname(path9.dirname(packageEntry)), "bin", "remnic-server.js");
|
|
2502
3040
|
}
|
|
2503
3041
|
return packageEntry;
|
|
2504
3042
|
}
|
|
@@ -2620,7 +3158,7 @@ function stripConfigArgv(args) {
|
|
|
2620
3158
|
}
|
|
2621
3159
|
|
|
2622
3160
|
// src/import-dispatch.ts
|
|
2623
|
-
import
|
|
3161
|
+
import fs8 from "fs";
|
|
2624
3162
|
import {
|
|
2625
3163
|
runImporter,
|
|
2626
3164
|
validateImportBatchSize,
|
|
@@ -2628,10 +3166,10 @@ import {
|
|
|
2628
3166
|
} from "@remnic/core";
|
|
2629
3167
|
|
|
2630
3168
|
// src/import-bundle-detect.ts
|
|
2631
|
-
import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as
|
|
2632
|
-
import
|
|
3169
|
+
import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
3170
|
+
import path10 from "path";
|
|
2633
3171
|
function detectBundleEntries(bundleDir, options = {}) {
|
|
2634
|
-
const
|
|
3172
|
+
const readdir3 = options.readdirImpl ?? defaultReaddir;
|
|
2635
3173
|
const readFileImpl = options.readFileImpl ?? defaultReadFile;
|
|
2636
3174
|
const isDirectory2 = options.isDirectoryImpl ?? defaultIsDirectory;
|
|
2637
3175
|
const isRegularFile = options.isRegularFileImpl ?? (options.readdirImpl !== void 0 || options.isDirectoryImpl !== void 0 ? (p) => !isDirectory2(p) : defaultIsRegularFile);
|
|
@@ -2651,7 +3189,7 @@ function detectBundleEntries(bundleDir, options = {}) {
|
|
|
2651
3189
|
}
|
|
2652
3190
|
const roots = collectCandidatePaths(
|
|
2653
3191
|
bundleDir,
|
|
2654
|
-
|
|
3192
|
+
readdir3,
|
|
2655
3193
|
isDirectory2,
|
|
2656
3194
|
isRegularFile
|
|
2657
3195
|
);
|
|
@@ -2660,7 +3198,7 @@ function detectBundleEntries(bundleDir, options = {}) {
|
|
|
2660
3198
|
for (const filePath of roots) {
|
|
2661
3199
|
if (seenFiles.has(filePath)) continue;
|
|
2662
3200
|
seenFiles.add(filePath);
|
|
2663
|
-
const name =
|
|
3201
|
+
const name = path10.basename(filePath);
|
|
2664
3202
|
const match = classifyFile(name, filePath, readFileImpl);
|
|
2665
3203
|
if (match) entries.push(match);
|
|
2666
3204
|
}
|
|
@@ -2680,9 +3218,9 @@ function detectBundleEntries(bundleDir, options = {}) {
|
|
|
2680
3218
|
return entries;
|
|
2681
3219
|
}
|
|
2682
3220
|
var MAX_WALK_DEPTH = 4;
|
|
2683
|
-
function collectCandidatePaths(root,
|
|
3221
|
+
function collectCandidatePaths(root, readdir3, isDirectory2, isRegularFile) {
|
|
2684
3222
|
try {
|
|
2685
|
-
|
|
3223
|
+
readdir3(root);
|
|
2686
3224
|
} catch {
|
|
2687
3225
|
throw new Error(
|
|
2688
3226
|
`Bundle directory '${root}' could not be read. Pass an existing directory.`
|
|
@@ -2693,12 +3231,12 @@ function collectCandidatePaths(root, readdir2, isDirectory2, isRegularFile) {
|
|
|
2693
3231
|
if (depth > MAX_WALK_DEPTH) return;
|
|
2694
3232
|
let entries;
|
|
2695
3233
|
try {
|
|
2696
|
-
entries =
|
|
3234
|
+
entries = readdir3(dir);
|
|
2697
3235
|
} catch {
|
|
2698
3236
|
return;
|
|
2699
3237
|
}
|
|
2700
3238
|
for (const entry of entries) {
|
|
2701
|
-
const full =
|
|
3239
|
+
const full = path10.join(dir, entry);
|
|
2702
3240
|
if (isDirectory2(full)) {
|
|
2703
3241
|
walk(full, depth + 1);
|
|
2704
3242
|
} else if (isRegularFile(full)) {
|
|
@@ -2750,7 +3288,7 @@ function defaultReaddir(dir) {
|
|
|
2750
3288
|
return readdirSync2(dir);
|
|
2751
3289
|
}
|
|
2752
3290
|
function defaultReadFile(p) {
|
|
2753
|
-
return
|
|
3291
|
+
return readFileSync3(p, "utf-8");
|
|
2754
3292
|
}
|
|
2755
3293
|
function defaultIsDirectory(p) {
|
|
2756
3294
|
try {
|
|
@@ -3134,7 +3672,7 @@ async function cmdImport(rest, targetFactory, disposeTarget, ioOverrides = {}) {
|
|
|
3134
3672
|
let materializedTarget;
|
|
3135
3673
|
let materializePromise;
|
|
3136
3674
|
const io = {
|
|
3137
|
-
readFile: ioOverrides.readFile ?? (async (p) =>
|
|
3675
|
+
readFile: ioOverrides.readFile ?? (async (p) => fs8.promises.readFile(p, "utf-8")),
|
|
3138
3676
|
loadAdapter: ioOverrides.loadAdapter ?? (async (name) => (await loadImporterModule(name)).adapter),
|
|
3139
3677
|
runImporter: ioOverrides.runImporter ?? runImporter,
|
|
3140
3678
|
getWriteTarget: async () => {
|
|
@@ -3207,8 +3745,8 @@ function takeOptionalValue(args, flag) {
|
|
|
3207
3745
|
}
|
|
3208
3746
|
|
|
3209
3747
|
// src/import-lossless-claw-cmd.ts
|
|
3210
|
-
import
|
|
3211
|
-
import
|
|
3748
|
+
import fs9 from "fs";
|
|
3749
|
+
import path11 from "path";
|
|
3212
3750
|
import {
|
|
3213
3751
|
applyLcmSchema,
|
|
3214
3752
|
ensureLcmStateDir,
|
|
@@ -3319,15 +3857,15 @@ async function loadImportLosslessClawModule() {
|
|
|
3319
3857
|
|
|
3320
3858
|
// src/import-lossless-claw-cmd.ts
|
|
3321
3859
|
function assertDirectoryOrAbsent(p, label) {
|
|
3322
|
-
if (
|
|
3860
|
+
if (fs9.existsSync(p) && !fs9.statSync(p).isDirectory()) {
|
|
3323
3861
|
throw new Error(`${label} is not a directory: ${p}`);
|
|
3324
3862
|
}
|
|
3325
3863
|
}
|
|
3326
3864
|
function assertFile(p, label) {
|
|
3327
|
-
if (!
|
|
3865
|
+
if (!fs9.existsSync(p)) {
|
|
3328
3866
|
throw new Error(`${label} does not exist: ${p}`);
|
|
3329
3867
|
}
|
|
3330
|
-
if (!
|
|
3868
|
+
if (!fs9.statSync(p).isFile()) {
|
|
3331
3869
|
throw new Error(`${label} is not a file: ${p}`);
|
|
3332
3870
|
}
|
|
3333
3871
|
}
|
|
@@ -3358,8 +3896,8 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
|
|
|
3358
3896
|
let destDb;
|
|
3359
3897
|
try {
|
|
3360
3898
|
if (parsed.dryRun) {
|
|
3361
|
-
const lcmPath =
|
|
3362
|
-
if (
|
|
3899
|
+
const lcmPath = path11.join(memoryDir, "state", "lcm.sqlite");
|
|
3900
|
+
if (fs9.existsSync(lcmPath)) {
|
|
3363
3901
|
destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
|
|
3364
3902
|
} else {
|
|
3365
3903
|
destDb = mod.openInMemoryDestinationDatabase();
|
|
@@ -3451,15 +3989,15 @@ registerPublisher("omp", () => new LazyPluginPiPublisher("omp", (mod) => mod.Omp
|
|
|
3451
3989
|
function readCompatEnv(primary, legacy) {
|
|
3452
3990
|
return process.env[primary] ?? process.env[legacy];
|
|
3453
3991
|
}
|
|
3454
|
-
var PID_DIR =
|
|
3455
|
-
var LEGACY_PID_DIR =
|
|
3456
|
-
var PID_FILE =
|
|
3457
|
-
var LEGACY_PID_FILE =
|
|
3458
|
-
var LOG_FILE =
|
|
3459
|
-
var LEGACY_LOG_FILE =
|
|
3460
|
-
var CLI_MODULE_DIR =
|
|
3461
|
-
var CLI_REPO_ROOT =
|
|
3462
|
-
var EVAL_RUNNER_PATH =
|
|
3992
|
+
var PID_DIR = path12.join(resolveHomeDir(), ".remnic");
|
|
3993
|
+
var LEGACY_PID_DIR = path12.join(resolveHomeDir(), ".engram");
|
|
3994
|
+
var PID_FILE = path12.join(PID_DIR, "server.pid");
|
|
3995
|
+
var LEGACY_PID_FILE = path12.join(LEGACY_PID_DIR, "server.pid");
|
|
3996
|
+
var LOG_FILE = path12.join(PID_DIR, "server.log");
|
|
3997
|
+
var LEGACY_LOG_FILE = path12.join(LEGACY_PID_DIR, "server.log");
|
|
3998
|
+
var CLI_MODULE_DIR = path12.dirname(fileURLToPath4(import.meta.url));
|
|
3999
|
+
var CLI_REPO_ROOT = path12.resolve(CLI_MODULE_DIR, "../../..");
|
|
4000
|
+
var EVAL_RUNNER_PATH = path12.join(CLI_REPO_ROOT, "evals", "run.ts");
|
|
3463
4001
|
var OPENCLAW_GATEWAY_LABEL = "ai.openclaw.gateway";
|
|
3464
4002
|
var CLI_SUCCESS_EXIT_GRACE_MS = 5e3;
|
|
3465
4003
|
var CLI_OUTPUT_FLUSH_GRACE_MS = 250;
|
|
@@ -3792,7 +4330,7 @@ async function resolveAllBenchmarks() {
|
|
|
3792
4330
|
if (packageBenchmarks) {
|
|
3793
4331
|
return packageBenchmarks.filter((entry) => entry.runnerAvailable).map((entry) => entry.id);
|
|
3794
4332
|
}
|
|
3795
|
-
if (!
|
|
4333
|
+
if (!fs10.existsSync(EVAL_RUNNER_PATH)) {
|
|
3796
4334
|
return [];
|
|
3797
4335
|
}
|
|
3798
4336
|
return BENCHMARK_CATALOG.filter((entry) => entry.category !== "ingestion").map((entry) => entry.id);
|
|
@@ -3840,17 +4378,17 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
3840
4378
|
`Fallback benchmark runner does not support provider-backed, gateway, or thinking/timeout flags (${unsupportedOptions.join(", ")}). Build/install @remnic/bench to use those options.`
|
|
3841
4379
|
);
|
|
3842
4380
|
}
|
|
3843
|
-
if (!
|
|
4381
|
+
if (!fs10.existsSync(EVAL_RUNNER_PATH)) {
|
|
3844
4382
|
console.error(
|
|
3845
4383
|
"Benchmark runner not found. Expected eval runner at evals/run.ts or a phase-1 @remnic/bench runtime export."
|
|
3846
4384
|
);
|
|
3847
4385
|
process.exit(1);
|
|
3848
4386
|
}
|
|
3849
4387
|
const tsxCandidates = [
|
|
3850
|
-
|
|
3851
|
-
|
|
4388
|
+
path12.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
|
|
4389
|
+
path12.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
|
|
3852
4390
|
];
|
|
3853
|
-
const tsxCmd = tsxCandidates.find((candidate) =>
|
|
4391
|
+
const tsxCmd = tsxCandidates.find((candidate) => fs10.existsSync(candidate)) ?? "tsx";
|
|
3854
4392
|
const fallbackOutputDir = createFallbackBenchOutputDir(
|
|
3855
4393
|
parsed.resultsDir ?? resolveBenchOutputDir(),
|
|
3856
4394
|
benchmarkId,
|
|
@@ -3867,7 +4405,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
3867
4405
|
return resolveFallbackBenchResultPath(fallbackOutputDir);
|
|
3868
4406
|
}
|
|
3869
4407
|
function resolveBenchOutputDir() {
|
|
3870
|
-
return
|
|
4408
|
+
return path12.join(resolveHomeDir(), ".remnic", "bench", "results");
|
|
3871
4409
|
}
|
|
3872
4410
|
var DOWNLOADABLE_BENCHMARK_DATASETS = [
|
|
3873
4411
|
"ama-bench",
|
|
@@ -3912,8 +4450,8 @@ var MEMORY_AGENT_BENCH_SPLIT_FILENAMES = [
|
|
|
3912
4450
|
];
|
|
3913
4451
|
var MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES = [
|
|
3914
4452
|
"entity2id.json",
|
|
3915
|
-
|
|
3916
|
-
|
|
4453
|
+
path12.join("processed_data", "Recsys_Redial", "entity2id.json"),
|
|
4454
|
+
path12.join("Recsys_Redial", "entity2id.json")
|
|
3917
4455
|
];
|
|
3918
4456
|
var DOWNLOADED_DATASET_MARKERS = {
|
|
3919
4457
|
"ama-bench": { anyOf: ["open_end_qa_set.jsonl"] },
|
|
@@ -3988,18 +4526,18 @@ var PERSONAMEM_DATASET_FILE_CANDIDATES = [
|
|
|
3988
4526
|
"benchmark/benchmark.csv",
|
|
3989
4527
|
"benchmark.csv"
|
|
3990
4528
|
];
|
|
3991
|
-
var PERSONAMEM_COMPLETION_MARKER =
|
|
4529
|
+
var PERSONAMEM_COMPLETION_MARKER = path12.join(
|
|
3992
4530
|
"data",
|
|
3993
4531
|
"chat_history_32k",
|
|
3994
4532
|
".download-complete"
|
|
3995
4533
|
);
|
|
3996
4534
|
function resolveRealpathWithinDataset(datasetPath, relativePath) {
|
|
3997
4535
|
try {
|
|
3998
|
-
const datasetRoot =
|
|
3999
|
-
const candidatePath =
|
|
4000
|
-
const candidateRealPath =
|
|
4001
|
-
const relativeToRoot =
|
|
4002
|
-
if (relativeToRoot.startsWith("..") ||
|
|
4536
|
+
const datasetRoot = fs10.realpathSync(datasetPath);
|
|
4537
|
+
const candidatePath = path12.resolve(datasetRoot, relativePath);
|
|
4538
|
+
const candidateRealPath = fs10.realpathSync(candidatePath);
|
|
4539
|
+
const relativeToRoot = path12.relative(datasetRoot, candidateRealPath);
|
|
4540
|
+
if (relativeToRoot.startsWith("..") || path12.isAbsolute(relativeToRoot)) {
|
|
4003
4541
|
return null;
|
|
4004
4542
|
}
|
|
4005
4543
|
return candidateRealPath;
|
|
@@ -4055,15 +4593,15 @@ function parseCsvRows(raw) {
|
|
|
4055
4593
|
}
|
|
4056
4594
|
function isPersonaMemDatasetComplete(datasetPath) {
|
|
4057
4595
|
try {
|
|
4058
|
-
const completionMarkerPath =
|
|
4059
|
-
if (
|
|
4596
|
+
const completionMarkerPath = path12.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
|
|
4597
|
+
if (fs10.statSync(completionMarkerPath).isFile()) {
|
|
4060
4598
|
return true;
|
|
4061
4599
|
}
|
|
4062
4600
|
} catch {
|
|
4063
4601
|
}
|
|
4064
4602
|
const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
|
|
4065
4603
|
try {
|
|
4066
|
-
return
|
|
4604
|
+
return fs10.statSync(path12.join(datasetPath, candidate)).isFile();
|
|
4067
4605
|
} catch {
|
|
4068
4606
|
return false;
|
|
4069
4607
|
}
|
|
@@ -4072,7 +4610,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4072
4610
|
return false;
|
|
4073
4611
|
}
|
|
4074
4612
|
try {
|
|
4075
|
-
const rows = parseCsvRows(
|
|
4613
|
+
const rows = parseCsvRows(fs10.readFileSync(path12.join(datasetPath, datasetFile), "utf8"));
|
|
4076
4614
|
if (rows.length < 2) {
|
|
4077
4615
|
return false;
|
|
4078
4616
|
}
|
|
@@ -4087,7 +4625,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4087
4625
|
}
|
|
4088
4626
|
return historyPaths.every((relativePath) => {
|
|
4089
4627
|
const resolvedPath = resolveRealpathWithinDataset(datasetPath, relativePath);
|
|
4090
|
-
return resolvedPath !== null &&
|
|
4628
|
+
return resolvedPath !== null && fs10.statSync(resolvedPath).isFile();
|
|
4091
4629
|
});
|
|
4092
4630
|
} catch {
|
|
4093
4631
|
return false;
|
|
@@ -4095,14 +4633,14 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4095
4633
|
}
|
|
4096
4634
|
function hasDatasetFile(datasetPath, relativePath) {
|
|
4097
4635
|
try {
|
|
4098
|
-
return
|
|
4636
|
+
return fs10.statSync(path12.join(datasetPath, relativePath)).isFile();
|
|
4099
4637
|
} catch {
|
|
4100
4638
|
return false;
|
|
4101
4639
|
}
|
|
4102
4640
|
}
|
|
4103
4641
|
function hasMemoryAgentBenchEntityMapping(datasetPath) {
|
|
4104
|
-
const absoluteDatasetPath =
|
|
4105
|
-
const roots = [absoluteDatasetPath,
|
|
4642
|
+
const absoluteDatasetPath = path12.resolve(datasetPath);
|
|
4643
|
+
const roots = [absoluteDatasetPath, path12.dirname(absoluteDatasetPath)];
|
|
4106
4644
|
return hasDatasetFile(absoluteDatasetPath, "entity2id.json") || roots.some(
|
|
4107
4645
|
(root) => MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES.filter((relativePath) => relativePath !== "entity2id.json").some((relativePath) => hasDatasetFile(root, relativePath))
|
|
4108
4646
|
);
|
|
@@ -4113,12 +4651,12 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
|
|
|
4113
4651
|
...MEMORY_AGENT_BENCH_SPLIT_FILENAMES
|
|
4114
4652
|
];
|
|
4115
4653
|
return candidateFilenames.some((filename) => {
|
|
4116
|
-
const filePath =
|
|
4654
|
+
const filePath = path12.join(datasetPath, filename);
|
|
4117
4655
|
try {
|
|
4118
|
-
if (!
|
|
4656
|
+
if (!fs10.statSync(filePath).isFile()) {
|
|
4119
4657
|
return false;
|
|
4120
4658
|
}
|
|
4121
|
-
const raw =
|
|
4659
|
+
const raw = fs10.readFileSync(filePath, "utf8");
|
|
4122
4660
|
return /"source"\s*:\s*"recsys[_-]/i.test(raw);
|
|
4123
4661
|
} catch {
|
|
4124
4662
|
return false;
|
|
@@ -4134,7 +4672,7 @@ function isMemoryAgentBenchDatasetComplete(datasetPath) {
|
|
|
4134
4672
|
function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
4135
4673
|
let stats;
|
|
4136
4674
|
try {
|
|
4137
|
-
stats =
|
|
4675
|
+
stats = fs10.statSync(datasetPath);
|
|
4138
4676
|
} catch {
|
|
4139
4677
|
return false;
|
|
4140
4678
|
}
|
|
@@ -4144,7 +4682,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4144
4682
|
const marker = DOWNLOADED_DATASET_MARKERS[benchmarkId];
|
|
4145
4683
|
if (!marker) {
|
|
4146
4684
|
try {
|
|
4147
|
-
return
|
|
4685
|
+
return fs10.readdirSync(datasetPath).length > 0;
|
|
4148
4686
|
} catch {
|
|
4149
4687
|
return false;
|
|
4150
4688
|
}
|
|
@@ -4152,7 +4690,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4152
4690
|
if (marker.allOf) {
|
|
4153
4691
|
const hasAllRequiredFiles = marker.allOf.every((name) => {
|
|
4154
4692
|
try {
|
|
4155
|
-
return
|
|
4693
|
+
return fs10.statSync(path12.join(datasetPath, name)).isFile();
|
|
4156
4694
|
} catch {
|
|
4157
4695
|
return false;
|
|
4158
4696
|
}
|
|
@@ -4164,7 +4702,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4164
4702
|
if (marker.anyOf) {
|
|
4165
4703
|
const hasMarkerFile = marker.anyOf.some((name) => {
|
|
4166
4704
|
try {
|
|
4167
|
-
return
|
|
4705
|
+
return fs10.statSync(path12.join(datasetPath, name)).isFile();
|
|
4168
4706
|
} catch {
|
|
4169
4707
|
return false;
|
|
4170
4708
|
}
|
|
@@ -4182,7 +4720,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4182
4720
|
}
|
|
4183
4721
|
if (marker.ext) {
|
|
4184
4722
|
try {
|
|
4185
|
-
return
|
|
4723
|
+
return fs10.readdirSync(datasetPath).some(
|
|
4186
4724
|
(name) => name.endsWith(marker.ext) && !marker.exclude?.includes(name)
|
|
4187
4725
|
);
|
|
4188
4726
|
} catch {
|
|
@@ -4192,9 +4730,9 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4192
4730
|
return false;
|
|
4193
4731
|
}
|
|
4194
4732
|
async function launchBenchUi(resultsDir) {
|
|
4195
|
-
const benchUiDir =
|
|
4733
|
+
const benchUiDir = path12.join(CLI_REPO_ROOT, "packages", "bench-ui");
|
|
4196
4734
|
const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
|
|
4197
|
-
if (!
|
|
4735
|
+
if (!fs10.existsSync(path12.join(benchUiDir, "package.json"))) {
|
|
4198
4736
|
console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
|
|
4199
4737
|
process.exit(1);
|
|
4200
4738
|
}
|
|
@@ -4221,24 +4759,24 @@ async function launchBenchUi(resultsDir) {
|
|
|
4221
4759
|
});
|
|
4222
4760
|
}
|
|
4223
4761
|
function resolveRepoDatasetRoot() {
|
|
4224
|
-
const repoCandidate =
|
|
4762
|
+
const repoCandidate = path12.join(CLI_REPO_ROOT, "evals", "datasets");
|
|
4225
4763
|
if (isRepoCheckout()) {
|
|
4226
4764
|
return repoCandidate;
|
|
4227
4765
|
}
|
|
4228
|
-
return
|
|
4766
|
+
return path12.join(resolveHomeDir(), ".remnic", "bench", "datasets");
|
|
4229
4767
|
}
|
|
4230
4768
|
function listDownloadableBenchmarks() {
|
|
4231
4769
|
return [...DOWNLOADABLE_BENCHMARK_DATASETS];
|
|
4232
4770
|
}
|
|
4233
4771
|
function resolveDatasetDownloadScriptPath() {
|
|
4234
|
-
const bundled =
|
|
4235
|
-
if (
|
|
4772
|
+
const bundled = path12.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
|
|
4773
|
+
if (fs10.existsSync(bundled)) {
|
|
4236
4774
|
return bundled;
|
|
4237
4775
|
}
|
|
4238
|
-
return
|
|
4776
|
+
return path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
|
|
4239
4777
|
}
|
|
4240
4778
|
function isRepoCheckout() {
|
|
4241
|
-
return
|
|
4779
|
+
return fs10.existsSync(path12.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs10.existsSync(path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
|
|
4242
4780
|
}
|
|
4243
4781
|
function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
|
|
4244
4782
|
const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
|
|
@@ -4289,7 +4827,7 @@ function resolveBenchDatasetDir(benchmarkId, quick, datasetDirOverride) {
|
|
|
4289
4827
|
if (quick) {
|
|
4290
4828
|
return void 0;
|
|
4291
4829
|
}
|
|
4292
|
-
const datasetDir =
|
|
4830
|
+
const datasetDir = path12.join(resolveRepoDatasetRoot(), benchmarkId);
|
|
4293
4831
|
if (isDatasetDownloaded(datasetDir, benchmarkId)) {
|
|
4294
4832
|
return datasetDir;
|
|
4295
4833
|
}
|
|
@@ -4607,13 +5145,13 @@ async function exportBenchPackageResult(parsed) {
|
|
|
4607
5145
|
process.exit(1);
|
|
4608
5146
|
}
|
|
4609
5147
|
const result = await loadBenchmarkResult(summary.path);
|
|
4610
|
-
const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(
|
|
5148
|
+
const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(path12.dirname(summary.path), result.meta.id) : void 0;
|
|
4611
5149
|
const rendered = renderBenchmarkResultExport(result, parsed.format, {
|
|
4612
5150
|
...reportCardProvenance ? { reportCardProvenance } : {}
|
|
4613
5151
|
});
|
|
4614
5152
|
if (parsed.output) {
|
|
4615
|
-
|
|
4616
|
-
|
|
5153
|
+
fs10.mkdirSync(path12.dirname(parsed.output), { recursive: true });
|
|
5154
|
+
fs10.writeFileSync(parsed.output, rendered);
|
|
4617
5155
|
console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
|
|
4618
5156
|
return;
|
|
4619
5157
|
}
|
|
@@ -4630,7 +5168,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
4630
5168
|
process.exit(1);
|
|
4631
5169
|
}
|
|
4632
5170
|
const status = supported.map((benchmarkId) => {
|
|
4633
|
-
const datasetPath =
|
|
5171
|
+
const datasetPath = path12.join(datasetRoot, benchmarkId);
|
|
4634
5172
|
return {
|
|
4635
5173
|
benchmark: benchmarkId,
|
|
4636
5174
|
downloaded: isDatasetDownloaded(datasetPath, benchmarkId),
|
|
@@ -4658,7 +5196,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
4658
5196
|
process.exit(1);
|
|
4659
5197
|
}
|
|
4660
5198
|
const scriptPath = resolveDatasetDownloadScriptPath();
|
|
4661
|
-
if (!
|
|
5199
|
+
if (!fs10.existsSync(scriptPath)) {
|
|
4662
5200
|
console.error(`ERROR: dataset download script not found: ${scriptPath}`);
|
|
4663
5201
|
process.exit(1);
|
|
4664
5202
|
}
|
|
@@ -4668,7 +5206,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
4668
5206
|
runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, parsed.json === true);
|
|
4669
5207
|
downloaded.push({
|
|
4670
5208
|
benchmark: benchmarkId,
|
|
4671
|
-
path:
|
|
5209
|
+
path: path12.join(datasetRoot, benchmarkId)
|
|
4672
5210
|
});
|
|
4673
5211
|
}
|
|
4674
5212
|
if (parsed.json) {
|
|
@@ -4807,10 +5345,10 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
4807
5345
|
}
|
|
4808
5346
|
const bench = await loadBenchModule();
|
|
4809
5347
|
const resultsDir = expandTilde(
|
|
4810
|
-
parsed.resultsDir ??
|
|
5348
|
+
parsed.resultsDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "results")
|
|
4811
5349
|
);
|
|
4812
5350
|
const calibrationDir = expandTilde(
|
|
4813
|
-
parsed.calibrationDir ??
|
|
5351
|
+
parsed.calibrationDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "calibration")
|
|
4814
5352
|
);
|
|
4815
5353
|
const stored = await bench.listBenchmarkResults(resultsDir);
|
|
4816
5354
|
const allForBenchmark = stored.filter((entry) => entry.benchmark === benchmarkId);
|
|
@@ -4858,7 +5396,7 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
4858
5396
|
);
|
|
4859
5397
|
process.exit(1);
|
|
4860
5398
|
}
|
|
4861
|
-
const sourceResultSha256 =
|
|
5399
|
+
const sourceResultSha256 = createHash2("sha256").update(fs10.readFileSync(latest.path)).digest("hex");
|
|
4862
5400
|
const expandedManifestPath = expandTilde(manifestPath);
|
|
4863
5401
|
if (!bench.resolveLocalLabJudgeProviderConfig) {
|
|
4864
5402
|
console.error(
|
|
@@ -5266,7 +5804,7 @@ function loadPinnedLoCoMoTaskSelector(parsed) {
|
|
|
5266
5804
|
}
|
|
5267
5805
|
let decoded;
|
|
5268
5806
|
try {
|
|
5269
|
-
decoded = JSON.parse(
|
|
5807
|
+
decoded = JSON.parse(fs10.readFileSync(parsed.taskIdsFile, "utf8"));
|
|
5270
5808
|
} catch (error) {
|
|
5271
5809
|
throw new Error(
|
|
5272
5810
|
`Unable to read --task-ids-file ${parsed.taskIdsFile}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -5362,8 +5900,8 @@ async function loadPublishedPromotionHelpers() {
|
|
|
5362
5900
|
const benchModule = await loadBenchModule();
|
|
5363
5901
|
return {
|
|
5364
5902
|
async promoteArtifactsToPublished(args) {
|
|
5365
|
-
const { mkdirSync, readFileSync:
|
|
5366
|
-
const
|
|
5903
|
+
const { mkdirSync, readFileSync: readFileSync4, writeFileSync } = await import("fs");
|
|
5904
|
+
const path13 = await import("path");
|
|
5367
5905
|
mkdirSync(args.publishedOutDir, { recursive: true });
|
|
5368
5906
|
if (args.artifactPaths.length === 0) {
|
|
5369
5907
|
console.warn(
|
|
@@ -5372,7 +5910,7 @@ async function loadPublishedPromotionHelpers() {
|
|
|
5372
5910
|
return;
|
|
5373
5911
|
}
|
|
5374
5912
|
for (const artifactPath of args.artifactPaths) {
|
|
5375
|
-
const raw =
|
|
5913
|
+
const raw = readFileSync4(artifactPath, "utf8");
|
|
5376
5914
|
const parsedUnknown = JSON.parse(raw);
|
|
5377
5915
|
const parsedObj = parsedUnknown !== null && typeof parsedUnknown === "object" && !Array.isArray(parsedUnknown) ? parsedUnknown : {};
|
|
5378
5916
|
const gitShaShort = (parsedObj.meta?.gitSha ?? "unknown").slice(0, 7);
|
|
@@ -5380,13 +5918,13 @@ async function loadPublishedPromotionHelpers() {
|
|
|
5380
5918
|
const modelSlug = args.model.replace(/[^a-zA-Z0-9_.-]/g, "-");
|
|
5381
5919
|
const rawProfile = parsedObj.config?.runtimeProfile;
|
|
5382
5920
|
const profileSlug = typeof rawProfile === "string" && rawProfile.length > 0 ? `-${rawProfile.replace(/[^a-zA-Z0-9_.-]/g, "-")}` : "";
|
|
5383
|
-
const target =
|
|
5921
|
+
const target = path13.join(
|
|
5384
5922
|
args.publishedOutDir,
|
|
5385
5923
|
`${today}-${args.benchmarkId}-${modelSlug}${profileSlug}-${gitShaShort}.json`
|
|
5386
5924
|
);
|
|
5387
5925
|
writeFileSync(target, raw, "utf8");
|
|
5388
5926
|
console.log(
|
|
5389
|
-
`[bench published] Promoted ${
|
|
5927
|
+
`[bench published] Promoted ${path13.basename(artifactPath)} \u2192 ${target}`
|
|
5390
5928
|
);
|
|
5391
5929
|
}
|
|
5392
5930
|
void benchModule;
|
|
@@ -5471,7 +6009,7 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
|
|
|
5471
6009
|
const previousCodexDiagnosticsDir = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV];
|
|
5472
6010
|
const previousCodexDiagnosticsMode = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_MODE_ENV];
|
|
5473
6011
|
if (!previousCodexDiagnosticsDir) {
|
|
5474
|
-
process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] =
|
|
6012
|
+
process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] = path12.join(
|
|
5475
6013
|
outputDir,
|
|
5476
6014
|
"codex-cli-diagnostics"
|
|
5477
6015
|
);
|
|
@@ -5609,7 +6147,7 @@ async function preparePersistedJudgeCalibrationAttachment(benchModule, benchmark
|
|
|
5609
6147
|
);
|
|
5610
6148
|
}
|
|
5611
6149
|
const calibrationDir = expandTilde(
|
|
5612
|
-
calibrationBinding.calibrationDir ??
|
|
6150
|
+
calibrationBinding.calibrationDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "calibration")
|
|
5613
6151
|
);
|
|
5614
6152
|
const state = await benchModule.loadJudgeCalibrationState?.(benchmarkId, calibrationDir);
|
|
5615
6153
|
if (!state) {
|
|
@@ -5683,7 +6221,7 @@ function attachPreparedJudgeCalibration(result, judgeCalibration) {
|
|
|
5683
6221
|
function hashCalibrationProviderConfig(config) {
|
|
5684
6222
|
const canonicalize = (value, key = "") => {
|
|
5685
6223
|
if (typeof value === "string" && /(?:api.?key|authorization|token|secret)/i.test(key)) {
|
|
5686
|
-
return { secretSha256:
|
|
6224
|
+
return { secretSha256: createHash2("sha256").update(value).digest("hex") };
|
|
5687
6225
|
}
|
|
5688
6226
|
if (Array.isArray(value)) return value.map((item) => canonicalize(item));
|
|
5689
6227
|
if (value && typeof value === "object") {
|
|
@@ -5694,7 +6232,7 @@ function hashCalibrationProviderConfig(config) {
|
|
|
5694
6232
|
}
|
|
5695
6233
|
return value;
|
|
5696
6234
|
};
|
|
5697
|
-
return
|
|
6235
|
+
return createHash2("sha256").update(JSON.stringify(canonicalize(config))).digest("hex");
|
|
5698
6236
|
}
|
|
5699
6237
|
function restoreOptionalEnv(key, previousValue) {
|
|
5700
6238
|
if (previousValue === void 0) {
|
|
@@ -5906,7 +6444,7 @@ function resolveBenchReproDatasetDir(datasetDir) {
|
|
|
5906
6444
|
return void 0;
|
|
5907
6445
|
}
|
|
5908
6446
|
try {
|
|
5909
|
-
return
|
|
6447
|
+
return fs10.realpathSync(datasetDir);
|
|
5910
6448
|
} catch {
|
|
5911
6449
|
return datasetDir;
|
|
5912
6450
|
}
|
|
@@ -5959,23 +6497,23 @@ async function writeBenchReproManifestForPackageRun(args) {
|
|
|
5959
6497
|
}
|
|
5960
6498
|
}
|
|
5961
6499
|
function resolveConfigPath(cliPath) {
|
|
5962
|
-
if (cliPath) return
|
|
6500
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
5963
6501
|
const envPath = readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH");
|
|
5964
|
-
if (envPath) return
|
|
6502
|
+
if (envPath) return path12.resolve(expandTilde(envPath));
|
|
5965
6503
|
const candidates = [
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
6504
|
+
path12.join(process.cwd(), "remnic.config.json"),
|
|
6505
|
+
path12.join(process.cwd(), "engram.config.json"),
|
|
6506
|
+
path12.join(resolveHomeDir(), ".config", "remnic", "config.json"),
|
|
6507
|
+
path12.join(resolveHomeDir(), ".config", "engram", "config.json")
|
|
5970
6508
|
];
|
|
5971
6509
|
for (const candidate of candidates) {
|
|
5972
|
-
if (
|
|
6510
|
+
if (fs10.existsSync(candidate)) return candidate;
|
|
5973
6511
|
}
|
|
5974
|
-
return
|
|
6512
|
+
return path12.join(resolveHomeDir(), ".config", "remnic", "config.json");
|
|
5975
6513
|
}
|
|
5976
6514
|
function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
5977
6515
|
const configPath = resolveConfigPath(cliPath);
|
|
5978
|
-
if (
|
|
6516
|
+
if (fs10.existsSync(configPath)) {
|
|
5979
6517
|
return configPath;
|
|
5980
6518
|
}
|
|
5981
6519
|
if (cliPath) {
|
|
@@ -5985,7 +6523,7 @@ function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
|
5985
6523
|
}
|
|
5986
6524
|
function resolveExistingBenchOpenclawConfigPath(cliPath) {
|
|
5987
6525
|
const configPath = resolveOpenclawConfigPath(cliPath);
|
|
5988
|
-
if (
|
|
6526
|
+
if (fs10.existsSync(configPath)) {
|
|
5989
6527
|
return configPath;
|
|
5990
6528
|
}
|
|
5991
6529
|
if (cliPath) {
|
|
@@ -6085,34 +6623,34 @@ async function resolvePackageBenchRuntime(benchModule, parsed, runtimeProfile) {
|
|
|
6085
6623
|
);
|
|
6086
6624
|
}
|
|
6087
6625
|
function normalizeMemoryDirPath(memoryDir) {
|
|
6088
|
-
return
|
|
6626
|
+
return path12.resolve(expandTilde(memoryDir));
|
|
6089
6627
|
}
|
|
6090
6628
|
function resolveMemoryDir() {
|
|
6091
6629
|
const configMemoryDir = (() => {
|
|
6092
6630
|
const envMemoryDir = readCompatEnv("REMNIC_MEMORY_DIR", "ENGRAM_MEMORY_DIR");
|
|
6093
6631
|
if (envMemoryDir) return normalizeMemoryDirPath(envMemoryDir);
|
|
6094
6632
|
const configPath = resolveConfigPath();
|
|
6095
|
-
const raw =
|
|
6096
|
-
const remnicCfg =
|
|
6633
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
6634
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
6097
6635
|
if (typeof remnicCfg.memoryDir === "string" && remnicCfg.memoryDir.length > 0) {
|
|
6098
6636
|
return normalizeMemoryDirPath(remnicCfg.memoryDir);
|
|
6099
6637
|
}
|
|
6100
6638
|
const home = resolveHomeDir();
|
|
6101
|
-
const standalonePath =
|
|
6102
|
-
const legacyStandalonePath =
|
|
6103
|
-
const openclawPath =
|
|
6104
|
-
if (
|
|
6105
|
-
if (
|
|
6639
|
+
const standalonePath = path12.join(home, ".remnic", "memory");
|
|
6640
|
+
const legacyStandalonePath = path12.join(home, ".engram", "memory");
|
|
6641
|
+
const openclawPath = path12.join(home, ".openclaw", "workspace", "memory", "local");
|
|
6642
|
+
if (fs10.existsSync(standalonePath)) return standalonePath;
|
|
6643
|
+
if (fs10.existsSync(legacyStandalonePath)) return legacyStandalonePath;
|
|
6106
6644
|
return openclawPath;
|
|
6107
6645
|
})();
|
|
6108
6646
|
const manifestPath = getManifestPath();
|
|
6109
|
-
if (
|
|
6647
|
+
if (fs10.existsSync(manifestPath)) {
|
|
6110
6648
|
try {
|
|
6111
6649
|
const active = getActiveSpace();
|
|
6112
6650
|
if (active?.memoryDir) {
|
|
6113
6651
|
const activeMemoryDir = normalizeMemoryDirPath(active.memoryDir);
|
|
6114
|
-
if (!
|
|
6115
|
-
|
|
6652
|
+
if (!fs10.existsSync(activeMemoryDir)) {
|
|
6653
|
+
fs10.mkdirSync(activeMemoryDir, { recursive: true });
|
|
6116
6654
|
}
|
|
6117
6655
|
return activeMemoryDir;
|
|
6118
6656
|
}
|
|
@@ -6151,20 +6689,20 @@ var REMNIC_OPENCLAW_LEGACY_PLUGIN_ID = "openclaw-engram";
|
|
|
6151
6689
|
var DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR = [
|
|
6152
6690
|
process.env.OPENCLAW_CONFIG_PATH,
|
|
6153
6691
|
process.env.OPENCLAW_ENGRAM_CONFIG_PATH,
|
|
6154
|
-
|
|
6692
|
+
path12.join(resolveHomeDir(), ".openclaw", "openclaw.json")
|
|
6155
6693
|
].filter(Boolean);
|
|
6156
6694
|
function resolveOpenclawConfigPath(cliPath) {
|
|
6157
|
-
if (cliPath) return
|
|
6695
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
6158
6696
|
const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
|
|
6159
|
-
if (envPath) return
|
|
6697
|
+
if (envPath) return path12.resolve(expandTilde(envPath));
|
|
6160
6698
|
for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
|
|
6161
|
-
if (
|
|
6699
|
+
if (fs10.existsSync(candidate)) return candidate;
|
|
6162
6700
|
}
|
|
6163
|
-
return
|
|
6701
|
+
return path12.join(resolveHomeDir(), ".openclaw", "openclaw.json");
|
|
6164
6702
|
}
|
|
6165
6703
|
function readOpenclawConfig(configPath) {
|
|
6166
|
-
if (!
|
|
6167
|
-
const raw =
|
|
6704
|
+
if (!fs10.existsSync(configPath)) return {};
|
|
6705
|
+
const raw = fs10.readFileSync(configPath, "utf-8");
|
|
6168
6706
|
let parsed;
|
|
6169
6707
|
try {
|
|
6170
6708
|
parsed = JSON.parse(raw);
|
|
@@ -6219,10 +6757,10 @@ function buildRemnicOpenclawHooksPolicy(legacyHooks, existingHooks) {
|
|
|
6219
6757
|
function resolveOpenclawInstallMemoryDir(args) {
|
|
6220
6758
|
const existingMemoryDir = (typeof args.existingNewEntryConfig.memoryDir === "string" ? args.existingNewEntryConfig.memoryDir : void 0) || (args.migrateLegacy && typeof args.legacyConfigToMerge.memoryDir === "string" ? args.legacyConfigToMerge.memoryDir : void 0);
|
|
6221
6759
|
if (args.requestedMemoryDir) {
|
|
6222
|
-
return
|
|
6760
|
+
return path12.resolve(expandTilde(args.requestedMemoryDir));
|
|
6223
6761
|
}
|
|
6224
6762
|
if (existingMemoryDir) {
|
|
6225
|
-
return
|
|
6763
|
+
return path12.resolve(expandTilde(existingMemoryDir));
|
|
6226
6764
|
}
|
|
6227
6765
|
return args.fallbackMemoryDir;
|
|
6228
6766
|
}
|
|
@@ -6240,18 +6778,18 @@ function resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir) {
|
|
|
6240
6778
|
if (!config || typeof config !== "object" || Array.isArray(config)) continue;
|
|
6241
6779
|
const memoryDir = config.memoryDir;
|
|
6242
6780
|
if (typeof memoryDir === "string" && memoryDir.trim().length > 0) {
|
|
6243
|
-
return
|
|
6781
|
+
return path12.resolve(expandTilde(memoryDir));
|
|
6244
6782
|
}
|
|
6245
6783
|
}
|
|
6246
6784
|
return fallbackMemoryDir;
|
|
6247
6785
|
}
|
|
6248
6786
|
function resolveOpenclawPluginDir(cliPath) {
|
|
6249
|
-
if (cliPath) return
|
|
6250
|
-
return
|
|
6787
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
6788
|
+
return path12.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
|
|
6251
6789
|
}
|
|
6252
6790
|
function resolveOpenclawLegacyPluginDir(cliPath) {
|
|
6253
|
-
if (cliPath) return
|
|
6254
|
-
return
|
|
6791
|
+
if (cliPath) return path12.resolve(expandTilde(cliPath));
|
|
6792
|
+
return path12.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID);
|
|
6255
6793
|
}
|
|
6256
6794
|
function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
6257
6795
|
const yyyy = now.getFullYear().toString();
|
|
@@ -6263,14 +6801,14 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
|
6263
6801
|
return `${yyyy}${mm}${dd}-${hh}${min}${ss}`;
|
|
6264
6802
|
}
|
|
6265
6803
|
function backupPathIfPresent(sourcePath, backupPath) {
|
|
6266
|
-
if (!
|
|
6267
|
-
|
|
6268
|
-
|
|
6804
|
+
if (!fs10.existsSync(sourcePath)) return false;
|
|
6805
|
+
fs10.mkdirSync(path12.dirname(backupPath), { recursive: true });
|
|
6806
|
+
fs10.cpSync(sourcePath, backupPath, { recursive: true });
|
|
6269
6807
|
return true;
|
|
6270
6808
|
}
|
|
6271
6809
|
function assertDirectoryPathOrMissing(targetPath, label) {
|
|
6272
|
-
if (!
|
|
6273
|
-
const stat =
|
|
6810
|
+
if (!fs10.existsSync(targetPath)) return;
|
|
6811
|
+
const stat = fs10.statSync(targetPath);
|
|
6274
6812
|
if (!stat.isDirectory()) {
|
|
6275
6813
|
throw new Error(`${label} must be a directory when it already exists: ${targetPath}`);
|
|
6276
6814
|
}
|
|
@@ -6295,7 +6833,7 @@ var PublishedOpenclawPluginInstallError = class extends Error {
|
|
|
6295
6833
|
}
|
|
6296
6834
|
};
|
|
6297
6835
|
function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
6298
|
-
const tempRoot =
|
|
6836
|
+
const tempRoot = fs10.mkdtempSync(path12.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
|
|
6299
6837
|
const stagedDir = `${pluginDir}.next-${process.pid}-${Date.now()}`;
|
|
6300
6838
|
const rollbackDir = `${pluginDir}.rollback-${process.pid}-${Date.now()}`;
|
|
6301
6839
|
let swapRollbackDir;
|
|
@@ -6310,17 +6848,17 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6310
6848
|
if (!tarballName) {
|
|
6311
6849
|
throw new Error(`npm pack ${spec} did not return a tarball name`);
|
|
6312
6850
|
}
|
|
6313
|
-
const unpackDir =
|
|
6314
|
-
|
|
6315
|
-
childProcess2.execFileSync("tar", ["-xzf",
|
|
6851
|
+
const unpackDir = path12.join(tempRoot, "unpacked");
|
|
6852
|
+
fs10.mkdirSync(unpackDir, { recursive: true });
|
|
6853
|
+
childProcess2.execFileSync("tar", ["-xzf", path12.join(tempRoot, tarballName), "-C", unpackDir], {
|
|
6316
6854
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6317
6855
|
});
|
|
6318
|
-
const packagedDir =
|
|
6319
|
-
if (!
|
|
6856
|
+
const packagedDir = path12.join(unpackDir, "package");
|
|
6857
|
+
if (!fs10.existsSync(packagedDir)) {
|
|
6320
6858
|
throw new Error(`npm pack ${spec} did not contain a package/ directory`);
|
|
6321
6859
|
}
|
|
6322
|
-
|
|
6323
|
-
|
|
6860
|
+
fs10.rmSync(stagedDir, { recursive: true, force: true });
|
|
6861
|
+
fs10.cpSync(packagedDir, stagedDir, { recursive: true });
|
|
6324
6862
|
childProcess2.execFileSync("npm", ["install", "--omit=dev"], {
|
|
6325
6863
|
cwd: stagedDir,
|
|
6326
6864
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -6335,8 +6873,8 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6335
6873
|
}
|
|
6336
6874
|
})();
|
|
6337
6875
|
swapRollbackDir = swapResult.rollbackDir;
|
|
6338
|
-
const installedPackageJsonPath =
|
|
6339
|
-
const installedPackage =
|
|
6876
|
+
const installedPackageJsonPath = path12.join(pluginDir, "package.json");
|
|
6877
|
+
const installedPackage = fs10.existsSync(installedPackageJsonPath) ? JSON.parse(fs10.readFileSync(installedPackageJsonPath, "utf8")) : {};
|
|
6340
6878
|
return {
|
|
6341
6879
|
rollbackDir: swapRollbackDir,
|
|
6342
6880
|
version: typeof installedPackage.version === "string" ? installedPackage.version : void 0
|
|
@@ -6351,8 +6889,8 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6351
6889
|
}
|
|
6352
6890
|
);
|
|
6353
6891
|
} finally {
|
|
6354
|
-
|
|
6355
|
-
|
|
6892
|
+
fs10.rmSync(stagedDir, { recursive: true, force: true });
|
|
6893
|
+
fs10.rmSync(tempRoot, { recursive: true, force: true });
|
|
6356
6894
|
}
|
|
6357
6895
|
}
|
|
6358
6896
|
function restartOpenclawGateway() {
|
|
@@ -6370,15 +6908,15 @@ function restartOpenclawGateway() {
|
|
|
6370
6908
|
});
|
|
6371
6909
|
}
|
|
6372
6910
|
function cmdInit() {
|
|
6373
|
-
const configPath =
|
|
6374
|
-
if (
|
|
6911
|
+
const configPath = path12.join(process.cwd(), "remnic.config.json");
|
|
6912
|
+
if (fs10.existsSync(configPath)) {
|
|
6375
6913
|
console.log(`Config already exists: ${configPath}`);
|
|
6376
6914
|
return;
|
|
6377
6915
|
}
|
|
6378
6916
|
const template = {
|
|
6379
6917
|
remnic: {
|
|
6380
6918
|
openaiApiKey: "${OPENAI_API_KEY}",
|
|
6381
|
-
memoryDir:
|
|
6919
|
+
memoryDir: path12.join(process.cwd(), ".remnic", "memory"),
|
|
6382
6920
|
memoryOsPreset: "balanced"
|
|
6383
6921
|
},
|
|
6384
6922
|
server: {
|
|
@@ -6387,7 +6925,7 @@ function cmdInit() {
|
|
|
6387
6925
|
authToken: "${REMNIC_AUTH_TOKEN}"
|
|
6388
6926
|
}
|
|
6389
6927
|
};
|
|
6390
|
-
|
|
6928
|
+
fs10.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
|
|
6391
6929
|
console.log(`Created ${configPath}`);
|
|
6392
6930
|
console.log("\nSet these environment variables:");
|
|
6393
6931
|
console.log(" export OPENAI_API_KEY=sk-...");
|
|
@@ -6396,6 +6934,18 @@ function cmdInit() {
|
|
|
6396
6934
|
console.log("\nThen start the server:");
|
|
6397
6935
|
console.log(" npx --package @remnic/server remnic-server");
|
|
6398
6936
|
}
|
|
6937
|
+
function resolveStatusProbeToken() {
|
|
6938
|
+
const operatorToken = oauthResolveOperatorToken();
|
|
6939
|
+
if (operatorToken) return operatorToken;
|
|
6940
|
+
try {
|
|
6941
|
+
const usable = listTokens().find(
|
|
6942
|
+
(t) => t.connector !== "chatgpt" && typeof t.token === "string" && t.token.length > 0
|
|
6943
|
+
);
|
|
6944
|
+
if (usable) return usable.token;
|
|
6945
|
+
} catch {
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
6948
|
+
var __statusHealthTestHooks = { resolveStatusProbeToken };
|
|
6399
6949
|
async function cmdStatus(json) {
|
|
6400
6950
|
const { running, pid } = isServiceRunning();
|
|
6401
6951
|
if (json) {
|
|
@@ -6408,18 +6958,34 @@ async function cmdStatus(json) {
|
|
|
6408
6958
|
}
|
|
6409
6959
|
console.log(`Remnic server: running${pid ? ` (pid ${pid})` : ""}`);
|
|
6410
6960
|
const port = inferPort();
|
|
6961
|
+
const probeToken = resolveStatusProbeToken();
|
|
6411
6962
|
const controller = new AbortController();
|
|
6412
6963
|
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
6413
6964
|
try {
|
|
6414
6965
|
const response = await fetch(`http://127.0.0.1:${port}/engram/v1/health`, {
|
|
6415
|
-
signal: controller.signal
|
|
6966
|
+
signal: controller.signal,
|
|
6967
|
+
...probeToken ? { headers: { Authorization: `Bearer ${probeToken}` } } : {}
|
|
6416
6968
|
});
|
|
6417
6969
|
if (!response.ok) {
|
|
6418
|
-
|
|
6970
|
+
const hint = response.status === 401 && !probeToken ? " (daemon requires auth and no local token was found \u2014 set REMNIC_AUTH_TOKEN, configure server.authToken, or run 'remnic token generate')" : response.status === 401 ? " (local token rejected by the daemon)" : "";
|
|
6971
|
+
console.log(`Health: server responded with ${response.status} ${response.statusText}${hint}`);
|
|
6419
6972
|
} else {
|
|
6420
6973
|
const health = await response.json();
|
|
6421
6974
|
const status = typeof health.status === "string" ? health.status : "ok";
|
|
6422
6975
|
console.log(`Health: ${status}`);
|
|
6976
|
+
const qmd = health.qmd;
|
|
6977
|
+
if (qmd?.pendingEmbeddings != null) {
|
|
6978
|
+
console.log(` Pending embeddings: ${qmd.pendingEmbeddings}`);
|
|
6979
|
+
if (qmd.oldestPendingAgeMs != null) {
|
|
6980
|
+
console.log(` Oldest pending: ${Math.round(qmd.oldestPendingAgeMs / 6e4)}m`);
|
|
6981
|
+
}
|
|
6982
|
+
if (qmd.embeddingBacklogThreshold != null) {
|
|
6983
|
+
console.log(` Backlog threshold: ${qmd.embeddingBacklogThreshold}`);
|
|
6984
|
+
}
|
|
6985
|
+
}
|
|
6986
|
+
if (qmd?.degradedReason) {
|
|
6987
|
+
console.log(` Degraded: ${qmd.degradedReason}`);
|
|
6988
|
+
}
|
|
6423
6989
|
}
|
|
6424
6990
|
} catch {
|
|
6425
6991
|
console.log("Health: unable to reach server");
|
|
@@ -6429,7 +6995,7 @@ async function cmdStatus(json) {
|
|
|
6429
6995
|
}
|
|
6430
6996
|
function oauthReadConfigRecord(configPath) {
|
|
6431
6997
|
try {
|
|
6432
|
-
const parsed = JSON.parse(
|
|
6998
|
+
const parsed = JSON.parse(fs10.readFileSync(configPath, "utf8"));
|
|
6433
6999
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
6434
7000
|
return parsed;
|
|
6435
7001
|
}
|
|
@@ -6480,14 +7046,14 @@ function oauthResolveOperatorToken() {
|
|
|
6480
7046
|
const server = raw.server;
|
|
6481
7047
|
if (server && typeof server === "object" && "authToken" in server) {
|
|
6482
7048
|
const candidate = server.authToken;
|
|
6483
|
-
if (typeof candidate === "string" && candidate.length > 0) {
|
|
7049
|
+
if (typeof candidate === "string" && candidate.length > 0 && !candidate.includes("${")) {
|
|
6484
7050
|
return candidate;
|
|
6485
7051
|
}
|
|
6486
7052
|
}
|
|
6487
7053
|
}
|
|
6488
7054
|
return void 0;
|
|
6489
7055
|
}
|
|
6490
|
-
async function oauthFetch(method,
|
|
7056
|
+
async function oauthFetch(method, path13, token, body) {
|
|
6491
7057
|
const controller = new AbortController();
|
|
6492
7058
|
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
6493
7059
|
try {
|
|
@@ -6506,7 +7072,7 @@ async function oauthFetch(method, path12, token, body) {
|
|
|
6506
7072
|
if (body !== void 0) {
|
|
6507
7073
|
init.body = JSON.stringify(body);
|
|
6508
7074
|
}
|
|
6509
|
-
const response = await fetch(`${oauthResolveBaseUrl()}${
|
|
7075
|
+
const response = await fetch(`${oauthResolveBaseUrl()}${path13}`, init);
|
|
6510
7076
|
if (response.status === 401) {
|
|
6511
7077
|
throw new Error(
|
|
6512
7078
|
"operator token rejected by remnic-server (HTTP 401). Update `server.authToken` or `REMNIC_AUTH_TOKEN` to match the running daemon."
|
|
@@ -6843,14 +7409,14 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
6843
7409
|
console.error("Usage: remnic query <text>");
|
|
6844
7410
|
process.exit(1);
|
|
6845
7411
|
}
|
|
6846
|
-
|
|
7412
|
+
initLogger2();
|
|
6847
7413
|
const configPath = resolveConfigPath();
|
|
6848
|
-
const raw =
|
|
6849
|
-
const remnicCfg =
|
|
6850
|
-
const config =
|
|
6851
|
-
const orchestrator = new
|
|
7414
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
7415
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
7416
|
+
const config = parseConfig3(remnicCfg);
|
|
7417
|
+
const orchestrator = new Orchestrator2(config);
|
|
6852
7418
|
await orchestrator.initialize();
|
|
6853
|
-
const service = new
|
|
7419
|
+
const service = new EngramAccessService2(orchestrator);
|
|
6854
7420
|
const recallRequest = buildQueryRecallRequest(queryText);
|
|
6855
7421
|
try {
|
|
6856
7422
|
if (explain) {
|
|
@@ -7014,15 +7580,15 @@ async function runXrayCommand(rest, io) {
|
|
|
7014
7580
|
async function cmdXray(rest) {
|
|
7015
7581
|
const { rawQuery, options } = extractXrayRawArgs(rest);
|
|
7016
7582
|
parseXrayCliOptions(rawQuery, options);
|
|
7017
|
-
|
|
7583
|
+
initLogger2();
|
|
7018
7584
|
const configPath = resolveConfigPath();
|
|
7019
|
-
const raw =
|
|
7020
|
-
const remnicCfg =
|
|
7021
|
-
const config =
|
|
7022
|
-
const orchestrator = new
|
|
7585
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
7586
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
7587
|
+
const config = parseConfig3(remnicCfg);
|
|
7588
|
+
const orchestrator = new Orchestrator2(config);
|
|
7023
7589
|
await orchestrator.initialize();
|
|
7024
7590
|
await orchestrator.deferredReady;
|
|
7025
|
-
const service = new
|
|
7591
|
+
const service = new EngramAccessService2(orchestrator);
|
|
7026
7592
|
try {
|
|
7027
7593
|
await runXrayCommand(rest, {
|
|
7028
7594
|
recallXray: (request) => service.recallXray(request),
|
|
@@ -7037,11 +7603,11 @@ async function cmdXray(rest) {
|
|
|
7037
7603
|
}
|
|
7038
7604
|
}
|
|
7039
7605
|
async function cmdVersions(rest) {
|
|
7040
|
-
|
|
7606
|
+
initLogger2();
|
|
7041
7607
|
const configPath = resolveConfigPath();
|
|
7042
|
-
const raw =
|
|
7043
|
-
const remnicCfg =
|
|
7044
|
-
const config =
|
|
7608
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
7609
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
7610
|
+
const config = parseConfig3(remnicCfg);
|
|
7045
7611
|
if (!config.versioningEnabled) {
|
|
7046
7612
|
console.error("Page versioning is disabled (versioningEnabled = false).");
|
|
7047
7613
|
process.exit(1);
|
|
@@ -7061,7 +7627,7 @@ async function cmdVersions(rest) {
|
|
|
7061
7627
|
console.error("Usage: remnic versions list <page-path>");
|
|
7062
7628
|
process.exit(1);
|
|
7063
7629
|
}
|
|
7064
|
-
const absPath =
|
|
7630
|
+
const absPath = path12.resolve(pagePath);
|
|
7065
7631
|
const history = await listVersions(absPath, versioningConfig, memDir);
|
|
7066
7632
|
if (json) {
|
|
7067
7633
|
console.log(JSON.stringify(history, null, 2));
|
|
@@ -7086,7 +7652,7 @@ async function cmdVersions(rest) {
|
|
|
7086
7652
|
console.error("Usage: remnic versions show <page-path> <version-id>");
|
|
7087
7653
|
process.exit(1);
|
|
7088
7654
|
}
|
|
7089
|
-
const absPath =
|
|
7655
|
+
const absPath = path12.resolve(pagePath);
|
|
7090
7656
|
try {
|
|
7091
7657
|
const content = await getVersion(absPath, versionId, versioningConfig, memDir);
|
|
7092
7658
|
console.log(content);
|
|
@@ -7104,7 +7670,7 @@ async function cmdVersions(rest) {
|
|
|
7104
7670
|
console.error("Usage: remnic versions diff <page-path> <v1> <v2>");
|
|
7105
7671
|
process.exit(1);
|
|
7106
7672
|
}
|
|
7107
|
-
const absPath =
|
|
7673
|
+
const absPath = path12.resolve(pagePath);
|
|
7108
7674
|
try {
|
|
7109
7675
|
const diffOutput = await diffVersions(absPath, v1, v2, versioningConfig, memDir);
|
|
7110
7676
|
console.log(diffOutput);
|
|
@@ -7121,7 +7687,7 @@ async function cmdVersions(rest) {
|
|
|
7121
7687
|
console.error("Usage: remnic versions revert <page-path> <version-id>");
|
|
7122
7688
|
process.exit(1);
|
|
7123
7689
|
}
|
|
7124
|
-
const absPath =
|
|
7690
|
+
const absPath = path12.resolve(pagePath);
|
|
7125
7691
|
try {
|
|
7126
7692
|
const version = await revertToVersion(absPath, versionId, versioningConfig, void 0, memDir);
|
|
7127
7693
|
if (json) {
|
|
@@ -7153,15 +7719,15 @@ Options:
|
|
|
7153
7719
|
}
|
|
7154
7720
|
}
|
|
7155
7721
|
async function cmdEnrich(rest) {
|
|
7156
|
-
|
|
7722
|
+
initLogger2();
|
|
7157
7723
|
const configPath = resolveConfigPath();
|
|
7158
|
-
const raw =
|
|
7159
|
-
const remnicCfg =
|
|
7160
|
-
const config =
|
|
7724
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
7725
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
7726
|
+
const config = parseConfig3(remnicCfg);
|
|
7161
7727
|
const subcommand = rest[0];
|
|
7162
7728
|
if (subcommand === "audit") {
|
|
7163
7729
|
const memoryDir2 = expandTilde(config.memoryDir);
|
|
7164
|
-
const auditDir2 =
|
|
7730
|
+
const auditDir2 = path12.join(memoryDir2, "enrichment");
|
|
7165
7731
|
const sinceFlag = resolveFlag(rest.slice(1), "--since");
|
|
7166
7732
|
const entries = await readAuditLog(auditDir2, sinceFlag ?? void 0);
|
|
7167
7733
|
if (entries.length === 0) {
|
|
@@ -7185,7 +7751,7 @@ async function cmdEnrich(rest) {
|
|
|
7185
7751
|
pipelineConfig2.providers = [
|
|
7186
7752
|
{ id: "web-search", enabled: true, costTier: "cheap" }
|
|
7187
7753
|
];
|
|
7188
|
-
const orchestrator2 = new
|
|
7754
|
+
const orchestrator2 = new Orchestrator2(config);
|
|
7189
7755
|
await orchestrator2.initialize();
|
|
7190
7756
|
await orchestrator2.deferredReady;
|
|
7191
7757
|
const searchBackend2 = orchestrator2.qmd;
|
|
@@ -7221,7 +7787,7 @@ Registered providers:`);
|
|
|
7221
7787
|
console.error("Usage: remnic enrich <entity-name> | --all | --dry-run | audit | providers");
|
|
7222
7788
|
process.exit(1);
|
|
7223
7789
|
}
|
|
7224
|
-
const orchestrator = new
|
|
7790
|
+
const orchestrator = new Orchestrator2(config);
|
|
7225
7791
|
await orchestrator.initialize();
|
|
7226
7792
|
await orchestrator.deferredReady;
|
|
7227
7793
|
const storage = await orchestrator.getStorage(config.defaultNamespace);
|
|
@@ -7286,18 +7852,13 @@ Registered providers:`);
|
|
|
7286
7852
|
return;
|
|
7287
7853
|
}
|
|
7288
7854
|
const memoryDir = expandTilde(config.memoryDir);
|
|
7289
|
-
const auditDir =
|
|
7855
|
+
const auditDir = path12.join(memoryDir, "enrichment");
|
|
7290
7856
|
let totalPersisted = 0;
|
|
7291
7857
|
for (const result of results) {
|
|
7292
7858
|
for (const candidate of result.acceptedCandidates) {
|
|
7293
7859
|
let persisted = false;
|
|
7294
7860
|
try {
|
|
7295
|
-
await storage
|
|
7296
|
-
confidence: candidate.confidence,
|
|
7297
|
-
tags: [...candidate.tags ?? [], "enrichment", candidate.source],
|
|
7298
|
-
entityRef: result.entityName,
|
|
7299
|
-
source: `enrichment:${candidate.source}`
|
|
7300
|
-
});
|
|
7861
|
+
await persistEnrichmentCandidate(storage, result.entityName, candidate);
|
|
7301
7862
|
persisted = true;
|
|
7302
7863
|
totalPersisted++;
|
|
7303
7864
|
} catch (err) {
|
|
@@ -7352,7 +7913,7 @@ Registered providers:`);
|
|
|
7352
7913
|
}
|
|
7353
7914
|
}
|
|
7354
7915
|
async function cmdProcedural(rest) {
|
|
7355
|
-
|
|
7916
|
+
initLogger2();
|
|
7356
7917
|
const subcommand = rest[0];
|
|
7357
7918
|
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
7358
7919
|
console.log(`remnic procedural \u2014 Procedural memory operations (issue #567)
|
|
@@ -7405,13 +7966,13 @@ Shared with:
|
|
|
7405
7966
|
process.exit(1);
|
|
7406
7967
|
}
|
|
7407
7968
|
const configPath = resolveConfigPath();
|
|
7408
|
-
const raw =
|
|
7409
|
-
const remnicCfg =
|
|
7410
|
-
const config =
|
|
7969
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
7970
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
7971
|
+
const config = parseConfig3(remnicCfg);
|
|
7411
7972
|
const memoryDir = expandTilde(
|
|
7412
7973
|
typeof memoryDirOverride === "string" && memoryDirOverride.length > 0 ? memoryDirOverride : config.memoryDir ?? resolveMemoryDir()
|
|
7413
7974
|
);
|
|
7414
|
-
const storage = new
|
|
7975
|
+
const storage = new StorageManager2(memoryDir);
|
|
7415
7976
|
const report = await computeProcedureStats({ storage, config });
|
|
7416
7977
|
if (format === "json") {
|
|
7417
7978
|
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
@@ -7420,11 +7981,11 @@ Shared with:
|
|
|
7420
7981
|
process.stdout.write(formatProcedureStatsText(report));
|
|
7421
7982
|
}
|
|
7422
7983
|
async function cmdExtensions(action, rest) {
|
|
7423
|
-
|
|
7984
|
+
initLogger2();
|
|
7424
7985
|
const configPath = resolveConfigPath();
|
|
7425
|
-
const raw =
|
|
7426
|
-
const remnicCfg =
|
|
7427
|
-
const config =
|
|
7986
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
7987
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
7988
|
+
const config = parseConfig3(remnicCfg);
|
|
7428
7989
|
const root = resolveExtensionsRoot(config);
|
|
7429
7990
|
const noopLog = { warn: () => {
|
|
7430
7991
|
}, debug: () => {
|
|
@@ -7473,7 +8034,7 @@ Root: ${root}`);
|
|
|
7473
8034
|
const extensions = await discoverMemoryExtensions(root, warnLog);
|
|
7474
8035
|
let entries = [];
|
|
7475
8036
|
try {
|
|
7476
|
-
entries =
|
|
8037
|
+
entries = fs10.readdirSync(root);
|
|
7477
8038
|
} catch {
|
|
7478
8039
|
console.log(`Extensions root does not exist: ${root}`);
|
|
7479
8040
|
process.exitCode = 0;
|
|
@@ -7482,9 +8043,9 @@ Root: ${root}`);
|
|
|
7482
8043
|
const validNames = new Set(extensions.map((e) => e.name));
|
|
7483
8044
|
let errors = 0;
|
|
7484
8045
|
for (const entry of entries) {
|
|
7485
|
-
const entryPath =
|
|
8046
|
+
const entryPath = path12.join(root, entry);
|
|
7486
8047
|
try {
|
|
7487
|
-
if (!
|
|
8048
|
+
if (!fs10.statSync(entryPath).isDirectory()) continue;
|
|
7488
8049
|
} catch {
|
|
7489
8050
|
continue;
|
|
7490
8051
|
}
|
|
@@ -7514,11 +8075,11 @@ Root: ${root}`);
|
|
|
7514
8075
|
}
|
|
7515
8076
|
}
|
|
7516
8077
|
async function cmdBriefing(rest) {
|
|
7517
|
-
|
|
8078
|
+
initLogger2();
|
|
7518
8079
|
const configPath = resolveConfigPath();
|
|
7519
|
-
const raw =
|
|
7520
|
-
const remnicCfg =
|
|
7521
|
-
const config =
|
|
8080
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
8081
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
8082
|
+
const config = parseConfig3(remnicCfg);
|
|
7522
8083
|
if (!config.briefing.enabled) {
|
|
7523
8084
|
console.error("Briefing is disabled in config (briefing.enabled = false).");
|
|
7524
8085
|
process.exit(1);
|
|
@@ -7571,7 +8132,7 @@ async function cmdBriefing(rest) {
|
|
|
7571
8132
|
process.exit(1);
|
|
7572
8133
|
}
|
|
7573
8134
|
const format = effectiveFormatFlag === "json" ? "json" : effectiveFormatFlag === "markdown" ? "markdown" : config.briefing.defaultFormat;
|
|
7574
|
-
const orchestrator = new
|
|
8135
|
+
const orchestrator = new Orchestrator2(config);
|
|
7575
8136
|
await orchestrator.initialize();
|
|
7576
8137
|
const storage = await orchestrator.getStorage(config.defaultNamespace);
|
|
7577
8138
|
const calendarSource = config.briefing.calendarSource ? new FileCalendarSource(config.briefing.calendarSource) : void 0;
|
|
@@ -7596,10 +8157,10 @@ async function cmdBriefing(rest) {
|
|
|
7596
8157
|
if (save) {
|
|
7597
8158
|
try {
|
|
7598
8159
|
const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
|
|
7599
|
-
|
|
8160
|
+
fs10.mkdirSync(saveDir, { recursive: true });
|
|
7600
8161
|
const filename = briefingFilename(new Date(result.window.to), format);
|
|
7601
|
-
const filePath =
|
|
7602
|
-
|
|
8162
|
+
const filePath = path12.join(saveDir, filename);
|
|
8163
|
+
fs10.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
|
|
7603
8164
|
console.error(`Saved briefing: ${filePath}`);
|
|
7604
8165
|
} catch (err) {
|
|
7605
8166
|
console.error(`Failed to save briefing: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -7617,17 +8178,19 @@ async function cmdDoctor() {
|
|
|
7617
8178
|
detail: `${nodeVersion} (requires >= 22.12.0)`
|
|
7618
8179
|
});
|
|
7619
8180
|
const configPath = resolveConfigPath();
|
|
7620
|
-
const configExists =
|
|
8181
|
+
const configExists = fs10.existsSync(configPath);
|
|
7621
8182
|
checks.push({ name: "Config file", ok: configExists, detail: configPath });
|
|
7622
8183
|
let standaloneConfig;
|
|
7623
8184
|
let standaloneConfigError;
|
|
7624
8185
|
let standaloneOpenaiApiKeyExplicitlyFalse = false;
|
|
8186
|
+
let configuredNs = { invalid: false };
|
|
7625
8187
|
if (configExists) {
|
|
7626
8188
|
try {
|
|
7627
|
-
const raw = JSON.parse(
|
|
7628
|
-
const remnicCfg =
|
|
8189
|
+
const raw = JSON.parse(fs10.readFileSync(configPath, "utf8"));
|
|
8190
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
7629
8191
|
standaloneOpenaiApiKeyExplicitlyFalse = isOpenaiApiKeyDisabled(remnicCfg.openaiApiKey);
|
|
7630
|
-
|
|
8192
|
+
configuredNs = readConfiguredNamespace(remnicCfg);
|
|
8193
|
+
standaloneConfig = parseConfig3(remnicCfg);
|
|
7631
8194
|
} catch (err) {
|
|
7632
8195
|
standaloneConfigError = err instanceof Error ? err.message : String(err);
|
|
7633
8196
|
}
|
|
@@ -7636,16 +8199,39 @@ async function cmdDoctor() {
|
|
|
7636
8199
|
try {
|
|
7637
8200
|
memoryDir = resolveMemoryDir();
|
|
7638
8201
|
} catch {
|
|
7639
|
-
memoryDir =
|
|
8202
|
+
memoryDir = parseConfig3({}).memoryDir;
|
|
7640
8203
|
}
|
|
7641
8204
|
try {
|
|
7642
|
-
|
|
8205
|
+
fs10.mkdirSync(memoryDir, { recursive: true });
|
|
7643
8206
|
checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
|
|
7644
8207
|
} catch {
|
|
7645
8208
|
checks.push({ name: "Memory directory", ok: false, detail: `cannot create ${memoryDir}` });
|
|
7646
8209
|
}
|
|
8210
|
+
try {
|
|
8211
|
+
const quarantined = await new WriteQuarantineStore2(memoryDir).count();
|
|
8212
|
+
checks.push({
|
|
8213
|
+
name: "Quarantined writes",
|
|
8214
|
+
ok: quarantined === 0,
|
|
8215
|
+
warn: quarantined > 0,
|
|
8216
|
+
detail: quarantined === 0 ? "none" : `${quarantined} parked`,
|
|
8217
|
+
remediation: quarantined > 0 ? "Inspect with `remnic quarantine list`, then fix the client's namespace config so writes are stored instead of parked." : void 0
|
|
8218
|
+
});
|
|
8219
|
+
} catch {
|
|
8220
|
+
checks.push({
|
|
8221
|
+
name: "Quarantined writes",
|
|
8222
|
+
ok: false,
|
|
8223
|
+
warn: true,
|
|
8224
|
+
detail: "unable to inspect quarantine store"
|
|
8225
|
+
});
|
|
8226
|
+
}
|
|
8227
|
+
const nsPolicyCheck = buildNamespacePolicyCheck({
|
|
8228
|
+
invalid: configuredNs.invalid,
|
|
8229
|
+
configuredNamespace: configuredNs.configuredNamespace,
|
|
8230
|
+
config: standaloneConfig
|
|
8231
|
+
});
|
|
8232
|
+
if (nsPolicyCheck) checks.push(nsPolicyCheck);
|
|
7647
8233
|
const openclawConfigPath = resolveOpenclawConfigPath();
|
|
7648
|
-
const openclawConfigExists =
|
|
8234
|
+
const openclawConfigExists = fs10.existsSync(openclawConfigPath);
|
|
7649
8235
|
let openclawConfig = {};
|
|
7650
8236
|
let openclawConfigValid = false;
|
|
7651
8237
|
let openclawPluginModeConfigured = false;
|
|
@@ -7653,7 +8239,7 @@ async function cmdDoctor() {
|
|
|
7653
8239
|
let activeOpenclawEntryConfig = null;
|
|
7654
8240
|
if (openclawConfigExists) {
|
|
7655
8241
|
try {
|
|
7656
|
-
const parsed = JSON.parse(
|
|
8242
|
+
const parsed = JSON.parse(fs10.readFileSync(openclawConfigPath, "utf-8"));
|
|
7657
8243
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
7658
8244
|
openclawConfig = parsed;
|
|
7659
8245
|
openclawConfigValid = true;
|
|
@@ -7729,13 +8315,13 @@ async function cmdDoctor() {
|
|
|
7729
8315
|
const rawMemoryDir = entryConfig?.memoryDir;
|
|
7730
8316
|
const configuredMemoryDir = typeof rawMemoryDir === "string" ? rawMemoryDir : void 0;
|
|
7731
8317
|
if (configuredMemoryDir) {
|
|
7732
|
-
const resolvedMemDir =
|
|
8318
|
+
const resolvedMemDir = path12.resolve(expandTilde(configuredMemoryDir));
|
|
7733
8319
|
let memDirOk = false;
|
|
7734
8320
|
let memDirDetail = `${resolvedMemDir} (not found)`;
|
|
7735
8321
|
let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
|
|
7736
|
-
if (
|
|
8322
|
+
if (fs10.existsSync(resolvedMemDir)) {
|
|
7737
8323
|
try {
|
|
7738
|
-
const stat =
|
|
8324
|
+
const stat = fs10.statSync(resolvedMemDir);
|
|
7739
8325
|
if (stat.isDirectory()) {
|
|
7740
8326
|
memDirOk = true;
|
|
7741
8327
|
memDirDetail = resolvedMemDir;
|
|
@@ -7877,12 +8463,12 @@ async function cmdDoctor() {
|
|
|
7877
8463
|
}
|
|
7878
8464
|
function cmdConfig() {
|
|
7879
8465
|
const configPath = resolveConfigPath();
|
|
7880
|
-
if (!
|
|
8466
|
+
if (!fs10.existsSync(configPath)) {
|
|
7881
8467
|
console.log("No config file found. Run `remnic init` to create one.");
|
|
7882
8468
|
return;
|
|
7883
8469
|
}
|
|
7884
8470
|
console.log(`Config: ${configPath}`);
|
|
7885
|
-
const rawConfig =
|
|
8471
|
+
const rawConfig = fs10.readFileSync(configPath, "utf8");
|
|
7886
8472
|
const redacted = rawConfig.replace(
|
|
7887
8473
|
/("(?:openaiApiKey|localLlmApiKey|authToken|apiKey|remoteSearchApiKey|meilisearchApiKey|opikApiKey)"\s*:\s*")([^"]*)(")/g,
|
|
7888
8474
|
"$1[REDACTED]$3"
|
|
@@ -7929,7 +8515,7 @@ async function cmdMigrate(json, rollback) {
|
|
|
7929
8515
|
console.log(` Rollback: ${result.rollbackCommand}`);
|
|
7930
8516
|
}
|
|
7931
8517
|
function cmdOnboard(dirPath, json) {
|
|
7932
|
-
const directory =
|
|
8518
|
+
const directory = path12.resolve(dirPath || process.cwd());
|
|
7933
8519
|
const result = onboard({ directory });
|
|
7934
8520
|
if (json) {
|
|
7935
8521
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -7948,7 +8534,7 @@ Suggested namespace: ${result.plan.suggestedNamespace}`);
|
|
|
7948
8534
|
async function cmdCurate(targetPath, json) {
|
|
7949
8535
|
const memoryDir = resolveMemoryDir();
|
|
7950
8536
|
const result = await curate({
|
|
7951
|
-
targetPath:
|
|
8537
|
+
targetPath: path12.resolve(targetPath),
|
|
7952
8538
|
memoryDir,
|
|
7953
8539
|
source: "curation",
|
|
7954
8540
|
checkDuplicates: true,
|
|
@@ -7986,13 +8572,13 @@ async function cmdReview(action, rest) {
|
|
|
7986
8572
|
console.error("Usage: remnic review <approve|dismiss|flag> <id>");
|
|
7987
8573
|
process.exit(1);
|
|
7988
8574
|
}
|
|
7989
|
-
const storage = new
|
|
8575
|
+
const storage = new StorageManager2(memoryDir);
|
|
7990
8576
|
const configPath = resolveConfigPath();
|
|
7991
8577
|
let tombstonesConfig = null;
|
|
7992
8578
|
try {
|
|
7993
|
-
const rawCfg =
|
|
7994
|
-
const remnicCfg =
|
|
7995
|
-
const config =
|
|
8579
|
+
const rawCfg = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
8580
|
+
const remnicCfg = resolveRemnicConfigRecord3(rawCfg);
|
|
8581
|
+
const config = parseConfig3(remnicCfg);
|
|
7996
8582
|
tombstonesConfig = {
|
|
7997
8583
|
enabled: config.tombstonesEnabled,
|
|
7998
8584
|
semanticMatch: config.tombstonesSemanticMatch,
|
|
@@ -8078,7 +8664,7 @@ async function cmdSync(action, rest, json) {
|
|
|
8078
8664
|
}
|
|
8079
8665
|
function localOfflineSourceId(memoryDir) {
|
|
8080
8666
|
const host = os.hostname() || "unknown-host";
|
|
8081
|
-
const dirHash =
|
|
8667
|
+
const dirHash = createHash2("sha256").update(path12.resolve(memoryDir)).digest("hex").slice(0, 16);
|
|
8082
8668
|
return `remnic-local:${host}:${dirHash}`;
|
|
8083
8669
|
}
|
|
8084
8670
|
function normalizeOfflineRemoteUrl(raw) {
|
|
@@ -8442,8 +9028,8 @@ var APPEND_TOLERANT_RUNTIME_STATE_FILES = /* @__PURE__ */ new Set([
|
|
|
8442
9028
|
function isAppendTolerantOfflineRuntimeFile(relPath) {
|
|
8443
9029
|
if (!shouldPreferIncomingOfflineRuntimeFile(relPath)) return false;
|
|
8444
9030
|
const parts = relPath.split("/");
|
|
8445
|
-
const
|
|
8446
|
-
return APPEND_TOLERANT_RUNTIME_STATE_FILES.has(
|
|
9031
|
+
const basename2 = parts[parts.length - 1] ?? "";
|
|
9032
|
+
return APPEND_TOLERANT_RUNTIME_STATE_FILES.has(basename2);
|
|
8447
9033
|
}
|
|
8448
9034
|
function offlineFileContentChunkMatchesExpected(options) {
|
|
8449
9035
|
const { chunk, expected, offset } = options;
|
|
@@ -8476,10 +9062,10 @@ var OFFLINE_SYNC_CONTENT_MISSING_RETRY_MAX = 3;
|
|
|
8476
9062
|
var OFFLINE_SYNC_CONTENT_MISSING_RETRY_DELAY_MS = 250;
|
|
8477
9063
|
var OfflineRemoteFileChangedError = class extends Error {
|
|
8478
9064
|
path;
|
|
8479
|
-
constructor(
|
|
8480
|
-
super(`remote file changed while fetching offline content: ${
|
|
9065
|
+
constructor(path13) {
|
|
9066
|
+
super(`remote file changed while fetching offline content: ${path13}`);
|
|
8481
9067
|
this.name = "OfflineRemoteFileChangedError";
|
|
8482
|
-
this.path =
|
|
9068
|
+
this.path = path13;
|
|
8483
9069
|
}
|
|
8484
9070
|
};
|
|
8485
9071
|
function isOfflineRemoteFileChangedError(error) {
|
|
@@ -8670,15 +9256,15 @@ function offlineDirectPushFiles(options) {
|
|
|
8670
9256
|
}).sort((left, right) => right.bytes - left.bytes || left.path.localeCompare(right.path));
|
|
8671
9257
|
}
|
|
8672
9258
|
function resolveOfflineDirectHydrationPath(memoryDir, relPath) {
|
|
8673
|
-
const base =
|
|
8674
|
-
const target =
|
|
8675
|
-
const relative =
|
|
8676
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
9259
|
+
const base = path12.resolve(memoryDir);
|
|
9260
|
+
const target = path12.resolve(base, relPath);
|
|
9261
|
+
const relative = path12.relative(base, target);
|
|
9262
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path12.sep}`) || path12.isAbsolute(relative)) {
|
|
8677
9263
|
throw new Error(`offline sync direct hydration path escapes memory dir: ${relPath}`);
|
|
8678
9264
|
}
|
|
8679
9265
|
return target;
|
|
8680
9266
|
}
|
|
8681
|
-
var OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES =
|
|
9267
|
+
var OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES = OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES2;
|
|
8682
9268
|
async function pushOfflineFileContent(args) {
|
|
8683
9269
|
if (args.readFileChunks) {
|
|
8684
9270
|
return pushOfflineFileContentFromChunkReader(args);
|
|
@@ -8686,7 +9272,7 @@ async function pushOfflineFileContent(args) {
|
|
|
8686
9272
|
let offset = 0;
|
|
8687
9273
|
let finalResult = null;
|
|
8688
9274
|
let remoteSatisfiedResult = null;
|
|
8689
|
-
const hash =
|
|
9275
|
+
const hash = createHash2("sha256");
|
|
8690
9276
|
let bytes = 0;
|
|
8691
9277
|
while (offset < args.file.bytes || args.file.bytes === 0 && offset === 0) {
|
|
8692
9278
|
const chunk = await readOfflineSyncFileContentChunk({
|
|
@@ -8743,13 +9329,13 @@ async function pushOfflineFileContent(args) {
|
|
|
8743
9329
|
}
|
|
8744
9330
|
async function pushOfflineFileContentFromChunkReader(args) {
|
|
8745
9331
|
const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
|
|
8746
|
-
const stat =
|
|
9332
|
+
const stat = fs10.statSync(filePath);
|
|
8747
9333
|
if (stat.mtimeMs !== args.file.mtimeMs) {
|
|
8748
9334
|
throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
|
|
8749
9335
|
}
|
|
8750
|
-
const hash =
|
|
9336
|
+
const hash = createHash2("sha256");
|
|
8751
9337
|
const chunks = args.readFileChunks({
|
|
8752
|
-
root:
|
|
9338
|
+
root: path12.resolve(args.memoryDir),
|
|
8753
9339
|
path: args.file.path,
|
|
8754
9340
|
filePath,
|
|
8755
9341
|
chunkSize: OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES
|
|
@@ -9187,147 +9773,6 @@ function waitForOfflineInterval(ms, setCancel) {
|
|
|
9187
9773
|
});
|
|
9188
9774
|
});
|
|
9189
9775
|
}
|
|
9190
|
-
async function createOfflineStorageIo(memoryDir) {
|
|
9191
|
-
const storage = new StorageManager(memoryDir);
|
|
9192
|
-
const header = await readHeader(memoryDir);
|
|
9193
|
-
let secureStoreKey = null;
|
|
9194
|
-
if (header) {
|
|
9195
|
-
storage.setSecureStoreRequired(true);
|
|
9196
|
-
const key = keyring.getKey(secureStoreDir(memoryDir));
|
|
9197
|
-
if (key) {
|
|
9198
|
-
storage.setSecureStoreKey(key);
|
|
9199
|
-
secureStoreKey = key;
|
|
9200
|
-
}
|
|
9201
|
-
}
|
|
9202
|
-
return {
|
|
9203
|
-
readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
|
|
9204
|
-
readFileDigest: async ({ filePath }) => {
|
|
9205
|
-
const hash = createHash("sha256");
|
|
9206
|
-
let bytes = 0;
|
|
9207
|
-
for await (const rawChunk of readOfflineSyncFileChunks({
|
|
9208
|
-
filePath,
|
|
9209
|
-
memoryDir,
|
|
9210
|
-
secureStoreKey,
|
|
9211
|
-
chunkSize: OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES
|
|
9212
|
-
})) {
|
|
9213
|
-
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
9214
|
-
hash.update(chunk);
|
|
9215
|
-
bytes += chunk.length;
|
|
9216
|
-
}
|
|
9217
|
-
return {
|
|
9218
|
-
sha256: hash.digest("hex"),
|
|
9219
|
-
bytes
|
|
9220
|
-
};
|
|
9221
|
-
},
|
|
9222
|
-
readFileChunks: ({ filePath, chunkSize }) => readOfflineSyncFileChunks({
|
|
9223
|
-
filePath,
|
|
9224
|
-
memoryDir,
|
|
9225
|
-
secureStoreKey,
|
|
9226
|
-
chunkSize
|
|
9227
|
-
}),
|
|
9228
|
-
writeFile: async ({ filePath, content }) => storage.writeOfflineSyncFile(filePath, content),
|
|
9229
|
-
writeStagingFile: async ({ filePath, content }) => storage.writeOfflineSyncStagingFile(filePath, content),
|
|
9230
|
-
writeFileChunks: async ({ filePath, chunks }) => storage.writeOfflineSyncFileChunks(filePath, chunks),
|
|
9231
|
-
deleteFile: async ({ filePath }) => storage.deleteOfflineSyncFile(filePath)
|
|
9232
|
-
};
|
|
9233
|
-
}
|
|
9234
|
-
async function* readOfflineSyncFileChunks(options) {
|
|
9235
|
-
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE);
|
|
9236
|
-
if (!isEncryptedFile(header)) {
|
|
9237
|
-
yield* readPlainOfflineFileChunks(options.filePath, options.chunkSize);
|
|
9238
|
-
return;
|
|
9239
|
-
}
|
|
9240
|
-
if (!options.secureStoreKey) {
|
|
9241
|
-
throw new SecureStoreLockedError(
|
|
9242
|
-
`secure-store is locked \u2014 cannot read encrypted file at ${options.filePath}. Run \`remnic secure-store unlock\` to decrypt.`
|
|
9243
|
-
);
|
|
9244
|
-
}
|
|
9245
|
-
yield* readEncryptedOfflineFileChunks({
|
|
9246
|
-
filePath: options.filePath,
|
|
9247
|
-
memoryDir: options.memoryDir,
|
|
9248
|
-
key: options.secureStoreKey,
|
|
9249
|
-
chunkSize: options.chunkSize
|
|
9250
|
-
});
|
|
9251
|
-
}
|
|
9252
|
-
async function readFilePrefix(filePath, length) {
|
|
9253
|
-
const handle = await fs7.promises.open(filePath, "r");
|
|
9254
|
-
try {
|
|
9255
|
-
const out = Buffer.alloc(length);
|
|
9256
|
-
const { bytesRead } = await handle.read(out, 0, length, 0);
|
|
9257
|
-
return out.subarray(0, bytesRead);
|
|
9258
|
-
} finally {
|
|
9259
|
-
await handle.close();
|
|
9260
|
-
}
|
|
9261
|
-
}
|
|
9262
|
-
async function* readPlainOfflineFileChunks(filePath, chunkSize) {
|
|
9263
|
-
const stream = fs7.createReadStream(filePath, { highWaterMark: chunkSize });
|
|
9264
|
-
for await (const chunk of stream) {
|
|
9265
|
-
yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
9266
|
-
}
|
|
9267
|
-
}
|
|
9268
|
-
async function* readEncryptedOfflineFileChunks(options) {
|
|
9269
|
-
const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
|
|
9270
|
-
if (header.length < MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE || !isEncryptedFile(header)) {
|
|
9271
|
-
throw new Error(`secure-store encrypted file is truncated: ${options.filePath}`);
|
|
9272
|
-
}
|
|
9273
|
-
const version = header.readUInt8(MAGIC_BYTES.length);
|
|
9274
|
-
const flags = header.readUInt8(MAGIC_BYTES.length + 1);
|
|
9275
|
-
if (version !== FILE_FORMAT_VERSION) {
|
|
9276
|
-
throw new Error(`secure-store file has unsupported version ${version}: ${options.filePath}`);
|
|
9277
|
-
}
|
|
9278
|
-
if (flags !== FILE_FORMAT_FLAGS) {
|
|
9279
|
-
throw new Error(`secure-store file has unsupported flags 0x${flags.toString(16)}: ${options.filePath}`);
|
|
9280
|
-
}
|
|
9281
|
-
const envelopeHeader = header.subarray(MAGIC_HEADER_SIZE);
|
|
9282
|
-
const envelopeVersion = envelopeHeader.readUInt8(ENVELOPE_LAYOUT.version);
|
|
9283
|
-
if (envelopeVersion !== ENVELOPE_VERSION) {
|
|
9284
|
-
throw new Error(`secure-store envelope has unsupported version ${envelopeVersion}: ${options.filePath}`);
|
|
9285
|
-
}
|
|
9286
|
-
const salt = envelopeHeader.subarray(
|
|
9287
|
-
ENVELOPE_LAYOUT.salt,
|
|
9288
|
-
ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH
|
|
9289
|
-
);
|
|
9290
|
-
const iv = envelopeHeader.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);
|
|
9291
|
-
const authTag = envelopeHeader.subarray(
|
|
9292
|
-
ENVELOPE_LAYOUT.authTag,
|
|
9293
|
-
ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
|
|
9294
|
-
);
|
|
9295
|
-
const decipher = createDecipheriv("aes-256-gcm", options.key, iv, {
|
|
9296
|
-
authTagLength: AUTH_TAG_LENGTH
|
|
9297
|
-
});
|
|
9298
|
-
decipher.setAuthTag(authTag);
|
|
9299
|
-
decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), filePathAad(options.filePath, options.memoryDir)]));
|
|
9300
|
-
let pending = Buffer.alloc(0);
|
|
9301
|
-
const stream = fs7.createReadStream(options.filePath, {
|
|
9302
|
-
start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
|
|
9303
|
-
highWaterMark: options.chunkSize
|
|
9304
|
-
});
|
|
9305
|
-
for await (const encryptedChunk of stream) {
|
|
9306
|
-
const plain = decipher.update(Buffer.isBuffer(encryptedChunk) ? encryptedChunk : Buffer.from(encryptedChunk));
|
|
9307
|
-
if (plain.length > 0) {
|
|
9308
|
-
pending = Buffer.concat([pending, plain], pending.length + plain.length);
|
|
9309
|
-
}
|
|
9310
|
-
while (pending.length >= options.chunkSize) {
|
|
9311
|
-
yield pending.subarray(0, options.chunkSize);
|
|
9312
|
-
pending = pending.subarray(options.chunkSize);
|
|
9313
|
-
}
|
|
9314
|
-
}
|
|
9315
|
-
const finalPlain = decipher.final();
|
|
9316
|
-
if (finalPlain.length > 0) {
|
|
9317
|
-
pending = Buffer.concat([pending, finalPlain], pending.length + finalPlain.length);
|
|
9318
|
-
}
|
|
9319
|
-
while (pending.length >= options.chunkSize) {
|
|
9320
|
-
yield pending.subarray(0, options.chunkSize);
|
|
9321
|
-
pending = pending.subarray(options.chunkSize);
|
|
9322
|
-
}
|
|
9323
|
-
if (pending.length > 0) yield pending;
|
|
9324
|
-
}
|
|
9325
|
-
function secureStoreEnvelopeHeaderAad(salt) {
|
|
9326
|
-
const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
|
|
9327
|
-
out.writeUInt8(ENVELOPE_VERSION, 0);
|
|
9328
|
-
Buffer.from(salt).copy(out, 1);
|
|
9329
|
-
return out;
|
|
9330
|
-
}
|
|
9331
9776
|
function formatOfflineLargeFilePushFailureMessage(failures) {
|
|
9332
9777
|
const paths = failures.slice(0, 5).map((failure) => `${failure.path}: ${failure.error}`).join("; ");
|
|
9333
9778
|
const suffix = failures.length > 5 ? `; +${failures.length - 5} more` : "";
|
|
@@ -9375,7 +9820,7 @@ function advanceOfflineBaseFilesForSuccessfulPush(options) {
|
|
|
9375
9820
|
return [...next.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
9376
9821
|
}
|
|
9377
9822
|
async function runOfflineSyncOnce(options) {
|
|
9378
|
-
|
|
9823
|
+
fs10.mkdirSync(options.memoryDir, { recursive: true });
|
|
9379
9824
|
let activeStatePath = options.statePath;
|
|
9380
9825
|
let priorState = await readOfflineSyncState(activeStatePath);
|
|
9381
9826
|
let syncNamespace = options.namespace ?? priorState?.namespace;
|
|
@@ -9413,8 +9858,22 @@ async function runOfflineSyncOnce(options) {
|
|
|
9413
9858
|
}
|
|
9414
9859
|
const baseFiles = priorState?.baseFiles ?? [];
|
|
9415
9860
|
const baseCapturedAt = priorState ? new Date(priorState.lastSyncedAt) : void 0;
|
|
9416
|
-
const
|
|
9861
|
+
const offlineStorage = await createConfiguredOfflineStorage(
|
|
9862
|
+
options.memoryDir,
|
|
9863
|
+
options.secureStoreEncryptOnWrite
|
|
9864
|
+
);
|
|
9865
|
+
const storageIo = await createOfflineStorageIo(options.memoryDir, offlineStorage);
|
|
9417
9866
|
const localSourceId = localOfflineSourceId(options.memoryDir);
|
|
9867
|
+
await drainOfflineSyncImpressions(options.memoryDir, options);
|
|
9868
|
+
await drainPendingLifecycleForOfflineSync(
|
|
9869
|
+
options.memoryDir,
|
|
9870
|
+
(ledgerPath) => createOfflineStorageForPath(
|
|
9871
|
+
options.memoryDir,
|
|
9872
|
+
ledgerPath,
|
|
9873
|
+
offlineStorage,
|
|
9874
|
+
options.secureStoreEncryptOnWrite ?? true
|
|
9875
|
+
).drainPendingMemoryLifecycleEventsForSyncAt(ledgerPath)
|
|
9876
|
+
);
|
|
9418
9877
|
const currentSnapshotForPush = await buildOfflineSyncSnapshotFromBase({
|
|
9419
9878
|
root: options.memoryDir,
|
|
9420
9879
|
sourceId: localSourceId,
|
|
@@ -9933,7 +10392,7 @@ function advanceOfflineLargeFileFailureCounts(options) {
|
|
|
9933
10392
|
}
|
|
9934
10393
|
return { counts: next, newlySkipped };
|
|
9935
10394
|
}
|
|
9936
|
-
function resolveOfflineSyncUserExcludes(rest) {
|
|
10395
|
+
function resolveOfflineSyncUserExcludes(rest, config) {
|
|
9937
10396
|
const globs = [];
|
|
9938
10397
|
for (let i = 0; i < rest.length; i += 1) {
|
|
9939
10398
|
if (rest[i] !== "--exclude") continue;
|
|
@@ -9944,27 +10403,17 @@ function resolveOfflineSyncUserExcludes(rest) {
|
|
|
9944
10403
|
globs.push(value.trim());
|
|
9945
10404
|
i += 1;
|
|
9946
10405
|
}
|
|
9947
|
-
const
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
const configured = remnicCfg.offlineSyncExcludes;
|
|
9952
|
-
if (configured !== void 0 && configured !== null) {
|
|
9953
|
-
if (!Array.isArray(configured)) {
|
|
9954
|
-
throw new Error("offlineSyncExcludes config must be an array of non-empty glob strings");
|
|
9955
|
-
}
|
|
9956
|
-
for (const entry of configured) {
|
|
9957
|
-
if (typeof entry !== "string" || entry.trim().length === 0) {
|
|
9958
|
-
throw new Error("offlineSyncExcludes config must contain only non-empty glob strings");
|
|
9959
|
-
}
|
|
9960
|
-
globs.push(entry.trim());
|
|
9961
|
-
}
|
|
10406
|
+
const configured = config.offlineSyncExcludes;
|
|
10407
|
+
if (configured !== void 0 && configured !== null) {
|
|
10408
|
+
if (!Array.isArray(configured)) {
|
|
10409
|
+
throw new Error("offlineSyncExcludes config must be an array of non-empty glob strings");
|
|
9962
10410
|
}
|
|
9963
|
-
|
|
9964
|
-
|
|
9965
|
-
|
|
10411
|
+
for (const entry of configured) {
|
|
10412
|
+
if (typeof entry !== "string" || entry.trim().length === 0) {
|
|
10413
|
+
throw new Error("offlineSyncExcludes config must contain only non-empty glob strings");
|
|
10414
|
+
}
|
|
10415
|
+
globs.push(entry.trim());
|
|
9966
10416
|
}
|
|
9967
|
-
throw error;
|
|
9968
10417
|
}
|
|
9969
10418
|
return compileOfflineSyncExcludeGlobs(globs);
|
|
9970
10419
|
}
|
|
@@ -9989,19 +10438,30 @@ Environment fallbacks:
|
|
|
9989
10438
|
REMNIC_OFFLINE_REMOTE_URL, REMNIC_OFFLINE_TOKEN, REMNIC_AUTH_TOKEN`);
|
|
9990
10439
|
return;
|
|
9991
10440
|
}
|
|
9992
|
-
const memoryDir =
|
|
10441
|
+
const memoryDir = path12.resolve(expandTilde(resolveRequiredValueFlag(rest, "--memory-dir") ?? resolveMemoryDir()));
|
|
9993
10442
|
const namespace = resolveRequiredValueFlag(rest, "--namespace");
|
|
9994
10443
|
const includeTranscripts = !hasFlag(rest, "--no-transcripts");
|
|
9995
10444
|
const stateOverride = resolveRequiredValueFlag(rest, "--state");
|
|
9996
10445
|
const statePathExplicit = stateOverride !== void 0;
|
|
9997
|
-
const
|
|
10446
|
+
const configPath = resolveConfigPath();
|
|
10447
|
+
let config;
|
|
10448
|
+
try {
|
|
10449
|
+
const rawConfig = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
10450
|
+
config = parseConfigQuietly(pickOfflineConfigRecord(rawConfig));
|
|
10451
|
+
} catch {
|
|
10452
|
+
throw new Error(
|
|
10453
|
+
"offline sync: failed to load the Remnic config \u2014 run `remnic doctor` and check the config file for errors"
|
|
10454
|
+
);
|
|
10455
|
+
}
|
|
10456
|
+
const userExcludeRegexps = resolveOfflineSyncUserExcludes(rest, config);
|
|
10457
|
+
const impressionRotation = resolveOfflineImpressionRotation(configPath);
|
|
9998
10458
|
const needsRemote = action === "prepare" || action === "sync" || action === "watch";
|
|
9999
10459
|
const remoteUrl = needsRemote ? resolveOfflineRemoteUrl(rest) : resolveOptionalOfflineRemoteUrl(rest);
|
|
10000
10460
|
const token = needsRemote ? resolveOfflineToken(rest) : void 0;
|
|
10001
|
-
const statePath = statePathExplicit ?
|
|
10461
|
+
const statePath = statePathExplicit ? path12.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
|
|
10002
10462
|
if (action === "prepare") {
|
|
10003
10463
|
if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
|
|
10004
|
-
|
|
10464
|
+
fs10.mkdirSync(memoryDir, { recursive: true });
|
|
10005
10465
|
const remoteSnapshot = await fetchOfflineSnapshot({
|
|
10006
10466
|
remoteUrl,
|
|
10007
10467
|
token,
|
|
@@ -10027,7 +10487,10 @@ Environment fallbacks:
|
|
|
10027
10487
|
statePath: existingState.statePath
|
|
10028
10488
|
});
|
|
10029
10489
|
}
|
|
10030
|
-
const storageIo = await createOfflineStorageIo(
|
|
10490
|
+
const storageIo = await createOfflineStorageIo(
|
|
10491
|
+
memoryDir,
|
|
10492
|
+
await createConfiguredOfflineStorage(memoryDir, config.secureStoreEncryptOnWrite)
|
|
10493
|
+
);
|
|
10031
10494
|
const pull = await applyOfflineSyncSnapshot({
|
|
10032
10495
|
root: memoryDir,
|
|
10033
10496
|
snapshot: remoteSnapshot,
|
|
@@ -10072,7 +10535,9 @@ Environment fallbacks:
|
|
|
10072
10535
|
includeTranscripts,
|
|
10073
10536
|
statePath,
|
|
10074
10537
|
statePathExplicit,
|
|
10075
|
-
userExcludeRegexps
|
|
10538
|
+
userExcludeRegexps,
|
|
10539
|
+
secureStoreEncryptOnWrite: config.secureStoreEncryptOnWrite,
|
|
10540
|
+
...impressionRotation
|
|
10076
10541
|
});
|
|
10077
10542
|
if (json) {
|
|
10078
10543
|
console.log(JSON.stringify(offlineSyncResultJsonSummary(result), null, 2));
|
|
@@ -10094,7 +10559,7 @@ Environment fallbacks:
|
|
|
10094
10559
|
return;
|
|
10095
10560
|
}
|
|
10096
10561
|
if (action === "status") {
|
|
10097
|
-
|
|
10562
|
+
fs10.mkdirSync(memoryDir, { recursive: true });
|
|
10098
10563
|
const state = statePath ? await readOfflineSyncState(statePath) : null;
|
|
10099
10564
|
if (state && remoteUrl && statePath) {
|
|
10100
10565
|
assertOfflineStateMatches({
|
|
@@ -10105,7 +10570,18 @@ Environment fallbacks:
|
|
|
10105
10570
|
statePath
|
|
10106
10571
|
});
|
|
10107
10572
|
}
|
|
10108
|
-
const
|
|
10573
|
+
const configuredStorage = await createConfiguredOfflineStorage(memoryDir, config.secureStoreEncryptOnWrite);
|
|
10574
|
+
const storageIo = await createOfflineStorageIo(memoryDir, configuredStorage);
|
|
10575
|
+
await drainOfflineSyncImpressions(memoryDir, impressionRotation);
|
|
10576
|
+
await drainPendingLifecycleForOfflineSync(
|
|
10577
|
+
memoryDir,
|
|
10578
|
+
(ledgerPath) => createOfflineStorageForPath(
|
|
10579
|
+
memoryDir,
|
|
10580
|
+
ledgerPath,
|
|
10581
|
+
configuredStorage,
|
|
10582
|
+
config.secureStoreEncryptOnWrite ?? true
|
|
10583
|
+
).drainPendingMemoryLifecycleEventsForSyncAt(ledgerPath)
|
|
10584
|
+
);
|
|
10109
10585
|
const summary = await summarizeOfflineSyncPendingChanges({
|
|
10110
10586
|
root: memoryDir,
|
|
10111
10587
|
sourceId: localOfflineSourceId(memoryDir),
|
|
@@ -10154,6 +10630,8 @@ Environment fallbacks:
|
|
|
10154
10630
|
statePath,
|
|
10155
10631
|
statePathExplicit,
|
|
10156
10632
|
userExcludeRegexps,
|
|
10633
|
+
secureStoreEncryptOnWrite: config.secureStoreEncryptOnWrite,
|
|
10634
|
+
...impressionRotation,
|
|
10157
10635
|
skipLargeFilePaths: skippedLargeFiles
|
|
10158
10636
|
});
|
|
10159
10637
|
const advanced = advanceOfflineLargeFileFailureCounts({
|
|
@@ -10161,11 +10639,11 @@ Environment fallbacks:
|
|
|
10161
10639
|
failures: result.largeFilePushFailures
|
|
10162
10640
|
});
|
|
10163
10641
|
largeFileFailureCounts = advanced.counts;
|
|
10164
|
-
for (const
|
|
10165
|
-
if (skippedLargeFiles.has(
|
|
10166
|
-
skippedLargeFiles.add(
|
|
10642
|
+
for (const path13 of advanced.newlySkipped) {
|
|
10643
|
+
if (skippedLargeFiles.has(path13)) continue;
|
|
10644
|
+
skippedLargeFiles.add(path13);
|
|
10167
10645
|
console.warn(
|
|
10168
|
-
`offline sync: permanently skipping ${
|
|
10646
|
+
`offline sync: permanently skipping ${path13} after ${OFFLINE_LARGE_FILE_SKIP_AFTER_FAILURES} failed large-file pushes for this watcher process (see issue #1786; use --exclude or offlineSyncExcludes to silence permanently)`
|
|
10169
10647
|
);
|
|
10170
10648
|
}
|
|
10171
10649
|
const pulled = result.pull ? result.pull.upserted + result.pull.deleted : 0;
|
|
@@ -10180,11 +10658,11 @@ Environment fallbacks:
|
|
|
10180
10658
|
failures: error.failures
|
|
10181
10659
|
});
|
|
10182
10660
|
largeFileFailureCounts = advanced.counts;
|
|
10183
|
-
for (const
|
|
10184
|
-
if (skippedLargeFiles.has(
|
|
10185
|
-
skippedLargeFiles.add(
|
|
10661
|
+
for (const path13 of advanced.newlySkipped) {
|
|
10662
|
+
if (skippedLargeFiles.has(path13)) continue;
|
|
10663
|
+
skippedLargeFiles.add(path13);
|
|
10186
10664
|
console.warn(
|
|
10187
|
-
`offline sync: permanently skipping ${
|
|
10665
|
+
`offline sync: permanently skipping ${path13} after ${OFFLINE_LARGE_FILE_SKIP_AFTER_FAILURES} failed large-file pushes for this watcher process (see issue #1786; use --exclude or offlineSyncExcludes to silence permanently)`
|
|
10188
10666
|
);
|
|
10189
10667
|
}
|
|
10190
10668
|
}
|
|
@@ -10219,7 +10697,7 @@ function cmdDedup(json) {
|
|
|
10219
10697
|
function readInstalledConnectorConfig(configPath, fallback) {
|
|
10220
10698
|
if (!configPath) return fallback;
|
|
10221
10699
|
try {
|
|
10222
|
-
const parsed = JSON.parse(
|
|
10700
|
+
const parsed = JSON.parse(fs10.readFileSync(configPath, "utf8"));
|
|
10223
10701
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fallback;
|
|
10224
10702
|
const { token: _token, ...config } = parsed;
|
|
10225
10703
|
return config;
|
|
@@ -10231,6 +10709,33 @@ function snapshotConnectorTokenEntry(connectorId) {
|
|
|
10231
10709
|
const entry = listTokens().find((candidate) => candidate.connector === connectorId);
|
|
10232
10710
|
return entry ? { ...entry } : null;
|
|
10233
10711
|
}
|
|
10712
|
+
async function cmdQuarantine(action, rest, json) {
|
|
10713
|
+
if (action !== "list" && action !== "replay") {
|
|
10714
|
+
process.stderr.write(`quarantine: unknown action "${action}". Use: list|replay [--namespace <ns>] [--principal <p>] [--json].
|
|
10715
|
+
`);
|
|
10716
|
+
process.exitCode = 2;
|
|
10717
|
+
return;
|
|
10718
|
+
}
|
|
10719
|
+
const format = json ? "json" : "text";
|
|
10720
|
+
if (action === "list") {
|
|
10721
|
+
const extra = rest.filter((a) => !a.startsWith("--"));
|
|
10722
|
+
if (extra.length > 0) {
|
|
10723
|
+
process.stderr.write(`quarantine list: unexpected argument(s): ${extra.join(", ")}. Use: list [--json].
|
|
10724
|
+
`);
|
|
10725
|
+
process.exitCode = 2;
|
|
10726
|
+
return;
|
|
10727
|
+
}
|
|
10728
|
+
try {
|
|
10729
|
+
const store = new WriteQuarantineStore2(resolveMemoryDir());
|
|
10730
|
+
console.log(renderQuarantineList(await store.list(), format));
|
|
10731
|
+
} catch {
|
|
10732
|
+
process.stderr.write("quarantine list: unable to inspect quarantine store\n");
|
|
10733
|
+
process.exitCode = 2;
|
|
10734
|
+
}
|
|
10735
|
+
return;
|
|
10736
|
+
}
|
|
10737
|
+
await runQuarantineReplay(rest, format, resolveConfigPath);
|
|
10738
|
+
}
|
|
10234
10739
|
async function cmdConnectors(action, rest, json) {
|
|
10235
10740
|
const rawNonFlagArgs = rest.filter((a) => !a.startsWith("--"));
|
|
10236
10741
|
const resolveConfigStrippedNonFlagArgs = () => {
|
|
@@ -10298,7 +10803,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10298
10803
|
const connectorDaemonUrl = typeof effectiveConnectorConfig.remnicDaemonUrl === "string" && effectiveConnectorConfig.remnicDaemonUrl.trim().length > 0 ? effectiveConnectorConfig.remnicDaemonUrl.trim() : void 0;
|
|
10299
10804
|
const pubResult = await pub.publish({
|
|
10300
10805
|
config: { memoryDir, namespace: connectorNamespace, daemonUrl: connectorDaemonUrl },
|
|
10301
|
-
skillsRoot:
|
|
10806
|
+
skillsRoot: path12.join(memoryDir, "skills"),
|
|
10302
10807
|
rollbackTokenEntry: preInstallTokenEntry,
|
|
10303
10808
|
log: { info: console.log, warn: console.warn, error: console.error }
|
|
10304
10809
|
});
|
|
@@ -10370,7 +10875,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10370
10875
|
const pub = factory();
|
|
10371
10876
|
const available = await pub.isHostAvailable();
|
|
10372
10877
|
const extRoot = available ? await pub.resolveExtensionRoot() : "(host not installed)";
|
|
10373
|
-
const extensionExists = available && extRoot ?
|
|
10878
|
+
const extensionExists = available && extRoot ? fs10.existsSync(extRoot) : false;
|
|
10374
10879
|
publisherChecks.push({
|
|
10375
10880
|
name: `Publisher: ${targetHostId}`,
|
|
10376
10881
|
ok: !available || extensionExists,
|
|
@@ -10441,17 +10946,30 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10441
10946
|
const memoryDir = resolveMemoryDir();
|
|
10442
10947
|
const states = await listLiveConnectorStates(memoryDir);
|
|
10443
10948
|
const stateMap = new Map(states.map((s) => [s.id, s]));
|
|
10949
|
+
let connectorsCfg;
|
|
10950
|
+
const configPath = resolveConfigPath();
|
|
10951
|
+
try {
|
|
10952
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
10953
|
+
connectorsCfg = parseConfigQuietly(raw).connectors;
|
|
10954
|
+
} catch {
|
|
10955
|
+
process.stderr.write(
|
|
10956
|
+
`connectors status: failed to read config at ${configPath}
|
|
10957
|
+
`
|
|
10958
|
+
);
|
|
10959
|
+
process.exitCode = 2;
|
|
10960
|
+
return;
|
|
10961
|
+
}
|
|
10444
10962
|
const rows = [
|
|
10445
10963
|
{
|
|
10446
10964
|
id: GDRIVE_ID,
|
|
10447
10965
|
displayName: "Google Drive",
|
|
10448
|
-
enabled:
|
|
10966
|
+
enabled: connectorsCfg.googleDrive.enabled,
|
|
10449
10967
|
state: stateMap.get(GDRIVE_ID) ?? null
|
|
10450
10968
|
},
|
|
10451
10969
|
{
|
|
10452
10970
|
id: NOTION_ID,
|
|
10453
10971
|
displayName: "Notion",
|
|
10454
|
-
enabled:
|
|
10972
|
+
enabled: connectorsCfg.notion.enabled,
|
|
10455
10973
|
state: stateMap.get(NOTION_ID) ?? null
|
|
10456
10974
|
}
|
|
10457
10975
|
];
|
|
@@ -10505,12 +11023,12 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10505
11023
|
process.exitCode = 2;
|
|
10506
11024
|
return;
|
|
10507
11025
|
}
|
|
10508
|
-
|
|
11026
|
+
initLogger2();
|
|
10509
11027
|
const configPath = resolveConfigPath();
|
|
10510
|
-
const raw =
|
|
10511
|
-
const remnicCfg =
|
|
10512
|
-
const config =
|
|
10513
|
-
const orchestrator = new
|
|
11028
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
11029
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
11030
|
+
const config = parseConfig3(remnicCfg);
|
|
11031
|
+
const orchestrator = new Orchestrator2(config);
|
|
10514
11032
|
try {
|
|
10515
11033
|
await orchestrator.initialize();
|
|
10516
11034
|
await orchestrator.deferredReady;
|
|
@@ -10632,9 +11150,9 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
10632
11150
|
console.error(`connectors marketplace: ${err instanceof Error ? err.message : String(err)}`);
|
|
10633
11151
|
process.exit(1);
|
|
10634
11152
|
}
|
|
10635
|
-
const rawConfig =
|
|
10636
|
-
const pluginConfig =
|
|
10637
|
-
const config =
|
|
11153
|
+
const rawConfig = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
11154
|
+
const pluginConfig = resolveRemnicConfigRecord3(rawConfig);
|
|
11155
|
+
const config = parseConfig3(pluginConfig);
|
|
10638
11156
|
if (subAction === "generate") {
|
|
10639
11157
|
let outputDir;
|
|
10640
11158
|
try {
|
|
@@ -10645,22 +11163,22 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
10645
11163
|
}
|
|
10646
11164
|
const manifest = generateMarketplaceManifest();
|
|
10647
11165
|
await writeMarketplaceManifest(outputDir, manifest);
|
|
10648
|
-
const outPath =
|
|
11166
|
+
const outPath = path12.join(outputDir, "marketplace.json");
|
|
10649
11167
|
if (json) {
|
|
10650
11168
|
console.log(JSON.stringify({ status: "generated", path: outPath }, null, 2));
|
|
10651
11169
|
} else {
|
|
10652
11170
|
console.log(`Generated marketplace.json at ${outPath}`);
|
|
10653
11171
|
}
|
|
10654
11172
|
} else if (subAction === "validate") {
|
|
10655
|
-
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ??
|
|
10656
|
-
const resolved =
|
|
10657
|
-
if (!
|
|
11173
|
+
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path12.join(process.cwd(), "marketplace.json");
|
|
11174
|
+
const resolved = path12.resolve(targetPath);
|
|
11175
|
+
if (!fs10.existsSync(resolved)) {
|
|
10658
11176
|
console.error(`File not found: ${resolved}`);
|
|
10659
11177
|
process.exit(1);
|
|
10660
11178
|
}
|
|
10661
11179
|
let parsed;
|
|
10662
11180
|
try {
|
|
10663
|
-
parsed = JSON.parse(
|
|
11181
|
+
parsed = JSON.parse(fs10.readFileSync(resolved, "utf8"));
|
|
10664
11182
|
} catch {
|
|
10665
11183
|
console.error(`Invalid JSON in ${resolved}`);
|
|
10666
11184
|
process.exit(1);
|
|
@@ -10859,13 +11377,13 @@ async function cmdSpace(action, rest, json) {
|
|
|
10859
11377
|
}
|
|
10860
11378
|
}
|
|
10861
11379
|
async function cmdLegacyBenchmark(action, rest, json) {
|
|
10862
|
-
|
|
11380
|
+
initLogger2();
|
|
10863
11381
|
const configPath = resolveConfigPath();
|
|
10864
|
-
const raw =
|
|
10865
|
-
const remnicCfg =
|
|
10866
|
-
const config =
|
|
10867
|
-
const orchestrator = new
|
|
10868
|
-
const service = new
|
|
11382
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
11383
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
11384
|
+
const config = parseConfig3(remnicCfg);
|
|
11385
|
+
const orchestrator = new Orchestrator2(config);
|
|
11386
|
+
const service = new EngramAccessService2(orchestrator);
|
|
10869
11387
|
const { runBenchSuite, loadBaseline, checkRegression } = await loadBenchModule();
|
|
10870
11388
|
const benchConfig = {
|
|
10871
11389
|
queries: rest.filter((a) => !a.startsWith("--")).length > 0 ? rest.filter((a) => !a.startsWith("--")) : void 0,
|
|
@@ -11057,7 +11575,7 @@ async function cmdBench(rest) {
|
|
|
11057
11575
|
}
|
|
11058
11576
|
const completeCount = prevStatus.benchmarks.filter((b) => b.status === "complete").length;
|
|
11059
11577
|
const failedCount = prevStatus.benchmarks.filter((b) => b.status === "failed").length;
|
|
11060
|
-
printBenchStatusLine(parsed.json, `Resuming from: ${
|
|
11578
|
+
printBenchStatusLine(parsed.json, `Resuming from: ${path12.basename(latestStatusPath)}`);
|
|
11061
11579
|
printBenchStatusLine(parsed.json, ` Previous run: ${prevStatus.startedAt}`);
|
|
11062
11580
|
printBenchStatusLine(parsed.json, ` Benchmarks: ${prevStatus.benchmarks.length} total, ${completeCount} complete, ${failedCount} failed`);
|
|
11063
11581
|
const before = selectedBenchmarks.length;
|
|
@@ -11219,9 +11737,9 @@ Options:
|
|
|
11219
11737
|
);
|
|
11220
11738
|
process.exit(1);
|
|
11221
11739
|
} else {
|
|
11222
|
-
fixturePath =
|
|
11740
|
+
fixturePath = path12.resolve(expandTilde(fixturePathRaw));
|
|
11223
11741
|
}
|
|
11224
|
-
const outPath =
|
|
11742
|
+
const outPath = path12.resolve(expandTilde(outPathRaw));
|
|
11225
11743
|
const benchModule = await loadBenchModule();
|
|
11226
11744
|
const runner = benchModule.runProceduralAblationCli;
|
|
11227
11745
|
if (typeof runner !== "function") {
|
|
@@ -11240,7 +11758,7 @@ Options:
|
|
|
11240
11758
|
);
|
|
11241
11759
|
console.log(`wrote ${outPath}`);
|
|
11242
11760
|
}
|
|
11243
|
-
var LOGS_DIR =
|
|
11761
|
+
var LOGS_DIR = path12.join(PID_DIR, "logs");
|
|
11244
11762
|
var LAUNCHD_PLIST_PATHS = launchdPlistPaths(resolveHomeDir());
|
|
11245
11763
|
var [LAUNCHD_PLIST_PATH] = LAUNCHD_PLIST_PATHS;
|
|
11246
11764
|
var SYSTEMD_UNIT_PATHS = systemdUnitPaths(resolveHomeDir());
|
|
@@ -11254,7 +11772,7 @@ function readPid() {
|
|
|
11254
11772
|
function inferPort() {
|
|
11255
11773
|
try {
|
|
11256
11774
|
const configPath = resolveConfigPath();
|
|
11257
|
-
const raw = JSON.parse(
|
|
11775
|
+
const raw = JSON.parse(fs10.readFileSync(configPath, "utf8"));
|
|
11258
11776
|
return raw.server?.port ?? 4318;
|
|
11259
11777
|
} catch {
|
|
11260
11778
|
return 4318;
|
|
@@ -11317,7 +11835,7 @@ function selectLaunchdInspection(openclawPluginModeConfigured) {
|
|
|
11317
11835
|
for (const plistPath of LAUNCHD_PLIST_PATHS.slice(1)) {
|
|
11318
11836
|
const legacy = inspectLaunchdPlist(plistPath);
|
|
11319
11837
|
if (!legacy.installed) continue;
|
|
11320
|
-
const label =
|
|
11838
|
+
const label = path12.basename(plistPath, ".plist");
|
|
11321
11839
|
return legacy.ok ? {
|
|
11322
11840
|
...legacy,
|
|
11323
11841
|
warn: true,
|
|
@@ -11349,13 +11867,13 @@ function daemonInstall() {
|
|
|
11349
11867
|
process.exit(1);
|
|
11350
11868
|
}
|
|
11351
11869
|
const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
|
|
11352
|
-
|
|
11870
|
+
fs10.mkdirSync(LOGS_DIR, { recursive: true });
|
|
11353
11871
|
if (isMacOS()) {
|
|
11354
|
-
const templatePath =
|
|
11355
|
-
const template =
|
|
11872
|
+
const templatePath = path12.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
|
|
11873
|
+
const template = fs10.readFileSync(templatePath, "utf8");
|
|
11356
11874
|
const plist = renderTemplate(template, vars);
|
|
11357
|
-
|
|
11358
|
-
|
|
11875
|
+
fs10.mkdirSync(path12.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
|
|
11876
|
+
fs10.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
11359
11877
|
try {
|
|
11360
11878
|
launchdLoadPlist(LAUNCHD_PLIST_PATH);
|
|
11361
11879
|
} catch (err) {
|
|
@@ -11371,11 +11889,11 @@ function daemonInstall() {
|
|
|
11371
11889
|
console.log(` RunAtLoad: true, KeepAlive: true`);
|
|
11372
11890
|
console.log(` Logs: ${LOGS_DIR}/daemon.log`);
|
|
11373
11891
|
} else if (isLinux()) {
|
|
11374
|
-
const templatePath =
|
|
11375
|
-
const template =
|
|
11892
|
+
const templatePath = path12.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
|
|
11893
|
+
const template = fs10.readFileSync(templatePath, "utf8");
|
|
11376
11894
|
const unit = renderTemplate(template, vars);
|
|
11377
|
-
|
|
11378
|
-
|
|
11895
|
+
fs10.mkdirSync(path12.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
|
|
11896
|
+
fs10.writeFileSync(SYSTEMD_UNIT_PATH, unit);
|
|
11379
11897
|
try {
|
|
11380
11898
|
childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
11381
11899
|
} catch (err) {
|
|
@@ -11411,7 +11929,7 @@ function daemonUninstall() {
|
|
|
11411
11929
|
} catch {
|
|
11412
11930
|
}
|
|
11413
11931
|
try {
|
|
11414
|
-
|
|
11932
|
+
fs10.unlinkSync(plistPath);
|
|
11415
11933
|
removed = true;
|
|
11416
11934
|
console.log(`Removed launchd service: ${plistPath}`);
|
|
11417
11935
|
} catch {
|
|
@@ -11431,7 +11949,7 @@ function daemonUninstall() {
|
|
|
11431
11949
|
let removed = false;
|
|
11432
11950
|
for (const unitPath of SYSTEMD_UNIT_PATHS) {
|
|
11433
11951
|
try {
|
|
11434
|
-
|
|
11952
|
+
fs10.unlinkSync(unitPath);
|
|
11435
11953
|
removed = true;
|
|
11436
11954
|
console.log(`Removed systemd service: ${unitPath}`);
|
|
11437
11955
|
} catch {
|
|
@@ -11498,13 +12016,13 @@ async function daemonStatus() {
|
|
|
11498
12016
|
console.log(` Port: ${port}`);
|
|
11499
12017
|
console.log(` Service: ${serviceInstalled ? "installed" : "not installed"}`);
|
|
11500
12018
|
console.log(` Platform: ${process.platform}`);
|
|
11501
|
-
console.log(` PID file: ${
|
|
11502
|
-
console.log(` Log file: ${
|
|
12019
|
+
console.log(` PID file: ${fs10.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
|
|
12020
|
+
console.log(` Log file: ${fs10.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
|
|
11503
12021
|
try {
|
|
11504
12022
|
const configPath = resolveConfigPath();
|
|
11505
|
-
const raw =
|
|
11506
|
-
const remnicCfg =
|
|
11507
|
-
const config =
|
|
12023
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
12024
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
12025
|
+
const config = parseConfig3(remnicCfg);
|
|
11508
12026
|
const extRoot = resolveExtensionsRoot(config);
|
|
11509
12027
|
const noopLog = { warn: () => {
|
|
11510
12028
|
}, debug: () => {
|
|
@@ -11543,9 +12061,9 @@ function daemonStart() {
|
|
|
11543
12061
|
return;
|
|
11544
12062
|
}
|
|
11545
12063
|
}
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
const logStream =
|
|
12064
|
+
fs10.mkdirSync(PID_DIR, { recursive: true });
|
|
12065
|
+
fs10.mkdirSync(LOGS_DIR, { recursive: true });
|
|
12066
|
+
const logStream = fs10.openSync(LOG_FILE, "a");
|
|
11549
12067
|
const serverBin = resolveServerBin();
|
|
11550
12068
|
const isSource = serverBin.endsWith(".ts");
|
|
11551
12069
|
let cmd;
|
|
@@ -11567,7 +12085,7 @@ function daemonStart() {
|
|
|
11567
12085
|
}
|
|
11568
12086
|
});
|
|
11569
12087
|
child.unref();
|
|
11570
|
-
|
|
12088
|
+
fs10.writeFileSync(PID_FILE, String(child.pid));
|
|
11571
12089
|
console.log(`Started remnic server (pid ${child.pid})`);
|
|
11572
12090
|
console.log(` Log: ${LOG_FILE}`);
|
|
11573
12091
|
}
|
|
@@ -11601,11 +12119,11 @@ function daemonStop() {
|
|
|
11601
12119
|
console.log("Process not found (cleaning up PID file)");
|
|
11602
12120
|
}
|
|
11603
12121
|
try {
|
|
11604
|
-
|
|
12122
|
+
fs10.unlinkSync(PID_FILE);
|
|
11605
12123
|
} catch {
|
|
11606
12124
|
}
|
|
11607
12125
|
try {
|
|
11608
|
-
|
|
12126
|
+
fs10.unlinkSync(LEGACY_PID_FILE);
|
|
11609
12127
|
} catch {
|
|
11610
12128
|
}
|
|
11611
12129
|
}
|
|
@@ -11731,11 +12249,11 @@ async function promptYesNo(question, defaultYes = true) {
|
|
|
11731
12249
|
});
|
|
11732
12250
|
}
|
|
11733
12251
|
async function cmdBinary(rest) {
|
|
11734
|
-
|
|
12252
|
+
initLogger2();
|
|
11735
12253
|
const configPath = resolveConfigPath();
|
|
11736
|
-
const raw =
|
|
11737
|
-
const remnicCfg =
|
|
11738
|
-
const config =
|
|
12254
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
12255
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
12256
|
+
const config = parseConfig3(remnicCfg);
|
|
11739
12257
|
const memoryDir = resolveMemoryDir();
|
|
11740
12258
|
const blConfig = {
|
|
11741
12259
|
enabled: config.binaryLifecycleEnabled,
|
|
@@ -11853,7 +12371,7 @@ Clean complete: cleaned=${result.cleaned}`
|
|
|
11853
12371
|
}
|
|
11854
12372
|
async function cmdOpenclawInstall(opts) {
|
|
11855
12373
|
const configPath = resolveOpenclawConfigPath(opts.configPath);
|
|
11856
|
-
const fallbackMemoryDir =
|
|
12374
|
+
const fallbackMemoryDir = path12.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
|
|
11857
12375
|
console.log(`OpenClaw config: ${configPath}`);
|
|
11858
12376
|
const existingConfig = readOpenclawConfig(configPath);
|
|
11859
12377
|
const { plugins, entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
|
|
@@ -11924,7 +12442,7 @@ async function cmdOpenclawInstall(opts) {
|
|
|
11924
12442
|
} else if (slotIsActiveLegacy) {
|
|
11925
12443
|
changes.push(` Slot left as "${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}" \u2014 re-run with --yes to activate the new entry`);
|
|
11926
12444
|
}
|
|
11927
|
-
if (!
|
|
12445
|
+
if (!fs10.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
|
|
11928
12446
|
if (hasLegacy && migrateLegacy) {
|
|
11929
12447
|
changes.push(`~ Legacy '${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}' entry retained (safe to remove after verifying hooks fire)`);
|
|
11930
12448
|
}
|
|
@@ -11944,8 +12462,8 @@ async function cmdOpenclawInstall(opts) {
|
|
|
11944
12462
|
Resulting plugins.slots.memory: ${dryRunPlugins.slots?.memory ?? "(unset)"}`);
|
|
11945
12463
|
return;
|
|
11946
12464
|
}
|
|
11947
|
-
if (
|
|
11948
|
-
const st =
|
|
12465
|
+
if (fs10.existsSync(memoryDir)) {
|
|
12466
|
+
const st = fs10.statSync(memoryDir);
|
|
11949
12467
|
if (!st.isDirectory()) {
|
|
11950
12468
|
throw new Error(
|
|
11951
12469
|
`Cannot use ${memoryDir} as the memory directory \u2014 a file already exists at that path.
|
|
@@ -11953,12 +12471,12 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
|
|
|
11953
12471
|
);
|
|
11954
12472
|
}
|
|
11955
12473
|
} else {
|
|
11956
|
-
|
|
12474
|
+
fs10.mkdirSync(memoryDir, { recursive: true });
|
|
11957
12475
|
console.log(`Created memory directory: ${memoryDir}`);
|
|
11958
12476
|
}
|
|
11959
|
-
const configDir =
|
|
11960
|
-
if (!
|
|
11961
|
-
|
|
12477
|
+
const configDir = path12.dirname(configPath);
|
|
12478
|
+
if (!fs10.existsSync(configDir)) {
|
|
12479
|
+
fs10.mkdirSync(configDir, { recursive: true });
|
|
11962
12480
|
}
|
|
11963
12481
|
atomicWriteFileSync(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
11964
12482
|
console.log("\nDone! Summary of changes:");
|
|
@@ -11984,11 +12502,11 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
11984
12502
|
const configPath = resolveOpenclawConfigPath(opts.configPath);
|
|
11985
12503
|
const pluginDir = resolveOpenclawPluginDir(opts.pluginDir);
|
|
11986
12504
|
const legacyPluginDirForBackup = opts.legacyPluginDirForBackup ? resolveOpenclawLegacyPluginDir(opts.legacyPluginDirForBackup) : void 0;
|
|
11987
|
-
const fallbackMemoryDir =
|
|
12505
|
+
const fallbackMemoryDir = path12.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
|
|
11988
12506
|
const packageSpec = `@remnic/plugin-openclaw@${opts.version ?? "latest"}`;
|
|
11989
12507
|
const existingConfig = readOpenclawConfig(configPath);
|
|
11990
12508
|
const { entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
|
|
11991
|
-
const preservedMemoryDir = opts.memoryDir ?
|
|
12509
|
+
const preservedMemoryDir = opts.memoryDir ? path12.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
|
|
11992
12510
|
assertDirectoryPathOrMissing(pluginDir, "OpenClaw plugin dir");
|
|
11993
12511
|
if (legacyPluginDirForBackup) {
|
|
11994
12512
|
assertDirectoryPathOrMissing(legacyPluginDirForBackup, "Legacy OpenClaw plugin dir");
|
|
@@ -12000,7 +12518,7 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
12000
12518
|
}
|
|
12001
12519
|
console.log(`Memory dir: ${preservedMemoryDir}`);
|
|
12002
12520
|
console.log(`Package spec: ${packageSpec}`);
|
|
12003
|
-
console.log(`Backup root: ${
|
|
12521
|
+
console.log(`Backup root: ${path12.join(resolveHomeDir(), ".openclaw", "backups")}`);
|
|
12004
12522
|
const plannedActions = [
|
|
12005
12523
|
`backup openclaw.json and the existing ${REMNIC_OPENCLAW_PLUGIN_ID} extension`,
|
|
12006
12524
|
...legacyPluginDirForBackup ? [`backup the existing ${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID} extension without modifying it`] : [],
|
|
@@ -12026,9 +12544,9 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
12026
12544
|
}
|
|
12027
12545
|
}
|
|
12028
12546
|
const backupDir = createOpenclawUpgradeBackupDir();
|
|
12029
|
-
const configBackupPath =
|
|
12030
|
-
const pluginBackupDir =
|
|
12031
|
-
const legacyPluginBackupDir = legacyPluginDirForBackup ?
|
|
12547
|
+
const configBackupPath = path12.join(backupDir, "openclaw.json");
|
|
12548
|
+
const pluginBackupDir = path12.join(backupDir, "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
|
|
12549
|
+
const legacyPluginBackupDir = legacyPluginDirForBackup ? path12.join(backupDir, "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID) : void 0;
|
|
12032
12550
|
const backupNotes = [];
|
|
12033
12551
|
if (backupPathIfPresent(configPath, configBackupPath)) {
|
|
12034
12552
|
backupNotes.push(`+ Backed up config to ${configBackupPath}`);
|
|
@@ -12129,16 +12647,16 @@ async function cmdOpenclawMigrateEngram(opts) {
|
|
|
12129
12647
|
console.log(" - Re-apply any local source patches to the new package only after verifying the published build.");
|
|
12130
12648
|
}
|
|
12131
12649
|
function createOpenclawUpgradeBackupDir() {
|
|
12132
|
-
const backupsRoot =
|
|
12133
|
-
|
|
12134
|
-
return
|
|
12650
|
+
const backupsRoot = path12.join(resolveHomeDir(), ".openclaw", "backups");
|
|
12651
|
+
fs10.mkdirSync(backupsRoot, { recursive: true });
|
|
12652
|
+
return fs10.mkdtempSync(path12.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
|
|
12135
12653
|
}
|
|
12136
12654
|
async function cmdTaxonomy(rest) {
|
|
12137
|
-
|
|
12655
|
+
initLogger2();
|
|
12138
12656
|
const configPath = resolveConfigPath();
|
|
12139
|
-
const raw =
|
|
12140
|
-
const remnicCfg =
|
|
12141
|
-
const config =
|
|
12657
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
12658
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
12659
|
+
const config = parseConfig3(remnicCfg);
|
|
12142
12660
|
if (!config.taxonomyEnabled) {
|
|
12143
12661
|
console.error(
|
|
12144
12662
|
"Taxonomy is disabled in config (taxonomyEnabled = false). Enable it to use taxonomy commands."
|
|
@@ -12173,9 +12691,9 @@ async function cmdTaxonomy(rest) {
|
|
|
12173
12691
|
const doc = generateResolverDocument(taxonomy);
|
|
12174
12692
|
console.log(doc);
|
|
12175
12693
|
if (config.taxonomyAutoGenResolver) {
|
|
12176
|
-
const resolverPath =
|
|
12177
|
-
|
|
12178
|
-
|
|
12694
|
+
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12695
|
+
fs10.mkdirSync(path12.dirname(resolverPath), { recursive: true });
|
|
12696
|
+
fs10.writeFileSync(resolverPath, doc);
|
|
12179
12697
|
console.error(`Written: ${resolverPath}`);
|
|
12180
12698
|
}
|
|
12181
12699
|
break;
|
|
@@ -12220,8 +12738,8 @@ async function cmdTaxonomy(rest) {
|
|
|
12220
12738
|
console.log(`Added category "${id}" (${name}).`);
|
|
12221
12739
|
if (config.taxonomyAutoGenResolver) {
|
|
12222
12740
|
const doc = generateResolverDocument(taxonomy);
|
|
12223
|
-
const resolverPath =
|
|
12224
|
-
|
|
12741
|
+
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12742
|
+
fs10.writeFileSync(resolverPath, doc);
|
|
12225
12743
|
console.error(`Regenerated: ${resolverPath}`);
|
|
12226
12744
|
}
|
|
12227
12745
|
break;
|
|
@@ -12251,8 +12769,8 @@ async function cmdTaxonomy(rest) {
|
|
|
12251
12769
|
console.log(`Removed category "${id}".`);
|
|
12252
12770
|
if (config.taxonomyAutoGenResolver) {
|
|
12253
12771
|
const doc = generateResolverDocument(taxonomy);
|
|
12254
|
-
const resolverPath =
|
|
12255
|
-
|
|
12772
|
+
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12773
|
+
fs10.writeFileSync(resolverPath, doc);
|
|
12256
12774
|
console.error(`Regenerated: ${resolverPath}`);
|
|
12257
12775
|
}
|
|
12258
12776
|
break;
|
|
@@ -12443,12 +12961,12 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
12443
12961
|
`Unknown training-export format "${args.format}". ${validList}`
|
|
12444
12962
|
);
|
|
12445
12963
|
}
|
|
12446
|
-
if (!
|
|
12964
|
+
if (!fs10.existsSync(args.memoryDir)) {
|
|
12447
12965
|
throw new Error(
|
|
12448
12966
|
`--memory-dir "${args.memoryDir}" does not exist. Provide the path to an existing memory directory.`
|
|
12449
12967
|
);
|
|
12450
12968
|
}
|
|
12451
|
-
if (!
|
|
12969
|
+
if (!fs10.statSync(args.memoryDir).isDirectory()) {
|
|
12452
12970
|
throw new Error(
|
|
12453
12971
|
`--memory-dir "${args.memoryDir}" is not a directory. Provide the path to a memory directory, not a file.`
|
|
12454
12972
|
);
|
|
@@ -12533,11 +13051,11 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
12533
13051
|
);
|
|
12534
13052
|
}
|
|
12535
13053
|
const formatted = adapter.formatRecords(records);
|
|
12536
|
-
const outDir =
|
|
12537
|
-
|
|
13054
|
+
const outDir = path12.dirname(args.output);
|
|
13055
|
+
fs10.mkdirSync(outDir, { recursive: true });
|
|
12538
13056
|
const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
|
|
12539
|
-
|
|
12540
|
-
|
|
13057
|
+
fs10.writeFileSync(tmpPath, formatted, "utf-8");
|
|
13058
|
+
fs10.renameSync(tmpPath, args.output);
|
|
12541
13059
|
stdout.write(
|
|
12542
13060
|
`Exported ${records.length} records to ${args.output} (${adapter.name} format)
|
|
12543
13061
|
`
|
|
@@ -12641,7 +13159,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12641
13159
|
case "tree": {
|
|
12642
13160
|
const subAction = rest[0];
|
|
12643
13161
|
const json = rest.includes("--json");
|
|
12644
|
-
const outputDir = resolveFlag(rest, "--output") ??
|
|
13162
|
+
const outputDir = resolveFlag(rest, "--output") ?? path12.join(process.cwd(), ".remnic", "context-tree");
|
|
12645
13163
|
const categoriesFlag = resolveFlag(rest, "--categories");
|
|
12646
13164
|
const categories = categoriesFlag ? categoriesFlag.split(",") : void 0;
|
|
12647
13165
|
const maxPerCategoryRaw = resolveFlag(rest, "--max-per-category");
|
|
@@ -12706,7 +13224,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12706
13224
|
}
|
|
12707
13225
|
}, 500);
|
|
12708
13226
|
};
|
|
12709
|
-
|
|
13227
|
+
fs10.watch(memoryDir, { recursive: true }, (_event, filename) => {
|
|
12710
13228
|
if (filename && filename.startsWith(".")) return;
|
|
12711
13229
|
rebuild();
|
|
12712
13230
|
});
|
|
@@ -12714,12 +13232,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
12714
13232
|
});
|
|
12715
13233
|
} else if (subAction === "validate") {
|
|
12716
13234
|
const treeDir = outputDir;
|
|
12717
|
-
if (!
|
|
13235
|
+
if (!fs10.existsSync(treeDir)) {
|
|
12718
13236
|
console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
|
|
12719
13237
|
process.exit(1);
|
|
12720
13238
|
}
|
|
12721
|
-
const indexPath =
|
|
12722
|
-
if (!
|
|
13239
|
+
const indexPath = path12.join(treeDir, "INDEX.md");
|
|
13240
|
+
if (!fs10.existsSync(indexPath)) {
|
|
12723
13241
|
console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
|
|
12724
13242
|
process.exit(1);
|
|
12725
13243
|
}
|
|
@@ -12788,6 +13306,12 @@ Options:
|
|
|
12788
13306
|
await cmdConnectors(action, rest.slice(1), json);
|
|
12789
13307
|
break;
|
|
12790
13308
|
}
|
|
13309
|
+
case "quarantine": {
|
|
13310
|
+
const action = rest[0] ?? "list";
|
|
13311
|
+
const json = rest.includes("--json");
|
|
13312
|
+
await cmdQuarantine(action, rest.slice(1), json);
|
|
13313
|
+
break;
|
|
13314
|
+
}
|
|
12791
13315
|
case "space": {
|
|
12792
13316
|
const action = rest[0] ?? "list";
|
|
12793
13317
|
const json = rest.includes("--json");
|
|
@@ -12883,10 +13407,10 @@ Other:
|
|
|
12883
13407
|
let wearablesService;
|
|
12884
13408
|
try {
|
|
12885
13409
|
const configPath = resolveConfigPath();
|
|
12886
|
-
const raw =
|
|
12887
|
-
const remnicCfg =
|
|
12888
|
-
const config =
|
|
12889
|
-
wearablesOrchestrator = new
|
|
13410
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
13411
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
13412
|
+
const config = parseConfig3(remnicCfg);
|
|
13413
|
+
wearablesOrchestrator = new Orchestrator2(config);
|
|
12890
13414
|
await wearablesOrchestrator.initialize();
|
|
12891
13415
|
await wearablesOrchestrator.deferredReady;
|
|
12892
13416
|
wearablesService = wearablesOrchestrator.getWearablesService();
|
|
@@ -12927,10 +13451,10 @@ Other:
|
|
|
12927
13451
|
const targetFactory = async () => {
|
|
12928
13452
|
if (!orchestratorSingleton) {
|
|
12929
13453
|
const configPath = resolveConfigPath();
|
|
12930
|
-
const raw =
|
|
12931
|
-
const remnicCfg =
|
|
12932
|
-
const config =
|
|
12933
|
-
orchestratorSingleton = new
|
|
13454
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
13455
|
+
const remnicCfg = resolveRemnicConfigRecord3(raw);
|
|
13456
|
+
const config = parseConfig3(remnicCfg);
|
|
13457
|
+
orchestratorSingleton = new Orchestrator2(config);
|
|
12934
13458
|
await orchestratorSingleton.initialize();
|
|
12935
13459
|
await orchestratorSingleton.deferredReady;
|
|
12936
13460
|
}
|
|
@@ -13143,6 +13667,7 @@ Usage:
|
|
|
13143
13667
|
marketplace generate Generate marketplace.json for Codex
|
|
13144
13668
|
marketplace validate Validate a marketplace.json file
|
|
13145
13669
|
marketplace install Install from a marketplace source
|
|
13670
|
+
remnic quarantine <list|replay> [--namespace <ns>] [--principal <p>] [--json] Inspect/replay ACL-rejected writes
|
|
13146
13671
|
remnic extensions <list|show|validate|reload> Manage memory extensions
|
|
13147
13672
|
remnic space <list|switch|create|delete|push|pull|share|promote|audit> Manage spaces
|
|
13148
13673
|
create accepts --parent <id> to set parent-child relationship
|
|
@@ -13261,6 +13786,7 @@ export {
|
|
|
13261
13786
|
TAXONOMY_RESOLVE_BOOLEAN_FLAGS,
|
|
13262
13787
|
TAXONOMY_RESOLVE_VALUE_FLAGS,
|
|
13263
13788
|
__benchDatasetTestHooks,
|
|
13789
|
+
__statusHealthTestHooks,
|
|
13264
13790
|
advanceOfflineBaseFilesForSuccessfulPush,
|
|
13265
13791
|
advanceOfflineLargeFileFailureCounts,
|
|
13266
13792
|
attachPreparedJudgeCalibration,
|