@xfxstudio/claworld 0.2.10-beta.1 → 0.2.10-beta.3
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/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
CLAWORLD_DOCTOR_COMMAND,
|
|
8
8
|
CLAWORLD_INSTALLER_BIN_NAME,
|
|
9
9
|
CLAWORLD_INSTALLER_COMMAND,
|
|
10
|
-
|
|
10
|
+
CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
11
11
|
CLAWORLD_UNINSTALL_COMMAND,
|
|
12
12
|
CLAWORLD_UPDATE_COMMAND,
|
|
13
13
|
} from './constants.js';
|
|
@@ -57,7 +57,7 @@ Install options:
|
|
|
57
57
|
--tool-profile <profile> minimal | default | full | world
|
|
58
58
|
--repo-root <path> Local repo root when using --plugin-install-mode link|copy
|
|
59
59
|
--plugin-install-mode <m> npm | link | copy | skip (default: npm)
|
|
60
|
-
--plugin-source <value> npm package or local path (default: ${
|
|
60
|
+
--plugin-source <value> npm package or local path (default: ${CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE})
|
|
61
61
|
Update options:
|
|
62
62
|
--config <path> OpenClaw config path (default: ${DEFAULT_OPENCLAW_CONFIG_PATH})
|
|
63
63
|
--state-dir <path> Optional OPENCLAW_STATE_DIR for OpenClaw commands
|
|
@@ -118,7 +118,7 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
|
|
|
118
118
|
displayName: null,
|
|
119
119
|
repoRoot: null,
|
|
120
120
|
pluginInstallMode: 'npm',
|
|
121
|
-
pluginInstallSource:
|
|
121
|
+
pluginInstallSource: CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
122
122
|
toolProfile: null,
|
|
123
123
|
},
|
|
124
124
|
update: {
|
|
@@ -266,7 +266,7 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
|
|
|
266
266
|
options.command === 'install'
|
|
267
267
|
&& options.install.pluginInstallMode === 'link'
|
|
268
268
|
&& !options.install.repoRoot
|
|
269
|
-
&& options.install.pluginInstallSource ===
|
|
269
|
+
&& options.install.pluginInstallSource === CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE
|
|
270
270
|
) {
|
|
271
271
|
throw new Error('Link install mode requires --repo-root or --plugin-source <local-path>.');
|
|
272
272
|
}
|
|
@@ -274,7 +274,7 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
|
|
|
274
274
|
options.command === 'install'
|
|
275
275
|
&& options.install.pluginInstallMode === 'copy'
|
|
276
276
|
&& !options.install.repoRoot
|
|
277
|
-
&& options.install.pluginInstallSource ===
|
|
277
|
+
&& options.install.pluginInstallSource === CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE
|
|
278
278
|
) {
|
|
279
279
|
throw new Error('Copy install mode requires --repo-root or --plugin-source <local-path>.');
|
|
280
280
|
}
|
|
@@ -283,7 +283,7 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
|
|
|
283
283
|
options.command === 'install'
|
|
284
284
|
&& options.install.pluginInstallMode !== 'npm'
|
|
285
285
|
&& options.install.repoRoot
|
|
286
|
-
&& options.install.pluginInstallSource ===
|
|
286
|
+
&& options.install.pluginInstallSource === CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE
|
|
287
287
|
) {
|
|
288
288
|
options.install.pluginInstallSource = options.install.repoRoot;
|
|
289
289
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
const installerPackageJson = require('../../../package.json');
|
|
5
|
+
|
|
1
6
|
export const CLAWORLD_INSTALLER_BIN_NAME = 'claworld';
|
|
2
7
|
export const CLAWORLD_INSTALLER_PACKAGE_NAME = '@xfxstudio/claworld';
|
|
8
|
+
export const CLAWORLD_INSTALLER_PACKAGE_VERSION = installerPackageJson.version;
|
|
9
|
+
export const CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE = `${CLAWORLD_INSTALLER_PACKAGE_NAME}@${CLAWORLD_INSTALLER_PACKAGE_VERSION}`;
|
|
3
10
|
export const CLAWORLD_INSTALLER_COMMAND = 'npx -y @xfxstudio/claworld install';
|
|
4
11
|
export const CLAWORLD_DOCTOR_COMMAND = 'npx -y @xfxstudio/claworld doctor';
|
|
5
12
|
export const CLAWORLD_UPDATE_COMMAND = 'npx -y @xfxstudio/claworld update';
|
|
@@ -5,10 +5,10 @@ import path from 'path';
|
|
|
5
5
|
import { spawnSync } from 'child_process';
|
|
6
6
|
import vm from 'vm';
|
|
7
7
|
import {
|
|
8
|
+
applyClaworldBootstrapConfig,
|
|
8
9
|
DEFAULT_CLAWORLD_ACCOUNT_ID,
|
|
9
10
|
DEFAULT_CLAWORLD_AGENT_ID,
|
|
10
11
|
DEFAULT_CLAWORLD_SERVER_URL,
|
|
11
|
-
applyClaworldManagedRuntimeConfig,
|
|
12
12
|
ensureObject,
|
|
13
13
|
expandUserPath,
|
|
14
14
|
findClaworldManagedRuntimeBackup,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '../plugin/config-schema.js';
|
|
25
25
|
import {
|
|
26
26
|
CLAWORLD_INSTALLER_COMMAND,
|
|
27
|
+
CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
27
28
|
CLAWORLD_INSTALLER_PACKAGE_NAME,
|
|
28
29
|
CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
|
|
29
30
|
CLAWORLD_UNINSTALL_COMMAND,
|
|
@@ -32,6 +33,7 @@ import {
|
|
|
32
33
|
import { seedManagedWorkspaceContract } from './workspace-contract.js';
|
|
33
34
|
|
|
34
35
|
export const DEFAULT_OPENCLAW_BIN = 'openclaw';
|
|
36
|
+
const DEFAULT_NPM_BIN = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
35
37
|
export const DEFAULT_OPENCLAW_CONFIG_PATH = '~/.openclaw/openclaw.json';
|
|
36
38
|
export const DEFAULT_OPENCLAW_STATE_DIR = null;
|
|
37
39
|
export const DEFAULT_INSTALL_TIMEOUT_MS = 15_000;
|
|
@@ -54,9 +56,28 @@ function normalizeComparablePath(value) {
|
|
|
54
56
|
return path.resolve(String(value));
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
function splitPackageNameSegments(packageName = CLAWORLD_INSTALLER_PACKAGE_NAME) {
|
|
60
|
+
const normalized = String(packageName || '').trim();
|
|
61
|
+
if (!normalized) return ['claworld'];
|
|
62
|
+
return normalized.split('/').filter(Boolean);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resolveInstallerManagedPluginInstallRoot(configPath = DEFAULT_OPENCLAW_CONFIG_PATH) {
|
|
66
|
+
const resolvedConfigPath = path.resolve(expandUserPath(configPath, os.homedir()));
|
|
67
|
+
return path.join(path.dirname(resolvedConfigPath), 'extensions', 'claworld');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function resolveInstallerManagedPluginSourcePath(installRoot, packageName = CLAWORLD_INSTALLER_PACKAGE_NAME) {
|
|
71
|
+
return path.join(installRoot, 'node_modules', ...splitPackageNameSegments(packageName));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function readJsonFile(filePath) {
|
|
75
|
+
return JSON.parse(await fs.readFile(filePath, 'utf8'));
|
|
76
|
+
}
|
|
77
|
+
|
|
57
78
|
async function resolveLocalPluginInstallTarget({
|
|
58
79
|
installMode = 'npm',
|
|
59
|
-
installSource =
|
|
80
|
+
installSource = CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
60
81
|
repoRoot = null,
|
|
61
82
|
commandRunner = defaultCommandRunner,
|
|
62
83
|
cwd = process.cwd(),
|
|
@@ -85,6 +106,7 @@ async function resolveLocalPluginInstallTarget({
|
|
|
85
106
|
resolvedInstallSource === derivedRepoRoot
|
|
86
107
|
|| resolvedInstallSource === path.join(derivedRepoRoot, 'packages', 'openclaw-plugin')
|
|
87
108
|
|| resolvedInstallSource === CLAWORLD_INSTALLER_PACKAGE_NAME
|
|
109
|
+
|| resolvedInstallSource === CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE
|
|
88
110
|
),
|
|
89
111
|
);
|
|
90
112
|
|
|
@@ -432,18 +454,44 @@ function parseBindingLine(text = '', { agentId, accountId } = {}) {
|
|
|
432
454
|
.find((line) => line === `- ${agentId} <- claworld accountId=${accountId}`) || null;
|
|
433
455
|
}
|
|
434
456
|
|
|
457
|
+
function normalizePathSuffix(value = '') {
|
|
458
|
+
return String(value || '').replace(/\\/g, '/').replace(/\/+$/, '');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function isInstallerManagedLocalSourceRecord(installRecord = {}) {
|
|
462
|
+
const source = normalizeText(installRecord.source, null);
|
|
463
|
+
if (source !== 'path') {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
const spec = normalizeText(installRecord.spec, null) || normalizeText(installRecord.resolvedSpec, null);
|
|
467
|
+
if (!spec || !spec.startsWith('@xfxstudio/claworld@')) {
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
const installPath = normalizePathSuffix(installRecord.installPath);
|
|
471
|
+
const sourcePath = normalizePathSuffix(installRecord.sourcePath);
|
|
472
|
+
return (
|
|
473
|
+
installPath.endsWith('/extensions/claworld')
|
|
474
|
+
&& sourcePath.endsWith('/extensions/claworld/node_modules/@xfxstudio/claworld')
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
435
478
|
function inspectTrackedClaworldPluginInstall(config = {}) {
|
|
436
479
|
const installRecord = ensureObject(config?.plugins?.installs?.claworld);
|
|
437
480
|
const tracked = Object.keys(installRecord).length > 0;
|
|
438
|
-
const
|
|
481
|
+
const recordedSource = normalizeText(installRecord.source, null);
|
|
482
|
+
const source = isInstallerManagedLocalSourceRecord(installRecord)
|
|
483
|
+
? 'installer_npm'
|
|
484
|
+
: recordedSource;
|
|
439
485
|
return {
|
|
440
486
|
tracked,
|
|
441
487
|
updateable: tracked && TRACKED_PLUGIN_UPDATEABLE_SOURCES.has(source),
|
|
442
488
|
source,
|
|
489
|
+
recordedSource,
|
|
443
490
|
spec: normalizeText(installRecord.spec, null),
|
|
444
491
|
resolvedSpec: normalizeText(installRecord.resolvedSpec, null),
|
|
445
492
|
resolvedVersion: normalizeText(installRecord.resolvedVersion, null),
|
|
446
493
|
installPath: normalizeText(installRecord.installPath, null),
|
|
494
|
+
sourcePath: normalizeText(installRecord.sourcePath, null),
|
|
447
495
|
record: tracked ? installRecord : null,
|
|
448
496
|
};
|
|
449
497
|
}
|
|
@@ -527,6 +575,67 @@ function mergePluginMetadata(config = {}, pluginConfig = {}) {
|
|
|
527
575
|
return next;
|
|
528
576
|
}
|
|
529
577
|
|
|
578
|
+
async function installPublishedClaworldPackageToLocalSource({
|
|
579
|
+
installSource = CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
580
|
+
configPath = DEFAULT_OPENCLAW_CONFIG_PATH,
|
|
581
|
+
commandRunner = defaultCommandRunner,
|
|
582
|
+
cwd = process.cwd(),
|
|
583
|
+
env = process.env,
|
|
584
|
+
dryRun = false,
|
|
585
|
+
refresh = false,
|
|
586
|
+
} = {}) {
|
|
587
|
+
const installRoot = resolveInstallerManagedPluginInstallRoot(configPath);
|
|
588
|
+
const sourcePath = resolveInstallerManagedPluginSourcePath(installRoot);
|
|
589
|
+
if (!dryRun && refresh) {
|
|
590
|
+
await fs.rm(installRoot, { recursive: true, force: true });
|
|
591
|
+
}
|
|
592
|
+
if (!dryRun) {
|
|
593
|
+
await fs.mkdir(installRoot, { recursive: true });
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
await executeCommand({
|
|
597
|
+
commandRunner,
|
|
598
|
+
bin: DEFAULT_NPM_BIN,
|
|
599
|
+
args: [
|
|
600
|
+
'install',
|
|
601
|
+
'--ignore-scripts',
|
|
602
|
+
'--no-package-lock',
|
|
603
|
+
'--omit=dev',
|
|
604
|
+
'--prefix',
|
|
605
|
+
installRoot,
|
|
606
|
+
installSource,
|
|
607
|
+
],
|
|
608
|
+
cwd,
|
|
609
|
+
env,
|
|
610
|
+
dryRun,
|
|
611
|
+
capture: false,
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
let resolvedVersion = null;
|
|
615
|
+
if (!dryRun) {
|
|
616
|
+
const sourcePackageJson = await readJsonFile(path.join(sourcePath, 'package.json'));
|
|
617
|
+
resolvedVersion = normalizeText(sourcePackageJson?.version, null);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return {
|
|
621
|
+
installRoot,
|
|
622
|
+
sourcePath,
|
|
623
|
+
resolvedVersion,
|
|
624
|
+
pluginConfig: {
|
|
625
|
+
installs: {
|
|
626
|
+
claworld: {
|
|
627
|
+
source: 'path',
|
|
628
|
+
spec: installSource,
|
|
629
|
+
resolvedSpec: installSource,
|
|
630
|
+
...(resolvedVersion ? { resolvedVersion } : {}),
|
|
631
|
+
installPath: installRoot,
|
|
632
|
+
sourcePath,
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
|
|
530
639
|
function defaultCommandRunner({
|
|
531
640
|
bin,
|
|
532
641
|
args,
|
|
@@ -863,9 +972,10 @@ export async function ensureClaworldPluginInstalled({
|
|
|
863
972
|
env = process.env,
|
|
864
973
|
dryRun = false,
|
|
865
974
|
installMode = 'npm',
|
|
866
|
-
installSource =
|
|
975
|
+
installSource = CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
867
976
|
refresh = false,
|
|
868
977
|
} = {}) {
|
|
978
|
+
const trackedInstall = inspectTrackedClaworldPluginInstall(config);
|
|
869
979
|
const bootstrap = await preparePluginBootstrapConfig({
|
|
870
980
|
configPath,
|
|
871
981
|
config,
|
|
@@ -883,7 +993,18 @@ export async function ensureClaworldPluginInstalled({
|
|
|
883
993
|
env,
|
|
884
994
|
dryRun,
|
|
885
995
|
});
|
|
886
|
-
|
|
996
|
+
const reusableInstallerManagedNpmInstall = (
|
|
997
|
+
installMode === 'npm'
|
|
998
|
+
&& trackedInstall.tracked
|
|
999
|
+
&& trackedInstall.source === 'installer_npm'
|
|
1000
|
+
&& trackedInstall.recordedSource === 'path'
|
|
1001
|
+
&& normalizeText(trackedInstall.sourcePath, null)
|
|
1002
|
+
);
|
|
1003
|
+
if (
|
|
1004
|
+
before.installed
|
|
1005
|
+
&& !refresh
|
|
1006
|
+
&& (installMode !== 'npm' || reusableInstallerManagedNpmInstall)
|
|
1007
|
+
) {
|
|
887
1008
|
return {
|
|
888
1009
|
changed: false,
|
|
889
1010
|
action: 'reused_existing_plugin_install',
|
|
@@ -901,6 +1022,37 @@ export async function ensureClaworldPluginInstalled({
|
|
|
901
1022
|
};
|
|
902
1023
|
}
|
|
903
1024
|
|
|
1025
|
+
if (installMode === 'npm') {
|
|
1026
|
+
const localInstall = await installPublishedClaworldPackageToLocalSource({
|
|
1027
|
+
installSource,
|
|
1028
|
+
configPath,
|
|
1029
|
+
commandRunner,
|
|
1030
|
+
cwd,
|
|
1031
|
+
env,
|
|
1032
|
+
dryRun,
|
|
1033
|
+
refresh,
|
|
1034
|
+
});
|
|
1035
|
+
return {
|
|
1036
|
+
changed: true,
|
|
1037
|
+
action: reusableInstallerManagedNpmInstall ? 'refreshed_local_plugin_source' : 'staged_local_plugin_source',
|
|
1038
|
+
plugin: before,
|
|
1039
|
+
pluginConfig: {
|
|
1040
|
+
...ensureObject(bootstrap?.pluginConfig),
|
|
1041
|
+
...ensureObject(localInstall.pluginConfig),
|
|
1042
|
+
entries: {
|
|
1043
|
+
...ensureObject(bootstrap?.pluginConfig?.entries),
|
|
1044
|
+
...ensureObject(localInstall.pluginConfig?.entries),
|
|
1045
|
+
},
|
|
1046
|
+
installs: {
|
|
1047
|
+
...ensureObject(bootstrap?.pluginConfig?.installs),
|
|
1048
|
+
...ensureObject(localInstall.pluginConfig?.installs),
|
|
1049
|
+
},
|
|
1050
|
+
},
|
|
1051
|
+
installSource,
|
|
1052
|
+
managedRepoRoot: localInstall.sourcePath,
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
|
|
904
1056
|
if (before.installed && refresh && installMode === 'copy') {
|
|
905
1057
|
await executeCommand({
|
|
906
1058
|
commandRunner,
|
|
@@ -990,6 +1142,26 @@ export async function updateTrackedClaworldPluginInstall({
|
|
|
990
1142
|
);
|
|
991
1143
|
}
|
|
992
1144
|
|
|
1145
|
+
if (trackedInstall.source === 'installer_npm') {
|
|
1146
|
+
const localInstall = await installPublishedClaworldPackageToLocalSource({
|
|
1147
|
+
installSource: trackedInstall.spec || CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
1148
|
+
configPath,
|
|
1149
|
+
commandRunner,
|
|
1150
|
+
cwd,
|
|
1151
|
+
env,
|
|
1152
|
+
dryRun,
|
|
1153
|
+
refresh: true,
|
|
1154
|
+
});
|
|
1155
|
+
return {
|
|
1156
|
+
changed: true,
|
|
1157
|
+
action: dryRun ? 'dry_run_updated_local_plugin_source' : 'updated_local_plugin_source',
|
|
1158
|
+
trackedInstall,
|
|
1159
|
+
plugin: before,
|
|
1160
|
+
pluginConfig: localInstall.pluginConfig,
|
|
1161
|
+
managedRepoRoot: localInstall.sourcePath,
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
|
|
993
1165
|
if (!trackedInstall.tracked) {
|
|
994
1166
|
return {
|
|
995
1167
|
changed: false,
|
|
@@ -1467,8 +1639,8 @@ async function reconcileManagedClaworldRuntime({
|
|
|
1467
1639
|
},
|
|
1468
1640
|
});
|
|
1469
1641
|
|
|
1470
|
-
const transformed =
|
|
1471
|
-
const configChanged = JSON.stringify(
|
|
1642
|
+
const transformed = applyClaworldBootstrapConfig(currentConfig, managedOptions);
|
|
1643
|
+
const configChanged = JSON.stringify(currentConfigState.config) !== JSON.stringify(transformed.config);
|
|
1472
1644
|
const backupPath = configChanged
|
|
1473
1645
|
? await backupConfigIfPresent(configPath, currentConfigState.existed, dryRun)
|
|
1474
1646
|
: null;
|
|
@@ -1560,7 +1732,7 @@ export async function runClaworldInstallerInstall({
|
|
|
1560
1732
|
sessionDmScope = null,
|
|
1561
1733
|
repoRoot = null,
|
|
1562
1734
|
pluginInstallMode = 'npm',
|
|
1563
|
-
pluginInstallSource =
|
|
1735
|
+
pluginInstallSource = CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
1564
1736
|
fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
1565
1737
|
commandRunner = defaultCommandRunner,
|
|
1566
1738
|
cwd = process.cwd(),
|
|
@@ -1639,7 +1811,7 @@ export async function runClaworldInstallerInstall({
|
|
|
1639
1811
|
toolProfile,
|
|
1640
1812
|
approvalMode,
|
|
1641
1813
|
sessionDmScope,
|
|
1642
|
-
repoRoot: localPluginInstall.managedRepoRoot,
|
|
1814
|
+
repoRoot: plugin.managedRepoRoot || localPluginInstall.managedRepoRoot,
|
|
1643
1815
|
fetchImpl,
|
|
1644
1816
|
commandRunner,
|
|
1645
1817
|
cwd,
|
|
@@ -1717,7 +1889,7 @@ export async function runClaworldInstallerUpdate({
|
|
|
1717
1889
|
});
|
|
1718
1890
|
|
|
1719
1891
|
const refreshedConfigState = await loadConfigFromDisk(resolvedConfigPath);
|
|
1720
|
-
const currentConfig = mergePluginMetadata(refreshedConfigState.config, null);
|
|
1892
|
+
const currentConfig = mergePluginMetadata(refreshedConfigState.config, plugin.pluginConfig || null);
|
|
1721
1893
|
const lifecycle = await reconcileManagedClaworldRuntime({
|
|
1722
1894
|
openclawBin,
|
|
1723
1895
|
configPath: resolvedConfigPath,
|
|
@@ -1736,6 +1908,7 @@ export async function runClaworldInstallerUpdate({
|
|
|
1736
1908
|
toolProfile,
|
|
1737
1909
|
approvalMode,
|
|
1738
1910
|
sessionDmScope,
|
|
1911
|
+
repoRoot: plugin.managedRepoRoot || null,
|
|
1739
1912
|
fetchImpl,
|
|
1740
1913
|
commandRunner,
|
|
1741
1914
|
cwd,
|
|
@@ -1778,6 +1951,7 @@ export async function runClaworldInstallerUninstall({
|
|
|
1778
1951
|
const currentConfigState = await loadConfigFromDisk(resolvedConfigPath);
|
|
1779
1952
|
const currentInstallerState = (await loadInstallerStateFromDisk(installerStatePath)).state;
|
|
1780
1953
|
const currentConfig = currentConfigState.config;
|
|
1954
|
+
const trackedInstall = inspectTrackedClaworldPluginInstall(currentConfig);
|
|
1781
1955
|
const host = await detectOpenclawHost({
|
|
1782
1956
|
openclawBin,
|
|
1783
1957
|
commandRunner,
|
|
@@ -1841,7 +2015,20 @@ export async function runClaworldInstallerUninstall({
|
|
|
1841
2015
|
|
|
1842
2016
|
let pluginAction = 'plugin_already_absent';
|
|
1843
2017
|
try {
|
|
1844
|
-
if (
|
|
2018
|
+
if (trackedInstall.source === 'installer_npm') {
|
|
2019
|
+
const localInstallPath = normalizeText(trackedInstall.installPath, null) || normalizeText(trackedInstall.sourcePath, null);
|
|
2020
|
+
if (!localInstallPath) {
|
|
2021
|
+
throw createInstallerError(
|
|
2022
|
+
'claworld_installer_managed_source_missing',
|
|
2023
|
+
'Installer-managed Claworld source is missing its local install path.',
|
|
2024
|
+
{ trackedInstall },
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
if (!dryRun) {
|
|
2028
|
+
await fs.rm(localInstallPath, { recursive: true, force: true });
|
|
2029
|
+
}
|
|
2030
|
+
pluginAction = 'removed_local_plugin_source';
|
|
2031
|
+
} else if (pluginBefore.installed) {
|
|
1845
2032
|
await executeCommand({
|
|
1846
2033
|
commandRunner,
|
|
1847
2034
|
bin: openclawBin,
|
|
@@ -1881,7 +2068,7 @@ export async function runClaworldInstallerUninstall({
|
|
|
1881
2068
|
env,
|
|
1882
2069
|
dryRun,
|
|
1883
2070
|
});
|
|
1884
|
-
if (pluginBefore.installed && pluginAfter.installed) {
|
|
2071
|
+
if ((pluginBefore.installed || trackedInstall.source === 'installer_npm') && pluginAfter.installed) {
|
|
1885
2072
|
throw createInstallerError(
|
|
1886
2073
|
'claworld_plugin_uninstall_failed',
|
|
1887
2074
|
'OpenClaw still reports the claworld plugin as installed after uninstall.',
|