openclaw-openviking-setup-helper 0.3.0-beta.7 → 0.3.0-beta.9

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/install.js +84 -85
  2. package/package.json +1 -1
package/install.js CHANGED
@@ -97,9 +97,9 @@ let rollbackLastUpgrade = false;
97
97
  let showCurrentVersion = false;
98
98
 
99
99
  const selectedMode = "remote";
100
- let remoteBaseUrl = "http://127.0.0.1:1933";
101
- let remoteApiKey = "";
102
- let remoteAgentPrefix = "";
100
+ let remoteBaseUrl = (process.env.OPENVIKING_BASE_URL || "http://127.0.0.1:1933").trim();
101
+ let remoteApiKey = (process.env.OPENVIKING_API_KEY || "").trim();
102
+ let remoteAgentPrefix = (process.env.OPENVIKING_AGENT_PREFIX || "").trim();
103
103
  let upgradeRuntimeConfig = null;
104
104
  let installedUpgradeState = null;
105
105
  let upgradeAudit = null;
@@ -1421,8 +1421,7 @@ async function configureOpenClawPlugin({
1421
1421
  const needWorkdirFlag = OPENCLAW_DIR !== DEFAULT_OPENCLAW_DIR;
1422
1422
 
1423
1423
  const oc = async (args) => {
1424
- const fullArgs = needWorkdirFlag ? [...args, "--workdir", OPENCLAW_DIR] : args;
1425
- const result = await runCapture("openclaw", fullArgs, { env: ocEnv, shell: IS_WIN });
1424
+ const result = await runCapture("openclaw", args, { env: ocEnv, shell: IS_WIN });
1426
1425
  if (result.code !== 0) {
1427
1426
  const detail = result.err || result.out;
1428
1427
  throw new Error(`openclaw ${args.join(" ")} failed (exit code ${result.code})${detail ? `: ${detail}` : ""}`);
@@ -1430,16 +1429,58 @@ async function configureOpenClawPlugin({
1430
1429
  return result;
1431
1430
  };
1432
1431
 
1432
+ // Direct file manipulation for config (reliable across all OpenClaw versions and --workdir scenarios).
1433
+ // OpenClaw CLI's --workdir / OPENCLAW_STATE_DIR support is inconsistent, so we read/write openclaw.json directly.
1434
+ const configPath = getOpenClawConfigPath();
1435
+ const readCfg = async () => {
1436
+ if (!existsSync(configPath)) return {};
1437
+ try { return JSON.parse(await readFile(configPath, "utf8")); } catch { return {}; }
1438
+ };
1439
+ const writeCfg = async (cfg) => {
1440
+ const out = JSON.stringify(cfg, null, 2) + "\n";
1441
+ const tmp = `${configPath}.ov-install-tmp.${process.pid}`;
1442
+ await writeFile(tmp, out, "utf8");
1443
+ await rename(tmp, configPath);
1444
+ };
1445
+ const ensurePluginRegistered = async (cfg) => {
1446
+ if (!cfg.plugins) cfg.plugins = {};
1447
+ const p = cfg.plugins;
1448
+ if (!p.entries) p.entries = {};
1449
+ if (!p.entries[pluginId]) p.entries[pluginId] = {};
1450
+ if (!p.entries[pluginId].config) p.entries[pluginId].config = {};
1451
+ if (!Array.isArray(p.allow)) p.allow = [];
1452
+ if (!p.allow.includes(pluginId)) p.allow.push(pluginId);
1453
+ return cfg;
1454
+ };
1455
+
1433
1456
  if (!preserveExistingConfig) {
1434
1457
  await scrubStaleOpenClawPluginRegistration();
1435
1458
  }
1436
1459
 
1437
- // Enable plugin (files already deployed to extensions dir by deployPlugin)
1438
- await oc(["plugins", "enable", pluginId]);
1460
+ // Enable plugin: try CLI first (default path), fall back to direct file for --workdir
1461
+ if (!needWorkdirFlag) {
1462
+ try {
1463
+ await oc(["plugins", "enable", pluginId]);
1464
+ } catch (_e) {
1465
+ info(tr("plugins enable via CLI failed, registering directly", "CLI plugins enable 失败,直接注册"));
1466
+ const cfg = await readCfg();
1467
+ await ensurePluginRegistered(cfg);
1468
+ await writeCfg(cfg);
1469
+ }
1470
+ } else {
1471
+ info(tr("Using direct config write for non-default workdir", "非默认目录,使用直接配置写入"));
1472
+ const cfg = await readCfg();
1473
+ await ensurePluginRegistered(cfg);
1474
+ await writeCfg(cfg);
1475
+ }
1439
1476
 
1440
1477
  if (preserveExistingConfig) {
1441
1478
  if (claimSlot) {
1442
- await oc(["config", "set", `plugins.slots.${pluginSlot}`, pluginId]);
1479
+ const cfg = await readCfg();
1480
+ if (!cfg.plugins) cfg.plugins = {};
1481
+ if (!cfg.plugins.slots) cfg.plugins.slots = {};
1482
+ cfg.plugins.slots[pluginSlot] = pluginId;
1483
+ await writeCfg(cfg);
1443
1484
  }
1444
1485
  info(
1445
1486
  tr(
@@ -1450,29 +1491,33 @@ async function configureOpenClawPlugin({
1450
1491
  return;
1451
1492
  }
1452
1493
 
1453
- // Legacy (memory) plugins still use direct config set
1454
- if (resolvedPluginKind === "memory") {
1455
- if (claimSlot) {
1456
- try { await oc(["config", "set", `plugins.slots.${pluginSlot}`, pluginId]); } catch (_e) {
1457
- warn(tr("Could not activate slot for legacy plugin", "无法为旧版插件激活 slot"));
1458
- }
1494
+ const writeConfigDirect = async (pluginConfig, slotValue) => {
1495
+ const cfg = await readCfg();
1496
+ await ensurePluginRegistered(cfg);
1497
+ Object.assign(cfg.plugins.entries[pluginId].config, pluginConfig);
1498
+ if (slotValue) {
1499
+ if (!cfg.plugins.slots) cfg.plugins.slots = {};
1500
+ cfg.plugins.slots[pluginSlot] = slotValue;
1459
1501
  }
1502
+ await writeCfg(cfg);
1503
+ };
1504
+
1505
+ // Legacy (memory) plugins: direct JSON write
1506
+ if (resolvedPluginKind === "memory") {
1460
1507
  const effectiveRuntimeConfig = runtimeConfig || {
1461
1508
  baseUrl: remoteBaseUrl,
1462
1509
  apiKey: remoteApiKey,
1463
- agent_prefix: remoteAgentPrefix,
1464
1510
  };
1465
- const trySet = async (k, v) => {
1466
- try { await oc(["config", "set", `plugins.entries.${pluginId}.config.${k}`, v]); }
1467
- catch (_e) { warn(tr(`Could not set ${k} for legacy plugin`, `无法为旧版插件设置 ${k}`)); }
1511
+ const pluginConfig = {
1512
+ baseUrl: effectiveRuntimeConfig.baseUrl || remoteBaseUrl,
1513
+ targetUri: "viking://user/memories",
1514
+ autoRecall: true,
1515
+ autoCapture: true,
1468
1516
  };
1469
- await trySet("baseUrl", effectiveRuntimeConfig.baseUrl || remoteBaseUrl);
1470
1517
  if (effectiveRuntimeConfig.apiKey) {
1471
- await trySet("apiKey", effectiveRuntimeConfig.apiKey);
1518
+ pluginConfig.apiKey = effectiveRuntimeConfig.apiKey;
1472
1519
  }
1473
- await trySet("targetUri", "viking://user/memories");
1474
- try { await oc(["config", "set", `plugins.entries.${pluginId}.config.autoRecall`, "true", "--json"]); } catch (_e) { /* optional */ }
1475
- try { await oc(["config", "set", `plugins.entries.${pluginId}.config.autoCapture`, "true", "--json"]); } catch (_e) { /* optional */ }
1520
+ await writeConfigDirect(pluginConfig, claimSlot ? pluginId : null);
1476
1521
  info(tr("OpenClaw plugin configured (legacy mode)", "OpenClaw 插件配置完成(旧版模式)"));
1477
1522
  return;
1478
1523
  }
@@ -1486,11 +1531,11 @@ async function configureOpenClawPlugin({
1486
1531
  agent_prefix: remoteAgentPrefix,
1487
1532
  };
1488
1533
 
1489
- const setupArgs = [
1490
- "openviking", "setup",
1491
- "--base-url", effectiveRuntimeConfig.baseUrl || remoteBaseUrl,
1492
- "--json",
1493
- ];
1534
+ const setupArgs = needWorkdirFlag
1535
+ ? ["--workdir", OPENCLAW_DIR, "openviking", "setup"]
1536
+ : ["openviking", "setup"];
1537
+ setupArgs.push("--base-url", effectiveRuntimeConfig.baseUrl || remoteBaseUrl);
1538
+ setupArgs.push("--json");
1494
1539
  if (effectiveRuntimeConfig.apiKey) {
1495
1540
  setupArgs.push("--api-key", effectiveRuntimeConfig.apiKey);
1496
1541
  }
@@ -1504,10 +1549,6 @@ async function configureOpenClawPlugin({
1504
1549
  setupArgs.push("--allow-offline");
1505
1550
  }
1506
1551
 
1507
- if (needWorkdirFlag) {
1508
- setupArgs.push("--workdir", OPENCLAW_DIR);
1509
- }
1510
-
1511
1552
  info(tr(
1512
1553
  "Delegating configuration to: openclaw openviking setup --json",
1513
1554
  "委托配置给: openclaw openviking setup --json",
@@ -1555,68 +1596,26 @@ async function configureOpenClawPlugin({
1555
1596
  }
1556
1597
  }
1557
1598
  } else if (setupResult.code !== 0) {
1558
- // JSON parse failed and non-zero exit
1599
+ // JSON parse failed and non-zero exit — setup CLI not available (old plugin version)
1559
1600
  warn(tr(
1560
- `openclaw openviking setup exited with code ${setupResult.code}. Falling back to direct config.`,
1561
- `openclaw openviking setup 退出码 ${setupResult.code},回退到直接配置。`,
1601
+ `openclaw openviking setup exited with code ${setupResult.code}. Falling back to direct JSON config write.`,
1602
+ `openclaw openviking setup 退出码 ${setupResult.code},回退到直接写入 JSON 配置。`,
1562
1603
  ));
1563
- // Fallback: direct config set (for backward compat if setup CLI not available)
1564
- // Each field is wrapped individually so one schema mismatch does not abort the rest.
1565
- let fallbackOk = true;
1566
- const tryConfigSet = async (key, value, altKey) => {
1567
- try {
1568
- await oc(["config", "set", `plugins.entries.${pluginId}.config.${key}`, value]);
1569
- } catch (_e) {
1570
- if (altKey) {
1571
- try {
1572
- await oc(["config", "set", `plugins.entries.${pluginId}.config.${altKey}`, value]);
1573
- return;
1574
- } catch (_e2) { /* fall through to warn */ }
1575
- }
1576
- fallbackOk = false;
1577
- warn(tr(
1578
- `Could not set config field "${key}": schema validation failed (plugin version may not support this field)`,
1579
- `无法设置配置字段 "${key}":schema 校验失败(插件版本可能不支持此字段)`,
1580
- ));
1581
- }
1604
+ const pluginConfig = {
1605
+ baseUrl: effectiveRuntimeConfig.baseUrl || remoteBaseUrl,
1582
1606
  };
1583
-
1584
- await tryConfigSet("baseUrl", effectiveRuntimeConfig.baseUrl || remoteBaseUrl);
1585
1607
  if (effectiveRuntimeConfig.apiKey) {
1586
- await tryConfigSet("apiKey", effectiveRuntimeConfig.apiKey);
1608
+ pluginConfig.apiKey = effectiveRuntimeConfig.apiKey;
1587
1609
  }
1588
1610
  if (effectiveRuntimeConfig.agent_prefix) {
1589
- await tryConfigSet("agent_prefix", effectiveRuntimeConfig.agent_prefix, "agentId");
1590
- }
1591
- if (claimSlot) {
1592
- try {
1593
- await oc(["config", "set", `plugins.slots.${pluginSlot}`, pluginId]);
1594
- } catch (_e) {
1595
- fallbackOk = false;
1596
- warn(tr(
1597
- "Could not activate contextEngine slot",
1598
- "无法激活 contextEngine slot",
1599
- ));
1600
- }
1601
- }
1602
- if (fallbackOk) {
1603
- info(tr("OpenClaw plugin configured (fallback)", "OpenClaw 插件配置完成(回退模式)"));
1604
- } else {
1605
- warn(tr(
1606
- "OpenClaw plugin partially configured (fallback). Some fields could not be set. Run `openclaw openviking setup` to complete configuration.",
1607
- "OpenClaw 插件部分配置完成(回退模式)。部分字段未能设置,请运行 `openclaw openviking setup` 完善配置。",
1608
- ));
1609
- }
1610
- if (effectiveRuntimeConfig.apiKey) {
1611
- warn(tr(
1612
- "Note: Root API key detection, accountId/userId tenant context, and server version compatibility checks are only available via `openclaw openviking setup`. If you are using a root API key, please upgrade the plugin and re-run setup.",
1613
- "提示:Root API Key 检测、accountId/userId 租户上下文、服务端版本兼容性检查仅在 `openclaw openviking setup` 中可用。如果您使用的是 root API key,请升级插件后重新执行 setup。",
1614
- ));
1611
+ pluginConfig.agent_prefix = effectiveRuntimeConfig.agent_prefix;
1615
1612
  }
1613
+ await writeConfigDirect(pluginConfig, claimSlot ? pluginId : null);
1614
+ info(tr("OpenClaw plugin configured (direct write)", "OpenClaw 插件配置完成(直接写入)"));
1616
1615
  if (effectiveRuntimeConfig.apiKey) {
1617
1616
  info(tr(
1618
- "Note: If using a root API key, run `openclaw openviking setup` to configure accountId/userId (required for tenant isolation).",
1619
- "提示:如果使用的是 root API key,请运行 `openclaw openviking setup` 配置 accountId/userId(多租户隔离必需)。",
1617
+ "Note: Root API key detection and tenant context are only available via `openclaw openviking setup`. If using a root API key, upgrade the plugin and re-run setup.",
1618
+ "提示:Root API Key 检测和租户上下文仅在 `openclaw openviking setup` 中可用。如果使用 root API key,请升级插件后重新执行 setup。",
1620
1619
  ));
1621
1620
  }
1622
1621
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-openviking-setup-helper",
3
- "version": "0.3.0-beta.7",
3
+ "version": "0.3.0-beta.9",
4
4
  "description": "Setup helper for installing OpenViking memory plugin into OpenClaw",
5
5
  "type": "module",
6
6
  "bin": {