@xfxstudio/claworld 0.2.9 → 0.2.10-beta.0

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 (49) hide show
  1. package/README.md +1 -1
  2. package/openclaw.plugin.json +7 -63
  3. package/package.json +6 -2
  4. package/skills/claworld-help/SKILL.md +5 -1
  5. package/skills/claworld-join-and-chat/SKILL.md +21 -1
  6. package/skills/claworld-manage-worlds/SKILL.md +81 -10
  7. package/src/lib/agent-profile.js +8 -3
  8. package/src/lib/chat-request.js +0 -1
  9. package/src/lib/policy.js +2 -6
  10. package/src/lib/public-identity.js +175 -0
  11. package/src/lib/relay/kickoff-text.js +1 -0
  12. package/src/openclaw/installer/cli.js +46 -1
  13. package/src/openclaw/installer/constants.js +1 -0
  14. package/src/openclaw/installer/core.js +234 -3
  15. package/src/openclaw/installer/doctor.js +2 -2
  16. package/src/openclaw/plugin/account-identity.js +1 -2
  17. package/src/openclaw/plugin/claworld-channel-plugin.js +270 -255
  18. package/src/openclaw/plugin/config-schema.js +9 -23
  19. package/src/openclaw/plugin/managed-config.js +284 -79
  20. package/src/openclaw/plugin/onboarding.js +22 -42
  21. package/src/openclaw/plugin/register.js +109 -10
  22. package/src/openclaw/plugin/relay-client.js +233 -17
  23. package/src/openclaw/runtime/backend-error-context.js +91 -0
  24. package/src/openclaw/runtime/feedback-helper.js +1 -2
  25. package/src/openclaw/runtime/product-shell-helper.js +43 -9
  26. package/src/openclaw/runtime/tool-contracts.js +26 -3
  27. package/src/openclaw/runtime/tool-inventory.js +7 -0
  28. package/src/openclaw/runtime/world-moderation-helper.js +3 -19
  29. package/src/product-shell/contracts/candidate-feed.js +7 -0
  30. package/src/product-shell/contracts/world-manifest.js +0 -1
  31. package/src/product-shell/contracts/world-orchestration.js +10 -1
  32. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +261 -0
  33. package/src/product-shell/feedback/feedback-routes.js +0 -1
  34. package/src/product-shell/feedback/feedback-service.js +4 -9
  35. package/src/product-shell/index.js +40 -7
  36. package/src/product-shell/matching/matchmaking-service.js +22 -1
  37. package/src/product-shell/membership/membership-service.js +5 -1
  38. package/src/product-shell/onboarding/onboarding-service.js +10 -21
  39. package/src/product-shell/profile/public-identity-routes.js +60 -0
  40. package/src/product-shell/profile/public-identity-service.js +190 -0
  41. package/src/product-shell/search/search-service.js +9 -2
  42. package/src/product-shell/social/chat-request-service.js +22 -7
  43. package/src/product-shell/social/friend-routes.js +1 -1
  44. package/src/product-shell/social/friend-service.js +16 -19
  45. package/src/product-shell/social/social-routes.js +2 -2
  46. package/src/product-shell/social/social-service.js +31 -35
  47. package/src/product-shell/worlds/world-admin-service.js +31 -10
  48. package/src/product-shell/worlds/world-broadcast-service.js +2 -2
  49. package/src/lib/agent-address.js +0 -46
@@ -8,6 +8,7 @@ import {
8
8
  CLAWORLD_INSTALLER_BIN_NAME,
9
9
  CLAWORLD_INSTALLER_COMMAND,
10
10
  CLAWORLD_INSTALLER_PACKAGE_NAME,
11
+ CLAWORLD_UNINSTALL_COMMAND,
11
12
  CLAWORLD_UPDATE_COMMAND,
12
13
  } from './constants.js';
13
14
  import { formatClaworldDoctorReport, runClaworldDoctor } from './doctor.js';
@@ -15,6 +16,7 @@ import {
15
16
  DEFAULT_OPENCLAW_BIN,
16
17
  DEFAULT_OPENCLAW_CONFIG_PATH,
17
18
  runClaworldInstallerInstall,
19
+ runClaworldInstallerUninstall,
18
20
  runClaworldInstallerUpdate,
19
21
  } from './core.js';
