openclaw-openviking-setup-helper 0.3.0-beta.21 → 0.3.0-beta.23
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 +295 -100
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -29,10 +29,12 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
29
29
|
|
|
30
30
|
let REPO = process.env.REPO || "volcengine/OpenViking";
|
|
31
31
|
// PLUGIN_VERSION takes precedence over BRANCH (legacy). If omitted, resolve the latest tag from GitHub.
|
|
32
|
-
const pluginVersionEnv = (process.env.PLUGIN_VERSION || process.env.BRANCH || "").trim();
|
|
33
|
-
let PLUGIN_VERSION = pluginVersionEnv;
|
|
34
|
-
let pluginVersionExplicit = Boolean(pluginVersionEnv);
|
|
35
|
-
const NPM_REGISTRY = process.env.NPM_REGISTRY || "https://registry.npmmirror.com";
|
|
32
|
+
const pluginVersionEnv = (process.env.PLUGIN_VERSION || process.env.BRANCH || "").trim();
|
|
33
|
+
let PLUGIN_VERSION = pluginVersionEnv;
|
|
34
|
+
let pluginVersionExplicit = Boolean(pluginVersionEnv);
|
|
35
|
+
const NPM_REGISTRY = process.env.NPM_REGISTRY || "https://registry.npmmirror.com";
|
|
36
|
+
const DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION = "2026.5.3";
|
|
37
|
+
const OPENCLAW_SHORT_VERSION_YEAR = 2026;
|
|
36
38
|
|
|
37
39
|
const IS_WIN = process.platform === "win32";
|
|
38
40
|
const HOME = process.env.HOME || process.env.USERPROFILE || "";
|
|
@@ -44,12 +46,13 @@ let PLUGIN_DEST = ""; // Will be set after resolving plugin config
|
|
|
44
46
|
// Fallback configs for old versions without manifest
|
|
45
47
|
const FALLBACK_LEGACY = {
|
|
46
48
|
dir: "openclaw-memory-plugin",
|
|
47
|
-
id: "memory-openviking",
|
|
48
|
-
kind: "memory",
|
|
49
|
-
slot: "memory",
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
id: "memory-openviking",
|
|
50
|
+
kind: "memory",
|
|
51
|
+
slot: "memory",
|
|
52
|
+
minOpenclawVersion: "2026.3.7",
|
|
53
|
+
required: ["index.ts", "config.ts", "client.ts", "openclaw.plugin.json", "package.json"],
|
|
54
|
+
optional: ["package-lock.json", ".gitignore", "memory-ranking.ts", "text-utils.ts", "process-manager.ts", "tsconfig.json"],
|
|
55
|
+
};
|
|
53
56
|
|
|
54
57
|
// Must match examples/openclaw-plugin/install-manifest.json (npm only installs package deps, not these .ts files).
|
|
55
58
|
const FALLBACK_CURRENT = {
|
|
@@ -57,15 +60,19 @@ const FALLBACK_CURRENT = {
|
|
|
57
60
|
id: "openviking",
|
|
58
61
|
kind: "context-engine",
|
|
59
62
|
slot: "contextEngine",
|
|
63
|
+
minOpenclawVersion: "2026.4.24",
|
|
60
64
|
required: ["index.ts", "config.ts", "package.json", "openclaw.plugin.json"],
|
|
61
65
|
optional: [
|
|
62
66
|
"context-engine.ts",
|
|
67
|
+
"auto-recall.ts",
|
|
63
68
|
"client.ts",
|
|
64
69
|
"process-manager.ts",
|
|
65
70
|
"memory-ranking.ts",
|
|
66
71
|
"text-utils.ts",
|
|
67
72
|
"tool-call-id.ts",
|
|
68
73
|
"session-transcript-repair.ts",
|
|
74
|
+
"runtime-utils.ts",
|
|
75
|
+
"commands/setup.ts",
|
|
69
76
|
"tsconfig.json",
|
|
70
77
|
"package-lock.json",
|
|
71
78
|
".gitignore",
|
|
@@ -82,12 +89,17 @@ let resolvedPluginDir = "";
|
|
|
82
89
|
let resolvedPluginId = "";
|
|
83
90
|
let resolvedPluginKind = "";
|
|
84
91
|
let resolvedPluginSlot = "";
|
|
85
|
-
let resolvedFilesRequired = [];
|
|
86
|
-
let resolvedFilesOptional = [];
|
|
87
|
-
let resolvedNpmOmitDev = true;
|
|
88
|
-
let
|
|
89
|
-
let
|
|
90
|
-
let
|
|
92
|
+
let resolvedFilesRequired = [];
|
|
93
|
+
let resolvedFilesOptional = [];
|
|
94
|
+
let resolvedNpmOmitDev = true;
|
|
95
|
+
let resolvedNpmBuild = false;
|
|
96
|
+
let resolvedNpmBuildMinOpenclawVersion = DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION;
|
|
97
|
+
let resolvedNpmBuildScript = "build";
|
|
98
|
+
let resolvedNpmPruneAfterBuild = true;
|
|
99
|
+
let resolvedMinOpenclawVersion = "";
|
|
100
|
+
let resolvedMinOpenvikingVersion = "";
|
|
101
|
+
let resolvedPluginReleaseId = "";
|
|
102
|
+
let detectedOpenClawVersion = "";
|
|
91
103
|
|
|
92
104
|
let nonInteractive = false;
|
|
93
105
|
let langZh = false;
|
|
@@ -402,15 +414,36 @@ function question(prompt, defaultValue = "") {
|
|
|
402
414
|
});
|
|
403
415
|
}
|
|
404
416
|
|
|
405
|
-
function isValidAgentPrefixInput(value) {
|
|
406
|
-
const trimmed = String(value || "").trim();
|
|
407
|
-
return !trimmed || /^[a-zA-Z0-9_-]+$/.test(trimmed);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
417
|
+
function isValidAgentPrefixInput(value) {
|
|
418
|
+
const trimmed = String(value || "").trim();
|
|
419
|
+
return !trimmed || /^[a-zA-Z0-9_-]+$/.test(trimmed);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function parseJsonObjectFromOutput(output) {
|
|
423
|
+
const text = String(output || "").trim();
|
|
424
|
+
if (!text) return null;
|
|
425
|
+
try {
|
|
426
|
+
return JSON.parse(text);
|
|
427
|
+
} catch {
|
|
428
|
+
// OpenClaw may print plugin registration logs before --json output.
|
|
429
|
+
}
|
|
430
|
+
for (let index = text.lastIndexOf("{"); index >= 0; index = text.lastIndexOf("{", index - 1)) {
|
|
431
|
+
try {
|
|
432
|
+
const parsed = JSON.parse(text.slice(index).trim());
|
|
433
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
434
|
+
return parsed;
|
|
435
|
+
}
|
|
436
|
+
} catch {
|
|
437
|
+
// Keep scanning earlier braces until the outer JSON object is found.
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function questionAgentPrefix(defaultValue = "") {
|
|
444
|
+
while (true) {
|
|
445
|
+
const answer = (await question(
|
|
446
|
+
tr("Agent Prefix (optional)", "Agent Prefix(可选)"),
|
|
414
447
|
defaultValue,
|
|
415
448
|
)).trim();
|
|
416
449
|
if (isValidAgentPrefixInput(answer)) {
|
|
@@ -497,23 +530,68 @@ async function checkOpenClaw() {
|
|
|
497
530
|
}
|
|
498
531
|
|
|
499
532
|
// Compare versions: returns true if v1 >= v2
|
|
500
|
-
function versionGte(v1, v2) {
|
|
501
|
-
const parseVersion = (v) => {
|
|
502
|
-
const cleaned = v.replace(/^v/, "").replace(/-.*$/, "");
|
|
503
|
-
const parts = cleaned.split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
504
|
-
while (parts.length < 3) parts.push(0);
|
|
533
|
+
function versionGte(v1, v2) {
|
|
534
|
+
const parseVersion = (v) => {
|
|
535
|
+
const cleaned = v.replace(/^v/, "").replace(/-.*$/, "");
|
|
536
|
+
const parts = cleaned.split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
537
|
+
while (parts.length < 3) parts.push(0);
|
|
505
538
|
return parts;
|
|
506
539
|
};
|
|
507
540
|
const [a1, a2, a3] = parseVersion(v1);
|
|
508
541
|
const [b1, b2, b3] = parseVersion(v2);
|
|
509
542
|
if (a1 !== b1) return a1 > b1;
|
|
510
|
-
if (a2 !== b2) return a2 > b2;
|
|
511
|
-
return a3 >= b3;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
function
|
|
515
|
-
|
|
516
|
-
|
|
543
|
+
if (a2 !== b2) return a2 > b2;
|
|
544
|
+
return a3 >= b3;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function parseOpenClawPolicyVersion(value) {
|
|
548
|
+
const parts = String(value || "")
|
|
549
|
+
.match(/\d+/g)
|
|
550
|
+
?.map((part) => Number.parseInt(part, 10) || 0) || [];
|
|
551
|
+
if (parts.length === 0) return [0, 0, 0];
|
|
552
|
+
if (parts[0] >= 2000) {
|
|
553
|
+
return [parts[0], parts[1] || 0, parts[2] || 0];
|
|
554
|
+
}
|
|
555
|
+
return [OPENCLAW_SHORT_VERSION_YEAR, parts[0] || 0, parts[1] || 0];
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function openClawPolicyVersionGte(v1, v2) {
|
|
559
|
+
const a = parseOpenClawPolicyVersion(v1);
|
|
560
|
+
const b = parseOpenClawPolicyVersion(v2);
|
|
561
|
+
for (let i = 0; i < 3; i++) {
|
|
562
|
+
if (a[i] !== b[i]) return a[i] > b[i];
|
|
563
|
+
}
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function applyOpenClawBuildPolicy(openClawVersion) {
|
|
568
|
+
if (!resolvedNpmBuild || !resolvedNpmBuildMinOpenclawVersion) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (!openClawVersion || openClawVersion === "0.0.0") {
|
|
572
|
+
warn(tr(
|
|
573
|
+
"Could not determine OpenClaw version; keeping plugin source build enabled.",
|
|
574
|
+
"无法确定 OpenClaw 版本,保持插件源码构建开启。",
|
|
575
|
+
));
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (openClawPolicyVersionGte(openClawVersion, resolvedNpmBuildMinOpenclawVersion)) {
|
|
579
|
+
info(tr(
|
|
580
|
+
`OpenClaw ${openClawVersion} requires plugin source build (>= ${resolvedNpmBuildMinOpenclawVersion})`,
|
|
581
|
+
`OpenClaw ${openClawVersion} 需要插件源码构建(>= ${resolvedNpmBuildMinOpenclawVersion})`,
|
|
582
|
+
));
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
resolvedNpmBuild = false;
|
|
586
|
+
info(tr(
|
|
587
|
+
`OpenClaw ${openClawVersion} is below ${resolvedNpmBuildMinOpenclawVersion}; skipping plugin source build`,
|
|
588
|
+
`OpenClaw ${openClawVersion} 低于 ${resolvedNpmBuildMinOpenclawVersion},跳过插件源码构建`,
|
|
589
|
+
));
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function isSemverLike(value) {
|
|
593
|
+
return /^v?\d+(\.\d+){1,2}$/.test(value);
|
|
594
|
+
}
|
|
517
595
|
|
|
518
596
|
function validateRequestedPluginVersion() {
|
|
519
597
|
if (!isSemverLike(PLUGIN_VERSION)) return;
|
|
@@ -534,16 +612,24 @@ if (uninstallPlugin && (upgradePluginOnly || rollbackLastUpgrade)) {
|
|
|
534
612
|
}
|
|
535
613
|
|
|
536
614
|
// Detect OpenClaw version
|
|
537
|
-
async function detectOpenClawVersion() {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
615
|
+
async function detectOpenClawVersion() {
|
|
616
|
+
if (detectedOpenClawVersion) {
|
|
617
|
+
return detectedOpenClawVersion;
|
|
618
|
+
}
|
|
619
|
+
try {
|
|
620
|
+
const result = await runCapture("openclaw", ["--version"], { shell: IS_WIN });
|
|
621
|
+
const output = `${result.out || ""}\n${result.err || ""}`;
|
|
622
|
+
if (result.code === 0 && output) {
|
|
623
|
+
const match = output.match(/\d+\.\d+(\.\d+)?/);
|
|
624
|
+
if (match) {
|
|
625
|
+
detectedOpenClawVersion = match[0];
|
|
626
|
+
return detectedOpenClawVersion;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
} catch {}
|
|
630
|
+
detectedOpenClawVersion = "0.0.0";
|
|
631
|
+
return detectedOpenClawVersion;
|
|
632
|
+
}
|
|
547
633
|
|
|
548
634
|
// Try to fetch a URL, return response text or null
|
|
549
635
|
async function tryFetch(url, timeout = 15000) {
|
|
@@ -686,13 +772,19 @@ async function resolveDefaultPluginVersion() {
|
|
|
686
772
|
}
|
|
687
773
|
|
|
688
774
|
// Resolve plugin configuration from manifest or fallback
|
|
689
|
-
async function resolvePluginConfig() {
|
|
690
|
-
const ghRaw = `https://raw.githubusercontent.com/${REPO}/${PLUGIN_VERSION}`;
|
|
691
|
-
|
|
692
|
-
info(tr(`Resolving plugin configuration for version: ${PLUGIN_VERSION}`, `正在解析插件配置,版本: ${PLUGIN_VERSION}`));
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
775
|
+
async function resolvePluginConfig() {
|
|
776
|
+
const ghRaw = `https://raw.githubusercontent.com/${REPO}/${PLUGIN_VERSION}`;
|
|
777
|
+
|
|
778
|
+
info(tr(`Resolving plugin configuration for version: ${PLUGIN_VERSION}`, `正在解析插件配置,版本: ${PLUGIN_VERSION}`));
|
|
779
|
+
|
|
780
|
+
resolvedNpmOmitDev = true;
|
|
781
|
+
resolvedNpmBuild = false;
|
|
782
|
+
resolvedNpmBuildMinOpenclawVersion = DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION;
|
|
783
|
+
resolvedNpmBuildScript = "build";
|
|
784
|
+
resolvedNpmPruneAfterBuild = true;
|
|
785
|
+
|
|
786
|
+
let pluginDir = "";
|
|
787
|
+
let manifestData = null;
|
|
696
788
|
|
|
697
789
|
// Try to detect plugin directory and download manifest
|
|
698
790
|
const manifestCurrent = await tryFetch(`${ghRaw}/examples/openclaw-plugin/install-manifest.json`);
|
|
@@ -729,13 +821,25 @@ async function resolvePluginConfig() {
|
|
|
729
821
|
resolvedPluginId = manifestData.plugin?.id || "";
|
|
730
822
|
resolvedPluginKind = manifestData.plugin?.kind || "";
|
|
731
823
|
resolvedPluginSlot = manifestData.plugin?.slot || "";
|
|
732
|
-
resolvedMinOpenclawVersion = manifestData.compatibility?.minOpenclawVersion || "";
|
|
733
|
-
resolvedMinOpenvikingVersion = manifestData.compatibility?.minOpenvikingVersion || "";
|
|
734
|
-
resolvedPluginReleaseId = manifestData.pluginVersion || manifestData.release?.id || "";
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
824
|
+
resolvedMinOpenclawVersion = manifestData.compatibility?.minOpenclawVersion || "";
|
|
825
|
+
resolvedMinOpenvikingVersion = manifestData.compatibility?.minOpenvikingVersion || "";
|
|
826
|
+
resolvedPluginReleaseId = manifestData.pluginVersion || manifestData.release?.id || "";
|
|
827
|
+
const npmConfig = manifestData.npm && typeof manifestData.npm === "object"
|
|
828
|
+
? manifestData.npm
|
|
829
|
+
: {};
|
|
830
|
+
resolvedNpmOmitDev = npmConfig.omitDev !== false;
|
|
831
|
+
resolvedNpmBuild = npmConfig.build === true || npmConfig.buildFromSource === true;
|
|
832
|
+
resolvedNpmBuildMinOpenclawVersion =
|
|
833
|
+
typeof npmConfig.buildMinOpenclawVersion === "string" && npmConfig.buildMinOpenclawVersion.trim()
|
|
834
|
+
? npmConfig.buildMinOpenclawVersion.trim()
|
|
835
|
+
: DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION;
|
|
836
|
+
resolvedNpmBuildScript = typeof npmConfig.buildScript === "string" && npmConfig.buildScript.trim()
|
|
837
|
+
? npmConfig.buildScript.trim()
|
|
838
|
+
: "build";
|
|
839
|
+
resolvedNpmPruneAfterBuild = npmConfig.pruneAfterBuild !== false;
|
|
840
|
+
resolvedFilesRequired = manifestData.files?.required || [];
|
|
841
|
+
resolvedFilesOptional = manifestData.files?.optional || [];
|
|
842
|
+
} else {
|
|
739
843
|
// No manifest — determine plugin identity by package.json name
|
|
740
844
|
let fallbackKey = pluginDir === "openclaw-memory-plugin" ? "legacy" : "current";
|
|
741
845
|
let compatVer = "";
|
|
@@ -764,11 +868,15 @@ async function resolvePluginConfig() {
|
|
|
764
868
|
resolvedPluginId = fallback.id;
|
|
765
869
|
resolvedPluginKind = fallback.kind;
|
|
766
870
|
resolvedPluginSlot = fallback.slot;
|
|
767
|
-
resolvedFilesRequired = fallback.required;
|
|
768
|
-
resolvedFilesOptional = fallback.optional;
|
|
769
|
-
resolvedNpmOmitDev = true;
|
|
770
|
-
|
|
771
|
-
|
|
871
|
+
resolvedFilesRequired = fallback.required;
|
|
872
|
+
resolvedFilesOptional = fallback.optional;
|
|
873
|
+
resolvedNpmOmitDev = true;
|
|
874
|
+
resolvedNpmBuild = false;
|
|
875
|
+
resolvedNpmBuildMinOpenclawVersion = DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION;
|
|
876
|
+
resolvedNpmBuildScript = "build";
|
|
877
|
+
resolvedNpmPruneAfterBuild = true;
|
|
878
|
+
|
|
879
|
+
// If no compatVer from package.json, try main branch manifest
|
|
772
880
|
if (!compatVer && PLUGIN_VERSION !== "main") {
|
|
773
881
|
const mainRaw = `https://raw.githubusercontent.com/${REPO}/main`;
|
|
774
882
|
const mainManifest = await tryFetch(`${mainRaw}/examples/openclaw-plugin/install-manifest.json`);
|
|
@@ -783,7 +891,7 @@ async function resolvePluginConfig() {
|
|
|
783
891
|
}
|
|
784
892
|
}
|
|
785
893
|
|
|
786
|
-
resolvedMinOpenclawVersion = compatVer || "2026.3.7";
|
|
894
|
+
resolvedMinOpenclawVersion = compatVer || fallback.minOpenclawVersion || "2026.3.7";
|
|
787
895
|
resolvedMinOpenvikingVersion = "";
|
|
788
896
|
}
|
|
789
897
|
|
|
@@ -799,11 +907,12 @@ async function checkOpenClawCompatibility() {
|
|
|
799
907
|
return;
|
|
800
908
|
}
|
|
801
909
|
|
|
802
|
-
const ocVersion = await detectOpenClawVersion();
|
|
803
|
-
info(tr(`Detected OpenClaw version: ${ocVersion}`, `检测到 OpenClaw 版本: ${ocVersion}`));
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
910
|
+
const ocVersion = await detectOpenClawVersion();
|
|
911
|
+
info(tr(`Detected OpenClaw version: ${ocVersion}`, `检测到 OpenClaw 版本: ${ocVersion}`));
|
|
912
|
+
applyOpenClawBuildPolicy(ocVersion);
|
|
913
|
+
|
|
914
|
+
// If no minimum version required, pass
|
|
915
|
+
if (!resolvedMinOpenclawVersion) {
|
|
807
916
|
return;
|
|
808
917
|
}
|
|
809
918
|
|
|
@@ -1309,7 +1418,7 @@ async function prepareStrongPluginUpgrade() {
|
|
|
1309
1418
|
info(tr(`Upgrade audit file: ${getUpgradeAuditPath()}`, `升级审计文件: ${getUpgradeAuditPath()}`));
|
|
1310
1419
|
}
|
|
1311
1420
|
|
|
1312
|
-
async function downloadPluginFile(destDir, fileName, url, required, index, total) {
|
|
1421
|
+
async function downloadPluginFile(destDir, fileName, url, required, index, total) {
|
|
1313
1422
|
const maxRetries = 3;
|
|
1314
1423
|
const destPath = join(destDir, fileName);
|
|
1315
1424
|
|
|
@@ -1369,12 +1478,109 @@ async function downloadPluginFile(destDir, fileName, url, required, index, total
|
|
|
1369
1478
|
|
|
1370
1479
|
console.log("");
|
|
1371
1480
|
err(tr(`Download failed after ${maxRetries} retries: ${url}`, `下载失败(已重试 ${maxRetries} 次): ${url}`));
|
|
1372
|
-
process.exit(1);
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
const
|
|
1377
|
-
|
|
1481
|
+
process.exit(1);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
function runtimeOutputCandidatesForEntry(entry) {
|
|
1485
|
+
const normalized = String(entry || "").replace(/\\/g, "/").replace(/^\.\//, "");
|
|
1486
|
+
if (!normalized.endsWith(".ts")) {
|
|
1487
|
+
return [];
|
|
1488
|
+
}
|
|
1489
|
+
const withoutExt = normalized.slice(0, -3);
|
|
1490
|
+
return [
|
|
1491
|
+
`dist/${withoutExt}.js`,
|
|
1492
|
+
`dist/${withoutExt}.mjs`,
|
|
1493
|
+
`dist/${withoutExt}.cjs`,
|
|
1494
|
+
`${withoutExt}.js`,
|
|
1495
|
+
`${withoutExt}.mjs`,
|
|
1496
|
+
`${withoutExt}.cjs`,
|
|
1497
|
+
];
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
async function assertBuiltRuntimeOutputs(destDir) {
|
|
1501
|
+
let pkg = null;
|
|
1502
|
+
try {
|
|
1503
|
+
pkg = JSON.parse(await readFile(join(destDir, "package.json"), "utf8"));
|
|
1504
|
+
} catch {
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
const entries = [];
|
|
1509
|
+
const extensions = pkg?.openclaw?.extensions;
|
|
1510
|
+
if (Array.isArray(extensions)) {
|
|
1511
|
+
for (const entry of extensions) {
|
|
1512
|
+
if (typeof entry === "string") entries.push(entry);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
if (typeof pkg?.openclaw?.setupEntry === "string") {
|
|
1516
|
+
entries.push(pkg.openclaw.setupEntry);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
const missing = [];
|
|
1520
|
+
for (const entry of entries) {
|
|
1521
|
+
const candidates = runtimeOutputCandidatesForEntry(entry);
|
|
1522
|
+
if (candidates.length === 0) continue;
|
|
1523
|
+
const found = candidates.some((candidate) => existsSync(join(destDir, ...candidate.split("/"))));
|
|
1524
|
+
if (!found) {
|
|
1525
|
+
missing.push(`${entry} (expected one of: ${candidates.join(", ")})`);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
if (missing.length === 0) {
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
err(tr(
|
|
1534
|
+
`Plugin build did not create required runtime output:\n - ${missing.join("\n - ")}`,
|
|
1535
|
+
`插件构建未生成必需的运行时产物:\n - ${missing.join("\n - ")}`,
|
|
1536
|
+
));
|
|
1537
|
+
process.exit(1);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
async function installPluginNpmDependencies(destDir) {
|
|
1541
|
+
if (!resolvedNpmBuild) {
|
|
1542
|
+
info(tr("Installing plugin npm dependencies...", "正在安装插件 npm 依赖..."));
|
|
1543
|
+
const npmArgs = resolvedNpmOmitDev
|
|
1544
|
+
? ["install", "--omit=dev", "--no-audit", "--no-fund", "--registry", NPM_REGISTRY]
|
|
1545
|
+
: ["install", "--no-audit", "--no-fund", "--registry", NPM_REGISTRY];
|
|
1546
|
+
await run("npm", npmArgs, { cwd: destDir, silent: false });
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
info(tr(
|
|
1551
|
+
"Installing plugin npm dependencies for source build...",
|
|
1552
|
+
"正在安装插件源码构建所需的 npm 依赖...",
|
|
1553
|
+
));
|
|
1554
|
+
await run("npm", [
|
|
1555
|
+
"install",
|
|
1556
|
+
"--include=dev",
|
|
1557
|
+
"--no-audit",
|
|
1558
|
+
"--no-fund",
|
|
1559
|
+
"--registry",
|
|
1560
|
+
NPM_REGISTRY,
|
|
1561
|
+
], { cwd: destDir, silent: false });
|
|
1562
|
+
|
|
1563
|
+
info(tr(
|
|
1564
|
+
`Building plugin runtime output with npm run ${resolvedNpmBuildScript}...`,
|
|
1565
|
+
`正在执行 npm run ${resolvedNpmBuildScript} 构建插件运行时产物...`,
|
|
1566
|
+
));
|
|
1567
|
+
await run("npm", ["run", resolvedNpmBuildScript], { cwd: destDir, silent: false });
|
|
1568
|
+
await assertBuiltRuntimeOutputs(destDir);
|
|
1569
|
+
|
|
1570
|
+
if (resolvedNpmOmitDev && resolvedNpmPruneAfterBuild) {
|
|
1571
|
+
info(tr("Pruning plugin dev dependencies...", "正在裁剪插件开发依赖..."));
|
|
1572
|
+
await run("npm", [
|
|
1573
|
+
"prune",
|
|
1574
|
+
"--omit=dev",
|
|
1575
|
+
"--no-audit",
|
|
1576
|
+
"--no-fund",
|
|
1577
|
+
], { cwd: destDir, silent: false });
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
async function downloadPlugin(destDir) {
|
|
1582
|
+
const ghRaw = `https://raw.githubusercontent.com/${REPO}/${PLUGIN_VERSION}`;
|
|
1583
|
+
const pluginDir = resolvedPluginDir;
|
|
1378
1584
|
const total = resolvedFilesRequired.length + resolvedFilesOptional.length;
|
|
1379
1585
|
|
|
1380
1586
|
await mkdir(destDir, { recursive: true });
|
|
@@ -1398,14 +1604,9 @@ async function downloadPlugin(destDir) {
|
|
|
1398
1604
|
await downloadPluginFile(destDir, name, url, false, i, total);
|
|
1399
1605
|
}
|
|
1400
1606
|
|
|
1401
|
-
|
|
1402
|
-
info(tr(
|
|
1403
|
-
|
|
1404
|
-
? ["install", "--omit=dev", "--no-audit", "--no-fund", "--registry", NPM_REGISTRY]
|
|
1405
|
-
: ["install", "--no-audit", "--no-fund", "--registry", NPM_REGISTRY];
|
|
1406
|
-
await run("npm", npmArgs, { cwd: destDir, silent: false });
|
|
1407
|
-
info(tr(`Plugin deployed: ${PLUGIN_DEST}`, `插件部署完成: ${PLUGIN_DEST}`));
|
|
1408
|
-
}
|
|
1607
|
+
await installPluginNpmDependencies(destDir);
|
|
1608
|
+
info(tr(`Plugin deployed: ${PLUGIN_DEST}`, `插件部署完成: ${PLUGIN_DEST}`));
|
|
1609
|
+
}
|
|
1409
1610
|
|
|
1410
1611
|
async function createPluginStagingDir() {
|
|
1411
1612
|
const pluginId = resolvedPluginId || "openviking";
|
|
@@ -1730,11 +1931,9 @@ async function configureOpenClawPlugin({
|
|
|
1730
1931
|
}
|
|
1731
1932
|
} catch { /* ignore read errors */ }
|
|
1732
1933
|
|
|
1733
|
-
let setupResult = null;
|
|
1734
|
-
if (setupJsonSupported) {
|
|
1735
|
-
const setupArgs =
|
|
1736
|
-
? ["--workdir", OPENCLAW_DIR, "openviking", "setup"]
|
|
1737
|
-
: ["openviking", "setup"];
|
|
1934
|
+
let setupResult = null;
|
|
1935
|
+
if (setupJsonSupported) {
|
|
1936
|
+
const setupArgs = ["openviking", "setup"];
|
|
1738
1937
|
setupArgs.push("--base-url", effectiveRuntimeConfig.baseUrl || remoteBaseUrl);
|
|
1739
1938
|
setupArgs.push("--json");
|
|
1740
1939
|
if (effectiveRuntimeConfig.apiKey) {
|
|
@@ -1769,14 +1968,10 @@ async function configureOpenClawPlugin({
|
|
|
1769
1968
|
));
|
|
1770
1969
|
}
|
|
1771
1970
|
|
|
1772
|
-
let parsed = null;
|
|
1773
|
-
if (setupResult) {
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
} catch {
|
|
1777
|
-
// If JSON parse fails, fall back to checking exit code
|
|
1778
|
-
}
|
|
1779
|
-
}
|
|
1971
|
+
let parsed = null;
|
|
1972
|
+
if (setupResult) {
|
|
1973
|
+
parsed = parseJsonObjectFromOutput(`${setupResult.out || ""}\n${setupResult.err || ""}`);
|
|
1974
|
+
}
|
|
1780
1975
|
|
|
1781
1976
|
if (parsed) {
|
|
1782
1977
|
if (parsed.success) {
|