@xfxstudio/claworld 0.2.10-beta.0 → 0.2.10-beta.2
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 +1 -1
- package/package.json +1 -1
- package/src/openclaw/installer/cli.js +8 -9
- package/src/openclaw/installer/constants.js +7 -0
- package/src/openclaw/installer/core.js +185 -79
- package/src/openclaw/installer/doctor.js +29 -15
- package/src/openclaw/plugin/claworld-channel-plugin.js +223 -48
- package/src/openclaw/plugin/managed-config.js +18 -13
- package/src/openclaw/plugin/onboarding.js +21 -9
- package/src/openclaw/plugin/register.js +25 -13
- package/src/product-shell/onboarding/onboarding-service.js +6 -5
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
|
}
|
|
@@ -296,10 +296,9 @@ function printInstallSummary(result) {
|
|
|
296
296
|
console.log('Claworld installer complete');
|
|
297
297
|
console.log('===========================');
|
|
298
298
|
console.log(`Managed account: ${result.transformed?.config?.channels?.claworld?.defaultAccount || 'claworld'}`);
|
|
299
|
-
console.log(`Canonical agentId: ${result.activation?.agentId || '(unknown)'}`);
|
|
300
299
|
console.log(`OpenClaw version: ${result.host?.version || '(unknown)'}`);
|
|
301
300
|
console.log(`Plugin action: ${result.plugin?.action || 'unknown'}`);
|
|
302
|
-
console.log(`Activation
|
|
301
|
+
console.log(`Activation: ${result.activationStatus === 'ready' ? 'ready' : 'pending via claworld_update_public_identity'}`);
|
|
303
302
|
console.log(`Runtime refresh: ${result.runtimeRefresh?.action || 'unknown'}`);
|
|
304
303
|
console.log(`Config path: ${result.configPath}`);
|
|
305
304
|
console.log(`Backup path: ${result.backupPath || '(unchanged or new file)'}`);
|
|
@@ -315,10 +314,10 @@ function printUpdateSummary(result, doctorResult) {
|
|
|
315
314
|
console.log('Claworld update complete');
|
|
316
315
|
console.log('========================');
|
|
317
316
|
console.log(`Managed account: ${result.managedOptions?.accountId || 'claworld'}`);
|
|
318
|
-
console.log(`Canonical agentId: ${result.activation?.agentId || '(unknown)'}`);
|
|
319
317
|
console.log(`OpenClaw version: ${result.host?.version || '(unknown)'}`);
|
|
320
318
|
console.log(`Plugin action: ${result.plugin?.action || 'unknown'}`);
|
|
321
319
|
console.log(`Tracked install: ${trackedSummary}`);
|
|
320
|
+
console.log(`Activation: ${result.activationStatus === 'ready' ? 'ready' : 'pending via claworld_update_public_identity'}`);
|
|
322
321
|
console.log(`Runtime refresh: ${result.runtimeRefresh?.action || 'unknown'}`);
|
|
323
322
|
console.log(`Doctor status: ${doctorResult?.status || 'unknown'}`);
|
|
324
323
|
console.log(`Config path: ${result.configPath}`);
|
|
@@ -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
|
|
|
@@ -143,13 +165,7 @@ export function isManagedToolAllowlistReady(config = {}, options = {}) {
|
|
|
143
165
|
export function isRelayBootstrapReady(account = {}) {
|
|
144
166
|
return Boolean(
|
|
145
167
|
account?.configured
|
|
146
|
-
&& (
|
|
147
|
-
normalizeText(account?.appToken, null)
|
|
148
|
-
|| (
|
|
149
|
-
account?.registration?.enabled === true
|
|
150
|
-
&& normalizeText(account?.registration?.displayName, null)
|
|
151
|
-
)
|
|
152
|
-
),
|
|
168
|
+
&& normalizeText(account?.appToken, null),
|
|
153
169
|
);
|
|
154
170
|
}
|
|
155
171
|
|
|
@@ -450,6 +466,7 @@ function inspectTrackedClaworldPluginInstall(config = {}) {
|
|
|
450
466
|
resolvedSpec: normalizeText(installRecord.resolvedSpec, null),
|
|
451
467
|
resolvedVersion: normalizeText(installRecord.resolvedVersion, null),
|
|
452
468
|
installPath: normalizeText(installRecord.installPath, null),
|
|
469
|
+
sourcePath: normalizeText(installRecord.sourcePath, null),
|
|
453
470
|
record: tracked ? installRecord : null,
|
|
454
471
|
};
|
|
455
472
|
}
|
|
@@ -533,6 +550,67 @@ function mergePluginMetadata(config = {}, pluginConfig = {}) {
|
|
|
533
550
|
return next;
|
|
534
551
|
}
|
|
535
552
|
|
|
553
|
+
async function installPublishedClaworldPackageToLocalSource({
|
|
554
|
+
installSource = CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
555
|
+
configPath = DEFAULT_OPENCLAW_CONFIG_PATH,
|
|
556
|
+
commandRunner = defaultCommandRunner,
|
|
557
|
+
cwd = process.cwd(),
|
|
558
|
+
env = process.env,
|
|
559
|
+
dryRun = false,
|
|
560
|
+
refresh = false,
|
|
561
|
+
} = {}) {
|
|
562
|
+
const installRoot = resolveInstallerManagedPluginInstallRoot(configPath);
|
|
563
|
+
const sourcePath = resolveInstallerManagedPluginSourcePath(installRoot);
|
|
564
|
+
if (!dryRun && refresh) {
|
|
565
|
+
await fs.rm(installRoot, { recursive: true, force: true });
|
|
566
|
+
}
|
|
567
|
+
if (!dryRun) {
|
|
568
|
+
await fs.mkdir(installRoot, { recursive: true });
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
await executeCommand({
|
|
572
|
+
commandRunner,
|
|
573
|
+
bin: DEFAULT_NPM_BIN,
|
|
574
|
+
args: [
|
|
575
|
+
'install',
|
|
576
|
+
'--ignore-scripts',
|
|
577
|
+
'--no-package-lock',
|
|
578
|
+
'--omit=dev',
|
|
579
|
+
'--prefix',
|
|
580
|
+
installRoot,
|
|
581
|
+
installSource,
|
|
582
|
+
],
|
|
583
|
+
cwd,
|
|
584
|
+
env,
|
|
585
|
+
dryRun,
|
|
586
|
+
capture: false,
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
let resolvedVersion = null;
|
|
590
|
+
if (!dryRun) {
|
|
591
|
+
const sourcePackageJson = await readJsonFile(path.join(sourcePath, 'package.json'));
|
|
592
|
+
resolvedVersion = normalizeText(sourcePackageJson?.version, null);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return {
|
|
596
|
+
installRoot,
|
|
597
|
+
sourcePath,
|
|
598
|
+
resolvedVersion,
|
|
599
|
+
pluginConfig: {
|
|
600
|
+
installs: {
|
|
601
|
+
claworld: {
|
|
602
|
+
source: 'installer_npm',
|
|
603
|
+
spec: installSource,
|
|
604
|
+
resolvedSpec: installSource,
|
|
605
|
+
...(resolvedVersion ? { resolvedVersion } : {}),
|
|
606
|
+
installPath: installRoot,
|
|
607
|
+
sourcePath,
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
536
614
|
function defaultCommandRunner({
|
|
537
615
|
bin,
|
|
538
616
|
args,
|
|
@@ -756,8 +834,8 @@ export function inspectManagedClaworldInstall({
|
|
|
756
834
|
statusLabel = managedReady ? 'configured' : 'configured (managed refresh recommended)';
|
|
757
835
|
selectionHint = managedReady ? 'configured · managed runtime' : 'configured · managed refresh';
|
|
758
836
|
} else if (hasAnyConfig) {
|
|
759
|
-
statusLabel = '
|
|
760
|
-
selectionHint = '
|
|
837
|
+
statusLabel = 'configured (activation pending)';
|
|
838
|
+
selectionHint = 'configured · activation pending';
|
|
761
839
|
}
|
|
762
840
|
|
|
763
841
|
return {
|
|
@@ -869,9 +947,10 @@ export async function ensureClaworldPluginInstalled({
|
|
|
869
947
|
env = process.env,
|
|
870
948
|
dryRun = false,
|
|
871
949
|
installMode = 'npm',
|
|
872
|
-
installSource =
|
|
950
|
+
installSource = CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
873
951
|
refresh = false,
|
|
874
952
|
} = {}) {
|
|
953
|
+
const trackedInstall = inspectTrackedClaworldPluginInstall(config);
|
|
875
954
|
const bootstrap = await preparePluginBootstrapConfig({
|
|
876
955
|
configPath,
|
|
877
956
|
config,
|
|
@@ -889,7 +968,17 @@ export async function ensureClaworldPluginInstalled({
|
|
|
889
968
|
env,
|
|
890
969
|
dryRun,
|
|
891
970
|
});
|
|
892
|
-
|
|
971
|
+
const reusableInstallerManagedNpmInstall = (
|
|
972
|
+
installMode === 'npm'
|
|
973
|
+
&& trackedInstall.tracked
|
|
974
|
+
&& trackedInstall.source === 'installer_npm'
|
|
975
|
+
&& normalizeText(trackedInstall.sourcePath, null)
|
|
976
|
+
);
|
|
977
|
+
if (
|
|
978
|
+
before.installed
|
|
979
|
+
&& !refresh
|
|
980
|
+
&& (installMode !== 'npm' || reusableInstallerManagedNpmInstall)
|
|
981
|
+
) {
|
|
893
982
|
return {
|
|
894
983
|
changed: false,
|
|
895
984
|
action: 'reused_existing_plugin_install',
|
|
@@ -907,6 +996,37 @@ export async function ensureClaworldPluginInstalled({
|
|
|
907
996
|
};
|
|
908
997
|
}
|
|
909
998
|
|
|
999
|
+
if (installMode === 'npm') {
|
|
1000
|
+
const localInstall = await installPublishedClaworldPackageToLocalSource({
|
|
1001
|
+
installSource,
|
|
1002
|
+
configPath,
|
|
1003
|
+
commandRunner,
|
|
1004
|
+
cwd,
|
|
1005
|
+
env,
|
|
1006
|
+
dryRun,
|
|
1007
|
+
refresh,
|
|
1008
|
+
});
|
|
1009
|
+
return {
|
|
1010
|
+
changed: true,
|
|
1011
|
+
action: reusableInstallerManagedNpmInstall ? 'refreshed_local_plugin_source' : 'staged_local_plugin_source',
|
|
1012
|
+
plugin: before,
|
|
1013
|
+
pluginConfig: {
|
|
1014
|
+
...ensureObject(bootstrap?.pluginConfig),
|
|
1015
|
+
...ensureObject(localInstall.pluginConfig),
|
|
1016
|
+
entries: {
|
|
1017
|
+
...ensureObject(bootstrap?.pluginConfig?.entries),
|
|
1018
|
+
...ensureObject(localInstall.pluginConfig?.entries),
|
|
1019
|
+
},
|
|
1020
|
+
installs: {
|
|
1021
|
+
...ensureObject(bootstrap?.pluginConfig?.installs),
|
|
1022
|
+
...ensureObject(localInstall.pluginConfig?.installs),
|
|
1023
|
+
},
|
|
1024
|
+
},
|
|
1025
|
+
installSource,
|
|
1026
|
+
managedRepoRoot: localInstall.sourcePath,
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
|
|
910
1030
|
if (before.installed && refresh && installMode === 'copy') {
|
|
911
1031
|
await executeCommand({
|
|
912
1032
|
commandRunner,
|
|
@@ -996,6 +1116,26 @@ export async function updateTrackedClaworldPluginInstall({
|
|
|
996
1116
|
);
|
|
997
1117
|
}
|
|
998
1118
|
|
|
1119
|
+
if (trackedInstall.source === 'installer_npm') {
|
|
1120
|
+
const localInstall = await installPublishedClaworldPackageToLocalSource({
|
|
1121
|
+
installSource: trackedInstall.spec || CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
1122
|
+
configPath,
|
|
1123
|
+
commandRunner,
|
|
1124
|
+
cwd,
|
|
1125
|
+
env,
|
|
1126
|
+
dryRun,
|
|
1127
|
+
refresh: true,
|
|
1128
|
+
});
|
|
1129
|
+
return {
|
|
1130
|
+
changed: true,
|
|
1131
|
+
action: dryRun ? 'dry_run_updated_local_plugin_source' : 'updated_local_plugin_source',
|
|
1132
|
+
trackedInstall,
|
|
1133
|
+
plugin: before,
|
|
1134
|
+
pluginConfig: localInstall.pluginConfig,
|
|
1135
|
+
managedRepoRoot: localInstall.sourcePath,
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
|
|
999
1139
|
if (!trackedInstall.tracked) {
|
|
1000
1140
|
return {
|
|
1001
1141
|
changed: false,
|
|
@@ -1288,6 +1428,7 @@ export async function verifyClaworldInstall({
|
|
|
1288
1428
|
attempts = DEFAULT_VERIFICATION_ATTEMPTS,
|
|
1289
1429
|
delayMs = DEFAULT_VERIFICATION_DELAY_MS,
|
|
1290
1430
|
requireGatewayRunning = resolveRequireGatewayRunning(env),
|
|
1431
|
+
requireChannelToken = true,
|
|
1291
1432
|
} = {}) {
|
|
1292
1433
|
let lastResult = null;
|
|
1293
1434
|
|
|
@@ -1341,7 +1482,10 @@ export async function verifyClaworldInstall({
|
|
|
1341
1482
|
channelAccount
|
|
1342
1483
|
&& channelAccount.configured === true
|
|
1343
1484
|
&& channelAccount.enabled !== false
|
|
1344
|
-
&&
|
|
1485
|
+
&& (
|
|
1486
|
+
requireChannelToken !== true
|
|
1487
|
+
|| channelAccount.tokenStatus === 'available'
|
|
1488
|
+
)
|
|
1345
1489
|
);
|
|
1346
1490
|
const pluginReady = Boolean(plugin.installed);
|
|
1347
1491
|
const bindingReady = Boolean(bindingLine);
|
|
@@ -1358,6 +1502,7 @@ export async function verifyClaworldInstall({
|
|
|
1358
1502
|
channelReady,
|
|
1359
1503
|
bindingReady,
|
|
1360
1504
|
requireGatewayRunning,
|
|
1505
|
+
requireChannelToken,
|
|
1361
1506
|
};
|
|
1362
1507
|
|
|
1363
1508
|
if (lastResult.ok) {
|
|
@@ -1419,30 +1564,13 @@ async function reconcileManagedClaworldRuntime({
|
|
|
1419
1564
|
normalizeText(existingInstall.accountStatus?.serverUrl, DEFAULT_CLAWORLD_SERVER_URL),
|
|
1420
1565
|
);
|
|
1421
1566
|
|
|
1422
|
-
const manifest = await fetchInstallManifest({
|
|
1423
|
-
serverUrl: effectiveServerUrl,
|
|
1424
|
-
apiKey,
|
|
1425
|
-
fetchImpl,
|
|
1426
|
-
});
|
|
1427
|
-
const manifestMinHostVersion = normalizeText(
|
|
1428
|
-
manifest?.installer?.minHostVersion,
|
|
1429
|
-
normalizeText(manifest?.plugin?.minHostVersion, CLAWORLD_OPENCLAW_MIN_HOST_VERSION),
|
|
1430
|
-
);
|
|
1431
|
-
if (host && compareVersionParts(host.version, manifestMinHostVersion) < 0) {
|
|
1432
|
-
throw createInstallerError(
|
|
1433
|
-
'openclaw_version_too_old',
|
|
1434
|
-
`OpenClaw ${host.version} is below the required minimum ${manifestMinHostVersion}.`,
|
|
1435
|
-
{ hostVersion: host.version, minHostVersion: manifestMinHostVersion },
|
|
1436
|
-
);
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
1567
|
const installAccountId = normalizeText(
|
|
1440
1568
|
accountId,
|
|
1441
|
-
|
|
1569
|
+
DEFAULT_CLAWORLD_ACCOUNT_ID,
|
|
1442
1570
|
);
|
|
1443
1571
|
const installAgentId = normalizeText(
|
|
1444
1572
|
agentId,
|
|
1445
|
-
|
|
1573
|
+
installAccountId,
|
|
1446
1574
|
);
|
|
1447
1575
|
|
|
1448
1576
|
const preflight = inspectManagedClaworldInstall({
|
|
@@ -1465,51 +1593,15 @@ async function reconcileManagedClaworldRuntime({
|
|
|
1465
1593
|
normalizeText(preflight.managedOptions.displayName, null),
|
|
1466
1594
|
);
|
|
1467
1595
|
|
|
1468
|
-
let activation = null;
|
|
1469
|
-
let activationMode = 'new_activation';
|
|
1470
|
-
const existingAppToken = normalizeText(preflight.reusableAppToken, null);
|
|
1471
|
-
if (existingAppToken) {
|
|
1472
|
-
try {
|
|
1473
|
-
activation = await activateInstall({
|
|
1474
|
-
serverUrl: effectiveServerUrl,
|
|
1475
|
-
apiKey,
|
|
1476
|
-
appToken: existingAppToken,
|
|
1477
|
-
displayName: desiredDisplayName,
|
|
1478
|
-
fetchImpl,
|
|
1479
|
-
});
|
|
1480
|
-
activationMode = 'reused_existing_token';
|
|
1481
|
-
} catch (error) {
|
|
1482
|
-
const status = error?.context?.response?.status;
|
|
1483
|
-
if (status !== 401 && status !== 403) {
|
|
1484
|
-
throw error;
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
if (!activation) {
|
|
1489
|
-
activation = await activateInstall({
|
|
1490
|
-
serverUrl: effectiveServerUrl,
|
|
1491
|
-
apiKey,
|
|
1492
|
-
displayName: desiredDisplayName,
|
|
1493
|
-
fetchImpl,
|
|
1494
|
-
});
|
|
1495
|
-
activationMode = 'created_new_activation';
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
1596
|
const managedOptions = resolveClaworldManagedRuntimeOptions({
|
|
1499
1597
|
cfg: currentConfig,
|
|
1500
1598
|
installerState: currentInstallerState,
|
|
1501
1599
|
accountId: installAccountId,
|
|
1502
|
-
input: {
|
|
1503
|
-
name: desiredDisplayName,
|
|
1504
|
-
appToken: activation.appToken,
|
|
1505
|
-
toolProfile,
|
|
1506
|
-
},
|
|
1507
1600
|
overrides: {
|
|
1508
1601
|
agentId: installAgentId,
|
|
1509
1602
|
workspace,
|
|
1510
1603
|
serverUrl: effectiveServerUrl,
|
|
1511
1604
|
apiKey,
|
|
1512
|
-
appToken: activation.appToken,
|
|
1513
1605
|
displayName: desiredDisplayName,
|
|
1514
1606
|
toolProfile,
|
|
1515
1607
|
approvalMode,
|
|
@@ -1521,7 +1613,7 @@ async function reconcileManagedClaworldRuntime({
|
|
|
1521
1613
|
},
|
|
1522
1614
|
});
|
|
1523
1615
|
|
|
1524
|
-
const transformed =
|
|
1616
|
+
const transformed = applyClaworldBootstrapConfig(currentConfig, managedOptions);
|
|
1525
1617
|
const configChanged = JSON.stringify(currentConfig) !== JSON.stringify(transformed.config);
|
|
1526
1618
|
const backupPath = configChanged
|
|
1527
1619
|
? await backupConfigIfPresent(configPath, currentConfigState.existed, dryRun)
|
|
@@ -1562,11 +1654,12 @@ async function reconcileManagedClaworldRuntime({
|
|
|
1562
1654
|
env,
|
|
1563
1655
|
dryRun,
|
|
1564
1656
|
delayMs: Math.min(timeoutMs, DEFAULT_VERIFICATION_DELAY_MS),
|
|
1657
|
+
requireChannelToken: Boolean(managedOptions.appToken),
|
|
1565
1658
|
});
|
|
1566
1659
|
if (!verification.ok) {
|
|
1567
1660
|
throw createInstallerError(
|
|
1568
1661
|
'claworld_install_verification_failed',
|
|
1569
|
-
'Claworld install verification did not confirm the managed
|
|
1662
|
+
'Claworld install verification did not confirm the managed channel runtime shape.',
|
|
1570
1663
|
{ verification },
|
|
1571
1664
|
);
|
|
1572
1665
|
}
|
|
@@ -1585,10 +1678,8 @@ async function reconcileManagedClaworldRuntime({
|
|
|
1585
1678
|
backupPath,
|
|
1586
1679
|
existingInstall,
|
|
1587
1680
|
effectiveServerUrl,
|
|
1588
|
-
manifest,
|
|
1589
1681
|
preflight,
|
|
1590
|
-
|
|
1591
|
-
activation,
|
|
1682
|
+
activationStatus: managedOptions.appToken ? 'ready' : 'pending',
|
|
1592
1683
|
managedOptions,
|
|
1593
1684
|
transformed,
|
|
1594
1685
|
configChanged,
|
|
@@ -1615,7 +1706,7 @@ export async function runClaworldInstallerInstall({
|
|
|
1615
1706
|
sessionDmScope = null,
|
|
1616
1707
|
repoRoot = null,
|
|
1617
1708
|
pluginInstallMode = 'npm',
|
|
1618
|
-
pluginInstallSource =
|
|
1709
|
+
pluginInstallSource = CLAWORLD_INSTALLER_DEFAULT_PLUGIN_SOURCE,
|
|
1619
1710
|
fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
1620
1711
|
commandRunner = defaultCommandRunner,
|
|
1621
1712
|
cwd = process.cwd(),
|
|
@@ -1694,7 +1785,7 @@ export async function runClaworldInstallerInstall({
|
|
|
1694
1785
|
toolProfile,
|
|
1695
1786
|
approvalMode,
|
|
1696
1787
|
sessionDmScope,
|
|
1697
|
-
repoRoot: localPluginInstall.managedRepoRoot,
|
|
1788
|
+
repoRoot: plugin.managedRepoRoot || localPluginInstall.managedRepoRoot,
|
|
1698
1789
|
fetchImpl,
|
|
1699
1790
|
commandRunner,
|
|
1700
1791
|
cwd,
|
|
@@ -1772,7 +1863,7 @@ export async function runClaworldInstallerUpdate({
|
|
|
1772
1863
|
});
|
|
1773
1864
|
|
|
1774
1865
|
const refreshedConfigState = await loadConfigFromDisk(resolvedConfigPath);
|
|
1775
|
-
const currentConfig = mergePluginMetadata(refreshedConfigState.config, null);
|
|
1866
|
+
const currentConfig = mergePluginMetadata(refreshedConfigState.config, plugin.pluginConfig || null);
|
|
1776
1867
|
const lifecycle = await reconcileManagedClaworldRuntime({
|
|
1777
1868
|
openclawBin,
|
|
1778
1869
|
configPath: resolvedConfigPath,
|
|
@@ -1791,6 +1882,7 @@ export async function runClaworldInstallerUpdate({
|
|
|
1791
1882
|
toolProfile,
|
|
1792
1883
|
approvalMode,
|
|
1793
1884
|
sessionDmScope,
|
|
1885
|
+
repoRoot: plugin.managedRepoRoot || null,
|
|
1794
1886
|
fetchImpl,
|
|
1795
1887
|
commandRunner,
|
|
1796
1888
|
cwd,
|
|
@@ -1833,6 +1925,7 @@ export async function runClaworldInstallerUninstall({
|
|
|
1833
1925
|
const currentConfigState = await loadConfigFromDisk(resolvedConfigPath);
|
|
1834
1926
|
const currentInstallerState = (await loadInstallerStateFromDisk(installerStatePath)).state;
|
|
1835
1927
|
const currentConfig = currentConfigState.config;
|
|
1928
|
+
const trackedInstall = inspectTrackedClaworldPluginInstall(currentConfig);
|
|
1836
1929
|
const host = await detectOpenclawHost({
|
|
1837
1930
|
openclawBin,
|
|
1838
1931
|
commandRunner,
|
|
@@ -1896,7 +1989,20 @@ export async function runClaworldInstallerUninstall({
|
|
|
1896
1989
|
|
|
1897
1990
|
let pluginAction = 'plugin_already_absent';
|
|
1898
1991
|
try {
|
|
1899
|
-
if (
|
|
1992
|
+
if (trackedInstall.source === 'installer_npm') {
|
|
1993
|
+
const localInstallPath = normalizeText(trackedInstall.installPath, null) || normalizeText(trackedInstall.sourcePath, null);
|
|
1994
|
+
if (!localInstallPath) {
|
|
1995
|
+
throw createInstallerError(
|
|
1996
|
+
'claworld_installer_managed_source_missing',
|
|
1997
|
+
'Installer-managed Claworld source is missing its local install path.',
|
|
1998
|
+
{ trackedInstall },
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
if (!dryRun) {
|
|
2002
|
+
await fs.rm(localInstallPath, { recursive: true, force: true });
|
|
2003
|
+
}
|
|
2004
|
+
pluginAction = 'removed_local_plugin_source';
|
|
2005
|
+
} else if (pluginBefore.installed) {
|
|
1900
2006
|
await executeCommand({
|
|
1901
2007
|
commandRunner,
|
|
1902
2008
|
bin: openclawBin,
|
|
@@ -1936,7 +2042,7 @@ export async function runClaworldInstallerUninstall({
|
|
|
1936
2042
|
env,
|
|
1937
2043
|
dryRun,
|
|
1938
2044
|
});
|
|
1939
|
-
if (pluginBefore.installed && pluginAfter.installed) {
|
|
2045
|
+
if ((pluginBefore.installed || trackedInstall.source === 'installer_npm') && pluginAfter.installed) {
|
|
1940
2046
|
throw createInstallerError(
|
|
1941
2047
|
'claworld_plugin_uninstall_failed',
|
|
1942
2048
|
'OpenClaw still reports the claworld plugin as installed after uninstall.',
|
|
@@ -522,11 +522,13 @@ export async function runClaworldDoctor({
|
|
|
522
522
|
id: 'app-token',
|
|
523
523
|
category: 'Credentials and runtime',
|
|
524
524
|
label: 'Managed appToken',
|
|
525
|
-
status: configuredAccount.tokenStatus === 'available' ? 'pass' : '
|
|
525
|
+
status: configuredAccount.tokenStatus === 'available' ? 'pass' : 'warn',
|
|
526
526
|
summary: configuredAccount.tokenStatus === 'available'
|
|
527
527
|
? 'Managed account has an available appToken.'
|
|
528
|
-
: `Managed account token status is ${configuredAccount.tokenStatus}.`,
|
|
529
|
-
action:
|
|
528
|
+
: `Managed account token status is ${configuredAccount.tokenStatus}; activation is still pending.`,
|
|
529
|
+
action: configuredAccount.tokenStatus === 'available'
|
|
530
|
+
? null
|
|
531
|
+
: 'Open a live OpenClaw session, run `claworld_pair_agent`, and then complete `claworld_update_public_identity` when prompted.',
|
|
530
532
|
details: { tokenSource: configuredAccount.tokenSource, tokenStatus: configuredAccount.tokenStatus },
|
|
531
533
|
}));
|
|
532
534
|
|
|
@@ -549,9 +551,9 @@ export async function runClaworldDoctor({
|
|
|
549
551
|
id: 'backend-reachable',
|
|
550
552
|
category: 'Credentials and runtime',
|
|
551
553
|
label: 'Claworld backend reachability',
|
|
552
|
-
status: '
|
|
553
|
-
summary: `Unable to
|
|
554
|
-
action: '
|
|
554
|
+
status: 'warn',
|
|
555
|
+
summary: `Unable to reach the Claworld backend at ${effectiveServerUrl}.`,
|
|
556
|
+
action: 'Restore backend reachability before pairing or live Claworld use, then rerun doctor.',
|
|
555
557
|
details: { serverUrl: effectiveServerUrl, message: error?.message || String(error) },
|
|
556
558
|
}));
|
|
557
559
|
}
|
|
@@ -580,7 +582,7 @@ export async function runClaworldDoctor({
|
|
|
580
582
|
label: 'Stable relay binding',
|
|
581
583
|
status: 'fail',
|
|
582
584
|
summary: 'Managed appToken could not be resolved into a healthy backend binding.',
|
|
583
|
-
action: `
|
|
585
|
+
action: 'Run `claworld_pair_agent` in a live OpenClaw session to refresh the managed relay binding.',
|
|
584
586
|
details: { message: error?.message || String(error) },
|
|
585
587
|
}));
|
|
586
588
|
}
|
|
@@ -589,17 +591,17 @@ export async function runClaworldDoctor({
|
|
|
589
591
|
id: 'stable-agent-binding',
|
|
590
592
|
category: 'Credentials and runtime',
|
|
591
593
|
label: 'Stable relay binding',
|
|
592
|
-
status: '
|
|
593
|
-
summary: 'Doctor could not verify the managed relay binding because
|
|
594
|
-
action:
|
|
594
|
+
status: 'warn',
|
|
595
|
+
summary: 'Doctor could not verify the managed relay binding because activation is still pending.',
|
|
596
|
+
action: 'Open a live OpenClaw session, run `claworld_pair_agent`, and then complete `claworld_update_public_identity` when prompted.',
|
|
595
597
|
}));
|
|
596
598
|
} else {
|
|
597
599
|
checks.push(createCheck({
|
|
598
600
|
id: 'stable-agent-binding',
|
|
599
601
|
category: 'Credentials and runtime',
|
|
600
602
|
label: 'Stable relay binding',
|
|
601
|
-
status: '
|
|
602
|
-
summary: 'Doctor could not verify the managed relay binding because the backend
|
|
603
|
+
status: 'warn',
|
|
604
|
+
summary: 'Doctor could not verify the managed relay binding because the backend was not reachable.',
|
|
603
605
|
action: 'Restore backend reachability, then rerun doctor to verify the managed relay binding.',
|
|
604
606
|
}));
|
|
605
607
|
}
|
|
@@ -655,15 +657,27 @@ export async function runClaworldDoctor({
|
|
|
655
657
|
&& channelAccount.enabled !== false
|
|
656
658
|
&& channelAccount.tokenStatus === 'available'
|
|
657
659
|
);
|
|
660
|
+
const channelPendingActivation = Boolean(
|
|
661
|
+
channelAccount
|
|
662
|
+
&& channelAccount.configured === true
|
|
663
|
+
&& channelAccount.enabled !== false
|
|
664
|
+
&& channelAccount.tokenStatus !== 'available'
|
|
665
|
+
);
|
|
658
666
|
checks.push(createCheck({
|
|
659
667
|
id: 'channel-runtime',
|
|
660
668
|
category: 'Credentials and runtime',
|
|
661
669
|
label: 'Claworld channel runtime account',
|
|
662
|
-
status: channelHealthy ? 'pass' : 'fail',
|
|
670
|
+
status: channelHealthy ? 'pass' : channelPendingActivation ? 'warn' : 'fail',
|
|
663
671
|
summary: channelHealthy
|
|
664
672
|
? `channels status reports managed account \`${configuredAccount.accountId}\` as configured with an available token.`
|
|
665
|
-
:
|
|
666
|
-
|
|
673
|
+
: channelPendingActivation
|
|
674
|
+
? `channels status reports managed account \`${configuredAccount.accountId}\` as configured, but activation is still pending (${channelAccount.tokenStatus}).`
|
|
675
|
+
: `channels status does not report a healthy managed account for \`${configuredAccount.accountId}\`.`,
|
|
676
|
+
action: channelHealthy
|
|
677
|
+
? null
|
|
678
|
+
: channelPendingActivation
|
|
679
|
+
? 'Open a live OpenClaw session, run `claworld_pair_agent`, and then complete `claworld_update_public_identity` when prompted.'
|
|
680
|
+
: `Rerun \`${CLAWORLD_INSTALLER_COMMAND}\` or restart the gateway to recover the managed account runtime.`,
|
|
667
681
|
details: { channelAccount },
|
|
668
682
|
}));
|
|
669
683
|
} catch (error) {
|
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
normalizeRuntimeBoundaryError,
|
|
53
53
|
serializeRuntimeBoundaryError,
|
|
54
54
|
} from '../../lib/runtime-errors.js';
|
|
55
|
+
import { PUBLIC_IDENTITY_STATUS } from '../../lib/public-identity.js';
|
|
55
56
|
import { v4 as uuidv4 } from 'uuid';
|
|
56
57
|
|
|
57
58
|
function normalizeRelayHttpBaseUrl(serverUrl) {
|
|
@@ -909,6 +910,48 @@ async function fetchPublicIdentity({
|
|
|
909
910
|
agentId = null,
|
|
910
911
|
fetchImpl,
|
|
911
912
|
}) {
|
|
913
|
+
if (!resolveRuntimeAppToken(runtimeConfig)) {
|
|
914
|
+
const recommendedDisplayName = normalizeClaworldText(
|
|
915
|
+
runtimeConfig?.name,
|
|
916
|
+
normalizeClaworldText(runtimeConfig?.registration?.displayName, null),
|
|
917
|
+
);
|
|
918
|
+
return {
|
|
919
|
+
status: 'pending',
|
|
920
|
+
agentId: normalizeClaworldText(agentId, null),
|
|
921
|
+
ready: false,
|
|
922
|
+
publicIdentity: {
|
|
923
|
+
status: PUBLIC_IDENTITY_STATUS.PENDING,
|
|
924
|
+
displayName: null,
|
|
925
|
+
code: null,
|
|
926
|
+
displayIdentity: null,
|
|
927
|
+
confirmedAt: null,
|
|
928
|
+
updatedAt: null,
|
|
929
|
+
},
|
|
930
|
+
recommendedDisplayName,
|
|
931
|
+
nextAction: 'set_public_identity',
|
|
932
|
+
requiredAction: 'set_public_identity',
|
|
933
|
+
nextTool: 'claworld_update_public_identity',
|
|
934
|
+
missingFields: [
|
|
935
|
+
{
|
|
936
|
+
fieldId: 'displayName',
|
|
937
|
+
label: 'Public Name',
|
|
938
|
+
description: 'A public display name used in Claworld identity surfaces.',
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
fieldId: 'code',
|
|
942
|
+
label: 'Public Code',
|
|
943
|
+
description: 'A system-generated unique suffix used in the public identity.',
|
|
944
|
+
},
|
|
945
|
+
],
|
|
946
|
+
feedbackSummary: {
|
|
947
|
+
totalLikesReceived: 0,
|
|
948
|
+
totalDislikesReceived: 0,
|
|
949
|
+
totalLikesGiven: 0,
|
|
950
|
+
totalDislikesGiven: 0,
|
|
951
|
+
},
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
|
|
912
955
|
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
913
956
|
const path = buildRelayJsonPath('/v1/profile/public-identity', {
|
|
914
957
|
agentId,
|
|
@@ -950,31 +993,85 @@ async function updatePublicIdentity({
|
|
|
950
993
|
context: { field: 'displayName' },
|
|
951
994
|
});
|
|
952
995
|
}
|
|
996
|
+
let resolvedRuntimeConfig = applyRuntimeIdentity(runtimeConfig);
|
|
997
|
+
let resolvedAgentId = normalizeClaworldText(agentId, normalizeClaworldText(resolvedRuntimeConfig?.relay?.agentId, null));
|
|
998
|
+
|
|
999
|
+
if (!resolveRuntimeAppToken(resolvedRuntimeConfig)) {
|
|
1000
|
+
const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
|
|
1001
|
+
const activationResult = await fetchJson(fetchImpl, `${baseUrl}/v1/onboarding/activate`, {
|
|
1002
|
+
method: 'POST',
|
|
1003
|
+
headers: {
|
|
1004
|
+
'content-type': 'application/json',
|
|
1005
|
+
...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
|
|
1006
|
+
...buildRuntimeAuthHeaders(resolvedRuntimeConfig),
|
|
1007
|
+
},
|
|
1008
|
+
body: JSON.stringify({
|
|
1009
|
+
displayName: normalizedDisplayName,
|
|
1010
|
+
}),
|
|
1011
|
+
});
|
|
1012
|
+
if (!activationResult.ok) {
|
|
1013
|
+
createRelayRouteError({
|
|
1014
|
+
result: activationResult,
|
|
1015
|
+
runtimeConfig: resolvedRuntimeConfig,
|
|
1016
|
+
code: 'claworld_activation_failed',
|
|
1017
|
+
publicMessage: 'failed to activate Claworld account',
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
const activatedToken = normalizeClaworldText(activationResult.body?.appToken, null);
|
|
1021
|
+
const activatedAgentId = normalizeClaworldText(activationResult.body?.agentId, null);
|
|
1022
|
+
if (!activatedToken || !activatedAgentId) {
|
|
1023
|
+
throw createRuntimeBoundaryError({
|
|
1024
|
+
code: 'claworld_activation_failed',
|
|
1025
|
+
category: 'runtime',
|
|
1026
|
+
status: 502,
|
|
1027
|
+
message: 'claworld activation did not return appToken and agentId',
|
|
1028
|
+
publicMessage: 'failed to activate Claworld account',
|
|
1029
|
+
recoverable: true,
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
resolvedRuntimeConfig = applyRuntimeIdentity(resolvedRuntimeConfig, {
|
|
1033
|
+
appToken: activatedToken,
|
|
1034
|
+
relay: {
|
|
1035
|
+
...(resolvedRuntimeConfig?.relay && typeof resolvedRuntimeConfig.relay === 'object' ? resolvedRuntimeConfig.relay : {}),
|
|
1036
|
+
agentId: activatedAgentId,
|
|
1037
|
+
},
|
|
1038
|
+
});
|
|
1039
|
+
resolvedAgentId = activatedAgentId;
|
|
1040
|
+
}
|
|
953
1041
|
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
954
1042
|
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/profile/public-identity`, {
|
|
955
1043
|
method: 'PUT',
|
|
956
1044
|
headers: {
|
|
957
1045
|
'content-type': 'application/json',
|
|
958
|
-
...(
|
|
959
|
-
...buildRuntimeAuthHeaders(
|
|
1046
|
+
...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
|
|
1047
|
+
...buildRuntimeAuthHeaders(resolvedRuntimeConfig),
|
|
960
1048
|
},
|
|
961
1049
|
body: JSON.stringify({
|
|
962
|
-
...(
|
|
1050
|
+
...(resolvedAgentId ? { agentId: resolvedAgentId } : {}),
|
|
963
1051
|
displayName: normalizedDisplayName,
|
|
964
1052
|
}),
|
|
965
1053
|
});
|
|
966
1054
|
if (!result.ok) {
|
|
967
1055
|
createRelayRouteError({
|
|
968
1056
|
result,
|
|
969
|
-
runtimeConfig,
|
|
1057
|
+
runtimeConfig: resolvedRuntimeConfig,
|
|
970
1058
|
code: 'public_identity_update_failed',
|
|
971
1059
|
publicMessage: 'failed to update public identity',
|
|
972
1060
|
context: {
|
|
973
|
-
agentId:
|
|
1061
|
+
agentId: resolvedAgentId,
|
|
974
1062
|
},
|
|
975
1063
|
});
|
|
976
1064
|
}
|
|
977
|
-
return
|
|
1065
|
+
return {
|
|
1066
|
+
...(result.body || {}),
|
|
1067
|
+
runtimeActivation: !resolveRuntimeAppToken(runtimeConfig)
|
|
1068
|
+
? {
|
|
1069
|
+
status: 'activated',
|
|
1070
|
+
agentId: resolvedAgentId,
|
|
1071
|
+
}
|
|
1072
|
+
: null,
|
|
1073
|
+
runtimeConfig: resolvedRuntimeConfig,
|
|
1074
|
+
};
|
|
978
1075
|
}
|
|
979
1076
|
|
|
980
1077
|
async function registerRelayBinding({ runtimeConfig, fetchImpl, logger }) {
|
|
@@ -1890,6 +1987,18 @@ export function createClaworldChannelPlugin({
|
|
|
1890
1987
|
});
|
|
1891
1988
|
}
|
|
1892
1989
|
|
|
1990
|
+
function rememberAccountBinding({ runtimeConfig, accountId = null, bindingSource = 'binding_cache', relayAgent = null }) {
|
|
1991
|
+
const normalizedRuntimeConfig = applyRuntimeIdentity(runtimeConfig);
|
|
1992
|
+
const accountKey = resolveAccountBindingKey(normalizedRuntimeConfig, accountId || null);
|
|
1993
|
+
accountBindingStates.set(accountKey, {
|
|
1994
|
+
binding: {
|
|
1995
|
+
runtimeConfig: normalizedRuntimeConfig,
|
|
1996
|
+
bindingSource,
|
|
1997
|
+
...(relayAgent ? { relayAgent } : {}),
|
|
1998
|
+
},
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
|
|
1893
2002
|
async function ensureAccountRelayBinding({ runtimeConfig, accountId = null }) {
|
|
1894
2003
|
const normalizedRuntimeConfig = applyRuntimeIdentity(runtimeConfig);
|
|
1895
2004
|
const accountKey = resolveAccountBindingKey(normalizedRuntimeConfig, accountId || null);
|
|
@@ -1937,7 +2046,7 @@ export function createClaworldChannelPlugin({
|
|
|
1937
2046
|
return promise;
|
|
1938
2047
|
}
|
|
1939
2048
|
|
|
1940
|
-
async function persistRuntimeAppToken({ runtime, accountId, appToken }) {
|
|
2049
|
+
async function persistRuntimeAppToken({ runtime, accountId, appToken, relayAgentId = null }) {
|
|
1941
2050
|
if (!runtime?.config?.loadConfig || !runtime?.config?.writeConfigFile) {
|
|
1942
2051
|
return { skipped: true, reason: 'missing_runtime_config_io' };
|
|
1943
2052
|
}
|
|
@@ -1960,43 +2069,67 @@ export function createClaworldChannelPlugin({
|
|
|
1960
2069
|
? accounts[accountId]
|
|
1961
2070
|
: {};
|
|
1962
2071
|
|
|
1963
|
-
|
|
2072
|
+
const normalizedRelayAgentId = normalizeClaworldText(relayAgentId, normalizeClaworldText(account?.relay?.agentId, null));
|
|
2073
|
+
const currentAppToken = normalizeClaworldText(account.appToken, null);
|
|
2074
|
+
const currentRelayAgentId = normalizeClaworldText(account?.relay?.agentId, null);
|
|
2075
|
+
if (currentAppToken === appToken && currentRelayAgentId === normalizedRelayAgentId) {
|
|
1964
2076
|
return { skipped: true, reason: 'already_persisted' };
|
|
1965
2077
|
}
|
|
1966
2078
|
|
|
1967
2079
|
accounts[accountId] = {
|
|
1968
2080
|
...account,
|
|
1969
2081
|
appToken,
|
|
2082
|
+
relay: {
|
|
2083
|
+
...(account?.relay && typeof account.relay === 'object' && !Array.isArray(account.relay) ? account.relay : {}),
|
|
2084
|
+
...(normalizedRelayAgentId ? { agentId: normalizedRelayAgentId } : {}),
|
|
2085
|
+
},
|
|
1970
2086
|
};
|
|
2087
|
+
delete accounts[accountId].registration;
|
|
1971
2088
|
claworldRoot.accounts = accounts;
|
|
1972
2089
|
nextCfg.channels.claworld = claworldRoot;
|
|
1973
2090
|
await runtime.config.writeConfigFile(nextCfg);
|
|
1974
2091
|
return { skipped: false, ok: true };
|
|
1975
2092
|
}
|
|
1976
2093
|
|
|
1977
|
-
|
|
2094
|
+
function resolveConfiguredRuntimeContext(context = {}) {
|
|
1978
2095
|
const cfg = context.cfg || {};
|
|
1979
2096
|
const accountId = context.accountId || null;
|
|
1980
2097
|
const runtimeContext = accountRuntimeContexts.get(accountId || 'default') || null;
|
|
1981
|
-
|
|
2098
|
+
const runtimeConfig = runtimeContext?.runtimeConfig || context.runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
|
|
2099
|
+
return {
|
|
2100
|
+
...context,
|
|
2101
|
+
cfg: runtimeContext?.cfg || cfg,
|
|
2102
|
+
accountId: runtimeConfig.accountId || accountId || null,
|
|
2103
|
+
runtimeConfig,
|
|
2104
|
+
agentId: context.agentId || runtimeConfig.relay?.agentId || null,
|
|
2105
|
+
bindingSource: runtimeContext?.deferredFailure ? 'runtime_context_deferred' : 'runtime_context',
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
async function resolveBoundRuntimeContext(context = {}) {
|
|
2110
|
+
const configuredContext = resolveConfiguredRuntimeContext(context);
|
|
2111
|
+
const cfg = configuredContext.cfg || {};
|
|
2112
|
+
const accountId = configuredContext.accountId || null;
|
|
2113
|
+
let runtimeConfig = configuredContext.runtimeConfig;
|
|
2114
|
+
const runtimeContext = accountRuntimeContexts.get(accountId || 'default') || null;
|
|
1982
2115
|
if (runtimeContext?.runtimeConfig && !runtimeContext?.deferredFailure) {
|
|
1983
2116
|
return {
|
|
1984
|
-
...
|
|
2117
|
+
...configuredContext,
|
|
1985
2118
|
cfg: runtimeContext.cfg || cfg,
|
|
1986
2119
|
accountId: runtimeConfig.accountId || accountId || null,
|
|
1987
2120
|
runtimeConfig,
|
|
1988
|
-
agentId:
|
|
2121
|
+
agentId: configuredContext.agentId || runtimeConfig.relay?.agentId || null,
|
|
1989
2122
|
bindingSource: 'runtime_context',
|
|
1990
2123
|
};
|
|
1991
2124
|
}
|
|
1992
2125
|
const binding = await ensureAccountRelayBinding({ runtimeConfig, accountId });
|
|
1993
2126
|
runtimeConfig = binding.runtimeConfig;
|
|
1994
2127
|
return {
|
|
1995
|
-
...
|
|
2128
|
+
...configuredContext,
|
|
1996
2129
|
cfg,
|
|
1997
2130
|
accountId: runtimeConfig.accountId || accountId || null,
|
|
1998
2131
|
runtimeConfig,
|
|
1999
|
-
agentId:
|
|
2132
|
+
agentId: configuredContext.agentId || runtimeConfig.relay?.agentId || null,
|
|
2000
2133
|
bindingSource: binding.bindingSource,
|
|
2001
2134
|
};
|
|
2002
2135
|
}
|
|
@@ -2117,6 +2250,7 @@ export function createClaworldChannelPlugin({
|
|
|
2117
2250
|
runtime: pluginRuntime,
|
|
2118
2251
|
accountId: runtimeConfig.accountId,
|
|
2119
2252
|
appToken: resolveRuntimeAppToken(runtimeConfig),
|
|
2253
|
+
relayAgentId: runtimeConfig.relay?.agentId || null,
|
|
2120
2254
|
});
|
|
2121
2255
|
if (!persisted.skipped) {
|
|
2122
2256
|
logger.info?.(`[claworld:${runtimeAccountId}] persisted runtime appToken`, {
|
|
@@ -2304,6 +2438,77 @@ export function createClaworldChannelPlugin({
|
|
|
2304
2438
|
};
|
|
2305
2439
|
}
|
|
2306
2440
|
|
|
2441
|
+
async function getRuntimePublicIdentity(context = {}) {
|
|
2442
|
+
const resolvedContext = resolveConfiguredRuntimeContext(context);
|
|
2443
|
+
return fetchPublicIdentity({
|
|
2444
|
+
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2445
|
+
agentId: resolvedContext.agentId || null,
|
|
2446
|
+
fetchImpl,
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
async function updateRuntimePublicIdentity(context = {}) {
|
|
2451
|
+
const resolvedContext = resolveConfiguredRuntimeContext(context);
|
|
2452
|
+
const updateResult = await updatePublicIdentity({
|
|
2453
|
+
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2454
|
+
agentId: resolvedContext.agentId || null,
|
|
2455
|
+
displayName: context.displayName || null,
|
|
2456
|
+
fetchImpl,
|
|
2457
|
+
});
|
|
2458
|
+
|
|
2459
|
+
const runtimeActivation = updateResult?.runtimeActivation && typeof updateResult.runtimeActivation === 'object'
|
|
2460
|
+
? updateResult.runtimeActivation
|
|
2461
|
+
: null;
|
|
2462
|
+
const nextRuntimeConfig = updateResult?.runtimeConfig && typeof updateResult.runtimeConfig === 'object'
|
|
2463
|
+
? updateResult.runtimeConfig
|
|
2464
|
+
: resolvedContext.runtimeConfig;
|
|
2465
|
+
const nextAgentId = normalizeClaworldText(
|
|
2466
|
+
runtimeActivation?.agentId,
|
|
2467
|
+
normalizeClaworldText(resolvedContext.agentId, normalizeClaworldText(nextRuntimeConfig?.relay?.agentId, null)),
|
|
2468
|
+
);
|
|
2469
|
+
|
|
2470
|
+
if (runtimeActivation && resolveRuntimeAppToken(nextRuntimeConfig)) {
|
|
2471
|
+
const runtimeResolution = resolvePluginRuntimeCandidate(context.runtime || null);
|
|
2472
|
+
try {
|
|
2473
|
+
await persistRuntimeAppToken({
|
|
2474
|
+
runtime: runtimeResolution.runtime,
|
|
2475
|
+
accountId: resolvedContext.accountId || nextRuntimeConfig.accountId || null,
|
|
2476
|
+
appToken: resolveRuntimeAppToken(nextRuntimeConfig),
|
|
2477
|
+
relayAgentId: nextAgentId,
|
|
2478
|
+
});
|
|
2479
|
+
} catch (error) {
|
|
2480
|
+
logger.warn?.('[claworld:profile] failed to persist activated runtime binding', {
|
|
2481
|
+
accountId: resolvedContext.accountId || nextRuntimeConfig.accountId || null,
|
|
2482
|
+
error: error?.message || String(error),
|
|
2483
|
+
});
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
rememberAccountBinding({
|
|
2487
|
+
runtimeConfig: nextRuntimeConfig,
|
|
2488
|
+
accountId: resolvedContext.accountId || nextRuntimeConfig.accountId || null,
|
|
2489
|
+
bindingSource: 'activated_app_token',
|
|
2490
|
+
});
|
|
2491
|
+
|
|
2492
|
+
const accountKey = resolveAccountBindingKey(nextRuntimeConfig, resolvedContext.accountId || null);
|
|
2493
|
+
const currentRuntimeContext = accountRuntimeContexts.get(accountKey) || null;
|
|
2494
|
+
if (currentRuntimeContext) {
|
|
2495
|
+
accountRuntimeContexts.set(accountKey, {
|
|
2496
|
+
...currentRuntimeContext,
|
|
2497
|
+
runtimeConfig: nextRuntimeConfig,
|
|
2498
|
+
deferredFailure: null,
|
|
2499
|
+
deferredErrorMessage: null,
|
|
2500
|
+
});
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
const payload = updateResult && typeof updateResult === 'object' && !Array.isArray(updateResult)
|
|
2505
|
+
? { ...updateResult }
|
|
2506
|
+
: {};
|
|
2507
|
+
delete payload.runtimeActivation;
|
|
2508
|
+
delete payload.runtimeConfig;
|
|
2509
|
+
return payload;
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2307
2512
|
return {
|
|
2308
2513
|
id: 'claworld',
|
|
2309
2514
|
meta: {
|
|
@@ -2556,23 +2761,8 @@ export function createClaworldChannelPlugin({
|
|
|
2556
2761
|
},
|
|
2557
2762
|
},
|
|
2558
2763
|
profile: {
|
|
2559
|
-
getPublicIdentity:
|
|
2560
|
-
|
|
2561
|
-
return fetchPublicIdentity({
|
|
2562
|
-
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2563
|
-
agentId: resolvedContext.agentId || null,
|
|
2564
|
-
fetchImpl,
|
|
2565
|
-
});
|
|
2566
|
-
},
|
|
2567
|
-
updatePublicIdentity: async (context = {}) => {
|
|
2568
|
-
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2569
|
-
return updatePublicIdentity({
|
|
2570
|
-
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2571
|
-
agentId: resolvedContext.agentId || null,
|
|
2572
|
-
displayName: context.displayName || null,
|
|
2573
|
-
fetchImpl,
|
|
2574
|
-
});
|
|
2575
|
-
},
|
|
2764
|
+
getPublicIdentity: getRuntimePublicIdentity,
|
|
2765
|
+
updatePublicIdentity: updateRuntimePublicIdentity,
|
|
2576
2766
|
},
|
|
2577
2767
|
postSetup: {
|
|
2578
2768
|
fetchWorldDirectory: async (context = {}) => {
|
|
@@ -2725,23 +2915,8 @@ export function createClaworldChannelPlugin({
|
|
|
2725
2915
|
demo,
|
|
2726
2916
|
productShell: {
|
|
2727
2917
|
profile: {
|
|
2728
|
-
getPublicIdentity:
|
|
2729
|
-
|
|
2730
|
-
return fetchPublicIdentity({
|
|
2731
|
-
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
2732
|
-
agentId: resolvedContext.agentId || null,
|
|
2733
|
-
fetchImpl,
|
|
2734
|
-
});
|
|
2735
|
-
},
|
|
2736
|
-
updatePublicIdentity: async (context = {}) => {
|
|
2737
|
-
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2738
|
-
return updatePublicIdentity({
|
|
2739
|
-
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
2740
|
-
agentId: resolvedContext.agentId || null,
|
|
2741
|
-
displayName: context.displayName || null,
|
|
2742
|
-
fetchImpl,
|
|
2743
|
-
});
|
|
2744
|
-
},
|
|
2918
|
+
getPublicIdentity: getRuntimePublicIdentity,
|
|
2919
|
+
updatePublicIdentity: updateRuntimePublicIdentity,
|
|
2745
2920
|
},
|
|
2746
2921
|
fetchWorldDirectory: async (context = {}) => {
|
|
2747
2922
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
@@ -355,7 +355,7 @@ function buildManagedAccountEntry(options = {}) {
|
|
|
355
355
|
|
|
356
356
|
if (options.appToken) {
|
|
357
357
|
base.appToken = options.appToken;
|
|
358
|
-
} else {
|
|
358
|
+
} else if (normalizeText(options.registrationDisplayName, null)) {
|
|
359
359
|
base.registration = {
|
|
360
360
|
enabled: true,
|
|
361
361
|
displayName: normalizeText(options.registrationDisplayName, options.displayName),
|
|
@@ -404,10 +404,18 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
|
|
|
404
404
|
delete merged.toolProfile;
|
|
405
405
|
|
|
406
406
|
if (options.appToken) {
|
|
407
|
-
|
|
407
|
+
const withToken = {
|
|
408
408
|
...merged,
|
|
409
409
|
appToken: options.appToken,
|
|
410
410
|
};
|
|
411
|
+
delete withToken.registration;
|
|
412
|
+
return withToken;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!normalizeText(options.registrationDisplayName, null)) {
|
|
416
|
+
const withoutRegistration = { ...merged };
|
|
417
|
+
delete withoutRegistration.registration;
|
|
418
|
+
return withoutRegistration;
|
|
411
419
|
}
|
|
412
420
|
|
|
413
421
|
return {
|
|
@@ -512,7 +520,9 @@ export function buildWorkspaceAgentsContent({
|
|
|
512
520
|
} = {}) {
|
|
513
521
|
const identityLine = appToken
|
|
514
522
|
? '- relay binding is resolved from the configured appToken at runtime'
|
|
515
|
-
:
|
|
523
|
+
: registrationDisplayName
|
|
524
|
+
? '- relay binding is created during runtime bootstrap and persists as backend-issued credentials'
|
|
525
|
+
: '- activation is pending until the user completes Claworld public identity setup';
|
|
516
526
|
|
|
517
527
|
return `# Claworld Channel Agent
|
|
518
528
|
|
|
@@ -522,7 +532,7 @@ Routing contract:
|
|
|
522
532
|
|
|
523
533
|
- local OpenClaw agent id: \`${agentId}\`
|
|
524
534
|
- claworld account id: \`${accountId}\`
|
|
525
|
-
${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : '- credential mode: appToken/manual binding'}
|
|
535
|
+
${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : (appToken ? '- credential mode: appToken/manual binding' : '- credential mode: activation pending')}
|
|
526
536
|
${identityLine}
|
|
527
537
|
${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : '- outbound sends require explicit target agentId inputs'}
|
|
528
538
|
|
|
@@ -553,7 +563,9 @@ export function buildWorkspaceMemoryContent({
|
|
|
553
563
|
} = {}) {
|
|
554
564
|
const identityLine = appToken
|
|
555
565
|
? '- relay binding: resolved from appToken at runtime'
|
|
556
|
-
:
|
|
566
|
+
: registrationDisplayName
|
|
567
|
+
? '- relay binding: assigned during runtime bootstrap'
|
|
568
|
+
: '- relay binding: pending until public identity setup completes';
|
|
557
569
|
|
|
558
570
|
return `# Claworld Memory
|
|
559
571
|
|
|
@@ -661,10 +673,7 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
661
673
|
? null
|
|
662
674
|
: normalizeRegistrationDisplayName(
|
|
663
675
|
explicitRegistrationDisplayName,
|
|
664
|
-
|
|
665
|
-
existingRegistrationDisplayName,
|
|
666
|
-
displayName,
|
|
667
|
-
),
|
|
676
|
+
existingRegistrationDisplayName,
|
|
668
677
|
);
|
|
669
678
|
const approvalMode = normalizeChatRequestApprovalMode(
|
|
670
679
|
normalizeText(overrides.approvalMode, null),
|
|
@@ -716,10 +725,6 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
|
|
|
716
725
|
const sessionDmScope = normalizeText(options.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE);
|
|
717
726
|
const manageAgentEntry = options.manageAgentEntry === true;
|
|
718
727
|
|
|
719
|
-
if (!options.appToken && !normalizeText(options.registrationDisplayName, null)) {
|
|
720
|
-
throw new Error('claworld registration displayName is required when appToken is absent');
|
|
721
|
-
}
|
|
722
|
-
|
|
723
728
|
const removedManagedToolNames = new Set([
|
|
724
729
|
...CLAWORLD_PUBLIC_TOOL_NAMES,
|
|
725
730
|
...CLAWORLD_COMPATIBILITY_TOOL_NAMES,
|
|
@@ -84,8 +84,11 @@ function validateClaworldSetupInput({ cfg = {}, accountId = null, input = {} } =
|
|
|
84
84
|
const registrationDisplayName = normalizeText(
|
|
85
85
|
input.name,
|
|
86
86
|
normalizeText(
|
|
87
|
-
inspected?.
|
|
88
|
-
normalizeText(
|
|
87
|
+
inspected?.name,
|
|
88
|
+
normalizeText(
|
|
89
|
+
inspected?.registration?.displayName,
|
|
90
|
+
normalizeText(inspected?.localAgent?.displayName, null),
|
|
91
|
+
),
|
|
89
92
|
),
|
|
90
93
|
);
|
|
91
94
|
if (!appToken && !registrationDisplayName) {
|
|
@@ -105,8 +108,11 @@ function currentManagedIdentityInput({ cfg = {}, accountId = null } = {}) {
|
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
const currentDisplayName = normalizeText(
|
|
108
|
-
inspected?.
|
|
109
|
-
normalizeText(
|
|
111
|
+
inspected?.name,
|
|
112
|
+
normalizeText(
|
|
113
|
+
inspected?.registration?.displayName,
|
|
114
|
+
normalizeText(inspected?.localAgent?.displayName, null),
|
|
115
|
+
),
|
|
110
116
|
);
|
|
111
117
|
return currentDisplayName
|
|
112
118
|
? { name: currentDisplayName }
|
|
@@ -163,11 +169,17 @@ function applyManagedAccountName({ cfg = {}, accountId, name } = {}) {
|
|
|
163
169
|
}
|
|
164
170
|
|
|
165
171
|
function resolveManagedOptionsFromContext({ cfg = {}, accountId = null, input = {}, overrides = {} } = {}) {
|
|
172
|
+
const normalizedInput = ensureObject(input);
|
|
173
|
+
const resolvedInput = { ...normalizedInput };
|
|
174
|
+
delete resolvedInput.name;
|
|
166
175
|
return resolveClaworldManagedRuntimeOptions({
|
|
167
176
|
cfg,
|
|
168
177
|
accountId: normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID),
|
|
169
|
-
input,
|
|
170
|
-
overrides
|
|
178
|
+
input: resolvedInput,
|
|
179
|
+
overrides: {
|
|
180
|
+
...overrides,
|
|
181
|
+
...(normalizeText(normalizedInput.name, null) ? { displayName: normalizedInput.name } : {}),
|
|
182
|
+
},
|
|
171
183
|
});
|
|
172
184
|
}
|
|
173
185
|
|
|
@@ -187,9 +199,9 @@ async function applyManagedOnboardingConfig({
|
|
|
187
199
|
const noteLines = [
|
|
188
200
|
`Bound local agent/account: ${managedOptions.agentId}`,
|
|
189
201
|
`Remote backend: ${managedOptions.serverUrl}`,
|
|
190
|
-
managedOptions.
|
|
191
|
-
?
|
|
192
|
-
: '
|
|
202
|
+
managedOptions.appToken
|
|
203
|
+
? 'Activation state: ready via configured appToken'
|
|
204
|
+
: 'Activation state: pending until claworld_update_public_identity runs',
|
|
193
205
|
managedOptions.manageWorkspace
|
|
194
206
|
? 'This flow refreshes plugin-side config and the dedicated claworld workspace contract. It does not start a backend service.'
|
|
195
207
|
: 'This flow refreshes plugin-side config and binds claworld onto the existing local agent. It does not start a backend service.',
|
|
@@ -178,12 +178,12 @@ function withToolErrorBoundary(toolName, execute) {
|
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
async function resolveToolContext(api, plugin, params = {}) {
|
|
181
|
+
async function resolveToolContext(api, plugin, params = {}, { bindRuntime = true } = {}) {
|
|
182
182
|
const cfg = await loadCurrentConfig(api);
|
|
183
183
|
const accountId = normalizeText(params.accountId, plugin.config.defaultAccountId(cfg) || null);
|
|
184
184
|
const runtimeConfig = plugin.config.resolveRuntimeConfig(cfg, accountId);
|
|
185
185
|
|
|
186
|
-
if (typeof plugin.helpers?.resolveToolRuntimeContext === 'function') {
|
|
186
|
+
if (bindRuntime && typeof plugin.helpers?.resolveToolRuntimeContext === 'function') {
|
|
187
187
|
return await plugin.helpers.resolveToolRuntimeContext({
|
|
188
188
|
cfg,
|
|
189
189
|
accountId,
|
|
@@ -1128,19 +1128,30 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1128
1128
|
runtimeConfig,
|
|
1129
1129
|
});
|
|
1130
1130
|
const pairedAgentId = payload.runtimeConfig?.relay?.agentId || payload.relayAgent?.agentId || null;
|
|
1131
|
-
const publicIdentity =
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1131
|
+
const publicIdentity = await plugin.runtime.productShell.profile.getPublicIdentity({
|
|
1132
|
+
cfg,
|
|
1133
|
+
accountId,
|
|
1134
|
+
runtimeConfig: payload.runtimeConfig || runtimeConfig,
|
|
1135
|
+
agentId: pairedAgentId,
|
|
1136
|
+
});
|
|
1137
|
+
const ready = payload.status === 'paired' && publicIdentity?.ready === true;
|
|
1138
|
+
const readiness = payload.status === 'paired'
|
|
1139
|
+
? (publicIdentity?.ready === true ? 'paired_and_ready' : 'paired_but_identity_pending')
|
|
1140
|
+
: 'installed_unactivated';
|
|
1139
1141
|
return buildToolResult({
|
|
1140
|
-
status:
|
|
1142
|
+
status: ready ? 'ready' : 'pending',
|
|
1143
|
+
ready,
|
|
1144
|
+
readiness,
|
|
1141
1145
|
reason: payload.reason || null,
|
|
1146
|
+
requiredAction: publicIdentity?.requiredAction || (ready ? null : 'set_public_identity'),
|
|
1147
|
+
nextAction: publicIdentity?.nextAction || (ready ? 'continue_claworld_flow' : 'set_public_identity'),
|
|
1148
|
+
nextTool: publicIdentity?.nextTool || (ready ? null : 'claworld_update_public_identity'),
|
|
1149
|
+
missingFields: Array.isArray(publicIdentity?.missingFields) ? publicIdentity.missingFields : [],
|
|
1142
1150
|
accountId: payload.runtimeConfig?.accountId || accountId,
|
|
1143
1151
|
bindingSource: payload.bindingSource || null,
|
|
1152
|
+
activation: {
|
|
1153
|
+
status: payload.status === 'paired' ? 'ready' : 'pending',
|
|
1154
|
+
},
|
|
1144
1155
|
relay: {
|
|
1145
1156
|
agentId: payload.runtimeConfig?.relay?.agentId || payload.relayAgent?.agentId || null,
|
|
1146
1157
|
displayName: payload.relayAgent?.displayName || null,
|
|
@@ -1148,6 +1159,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1148
1159
|
contactable: payload.relayAgent?.contactable ?? null,
|
|
1149
1160
|
online: payload.relayAgent?.online ?? null,
|
|
1150
1161
|
resolved: payload.relayAgent?.resolved ?? null,
|
|
1162
|
+
bindingStatus: payload.status === 'paired' ? 'bound' : 'unactivated',
|
|
1151
1163
|
},
|
|
1152
1164
|
publicIdentity: publicIdentity
|
|
1153
1165
|
? {
|
|
@@ -1192,7 +1204,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1192
1204
|
},
|
|
1193
1205
|
}),
|
|
1194
1206
|
async execute(_toolCallId, params = {}) {
|
|
1195
|
-
const context = await resolveToolContext(api, plugin, params);
|
|
1207
|
+
const context = await resolveToolContext(api, plugin, params, { bindRuntime: false });
|
|
1196
1208
|
const payload = await plugin.runtime.productShell.profile.getPublicIdentity(context);
|
|
1197
1209
|
return buildToolResult(payload);
|
|
1198
1210
|
},
|
|
@@ -1221,7 +1233,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1221
1233
|
},
|
|
1222
1234
|
}),
|
|
1223
1235
|
async execute(_toolCallId, params = {}) {
|
|
1224
|
-
const context = await resolveToolContext(api, plugin, params);
|
|
1236
|
+
const context = await resolveToolContext(api, plugin, params, { bindRuntime: false });
|
|
1225
1237
|
const payload = await plugin.runtime.productShell.profile.updatePublicIdentity({
|
|
1226
1238
|
...context,
|
|
1227
1239
|
displayName: params.displayName,
|
|
@@ -164,9 +164,9 @@ export function createOnboardingService({ worldService, store = null } = {}) {
|
|
|
164
164
|
'installer validates OpenClaw availability and minimum host version',
|
|
165
165
|
'installer verifies or installs the claworld OpenClaw plugin package',
|
|
166
166
|
'installer writes or refreshes the managed claworld channel config and binds it to the local main agent by default',
|
|
167
|
-
'installer
|
|
168
|
-
'
|
|
169
|
-
'
|
|
167
|
+
'installer reloads or starts the runtime and verifies the managed channel shape without requiring backend activation',
|
|
168
|
+
'first-run readiness goes through claworld_pair_agent and then claworld_update_public_identity',
|
|
169
|
+
'claworld_update_public_identity performs activation when needed and completes the public displayName#code identity',
|
|
170
170
|
`ongoing lifecycle uses ${CLAWORLD_UPDATE_COMMAND} for tracked package updates plus managed repair, then ${CLAWORLD_DOCTOR_COMMAND} for health confirmation`,
|
|
171
171
|
],
|
|
172
172
|
recommendedWorlds,
|
|
@@ -182,8 +182,9 @@ export function createOnboardingService({ worldService, store = null } = {}) {
|
|
|
182
182
|
selectedWorld: selectedWorld ? { worldId: selectedWorld.worldId, displayName: selectedWorld.displayName } : null,
|
|
183
183
|
actions: [
|
|
184
184
|
'install the claworld plugin and write the managed config shape',
|
|
185
|
-
'
|
|
186
|
-
'
|
|
185
|
+
'run claworld_pair_agent to confirm readiness after install',
|
|
186
|
+
'if public identity is pending, call claworld_update_public_identity',
|
|
187
|
+
'claworld_update_public_identity activates the backend binding when needed and persists the returned appToken',
|
|
187
188
|
'collect required world profile fields',
|
|
188
189
|
'validate world membership eligibility',
|
|
189
190
|
'start the first A2A loop or deliver world content',
|