20
22
 
@@ -38,6 +40,7 @@ Commands:
38
40
  install Run the installer-first Claworld setup flow
39
41
  doctor Validate the managed Claworld install health
40
42
  update Update the tracked Claworld plugin, refresh managed state, and run doctor
43
+ uninstall Safely remove the managed Claworld runtime and uninstall the plugin
41
44
  upgrade Alias for update
42
45
  help Show this help
43
46
 
@@ -74,6 +77,12 @@ Doctor options:
74
77
  --account-id <id> Managed Claworld account id (default: claworld)
75
78
  --agent-id <id> Local OpenClaw agent id bound to claworld (default: main)
76
79
  --workspace <path> Optional dedicated workspace path override
80
+ Uninstall options:
81
+ --config <path> OpenClaw config path (default: ${DEFAULT_OPENCLAW_CONFIG_PATH})
82
+ --state-dir <path> Optional OPENCLAW_STATE_DIR for OpenClaw commands
83
+ --openclaw-bin <path> OpenClaw CLI binary (default: ${DEFAULT_OPENCLAW_BIN})
84
+ --account-id <id> Managed Claworld account id (default: claworld)
85
+ --agent-id <id> Local OpenClaw agent id bound to claworld (default: main)
77
86
  --json Print machine-readable result
78
87
  --help, -h Show this help
79
88
 
@@ -81,6 +90,7 @@ Canonical commands:
81
90
  ${CLAWORLD_INSTALLER_COMMAND}
82
91
  ${CLAWORLD_DOCTOR_COMMAND}
83
92
  ${CLAWORLD_UPDATE_COMMAND}
