@remnic/cli 9.35.5 → 9.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +655 -487
  2. package/package.json +29 -29
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ async function persistEnrichmentCandidate(storage, entityName, candidate) {
20
20
  // src/index.ts
21
21
  import fs11 from "fs";
22
22
  import os from "os";
23
- import path12 from "path";
23
+ import path14 from "path";
24
24
  import { createHash as createHash2 } from "crypto";
25
25
  import * as childProcess2 from "child_process";
26
26
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -1120,199 +1120,16 @@ function firstSuccessfulCandidate(candidates, attempt) {
1120
1120
  }
1121
1121
 
1122
1122
  // src/bench-args.ts
1123
- import path5 from "path";
1124
-
1125
- // src/path-utils.ts
1126
- function resolveHomeDir() {
1127
- return process.env.HOME ?? process.env.USERPROFILE ?? "~";
1128
- }
1129
- function expandTilde(p) {
1130
- if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
1131
- return resolveHomeDir() + p.slice(1);
1132
- }
1133
- const home = resolveHomeDir();
1134
- if (p === "$HOME" || p.startsWith("$HOME/") || p.startsWith("$HOME\\")) {
1135
- return home + p.slice(5);
1136
- }
1137
- if (p === "${HOME}" || p.startsWith("${HOME}/") || p.startsWith("${HOME}\\")) {
1138
- return home + p.slice(7);
1139
- }
1140
- return p;
1141
- }
1123
+ import path6 from "path";
1142
1124
 
