openclaw-openviking-setup-helper 0.3.0-beta.25 → 0.3.0-beta.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/install.js +204 -92
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -106,8 +106,10 @@ let langZh = false;
|
|
|
106
106
|
let workdirExplicit = false;
|
|
107
107
|
let upgradePluginOnly = false;
|
|
108
108
|
let rollbackLastUpgrade = false;
|
|
109
|
-
let showCurrentVersion = false;
|
|
110
|
-
let uninstallPlugin = false;
|
|
109
|
+
let showCurrentVersion = false;
|
|
110
|
+
let uninstallPlugin = false;
|
|
111
|
+
let forceSlotExplicit = false;
|
|
112
|
+
let allowOfflineExplicit = false;
|
|
111
113
|
|
|
112
114
|
const selectedMode = "remote";
|
|
113
115
|
const baseUrlFromEnv = !!process.env.OPENVIKING_BASE_URL;
|
|
@@ -147,11 +149,19 @@ for (let i = 0; i < argv.length; i++) {
|
|
|
147
149
|
rollbackLastUpgrade = true;
|
|
148
150
|
continue;
|
|
149
151
|
}
|
|
150
|
-
if (arg === "--uninstall" || arg === "--remove") {
|
|
151
|
-
uninstallPlugin = true;
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
if (arg === "--
|
|
152
|
+
if (arg === "--uninstall" || arg === "--remove") {
|
|
153
|
+
uninstallPlugin = true;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (arg === "--force-slot") {
|
|
157
|
+
forceSlotExplicit = true;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (arg === "--allow-offline") {
|
|
161
|
+
allowOfflineExplicit = true;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (arg === "--workdir") {
|
|
155
165
|
const workdir = argv[i + 1]?.trim();
|
|
156
166
|
if (!workdir) {
|
|
157
167
|
console.error("--workdir requires a path");
|
|
@@ -282,9 +292,11 @@ function printHelp() {
|
|
|
282
292
|
console.log(" --base-url=URL OpenViking server URL (default: $OPENVIKING_BASE_URL or http://127.0.0.1:1933)");
|
|
283
293
|
console.log(" --api-key=KEY OpenViking API key (default: $OPENVIKING_API_KEY)");
|
|
284
294
|
console.log(" --agent-prefix=PREFIX Agent routing prefix (default: $OPENVIKING_AGENT_PREFIX)");
|
|
285
|
-
console.log(" --account-id=ID Account ID for root API key (default: $OPENVIKING_ACCOUNT_ID)");
|
|
286
|
-
console.log(" --user-id=ID User ID for root API key (default: $OPENVIKING_USER_ID)");
|
|
287
|
-
console.log(" --
|
|
295
|
+
console.log(" --account-id=ID Account ID for root API key (default: $OPENVIKING_ACCOUNT_ID)");
|
|
296
|
+
console.log(" --user-id=ID User ID for root API key (default: $OPENVIKING_USER_ID)");
|
|
297
|
+
console.log(" --force-slot Explicitly replace an existing contextEngine slot owner");
|
|
298
|
+
console.log(" --allow-offline Explicitly save config when the OpenViking server is unreachable");
|
|
299
|
+
console.log(" --zh Chinese prompts");
|
|
288
300
|
console.log(" -h, --help This help");
|
|
289
301
|
console.log("");
|
|
290
302
|
console.log("Examples:");
|
|
@@ -403,18 +415,23 @@ function runCapture(cmd, args, opts = {}) {
|
|
|
403
415
|
});
|
|
404
416
|
}
|
|
405
417
|
|
|
406
|
-
function question(prompt, defaultValue = "") {
|
|
407
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
408
|
-
const suffix = defaultValue ? ` [${defaultValue}]` : "";
|
|
409
|
-
return new Promise((resolve) => {
|
|
410
|
-
rl.question(`${prompt}${suffix}: `, (answer) => {
|
|
418
|
+
function question(prompt, defaultValue = "") {
|
|
419
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
420
|
+
const suffix = defaultValue ? ` [${defaultValue}]` : "";
|
|
421
|
+
return new Promise((resolve) => {
|
|
422
|
+
rl.question(`${prompt}${suffix}: `, (answer) => {
|
|
411
423
|
rl.close();
|
|
412
424
|
resolve((answer ?? defaultValue).trim() || defaultValue);
|
|
413
425
|
});
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function isYes(answer) {
|
|
430
|
+
const normalized = String(answer || "").trim().toLowerCase();
|
|
431
|
+
return normalized === "y" || normalized === "yes";
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function isValidAgentPrefixInput(value) {
|
|
418
435
|
const trimmed = String(value || "").trim();
|
|
419
436
|
return !trimmed || /^[a-zA-Z0-9_-]+$/.test(trimmed);
|
|
420
437
|
}
|
|
@@ -922,7 +939,7 @@ async function checkOpenClawCompatibility() {
|
|
|
922
939
|
}
|
|
923
940
|
|
|
924
941
|
// Check compatibility
|
|
925
|
-
if (!openClawPolicyVersionGte(ocVersion, resolvedMinOpenclawVersion)) {
|
|
942
|
+
if (!openClawPolicyVersionGte(ocVersion, resolvedMinOpenclawVersion)) {
|
|
926
943
|
err(tr(
|
|
927
944
|
`OpenClaw ${ocVersion} does not support this plugin (requires >= ${resolvedMinOpenclawVersion})`,
|
|
928
945
|
`OpenClaw ${ocVersion} 不支持此插件(需要 >= ${resolvedMinOpenclawVersion})`
|
|
@@ -1086,11 +1103,17 @@ function extractRuntimeConfigFromPluginEntry(entryConfig) {
|
|
|
1086
1103
|
runtime.apiKey = entryConfig.apiKey;
|
|
1087
1104
|
}
|
|
1088
1105
|
const prefix = entryConfig.agent_prefix || entryConfig.agentId;
|
|
1089
|
-
if (typeof prefix === "string" && prefix.trim()) {
|
|
1090
|
-
runtime.agent_prefix = prefix.trim();
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1106
|
+
if (typeof prefix === "string" && prefix.trim()) {
|
|
1107
|
+
runtime.agent_prefix = prefix.trim();
|
|
1108
|
+
}
|
|
1109
|
+
if (typeof entryConfig.accountId === "string" && entryConfig.accountId.trim()) {
|
|
1110
|
+
runtime.accountId = entryConfig.accountId.trim();
|
|
1111
|
+
}
|
|
1112
|
+
if (typeof entryConfig.userId === "string" && entryConfig.userId.trim()) {
|
|
1113
|
+
runtime.userId = entryConfig.userId.trim();
|
|
1114
|
+
}
|
|
1115
|
+
return runtime;
|
|
1116
|
+
}
|
|
1094
1117
|
|
|
1095
1118
|
async function backupOpenClawConfig(configPath) {
|
|
1096
1119
|
await mkdir(getUpgradeAuditDir(), { recursive: true });
|
|
@@ -1380,10 +1403,12 @@ async function prepareStrongPluginUpgrade() {
|
|
|
1380
1403
|
`检测到已安装 OpenViking 插件状态: ${installedState.generation}`,
|
|
1381
1404
|
),
|
|
1382
1405
|
);
|
|
1383
|
-
remoteBaseUrl = upgradeRuntimeConfig.baseUrl || remoteBaseUrl;
|
|
1384
|
-
remoteApiKey = upgradeRuntimeConfig.apiKey || "";
|
|
1385
|
-
remoteAgentPrefix = upgradeRuntimeConfig.agent_prefix || "";
|
|
1386
|
-
|
|
1406
|
+
remoteBaseUrl = upgradeRuntimeConfig.baseUrl || remoteBaseUrl;
|
|
1407
|
+
remoteApiKey = upgradeRuntimeConfig.apiKey || "";
|
|
1408
|
+
remoteAgentPrefix = upgradeRuntimeConfig.agent_prefix || "";
|
|
1409
|
+
remoteAccountId = upgradeRuntimeConfig.accountId || "";
|
|
1410
|
+
remoteUserId = upgradeRuntimeConfig.userId || "";
|
|
1411
|
+
info(tr(`Upgrade runtime mode: ${selectedMode} (remote OpenViking server)`, `升级运行模式: ${selectedMode}(远程 OpenViking 服务)`));
|
|
1387
1412
|
|
|
1388
1413
|
info(tr(`Upgrade path: ${fromVersion} -> ${toVersion}`, `升级路径: ${fromVersion} -> ${toVersion}`));
|
|
1389
1414
|
|
|
@@ -1768,6 +1793,53 @@ async function cleanupConflictingPluginVariants() {
|
|
|
1768
1793
|
info(tr("Conflicting plugin variants cleaned up", "冲突的插件变体已清理"));
|
|
1769
1794
|
}
|
|
1770
1795
|
|
|
1796
|
+
function normalizeOpenClawLoadPath(filePath) {
|
|
1797
|
+
return String(filePath || "")
|
|
1798
|
+
.replace(/\\/g, "/")
|
|
1799
|
+
.replace(/\/+$/g, "");
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
async function ensureOpenClawPluginLoadPath() {
|
|
1803
|
+
const configPath = getOpenClawConfigPath();
|
|
1804
|
+
let cfg = {};
|
|
1805
|
+
if (existsSync(configPath)) {
|
|
1806
|
+
try {
|
|
1807
|
+
cfg = JSON.parse(await readFile(configPath, "utf8"));
|
|
1808
|
+
} catch {
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
const pluginPath = PLUGIN_DEST;
|
|
1814
|
+
const normalizedPluginPath = normalizeOpenClawLoadPath(pluginPath);
|
|
1815
|
+
const plugins = cfg.plugins && typeof cfg.plugins === "object" && !Array.isArray(cfg.plugins)
|
|
1816
|
+
? cfg.plugins
|
|
1817
|
+
: {};
|
|
1818
|
+
const load = plugins.load && typeof plugins.load === "object" && !Array.isArray(plugins.load)
|
|
1819
|
+
? plugins.load
|
|
1820
|
+
: {};
|
|
1821
|
+
const paths = Array.isArray(load.paths) ? load.paths : [];
|
|
1822
|
+
if (paths.some((item) => normalizeOpenClawLoadPath(item) === normalizedPluginPath)) {
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
const next = {
|
|
1827
|
+
...cfg,
|
|
1828
|
+
plugins: {
|
|
1829
|
+
...plugins,
|
|
1830
|
+
load: {
|
|
1831
|
+
...load,
|
|
1832
|
+
paths: [...paths, pluginPath],
|
|
1833
|
+
},
|
|
1834
|
+
},
|
|
1835
|
+
};
|
|
1836
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
1837
|
+
const tmp = `${configPath}.ov-install-tmp.${process.pid}`;
|
|
1838
|
+
await writeFile(tmp, `${JSON.stringify(next, null, 2)}\n`, "utf8");
|
|
1839
|
+
await rename(tmp, configPath);
|
|
1840
|
+
info(tr(`Added OpenClaw plugin load path: ${pluginPath}`, `已添加 OpenClaw 插件加载路径: ${pluginPath}`));
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1771
1843
|
async function configureOpenClawPlugin({
|
|
1772
1844
|
preserveExistingConfig = false,
|
|
1773
1845
|
runtimeConfig = null,
|
|
@@ -1821,6 +1893,8 @@ async function configureOpenClawPlugin({
|
|
|
1821
1893
|
await scrubStaleOpenClawPluginRegistration();
|
|
1822
1894
|
}
|
|
1823
1895
|
|
|
1896
|
+
await ensureOpenClawPluginLoadPath();
|
|
1897
|
+
|
|
1824
1898
|
// Enable plugin: try CLI first (default path), fall back to direct file for --workdir
|
|
1825
1899
|
if (!needWorkdirFlag) {
|
|
1826
1900
|
try {
|
|
@@ -1931,13 +2005,14 @@ async function configureOpenClawPlugin({
|
|
|
1931
2005
|
}
|
|
1932
2006
|
} catch { /* ignore read errors */ }
|
|
1933
2007
|
|
|
1934
|
-
let setupResult = null;
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
setupArgs
|
|
1938
|
-
setupArgs.push("--
|
|
1939
|
-
|
|
1940
|
-
|
|
2008
|
+
let setupResult = null;
|
|
2009
|
+
let parsed = null;
|
|
2010
|
+
const runSetupJson = async (extraArgs = []) => {
|
|
2011
|
+
const setupArgs = ["openviking", "setup"];
|
|
2012
|
+
setupArgs.push("--base-url", effectiveRuntimeConfig.baseUrl || remoteBaseUrl);
|
|
2013
|
+
setupArgs.push("--json");
|
|
2014
|
+
if (effectiveRuntimeConfig.apiKey) {
|
|
2015
|
+
setupArgs.push("--api-key", effectiveRuntimeConfig.apiKey);
|
|
1941
2016
|
}
|
|
1942
2017
|
if (effectiveRuntimeConfig.agent_prefix) {
|
|
1943
2018
|
setupArgs.push("--agent-prefix", effectiveRuntimeConfig.agent_prefix);
|
|
@@ -1945,35 +2020,67 @@ async function configureOpenClawPlugin({
|
|
|
1945
2020
|
if (effectiveRuntimeConfig.accountId) {
|
|
1946
2021
|
setupArgs.push("--account-id", effectiveRuntimeConfig.accountId);
|
|
1947
2022
|
}
|
|
1948
|
-
if (effectiveRuntimeConfig.userId) {
|
|
1949
|
-
setupArgs.push("--user-id", effectiveRuntimeConfig.userId);
|
|
1950
|
-
}
|
|
1951
|
-
if (
|
|
1952
|
-
setupArgs.push("--force-slot");
|
|
1953
|
-
}
|
|
1954
|
-
if (
|
|
1955
|
-
setupArgs.push("--allow-offline");
|
|
1956
|
-
}
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
2023
|
+
if (effectiveRuntimeConfig.userId) {
|
|
2024
|
+
setupArgs.push("--user-id", effectiveRuntimeConfig.userId);
|
|
2025
|
+
}
|
|
2026
|
+
if (forceSlotExplicit) {
|
|
2027
|
+
setupArgs.push("--force-slot");
|
|
2028
|
+
}
|
|
2029
|
+
if (allowOfflineExplicit) {
|
|
2030
|
+
setupArgs.push("--allow-offline");
|
|
2031
|
+
}
|
|
2032
|
+
setupArgs.push(...extraArgs);
|
|
2033
|
+
|
|
2034
|
+
const result = await runCapture("openclaw", setupArgs, { env: ocEnv, shell: IS_WIN });
|
|
2035
|
+
return {
|
|
2036
|
+
result,
|
|
2037
|
+
parsed: parseJsonObjectFromOutput(`${result.out || ""}\n${result.err || ""}`),
|
|
2038
|
+
};
|
|
2039
|
+
};
|
|
2040
|
+
|
|
2041
|
+
if (setupJsonSupported) {
|
|
2042
|
+
info(tr(
|
|
2043
|
+
"Delegating configuration to: openclaw openviking setup --json",
|
|
2044
|
+
"委托配置给: openclaw openviking setup --json",
|
|
2045
|
+
));
|
|
2046
|
+
|
|
2047
|
+
({ result: setupResult, parsed } = await runSetupJson());
|
|
2048
|
+
} else {
|
|
2049
|
+
info(tr(
|
|
2050
|
+
"Installed plugin does not support setup --json, using direct config write",
|
|
2051
|
+
"已安装的插件不支持 setup --json,使用直接配置写入",
|
|
2052
|
+
));
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
if (parsed && !parsed.success && !nonInteractive) {
|
|
2056
|
+
if (parsed.action === "slot_blocked" && !forceSlotExplicit) {
|
|
2057
|
+
const answer = await question(
|
|
2058
|
+
tr(
|
|
2059
|
+
`contextEngine slot is owned by "${parsed.slot?.previousOwner}". Replace it with OpenViking? (y/N)`,
|
|
2060
|
+
`contextEngine slot is owned by "${parsed.slot?.previousOwner}". Replace it with OpenViking? (y/N)`,
|
|
2061
|
+
),
|
|
2062
|
+
);
|
|
2063
|
+
if (isYes(answer)) {
|
|
2064
|
+
({ result: setupResult, parsed } = await runSetupJson(["--force-slot"]));
|
|
2065
|
+
}
|
|
2066
|
+
} else if (
|
|
2067
|
+
typeof parsed.error === "string" &&
|
|
2068
|
+
parsed.error.includes("Server unreachable") &&
|
|
2069
|
+
!allowOfflineExplicit
|
|
2070
|
+
) {
|
|
2071
|
+
const answer = await question(
|
|
2072
|
+
tr(
|
|
2073
|
+
"OpenViking server is unreachable. Save config offline anyway? (y/N)",
|
|
2074
|
+
"OpenViking server is unreachable. Save config offline anyway? (y/N)",
|
|
2075
|
+
),
|
|
2076
|
+
);
|
|
2077
|
+
if (isYes(answer)) {
|
|
2078
|
+
({ result: setupResult, parsed } = await runSetupJson(["--allow-offline"]));
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
if (parsed) {
|
|
1977
2084
|
if (parsed.success) {
|
|
1978
2085
|
info(tr("OpenClaw plugin configured via setup", "OpenClaw 插件通过 setup 配置完成"));
|
|
1979
2086
|
if (parsed.health?.ok) {
|
|
@@ -1991,32 +2098,37 @@ async function configureOpenClawPlugin({
|
|
|
1991
2098
|
if (parsed.slot?.activated) {
|
|
1992
2099
|
info(tr(`contextEngine slot activated`, `contextEngine slot 已激活`));
|
|
1993
2100
|
}
|
|
1994
|
-
} else {
|
|
1995
|
-
// Setup returned success: false
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
`openclaw openviking setup
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2101
|
+
} else {
|
|
2102
|
+
// Setup returned success: false
|
|
2103
|
+
const setupError = parsed.error || parsed.action || "unknown error";
|
|
2104
|
+
if (parsed.action === "slot_blocked") {
|
|
2105
|
+
warn(tr(
|
|
2106
|
+
`Config saved but contextEngine slot is owned by "${parsed.slot?.previousOwner}". Use --force-slot to override.`,
|
|
2107
|
+
`配置已保存,但 contextEngine slot 被 "${parsed.slot?.previousOwner}" 占用。使用 --force-slot 覆盖。`,
|
|
2108
|
+
));
|
|
2109
|
+
} else {
|
|
2110
|
+
err(tr(
|
|
2111
|
+
`Setup failed: ${setupError}`,
|
|
2112
|
+
`配置失败: ${setupError}`,
|
|
2113
|
+
));
|
|
2114
|
+
}
|
|
2115
|
+
return {
|
|
2116
|
+
runtimeConfigOk: false,
|
|
2117
|
+
error: setupError,
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
} else if (setupJsonSupported) {
|
|
2121
|
+
const setupError = setupResult
|
|
2122
|
+
? `openclaw openviking setup did not return JSON (exit code ${setupResult.code})`
|
|
2123
|
+
: "openclaw openviking setup did not run";
|
|
2124
|
+
err(tr(`Setup failed: ${setupError}`, `配置失败: ${setupError}`));
|
|
2125
|
+
return {
|
|
2126
|
+
runtimeConfigOk: false,
|
|
2127
|
+
error: setupError,
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
if (!setupJsonSupported) {
|
|
2020
2132
|
// Direct write: only used when the installed plugin doesn't support `setup --json` (old version).
|
|
2021
2133
|
// Read the deployed configSchema to determine which fields are allowed, avoiding
|
|
2022
2134
|
// "additionalProperties" validation failures when writing new fields to old schemas.
|
|
@@ -2153,7 +2265,7 @@ async function performUninstall() {
|
|
|
2153
2265
|
tr("Confirm uninstall? (y/N)", "确认卸载?(y/N)"),
|
|
2154
2266
|
"N",
|
|
2155
2267
|
);
|
|
2156
|
-
if (
|
|
2268
|
+
if (!isYes(answer)) {
|
|
2157
2269
|
info(tr("Cancelled.", "已取消。"));
|
|
2158
2270
|
return;
|
|
2159
2271
|
}
|