93
+ ${CLAWORLD_UNINSTALL_COMMAND}
84
94
  `);
85
95
  }
86
96
 
@@ -132,6 +142,13 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
132
142
  agentId: 'main',
133
143
  workspace: null,
134
144
  },
145
+ uninstall: {
146
+ openclawBin: env.OPENCLAW_BIN || DEFAULT_OPENCLAW_BIN,
147
+ configPath: expandUserPath(env.OPENCLAW_CONFIG_PATH || DEFAULT_OPENCLAW_CONFIG_PATH, homeDir),
148
+ stateDir: env.OPENCLAW_STATE_DIR ? expandUserPath(env.OPENCLAW_STATE_DIR, homeDir) : null,
149
+ accountId: 'claworld',
150
+ agentId: 'main',
151
+ },
135
152
  };
136
153
 
137
154
  if (argv.length === 0) {
@@ -149,18 +166,21 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
149
166
  options.install.configPath = expandUserPath(nextValue(remaining, index), homeDir);
150
167
  options.update.configPath = options.install.configPath;
151
168
  options.doctor.configPath = options.install.configPath;
169
+ options.uninstall.configPath = options.install.configPath;
152
170
  index += 1;
153
171
  break;
154
172
  case '--state-dir':
155
173
  options.install.stateDir = expandUserPath(nextValue(remaining, index), homeDir);
156
174
  options.update.stateDir = options.install.stateDir;
157
175
  options.doctor.stateDir = options.install.stateDir;
176
+ options.uninstall.stateDir = options.install.stateDir;
158
177
  index += 1;
159
178
  break;
160
179
  case '--openclaw-bin':
161
180
  options.install.openclawBin = nextValue(remaining, index);
162
181
  options.update.openclawBin = options.install.openclawBin;
163
182
  options.doctor.openclawBin = options.install.openclawBin;
183
+ options.uninstall.openclawBin = options.install.openclawBin;
164
184
  index += 1;
165
185
  break;
166
186
  case '--server-url':
@@ -178,12 +198,14 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
178
198
  options.install.accountId = nextValue(remaining, index);
179
199
  options.update.accountId = options.install.accountId;
180
200
  options.doctor.accountId = options.install.accountId;
201
+ options.uninstall.accountId = options.install.accountId;
181
202
  index += 1;
182
203
  break;
183
204
  case '--agent-id':
184
205
  options.install.agentId = nextValue(remaining, index);
185
206
  options.update.agentId = options.install.agentId;
186
207
  options.doctor.agentId = options.install.agentId;
208
+ options.uninstall.agentId = options.install.agentId;
187
209
  index += 1;
188
210
  break;
189
211
  case '--workspace':
@@ -226,7 +248,7 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
226
248
  }
227
249
  }
228
250
 
229
- if (!['install', 'update', 'doctor', 'help'].includes(options.command)) {
251
+ if (!['install', 'update', 'uninstall', 'doctor', 'help'].includes(options.command)) {
230
252
  throw new Error(`Unknown command: ${options.command}`);
231
253
  }
232
254
  if (options.command === 'install' && !['npm', 'link', 'copy', 'skip'].includes(options.install.pluginInstallMode)) {
@@ -304,6 +326,19 @@ function printUpdateSummary(result, doctorResult) {
304
326
  console.log('');
305
327
  }
306
328
 
329
+ function printUninstallSummary(result) {
330
+ console.log('');
331
+ console.log('Claworld uninstall complete');
332
+ console.log('===========================');
333
+ console.log(`Managed account: ${result.transformed?.backup?.accountId || 'claworld'}`);
334
+ console.log(`OpenClaw version: ${result.host?.version || '(unknown)'}`);
335
+ console.log(`Plugin action: ${result.plugin?.action || 'unknown'}`);
336
+ console.log(`Runtime refresh: ${result.runtimeRefresh?.action || 'unknown'}`);
337
+ console.log(`Config path: ${result.configPath}`);
338
+ console.log(`Backup path: ${result.backupPath || '(unchanged or new file)'}`);
339
+ console.log('');
340
+ }
341
+
307
342
  export async function runInstallerCli(argv = process.argv.slice(2), env = process.env) {
308
343
  const parsed = parseInstallerCliArgs(argv, env);
309
344
  if (parsed.command === 'help') {
@@ -347,6 +382,16 @@ export async function runInstallerCli(argv = process.argv.slice(2), env = proces
347
382
  };
348
383
  }
349
384
 
385
+ if (parsed.command === 'uninstall') {
386
+ const result = await runClaworldInstallerUninstall(parsed.uninstall);
387
+ if (parsed.json) {
388
+ console.log(JSON.stringify(result, null, 2));
389
+ } else {
390
+ printUninstallSummary(result);
391
+ }
392
+ return result;
393
+ }
394
+
350
395
  const result = await runClaworldDoctor(parsed.doctor);
351
396
  if (parsed.json) {
352
397
  console.log(JSON.stringify(result, null, 2));
@@ -3,4 +3,5 @@ export const CLAWORLD_INSTALLER_PACKAGE_NAME = '@xfxstudio/claworld';
3
3
  export const CLAWORLD_INSTALLER_COMMAND = 'npx -y @xfxstudio/claworld install';
4
4
  export const CLAWORLD_DOCTOR_COMMAND = 'npx -y @xfxstudio/claworld doctor';
5
5
  export const CLAWORLD_UPDATE_COMMAND = 'npx -y @xfxstudio/claworld update';
6
+ export const CLAWORLD_UNINSTALL_COMMAND = 'npx -y @xfxstudio/claworld uninstall';
6
7
  export const CLAWORLD_OPENCLAW_MIN_HOST_VERSION = '>=2026.3.22';
@@ -11,8 +11,11 @@ import {
11
11
  applyClaworldManagedRuntimeConfig,
12
12
  ensureObject,
13
13
  expandUserPath,
14
+ findClaworldManagedRuntimeBackup,
14
15
  normalizeText,
15
16
  resolveClaworldManagedRuntimeOptions,
17
+ setClaworldManagedRuntimeBackupState,
18
+ stripClaworldManagedRuntimeConfig,
16
19
  } from '../plugin/managed-config.js';
17
20
  import {
18
21
  defaultClaworldAccountId,
@@ -23,6 +26,7 @@ import {
23
26
  CLAWORLD_INSTALLER_COMMAND,
24
27
  CLAWORLD_INSTALLER_PACKAGE_NAME,
25
28
  CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
29
+ CLAWORLD_UNINSTALL_COMMAND,
26
30
  CLAWORLD_UPDATE_COMMAND,
27
31
  } from './constants.js';
28
32
  import { seedManagedWorkspaceContract } from './workspace-contract.js';
@@ -143,7 +147,7 @@ export function isRelayBootstrapReady(account = {}) {
143
147
  normalizeText(account?.appToken, null)
144
148
  || (
145
149
  account?.registration?.enabled === true
146
- && normalizeText(account?.registration?.agentCode, null)
150
+ && normalizeText(account?.registration?.displayName, null)
147
151
  )
148
152
  ),
149
153
  );
@@ -658,6 +662,23 @@ export async function loadConfigFromDisk(configPath) {
658
662
  }
659
663
  }
660
664
 
665
+ export function resolveClaworldInstallerStatePath(configPath) {
666
+ const resolvedConfigPath = path.resolve(String(configPath || DEFAULT_OPENCLAW_CONFIG_PATH));
667
+ return path.join(path.dirname(resolvedConfigPath), '.claworld-installer-state.json');
668
+ }
669
+
670
+ export async function loadInstallerStateFromDisk(installerStatePath) {
671
+ try {
672
+ const raw = await fs.readFile(installerStatePath, 'utf8');
673
+ return { existed: true, state: parseConfigObject(raw, installerStatePath) };
674
+ } catch (error) {
675
+ if (error && error.code === 'ENOENT') {
676
+ return { existed: false, state: {} };
677
+ }
678
+ throw error;
679
+ }
680
+ }
681
+
661
682
  export async function backupConfigIfPresent(configPath, existed, dryRun = false) {
662
683
  if (!existed) return null;
663
684
  const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\..+$/, '').replace('T', '-');
@@ -675,6 +696,20 @@ export async function writeConfig(configPath, config, dryRun = false) {
675
696
  return rendered;
676
697
  }
677
698
 
699
+ export async function writeInstallerState(installerStatePath, installerState, dryRun = false) {
700
+ const renderedState = ensureObject(installerState);
701
+ if (Object.keys(renderedState).length === 0) {
702
+ if (dryRun) return '';
703
+ await fs.rm(installerStatePath, { force: true });
704
+ return '';
705
+ }
706
+ const rendered = `${JSON.stringify(renderedState, null, 2)}\n`;
707
+ if (dryRun) return rendered;
708
+ await fs.mkdir(path.dirname(installerStatePath), { recursive: true });
709
+ await fs.writeFile(installerStatePath, rendered, 'utf8');
710
+ return rendered;
711
+ }
712
+
678
713
  export function buildOpenclawCommandEnv({ configPath, stateDir = null, env = process.env } = {}) {
679
714
  return {
680
715
  ...env,
@@ -688,6 +723,7 @@ export function inspectManagedClaworldInstall({
688
723
  accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
689
724
  input = {},
690
725
  overrides = {},
726
+ installerState = {},
691
727
  } = {}) {
692
728
  const configuredAccountIds = listClaworldAccountIds(cfg);
693
729
  const hasAnyConfig = configuredAccountIds.length > 0 || cfg?.channels?.claworld != null;
@@ -696,6 +732,7 @@ export function inspectManagedClaworldInstall({
696
732
  accountId,
697
733
  input,
698
734
  overrides,
735
+ installerState,
699
736
  });
700
737
  const managedAgentPresent = Boolean(findAgentEntry(cfg, managedOptions.agentId));
701
738
  const managedBindingPresent = hasManagedBinding(cfg, managedOptions);
@@ -735,7 +772,10 @@ export function inspectManagedClaworldInstall({
735
772
  accountStatus,
736
773
  managedRuntimeReady,
737
774
  managedReady,
738
- reusableAppToken: normalizeText(accountStatus?.appToken, null),
775
+ reusableAppToken: normalizeText(
776
+ managedOptions.appToken,
777
+ normalizeText(accountStatus?.appToken, null),
778
+ ),
739
779
  statusLabel,
740
780
  selectionHint,
741
781
  quickstartScore: managedRuntimeReady ? 2 : 5,
@@ -879,7 +919,7 @@ export async function ensureClaworldPluginInstalled({
879
919
  });
880
920
  }
881
921
 
882
- const args = ['plugins', 'install'];
922
+ const args = ['plugins', 'install', '--dangerously-force-unsafe-install'];
883
923
  if (installMode === 'link') args.push('--link');
884
924
  args.push(installSource);
885
925
  await executeCommand({
@@ -1337,8 +1377,10 @@ export async function verifyClaworldInstall({
1337
1377
  async function reconcileManagedClaworldRuntime({
1338
1378
  openclawBin = DEFAULT_OPENCLAW_BIN,
1339
1379
  configPath = DEFAULT_OPENCLAW_CONFIG_PATH,
1380
+ installerStatePath = null,
1340
1381
  stateDir = DEFAULT_OPENCLAW_STATE_DIR,
1341
1382
  currentConfigState = { existed: false, config: {} },
1383
+ currentInstallerState = {},
1342
1384
  currentConfig = {},
1343
1385
  host = null,
1344
1386
  serverUrl = null,
@@ -1361,6 +1403,7 @@ async function reconcileManagedClaworldRuntime({
1361
1403
  const existingInstall = inspectManagedClaworldInstall({
1362
1404
  cfg: currentConfig,
1363
1405
  accountId,
1406
+ installerState: currentInstallerState,
1364
1407
  overrides: {
1365
1408
  agentId,
1366
1409
  workspace,
@@ -1405,6 +1448,7 @@ async function reconcileManagedClaworldRuntime({
1405
1448
  const preflight = inspectManagedClaworldInstall({
1406
1449
  cfg: currentConfig,
1407
1450
  accountId: installAccountId,
1451
+ installerState: currentInstallerState,
1408
1452
  overrides: {
1409
1453
  agentId: installAgentId,
1410
1454
  workspace,
@@ -1453,6 +1497,7 @@ async function reconcileManagedClaworldRuntime({
1453
1497
 
1454
1498
  const managedOptions = resolveClaworldManagedRuntimeOptions({
1455
1499
  cfg: currentConfig,
1500
+ installerState: currentInstallerState,
1456
1501
  accountId: installAccountId,
1457
1502
  input: {
1458
1503
  name: desiredDisplayName,
@@ -1526,6 +1571,16 @@ async function reconcileManagedClaworldRuntime({
1526
1571
  );
1527
1572
  }
1528
1573
 
1574
+ let installerStateChanged = false;
1575
+ if (installerStatePath && installAccountId) {
1576
+ const nextInstallerState = JSON.parse(JSON.stringify(ensureObject(currentInstallerState)));
1577
+ setClaworldManagedRuntimeBackupState(nextInstallerState, installAccountId, null);
1578
+ installerStateChanged = JSON.stringify(currentInstallerState) !== JSON.stringify(nextInstallerState);
1579
+ if (installerStateChanged) {
1580
+ await writeInstallerState(installerStatePath, nextInstallerState, dryRun);
1581
+ }
1582
+ }
1583
+
1529
1584
  return {
1530
1585
  backupPath,
1531
1586
  existingInstall,
@@ -1540,6 +1595,8 @@ async function reconcileManagedClaworldRuntime({
1540
1595
  workspaceActions,
1541
1596
  runtimeRefresh,
1542
1597
  verification,
1598
+ installerStatePath,
1599
+ installerStateChanged,
1543
1600
  };
1544
1601
  }
1545
1602
 
@@ -1567,6 +1624,7 @@ export async function runClaworldInstallerInstall({
1567
1624
  timeoutMs = DEFAULT_INSTALL_TIMEOUT_MS,
1568
1625
  } = {}) {
1569
1626
  const resolvedConfigPath = path.resolve(expandUserPath(configPath, os.homedir()));
1627
+ const installerStatePath = resolveClaworldInstallerStatePath(resolvedConfigPath);
1570
1628
  const resolvedStateDir = stateDir ? path.resolve(expandUserPath(stateDir, os.homedir())) : null;
1571
1629
  const commandEnv = buildOpenclawCommandEnv({
1572
1630
  configPath: resolvedConfigPath,
@@ -1574,6 +1632,7 @@ export async function runClaworldInstallerInstall({
1574
1632
  env,
1575
1633
  });
1576
1634
  const currentConfigState = await loadConfigFromDisk(resolvedConfigPath);
1635
+ const currentInstallerState = (await loadInstallerStateFromDisk(installerStatePath)).state;
1577
1636
  const currentConfigBeforePluginInstall = currentConfigState.config;
1578
1637
  const host = await detectOpenclawHost({
1579
1638
  openclawBin,
@@ -1620,8 +1679,10 @@ export async function runClaworldInstallerInstall({
1620
1679
  const lifecycle = await reconcileManagedClaworldRuntime({
1621
1680
  openclawBin,
1622
1681
  configPath: resolvedConfigPath,
1682
+ installerStatePath,
1623
1683
  stateDir: resolvedStateDir,
1624
1684
  currentConfigState,
1685
+ currentInstallerState,
1625
1686
  currentConfig,
1626
1687
  host,
1627
1688
  serverUrl,
@@ -1646,6 +1707,7 @@ export async function runClaworldInstallerInstall({
1646
1707
  ok: true,
1647
1708
  command: CLAWORLD_INSTALLER_COMMAND,
1648
1709
  configPath: resolvedConfigPath,
1710
+ installerStatePath,
1649
1711
  stateDir: resolvedStateDir,
1650
1712
  host,
1651
1713
  plugin,
@@ -1674,6 +1736,7 @@ export async function runClaworldInstallerUpdate({
1674
1736
  timeoutMs = DEFAULT_INSTALL_TIMEOUT_MS,
1675
1737
  } = {}) {
1676
1738
  const resolvedConfigPath = path.resolve(expandUserPath(configPath, os.homedir()));
1739
+ const installerStatePath = resolveClaworldInstallerStatePath(resolvedConfigPath);
1677
1740
  const resolvedStateDir = stateDir ? path.resolve(expandUserPath(stateDir, os.homedir())) : null;
1678
1741
  const commandEnv = buildOpenclawCommandEnv({
1679
1742
  configPath: resolvedConfigPath,
@@ -1681,6 +1744,7 @@ export async function runClaworldInstallerUpdate({
1681
1744
  env,
1682
1745
  });
1683
1746
  const currentConfigState = await loadConfigFromDisk(resolvedConfigPath);
1747
+ const currentInstallerState = (await loadInstallerStateFromDisk(installerStatePath)).state;
1684
1748
  const host = await detectOpenclawHost({
1685
1749
  openclawBin,
1686
1750
  commandRunner,
@@ -1712,8 +1776,10 @@ export async function runClaworldInstallerUpdate({
1712
1776
  const lifecycle = await reconcileManagedClaworldRuntime({
1713
1777
  openclawBin,
1714
1778
  configPath: resolvedConfigPath,
1779
+ installerStatePath,
1715
1780
  stateDir: resolvedStateDir,
1716
1781
  currentConfigState: refreshedConfigState,
1782
+ currentInstallerState,
1717
1783
  currentConfig,
1718
1784
  host,
1719
1785
  serverUrl,
@@ -1737,6 +1803,7 @@ export async function runClaworldInstallerUpdate({
1737
1803
  ok: true,
1738
1804
  command: CLAWORLD_UPDATE_COMMAND,
1739
1805
  configPath: resolvedConfigPath,
1806
+ installerStatePath,
1740
1807
  stateDir: resolvedStateDir,
1741
1808
  host,
1742
1809
  plugin,
@@ -1744,6 +1811,170 @@ export async function runClaworldInstallerUpdate({
1744
1811
  };
1745
1812
  }
1746
1813
 
1814
+ export async function runClaworldInstallerUninstall({
1815
+ openclawBin = DEFAULT_OPENCLAW_BIN,
1816
+ configPath = DEFAULT_OPENCLAW_CONFIG_PATH,
1817
+ stateDir = DEFAULT_OPENCLAW_STATE_DIR,
1818
+ accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
1819
+ agentId = DEFAULT_CLAWORLD_AGENT_ID,
1820
+ commandRunner = defaultCommandRunner,
1821
+ cwd = process.cwd(),
1822
+ env = process.env,
1823
+ dryRun = false,
1824
+ } = {}) {
1825
+ const resolvedConfigPath = path.resolve(expandUserPath(configPath, os.homedir()));
1826
+ const installerStatePath = resolveClaworldInstallerStatePath(resolvedConfigPath);
1827
+ const resolvedStateDir = stateDir ? path.resolve(expandUserPath(stateDir, os.homedir())) : null;
1828
+ const commandEnv = buildOpenclawCommandEnv({
1829
+ configPath: resolvedConfigPath,
1830
+ stateDir: resolvedStateDir,
1831
+ env,
1832
+ });
1833
+ const currentConfigState = await loadConfigFromDisk(resolvedConfigPath);
1834
+ const currentInstallerState = (await loadInstallerStateFromDisk(installerStatePath)).state;
1835
+ const currentConfig = currentConfigState.config;
1836
+ const host = await detectOpenclawHost({
1837
+ openclawBin,
1838
+ commandRunner,
1839
+ cwd,
1840
+ env: commandEnv,
1841
+ dryRun,
1842
+ });
1843
+ if (compareVersionParts(host.version, CLAWORLD_OPENCLAW_MIN_HOST_VERSION) < 0) {
1844
+ throw createInstallerError(
1845
+ 'openclaw_version_too_old',
1846
+ `OpenClaw ${host.version} is below the required minimum ${CLAWORLD_OPENCLAW_MIN_HOST_VERSION}.`,
1847
+ { hostVersion: host.version, minHostVersion: CLAWORLD_OPENCLAW_MIN_HOST_VERSION },
1848
+ );
1849
+ }
1850
+
1851
+ const pluginBefore = await inspectClaworldPluginInstall({
1852
+ openclawBin,
1853
+ configPath: resolvedConfigPath,
1854
+ stateDir: resolvedStateDir,
1855
+ commandRunner,
1856
+ cwd,
1857
+ env,
1858
+ dryRun,
1859
+ });
1860
+ const transformed = stripClaworldManagedRuntimeConfig(currentConfig, {
1861
+ accountId,
1862
+ agentId,
1863
+ preserveBackup: true,
1864
+ });
1865
+ const configChanged = JSON.stringify(currentConfig) !== JSON.stringify(transformed.config);
1866
+ const backupPath = configChanged
1867
+ ? await backupConfigIfPresent(resolvedConfigPath, currentConfigState.existed, dryRun)
1868
+ : null;
1869
+ if (configChanged) {
1870
+ await writeConfig(resolvedConfigPath, transformed.config, dryRun);
1871
+ }
1872
+ const nextInstallerState = JSON.parse(JSON.stringify(ensureObject(currentInstallerState)));
1873
+ setClaworldManagedRuntimeBackupState(nextInstallerState, accountId, transformed.backup);
1874
+ const installerStateChanged = JSON.stringify(currentInstallerState) !== JSON.stringify(nextInstallerState);
1875
+ if (installerStateChanged) {
1876
+ await writeInstallerState(installerStatePath, nextInstallerState, dryRun);
1877
+ }
1878
+
1879
+ await validateOpenclawConfig({
1880
+ openclawBin,
1881
+ configPath: resolvedConfigPath,
1882
+ stateDir: resolvedStateDir,
1883
+ commandRunner,
1884
+ cwd,
1885
+ env,
1886
+ dryRun,
1887
+ });
1888
+
1889
+ const uninstallBootstrap = pluginBefore.installed
1890
+ ? await preparePluginBootstrapConfig({
1891
+ configPath: resolvedConfigPath,
1892
+ config: currentConfig,
1893
+ dryRun,
1894
+ })
1895
+ : null;
1896
+
1897
+ let pluginAction = 'plugin_already_absent';
1898
+ try {
1899
+ if (pluginBefore.installed) {
1900
+ await executeCommand({
1901
+ commandRunner,
1902
+ bin: openclawBin,
1903
+ args: ['plugins', 'uninstall', 'claworld', '--force'],
1904
+ cwd,
1905
+ env: buildOpenclawCommandEnv({
1906
+ configPath: uninstallBootstrap?.configPath || resolvedConfigPath,
1907
+ stateDir: resolvedStateDir,
1908
+ env,
1909
+ }),
1910
+ dryRun,
1911
+ capture: false,
1912
+ });
1913
+ pluginAction = 'uninstalled_plugin';
1914
+ }
1915
+ } finally {
1916
+ if (uninstallBootstrap) {
1917
+ await uninstallBootstrap.cleanup();
1918
+ }
1919
+ }
1920
+
1921
+ const runtimeRefresh = await refreshOpenclawRuntime({
1922
+ openclawBin,
1923
+ configPath: resolvedConfigPath,
1924
+ stateDir: resolvedStateDir,
1925
+ commandRunner,
1926
+ cwd,
1927
+ env,
1928
+ dryRun,
1929
+ });
1930
+ const pluginAfter = await inspectClaworldPluginInstall({
1931
+ openclawBin,
1932
+ configPath: resolvedConfigPath,
1933
+ stateDir: resolvedStateDir,
1934
+ commandRunner,
1935
+ cwd,
1936
+ env,
1937
+ dryRun,
1938
+ });
1939
+ if (pluginBefore.installed && pluginAfter.installed) {
1940
+ throw createInstallerError(
1941
+ 'claworld_plugin_uninstall_failed',
1942
+ 'OpenClaw still reports the claworld plugin as installed after uninstall.',
1943
+ { before: pluginBefore, after: pluginAfter },
1944
+ );
1945
+ }
1946
+
1947
+ const gatewayStatus = await readGatewayStatus({
1948
+ openclawBin,
1949
+ configPath: resolvedConfigPath,
1950
+ stateDir: resolvedStateDir,
1951
+ commandRunner,
1952
+ cwd,
1953
+ env,
1954
+ dryRun,
1955
+ });
1956
+
1957
+ return {
1958
+ ok: true,
1959
+ command: CLAWORLD_UNINSTALL_COMMAND,
1960
+ configPath: resolvedConfigPath,
1961
+ installerStatePath,
1962
+ stateDir: resolvedStateDir,
1963
+ host,
1964
+ backupPath,
1965
+ transformed,
1966
+ configChanged,
1967
+ installerStateChanged,
1968
+ plugin: {
1969
+ action: pluginAction,
1970
+ before: pluginBefore,
1971
+ after: pluginAfter,
1972
+ },
1973
+ runtimeRefresh,
1974
+ gatewayStatus,
1975
+ };
1976
+ }
1977
+
1747
1978
  export {
1748
1979
  compareVersionParts,
1749
1980
  defaultCommandRunner,
@@ -249,8 +249,8 @@ export async function runClaworldDoctor({
249
249
  workspace: resolvedWorkspace,
250
250
  serverUrl: effectiveServerUrl,
251
251
  appToken: configuredAccount.appToken,
252
- registrationAgentCode: configuredAccount.registration?.agentCode || null,
253
- defaultToAddress: configuredAccount.relay?.defaultToAddress || null,
252
+ registrationDisplayName: configuredAccount.registration?.displayName || null,
253
+ defaultTargetAgentId: configuredAccount.relay?.defaultTargetAgentId || null,
254
254
  })
255
255
  : {
256
256
  ok: true,
@@ -17,7 +17,6 @@ export function normalizeRuntimeRegistration(candidate = {}) {
17
17
 
18
18
  return {
19
19
  enabled: true,
20
- agentCode: normalizeText(registration.agentCode, normalizeText(legacyLocalAgent.agentCode, null)),
21
20
  displayName: normalizeText(registration.displayName, normalizeText(legacyLocalAgent.displayName, null)),
22
21
  };
23
22
  }
@@ -49,7 +48,7 @@ export function applyRuntimeIdentity(runtimeConfig = {}, { agentId = null, appTo
49
48
  agentId: normalizeText(agentId, normalizeText(relay.agentId, null)),
50
49
  appToken: resolvedAppToken,
51
50
  credentialToken: resolvedAppToken,
52
- defaultToAddress: normalizeText(relay.defaultToAddress, null),
51
+ defaultTargetAgentId: normalizeText(relay.defaultTargetAgentId, null),
53
52
  },
54
53
  };
55
54
  }