1143
- // src/bench-args.ts
1144
- function createBenchWorkItems(benchmarks, runtimeProfiles) {
1145
- return benchmarks.flatMap(
1146
- (benchmarkId) => runtimeProfiles.map((runtimeProfile) => ({ benchmarkId, runtimeProfile }))
1147
- );
1148
- }
1149
- function deriveRuntimeProfilesFromBenchWorkItems(workItems) {
1150
- return [...new Set(workItems.map((item) => item.runtimeProfile))];
1151
- }
1152
- function filterBenchWorkItemsForPreviousStatus(workItems, previousEntries, mode) {
1153
- const statusById = new Map(previousEntries.map((entry) => [entry.id, entry.status]));
1154
- const hasMatrixWork = new Set(workItems.map((item) => item.benchmarkId)).size !== workItems.length;
1155
- function statusFor(item) {
1156
- const profileStatus = statusById.get(`${item.benchmarkId} [${item.runtimeProfile}]`);
1157
- if (profileStatus !== void 0) return profileStatus;
1158
- if (hasMatrixWork) {
1159
- return mode === "retry-failed" ? statusById.get(item.benchmarkId) : void 0;
1160
- }
1161
- return statusById.get(item.benchmarkId);
1162
- }
1163
- return workItems.filter((item) => {
1164
- const status = statusFor(item);
1165
- if (mode === "retry-failed") {
1166
- return status === "failed";
1167
- }
1168
- return status !== "complete";
1169
- });
1170
- }
1171
- var PUBLISHED_BENCHMARK_NAMES = Object.freeze([
1172
- "ama-bench",
1173
- "memory-arena",
1174
- "amemgym",
1175
- "longmemeval",
1176
- "locomo",
1177
- "beam",
1178
- "personamem",
1179
- "memoryagentbench",
1180
- "membench"
1181
- ]);
1182
- function isBenchRuntimeProfile(value) {
1183
- return value === "baseline" || value === "real" || value === "openclaw-chain" || value === "local-lab";
1184
- }
1185
- function parseBenchRuntimeProfile(value, flagName) {
1186
- if (isBenchRuntimeProfile(value)) {
1187
- return value;
1188
- }
1189
- if (flagName === "--runtime-profile") {
1190
- throw new Error(
1191
- 'ERROR: --runtime-profile must be "baseline", "real", "openclaw-chain", or "local-lab".'
1192
- );
1193
- }
1194
- throw new Error(
1195
- 'ERROR: --matrix must contain only "baseline", "real", "openclaw-chain", or "local-lab".'
1196
- );
1197
- }
1198
- var BENCH_PROVIDER_ALLOWED = Object.freeze([
1199
- "openai",
1200
- "anthropic",
1201
- "ollama",
1202
- "litellm",
1203
- "local-llm",
1204
- "codex-cli",
1205
- "claude-cli"
1206
- ]);
1207
- var BENCH_INTERNAL_PROVIDER_ALLOWED = Object.freeze(
1208
- BENCH_PROVIDER_ALLOWED.filter((provider) => provider !== "claude-cli")
1209
- );
1210
- function isBuiltInProvider(value) {
1211
- return BENCH_PROVIDER_ALLOWED.includes(value);
1212
- }
1213
- function isBuiltInInternalProvider(value) {
1214
- return BENCH_INTERNAL_PROVIDER_ALLOWED.includes(value);
1215
- }
1216
- function parseBenchProvider(raw, flag) {
1217
- if (!isBuiltInProvider(raw)) {
1218
- throw new Error(
1219
- `ERROR: ${flag} must be one of "openai", "anthropic", "ollama", "litellm", "local-llm", "codex-cli", or "claude-cli".`
1220
- );
1221
- }
1222
- return raw;
1223
- }
1224
- function parseBenchInternalProvider(raw, flag) {
1225
- if (!isBuiltInInternalProvider(raw)) {
1226
- if (raw === "claude-cli") {
1227
- throw new Error(
1228
- `ERROR: ${flag} does not support "claude-cli" (no @remnic/core gateway wiring); use --provider, --system-provider, or --judge-provider instead.`
1229
- );
1230
- }
1231
- throw new Error(
1232
- `ERROR: ${flag} must be one of "openai", "anthropic", "ollama", "litellm", "local-llm", or "codex-cli".`
1233
- );
1234
- }
1235
- return raw;
1236
- }
1237
- function parseCodexReasoningEffort(raw, flag) {
1238
- if (raw !== "low" && raw !== "medium" && raw !== "high" && raw !== "xhigh") {
1239
- throw new Error(
1240
- `ERROR: ${flag} must be "low", "medium", "high", or "xhigh".`
1241
- );
1242
- }
1243
- return raw;
1244
- }
1245
- var MCP_TOOL_OPERATIONS = /* @__PURE__ */ new Set(["store", "recall", "correct", "reset"]);
1246
- var MCP_ARGUMENT_SEMANTICS = /* @__PURE__ */ new Set([
1247
- "namespace",
1248
- "sessionId",
1249
- "content",
1250
- "role",
1251
- "timestamp",
1252
- "query",
1253
- "limit"
1254
- ]);
1255
- function parseMcpToolMapping(value) {
1256
- if (!isPlainObject(value)) throw new Error("expected a JSON object");
1257
- for (const operation of Object.keys(value).sort()) {
1258
- if (!MCP_TOOL_OPERATIONS.has(operation)) {
1259
- throw new Error(`unknown operation ${operation}`);
1260
- }
1261
- const entry = value[operation];
1262
- if (typeof entry === "string") {
1263
- if (entry.trim().length === 0) throw new Error(`${operation} tool name must not be empty`);
1264
- continue;
1265
- }
1266
- if (!isPlainObject(entry)) {
1267
- throw new Error(`${operation} must be a tool-name string or mapping object`);
1268
- }
1269
- for (const field of Object.keys(entry).sort()) {
1270
- if (field !== "name" && field !== "arguments" && field !== "resultPath") {
1271
- throw new Error(`${operation} contains unknown field ${field}`);
1272
- }
1273
- }
1274
- if (typeof entry.name !== "string" || entry.name.trim().length === 0) {
1275
- throw new Error(`${operation}.name must be a non-empty string`);
1276
- }
1277
- if (entry.resultPath !== void 0) {
1278
- if (typeof entry.resultPath !== "string" || !isSafeMcpResultPath(entry.resultPath)) {
1279
- throw new Error(`${operation}.resultPath must be a non-empty safe dot path`);
1280
- }
1281
- }
1282
- if (entry.arguments !== void 0) {
1283
- if (!isPlainObject(entry.arguments)) {
1284
- throw new Error(`${operation}.arguments must be an object`);
1285
- }
1286
- for (const semantic of Object.keys(entry.arguments).sort()) {
1287
- if (!MCP_ARGUMENT_SEMANTICS.has(semantic)) {
1288
- throw new Error(`${operation}.arguments contains unknown semantic ${semantic}`);
1289
- }
1290
- const argumentName = entry.arguments[semantic];
1291
- if (typeof argumentName !== "string" || argumentName.trim().length === 0) {
1292
- throw new Error(`${operation}.arguments.${semantic} must be a non-empty string`);
1293
- }
1294
- }
1295
- }
1296
- }
1297
- return value;
1298
- }
1299
- function isPlainObject(value) {
1300
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1301
- const prototype = Object.getPrototypeOf(value);
1302
- return prototype === Object.prototype || prototype === null;
1303
- }
1304
- function isSafeMcpResultPath(value) {
1305
- return value.split(".").every(
1306
- (segment) => segment.length > 0 && segment !== "__proto__" && segment !== "prototype" && segment !== "constructor" && /^[A-Za-z0-9_-]+$/.test(segment)
1307
- );
1308
- }
1125
+ // src/bench-flags.ts
1309
1126
  function readBenchOptionValue(argv, flag) {
1310
1127
  const index = argv.indexOf(flag);
1311
1128
  if (index === -1) {
1312
1129
  return void 0;
1313
1130
  }
1314
1131
  const value = argv[index + 1];
1315
- if (!value || value.startsWith("-")) {
1132
+ if (!value || value.startsWith("-") && !/^-\d/.test(value)) {
1316
1133
  throw new Error(`ERROR: ${flag} requires a value.`);
1317
1134
  }
1318
1135
  return value;
@@ -1389,7 +1206,14 @@ var BENCH_VALUE_FLAGS = Object.freeze([
1389
1206
  "--ama-bench-cross-judge-api-key",
1390
1207
  "--ama-bench-cross-judge-codex-reasoning-effort",
1391
1208
  "--local-lab-manifest",
1392
- "--memcorrect-adapter"
1209
+ "--memcorrect-adapter",
1210
+ "--run",
1211
+ "--memory-dir",
1212
+ "--users",
1213
+ "--epochs",
1214
+ "--facts-per-epoch",
1215
+ "--drifting-ratio",
1216
+ "--contradicted-ratio"
1393
1217
  ]);
1394
1218
  var BENCH_BOOLEAN_FLAGS = Object.freeze([
1395
1219
  "--mcp-demo",
@@ -1564,6 +1388,22 @@ var BENCH_ACTION_FLAGS = {
1564
1388
  value: [],
1565
1389
  boolean: ["--json", "--explain", "--help", "-h"],
1566
1390
  legacyEqualsPrefixes: ["--baseline=", "--report="]
1391
+ },
1392
+ attribute: {
1393
+ value: ["--run", "--results-dir", "--memory-dir", "--threshold"],
1394
+ boolean: ["--json", "--help", "-h"]
1395
+ },
1396
+ "drift-gen": {
1397
+ value: [
1398
+ "--users",
1399
+ "--epochs",
1400
+ "--seed",
1401
+ "--out",
1402
+ "--facts-per-epoch",
1403
+ "--drifting-ratio",
1404
+ "--contradicted-ratio"
1405
+ ],
1406
+ boolean: ["--json", "--help", "-h"]
1567
1407
  }
1568
1408
  };
1569
1409
  function formatBenchOptions(valueFlags, booleanFlags, legacyEqualsPrefixes = []) {
@@ -1602,45 +1442,294 @@ function validateBenchFlags(action, args) {
1602
1442
  );
1603
1443
  }
1604
1444
  const value = args[index + 1];
1605
- if (!value || value.startsWith("-")) {
1445
+ if (!value || value.startsWith("-") && !/^-\d/.test(value)) {
1606
1446
  throw new Error(`ERROR: ${arg} requires a value.`);
1607
1447
  }
1608
1448
  index += 1;
1609
1449
  continue;
1610
1450
  }
1611
- if (isBenchBooleanFlag(arg)) {
1612
- if (!allowedBoolean.has(arg)) {
1613
- throw new Error(
1614
- `ERROR: ${arg} is not supported for bench ${action}. Supported options: ${supportedOptions || "(none)"}.`
1615
- );
1451
+ if (isBenchBooleanFlag(arg)) {
1452
+ if (!allowedBoolean.has(arg)) {
1453
+ throw new Error(
1454
+ `ERROR: ${arg} is not supported for bench ${action}. Supported options: ${supportedOptions || "(none)"}.`
1455
+ );
1456
+ }
1457
+ continue;
1458
+ }
1459
+ throw new Error(
1460
+ `ERROR: unknown bench option ${arg}. Supported options: ${allOptions}.`
1461
+ );
1462
+ }
1463
+ }
1464
+ function collectBenchmarks(argv) {
1465
+ const benchmarks = [];
1466
+ for (let index = 0; index < argv.length; index += 1) {
1467
+ const arg = argv[index];
1468
+ if (isBenchValueFlag(arg)) {
1469
+ index += 1;
1470
+ continue;
1471
+ }
1472
+ if (isBenchBooleanFlag(arg)) {
1473
+ continue;
1474
+ }
1475
+ if (!arg.startsWith("-")) {
1476
+ benchmarks.push(arg);
1477
+ }
1478
+ }
1479
+ return benchmarks;
1480
+ }
1481
+
1482
+ // src/path-utils.ts
1483
+ function resolveHomeDir() {
1484
+ return process.env.HOME ?? process.env.USERPROFILE ?? "~";
1485
+ }
1486
+ function expandTilde(p) {
1487
+ if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
1488
+ return resolveHomeDir() + p.slice(1);
1489
+ }
1490
+ const home = resolveHomeDir();
1491
+ if (p === "$HOME" || p.startsWith("$HOME/") || p.startsWith("$HOME\\")) {
1492
+ return home + p.slice(5);
1493
+ }
1494
+ if (p === "${HOME}" || p.startsWith("${HOME}/") || p.startsWith("${HOME}\\")) {
1495
+ return home + p.slice(7);
1496
+ }
1497
+ return p;
1498
+ }
1499
+
1500
+ // src/bench-args-research.ts
1501
+ import path5 from "path";
1502
+ function readPositiveInteger(args, flag) {
1503
+ const raw = readBenchOptionValue(args, flag);
1504
+ if (raw === void 0) return void 0;
1505
+ const parsed = Number(raw);
1506
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
1507
+ throw new Error(`ERROR: ${flag} must be a positive safe integer.`);
1508
+ }
1509
+ return parsed;
1510
+ }
1511
+ function readUnitRatio(args, flag) {
1512
+ const raw = readBenchOptionValue(args, flag);
1513
+ if (raw === void 0) return void 0;
1514
+ const parsed = Number(raw);
1515
+ if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
1516
+ throw new Error(`ERROR: ${flag} must be a number between 0 and 1.`);
1517
+ }
1518
+ return parsed;
1519
+ }
1520
+ function parseBenchResearchArgs(action, args) {
1521
+ const runRef = readBenchOptionValue(args, "--run");
1522
+ if (action === "attribute" && !runRef) {
1523
+ throw new Error("ERROR: bench attribute requires --run <id>.");
1524
+ }
1525
+ const memoryDirRaw = readBenchOptionValue(args, "--memory-dir");
1526
+ let seed;
1527
+ let out;
1528
+ if (action === "drift-gen") {
1529
+ const seedRaw = readBenchOptionValue(args, "--seed");
1530
+ if (seedRaw !== void 0) {
1531
+ const parsed = Number(seedRaw);
1532
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
1533
+ throw new Error("ERROR: --seed must be a non-negative safe integer.");
1534
+ }
1535
+ seed = parsed;
1536
+ }
1537
+ const outRaw = readBenchOptionValue(args, "--out");
1538
+ if (outRaw !== void 0) {
1539
+ out = path5.resolve(expandTilde(outRaw));
1540
+ }
1541
+ }
1542
+ const epochs = readPositiveInteger(args, "--epochs");
1543
+ if (action === "drift-gen" && epochs !== void 0 && epochs < 2) {
1544
+ throw new Error("ERROR: --epochs must be at least 2 (supersession needs two epochs).");
1545
+ }
1546
+ const driftingRatio = readUnitRatio(args, "--drifting-ratio");
1547
+ const contradictedRatio = readUnitRatio(args, "--contradicted-ratio");
1548
+ if ((driftingRatio ?? 0.2) + (contradictedRatio ?? 0.1) > 1) {
1549
+ throw new Error("ERROR: --drifting-ratio and --contradicted-ratio must sum to at most 1.");
1550
+ }
1551
+ return {
1552
+ runRef,
1553
+ memoryDir: memoryDirRaw ? path5.resolve(expandTilde(memoryDirRaw)) : void 0,
1554
+ users: readPositiveInteger(args, "--users"),
1555
+ epochs,
1556
+ seed,
1557
+ out,
1558
+ factsPerEpoch: readPositiveInteger(args, "--facts-per-epoch"),
1559
+ driftingRatio,
1560
+ contradictedRatio
1561
+ };
1562
+ }
1563
+
1564
+ // src/bench-args.ts
1565
+ function createBenchWorkItems(benchmarks, runtimeProfiles) {
1566
+ return benchmarks.flatMap(
1567
+ (benchmarkId) => runtimeProfiles.map((runtimeProfile) => ({ benchmarkId, runtimeProfile }))
1568
+ );
1569
+ }
1570
+ function deriveRuntimeProfilesFromBenchWorkItems(workItems) {
1571
+ return [...new Set(workItems.map((item) => item.runtimeProfile))];
1572
+ }
1573
+ function filterBenchWorkItemsForPreviousStatus(workItems, previousEntries, mode) {
1574
+ const statusById = new Map(previousEntries.map((entry) => [entry.id, entry.status]));
1575
+ const hasMatrixWork = new Set(workItems.map((item) => item.benchmarkId)).size !== workItems.length;
1576
+ function statusFor(item) {
1577
+ const profileStatus = statusById.get(`${item.benchmarkId} [${item.runtimeProfile}]`);
1578
+ if (profileStatus !== void 0) return profileStatus;
1579
+ if (hasMatrixWork) {
1580
+ return mode === "retry-failed" ? statusById.get(item.benchmarkId) : void 0;
1581
+ }
1582
+ return statusById.get(item.benchmarkId);
1583
+ }
1584
+ return workItems.filter((item) => {
1585
+ const status = statusFor(item);
1586
+ if (mode === "retry-failed") {
1587
+ return status === "failed";
1588
+ }
1589
+ return status !== "complete";
1590
+ });
1591
+ }
1592
+ var PUBLISHED_BENCHMARK_NAMES = Object.freeze([
1593
+ "ama-bench",
1594
+ "memory-arena",
1595
+ "amemgym",
1596
+ "longmemeval",
1597
+ "locomo",
1598
+ "beam",
1599
+ "personamem",
1600
+ "memoryagentbench",
1601
+ "membench"
1602
+ ]);
1603
+ function isBenchRuntimeProfile(value) {
1604
+ return value === "baseline" || value === "real" || value === "openclaw-chain" || value === "local-lab";
1605
+ }
1606
+ function parseBenchRuntimeProfile(value, flagName) {
1607
+ if (isBenchRuntimeProfile(value)) {
1608
+ return value;
1609
+ }
1610
+ if (flagName === "--runtime-profile") {
1611
+ throw new Error(
1612
+ 'ERROR: --runtime-profile must be "baseline", "real", "openclaw-chain", or "local-lab".'
1613
+ );
1614
+ }
1615
+ throw new Error(
1616
+ 'ERROR: --matrix must contain only "baseline", "real", "openclaw-chain", or "local-lab".'
1617
+ );
1618
+ }
1619
+ var BENCH_PROVIDER_ALLOWED = Object.freeze([
1620
+ "openai",
1621
+ "anthropic",
1622
+ "ollama",
1623
+ "litellm",
1624
+ "local-llm",
1625
+ "codex-cli",
1626
+ "claude-cli"
1627
+ ]);
1628
+ var BENCH_INTERNAL_PROVIDER_ALLOWED = Object.freeze(
1629
+ BENCH_PROVIDER_ALLOWED.filter((provider) => provider !== "claude-cli")
1630
+ );
1631
+ function isBuiltInProvider(value) {
1632
+ return BENCH_PROVIDER_ALLOWED.includes(value);
1633
+ }
1634
+ function isBuiltInInternalProvider(value) {
1635
+ return BENCH_INTERNAL_PROVIDER_ALLOWED.includes(value);
1636
+ }
1637
+ function parseBenchProvider(raw, flag) {
1638
+ if (!isBuiltInProvider(raw)) {
1639
+ throw new Error(
1640
+ `ERROR: ${flag} must be one of "openai", "anthropic", "ollama", "litellm", "local-llm", "codex-cli", or "claude-cli".`
1641
+ );
1642
+ }
1643
+ return raw;
1644
+ }
1645
+ function parseBenchInternalProvider(raw, flag) {
1646
+ if (!isBuiltInInternalProvider(raw)) {
1647
+ if (raw === "claude-cli") {
1648
+ throw new Error(
1649
+ `ERROR: ${flag} does not support "claude-cli" (no @remnic/core gateway wiring); use --provider, --system-provider, or --judge-provider instead.`
1650
+ );
1651
+ }
1652
+ throw new Error(
1653
+ `ERROR: ${flag} must be one of "openai", "anthropic", "ollama", "litellm", "local-llm", or "codex-cli".`
1654
+ );
1655
+ }
1656
+ return raw;
1657
+ }
1658
+ function parseCodexReasoningEffort(raw, flag) {
1659
+ if (raw !== "low" && raw !== "medium" && raw !== "high" && raw !== "xhigh") {
1660
+ throw new Error(
1661
+ `ERROR: ${flag} must be "low", "medium", "high", or "xhigh".`
1662
+ );
1663
+ }
1664
+ return raw;
1665
+ }
1666
+ var MCP_TOOL_OPERATIONS = /* @__PURE__ */ new Set(["store", "recall", "correct", "reset"]);
1667
+ var MCP_ARGUMENT_SEMANTICS = /* @__PURE__ */ new Set([
1668
+ "namespace",
1669
+ "sessionId",
1670
+ "content",
1671
+ "role",
1672
+ "timestamp",
1673
+ "query",
1674
+ "limit"
1675
+ ]);
1676
+ function parseMcpToolMapping(value) {
1677
+ if (!isPlainObject(value)) throw new Error("expected a JSON object");
1678
+ for (const operation of Object.keys(value).sort()) {
1679
+ if (!MCP_TOOL_OPERATIONS.has(operation)) {
1680
+ throw new Error(`unknown operation ${operation}`);
1681
+ }
1682
+ const entry = value[operation];
1683
+ if (typeof entry === "string") {
1684
+ if (entry.trim().length === 0) throw new Error(`${operation} tool name must not be empty`);
1685
+ continue;
1686
+ }
1687
+ if (!isPlainObject(entry)) {
1688
+ throw new Error(`${operation} must be a tool-name string or mapping object`);
1689
+ }
1690
+ for (const field of Object.keys(entry).sort()) {
1691
+ if (field !== "name" && field !== "arguments" && field !== "resultPath") {
1692
+ throw new Error(`${operation} contains unknown field ${field}`);
1616
1693
  }
1617
- continue;
1618
1694
  }
1619
- throw new Error(
1620
- `ERROR: unknown bench option ${arg}. Supported options: ${allOptions}.`
1621
- );
1622
- }
1623
- }
1624
- function collectBenchmarks(argv) {
1625
- const benchmarks = [];
1626
- for (let index = 0; index < argv.length; index += 1) {
1627
- const arg = argv[index];
1628
- if (isBenchValueFlag(arg)) {
1629
- index += 1;
1630
- continue;
1695
+ if (typeof entry.name !== "string" || entry.name.trim().length === 0) {
1696
+ throw new Error(`${operation}.name must be a non-empty string`);
1631
1697
  }
1632
- if (isBenchBooleanFlag(arg)) {
1633
- continue;
1698
+ if (entry.resultPath !== void 0) {
1699
+ if (typeof entry.resultPath !== "string" || !isSafeMcpResultPath(entry.resultPath)) {
1700
+ throw new Error(`${operation}.resultPath must be a non-empty safe dot path`);
1701
+ }
1634
1702
  }
1635
- if (!arg.startsWith("-")) {
1636
- benchmarks.push(arg);
1703
+ if (entry.arguments !== void 0) {
1704
+ if (!isPlainObject(entry.arguments)) {
1705
+ throw new Error(`${operation}.arguments must be an object`);
1706
+ }
1707
+ for (const semantic of Object.keys(entry.arguments).sort()) {
1708
+ if (!MCP_ARGUMENT_SEMANTICS.has(semantic)) {
1709
+ throw new Error(`${operation}.arguments contains unknown semantic ${semantic}`);
1710
+ }
1711
+ const argumentName = entry.arguments[semantic];
1712
+ if (typeof argumentName !== "string" || argumentName.trim().length === 0) {
1713
+ throw new Error(`${operation}.arguments.${semantic} must be a non-empty string`);
1714
+ }
1715
+ }
1637
1716
  }
1638
1717
  }
1639
- return benchmarks;
1718
+ return value;
1719
+ }
1720
+ function isPlainObject(value) {
1721
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1722
+ const prototype = Object.getPrototypeOf(value);
1723
+ return prototype === Object.prototype || prototype === null;
1724
+ }
1725
+ function isSafeMcpResultPath(value) {
1726
+ return value.split(".").every(
1727
+ (segment) => segment.length > 0 && segment !== "__proto__" && segment !== "prototype" && segment !== "constructor" && /^[A-Za-z0-9_-]+$/.test(segment)
1728
+ );
1640
1729
  }
1641
1730
  function parseBenchActionArgs(argv) {
1642
1731
  const [first, ...rest] = argv;
1643
- const action = first === "list" || first === "run" || first === "datasets" || first === "runs" || first === "compare" || first === "ui" || first === "results" || first === "baseline" || first === "export" || first === "providers" || first === "publish" || first === "published" || first === "judge-calibrate" || first === "check" || first === "report" ? first : first === void 0 || first === "--help" || first === "-h" ? "help" : "run";
1732
+ const action = first === "list" || first === "run" || first === "datasets" || first === "runs" || first === "compare" || first === "ui" || first === "results" || first === "baseline" || first === "export" || first === "providers" || first === "publish" || first === "published" || first === "judge-calibrate" || first === "check" || first === "report" || first === "attribute" || first === "drift-gen" ? first : first === void 0 || first === "--help" || first === "-h" ? "help" : "run";
1644
1733
  return {
1645
1734
  action,
1646
1735
  args: action === "run" && action !== first ? argv : rest
@@ -1662,6 +1751,7 @@ function parseBenchArgs(argv) {
1662
1751
  const datasetAction = action === "datasets" ? args[0] === "download" || args[0] === "status" ? args[0] : void 0 : void 0;
1663
1752
  const providerAction = action === "providers" ? args[0] === "discover" ? args[0] : void 0 : void 0;
1664
1753
  const runAction = action === "runs" ? args[0] === "list" || args[0] === "show" || args[0] === "delete" ? args[0] : void 0 : void 0;
1754
+ const driftGenAction = action === "drift-gen" ? args[0] === "validate" ? "validate" : args[0] === "generate" ? "generate" : args[0] !== void 0 && !args[0].startsWith("-") ? void 0 : "generate" : void 0;
1665
1755
  if (action === "baseline" && baselineAction === void 0) {
1666
1756
  throw new Error("ERROR: baseline requires a subcommand: save or list.");
1667
1757
  }
@@ -1674,8 +1764,13 @@ function parseBenchArgs(argv) {
1674
1764
  if (action === "runs" && runAction === void 0) {
1675
1765
  throw new Error("ERROR: runs requires a subcommand: list, show, or delete.");
1676
1766
  }
1767
+ if (action === "drift-gen" && driftGenAction === void 0) {
1768
+ throw new Error('ERROR: drift-gen subcommand must be "generate" or "validate".');
1769
+ }
1677
1770
  validateBenchFlags(action, args);
1678
- const benchmarkArgs = action === "baseline" || action === "datasets" || action === "providers" || action === "runs" ? args.slice(1) : args;
1771
+ const driftGenPositionals = action === "drift-gen" && driftGenAction === "validate" ? collectBenchmarks(args.slice(1)) : [];
1772
+ const driftGenDir = driftGenPositionals[0] ? path6.resolve(expandTilde(driftGenPositionals[0])) : void 0;
1773
+ const benchmarkArgs = action === "baseline" || action === "datasets" || action === "providers" || action === "runs" || action === "drift-gen" && (args[0] === "validate" || args[0] === "generate") ? args.slice(1) : args;
1679
1774
  const benchmarks = collectBenchmarks(benchmarkArgs);
1680
1775
  const datasetDir = readBenchOptionValue(args, "--dataset-dir") ?? readBenchOptionValue(args, "--dataset");
1681
1776
  const adapterRaw = readBenchOptionValue(args, "--adapter");
@@ -1757,6 +1852,7 @@ function parseBenchArgs(argv) {
1757
1852
  }
1758
1853
  adapter = adapterRaw;
1759
1854
  }
1855
+ const research = parseBenchResearchArgs(action, args);
1760
1856
  const hasMcpOptions = Boolean(
1761
1857
  mcpCommand || mcpArgsRaw || mcpUrl || mcpToolMapRaw || mcpDemo
1762
1858
  );
@@ -1887,6 +1983,9 @@ function parseBenchArgs(argv) {
1887
1983
  if (!Number.isFinite(threshold) || threshold < 0) {
1888
1984
  throw new Error("ERROR: --threshold must be a non-negative number.");
1889
1985
  }
1986
+ if (action === "attribute" && threshold > 1) {
1987
+ throw new Error("ERROR: --threshold must be a number between 0 and 1.");
1988
+ }
1890
1989
  }
1891
1990
  let format;
1892
1991
  if (formatRaw !== void 0) {
@@ -2220,13 +2319,13 @@ function parseBenchArgs(argv) {
2220
2319
  mcpUrl,
2221
2320
  mcpToolMap,
2222
2321
  mcpDemo,
2223
- datasetDir: datasetDir ? path5.resolve(expandTilde(datasetDir)) : void 0,
2224
- resultsDir: resultsDir ? path5.resolve(expandTilde(resultsDir)) : void 0,
2225
- baselinesDir: baselinesDir ? path5.resolve(expandTilde(baselinesDir)) : void 0,
2322
+ datasetDir: datasetDir ? path6.resolve(expandTilde(datasetDir)) : void 0,
2323
+ resultsDir: resultsDir ? path6.resolve(expandTilde(resultsDir)) : void 0,
2324
+ baselinesDir: baselinesDir ? path6.resolve(expandTilde(baselinesDir)) : void 0,
2226
2325
  runtimeProfile,
2227
2326
  matrixProfiles,
2228
- remnicConfigPath: remnicConfigRaw ? path5.resolve(expandTilde(remnicConfigRaw)) : void 0,
2229
- openclawConfigPath: openclawConfigRaw ? path5.resolve(expandTilde(openclawConfigRaw)) : void 0,
2327
+ remnicConfigPath: remnicConfigRaw ? path6.resolve(expandTilde(remnicConfigRaw)) : void 0,
2328
+ openclawConfigPath: openclawConfigRaw ? path6.resolve(expandTilde(openclawConfigRaw)) : void 0,
2230
2329
  modelSource,
2231
2330
  gatewayAgentId,
2232
2331
  fastGatewayAgentId,
@@ -2249,13 +2348,13 @@ function parseBenchArgs(argv) {
2249
2348
  internalDisableThinking: args.includes("--internal-disable-thinking"),
2250
2349
  internalCodexReasoningEffort,
2251
2350
  threshold,
2252
- custom: customRaw ? path5.resolve(expandTilde(customRaw)) : void 0,
2351
+ custom: customRaw ? path6.resolve(expandTilde(customRaw)) : void 0,
2253
2352
  baselineAction,
2254
2353
  datasetAction,
2255
2354
  providerAction,
2256
2355
  runAction,
2257
2356
  format,
2258
- output: output ? path5.resolve(expandTilde(output)) : void 0,
2357
+ output: output ? path6.resolve(expandTilde(output)) : void 0,
2259
2358
  target,
2260
2359
  publishedName,
2261
2360
  publishedSeed,
@@ -2265,24 +2364,24 @@ function parseBenchArgs(argv) {
2265
2364
  publishedIngestConcurrency,
2266
2365
  publishedTaskFilter,
2267
2366
  memcorrectAdapter,
2268
- publishedOut: publishedOutRaw ? path5.resolve(expandTilde(publishedOutRaw)) : void 0,
2367
+ publishedOut: publishedOutRaw ? path6.resolve(expandTilde(publishedOutRaw)) : void 0,
2269
2368
  publishedDryRun: args.includes("--dry-run"),
2270
2369
  requestTimeout,
2271
2370
  localJudgeRequestTimeout,
2272
2371
  frontierJudgeRequestTimeout,
2273
- calibrationDir: calibrationDirRaw ? path5.resolve(expandTilde(calibrationDirRaw)) : void 0,
2372
+ calibrationDir: calibrationDirRaw ? path6.resolve(expandTilde(calibrationDirRaw)) : void 0,
2274
2373
  calibrationLocalConfigSha256,
2275
2374
  calibrationFrontierConfigSha256,
2276
2375
  sourceResultId,
2277
2376
  expectedAnswerSetSha256,
2278
2377
  expectedQuestionIdListSha256,
2279
- taskIdsFile: taskIdsFileRaw ? path5.resolve(expandTilde(taskIdsFileRaw)) : void 0,
2378
+ taskIdsFile: taskIdsFileRaw ? path6.resolve(expandTilde(taskIdsFileRaw)) : void 0,
2280
2379
  expectedTaskIdListSha256,
2281
2380
  drainTimeout,
2282
2381
  // Issue #1573 PR1: surface judge-cache flags into the runner options.
2283
2382
  noJudgeCache: args.includes("--no-judge-cache"),
2284
- judgeCacheDir: judgeCacheDirRaw ? path5.resolve(expandTilde(judgeCacheDirRaw)) : void 0,
2285
- localLabManifestPath: localLabManifestRaw ? path5.resolve(expandTilde(localLabManifestRaw)) : void 0,
2383
+ judgeCacheDir: judgeCacheDirRaw ? path6.resolve(expandTilde(judgeCacheDirRaw)) : void 0,
2384
+ localLabManifestPath: localLabManifestRaw ? path6.resolve(expandTilde(localLabManifestRaw)) : void 0,
2286
2385
  max429WaitMs,
2287
2386
  disableThinking: args.includes("--disable-thinking"),
2288
2387
  amaBenchJudgeProtocol,
@@ -2292,15 +2391,18 @@ function parseBenchArgs(argv) {
2292
2391
  amaBenchCrossJudgeApiKey,
2293
2392
  amaBenchCrossJudgeCodexReasoningEffort,
2294
2393
  resume,
2295
- retryFailed
2394
+ retryFailed,
2395
+ ...research,
2396
+ driftGenAction,
2397
+ driftGenDir
2296
2398
  };
2297
2399
  }
2298
2400
 
2299
2401
  // src/bench-status.ts
2300
2402
  import { mkdir, readFile, readdir as readdir2, rename, writeFile } from "fs/promises";
2301
- import path6 from "path";
2403
+ import path7 from "path";
2302
2404
  function createBenchStatusPath(resultsDir, pid, startedAtMs = Date.now()) {
2303
- return path6.join(resultsDir, `bench-status-${startedAtMs}-${pid}.json`);
2405
+ return path7.join(resultsDir, `bench-status-${startedAtMs}-${pid}.json`);
2304
2406
  }
2305
2407
  var BENCH_STATUS_FILENAME = /^bench-status-\d+-\d+\.json$/;
2306
2408
  var VALID_BENCH_ENTRY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "complete", "failed"]);
@@ -2313,7 +2415,7 @@ async function findLatestBenchStatusFile(resultsDir) {
2313
2415
  }
2314
2416
  const candidates = entries.filter((name) => BENCH_STATUS_FILENAME.test(name)).sort().reverse();
2315
2417
  for (const name of candidates) {
2316
- const filePath = path6.join(resultsDir, name);
2418
+ const filePath = path7.join(resultsDir, name);
2317
2419
  const status = await readBenchStatus(filePath);
2318
2420
  if (status) {
2319
2421
  return filePath;
@@ -2322,7 +2424,7 @@ async function findLatestBenchStatusFile(resultsDir) {
2322
2424
  return null;
2323
2425
  }
2324
2426
  async function atomicWriteJSON(filePath, data) {
2325
- await mkdir(path6.dirname(filePath), { recursive: true });
2427
+ await mkdir(path7.dirname(filePath), { recursive: true });
2326
2428
  const tmp = `${filePath}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;
2327
2429
  await writeFile(tmp, JSON.stringify(data, null, 2) + "\n");
2328
2430
  await rename(tmp, filePath);
@@ -2440,7 +2542,7 @@ function finalizeBenchStatus(filePath) {
2440
2542
 
2441
2543
  // src/bench-fallback.ts
2442
2544
  import fs6 from "fs";
2443
- import path7 from "path";
2545
+ import path8 from "path";
2444
2546
  var FALLBACK_RESULTS_DIRNAME = "fallback-runs";
2445
2547
  function buildBenchRunnerArgs(parsed, benchmarkId, outputDir) {
2446
2548
  const args = ["--benchmark", benchmarkId];
@@ -2504,7 +2606,7 @@ function findUnsupportedFallbackBenchOptions(parsed) {
2504
2606
  return unsupported;
2505
2607
  }
2506
2608
  function createFallbackBenchOutputDir(resultsDir, benchmarkId, pid, startedAtMs = Date.now()) {
2507
- return path7.join(
2609
+ return path8.join(
2508
2610
  resultsDir,
2509
2611
  FALLBACK_RESULTS_DIRNAME,
2510
2612
  `${benchmarkId}-${startedAtMs}-${pid}`
@@ -2515,18 +2617,18 @@ function resolveFallbackBenchResultPath(outputDir) {
2515
2617
  if (entries.length === 0) {
2516
2618
  throw new Error(`Fallback benchmark runner did not write a JSON result artifact in ${outputDir}`);
2517
2619
  }
2518
- return path7.join(outputDir, entries[0]);
2620
+ return path8.join(outputDir, entries[0]);
2519
2621
  }
2520
2622
 
2521
2623
  // src/openclaw-upgrade-swap.ts
2522
2624
  import fs7 from "fs";
2523
- import path8 from "path";
2625
+ import path9 from "path";
2524
2626
  function describeError(error) {
2525
2627
  return error instanceof Error ? error.message : String(error);
2526
2628
  }
2527
2629
  function createSiblingTempFilePath(targetPath, label) {
2528
2630
  const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
2529
- return path8.join(path8.dirname(targetPath), `.${path8.basename(targetPath)}.${label}.${nonce}.tmp`);
2631
+ return path9.join(path9.dirname(targetPath), `.${path9.basename(targetPath)}.${label}.${nonce}.tmp`);
2530
2632
  }
2531
2633
  function resolveAtomicWriteMode(targetPath, explicitMode) {
2532
2634
  if (explicitMode !== void 0) return explicitMode;
@@ -2554,7 +2656,7 @@ function resolveAtomicReplacementPath(targetPath) {
2554
2656
  }
2555
2657
  function createSiblingSwapPath(targetDir, label) {
2556
2658
  const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
2557
- return path8.join(path8.dirname(targetDir), `.${path8.basename(targetDir)}.${label}.${nonce}`);
2659
+ return path9.join(path9.dirname(targetDir), `.${path9.basename(targetDir)}.${label}.${nonce}`);
2558
2660
  }
2559
2661
  function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
2560
2662
  if (!displacedDir) return void 0;
@@ -2567,7 +2669,7 @@ function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
2567
2669
  }
2568
2670
  function atomicWriteFileSync(targetPath, data, options = {}) {
2569
2671
  const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
2570
- fs7.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
2672
+ fs7.mkdirSync(path9.dirname(resolvedTargetPath), { recursive: true });
2571
2673
  const tempPath = createSiblingTempFilePath(resolvedTargetPath, "write");
2572
2674
  const mode = resolveAtomicWriteMode(resolvedTargetPath, options.mode);
2573
2675
  try {
@@ -2587,7 +2689,7 @@ function atomicWriteFileSync(targetPath, data, options = {}) {
2587
2689
  function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
2588
2690
  if (!fs7.existsSync(sourcePath)) return;
2589
2691
  const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
2590
- fs7.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
2692
+ fs7.mkdirSync(path9.dirname(resolvedTargetPath), { recursive: true });
2591
2693
  const tempPath = createSiblingTempFilePath(resolvedTargetPath, "copy");
2592
2694
  const mode = fs7.statSync(sourcePath).mode & 4095;
2593
2695
  try {
@@ -2603,7 +2705,7 @@ function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
2603
2705
  }
2604
2706
  function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
2605
2707
  let hasRollbackCopy = false;
2606
- fs7.mkdirSync(path8.dirname(targetDir), { recursive: true });
2708
+ fs7.mkdirSync(path9.dirname(targetDir), { recursive: true });
2607
2709
  fs7.rmSync(rollbackDir, { recursive: true, force: true });
2608
2710
  if (fs7.existsSync(targetDir)) {
2609
2711
  fs7.renameSync(targetDir, rollbackDir);
@@ -2645,7 +2747,7 @@ function restoreDirectoryFromRollback(targetDir, rollbackDir) {
2645
2747
  if (!fs7.existsSync(rollbackDir)) {
2646
2748
  throw new Error(`Rollback directory is missing: ${rollbackDir}`);
2647
2749
  }
2648
- fs7.mkdirSync(path8.dirname(targetDir), { recursive: true });
2750
+ fs7.mkdirSync(path9.dirname(targetDir), { recursive: true });
2649
2751
  const displacedDir = fs7.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
2650
2752
  if (displacedDir) {
2651
2753
  fs7.renameSync(targetDir, displacedDir);
@@ -2677,7 +2779,7 @@ function restoreDirectoryFromBackup(targetDir, backupDir) {
2677
2779
  if (!fs7.existsSync(backupDir)) {
2678
2780
  throw new Error(`Plugin backup directory is missing: ${backupDir}`);
2679
2781
  }
2680
- fs7.mkdirSync(path8.dirname(targetDir), { recursive: true });
2782
+ fs7.mkdirSync(path9.dirname(targetDir), { recursive: true });
2681
2783
  const stagedDir = createSiblingSwapPath(targetDir, "backup-restore");
2682
2784
  const displacedDir = fs7.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
2683
2785
  fs7.cpSync(backupDir, stagedDir, { recursive: true });
@@ -2802,10 +2904,10 @@ Run this manually when you're ready:
2802
2904
 
2803
2905
  // src/daemon-service.ts
2804
2906
  import fs8 from "fs";
2805
- import path9 from "path";
2907
+ import path10 from "path";
2806
2908
  import * as childProcess from "child_process";
2807
2909
  import { fileURLToPath as fileURLToPath3 } from "url";
2808
- var thisModuleDir = path9.dirname(fileURLToPath3(import.meta.url));
2910
+ var thisModuleDir = path10.dirname(fileURLToPath3(import.meta.url));
2809
2911
  function launchdLoadPlist(plistPath, processApi = childProcess) {
2810
2912
  processApi.execFileSync("launchctl", ["load", "-w", plistPath], { stdio: "pipe" });
2811
2913
  }
@@ -2827,8 +2929,8 @@ function resolveServerBinDetails(options = {}) {
2827
2929
  });
2828
2930
  } catch {
2829
2931
  }
2830
- const workspaceServerBin = path9.resolve(moduleDir, "../../remnic-server/bin/remnic-server.js");
2831
- const workspaceDistIndex = path9.resolve(moduleDir, "../../remnic-server/dist/index.js");
2932
+ const workspaceServerBin = path10.resolve(moduleDir, "../../remnic-server/bin/remnic-server.js");
2933
+ const workspaceDistIndex = path10.resolve(moduleDir, "../../remnic-server/dist/index.js");
2832
2934
  candidates.push(
2833
2935
  {
2834
2936
  path: workspaceServerBin,
@@ -2849,11 +2951,11 @@ function resolveServerBinDetails(options = {}) {
2849
2951
  });
2850
2952
  }
2851
2953
  candidates.push({
2852
- path: path9.resolve(moduleDir, "../../remnic-server/src/index.ts"),
2954
+ path: path10.resolve(moduleDir, "../../remnic-server/src/index.ts"),
2853
2955
  source: "workspace-source"
2854
2956
  });
2855
2957
  const selected = candidates.find((candidate) => isCandidateReady(candidate, existsSync4)) ?? candidates.find((candidate) => existsSync4(candidate.path)) ?? candidates[0] ?? {
2856
- path: path9.resolve(moduleDir, "../../remnic-server/dist/index.js"),
2958
+ path: path10.resolve(moduleDir, "../../remnic-server/dist/index.js"),
2857
2959
  source: "workspace-dist"
2858
2960
  };
2859
2961
  const exists = existsSync4(selected.path);
@@ -2908,7 +3010,7 @@ function readVerifiedDaemonPid(options) {
2908
3010
  }
2909
3011
  function doesProcessCommandLookLikeRemnicDaemon(command, expectedServerBin) {
2910
3012
  const normalizedCommand = command.trim();
2911
- const normalizedExpected = path9.resolve(expandTilde(expectedServerBin));
3013
+ const normalizedExpected = path10.resolve(expandTilde(expectedServerBin));
2912
3014
  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);
2913
3015
  }
2914
3016
  function parseDaemonPid(raw) {
@@ -3013,7 +3115,7 @@ function inspectLaunchdPlist(plistPath, options = {}) {
3013
3115
  };
3014
3116
  }
3015
3117
  const expandedServerArg = expandTilde(serverArg);
3016
- if (!path9.isAbsolute(expandedServerArg)) {
3118
+ if (!path10.isAbsolute(expandedServerArg)) {
3017
3119
  return {
3018
3120
  installed: true,
3019
3121
  ok: false,
@@ -3085,8 +3187,8 @@ function normalizeResolvedPath(resolved) {
3085
3187
  return resolved;
3086
3188
  }
3087
3189
  function packageServerBinFromEntry(packageEntry) {
3088
- if (path9.basename(packageEntry) === "index.js" && path9.basename(path9.dirname(packageEntry)) === "dist") {
3089
- return path9.join(path9.dirname(path9.dirname(packageEntry)), "bin", "remnic-server.js");
3190
+ if (path10.basename(packageEntry) === "index.js" && path10.basename(path10.dirname(packageEntry)) === "dist") {
3191
+ return path10.join(path10.dirname(path10.dirname(packageEntry)), "bin", "remnic-server.js");
3090
3192
  }
3091
3193
  return packageEntry;
3092
3194
  }
@@ -3217,7 +3319,7 @@ import {
3217
3319
 
3218
3320
  // src/import-bundle-detect.ts
3219
3321
  import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
3220
- import path10 from "path";
3322
+ import path11 from "path";
3221
3323
  function detectBundleEntries(bundleDir, options = {}) {
3222
3324
  const readdir3 = options.readdirImpl ?? defaultReaddir;
3223
3325
  const readFileImpl = options.readFileImpl ?? defaultReadFile;
@@ -3248,7 +3350,7 @@ function detectBundleEntries(bundleDir, options = {}) {
3248
3350
  for (const filePath of roots) {
3249
3351
  if (seenFiles.has(filePath)) continue;
3250
3352
  seenFiles.add(filePath);
3251
- const name = path10.basename(filePath);
3353
+ const name = path11.basename(filePath);
3252
3354
  const match = classifyFile(name, filePath, readFileImpl);
3253
3355
  if (match) entries.push(match);
3254
3356
  }
@@ -3286,7 +3388,7 @@ function collectCandidatePaths(root, readdir3, isDirectory2, isRegularFile) {
3286
3388
  return;
3287
3389
  }
3288
3390
  for (const entry of entries) {
3289
- const full = path10.join(dir, entry);
3391
+ const full = path11.join(dir, entry);
3290
3392
  if (isDirectory2(full)) {
3291
3393
  walk(full, depth + 1);
3292
3394
  } else if (isRegularFile(full)) {
@@ -3836,7 +3938,7 @@ async function cmdCapture(rest, io) {
3836
3938
 
3837
3939
  // src/import-lossless-claw-cmd.ts
3838
3940
  import fs10 from "fs";
3839
- import path11 from "path";
3941
+ import path12 from "path";
3840
3942
  import {
3841
3943
  applyLcmSchema,
3842
3944
  ensureLcmStateDir,
@@ -3986,7 +4088,7 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
3986
4088
  let destDb;
3987
4089
  try {
3988
4090
  if (parsed.dryRun) {
3989
- const lcmPath = path11.join(memoryDir, "state", "lcm.sqlite");
4091
+ const lcmPath = path12.join(memoryDir, "state", "lcm.sqlite");
3990
4092
  if (fs10.existsSync(lcmPath)) {
3991
4093
  destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
3992
4094
  } else {
@@ -4104,106 +4206,54 @@ function printBenchComparisonSummary(comparison, baseline, candidate) {
4104
4206
  }
4105
4207
  }
4106
4208
 
4107
- // src/index.ts
4108
- var LazyPluginPiPublisher = class {
4109
- constructor(hostId, select) {
4110
- this.hostId = hostId;
4111
- this.select = select;
4112
- }
4113
- hostId;
4114
- select;
4115
- delegate;
4116
- async resolveExtensionRoot(env) {
4117
- return (await this.load()).resolveExtensionRoot(env);
4118
- }
4119
- async isHostAvailable() {
4120
- return (await this.load()).isHostAvailable();
4121
- }
4122
- async renderInstructions(ctx) {
4123
- return (await this.load()).renderInstructions(ctx);
4124
- }
4125
- async publish(ctx) {
4126
- return (await this.load()).publish(ctx);
4127
- }
4128
- async unpublish() {
4129
- return (await this.load()).unpublish();
4130
- }
4131
- async load() {
4132
- this.delegate ??= loadPiPublisherModule().then((mod) => new (this.select(mod))()).catch((err) => {
4133
- this.delegate = void 0;
4134
- throw err;
4135
- });
4136
- return this.delegate;
4137
- }
4138
- };
4139
- async function loadPiPublisherModule() {
4140
- return await import("@remnic/plugin-pi/publisher");
4141
- }
4142
- registerPublisher("codex", () => new CodexMemoryExtensionPublisher());
4143
- registerPublisher("claude-code", () => new ClaudeCodeMemoryExtensionPublisher());
4144
- registerPublisher("hermes", () => new HermesMemoryExtensionPublisher());
4145
- registerPublisher("pi", () => new LazyPluginPiPublisher("pi", (mod) => mod.PiMemoryExtensionPublisher));
4146
- registerPublisher("omp", () => new LazyPluginPiPublisher("omp", (mod) => mod.OmpMemoryExtensionPublisher));
4147
- function readCompatEnv(primary, legacy) {
4148
- return process.env[primary] ?? process.env[legacy];
4149
- }
4150
- var PID_DIR = path12.join(resolveHomeDir(), ".remnic");
4151
- var LEGACY_PID_DIR = path12.join(resolveHomeDir(), ".engram");
4152
- var PID_FILE = path12.join(PID_DIR, "server.pid");
4153
- var LEGACY_PID_FILE = path12.join(LEGACY_PID_DIR, "server.pid");
4154
- var LOG_FILE = path12.join(PID_DIR, "server.log");
4155
- var LEGACY_LOG_FILE = path12.join(LEGACY_PID_DIR, "server.log");
4156
- var CLI_MODULE_DIR = path12.dirname(fileURLToPath4(import.meta.url));
4157
- var CLI_REPO_ROOT = path12.resolve(CLI_MODULE_DIR, "../../..");
4158
- var EVAL_RUNNER_PATH = path12.join(CLI_REPO_ROOT, "evals", "run.ts");
4159
- var OPENCLAW_GATEWAY_LABEL = "ai.openclaw.gateway";
4160
- var CLI_SUCCESS_EXIT_GRACE_MS = 5e3;
4161
- var CLI_OUTPUT_FLUSH_GRACE_MS = 250;
4162
- var BENCHMARK_CATALOG = [
4163
- {
4164
- id: "ama-bench",
4165
- title: "AMA-Bench",
4166
- category: "agentic",
4167
- summary: "Agent Memory Abilities benchmark for long-horizon agent workflows."
4168
- },
4169
- {
4170
- id: "memory-arena",
4171
- title: "Memory Arena",
4172
- category: "agentic",
4173
- summary: "Interdependent multi-session tasks that stress operational recall."
4174
- },
4175
- {
4176
- id: "amemgym",
4177
- title: "AMemGym",
4178
- category: "agentic",
4179
- summary: "Interactive personalization benchmark for agent memory adaptation."
4180
- },
4181
- {
4182
- id: "longmemeval",
4183
- title: "LongMemEval",
4184
- category: "retrieval",
4185
- summary: "Long-term memory retrieval benchmark across core memory abilities."
4186
- },
4187
- {
4188
- id: "locomo",
4189
- title: "LoCoMo",
4190
- category: "conversational",
4191
- summary: "Long-conversation memory benchmark for persistent dialogue context."
4192
- },
4193
- {
4194
- id: "beam",
4195
- title: "BEAM",
4196
- category: "retrieval",
4197
- summary: "Beyond a Million Tokens benchmark for long-term memory abilities."
4209
+ // src/bench-research-commands.ts
4210
+ import path13 from "path";
4211
+ function emit(result) {
4212
+ if (result.output) {
4213
+ console.log(result.output);
4214
+ }
4215
+ if (result.exitCode !== 0) {
4216
+ process.exitCode = result.exitCode;
4217
+ }
4218
+ }
4219
+ async function runBenchResearchCommand(parsed) {
4220
+ if (parsed.action === "attribute") {
4221
+ if (!parsed.runRef) {
4222
+ throw new Error("ERROR: bench attribute requires --run <id>.");
4223
+ }
4224
+ const { runAttributeCliCommand } = await loadBenchModule();
4225
+ emit(
4226
+ await runAttributeCliCommand({
4227
+ runRef: parsed.runRef,
4228
+ resultsDir: parsed.resultsDir ?? path13.join(resolveHomeDir(), ".remnic", "bench", "results"),
4229
+ memoryDir: parsed.memoryDir,
4230
+ threshold: parsed.threshold,
4231
+ json: parsed.json
4232
+ })
4233
+ );
4234
+ return;
4198
4235
  }
4199
- ];
4200
- var BENCHMARK_IDS = new Set(BENCHMARK_CATALOG.map((entry) => entry.id));
4201
- async function loadTrainingExportCoreRuntime() {
4202
- return await import("@remnic/core");
4236
+ const { runDriftGenCliCommand } = await loadBenchModule();
4237
+ emit(
4238
+ await runDriftGenCliCommand({
4239
+ action: parsed.driftGenAction ?? "generate",
4240
+ dir: parsed.driftGenDir,
4241
+ users: parsed.users,
4242
+ epochs: parsed.epochs,
4243
+ seed: parsed.seed,
4244
+ out: parsed.out,
4245
+ factsPerEpoch: parsed.factsPerEpoch,
4246
+ driftingRatio: parsed.driftingRatio,
4247
+ contradictedRatio: parsed.contradictedRatio,
4248
+ json: parsed.json
4249
+ })
4250
+ );
4203
4251
  }
4252
+
4253
+ // src/bench-usage.ts
4204
4254
  function getBenchUsageText() {
4205
- return `Usage: remnic bench <list|run|published|datasets|runs|compare|results|baseline|export|publish|ui|providers|judge-calibrate> [options] [benchmark...]
4206
- remnic benchmark <list|run|published|datasets|runs|compare|results|baseline|export|publish|ui|providers|judge-calibrate|check|report> [options] [benchmark...]
4255
+ return `Usage: remnic bench <list|run|published|datasets|runs|compare|results|baseline|export|publish|ui|providers|judge-calibrate|attribute|drift-gen> [options] [benchmark...]
4256
+ remnic benchmark <list|run|published|datasets|runs|compare|results|baseline|export|publish|ui|providers|judge-calibrate|check|report|attribute|drift-gen> [options] [benchmark...]
4207
4257
 
4208
4258
  Commands:
4209
4259
  list List published benchmark packs
@@ -4239,6 +4289,12 @@ Commands:
4239
4289
  answers, reports Cohen's kappa, and persists it so
4240
4290
  subsequent local artifacts carry the kappa + warning.
4241
4291
  check Legacy latency regression gate (compatibility)
4292
+ attribute --run <id> [--results-dir <path>] [--memory-dir <path>] [--threshold <value>]
4293
+ Attribute operation-level benchmark failures to memory operations
4294
+ drift-gen [generate|validate <dir>] [--users <n>] [--epochs <n>] [--seed <n>]
4295
+ [--out <dir>] [--facts-per-epoch <n>] [--drifting-ratio <r>]
4296
+ [--contradicted-ratio <r>]
4297
+ Generate or validate synthetic memory drift bench corpora
4242
4298
  report Legacy latency report generator (compatibility)
4243
4299
  procedural-ablation --out <path> [--fixture <path>]
4244
4300
  Run the procedural recall ablation harness (issue #567)
@@ -4327,7 +4383,8 @@ Options:
4327
4383
  (defaults to --request-timeout; implicit codex-cli default: 600000)
4328
4384
  --local-lab-manifest <path>
4329
4385
  Path to a local-lab manifest JSON file (required for --runtime-profile local-lab)
4330
- --threshold <value> Regression threshold for compare (default: 0.05)
4386
+ --threshold <value> Regression threshold for compare (default: 0.05);
4387
+ gold-memory similarity threshold for attribute (default: 0.6)
4331
4388
  --trial-limit <n> Cap scored LoCoMo or MemoryAgentBench QA trials for staged published runs
4332
4389
  --task-ids-file <path> Select an explicit JSON array of LoCoMo task IDs
4333
4390
  --expected-task-id-list-sha256 <sha256>
@@ -4338,6 +4395,13 @@ Options:
4338
4395
  --output <path> Write bench export output to a file
4339
4396
  --target <name> Publish target for bench publish (remnic-ai)
4340
4397
  --json Output JSON for \`list\`
4398
+ --run <id> Benchmark run reference for attribute
4399
+ --memory-dir <path> Memory directory for failure attribution
4400
+ --users <n> Synthetic user count for drift-gen
4401
+ --epochs <n> Synthetic timeline epochs for drift-gen
4402
+ --facts-per-epoch <n> Facts generated per user per epoch for drift-gen
4403
+ --drifting-ratio <r> Ratio of facts that undergo drift across epochs
4404
+ --contradicted-ratio <r> Ratio of drifting facts that are direct contradictions
4341
4405
 
4342
4406
  Examples:
4343
4407
  remnic bench list
@@ -4367,8 +4431,109 @@ Examples:
4367
4431
  remnic bench providers discover
4368
4432
  remnic bench run --custom ./my-bench.yaml
4369
4433
  remnic bench procedural-ablation --out ./artifacts/procedural-ablation.json
4434
+ remnic bench attribute --run run-12345 --memory-dir ./memories
4435
+ remnic bench drift-gen generate --users 20 --epochs 10 --out ./corpus
4436
+ remnic bench drift-gen validate ./corpus
4370
4437
  remnic benchmark run --quick longmemeval`;
4371
4438
  }
4439
+
4440
+ // src/index.ts
4441
+ var LazyPluginPiPublisher = class {
4442
+ constructor(hostId, select) {
4443
+ this.hostId = hostId;
4444
+ this.select = select;
4445
+ }
4446
+ hostId;
4447
+ select;
4448
+ delegate;
4449
+ async resolveExtensionRoot(env) {
4450
+ return (await this.load()).resolveExtensionRoot(env);
4451
+ }
4452
+ async isHostAvailable() {
4453
+ return (await this.load()).isHostAvailable();
4454
+ }
4455
+ async renderInstructions(ctx) {
4456
+ return (await this.load()).renderInstructions(ctx);
4457
+ }
4458
+ async publish(ctx) {
4459
+ return (await this.load()).publish(ctx);
4460
+ }
4461
+ async unpublish() {
4462
+ return (await this.load()).unpublish();
4463
+ }
4464
+ async load() {
4465
+ this.delegate ??= loadPiPublisherModule().then((mod) => new (this.select(mod))()).catch((err) => {
4466
+ this.delegate = void 0;
4467
+ throw err;
4468
+ });
4469
+ return this.delegate;
4470
+ }
4471
+ };
4472
+ async function loadPiPublisherModule() {
4473
+ return await import("@remnic/plugin-pi/publisher");
4474
+ }
4475
+ registerPublisher("codex", () => new CodexMemoryExtensionPublisher());
4476
+ registerPublisher("claude-code", () => new ClaudeCodeMemoryExtensionPublisher());
4477
+ registerPublisher("hermes", () => new HermesMemoryExtensionPublisher());
4478
+ registerPublisher("pi", () => new LazyPluginPiPublisher("pi", (mod) => mod.PiMemoryExtensionPublisher));
4479
+ registerPublisher("omp", () => new LazyPluginPiPublisher("omp", (mod) => mod.OmpMemoryExtensionPublisher));
4480
+ function readCompatEnv(primary, legacy) {
4481
+ return process.env[primary] ?? process.env[legacy];
4482
+ }
4483
+ var PID_DIR = path14.join(resolveHomeDir(), ".remnic");
4484
+ var LEGACY_PID_DIR = path14.join(resolveHomeDir(), ".engram");
4485
+ var PID_FILE = path14.join(PID_DIR, "server.pid");
4486
+ var LEGACY_PID_FILE = path14.join(LEGACY_PID_DIR, "server.pid");
4487
+ var LOG_FILE = path14.join(PID_DIR, "server.log");
4488
+ var LEGACY_LOG_FILE = path14.join(LEGACY_PID_DIR, "server.log");
4489
+ var CLI_MODULE_DIR = path14.dirname(fileURLToPath4(import.meta.url));
4490
+ var CLI_REPO_ROOT = path14.resolve(CLI_MODULE_DIR, "../../..");
4491
+ var EVAL_RUNNER_PATH = path14.join(CLI_REPO_ROOT, "evals", "run.ts");
4492
+ var OPENCLAW_GATEWAY_LABEL = "ai.openclaw.gateway";
4493
+ var CLI_SUCCESS_EXIT_GRACE_MS = 5e3;
4494
+ var CLI_OUTPUT_FLUSH_GRACE_MS = 250;
4495
+ var BENCHMARK_CATALOG = [
4496
+ {
4497
+ id: "ama-bench",
4498
+ title: "AMA-Bench",
4499
+ category: "agentic",
4500
+ summary: "Agent Memory Abilities benchmark for long-horizon agent workflows."
4501
+ },
4502
+ {
4503
+ id: "memory-arena",
4504
+ title: "Memory Arena",
4505
+ category: "agentic",
4506
+ summary: "Interdependent multi-session tasks that stress operational recall."
4507
+ },
4508
+ {
4509
+ id: "amemgym",
4510
+ title: "AMemGym",
4511
+ category: "agentic",
4512
+ summary: "Interactive personalization benchmark for agent memory adaptation."
4513
+ },
4514
+ {
4515
+ id: "longmemeval",
4516
+ title: "LongMemEval",
4517
+ category: "retrieval",
4518
+ summary: "Long-term memory retrieval benchmark across core memory abilities."
4519
+ },
4520
+ {
4521
+ id: "locomo",
4522
+ title: "LoCoMo",
4523
+ category: "conversational",
4524
+ summary: "Long-conversation memory benchmark for persistent dialogue context."
4525
+ },
4526
+ {
4527
+ id: "beam",
4528
+ title: "BEAM",
4529
+ category: "retrieval",
4530
+ summary: "Beyond a Million Tokens benchmark for long-term memory abilities."
4531
+ }
4532
+ ];
4533
+ var BENCHMARK_IDS = new Set(BENCHMARK_CATALOG.map((entry) => entry.id));
4534
+ async function loadTrainingExportCoreRuntime() {
4535
+ return await import("@remnic/core");
4536
+ }
4372
4537
  function buildBenchRuntimeProfileRequest(parsed, runtimeProfile) {
4373
4538
  return {
4374
4539
  runtimeProfile,
@@ -4543,8 +4708,8 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
4543
4708
  process.exit(1);
4544
4709
  }
4545
4710
  const tsxCandidates = [
4546
- path12.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
4547
- path12.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
4711
+ path14.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
4712
+ path14.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
4548
4713
  ];
4549
4714
  const tsxCmd = tsxCandidates.find((candidate) => fs11.existsSync(candidate)) ?? "tsx";
4550
4715
  const fallbackOutputDir = createFallbackBenchOutputDir(
@@ -4563,7 +4728,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
4563
4728
  return resolveFallbackBenchResultPath(fallbackOutputDir);
4564
4729
  }
4565
4730
  function resolveBenchOutputDir() {
4566
- return path12.join(resolveHomeDir(), ".remnic", "bench", "results");
4731
+ return path14.join(resolveHomeDir(), ".remnic", "bench", "results");
4567
4732
  }
4568
4733
  var DOWNLOADABLE_BENCHMARK_DATASETS = [
4569
4734
  "ama-bench",
@@ -4608,8 +4773,8 @@ var MEMORY_AGENT_BENCH_SPLIT_FILENAMES = [
4608
4773
  ];
4609
4774
  var MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES = [
4610
4775
  "entity2id.json",
4611
- path12.join("processed_data", "Recsys_Redial", "entity2id.json"),
4612
- path12.join("Recsys_Redial", "entity2id.json")
4776
+ path14.join("processed_data", "Recsys_Redial", "entity2id.json"),
4777
+ path14.join("Recsys_Redial", "entity2id.json")
4613
4778
  ];
4614
4779
  var DOWNLOADED_DATASET_MARKERS = {
4615
4780
  "ama-bench": { anyOf: ["open_end_qa_set.jsonl"] },
@@ -4684,7 +4849,7 @@ var PERSONAMEM_DATASET_FILE_CANDIDATES = [
4684
4849
  "benchmark/benchmark.csv",
4685
4850
  "benchmark.csv"
4686
4851
  ];
4687
- var PERSONAMEM_COMPLETION_MARKER = path12.join(
4852
+ var PERSONAMEM_COMPLETION_MARKER = path14.join(
4688
4853
  "data",
4689
4854
  "chat_history_32k",
4690
4855
  ".download-complete"
@@ -4692,10 +4857,10 @@ var PERSONAMEM_COMPLETION_MARKER = path12.join(
4692
4857
  function resolveRealpathWithinDataset(datasetPath, relativePath) {
4693
4858
  try {
4694
4859
  const datasetRoot = fs11.realpathSync(datasetPath);
4695
- const candidatePath = path12.resolve(datasetRoot, relativePath);
4860
+ const candidatePath = path14.resolve(datasetRoot, relativePath);
4696
4861
  const candidateRealPath = fs11.realpathSync(candidatePath);
4697
- const relativeToRoot = path12.relative(datasetRoot, candidateRealPath);
4698
- if (relativeToRoot.startsWith("..") || path12.isAbsolute(relativeToRoot)) {
4862
+ const relativeToRoot = path14.relative(datasetRoot, candidateRealPath);
4863
+ if (relativeToRoot.startsWith("..") || path14.isAbsolute(relativeToRoot)) {
4699
4864
  return null;
4700
4865
  }
4701
4866
  return candidateRealPath;
@@ -4751,7 +4916,7 @@ function parseCsvRows(raw) {
4751
4916
  }
4752
4917
  function isPersonaMemDatasetComplete(datasetPath) {
4753
4918
  try {
4754
- const completionMarkerPath = path12.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
4919
+ const completionMarkerPath = path14.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
4755
4920
  if (fs11.statSync(completionMarkerPath).isFile()) {
4756
4921
  return true;
4757
4922
  }
@@ -4759,7 +4924,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
4759
4924
  }
4760
4925
  const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
4761
4926
  try {
4762
- return fs11.statSync(path12.join(datasetPath, candidate)).isFile();
4927
+ return fs11.statSync(path14.join(datasetPath, candidate)).isFile();
4763
4928
  } catch {
4764
4929
  return false;
4765
4930
  }
@@ -4768,7 +4933,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
4768
4933
  return false;
4769
4934
  }
4770
4935
  try {
4771
- const rows = parseCsvRows(fs11.readFileSync(path12.join(datasetPath, datasetFile), "utf8"));
4936
+ const rows = parseCsvRows(fs11.readFileSync(path14.join(datasetPath, datasetFile), "utf8"));
4772
4937
  if (rows.length < 2) {
4773
4938
  return false;
4774
4939
  }
@@ -4791,14 +4956,14 @@ function isPersonaMemDatasetComplete(datasetPath) {
4791
4956
  }
4792
4957
  function hasDatasetFile(datasetPath, relativePath) {
4793
4958
  try {
4794
- return fs11.statSync(path12.join(datasetPath, relativePath)).isFile();
4959
+ return fs11.statSync(path14.join(datasetPath, relativePath)).isFile();
4795
4960
  } catch {
4796
4961
  return false;
4797
4962
  }
4798
4963
  }
4799
4964
  function hasMemoryAgentBenchEntityMapping(datasetPath) {
4800
- const absoluteDatasetPath = path12.resolve(datasetPath);
4801
- const roots = [absoluteDatasetPath, path12.dirname(absoluteDatasetPath)];
4965
+ const absoluteDatasetPath = path14.resolve(datasetPath);
4966
+ const roots = [absoluteDatasetPath, path14.dirname(absoluteDatasetPath)];
4802
4967
  return hasDatasetFile(absoluteDatasetPath, "entity2id.json") || roots.some(
4803
4968
  (root) => MEMORY_AGENT_BENCH_ENTITY_MAPPING_CANDIDATES.filter((relativePath) => relativePath !== "entity2id.json").some((relativePath) => hasDatasetFile(root, relativePath))
4804
4969
  );
@@ -4809,7 +4974,7 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
4809
4974
  ...MEMORY_AGENT_BENCH_SPLIT_FILENAMES
4810
4975
  ];
4811
4976
  return candidateFilenames.some((filename) => {
4812
- const filePath = path12.join(datasetPath, filename);
4977
+ const filePath = path14.join(datasetPath, filename);
4813
4978
  try {
4814
4979
  if (!fs11.statSync(filePath).isFile()) {
4815
4980
  return false;
@@ -4848,7 +5013,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
4848
5013
  if (marker.allOf) {
4849
5014
  const hasAllRequiredFiles = marker.allOf.every((name) => {
4850
5015
  try {
4851
- return fs11.statSync(path12.join(datasetPath, name)).isFile();
5016
+ return fs11.statSync(path14.join(datasetPath, name)).isFile();
4852
5017
  } catch {
4853
5018
  return false;
4854
5019
  }
@@ -4860,7 +5025,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
4860
5025
  if (marker.anyOf) {
4861
5026
  const hasMarkerFile = marker.anyOf.some((name) => {
4862
5027
  try {
4863
- return fs11.statSync(path12.join(datasetPath, name)).isFile();
5028
+ return fs11.statSync(path14.join(datasetPath, name)).isFile();
4864
5029
  } catch {
4865
5030
  return false;
4866
5031
  }
@@ -4888,9 +5053,9 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
4888
5053
  return false;
4889
5054
  }
4890
5055
  async function launchBenchUi(resultsDir) {
4891
- const benchUiDir = path12.join(CLI_REPO_ROOT, "packages", "bench-ui");
5056
+ const benchUiDir = path14.join(CLI_REPO_ROOT, "packages", "bench-ui");
4892
5057
  const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
4893
- if (!fs11.existsSync(path12.join(benchUiDir, "package.json"))) {
5058
+ if (!fs11.existsSync(path14.join(benchUiDir, "package.json"))) {
4894
5059
  console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
4895
5060
  process.exit(1);
4896
5061
  }
@@ -4917,24 +5082,24 @@ async function launchBenchUi(resultsDir) {
4917
5082
  });
4918
5083
  }
4919
5084
  function resolveRepoDatasetRoot() {
4920
- const repoCandidate = path12.join(CLI_REPO_ROOT, "evals", "datasets");
5085
+ const repoCandidate = path14.join(CLI_REPO_ROOT, "evals", "datasets");
4921
5086
  if (isRepoCheckout()) {
4922
5087
  return repoCandidate;
4923
5088
  }
4924
- return path12.join(resolveHomeDir(), ".remnic", "bench", "datasets");
5089
+ return path14.join(resolveHomeDir(), ".remnic", "bench", "datasets");
4925
5090
  }
4926
5091
  function listDownloadableBenchmarks() {
4927
5092
  return [...DOWNLOADABLE_BENCHMARK_DATASETS];
4928
5093
  }
4929
5094
  function resolveDatasetDownloadScriptPath() {
4930
- const bundled = path12.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
5095
+ const bundled = path14.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
4931
5096
  if (fs11.existsSync(bundled)) {
4932
5097
  return bundled;
4933
5098
  }
4934
- return path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
5099
+ return path14.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
4935
5100
  }
4936
5101
  function isRepoCheckout() {
4937
- return fs11.existsSync(path12.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs11.existsSync(path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
5102
+ return fs11.existsSync(path14.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs11.existsSync(path14.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
4938
5103
  }
4939
5104
  function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
4940
5105
  const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
@@ -4985,7 +5150,7 @@ function resolveBenchDatasetDir(benchmarkId, quick, datasetDirOverride) {
4985
5150
  if (quick) {
4986
5151
  return void 0;
4987
5152
  }
4988
- const datasetDir = path12.join(resolveRepoDatasetRoot(), benchmarkId);
5153
+ const datasetDir = path14.join(resolveRepoDatasetRoot(), benchmarkId);
4989
5154
  if (isDatasetDownloaded(datasetDir, benchmarkId)) {
4990
5155
  return datasetDir;
4991
5156
  }
@@ -5242,12 +5407,12 @@ async function exportBenchPackageResult(parsed) {
5242
5407
  process.exit(1);
5243
5408
  }
5244
5409
  const result = await loadBenchmarkResult(summary.path);
5245
- const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(path12.dirname(summary.path), result.meta.id) : void 0;
5410
+ const reportCardProvenance = parsed.format === "html" ? await loadBenchmarkReportCardProvenance(path14.dirname(summary.path), result.meta.id) : void 0;
5246
5411
  const rendered = renderBenchmarkResultExport(result, parsed.format, {
5247
5412
  ...reportCardProvenance ? { reportCardProvenance } : {}
5248
5413
  });
5249
5414
  if (parsed.output) {
5250
- fs11.mkdirSync(path12.dirname(parsed.output), { recursive: true });
5415
+ fs11.mkdirSync(path14.dirname(parsed.output), { recursive: true });
5251
5416
  fs11.writeFileSync(parsed.output, rendered);
5252
5417
  console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
5253
5418
  return;
@@ -5265,7 +5430,7 @@ async function manageBenchDatasets(parsed) {
5265
5430
  process.exit(1);
5266
5431
  }
5267
5432
  const status = supported.map((benchmarkId) => {
5268
- const datasetPath = path12.join(datasetRoot, benchmarkId);
5433
+ const datasetPath = path14.join(datasetRoot, benchmarkId);
5269
5434
  return {
5270
5435
  benchmark: benchmarkId,
5271
5436
  downloaded: isDatasetDownloaded(datasetPath, benchmarkId),
@@ -5303,7 +5468,7 @@ async function manageBenchDatasets(parsed) {
5303
5468
  runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, parsed.json === true);
5304
5469
  downloaded.push({
5305
5470
  benchmark: benchmarkId,
5306
- path: path12.join(datasetRoot, benchmarkId)
5471
+ path: path14.join(datasetRoot, benchmarkId)
5307
5472
  });
5308
5473
  }
5309
5474
  if (parsed.json) {
@@ -5442,10 +5607,10 @@ async function calibrateBenchJudges(parsed, rawArgs) {
5442
5607
  }
5443
5608
  const bench = await loadBenchModule();
5444
5609
  const resultsDir = expandTilde(
5445
- parsed.resultsDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "results")
5610
+ parsed.resultsDir ?? path14.join(resolveHomeDir(), ".remnic", "bench", "results")
5446
5611
  );
5447
5612
  const calibrationDir = expandTilde(
5448
- parsed.calibrationDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "calibration")
5613
+ parsed.calibrationDir ?? path14.join(resolveHomeDir(), ".remnic", "bench", "calibration")
5449
5614
  );
5450
5615
  const stored = await bench.listBenchmarkResults(resultsDir);
5451
5616
  const allForBenchmark = stored.filter((entry) => entry.benchmark === benchmarkId);
@@ -6005,7 +6170,7 @@ async function loadPublishedPromotionHelpers() {
6005
6170
  return {
6006
6171
  async promoteArtifactsToPublished(args) {
6007
6172
  const { mkdirSync, readFileSync: readFileSync4, writeFileSync } = await import("fs");
6008
- const path13 = await import("path");
6173
+ const path15 = await import("path");
6009
6174
  mkdirSync(args.publishedOutDir, { recursive: true });
6010
6175
  if (args.artifactPaths.length === 0) {
6011
6176
  console.warn(
@@ -6022,13 +6187,13 @@ async function loadPublishedPromotionHelpers() {
6022
6187
  const modelSlug = args.model.replace(/[^a-zA-Z0-9_.-]/g, "-");
6023
6188
  const rawProfile = parsedObj.config?.runtimeProfile;
6024
6189
  const profileSlug = typeof rawProfile === "string" && rawProfile.length > 0 ? `-${rawProfile.replace(/[^a-zA-Z0-9_.-]/g, "-")}` : "";
6025
- const target = path13.join(
6190
+ const target = path15.join(
6026
6191
  args.publishedOutDir,
6027
6192
  `${today}-${args.benchmarkId}-${modelSlug}${profileSlug}-${gitShaShort}.json`
6028
6193
  );
6029
6194
  writeFileSync(target, raw, "utf8");
6030
6195
  console.log(
6031
- `[bench published] Promoted ${path13.basename(artifactPath)} \u2192 ${target}`
6196
+ `[bench published] Promoted ${path15.basename(artifactPath)} \u2192 ${target}`
6032
6197
  );
6033
6198
  }
6034
6199
  void benchModule;
@@ -6135,7 +6300,7 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
6135
6300
  const previousCodexDiagnosticsDir = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV];
6136
6301
  const previousCodexDiagnosticsMode = process.env[CODEX_CLI_BENCH_DIAGNOSTICS_MODE_ENV];
6137
6302
  if (!previousCodexDiagnosticsDir) {
6138
- process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] = path12.join(
6303
+ process.env[CODEX_CLI_BENCH_DIAGNOSTICS_DIR_ENV] = path14.join(
6139
6304
  outputDir,
6140
6305
  "codex-cli-diagnostics"
6141
6306
  );
@@ -6283,7 +6448,7 @@ async function preparePersistedJudgeCalibrationAttachment(benchModule, benchmark
6283
6448
  );
6284
6449
  }
6285
6450
  const calibrationDir = expandTilde(
6286
- calibrationBinding.calibrationDir ?? path12.join(resolveHomeDir(), ".remnic", "bench", "calibration")
6451
+ calibrationBinding.calibrationDir ?? path14.join(resolveHomeDir(), ".remnic", "bench", "calibration")
6287
6452
  );
6288
6453
  const state = await benchModule.loadJudgeCalibrationState?.(benchmarkId, calibrationDir);
6289
6454
  if (!state) {
@@ -6633,19 +6798,19 @@ async function writeBenchReproManifestForPackageRun(args) {
6633
6798
  }
6634
6799
  }
6635
6800
  function resolveConfigPath(cliPath) {
6636
- if (cliPath) return path12.resolve(expandTilde(cliPath));
6801
+ if (cliPath) return path14.resolve(expandTilde(cliPath));
6637
6802
  const envPath = readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH");
6638
- if (envPath) return path12.resolve(expandTilde(envPath));
6803
+ if (envPath) return path14.resolve(expandTilde(envPath));
6639
6804
  const candidates = [
6640
- path12.join(process.cwd(), "remnic.config.json"),
6641
- path12.join(process.cwd(), "engram.config.json"),
6642
- path12.join(resolveHomeDir(), ".config", "remnic", "config.json"),
6643
- path12.join(resolveHomeDir(), ".config", "engram", "config.json")
6805
+ path14.join(process.cwd(), "remnic.config.json"),
6806
+ path14.join(process.cwd(), "engram.config.json"),
6807
+ path14.join(resolveHomeDir(), ".config", "remnic", "config.json"),
6808
+ path14.join(resolveHomeDir(), ".config", "engram", "config.json")
6644
6809
  ];
6645
6810
  for (const candidate of candidates) {
6646
6811
  if (fs11.existsSync(candidate)) return candidate;
6647
6812
  }
6648
- return path12.join(resolveHomeDir(), ".config", "remnic", "config.json");
6813
+ return path14.join(resolveHomeDir(), ".config", "remnic", "config.json");
6649
6814
  }
6650
6815
  function resolveExistingBenchRemnicConfigPath(cliPath) {
6651
6816
  const configPath = resolveConfigPath(cliPath);
@@ -6759,7 +6924,7 @@ async function resolvePackageBenchRuntime(benchModule, parsed, runtimeProfile) {
6759
6924
  );
6760
6925
  }
6761
6926
  function normalizeMemoryDirPath(memoryDir) {
6762
- return path12.resolve(expandTilde(memoryDir));
6927
+ return path14.resolve(expandTilde(memoryDir));
6763
6928
  }
6764
6929
  function resolveMemoryDir() {
6765
6930
  const configMemoryDir = (() => {
@@ -6772,9 +6937,9 @@ function resolveMemoryDir() {
6772
6937
  return normalizeMemoryDirPath(remnicCfg.memoryDir);
6773
6938
  }
6774
6939
  const home = resolveHomeDir();
6775
- const standalonePath = path12.join(home, ".remnic", "memory");
6776
- const legacyStandalonePath = path12.join(home, ".engram", "memory");
6777
- const openclawPath = path12.join(home, ".openclaw", "workspace", "memory", "local");
6940
+ const standalonePath = path14.join(home, ".remnic", "memory");
6941
+ const legacyStandalonePath = path14.join(home, ".engram", "memory");
6942
+ const openclawPath = path14.join(home, ".openclaw", "workspace", "memory", "local");
6778
6943
  if (fs11.existsSync(standalonePath)) return standalonePath;
6779
6944
  if (fs11.existsSync(legacyStandalonePath)) return legacyStandalonePath;
6780
6945
  return openclawPath;
@@ -6825,16 +6990,16 @@ var REMNIC_OPENCLAW_LEGACY_PLUGIN_ID = "openclaw-engram";
6825
6990
  var DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR = [
6826
6991
  process.env.OPENCLAW_CONFIG_PATH,
6827
6992
  process.env.OPENCLAW_ENGRAM_CONFIG_PATH,
6828
- path12.join(resolveHomeDir(), ".openclaw", "openclaw.json")
6993
+ path14.join(resolveHomeDir(), ".openclaw", "openclaw.json")
6829
6994
  ].filter(Boolean);
6830
6995
  function resolveOpenclawConfigPath(cliPath) {
6831
- if (cliPath) return path12.resolve(expandTilde(cliPath));
6996
+ if (cliPath) return path14.resolve(expandTilde(cliPath));
6832
6997
  const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
6833
- if (envPath) return path12.resolve(expandTilde(envPath));
6998
+ if (envPath) return path14.resolve(expandTilde(envPath));
6834
6999
  for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
6835
7000
  if (fs11.existsSync(candidate)) return candidate;
6836
7001
  }
6837
- return path12.join(resolveHomeDir(), ".openclaw", "openclaw.json");
7002
+ return path14.join(resolveHomeDir(), ".openclaw", "openclaw.json");
6838
7003
  }
6839
7004
  function readOpenclawConfig(configPath) {
6840
7005
  if (!fs11.existsSync(configPath)) return {};
@@ -6893,10 +7058,10 @@ function buildRemnicOpenclawHooksPolicy(legacyHooks, existingHooks) {
6893
7058
  function resolveOpenclawInstallMemoryDir(args) {
6894
7059
  const existingMemoryDir = (typeof args.existingNewEntryConfig.memoryDir === "string" ? args.existingNewEntryConfig.memoryDir : void 0) || (args.migrateLegacy && typeof args.legacyConfigToMerge.memoryDir === "string" ? args.legacyConfigToMerge.memoryDir : void 0);
6895
7060
  if (args.requestedMemoryDir) {
6896
- return path12.resolve(expandTilde(args.requestedMemoryDir));
7061
+ return path14.resolve(expandTilde(args.requestedMemoryDir));
6897
7062
  }
6898
7063
  if (existingMemoryDir) {
6899
- return path12.resolve(expandTilde(existingMemoryDir));
7064
+ return path14.resolve(expandTilde(existingMemoryDir));
6900
7065
  }
6901
7066
  return args.fallbackMemoryDir;
6902
7067
  }
@@ -6914,18 +7079,18 @@ function resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir) {
6914
7079
  if (!config || typeof config !== "object" || Array.isArray(config)) continue;
6915
7080
  const memoryDir = config.memoryDir;
6916
7081
  if (typeof memoryDir === "string" && memoryDir.trim().length > 0) {
6917
- return path12.resolve(expandTilde(memoryDir));
7082
+ return path14.resolve(expandTilde(memoryDir));
6918
7083
  }
6919
7084
  }
6920
7085
  return fallbackMemoryDir;
6921
7086
  }
6922
7087
  function resolveOpenclawPluginDir(cliPath) {
6923
- if (cliPath) return path12.resolve(expandTilde(cliPath));
6924
- return path12.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
7088
+ if (cliPath) return path14.resolve(expandTilde(cliPath));
7089
+ return path14.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
6925
7090
  }
6926
7091
  function resolveOpenclawLegacyPluginDir(cliPath) {
6927
- if (cliPath) return path12.resolve(expandTilde(cliPath));
6928
- return path12.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID);
7092
+ if (cliPath) return path14.resolve(expandTilde(cliPath));
7093
+ return path14.join(resolveHomeDir(), ".openclaw", "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID);
6929
7094
  }
6930
7095
  function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
6931
7096
  const yyyy = now.getFullYear().toString();
@@ -6938,7 +7103,7 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
6938
7103
  }
6939
7104
  function backupPathIfPresent(sourcePath, backupPath) {
6940
7105
  if (!fs11.existsSync(sourcePath)) return false;
6941
- fs11.mkdirSync(path12.dirname(backupPath), { recursive: true });
7106
+ fs11.mkdirSync(path14.dirname(backupPath), { recursive: true });
6942
7107
  fs11.cpSync(sourcePath, backupPath, { recursive: true });
6943
7108
  return true;
6944
7109
  }
@@ -6969,7 +7134,7 @@ var PublishedOpenclawPluginInstallError = class extends Error {
6969
7134
  }
6970
7135
  };
6971
7136
  function installPublishedOpenclawPlugin(spec, pluginDir) {
6972
- const tempRoot = fs11.mkdtempSync(path12.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
7137
+ const tempRoot = fs11.mkdtempSync(path14.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
6973
7138
  const stagedDir = `${pluginDir}.next-${process.pid}-${Date.now()}`;
6974
7139
  const rollbackDir = `${pluginDir}.rollback-${process.pid}-${Date.now()}`;
6975
7140
  let swapRollbackDir;
@@ -6984,12 +7149,12 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
6984
7149
  if (!tarballName) {
6985
7150
  throw new Error(`npm pack ${spec} did not return a tarball name`);
6986
7151
  }
6987
- const unpackDir = path12.join(tempRoot, "unpacked");
7152
+ const unpackDir = path14.join(tempRoot, "unpacked");
6988
7153
  fs11.mkdirSync(unpackDir, { recursive: true });
6989
- childProcess2.execFileSync("tar", ["-xzf", path12.join(tempRoot, tarballName), "-C", unpackDir], {
7154
+ childProcess2.execFileSync("tar", ["-xzf", path14.join(tempRoot, tarballName), "-C", unpackDir], {
6990
7155
  stdio: ["ignore", "pipe", "pipe"]
6991
7156
  });
6992
- const packagedDir = path12.join(unpackDir, "package");
7157
+ const packagedDir = path14.join(unpackDir, "package");
6993
7158
  if (!fs11.existsSync(packagedDir)) {
6994
7159
  throw new Error(`npm pack ${spec} did not contain a package/ directory`);
6995
7160
  }
@@ -7009,7 +7174,7 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
7009
7174
  }
7010
7175
  })();
7011
7176
  swapRollbackDir = swapResult.rollbackDir;
7012
- const installedPackageJsonPath = path12.join(pluginDir, "package.json");
7177
+ const installedPackageJsonPath = path14.join(pluginDir, "package.json");
7013
7178
  const installedPackage = fs11.existsSync(installedPackageJsonPath) ? JSON.parse(fs11.readFileSync(installedPackageJsonPath, "utf8")) : {};
7014
7179
  return {
7015
7180
  rollbackDir: swapRollbackDir,
@@ -7044,7 +7209,7 @@ function restartOpenclawGateway() {
7044
7209
  });
7045
7210
  }
7046
7211
  function cmdInit() {
7047
- const configPath = path12.join(process.cwd(), "remnic.config.json");
7212
+ const configPath = path14.join(process.cwd(), "remnic.config.json");
7048
7213
  if (fs11.existsSync(configPath)) {
7049
7214
  console.log(`Config already exists: ${configPath}`);
7050
7215
  return;
@@ -7052,7 +7217,7 @@ function cmdInit() {
7052
7217
  const template = {
7053
7218
  remnic: {
7054
7219
  openaiApiKey: "${OPENAI_API_KEY}",
7055
- memoryDir: path12.join(process.cwd(), ".remnic", "memory"),
7220
+ memoryDir: path14.join(process.cwd(), ".remnic", "memory"),
7056
7221
  memoryOsPreset: "balanced"
7057
7222
  },
7058
7223
  server: {
@@ -7189,7 +7354,7 @@ function oauthResolveOperatorToken() {
7189
7354
  }
7190
7355
  return void 0;
7191
7356
  }
7192
- async function oauthFetch(method, path13, token, body) {
7357
+ async function oauthFetch(method, path15, token, body) {
7193
7358
  const controller = new AbortController();
7194
7359
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
7195
7360
  try {
@@ -7208,7 +7373,7 @@ async function oauthFetch(method, path13, token, body) {
7208
7373
  if (body !== void 0) {
7209
7374
  init.body = JSON.stringify(body);
7210
7375
  }
7211
- const response = await fetch(`${oauthResolveBaseUrl()}${path13}`, init);
7376
+ const response = await fetch(`${oauthResolveBaseUrl()}${path15}`, init);
7212
7377
  if (response.status === 401) {
7213
7378
  throw new Error(
7214
7379
  "operator token rejected by remnic-server (HTTP 401). Update `server.authToken` or `REMNIC_AUTH_TOKEN` to match the running daemon."
@@ -7763,7 +7928,7 @@ async function cmdVersions(rest) {
7763
7928
  console.error("Usage: remnic versions list <page-path>");
7764
7929
  process.exit(1);
7765
7930
  }
7766
- const absPath = path12.resolve(pagePath);
7931
+ const absPath = path14.resolve(pagePath);
7767
7932
  const history = await listVersions(absPath, versioningConfig, memDir);
7768
7933
  if (json) {
7769
7934
  console.log(JSON.stringify(history, null, 2));
@@ -7788,7 +7953,7 @@ async function cmdVersions(rest) {
7788
7953
  console.error("Usage: remnic versions show <page-path> <version-id>");
7789
7954
  process.exit(1);
7790
7955
  }
7791
- const absPath = path12.resolve(pagePath);
7956
+ const absPath = path14.resolve(pagePath);
7792
7957
  try {
7793
7958
  const content = await getVersion(absPath, versionId, versioningConfig, memDir);
7794
7959
  console.log(content);
@@ -7806,7 +7971,7 @@ async function cmdVersions(rest) {
7806
7971
  console.error("Usage: remnic versions diff <page-path> <v1> <v2>");
7807
7972
  process.exit(1);
7808
7973
  }
7809
- const absPath = path12.resolve(pagePath);
7974
+ const absPath = path14.resolve(pagePath);
7810
7975
  try {
7811
7976
  const diffOutput = await diffVersions(absPath, v1, v2, versioningConfig, memDir);
7812
7977
  console.log(diffOutput);
@@ -7823,7 +7988,7 @@ async function cmdVersions(rest) {
7823
7988
  console.error("Usage: remnic versions revert <page-path> <version-id>");
7824
7989
  process.exit(1);
7825
7990
  }
7826
- const absPath = path12.resolve(pagePath);
7991
+ const absPath = path14.resolve(pagePath);
7827
7992
  try {
7828
7993
  const version = await revertToVersion(absPath, versionId, versioningConfig, void 0, memDir);
7829
7994
  if (json) {
@@ -7863,7 +8028,7 @@ async function cmdEnrich(rest) {
7863
8028
  const subcommand = rest[0];
7864
8029
  if (subcommand === "audit") {
7865
8030
  const memoryDir2 = expandTilde(config.memoryDir);
7866
- const auditDir2 = path12.join(memoryDir2, "enrichment");
8031
+ const auditDir2 = path14.join(memoryDir2, "enrichment");
7867
8032
  const sinceFlag = resolveFlag(rest.slice(1), "--since");
7868
8033
  const entries = await readAuditLog(auditDir2, sinceFlag ?? void 0);
7869
8034
  if (entries.length === 0) {
@@ -7988,7 +8153,7 @@ Registered providers:`);
7988
8153
  return;
7989
8154
  }
7990
8155
  const memoryDir = expandTilde(config.memoryDir);
7991
- const auditDir = path12.join(memoryDir, "enrichment");
8156
+ const auditDir = path14.join(memoryDir, "enrichment");
7992
8157
  let totalPersisted = 0;
7993
8158
  for (const result of results) {
7994
8159
  for (const candidate of result.acceptedCandidates) {
@@ -8179,7 +8344,7 @@ Root: ${root}`);
8179
8344
  const validNames = new Set(extensions.map((e) => e.name));
8180
8345
  let errors = 0;
8181
8346
  for (const entry of entries) {
8182
- const entryPath = path12.join(root, entry);
8347
+ const entryPath = path14.join(root, entry);
8183
8348
  try {
8184
8349
  if (!fs11.statSync(entryPath).isDirectory()) continue;
8185
8350
  } catch {
@@ -8295,7 +8460,7 @@ async function cmdBriefing(rest) {
8295
8460
  const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
8296
8461
  fs11.mkdirSync(saveDir, { recursive: true });
8297
8462
  const filename = briefingFilename(new Date(result.window.to), format);
8298
- const filePath = path12.join(saveDir, filename);
8463
+ const filePath = path14.join(saveDir, filename);
8299
8464
  fs11.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
8300
8465
  console.error(`Saved briefing: ${filePath}`);
8301
8466
  } catch (err) {
@@ -8451,7 +8616,7 @@ async function cmdDoctor() {
8451
8616
  const rawMemoryDir = entryConfig?.memoryDir;
8452
8617
  const configuredMemoryDir = typeof rawMemoryDir === "string" ? rawMemoryDir : void 0;
8453
8618
  if (configuredMemoryDir) {
8454
- const resolvedMemDir = path12.resolve(expandTilde(configuredMemoryDir));
8619
+ const resolvedMemDir = path14.resolve(expandTilde(configuredMemoryDir));
8455
8620
  let memDirOk = false;
8456
8621
  let memDirDetail = `${resolvedMemDir} (not found)`;
8457
8622
  let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
@@ -8651,7 +8816,7 @@ async function cmdMigrate(json, rollback) {
8651
8816
  console.log(` Rollback: ${result.rollbackCommand}`);
8652
8817
  }
8653
8818
  function cmdOnboard(dirPath, json) {
8654
- const directory = path12.resolve(dirPath || process.cwd());
8819
+ const directory = path14.resolve(dirPath || process.cwd());
8655
8820
  const result = onboard({ directory });
8656
8821
  if (json) {
8657
8822
  console.log(JSON.stringify(result, null, 2));
@@ -8670,7 +8835,7 @@ Suggested namespace: ${result.plan.suggestedNamespace}`);
8670
8835
  async function cmdCurate(targetPath, json) {
8671
8836
  const memoryDir = resolveMemoryDir();
8672
8837
  const result = await curate({
8673
- targetPath: path12.resolve(targetPath),
8838
+ targetPath: path14.resolve(targetPath),
8674
8839
  memoryDir,
8675
8840
  source: "curation",
8676
8841
  checkDuplicates: true,
@@ -8800,7 +8965,7 @@ async function cmdSync(action, rest, json) {
8800
8965
  }
8801
8966
  function localOfflineSourceId(memoryDir) {
8802
8967
  const host = os.hostname() || "unknown-host";
8803
- const dirHash = createHash2("sha256").update(path12.resolve(memoryDir)).digest("hex").slice(0, 16);
8968
+ const dirHash = createHash2("sha256").update(path14.resolve(memoryDir)).digest("hex").slice(0, 16);
8804
8969
  return `remnic-local:${host}:${dirHash}`;
8805
8970
  }
8806
8971
  function normalizeOfflineRemoteUrl(raw) {
@@ -9198,10 +9363,10 @@ var OFFLINE_SYNC_CONTENT_MISSING_RETRY_MAX = 3;
9198
9363
  var OFFLINE_SYNC_CONTENT_MISSING_RETRY_DELAY_MS = 250;
9199
9364
  var OfflineRemoteFileChangedError = class extends Error {
9200
9365
  path;
9201
- constructor(path13) {
9202
- super(`remote file changed while fetching offline content: ${path13}`);
9366
+ constructor(path15) {
9367
+ super(`remote file changed while fetching offline content: ${path15}`);
9203
9368
  this.name = "OfflineRemoteFileChangedError";
9204
- this.path = path13;
9369
+ this.path = path15;
9205
9370
  }
9206
9371
  };
9207
9372
  function isOfflineRemoteFileChangedError(error) {
@@ -9392,10 +9557,10 @@ function offlineDirectPushFiles(options) {
9392
9557
  }).sort((left, right) => right.bytes - left.bytes || left.path.localeCompare(right.path));
9393
9558
  }
9394
9559
  function resolveOfflineDirectHydrationPath(memoryDir, relPath) {
9395
- const base = path12.resolve(memoryDir);
9396
- const target = path12.resolve(base, relPath);
9397
- const relative = path12.relative(base, target);
9398
- if (relative === "" || relative === ".." || relative.startsWith(`..${path12.sep}`) || path12.isAbsolute(relative)) {
9560
+ const base = path14.resolve(memoryDir);
9561
+ const target = path14.resolve(base, relPath);
9562
+ const relative = path14.relative(base, target);
9563
+ if (relative === "" || relative === ".." || relative.startsWith(`..${path14.sep}`) || path14.isAbsolute(relative)) {
9399
9564
  throw new Error(`offline sync direct hydration path escapes memory dir: ${relPath}`);
9400
9565
  }
9401
9566
  return target;
@@ -9471,7 +9636,7 @@ async function pushOfflineFileContentFromChunkReader(args) {
9471
9636
  }
9472
9637
  const hash = createHash2("sha256");
9473
9638
  const chunks = args.readFileChunks({
9474
- root: path12.resolve(args.memoryDir),
9639
+ root: path14.resolve(args.memoryDir),
9475
9640
  path: args.file.path,
9476
9641
  filePath,
9477
9642
  chunkSize: OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES
@@ -10574,7 +10739,7 @@ Environment fallbacks:
10574
10739
  REMNIC_OFFLINE_REMOTE_URL, REMNIC_OFFLINE_TOKEN, REMNIC_AUTH_TOKEN`);
10575
10740
  return;
10576
10741
  }
10577
- const memoryDir = path12.resolve(expandTilde(resolveRequiredValueFlag(rest, "--memory-dir") ?? resolveMemoryDir()));
10742
+ const memoryDir = path14.resolve(expandTilde(resolveRequiredValueFlag(rest, "--memory-dir") ?? resolveMemoryDir()));
10578
10743
  const namespace = resolveRequiredValueFlag(rest, "--namespace");
10579
10744
  const includeTranscripts = !hasFlag(rest, "--no-transcripts");
10580
10745
  const stateOverride = resolveRequiredValueFlag(rest, "--state");
@@ -10594,7 +10759,7 @@ Environment fallbacks:
10594
10759
  const needsRemote = action === "prepare" || action === "sync" || action === "watch";
10595
10760
  const remoteUrl = needsRemote ? resolveOfflineRemoteUrl(rest) : resolveOptionalOfflineRemoteUrl(rest);
10596
10761
  const token = needsRemote ? resolveOfflineToken(rest) : void 0;
10597
- const statePath = statePathExplicit ? path12.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
10762
+ const statePath = statePathExplicit ? path14.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
10598
10763
  if (action === "prepare") {
10599
10764
  if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
10600
10765
  fs11.mkdirSync(memoryDir, { recursive: true });
@@ -10775,11 +10940,11 @@ Environment fallbacks:
10775
10940
  failures: result.largeFilePushFailures
10776
10941
  });
10777
10942
  largeFileFailureCounts = advanced.counts;
10778
- for (const path13 of advanced.newlySkipped) {
10779
- if (skippedLargeFiles.has(path13)) continue;
10780
- skippedLargeFiles.add(path13);
10943
+ for (const path15 of advanced.newlySkipped) {
10944
+ if (skippedLargeFiles.has(path15)) continue;
10945
+ skippedLargeFiles.add(path15);
10781
10946
  console.warn(
10782
- `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)`
10947
+ `offline sync: permanently skipping ${path15} after ${OFFLINE_LARGE_FILE_SKIP_AFTER_FAILURES} failed large-file pushes for this watcher process (see issue #1786; use --exclude or offlineSyncExcludes to silence permanently)`
10783
10948
  );
10784
10949
  }
10785
10950
  const pulled = result.pull ? result.pull.upserted + result.pull.deleted : 0;
@@ -10794,11 +10959,11 @@ Environment fallbacks:
10794
10959
  failures: error.failures
10795
10960
  });
10796
10961
  largeFileFailureCounts = advanced.counts;
10797
- for (const path13 of advanced.newlySkipped) {
10798
- if (skippedLargeFiles.has(path13)) continue;
10799
- skippedLargeFiles.add(path13);
10962
+ for (const path15 of advanced.newlySkipped) {
10963
+ if (skippedLargeFiles.has(path15)) continue;
10964
+ skippedLargeFiles.add(path15);
10800
10965
  console.warn(
10801
- `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)`
10966
+ `offline sync: permanently skipping ${path15} after ${OFFLINE_LARGE_FILE_SKIP_AFTER_FAILURES} failed large-file pushes for this watcher process (see issue #1786; use --exclude or offlineSyncExcludes to silence permanently)`
10802
10967
  );
10803
10968
  }
10804
10969
  }
@@ -10939,7 +11104,7 @@ async function cmdConnectors(action, rest, json) {
10939
11104
  const connectorDaemonUrl = typeof effectiveConnectorConfig.remnicDaemonUrl === "string" && effectiveConnectorConfig.remnicDaemonUrl.trim().length > 0 ? effectiveConnectorConfig.remnicDaemonUrl.trim() : void 0;
10940
11105
  const pubResult = await pub.publish({
10941
11106
  config: { memoryDir, namespace: connectorNamespace, daemonUrl: connectorDaemonUrl },
10942
- skillsRoot: path12.join(memoryDir, "skills"),
11107
+ skillsRoot: path14.join(memoryDir, "skills"),
10943
11108
  rollbackTokenEntry: preInstallTokenEntry,
10944
11109
  log: { info: console.log, warn: console.warn, error: console.error }
10945
11110
  });
@@ -11299,15 +11464,15 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
11299
11464
  }
11300
11465
  const manifest = generateMarketplaceManifest();
11301
11466
  await writeMarketplaceManifest(outputDir, manifest);
11302
- const outPath = path12.join(outputDir, "marketplace.json");
11467
+ const outPath = path14.join(outputDir, "marketplace.json");
11303
11468
  if (json) {
11304
11469
  console.log(JSON.stringify({ status: "generated", path: outPath }, null, 2));
11305
11470
  } else {
11306
11471
  console.log(`Generated marketplace.json at ${outPath}`);
11307
11472
  }
11308
11473
  } else if (subAction === "validate") {
11309
- const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path12.join(process.cwd(), "marketplace.json");
11310
- const resolved = path12.resolve(targetPath);
11474
+ const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path14.join(process.cwd(), "marketplace.json");
11475
+ const resolved = path14.resolve(targetPath);
11311
11476
  if (!fs11.existsSync(resolved)) {
11312
11477
  console.error(`File not found: ${resolved}`);
11313
11478
  process.exit(1);
@@ -11613,6 +11778,10 @@ async function cmdBench(rest) {
11613
11778
  await compareBenchPackageResults(parsed);
11614
11779
  return;
11615
11780
  }
11781
+ if (parsed.action === "attribute" || parsed.action === "drift-gen") {
11782
+ await runBenchResearchCommand(parsed);
11783
+ return;
11784
+ }
11616
11785
  if (parsed.action === "results") {
11617
11786
  await showBenchPackageResults(parsed);
11618
11787
  return;
@@ -11711,7 +11880,7 @@ async function cmdBench(rest) {
11711
11880
  }
11712
11881
  const completeCount = prevStatus.benchmarks.filter((b) => b.status === "complete").length;
11713
11882
  const failedCount = prevStatus.benchmarks.filter((b) => b.status === "failed").length;
11714
- printBenchStatusLine(parsed.json, `Resuming from: ${path12.basename(latestStatusPath)}`);
11883
+ printBenchStatusLine(parsed.json, `Resuming from: ${path14.basename(latestStatusPath)}`);
11715
11884
  printBenchStatusLine(parsed.json, ` Previous run: ${prevStatus.startedAt}`);
11716
11885
  printBenchStatusLine(parsed.json, ` Benchmarks: ${prevStatus.benchmarks.length} total, ${completeCount} complete, ${failedCount} failed`);
11717
11886
  const before = selectedBenchmarks.length;
@@ -11879,9 +12048,9 @@ Options:
11879
12048
  );
11880
12049
  process.exit(1);
11881
12050
  } else {
11882
- fixturePath = path12.resolve(expandTilde(fixturePathRaw));
12051
+ fixturePath = path14.resolve(expandTilde(fixturePathRaw));
11883
12052
  }
11884
- const outPath = path12.resolve(expandTilde(outPathRaw));
12053
+ const outPath = path14.resolve(expandTilde(outPathRaw));
11885
12054
  const benchModule = await loadBenchModule();
11886
12055
  const runner = benchModule.runProceduralAblationCli;
11887
12056
  if (typeof runner !== "function") {
@@ -11900,7 +12069,7 @@ Options:
11900
12069
  );
11901
12070
  console.log(`wrote ${outPath}`);
11902
12071
  }
11903
- var LOGS_DIR = path12.join(PID_DIR, "logs");
12072
+ var LOGS_DIR = path14.join(PID_DIR, "logs");
11904
12073
  var LAUNCHD_PLIST_PATHS = launchdPlistPaths(resolveHomeDir());
11905
12074
  var [LAUNCHD_PLIST_PATH] = LAUNCHD_PLIST_PATHS;
11906
12075
  var SYSTEMD_UNIT_PATHS = systemdUnitPaths(resolveHomeDir());
@@ -11977,7 +12146,7 @@ function selectLaunchdInspection(openclawPluginModeConfigured) {
11977
12146
  for (const plistPath of LAUNCHD_PLIST_PATHS.slice(1)) {
11978
12147
  const legacy = inspectLaunchdPlist(plistPath);
11979
12148
  if (!legacy.installed) continue;
11980
- const label = path12.basename(plistPath, ".plist");
12149
+ const label = path14.basename(plistPath, ".plist");
11981
12150
  return legacy.ok ? {
11982
12151
  ...legacy,
11983
12152
  warn: true,
@@ -12011,10 +12180,10 @@ function daemonInstall() {
12011
12180
  const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
12012
12181
  fs11.mkdirSync(LOGS_DIR, { recursive: true });
12013
12182
  if (isMacOS()) {
12014
- const templatePath = path12.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
12183
+ const templatePath = path14.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
12015
12184
  const template = fs11.readFileSync(templatePath, "utf8");
12016
12185
  const plist = renderTemplate(template, vars);
12017
- fs11.mkdirSync(path12.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
12186
+ fs11.mkdirSync(path14.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
12018
12187
  fs11.writeFileSync(LAUNCHD_PLIST_PATH, plist);
12019
12188
  try {
12020
12189
  launchdLoadPlist(LAUNCHD_PLIST_PATH);
@@ -12031,10 +12200,10 @@ function daemonInstall() {
12031
12200
  console.log(` RunAtLoad: true, KeepAlive: true`);
12032
12201
  console.log(` Logs: ${LOGS_DIR}/daemon.log`);
12033
12202
  } else if (isLinux()) {
12034
- const templatePath = path12.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
12203
+ const templatePath = path14.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
12035
12204
  const template = fs11.readFileSync(templatePath, "utf8");
12036
12205
  const unit = renderTemplate(template, vars);
12037
- fs11.mkdirSync(path12.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
12206
+ fs11.mkdirSync(path14.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
12038
12207
  fs11.writeFileSync(SYSTEMD_UNIT_PATH, unit);
12039
12208
  try {
12040
12209
  childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
@@ -12513,7 +12682,7 @@ Clean complete: cleaned=${result.cleaned}`
12513
12682
  }
12514
12683
  async function cmdOpenclawInstall(opts) {
12515
12684
  const configPath = resolveOpenclawConfigPath(opts.configPath);
12516
- const fallbackMemoryDir = path12.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
12685
+ const fallbackMemoryDir = path14.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
12517
12686
  console.log(`OpenClaw config: ${configPath}`);
12518
12687
  const existingConfig = readOpenclawConfig(configPath);
12519
12688
  const { plugins, entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
@@ -12616,7 +12785,7 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
12616
12785
  fs11.mkdirSync(memoryDir, { recursive: true });
12617
12786
  console.log(`Created memory directory: ${memoryDir}`);
12618
12787
  }
12619
- const configDir = path12.dirname(configPath);
12788
+ const configDir = path14.dirname(configPath);
12620
12789
  if (!fs11.existsSync(configDir)) {
12621
12790
  fs11.mkdirSync(configDir, { recursive: true });
12622
12791
  }
@@ -12644,11 +12813,11 @@ async function cmdOpenclawUpgrade(opts) {
12644
12813
  const configPath = resolveOpenclawConfigPath(opts.configPath);
12645
12814
  const pluginDir = resolveOpenclawPluginDir(opts.pluginDir);
12646
12815
  const legacyPluginDirForBackup = opts.legacyPluginDirForBackup ? resolveOpenclawLegacyPluginDir(opts.legacyPluginDirForBackup) : void 0;
12647
- const fallbackMemoryDir = path12.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
12816
+ const fallbackMemoryDir = path14.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
12648
12817
  const packageSpec = `@remnic/plugin-openclaw@${opts.version ?? "latest"}`;
12649
12818
  const existingConfig = readOpenclawConfig(configPath);
12650
12819
  const { entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
12651
- const preservedMemoryDir = opts.memoryDir ? path12.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
12820
+ const preservedMemoryDir = opts.memoryDir ? path14.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
12652
12821
  assertDirectoryPathOrMissing(pluginDir, "OpenClaw plugin dir");
12653
12822
  if (legacyPluginDirForBackup) {
12654
12823
  assertDirectoryPathOrMissing(legacyPluginDirForBackup, "Legacy OpenClaw plugin dir");
@@ -12660,7 +12829,7 @@ async function cmdOpenclawUpgrade(opts) {
12660
12829
  }
12661
12830
  console.log(`Memory dir: ${preservedMemoryDir}`);
12662
12831
  console.log(`Package spec: ${packageSpec}`);
12663
- console.log(`Backup root: ${path12.join(resolveHomeDir(), ".openclaw", "backups")}`);
12832
+ console.log(`Backup root: ${path14.join(resolveHomeDir(), ".openclaw", "backups")}`);
12664
12833
  const plannedActions = [
12665
12834
  `backup openclaw.json and the existing ${REMNIC_OPENCLAW_PLUGIN_ID} extension`,
12666
12835
  ...legacyPluginDirForBackup ? [`backup the existing ${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID} extension without modifying it`] : [],
@@ -12686,9 +12855,9 @@ async function cmdOpenclawUpgrade(opts) {
12686
12855
  }
12687
12856
  }
12688
12857
  const backupDir = createOpenclawUpgradeBackupDir();
12689
- const configBackupPath = path12.join(backupDir, "openclaw.json");
12690
- const pluginBackupDir = path12.join(backupDir, "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
12691
- const legacyPluginBackupDir = legacyPluginDirForBackup ? path12.join(backupDir, "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID) : void 0;
12858
+ const configBackupPath = path14.join(backupDir, "openclaw.json");
12859
+ const pluginBackupDir = path14.join(backupDir, "extensions", REMNIC_OPENCLAW_PLUGIN_ID);
12860
+ const legacyPluginBackupDir = legacyPluginDirForBackup ? path14.join(backupDir, "extensions", REMNIC_OPENCLAW_LEGACY_PLUGIN_ID) : void 0;
12692
12861
  const backupNotes = [];
12693
12862
  if (backupPathIfPresent(configPath, configBackupPath)) {
12694
12863
  backupNotes.push(`+ Backed up config to ${configBackupPath}`);
@@ -12789,9 +12958,9 @@ async function cmdOpenclawMigrateEngram(opts) {
12789
12958
  console.log(" - Re-apply any local source patches to the new package only after verifying the published build.");
12790
12959
  }
12791
12960
  function createOpenclawUpgradeBackupDir() {
12792
- const backupsRoot = path12.join(resolveHomeDir(), ".openclaw", "backups");
12961
+ const backupsRoot = path14.join(resolveHomeDir(), ".openclaw", "backups");
12793
12962
  fs11.mkdirSync(backupsRoot, { recursive: true });
12794
- return fs11.mkdtempSync(path12.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
12963
+ return fs11.mkdtempSync(path14.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
12795
12964
  }
12796
12965
  async function cmdTaxonomy(rest) {
12797
12966
  initLogger2();
@@ -12833,8 +13002,8 @@ async function cmdTaxonomy(rest) {
12833
13002
  const doc = generateResolverDocument(taxonomy);
12834
13003
  console.log(doc);
12835
13004
  if (config.taxonomyAutoGenResolver) {
12836
- const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
12837
- fs11.mkdirSync(path12.dirname(resolverPath), { recursive: true });
13005
+ const resolverPath = path14.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13006
+ fs11.mkdirSync(path14.dirname(resolverPath), { recursive: true });
12838
13007
  fs11.writeFileSync(resolverPath, doc);
12839
13008
  console.error(`Written: ${resolverPath}`);
12840
13009
  }
@@ -12880,7 +13049,7 @@ async function cmdTaxonomy(rest) {
12880
13049
  console.log(`Added category "${id}" (${name}).`);
12881
13050
  if (config.taxonomyAutoGenResolver) {
12882
13051
  const doc = generateResolverDocument(taxonomy);
12883
- const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13052
+ const resolverPath = path14.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
12884
13053
  fs11.writeFileSync(resolverPath, doc);
12885
13054
  console.error(`Regenerated: ${resolverPath}`);
12886
13055
  }
@@ -12911,7 +13080,7 @@ async function cmdTaxonomy(rest) {
12911
13080
  console.log(`Removed category "${id}".`);
12912
13081
  if (config.taxonomyAutoGenResolver) {
12913
13082
  const doc = generateResolverDocument(taxonomy);
12914
- const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
13083
+ const resolverPath = path14.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
12915
13084
  fs11.writeFileSync(resolverPath, doc);
12916
13085
  console.error(`Regenerated: ${resolverPath}`);
12917
13086
  }
@@ -13193,7 +13362,7 @@ async function runTrainingExport(args, stdout = process.stdout) {
13193
13362
  );
13194
13363
  }
13195
13364
  const formatted = adapter.formatRecords(records);
13196
- const outDir = path12.dirname(args.output);
13365
+ const outDir = path14.dirname(args.output);
13197
13366
  fs11.mkdirSync(outDir, { recursive: true });
13198
13367
  const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
13199
13368
  fs11.writeFileSync(tmpPath, formatted, "utf-8");
@@ -13301,7 +13470,7 @@ async function main(argv = process.argv.slice(2)) {
13301
13470
  case "tree": {
13302
13471
  const subAction = rest[0];
13303
13472
  const json = rest.includes("--json");
13304
- const outputDir = resolveFlag(rest, "--output") ?? path12.join(process.cwd(), ".remnic", "context-tree");
13473
+ const outputDir = resolveFlag(rest, "--output") ?? path14.join(process.cwd(), ".remnic", "context-tree");
13305
13474
  const categoriesFlag = resolveFlag(rest, "--categories");
13306
13475
  const categories = categoriesFlag ? categoriesFlag.split(",") : void 0;
13307
13476
  const maxPerCategoryRaw = resolveFlag(rest, "--max-per-category");
@@ -13378,7 +13547,7 @@ async function main(argv = process.argv.slice(2)) {
13378
13547
  console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
13379
13548
  process.exit(1);
13380
13549
  }
13381
- const indexPath = path12.join(treeDir, "INDEX.md");
13550
+ const indexPath = path14.join(treeDir, "INDEX.md");
13382
13551
  if (!fs11.existsSync(indexPath)) {
13383
13552
  console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
13384
13553
  process.exit(1);
@@ -13832,9 +14001,9 @@ Usage:
13832
14001
  remnic extensions <list|show|validate|reload> Manage memory extensions
13833
14002
  remnic space <list|switch|create|delete|push|pull|share|promote|audit> Manage spaces
13834
14003
  create accepts --parent <id> to set parent-child relationship
13835
- remnic bench <list|run|datasets|runs|compare|results|baseline|export|publish|ui|providers> [benchmark...] [--quick] [--all] [--dataset-dir <path>] [--results-dir <path>] [--baselines-dir <path>] [--threshold <value>] [--detail] [--format <json|csv|html>] [--output <path>] [--target remnic-ai] [--json]
14004
+ remnic bench <list|run|published|datasets|runs|compare|results|baseline|export|publish|ui|providers|judge-calibrate|attribute|drift-gen> [benchmark...] [--quick] [--all] [--dataset-dir <path>] [--results-dir <path>] [--baselines-dir <path>] [--threshold <value>] [--detail] [--format <json|csv|html>] [--output <path>] [--target remnic-ai] [--json]
13836
14005
  benchmark is kept as a compatibility alias. check/report remain under that alias.
13837
- remnic benchmark <list|run|datasets|runs|compare|results|baseline|export|publish|ui|providers|check|report> [queries...] [--explain] [--baseline=<path>] [--report=<path>]
14006
+ remnic benchmark <list|run|datasets|runs|compare|results|baseline|export|publish|ui|providers|check|report|attribute|drift-gen> [queries...] [--explain] [--baseline=<path>] [--report=<path>]
13838
14007
  remnic briefing [--since <window>] [--focus <filter>] [--save] [--format markdown|json]
13839
14008
  Daily context briefing. Windows: yesterday, today, NNh, NNd, NNw.
13840
14009
  Focus: person:<name>, project:<name>, topic:<name>.
@@ -13962,7 +14131,6 @@ export {
13962
14131
  fetchOfflineSnapshot,
13963
14132
  formatOfflineLargeFilePushFailureMessage,
13964
14133
  formatOfflineRequestForError,
13965
- getBenchUsageText,
13966
14134
  hasFlag,
13967
14135
  hashCalibrationProviderConfig,
13968
14136
  hydrateOfflineSnapshotContent,