openclaw-openviking-setup-helper 0.3.0 → 0.3.1

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 +635 -191
  2. package/package.json +1 -1
package/install.js CHANGED
@@ -9,29 +9,34 @@
9
9
  * ov-install
10
10
  * openclaw-openviking-install
11
11
  *
12
- * Direct run:
13
- * node install.js [ --base-url URL ] [ --api-key KEY ] [ --zh ] [ --workdir PATH ] [ --upgrade-plugin ]
14
- * [ --plugin-version=TAG ]
15
- *
16
- * Environment variables:
17
- * REPO, PLUGIN_VERSION (or BRANCH), OPENVIKING_BASE_URL, OPENVIKING_API_KEY, SKIP_OPENCLAW
18
- * NPM_REGISTRY
19
- */
12
+ * Direct run:
13
+ * node install.js [ --base-url URL ] [ --api-key KEY ] [ --zh ] [ --workdir PATH ] [ --upgrade-plugin ]
14
+ * [ --plugin-version=VERSION ] [ --plugin-source=npm|github ]
15
+ *
16
+ * Environment variables:
17
+ * PLUGIN_SOURCE, PLUGIN_NPM_PACKAGE, REPO, PLUGIN_VERSION (or BRANCH),
18
+ * OPENVIKING_BASE_URL, OPENVIKING_API_KEY, SKIP_OPENCLAW, NPM_REGISTRY
19
+ */
20
20
 
21
21
  import { spawn } from "node:child_process";
22
- import { cp, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
23
- import { existsSync, readdirSync } from "node:fs";
24
- import { basename, dirname, join } from "node:path";
25
- import { createInterface } from "node:readline";
26
- import { fileURLToPath } from "node:url";
22
+ import { cp, mkdir, mkdtemp, readFile, rename, rm, writeFile } from "node:fs/promises";
23
+ import { existsSync, readdirSync } from "node:fs";
24
+ import { basename, dirname, join } from "node:path";
25
+ import { tmpdir } from "node:os";
26
+ import { createInterface } from "node:readline";
27
+ import { fileURLToPath } from "node:url";
27
28
 
28
29
  const __dirname = dirname(fileURLToPath(import.meta.url));
29
30
 
30
- let REPO = process.env.REPO || "volcengine/OpenViking";
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);
31
+ let REPO = process.env.REPO || "volcengine/OpenViking";
32
+ const DEFAULT_PLUGIN_NPM_PACKAGE = "@openviking/openclaw-plugin";
33
+ let pluginNpmPackage = (process.env.PLUGIN_NPM_PACKAGE || DEFAULT_PLUGIN_NPM_PACKAGE).trim();
34
+ let pluginSource = (process.env.PLUGIN_SOURCE || "npm").trim().toLowerCase();
35
+ let pluginSourceExplicit = Boolean(process.env.PLUGIN_SOURCE);
36
+ // PLUGIN_VERSION takes precedence over BRANCH (legacy). If omitted, resolve the latest npm dist-tag or GitHub tag.
37
+ const pluginVersionEnv = (process.env.PLUGIN_VERSION || process.env.BRANCH || "").trim();
38
+ let PLUGIN_VERSION = pluginVersionEnv;
39
+ let pluginVersionExplicit = Boolean(pluginVersionEnv);
35
40
  const NPM_REGISTRY = process.env.NPM_REGISTRY || "https://registry.npmmirror.com";
36
41
  const DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION = "2026.5.3";
37
42
  const OPENCLAW_SHORT_VERSION_YEAR = 2026;
@@ -97,17 +102,21 @@ let resolvedNpmBuildMinOpenclawVersion = DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION;
97
102
  let resolvedNpmBuildScript = "build";
98
103
  let resolvedNpmPruneAfterBuild = true;
99
104
  let resolvedMinOpenclawVersion = "";
100
- let resolvedMinOpenvikingVersion = "";
101
- let resolvedPluginReleaseId = "";
102
- let detectedOpenClawVersion = "";
105
+ let resolvedMinOpenvikingVersion = "";
106
+ let resolvedPluginReleaseId = "";
107
+ let detectedOpenClawVersion = "";
108
+ let npmPackageTempDir = "";
109
+ let npmPackageExtractDir = "";
103
110
 
104
111
  let nonInteractive = false;
105
112
  let langZh = false;
106
113
  let workdirExplicit = false;
107
114
  let upgradePluginOnly = false;
108
115
  let rollbackLastUpgrade = false;
109
- let showCurrentVersion = false;
110
- let uninstallPlugin = false;
116
+ let showCurrentVersion = false;
117
+ let uninstallPlugin = false;
118
+ let forceSlotExplicit = false;
119
+ let allowOfflineExplicit = false;
111
120
 
112
121
  const selectedMode = "remote";
113
122
  const baseUrlFromEnv = !!process.env.OPENVIKING_BASE_URL;
@@ -147,11 +156,19 @@ for (let i = 0; i < argv.length; i++) {
147
156
  rollbackLastUpgrade = true;
148
157
  continue;
149
158
  }
150
- if (arg === "--uninstall" || arg === "--remove") {
151
- uninstallPlugin = true;
152
- continue;
153
- }
154
- if (arg === "--workdir") {
159
+ if (arg === "--uninstall" || arg === "--remove") {
160
+ uninstallPlugin = true;
161
+ continue;
162
+ }
163
+ if (arg === "--force-slot") {
164
+ forceSlotExplicit = true;
165
+ continue;
166
+ }
167
+ if (arg === "--allow-offline") {
168
+ allowOfflineExplicit = true;
169
+ continue;
170
+ }
171
+ if (arg === "--workdir") {
155
172
  const workdir = argv[i + 1]?.trim();
156
173
  if (!workdir) {
157
174
  console.error("--workdir requires a path");
@@ -168,35 +185,81 @@ for (let i = 0; i < argv.length; i++) {
168
185
  console.error("--plugin-version requires a value");
169
186
  process.exit(1);
170
187
  }
171
- PLUGIN_VERSION = version;
172
- pluginVersionExplicit = true;
173
- continue;
174
- }
188
+ PLUGIN_VERSION = version;
189
+ pluginVersionExplicit = true;
190
+ continue;
191
+ }
175
192
  if (arg === "--plugin-version") {
176
193
  const version = argv[i + 1]?.trim();
177
194
  if (!version) {
178
195
  console.error("--plugin-version requires a value");
179
196
  process.exit(1);
180
197
  }
181
- PLUGIN_VERSION = version;
182
- pluginVersionExplicit = true;
183
- i += 1;
184
- continue;
185
- }
186
- if (arg.startsWith("--github-repo=")) {
187
- REPO = arg.slice("--github-repo=".length).trim();
188
- continue;
189
- }
190
- if (arg === "--github-repo") {
198
+ PLUGIN_VERSION = version;
199
+ pluginVersionExplicit = true;
200
+ i += 1;
201
+ continue;
202
+ }
203
+ if (arg.startsWith("--github-repo=")) {
204
+ REPO = arg.slice("--github-repo=".length).trim();
205
+ if (!pluginSourceExplicit) {
206
+ pluginSource = "github";
207
+ }
208
+ continue;
209
+ }
210
+ if (arg === "--github-repo") {
191
211
  const repo = argv[i + 1]?.trim();
192
212
  if (!repo) {
193
213
  console.error("--github-repo requires a value (e.g. owner/repo)");
194
214
  process.exit(1);
195
- }
196
- REPO = repo;
197
- i += 1;
198
- continue;
199
- }
215
+ }
216
+ REPO = repo;
217
+ if (!pluginSourceExplicit) {
218
+ pluginSource = "github";
219
+ }
220
+ i += 1;
221
+ continue;
222
+ }
223
+ if (arg.startsWith("--plugin-source=") || arg.startsWith("--source=")) {
224
+ const value = arg.includes("--plugin-source=")
225
+ ? arg.slice("--plugin-source=".length).trim()
226
+ : arg.slice("--source=".length).trim();
227
+ pluginSource = value.toLowerCase();
228
+ pluginSourceExplicit = true;
229
+ continue;
230
+ }
231
+ if (arg === "--plugin-source" || arg === "--source") {
232
+ const value = argv[i + 1]?.trim();
233
+ if (!value) {
234
+ console.error(`${arg} requires a value (npm or github)`);
235
+ process.exit(1);
236
+ }
237
+ pluginSource = value.toLowerCase();
238
+ pluginSourceExplicit = true;
239
+ i += 1;
240
+ continue;
241
+ }
242
+ if (arg.startsWith("--plugin-package=") || arg.startsWith("--npm-package=")) {
243
+ const value = arg.includes("--plugin-package=")
244
+ ? arg.slice("--plugin-package=".length).trim()
245
+ : arg.slice("--npm-package=".length).trim();
246
+ if (!value) {
247
+ console.error("--plugin-package requires a package name");
248
+ process.exit(1);
249
+ }
250
+ pluginNpmPackage = value;
251
+ continue;
252
+ }
253
+ if (arg === "--plugin-package" || arg === "--npm-package") {
254
+ const value = argv[i + 1]?.trim();
255
+ if (!value) {
256
+ console.error(`${arg} requires a package name`);
257
+ process.exit(1);
258
+ }
259
+ pluginNpmPackage = value;
260
+ i += 1;
261
+ continue;
262
+ }
200
263
  if (arg === "--base-url") {
201
264
  const val = argv[i + 1]?.trim();
202
265
  if (!val) { console.error("--base-url requires a URL"); process.exit(1); }
@@ -268,10 +331,13 @@ function setOpenClawDir(dir) {
268
331
 
269
332
  function printHelp() {
270
333
  console.log("Usage: node install.js [ OPTIONS ]");
271
- console.log("");
272
- console.log("Options:");
273
- console.log(" --github-repo=OWNER/REPO GitHub repository (default: volcengine/OpenViking)");
274
- console.log(" --plugin-version=TAG Plugin version (Git tag, e.g. v0.2.9, default: latest tag)");
334
+ console.log("");
335
+ console.log("Options:");
336
+ console.log(" --plugin-source=npm|github");
337
+ console.log(" Plugin download source (default: npm)");
338
+ console.log(" --plugin-package=NAME npm plugin package (default: @openviking/openclaw-plugin)");
339
+ console.log(" --github-repo=OWNER/REPO GitHub repository (implies --plugin-source=github unless source is set)");
340
+ console.log(" --plugin-version=VERSION Plugin version (npm version/tag or Git tag; default: npm latest)");
275
341
  console.log(" --workdir PATH OpenClaw config directory (default: ~/.openclaw)");
276
342
  console.log(" --current-version Print installed plugin version and exit");
277
343
  console.log(" --update, --upgrade-plugin");
@@ -282,9 +348,11 @@ function printHelp() {
282
348
  console.log(" --base-url=URL OpenViking server URL (default: $OPENVIKING_BASE_URL or http://127.0.0.1:1933)");
283
349
  console.log(" --api-key=KEY OpenViking API key (default: $OPENVIKING_API_KEY)");
284
350
  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(" --zh Chinese prompts");
351
+ console.log(" --account-id=ID Account ID for root API key (default: $OPENVIKING_ACCOUNT_ID)");
352
+ console.log(" --user-id=ID User ID for root API key (default: $OPENVIKING_USER_ID)");
353
+ console.log(" --force-slot Explicitly replace an existing contextEngine slot owner");
354
+ console.log(" --allow-offline Explicitly save config when the OpenViking server is unreachable");
355
+ console.log(" --zh Chinese prompts");
288
356
  console.log(" -h, --help This help");
289
357
  console.log("");
290
358
  console.log("Examples:");
@@ -294,11 +362,11 @@ function printHelp() {
294
362
  console.log(" # Show installed versions");
295
363
  console.log(" node install.js --current-version");
296
364
  console.log("");
297
- console.log(" # Install a specific release version");
298
- console.log(" node install.js --plugin-version=v0.2.9");
299
- console.log("");
300
- console.log(" # Install from a fork repository");
301
- console.log(" node install.js --github-repo=yourname/OpenViking --plugin-version=dev-branch");
365
+ console.log(" # Install a specific release version");
366
+ console.log(" node install.js --plugin-version=2026.5.8");
367
+ console.log("");
368
+ console.log(" # Install from a fork repository");
369
+ console.log(" node install.js --github-repo=yourname/OpenViking --plugin-version=dev-branch");
302
370
  console.log("");
303
371
  console.log(" # Install specific plugin version");
304
372
  console.log(" node install.js --plugin-version=v0.2.8");
@@ -309,8 +377,8 @@ function printHelp() {
309
377
  console.log(" # Roll back the last plugin upgrade");
310
378
  console.log(" node install.js --rollback");
311
379
  console.log("");
312
- console.log("Env: REPO, PLUGIN_VERSION, SKIP_OPENCLAW, NPM_REGISTRY");
313
- }
380
+ console.log("Env: PLUGIN_SOURCE, PLUGIN_NPM_PACKAGE, REPO, PLUGIN_VERSION, SKIP_OPENCLAW, NPM_REGISTRY");
381
+ }
314
382
 
315
383
  function formatCliArg(value) {
316
384
  if (!value) {
@@ -403,18 +471,23 @@ function runCapture(cmd, args, opts = {}) {
403
471
  });
404
472
  }
405
473
 
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) => {
474
+ function question(prompt, defaultValue = "") {
475
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
476
+ const suffix = defaultValue ? ` [${defaultValue}]` : "";
477
+ return new Promise((resolve) => {
478
+ rl.question(`${prompt}${suffix}: `, (answer) => {
411
479
  rl.close();
412
480
  resolve((answer ?? defaultValue).trim() || defaultValue);
413
481
  });
414
- });
415
- }
416
-
417
- function isValidAgentPrefixInput(value) {
482
+ });
483
+ }
484
+
485
+ function isYes(answer) {
486
+ const normalized = String(answer || "").trim().toLowerCase();
487
+ return normalized === "y" || normalized === "yes";
488
+ }
489
+
490
+ function isValidAgentPrefixInput(value) {
418
491
  const trimmed = String(value || "").trim();
419
492
  return !trimmed || /^[a-zA-Z0-9_-]+$/.test(trimmed);
420
493
  }
@@ -606,13 +679,30 @@ if (upgradePluginOnly && rollbackLastUpgrade) {
606
679
  process.exit(1);
607
680
  }
608
681
 
609
- if (uninstallPlugin && (upgradePluginOnly || rollbackLastUpgrade)) {
610
- console.error("--uninstall cannot be used with --upgrade-plugin or --rollback");
611
- process.exit(1);
612
- }
613
-
614
- // Detect OpenClaw version
615
- async function detectOpenClawVersion() {
682
+ if (uninstallPlugin && (upgradePluginOnly || rollbackLastUpgrade)) {
683
+ console.error("--uninstall cannot be used with --upgrade-plugin or --rollback");
684
+ process.exit(1);
685
+ }
686
+
687
+ if (!["npm", "github"].includes(pluginSource)) {
688
+ console.error("--plugin-source must be either npm or github");
689
+ process.exit(1);
690
+ }
691
+
692
+ function looksLikeLegacyGitHubRef(value) {
693
+ const ref = String(value || "").trim();
694
+ if (!ref) return false;
695
+ if (/^v\d+(\.\d+){1,2}([-.].*)?$/i.test(ref)) return true;
696
+ if (["main", "master"].includes(ref.toLowerCase())) return true;
697
+ return false;
698
+ }
699
+
700
+ if (!pluginSourceExplicit && pluginVersionExplicit && looksLikeLegacyGitHubRef(PLUGIN_VERSION)) {
701
+ pluginSource = "github";
702
+ }
703
+
704
+ // Detect OpenClaw version
705
+ async function detectOpenClawVersion() {
616
706
  if (detectedOpenClawVersion) {
617
707
  return detectedOpenClawVersion;
618
708
  }
@@ -664,10 +754,10 @@ function compareSemverDesc(a, b) {
664
754
  return versionGte(a, b) ? -1 : 1;
665
755
  }
666
756
 
667
- function pickLatestPluginTag(tagNames) {
668
- const normalized = tagNames
669
- .map((tag) => String(tag ?? "").trim())
670
- .filter(Boolean);
757
+ function pickLatestPluginTag(tagNames) {
758
+ const normalized = tagNames
759
+ .map((tag) => String(tag ?? "").trim())
760
+ .filter(Boolean);
671
761
 
672
762
  const semverTags = normalized
673
763
  .filter((tag) => isSemverLike(tag))
@@ -676,9 +766,118 @@ function pickLatestPluginTag(tagNames) {
676
766
  if (semverTags.length > 0) {
677
767
  return semverTags[0];
678
768
  }
679
-
680
- return normalized[0] || "";
681
- }
769
+
770
+ return normalized[0] || "";
771
+ }
772
+
773
+ function npmPackageSpec(version = PLUGIN_VERSION) {
774
+ return version ? `${pluginNpmPackage}@${version}` : pluginNpmPackage;
775
+ }
776
+
777
+ function parseNpmJsonOutput(output) {
778
+ const text = String(output || "").trim();
779
+ if (!text) return null;
780
+ try {
781
+ return JSON.parse(text);
782
+ } catch {
783
+ const firstArray = text.indexOf("[");
784
+ const lastArray = text.lastIndexOf("]");
785
+ if (firstArray >= 0 && lastArray > firstArray) {
786
+ try {
787
+ return JSON.parse(text.slice(firstArray, lastArray + 1));
788
+ } catch {}
789
+ }
790
+ const firstObject = text.indexOf("{");
791
+ const lastObject = text.lastIndexOf("}");
792
+ if (firstObject >= 0 && lastObject > firstObject) {
793
+ try {
794
+ return JSON.parse(text.slice(firstObject, lastObject + 1));
795
+ } catch {}
796
+ }
797
+ }
798
+ return null;
799
+ }
800
+
801
+ async function resolveDefaultPluginVersionFromNpm() {
802
+ info(tr(
803
+ `No plugin version specified; resolving latest npm version from ${pluginNpmPackage}...`,
804
+ `No plugin version specified; resolving latest npm version from ${pluginNpmPackage}...`,
805
+ ));
806
+
807
+ const result = await runCapture("npm", [
808
+ "view",
809
+ `${pluginNpmPackage}@latest`,
810
+ "version",
811
+ "--json",
812
+ "--registry",
813
+ NPM_REGISTRY,
814
+ ], { shell: IS_WIN });
815
+
816
+ if (result.code === 0) {
817
+ const parsed = parseNpmJsonOutput(result.out);
818
+ const version = typeof parsed === "string" ? parsed : String(result.out || "").trim().replace(/^"|"$/g, "");
819
+ if (version) {
820
+ PLUGIN_VERSION = version;
821
+ info(tr(
822
+ `Resolved default plugin version to npm latest: ${PLUGIN_VERSION}`,
823
+ `Resolved default plugin version to npm latest: ${PLUGIN_VERSION}`,
824
+ ));
825
+ return true;
826
+ }
827
+ }
828
+
829
+ warn(tr(
830
+ `Could not resolve npm latest for ${pluginNpmPackage}${result.err ? `: ${result.err}` : ""}`,
831
+ `Could not resolve npm latest for ${pluginNpmPackage}${result.err ? `: ${result.err}` : ""}`,
832
+ ));
833
+ return false;
834
+ }
835
+
836
+ async function ensureNpmPackageExtracted() {
837
+ if (npmPackageExtractDir && existsSync(npmPackageExtractDir)) {
838
+ return npmPackageExtractDir;
839
+ }
840
+
841
+ npmPackageTempDir = await mkdtemp(join(tmpdir(), "ov-plugin-npm-"));
842
+ info(tr(
843
+ `Downloading plugin package from npm: ${npmPackageSpec()}`,
844
+ `Downloading plugin package from npm: ${npmPackageSpec()}`,
845
+ ));
846
+
847
+ const packResult = await runCapture("npm", [
848
+ "pack",
849
+ npmPackageSpec(),
850
+ "--pack-destination",
851
+ npmPackageTempDir,
852
+ "--json",
853
+ "--registry",
854
+ NPM_REGISTRY,
855
+ ], { shell: IS_WIN });
856
+
857
+ if (packResult.code !== 0) {
858
+ throw new Error(`npm pack failed for ${npmPackageSpec()}${packResult.err ? `: ${packResult.err}` : ""}`);
859
+ }
860
+
861
+ const parsed = parseNpmJsonOutput(packResult.out);
862
+ const first = Array.isArray(parsed) ? parsed[0] : parsed;
863
+ const filename = first?.filename || readdirSync(npmPackageTempDir).find((name) => name.endsWith(".tgz"));
864
+ if (!filename) {
865
+ throw new Error(`npm pack did not produce a tarball for ${npmPackageSpec()}`);
866
+ }
867
+
868
+ const tarballPath = join(npmPackageTempDir, filename);
869
+ const extractRoot = join(npmPackageTempDir, "extract");
870
+ await mkdir(extractRoot, { recursive: true });
871
+ await run("tar", ["-xzf", tarballPath, "-C", extractRoot], { silent: true, shell: IS_WIN });
872
+
873
+ const packageDir = join(extractRoot, "package");
874
+ if (!existsSync(packageDir)) {
875
+ throw new Error(`npm package ${npmPackageSpec()} did not contain the expected package directory`);
876
+ }
877
+
878
+ npmPackageExtractDir = packageDir;
879
+ return npmPackageExtractDir;
880
+ }
682
881
 
683
882
  function parseGitLsRemoteTags(output) {
684
883
  return String(output ?? "")
@@ -690,13 +889,23 @@ function parseGitLsRemoteTags(output) {
690
889
  .filter(Boolean);
691
890
  }
692
891
 
693
- async function resolveDefaultPluginVersion() {
694
- if (PLUGIN_VERSION) {
695
- return;
696
- }
697
-
698
- info(tr(
699
- `No plugin version specified; resolving latest tag from ${REPO}...`,
892
+ async function resolveDefaultPluginVersion() {
893
+ if (PLUGIN_VERSION) {
894
+ return;
895
+ }
896
+
897
+ if (pluginSource === "npm") {
898
+ if (await resolveDefaultPluginVersionFromNpm()) {
899
+ return;
900
+ }
901
+ warn(tr(
902
+ "Falling back to GitHub tag resolution.",
903
+ "Falling back to GitHub tag resolution.",
904
+ ));
905
+ }
906
+
907
+ info(tr(
908
+ `No plugin version specified; resolving latest tag from ${REPO}...`,
700
909
  `未指定插件版本,正在解析 ${REPO} 的最新 tag...`,
701
910
  ));
702
911
 
@@ -768,12 +977,117 @@ async function resolveDefaultPluginVersion() {
768
977
  if (failures.length > 0) {
769
978
  warn(failures.join(" | "));
770
979
  }
771
- process.exit(1);
772
- }
773
-
774
- // Resolve plugin configuration from manifest or fallback
775
- async function resolvePluginConfig() {
776
- const ghRaw = `https://raw.githubusercontent.com/${REPO}/${PLUGIN_VERSION}`;
980
+ process.exit(1);
981
+ }
982
+
983
+ function applyManifestConfig(manifestData) {
984
+ resolvedPluginId = manifestData.plugin?.id || "";
985
+ resolvedPluginKind = manifestData.plugin?.kind || "";
986
+ resolvedPluginSlot = manifestData.plugin?.slot || "";
987
+ resolvedMinOpenclawVersion = manifestData.compatibility?.minOpenclawVersion || "";
988
+ resolvedMinOpenvikingVersion = manifestData.compatibility?.minOpenvikingVersion || "";
989
+ resolvedPluginReleaseId = manifestData.pluginVersion || manifestData.release?.id || "";
990
+ const npmConfig = manifestData.npm && typeof manifestData.npm === "object"
991
+ ? manifestData.npm
992
+ : {};
993
+ resolvedNpmOmitDev = npmConfig.omitDev !== false;
994
+ resolvedNpmBuild = npmConfig.build === true || npmConfig.buildFromSource === true;
995
+ resolvedNpmBuildMinOpenclawVersion =
996
+ typeof npmConfig.buildMinOpenclawVersion === "string" && npmConfig.buildMinOpenclawVersion.trim()
997
+ ? npmConfig.buildMinOpenclawVersion.trim()
998
+ : DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION;
999
+ resolvedNpmBuildScript = typeof npmConfig.buildScript === "string" && npmConfig.buildScript.trim()
1000
+ ? npmConfig.buildScript.trim()
1001
+ : "build";
1002
+ resolvedNpmPruneAfterBuild = npmConfig.pruneAfterBuild !== false;
1003
+ resolvedFilesRequired = manifestData.files?.required || [];
1004
+ resolvedFilesOptional = manifestData.files?.optional || [];
1005
+ }
1006
+
1007
+ function hasPrebuiltRuntimeOutputs(packageDir) {
1008
+ return existsSync(join(packageDir, "dist", "index.js"));
1009
+ }
1010
+
1011
+ async function resolvePluginConfigFromNpm() {
1012
+ info(tr(
1013
+ `Resolving plugin configuration from npm package: ${npmPackageSpec()}`,
1014
+ `Resolving plugin configuration from npm package: ${npmPackageSpec()}`,
1015
+ ));
1016
+
1017
+ const packageDir = await ensureNpmPackageExtracted();
1018
+ const manifestPath = join(packageDir, "install-manifest.json");
1019
+ const packageJsonPath = join(packageDir, "package.json");
1020
+ let manifestData = null;
1021
+ let packageJson = null;
1022
+
1023
+ if (existsSync(packageJsonPath)) {
1024
+ try {
1025
+ packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
1026
+ resolvedPluginReleaseId = packageJson.version || "";
1027
+ } catch {}
1028
+ }
1029
+
1030
+ if (existsSync(manifestPath)) {
1031
+ try {
1032
+ manifestData = JSON.parse(await readFile(manifestPath, "utf8"));
1033
+ info(tr("Found manifest in npm package", "Found manifest in npm package"));
1034
+ } catch {}
1035
+ }
1036
+
1037
+ resolvedPluginDir = ".";
1038
+ if (manifestData) {
1039
+ applyManifestConfig(manifestData);
1040
+ } else {
1041
+ const pkgName = packageJson?.name || "";
1042
+ const fallback = pkgName && pkgName !== DEFAULT_PLUGIN_NPM_PACKAGE ? FALLBACK_LEGACY : FALLBACK_CURRENT;
1043
+ resolvedPluginId = fallback.id;
1044
+ resolvedPluginKind = fallback.kind;
1045
+ resolvedPluginSlot = fallback.slot;
1046
+ resolvedFilesRequired = fallback.required;
1047
+ resolvedFilesOptional = fallback.optional;
1048
+ resolvedNpmOmitDev = true;
1049
+ resolvedNpmBuild = false;
1050
+ resolvedNpmBuildMinOpenclawVersion = DEFAULT_NPM_BUILD_MIN_OPENCLAW_VERSION;
1051
+ resolvedNpmBuildScript = "build";
1052
+ resolvedNpmPruneAfterBuild = true;
1053
+ resolvedMinOpenclawVersion = (packageJson?.engines?.openclaw || "").replace(/^>=?\s*/, "").trim()
1054
+ || fallback.minOpenclawVersion
1055
+ || "2026.3.7";
1056
+ resolvedMinOpenvikingVersion = "";
1057
+ }
1058
+
1059
+ if (hasPrebuiltRuntimeOutputs(packageDir)) {
1060
+ resolvedNpmBuild = false;
1061
+ info(tr(
1062
+ "npm package contains prebuilt runtime output; skipping source build.",
1063
+ "npm package contains prebuilt runtime output; skipping source build.",
1064
+ ));
1065
+ }
1066
+
1067
+ PLUGIN_DEST = join(OPENCLAW_DIR, "extensions", resolvedPluginId || "openviking");
1068
+ info(tr(`Plugin: ${resolvedPluginId} (${resolvedPluginKind})`, `Plugin: ${resolvedPluginId} (${resolvedPluginKind})`));
1069
+ }
1070
+
1071
+ // Resolve plugin configuration from manifest or fallback
1072
+ async function resolvePluginConfig() {
1073
+ if (pluginSource === "npm") {
1074
+ try {
1075
+ await resolvePluginConfigFromNpm();
1076
+ return;
1077
+ } catch (error) {
1078
+ warn(tr(
1079
+ `npm plugin resolution failed: ${error?.message || error}`,
1080
+ `npm plugin resolution failed: ${error?.message || error}`,
1081
+ ));
1082
+ warn(tr(
1083
+ "Falling back to GitHub plugin download.",
1084
+ "Falling back to GitHub plugin download.",
1085
+ ));
1086
+ pluginSource = "github";
1087
+ }
1088
+ }
1089
+
1090
+ const ghRaw = `https://raw.githubusercontent.com/${REPO}/${PLUGIN_VERSION}`;
777
1091
 
778
1092
  info(tr(`Resolving plugin configuration for version: ${PLUGIN_VERSION}`, `正在解析插件配置,版本: ${PLUGIN_VERSION}`));
779
1093
 
@@ -1086,11 +1400,17 @@ function extractRuntimeConfigFromPluginEntry(entryConfig) {
1086
1400
  runtime.apiKey = entryConfig.apiKey;
1087
1401
  }
1088
1402
  const prefix = entryConfig.agent_prefix || entryConfig.agentId;
1089
- if (typeof prefix === "string" && prefix.trim()) {
1090
- runtime.agent_prefix = prefix.trim();
1091
- }
1092
- return runtime;
1093
- }
1403
+ if (typeof prefix === "string" && prefix.trim()) {
1404
+ runtime.agent_prefix = prefix.trim();
1405
+ }
1406
+ if (typeof entryConfig.accountId === "string" && entryConfig.accountId.trim()) {
1407
+ runtime.accountId = entryConfig.accountId.trim();
1408
+ }
1409
+ if (typeof entryConfig.userId === "string" && entryConfig.userId.trim()) {
1410
+ runtime.userId = entryConfig.userId.trim();
1411
+ }
1412
+ return runtime;
1413
+ }
1094
1414
 
1095
1415
  async function backupOpenClawConfig(configPath) {
1096
1416
  await mkdir(getUpgradeAuditDir(), { recursive: true });
@@ -1380,10 +1700,12 @@ async function prepareStrongPluginUpgrade() {
1380
1700
  `检测到已安装 OpenViking 插件状态: ${installedState.generation}`,
1381
1701
  ),
1382
1702
  );
1383
- remoteBaseUrl = upgradeRuntimeConfig.baseUrl || remoteBaseUrl;
1384
- remoteApiKey = upgradeRuntimeConfig.apiKey || "";
1385
- remoteAgentPrefix = upgradeRuntimeConfig.agent_prefix || "";
1386
- info(tr(`Upgrade runtime mode: ${selectedMode} (remote OpenViking server)`, `升级运行模式: ${selectedMode}(远程 OpenViking 服务)`));
1703
+ remoteBaseUrl = upgradeRuntimeConfig.baseUrl || remoteBaseUrl;
1704
+ remoteApiKey = upgradeRuntimeConfig.apiKey || "";
1705
+ remoteAgentPrefix = upgradeRuntimeConfig.agent_prefix || "";
1706
+ remoteAccountId = upgradeRuntimeConfig.accountId || "";
1707
+ remoteUserId = upgradeRuntimeConfig.userId || "";
1708
+ info(tr(`Upgrade runtime mode: ${selectedMode} (remote OpenViking server)`, `升级运行模式: ${selectedMode}(远程 OpenViking 服务)`));
1387
1709
 
1388
1710
  info(tr(`Upgrade path: ${fromVersion} -> ${toVersion}`, `升级路径: ${fromVersion} -> ${toVersion}`));
1389
1711
 
@@ -1537,7 +1859,7 @@ async function assertBuiltRuntimeOutputs(destDir) {
1537
1859
  process.exit(1);
1538
1860
  }
1539
1861
 
1540
- async function installPluginNpmDependencies(destDir) {
1862
+ async function installPluginNpmDependencies(destDir) {
1541
1863
  if (!resolvedNpmBuild) {
1542
1864
  info(tr("Installing plugin npm dependencies...", "正在安装插件 npm 依赖..."));
1543
1865
  const npmArgs = resolvedNpmOmitDev
@@ -1575,12 +1897,40 @@ async function installPluginNpmDependencies(destDir) {
1575
1897
  "--no-audit",
1576
1898
  "--no-fund",
1577
1899
  ], { 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;
1900
+ }
1901
+ }
1902
+
1903
+ async function copyNpmPackageToDest(destDir) {
1904
+ const packageDir = await ensureNpmPackageExtracted();
1905
+ await mkdir(destDir, { recursive: true });
1906
+ const entries = readdirSync(packageDir, { withFileTypes: true });
1907
+ for (const entry of entries) {
1908
+ await cp(join(packageDir, entry.name), join(destDir, entry.name), { recursive: true, force: true });
1909
+ }
1910
+ }
1911
+
1912
+ async function cleanupNpmPackageTemp() {
1913
+ if (!npmPackageTempDir) return;
1914
+ await rm(npmPackageTempDir, { recursive: true, force: true });
1915
+ npmPackageTempDir = "";
1916
+ npmPackageExtractDir = "";
1917
+ }
1918
+
1919
+ async function downloadPlugin(destDir) {
1920
+ if (pluginSource === "npm") {
1921
+ await mkdir(destDir, { recursive: true });
1922
+ info(tr(
1923
+ `Installing plugin from npm package ${npmPackageSpec()}...`,
1924
+ `Installing plugin from npm package ${npmPackageSpec()}...`,
1925
+ ));
1926
+ await copyNpmPackageToDest(destDir);
1927
+ await installPluginNpmDependencies(destDir);
1928
+ info(tr(`Plugin deployed: ${PLUGIN_DEST}`, `Plugin deployed: ${PLUGIN_DEST}`));
1929
+ return;
1930
+ }
1931
+
1932
+ const ghRaw = `https://raw.githubusercontent.com/${REPO}/${PLUGIN_VERSION}`;
1933
+ const pluginDir = resolvedPluginDir;
1584
1934
  const total = resolvedFilesRequired.length + resolvedFilesOptional.length;
1585
1935
 
1586
1936
  await mkdir(destDir, { recursive: true });
@@ -1637,16 +1987,18 @@ async function finalizePluginDeployment(stagingDir) {
1637
1987
  return info(tr(`Plugin deployed: ${PLUGIN_DEST}`, `插件部署完成: ${PLUGIN_DEST}`));
1638
1988
  }
1639
1989
 
1640
- async function deployPluginFromRemote() {
1641
- const stagingDir = await createPluginStagingDir();
1642
- try {
1643
- await downloadPlugin(stagingDir);
1644
- await finalizePluginDeployment(stagingDir);
1645
- } catch (error) {
1646
- await rm(stagingDir, { recursive: true, force: true });
1647
- throw error;
1648
- }
1649
- }
1990
+ async function deployPluginFromRemote() {
1991
+ const stagingDir = await createPluginStagingDir();
1992
+ try {
1993
+ await downloadPlugin(stagingDir);
1994
+ await finalizePluginDeployment(stagingDir);
1995
+ } catch (error) {
1996
+ await rm(stagingDir, { recursive: true, force: true });
1997
+ throw error;
1998
+ } finally {
1999
+ await cleanupNpmPackageTemp();
2000
+ }
2001
+ }
1650
2002
 
1651
2003
  /** Same as INSTALL*.md manual cleanup: stale entries block `plugins.slots.*` validation after reinstall. */
1652
2004
  function resolvedPluginSlotFallback() {
@@ -1768,6 +2120,53 @@ async function cleanupConflictingPluginVariants() {
1768
2120
  info(tr("Conflicting plugin variants cleaned up", "冲突的插件变体已清理"));
1769
2121
  }
1770
2122
 
2123
+ function normalizeOpenClawLoadPath(filePath) {
2124
+ return String(filePath || "")
2125
+ .replace(/\\/g, "/")
2126
+ .replace(/\/+$/g, "");
2127
+ }
2128
+
2129
+ async function ensureOpenClawPluginLoadPath() {
2130
+ const configPath = getOpenClawConfigPath();
2131
+ let cfg = {};
2132
+ if (existsSync(configPath)) {
2133
+ try {
2134
+ cfg = JSON.parse(await readFile(configPath, "utf8"));
2135
+ } catch {
2136
+ return;
2137
+ }
2138
+ }
2139
+
2140
+ const pluginPath = PLUGIN_DEST;
2141
+ const normalizedPluginPath = normalizeOpenClawLoadPath(pluginPath);
2142
+ const plugins = cfg.plugins && typeof cfg.plugins === "object" && !Array.isArray(cfg.plugins)
2143
+ ? cfg.plugins
2144
+ : {};
2145
+ const load = plugins.load && typeof plugins.load === "object" && !Array.isArray(plugins.load)
2146
+ ? plugins.load
2147
+ : {};
2148
+ const paths = Array.isArray(load.paths) ? load.paths : [];
2149
+ if (paths.some((item) => normalizeOpenClawLoadPath(item) === normalizedPluginPath)) {
2150
+ return;
2151
+ }
2152
+
2153
+ const next = {
2154
+ ...cfg,
2155
+ plugins: {
2156
+ ...plugins,
2157
+ load: {
2158
+ ...load,
2159
+ paths: [...paths, pluginPath],
2160
+ },
2161
+ },
2162
+ };
2163
+ await mkdir(dirname(configPath), { recursive: true });
2164
+ const tmp = `${configPath}.ov-install-tmp.${process.pid}`;
2165
+ await writeFile(tmp, `${JSON.stringify(next, null, 2)}\n`, "utf8");
2166
+ await rename(tmp, configPath);
2167
+ info(tr(`Added OpenClaw plugin load path: ${pluginPath}`, `已添加 OpenClaw 插件加载路径: ${pluginPath}`));
2168
+ }
2169
+
1771
2170
  async function configureOpenClawPlugin({
1772
2171
  preserveExistingConfig = false,
1773
2172
  runtimeConfig = null,
@@ -1821,6 +2220,8 @@ async function configureOpenClawPlugin({
1821
2220
  await scrubStaleOpenClawPluginRegistration();
1822
2221
  }
1823
2222
 
2223
+ await ensureOpenClawPluginLoadPath();
2224
+
1824
2225
  // Enable plugin: try CLI first (default path), fall back to direct file for --workdir
1825
2226
  if (!needWorkdirFlag) {
1826
2227
  try {
@@ -1931,13 +2332,14 @@ async function configureOpenClawPlugin({
1931
2332
  }
1932
2333
  } catch { /* ignore read errors */ }
1933
2334
 
1934
- let setupResult = null;
1935
- if (setupJsonSupported) {
1936
- const setupArgs = ["openviking", "setup"];
1937
- setupArgs.push("--base-url", effectiveRuntimeConfig.baseUrl || remoteBaseUrl);
1938
- setupArgs.push("--json");
1939
- if (effectiveRuntimeConfig.apiKey) {
1940
- setupArgs.push("--api-key", effectiveRuntimeConfig.apiKey);
2335
+ let setupResult = null;
2336
+ let parsed = null;
2337
+ const runSetupJson = async (extraArgs = []) => {
2338
+ const setupArgs = ["openviking", "setup"];
2339
+ setupArgs.push("--base-url", effectiveRuntimeConfig.baseUrl || remoteBaseUrl);
2340
+ setupArgs.push("--json");
2341
+ if (effectiveRuntimeConfig.apiKey) {
2342
+ setupArgs.push("--api-key", effectiveRuntimeConfig.apiKey);
1941
2343
  }
1942
2344
  if (effectiveRuntimeConfig.agent_prefix) {
1943
2345
  setupArgs.push("--agent-prefix", effectiveRuntimeConfig.agent_prefix);
@@ -1945,35 +2347,67 @@ async function configureOpenClawPlugin({
1945
2347
  if (effectiveRuntimeConfig.accountId) {
1946
2348
  setupArgs.push("--account-id", effectiveRuntimeConfig.accountId);
1947
2349
  }
1948
- if (effectiveRuntimeConfig.userId) {
1949
- setupArgs.push("--user-id", effectiveRuntimeConfig.userId);
1950
- }
1951
- if (claimSlot) {
1952
- setupArgs.push("--force-slot");
1953
- }
1954
- if (nonInteractive) {
1955
- setupArgs.push("--allow-offline");
1956
- }
1957
-
1958
- info(tr(
1959
- "Delegating configuration to: openclaw openviking setup --json",
1960
- "委托配置给: openclaw openviking setup --json",
1961
- ));
1962
-
1963
- setupResult = await runCapture("openclaw", setupArgs, { env: ocEnv, shell: IS_WIN });
1964
- } else {
1965
- info(tr(
1966
- "Installed plugin does not support setup --json, using direct config write",
1967
- "已安装的插件不支持 setup --json,使用直接配置写入",
1968
- ));
1969
- }
1970
-
1971
- let parsed = null;
1972
- if (setupResult) {
1973
- parsed = parseJsonObjectFromOutput(`${setupResult.out || ""}\n${setupResult.err || ""}`);
1974
- }
1975
-
1976
- if (parsed) {
2350
+ if (effectiveRuntimeConfig.userId) {
2351
+ setupArgs.push("--user-id", effectiveRuntimeConfig.userId);
2352
+ }
2353
+ if (forceSlotExplicit) {
2354
+ setupArgs.push("--force-slot");
2355
+ }
2356
+ if (allowOfflineExplicit) {
2357
+ setupArgs.push("--allow-offline");
2358
+ }
2359
+ setupArgs.push(...extraArgs);
2360
+
2361
+ const result = await runCapture("openclaw", setupArgs, { env: ocEnv, shell: IS_WIN });
2362
+ return {
2363
+ result,
2364
+ parsed: parseJsonObjectFromOutput(`${result.out || ""}\n${result.err || ""}`),
2365
+ };
2366
+ };
2367
+
2368
+ if (setupJsonSupported) {
2369
+ info(tr(
2370
+ "Delegating configuration to: openclaw openviking setup --json",
2371
+ "委托配置给: openclaw openviking setup --json",
2372
+ ));
2373
+
2374
+ ({ result: setupResult, parsed } = await runSetupJson());
2375
+ } else {
2376
+ info(tr(
2377
+ "Installed plugin does not support setup --json, using direct config write",
2378
+ "已安装的插件不支持 setup --json,使用直接配置写入",
2379
+ ));
2380
+ }
2381
+
2382
+ if (parsed && !parsed.success && !nonInteractive) {
2383
+ if (parsed.action === "slot_blocked" && !forceSlotExplicit) {
2384
+ const answer = await question(
2385
+ tr(
2386
+ `contextEngine slot is owned by "${parsed.slot?.previousOwner}". Replace it with OpenViking? (y/N)`,
2387
+ `contextEngine slot is owned by "${parsed.slot?.previousOwner}". Replace it with OpenViking? (y/N)`,
2388
+ ),
2389
+ );
2390
+ if (isYes(answer)) {
2391
+ ({ result: setupResult, parsed } = await runSetupJson(["--force-slot"]));
2392
+ }
2393
+ } else if (
2394
+ typeof parsed.error === "string" &&
2395
+ parsed.error.includes("Server unreachable") &&
2396
+ !allowOfflineExplicit
2397
+ ) {
2398
+ const answer = await question(
2399
+ tr(
2400
+ "OpenViking server is unreachable. Save config offline anyway? (y/N)",
2401
+ "OpenViking server is unreachable. Save config offline anyway? (y/N)",
2402
+ ),
2403
+ );
2404
+ if (isYes(answer)) {
2405
+ ({ result: setupResult, parsed } = await runSetupJson(["--allow-offline"]));
2406
+ }
2407
+ }
2408
+ }
2409
+
2410
+ if (parsed) {
1977
2411
  if (parsed.success) {
1978
2412
  info(tr("OpenClaw plugin configured via setup", "OpenClaw 插件通过 setup 配置完成"));
1979
2413
  if (parsed.health?.ok) {
@@ -1991,32 +2425,37 @@ async function configureOpenClawPlugin({
1991
2425
  if (parsed.slot?.activated) {
1992
2426
  info(tr(`contextEngine slot activated`, `contextEngine slot 已激活`));
1993
2427
  }
1994
- } else {
1995
- // Setup returned success: false
1996
- if (parsed.action === "slot_blocked") {
1997
- warn(tr(
1998
- `Config saved but contextEngine slot is owned by "${parsed.slot?.previousOwner}". Use --force-slot to override.`,
1999
- `配置已保存,但 contextEngine slot "${parsed.slot?.previousOwner}" 占用。使用 --force-slot 覆盖。`,
2000
- ));
2001
- } else {
2002
- err(tr(
2003
- `Setup failed: ${parsed.error || "unknown error"}`,
2004
- `配置失败: ${parsed.error || "未知错误"}`,
2005
- ));
2006
- return {
2007
- runtimeConfigOk: false,
2008
- error: parsed.error || parsed.action || "unknown error",
2009
- };
2010
- }
2011
- }
2012
- } else if (setupResult && setupResult.code !== 0) {
2013
- warn(tr(
2014
- `openclaw openviking setup exited with code ${setupResult.code}. Falling back to direct JSON config write.`,
2015
- `openclaw openviking setup 退出码 ${setupResult.code},回退到直接写入 JSON 配置。`,
2016
- ));
2017
- }
2018
-
2019
- if (!parsed) {
2428
+ } else {
2429
+ // Setup returned success: false
2430
+ const setupError = parsed.error || parsed.action || "unknown error";
2431
+ if (parsed.action === "slot_blocked") {
2432
+ warn(tr(
2433
+ `Config saved but contextEngine slot is owned by "${parsed.slot?.previousOwner}". Use --force-slot to override.`,
2434
+ `配置已保存,但 contextEngine slot 被 "${parsed.slot?.previousOwner}" 占用。使用 --force-slot 覆盖。`,
2435
+ ));
2436
+ } else {
2437
+ err(tr(
2438
+ `Setup failed: ${setupError}`,
2439
+ `配置失败: ${setupError}`,
2440
+ ));
2441
+ }
2442
+ return {
2443
+ runtimeConfigOk: false,
2444
+ error: setupError,
2445
+ };
2446
+ }
2447
+ } else if (setupJsonSupported) {
2448
+ const setupError = setupResult
2449
+ ? `openclaw openviking setup did not return JSON (exit code ${setupResult.code})`
2450
+ : "openclaw openviking setup did not run";
2451
+ err(tr(`Setup failed: ${setupError}`, `配置失败: ${setupError}`));
2452
+ return {
2453
+ runtimeConfigOk: false,
2454
+ error: setupError,
2455
+ };
2456
+ }
2457
+
2458
+ if (!setupJsonSupported) {
2020
2459
  // Direct write: only used when the installed plugin doesn't support `setup --json` (old version).
2021
2460
  // Read the deployed configSchema to determine which fields are allowed, avoiding
2022
2461
  // "additionalProperties" validation failures when writing new fields to old schemas.
@@ -2153,7 +2592,7 @@ async function performUninstall() {
2153
2592
  tr("Confirm uninstall? (y/N)", "确认卸载?(y/N)"),
2154
2593
  "N",
2155
2594
  );
2156
- if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
2595
+ if (!isYes(answer)) {
2157
2596
  info(tr("Cancelled.", "已取消。"));
2158
2597
  return;
2159
2598
  }
@@ -2262,11 +2701,16 @@ async function main() {
2262
2701
  await rollbackLastUpgradeOperation();
2263
2702
  return;
2264
2703
  }
2265
- await resolveDefaultPluginVersion();
2266
- validateRequestedPluginVersion();
2267
- info(tr(`Target: ${OPENCLAW_DIR}`, `目标实例: ${OPENCLAW_DIR}`));
2268
- info(tr(`Repository: ${REPO}`, `仓库: ${REPO}`));
2269
- info(tr(`Plugin version: ${PLUGIN_VERSION}`, `插件版本: ${PLUGIN_VERSION}`));
2704
+ await resolveDefaultPluginVersion();
2705
+ validateRequestedPluginVersion();
2706
+ info(tr(`Target: ${OPENCLAW_DIR}`, `目标实例: ${OPENCLAW_DIR}`));
2707
+ info(tr(`Plugin source: ${pluginSource}`, `Plugin source: ${pluginSource}`));
2708
+ if (pluginSource === "npm") {
2709
+ info(tr(`Plugin package: ${pluginNpmPackage}`, `Plugin package: ${pluginNpmPackage}`));
2710
+ } else {
2711
+ info(tr(`Repository: ${REPO}`, `仓库: ${REPO}`));
2712
+ }
2713
+ info(tr(`Plugin version: ${PLUGIN_VERSION}`, `插件版本: ${PLUGIN_VERSION}`));
2270
2714
 
2271
2715
  if (upgradePluginOnly) {
2272
2716
  info(tr("Mode: plugin upgrade only", "模式: 仅升级插件"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-openviking-setup-helper",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Setup helper for installing OpenViking memory plugin into OpenClaw",
5
5
  "type": "module",
6
6
  "bin": {