@xfxstudio/claworld 2026.6.10-testing.5 → 2026.6.26-testing.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -9
- package/openclaw.plugin.json +1 -1
- package/package.json +6 -3
- package/skills/claworld-help/SKILL.md +2 -1
- package/skills/claworld-main-session/SKILL.md +0 -2
- package/skills/claworld-manage-worlds/SKILL.md +72 -38
- package/skills/claworld-management-session/SKILL.md +0 -1
- package/src/openclaw/plugin/claworld-channel-plugin.js +323 -62
- package/src/openclaw/plugin/managed-config.js +30 -206
- package/src/openclaw/plugin/onboarding.js +169 -15
- package/src/openclaw/plugin/register-tooling.js +70 -37
- package/src/openclaw/plugin/register.js +95 -92
- package/src/openclaw/runtime/tool-contracts.js +0 -40
- package/src/product-shell/contracts/search-item.js +2 -1
- package/src/openclaw/plugin/conversation-viewer-env.js +0 -67
- package/src/openclaw/plugin/conversation-viewer.js +0 -1547
|
@@ -336,25 +336,6 @@ function inferExistingAgentId(config = {}, accountId = DEFAULT_CLAWORLD_ACCOUNT_
|
|
|
336
336
|
return DEFAULT_CLAWORLD_AGENT_ID;
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
const MANAGED_LEGACY_BUNDLED_SKILL_NAMES = Object.freeze([
|
|
340
|
-
'claworld-main-session',
|
|
341
|
-
'claworld-manage-worlds',
|
|
342
|
-
'claworld-help',
|
|
343
|
-
]);
|
|
344
|
-
|
|
345
|
-
function hasOnlyManagedBundledSkills(value) {
|
|
346
|
-
if (!Array.isArray(value) || value.length === 0) return false;
|
|
347
|
-
return value.every((skillName) => MANAGED_LEGACY_BUNDLED_SKILL_NAMES.includes(skillName));
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function buildManagedAgentEntry(options = {}) {
|
|
351
|
-
return {
|
|
352
|
-
id: options.agentId,
|
|
353
|
-
workspace: options.workspace,
|
|
354
|
-
...(options.agentDirExplicit && options.agentDir ? { agentDir: options.agentDir } : {}),
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
|
|
358
339
|
function buildManagedRoutingEntry(options = {}, existingRouting = {}) {
|
|
359
340
|
return {
|
|
360
341
|
...ensureObject(existingRouting),
|
|
@@ -383,21 +364,33 @@ function buildManagedAccountEntry(options = {}) {
|
|
|
383
364
|
};
|
|
384
365
|
}
|
|
385
366
|
|
|
386
|
-
|
|
367
|
+
const relay = {
|
|
368
|
+
...(normalizeText(options.relayAgentId, null) ? { agentId: normalizeText(options.relayAgentId, null) } : {}),
|
|
369
|
+
...(normalizeText(options.defaultTargetAgentId, null)
|
|
370
|
+
? { defaultTargetAgentId: normalizeText(options.defaultTargetAgentId, null) }
|
|
371
|
+
: {}),
|
|
372
|
+
};
|
|
373
|
+
if (Object.keys(relay).length === 0) {
|
|
387
374
|
return base;
|
|
388
375
|
}
|
|
389
376
|
|
|
390
377
|
return {
|
|
391
378
|
...base,
|
|
392
|
-
relay
|
|
393
|
-
defaultTargetAgentId: options.defaultTargetAgentId,
|
|
394
|
-
},
|
|
379
|
+
relay,
|
|
395
380
|
};
|
|
396
381
|
}
|
|
397
382
|
|
|
398
383
|
function buildMergedAccountEntry(existingAccount = {}, options = {}) {
|
|
399
384
|
const existingRelay = ensureObject(existingAccount.relay);
|
|
400
385
|
const existingRegistration = ensureObject(existingAccount.registration);
|
|
386
|
+
const relayAgentId = normalizeText(options.relayAgentId, null);
|
|
387
|
+
const defaultTargetAgentId = normalizeText(options.defaultTargetAgentId, null);
|
|
388
|
+
const mergedRelay = {
|
|
389
|
+
...existingRelay,
|
|
390
|
+
...(relayAgentId ? { agentId: relayAgentId } : {}),
|
|
391
|
+
...(defaultTargetAgentId ? { defaultTargetAgentId } : {}),
|
|
392
|
+
};
|
|
393
|
+
const shouldPersistRelay = Boolean(existingAccount.relay || relayAgentId || defaultTargetAgentId);
|
|
401
394
|
const merged = {
|
|
402
395
|
...existingAccount,
|
|
403
396
|
enabled: true,
|
|
@@ -406,16 +399,7 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
|
|
|
406
399
|
accountId: options.accountId,
|
|
407
400
|
name: normalizeText(options.name, normalizeText(existingAccount.name, normalizeText(options.displayName, null))),
|
|
408
401
|
routing: buildManagedRoutingEntry(options, existingAccount.routing),
|
|
409
|
-
...(
|
|
410
|
-
? {
|
|
411
|
-
relay: {
|
|
412
|
-
...existingRelay,
|
|
413
|
-
defaultTargetAgentId: options.defaultTargetAgentId,
|
|
414
|
-
},
|
|
415
|
-
}
|
|
416
|
-
: existingAccount.relay
|
|
417
|
-
? { relay: existingRelay }
|
|
418
|
-
: {}),
|
|
402
|
+
...(shouldPersistRelay ? { relay: mergedRelay } : {}),
|
|
419
403
|
};
|
|
420
404
|
delete merged.toolProfile;
|
|
421
405
|
|
|
@@ -507,60 +491,6 @@ export function resolveToolNames({ toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE }
|
|
|
507
491
|
return [...baseProfile];
|
|
508
492
|
}
|
|
509
493
|
|
|
510
|
-
const MANAGED_BUNDLED_SKILL_NAMES = Object.freeze([
|
|
511
|
-
'claworld-main-session',
|
|
512
|
-
'claworld-manage-worlds',
|
|
513
|
-
'claworld-help',
|
|
514
|
-
]);
|
|
515
|
-
|
|
516
|
-
export function resolveManagedAgentSkills({ toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE } = {}) {
|
|
517
|
-
const normalizedProfile = normalizeClaworldToolProfile(toolProfile);
|
|
518
|
-
return normalizedProfile === 'full' ? undefined : [...MANAGED_BUNDLED_SKILL_NAMES];
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
function describeToolAllowEntries(toolNames = []) {
|
|
522
|
-
if (toolNames.length === 1) {
|
|
523
|
-
return toolNames[0] === '*' ? '1 entry (includes *)' : '1 entry';
|
|
524
|
-
}
|
|
525
|
-
return toolNames.includes('*')
|
|
526
|
-
? `${toolNames.length} entries (includes *)`
|
|
527
|
-
: `${toolNames.length} entries`;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
export function buildWorkspaceAgentsContent({
|
|
531
|
-
agentId,
|
|
532
|
-
accountId,
|
|
533
|
-
registrationDisplayName,
|
|
534
|
-
appToken = null,
|
|
535
|
-
defaultTargetAgentId = null,
|
|
536
|
-
} = {}) {
|
|
537
|
-
const identityLine = appToken
|
|
538
|
-
? '- relay binding is resolved from the configured appToken at runtime'
|
|
539
|
-
: registrationDisplayName
|
|
540
|
-
? '- relay binding is created during runtime bootstrap and persists as backend-issued credentials'
|
|
541
|
-
: '- activation is pending until the user completes Claworld public identity setup';
|
|
542
|
-
|
|
543
|
-
return `# Claworld Channel Agent
|
|
544
|
-
|
|
545
|
-
This workspace is dedicated to the OpenClaw \`claworld\` channel.
|
|
546
|
-
|
|
547
|
-
Routing contract:
|
|
548
|
-
|
|
549
|
-
- local OpenClaw agent id: \`${agentId}\`
|
|
550
|
-
- claworld account id: \`${accountId}\`
|
|
551
|
-
${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : (appToken ? '- credential mode: appToken/manual binding' : '- credential mode: activation pending')}
|
|
552
|
-
${identityLine}
|
|
553
|
-
${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : '- outbound sends require explicit target agentId inputs'}
|
|
554
|
-
|
|
555
|
-
Operating rules:
|
|
556
|
-
|
|
557
|
-
- keep this workspace focused on Claworld relay and world interactions
|
|
558
|
-
- use explicit \`claworld_*\` tools when they are available
|
|
559
|
-
- do not treat this workspace as the user's general-purpose main agent
|
|
560
|
-
- do not treat this as a separately bootstrapped OpenClaw persona
|
|
561
|
-
`;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
494
|
function buildBoundAgentEntry(existingAgent = {}, agentId) {
|
|
565
495
|
const nextAgent = {
|
|
566
496
|
...ensureObject(existingAgent),
|
|
@@ -570,41 +500,8 @@ function buildBoundAgentEntry(existingAgent = {}, agentId) {
|
|
|
570
500
|
return nextAgent;
|
|
571
501
|
}
|
|
572
502
|
|
|
573
|
-
export function buildWorkspaceMemoryContent({
|
|
574
|
-
agentId,
|
|
575
|
-
accountId,
|
|
576
|
-
registrationDisplayName,
|
|
577
|
-
appToken = null,
|
|
578
|
-
defaultTargetAgentId = null,
|
|
579
|
-
} = {}) {
|
|
580
|
-
const identityLine = appToken
|
|
581
|
-
? '- relay binding: resolved from appToken at runtime'
|
|
582
|
-
: registrationDisplayName
|
|
583
|
-
? '- relay binding: assigned during runtime bootstrap'
|
|
584
|
-
: '- relay binding: pending until public identity setup completes';
|
|
585
|
-
|
|
586
|
-
return `# Claworld Memory
|
|
587
|
-
|
|
588
|
-
- workspace owner: \`${agentId}\`
|
|
589
|
-
- claworld account: \`${accountId}\`
|
|
590
|
-
${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : ''}
|
|
591
|
-
${identityLine}
|
|
592
|
-
${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : ''}
|
|
593
|
-
|
|
594
|
-
Use this file for durable Claworld-specific notes only.
|
|
595
|
-
|
|
596
|
-
- keep world rules, pairing context, and recurring counterpart preferences here when they help future Claworld conversations
|
|
597
|
-
- do not duplicate a full standalone OpenClaw bootstrap/persona here
|
|
598
|
-
- prefer channel/world-specific memory over general-purpose assistant memory
|
|
599
|
-
`;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
export function resolveDefaultManagedWorkspace(agentId = DEFAULT_CLAWORLD_AGENT_ID) {
|
|
603
|
-
return `~/.openclaw/workspace-${agentId}`;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
503
|
export function resolveDefaultManagedDisplayName(accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
|
|
607
|
-
return `${titleCase(accountId)} Channel
|
|
504
|
+
return `${titleCase(accountId)} Channel`;
|
|
608
505
|
}
|
|
609
506
|
|
|
610
507
|
export function resolveClaworldManagedRuntimeOptions({
|
|
@@ -615,7 +512,6 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
615
512
|
installerState = null,
|
|
616
513
|
} = {}) {
|
|
617
514
|
const resolvedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
|
|
618
|
-
const attachToExistingAgent = overrides.attachToExistingAgent !== false;
|
|
619
515
|
const existingBackup = findClaworldManagedRuntimeBackup(installerState, resolvedAccountId);
|
|
620
516
|
const inferredAgentId = inferExistingAgentId(cfg, resolvedAccountId)
|
|
621
517
|
|| normalizeText(existingBackup.agentId, null);
|
|
@@ -623,20 +519,7 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
623
519
|
const existingAgent = findAgentEntry(cfg, agentId);
|
|
624
520
|
const existingAccount = findManagedAccountEntry(cfg, resolvedAccountId);
|
|
625
521
|
const replaceManagedRuntime = overrides.replaceManagedRuntime !== false;
|
|
626
|
-
const
|
|
627
|
-
const manageAgentEntry = overrides.manageAgentEntry === true
|
|
628
|
-
|| overrides.agentDirExplicit === true
|
|
629
|
-
|| attachToExistingAgent !== true;
|
|
630
|
-
const manageWorkspace = overrides.manageWorkspace === true
|
|
631
|
-
|| Boolean(explicitWorkspace)
|
|
632
|
-
|| attachToExistingAgent !== true;
|
|
633
|
-
const defaultWorkspace = manageWorkspace ? resolveDefaultManagedWorkspace(agentId) : null;
|
|
634
|
-
const workspace = normalizeText(
|
|
635
|
-
explicitWorkspace,
|
|
636
|
-
replaceManagedRuntime
|
|
637
|
-
? normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace))
|
|
638
|
-
: normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace)),
|
|
639
|
-
);
|
|
522
|
+
const workspace = normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, null));
|
|
640
523
|
const serverUrl = normalizeText(
|
|
641
524
|
overrides.serverUrl,
|
|
642
525
|
normalizeText(input.httpUrl, normalizeText(input.url, normalizeText(existingBackup.serverUrl, DEFAULT_CLAWORLD_SERVER_URL))),
|
|
@@ -680,20 +563,16 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
680
563
|
|
|
681
564
|
return {
|
|
682
565
|
repoRoot: normalizeText(overrides.repoRoot, null),
|
|
683
|
-
attachToExistingAgent,
|
|
684
566
|
agentId,
|
|
685
567
|
accountId: resolvedAccountId,
|
|
686
568
|
workspace,
|
|
687
|
-
manageAgentEntry,
|
|
688
|
-
manageWorkspace,
|
|
689
|
-
agentDir: normalizeText(overrides.agentDir, null),
|
|
690
|
-
agentDirExplicit: overrides.agentDirExplicit === true,
|
|
691
569
|
serverUrl,
|
|
692
570
|
apiKey,
|
|
693
571
|
appToken,
|
|
694
572
|
registrationDisplayName,
|
|
695
573
|
displayName,
|
|
696
574
|
name,
|
|
575
|
+
relayAgentId: normalizeText(overrides.relayAgentId, normalizeText(existingAccount?.relay?.agentId, null)),
|
|
697
576
|
defaultTargetAgentId: normalizeText(overrides.defaultTargetAgentId, null),
|
|
698
577
|
sessionDmScope: normalizeText(
|
|
699
578
|
overrides.sessionDmScope,
|
|
@@ -715,7 +594,6 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
|
|
|
715
594
|
const replaceManagedRuntime = options.replaceManagedRuntime !== false;
|
|
716
595
|
const preserveDefaultAccount = options.preserveDefaultAccount === true;
|
|
717
596
|
const sessionDmScope = normalizeText(options.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE);
|
|
718
|
-
const manageAgentEntry = options.manageAgentEntry === true;
|
|
719
597
|
|
|
720
598
|
const removedManagedToolNames = new Set(CLAWORLD_PUBLIC_TOOL_NAMES);
|
|
721
599
|
if (inputConfig?.tools && typeof inputConfig.tools === 'object') {
|
|
@@ -754,72 +632,18 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
|
|
|
754
632
|
|
|
755
633
|
config.agents = ensureObject(config.agents);
|
|
756
634
|
const existingAgentList = Array.isArray(config.agents.list) ? [...config.agents.list] : [];
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
{
|
|
764
|
-
...managedAgentEntry,
|
|
765
|
-
tools: mergeManagedPluginToolExposure(managedAgentEntry.tools),
|
|
766
|
-
},
|
|
767
|
-
];
|
|
768
|
-
summary.push(
|
|
769
|
-
removedAgentEntries > 0
|
|
770
|
-
? `replaced managed agent entry ${options.agentId}`
|
|
771
|
-
: `added workspace-scoped agent entry ${options.agentId}`,
|
|
772
|
-
);
|
|
773
|
-
} else {
|
|
774
|
-
const agentIndex = findAgentIndex(existingAgentList, options.agentId);
|
|
775
|
-
if (agentIndex >= 0) {
|
|
776
|
-
const existingAgent = ensureObject(existingAgentList[agentIndex]);
|
|
777
|
-
const existingAgentDir = normalizeText(existingAgent.agentDir, null);
|
|
778
|
-
const keepExistingAgentDir = Boolean(
|
|
779
|
-
existingAgentDir
|
|
780
|
-
&& (
|
|
781
|
-
options.agentDirExplicit
|
|
782
|
-
|| existingAgentDir !== normalizeText(options.agentDir, null)
|
|
783
|
-
),
|
|
784
|
-
);
|
|
785
|
-
const nextAgentEntry = {
|
|
786
|
-
...existingAgent,
|
|
787
|
-
id: options.agentId,
|
|
788
|
-
workspace: normalizeText(existingAgent.workspace, options.workspace),
|
|
789
|
-
...(keepExistingAgentDir ? { agentDir: existingAgentDir } : {}),
|
|
790
|
-
};
|
|
791
|
-
if (!keepExistingAgentDir) {
|
|
792
|
-
delete nextAgentEntry.agentDir;
|
|
793
|
-
}
|
|
794
|
-
if (hasOnlyManagedBundledSkills(existingAgent.skills)) {
|
|
795
|
-
delete nextAgentEntry.skills;
|
|
796
|
-
}
|
|
797
|
-
nextAgentEntry.tools = mergeManagedPluginToolExposure(existingAgent.tools);
|
|
798
|
-
existingAgentList[agentIndex] = nextAgentEntry;
|
|
799
|
-
summary.push(`updated existing agent entry ${options.agentId}`);
|
|
800
|
-
} else {
|
|
801
|
-
existingAgentList.push({
|
|
802
|
-
...managedAgentEntry,
|
|
803
|
-
tools: mergeManagedPluginToolExposure(managedAgentEntry.tools),
|
|
804
|
-
});
|
|
805
|
-
summary.push(`added workspace-scoped agent entry ${options.agentId}`);
|
|
806
|
-
}
|
|
807
|
-
config.agents.list = existingAgentList;
|
|
808
|
-
}
|
|
635
|
+
const agentIndex = findAgentIndex(existingAgentList, options.agentId);
|
|
636
|
+
if (agentIndex >= 0) {
|
|
637
|
+
const existingAgent = ensureObject(existingAgentList[agentIndex]);
|
|
638
|
+
existingAgentList[agentIndex] = buildBoundAgentEntry(existingAgent, options.agentId);
|
|
639
|
+
config.agents.list = existingAgentList;
|
|
640
|
+
summary.push(`updated bound agent tool exposure ${options.agentId}`);
|
|
809
641
|
} else {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
existingAgentList[agentIndex] = buildBoundAgentEntry(existingAgent, options.agentId);
|
|
814
|
-
config.agents.list = existingAgentList;
|
|
815
|
-
summary.push(`updated bound agent tool exposure ${options.agentId}`);
|
|
816
|
-
} else {
|
|
817
|
-
existingAgentList.push(buildBoundAgentEntry({}, options.agentId));
|
|
818
|
-
config.agents.list = existingAgentList;
|
|
819
|
-
summary.push(`added bound agent entry ${options.agentId}`);
|
|
820
|
-
}
|
|
821
|
-
summary.push(`attached claworld account ${options.accountId} to existing local agent ${options.agentId}`);
|
|
642
|
+
existingAgentList.push(buildBoundAgentEntry({}, options.agentId));
|
|
643
|
+
config.agents.list = existingAgentList;
|
|
644
|
+
summary.push(`added bound agent entry ${options.agentId}`);
|
|
822
645
|
}
|
|
646
|
+
summary.push(`attached claworld account ${options.accountId} to local agent ${options.agentId}`);
|
|
823
647
|
|
|
824
648
|
config.channels = ensureObject(config.channels);
|
|
825
649
|
const existingClaworldRoot = ensureObject(config.channels.claworld);
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
inspectClaworldChannelAccount,
|
|
11
11
|
listClaworldAccountIds,
|
|
12
12
|
} from './config-schema.js';
|
|
13
|
+
import {
|
|
14
|
+
fetchJson,
|
|
15
|
+
normalizeRelayHttpBaseUrl,
|
|
16
|
+
} from '../runtime/http-boundary.js';
|
|
13
17
|
|
|
14
18
|
function collectUnsupportedSetupFlags(input = {}) {
|
|
15
19
|
const unsupported = [];
|
|
@@ -102,7 +106,7 @@ function hasClaworldBinding(config = {}, { agentId, accountId } = {}) {
|
|
|
102
106
|
});
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
function
|
|
109
|
+
function hasRuntimeCredential(account = {}) {
|
|
106
110
|
return Boolean(
|
|
107
111
|
account?.configured
|
|
108
112
|
&& normalizeText(account?.appToken, null),
|
|
@@ -129,24 +133,23 @@ export function inspectManagedClaworldInstall({
|
|
|
129
133
|
const accountStatus = managedAccountPresent
|
|
130
134
|
? inspectClaworldChannelAccount(cfg, managedOptions.accountId)
|
|
131
135
|
: inspectClaworldChannelAccount({}, managedOptions.accountId);
|
|
132
|
-
const
|
|
136
|
+
const runtimeCredentialReady = hasRuntimeCredential(accountStatus);
|
|
133
137
|
const setupReady = Boolean(
|
|
134
138
|
managedAccountPresent
|
|
135
139
|
&& managedBindingPresent
|
|
136
|
-
&& (managedOptions.manageAgentEntry !== true || managedAgentPresent)
|
|
137
140
|
);
|
|
138
141
|
|
|
139
142
|
let statusLabel = 'needs setup';
|
|
140
143
|
let selectionHint = 'remote relay world channel';
|
|
141
144
|
let quickstartScore = 5;
|
|
142
145
|
|
|
143
|
-
if (setupReady &&
|
|
146
|
+
if (setupReady && runtimeCredentialReady) {
|
|
144
147
|
statusLabel = 'configured';
|
|
145
148
|
selectionHint = 'configured · ready';
|
|
146
149
|
quickstartScore = 2;
|
|
147
150
|
} else if (setupReady) {
|
|
148
|
-
statusLabel = 'configured (
|
|
149
|
-
selectionHint = 'configured ·
|
|
151
|
+
statusLabel = 'configured (email verification pending)';
|
|
152
|
+
selectionHint = 'configured · email verification pending';
|
|
150
153
|
quickstartScore = 3;
|
|
151
154
|
} else if (managedAccountPresent && !managedBindingPresent) {
|
|
152
155
|
statusLabel = 'configured (binding pending)';
|
|
@@ -167,7 +170,7 @@ export function inspectManagedClaworldInstall({
|
|
|
167
170
|
managedAgentPresent,
|
|
168
171
|
managedBindingPresent,
|
|
169
172
|
accountStatus,
|
|
170
|
-
|
|
173
|
+
runtimeCredentialReady,
|
|
171
174
|
setupReady,
|
|
172
175
|
statusLabel,
|
|
173
176
|
selectionHint,
|
|
@@ -185,7 +188,7 @@ export function buildClaworldOnboardingStatus({
|
|
|
185
188
|
statusLines: [`Claworld: ${inspection.statusLabel}`],
|
|
186
189
|
selectionHint: inspection.selectionHint,
|
|
187
190
|
quickstartScore: inspection.quickstartScore,
|
|
188
|
-
|
|
191
|
+
runtimeCredentialReady: inspection.runtimeCredentialReady,
|
|
189
192
|
};
|
|
190
193
|
}
|
|
191
194
|
|
|
@@ -232,23 +235,172 @@ function resolveManagedOptionsFromContext({ cfg = {}, accountId = null, input =
|
|
|
232
235
|
});
|
|
233
236
|
}
|
|
234
237
|
|
|
238
|
+
function resolveSetupFetchImpl(runtime = {}) {
|
|
239
|
+
const candidate = runtime?.fetchImpl
|
|
240
|
+
|| runtime?.fetch
|
|
241
|
+
|| (typeof globalThis.fetch === 'function' ? globalThis.fetch : null);
|
|
242
|
+
if (typeof candidate !== 'function') {
|
|
243
|
+
throw new Error('Claworld setup requires fetch support to complete email verification.');
|
|
244
|
+
}
|
|
245
|
+
return (url, init) => candidate(url, init);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function validateSetupEmail(value) {
|
|
249
|
+
const normalized = normalizeText(value, null);
|
|
250
|
+
if (!normalized) return 'Email is required.';
|
|
251
|
+
if (!normalized.includes('@')) return 'Enter a valid email address.';
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function validateSetupVerificationCode(value) {
|
|
256
|
+
return normalizeText(value, null) ? null : 'Verification code is required.';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function formatSetupApiError(result, fallbackMessage) {
|
|
260
|
+
const body = ensureObject(result?.body);
|
|
261
|
+
const detail = normalizeText(
|
|
262
|
+
body.publicMessage,
|
|
263
|
+
normalizeText(body.error, normalizeText(body.message, null)),
|
|
264
|
+
);
|
|
265
|
+
return detail ? `${fallbackMessage}: ${detail}` : fallbackMessage;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function startSetupEmailVerification({
|
|
269
|
+
runtimeConfig,
|
|
270
|
+
email,
|
|
271
|
+
displayName = null,
|
|
272
|
+
fetchImpl,
|
|
273
|
+
} = {}) {
|
|
274
|
+
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
275
|
+
const normalizedEmail = normalizeText(email, null);
|
|
276
|
+
const normalizedDisplayName = normalizeText(displayName, null);
|
|
277
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/identity/email/start`, {
|
|
278
|
+
method: 'POST',
|
|
279
|
+
headers: {
|
|
280
|
+
'content-type': 'application/json',
|
|
281
|
+
...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
|
|
282
|
+
},
|
|
283
|
+
body: JSON.stringify({
|
|
284
|
+
email: normalizedEmail,
|
|
285
|
+
...(normalizedDisplayName ? { displayName: normalizedDisplayName } : {}),
|
|
286
|
+
}),
|
|
287
|
+
});
|
|
288
|
+
if (!result.ok) {
|
|
289
|
+
throw new Error(formatSetupApiError(result, 'Failed to start Claworld email verification'));
|
|
290
|
+
}
|
|
291
|
+
return ensureObject(result.body);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function completeSetupEmailVerification({
|
|
295
|
+
runtimeConfig,
|
|
296
|
+
email,
|
|
297
|
+
code,
|
|
298
|
+
fetchImpl,
|
|
299
|
+
} = {}) {
|
|
300
|
+
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
301
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/identity/email/verify`, {
|
|
302
|
+
method: 'POST',
|
|
303
|
+
headers: {
|
|
304
|
+
'content-type': 'application/json',
|
|
305
|
+
...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
|
|
306
|
+
},
|
|
307
|
+
body: JSON.stringify({
|
|
308
|
+
email: normalizeText(email, null),
|
|
309
|
+
code: normalizeText(code, null),
|
|
310
|
+
}),
|
|
311
|
+
});
|
|
312
|
+
if (!result.ok) {
|
|
313
|
+
throw new Error(formatSetupApiError(result, 'Failed to complete Claworld email verification'));
|
|
314
|
+
}
|
|
315
|
+
return ensureObject(result.body);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async function resolveSetupCredential({
|
|
319
|
+
managedOptions,
|
|
320
|
+
prompter,
|
|
321
|
+
runtime = {},
|
|
322
|
+
input = {},
|
|
323
|
+
} = {}) {
|
|
324
|
+
if (managedOptions.appToken) return null;
|
|
325
|
+
|
|
326
|
+
const fetchImpl = resolveSetupFetchImpl(runtime);
|
|
327
|
+
const email = normalizeText(await prompter.text({
|
|
328
|
+
message: 'Claworld account email',
|
|
329
|
+
placeholder: 'you@example.com',
|
|
330
|
+
validate: validateSetupEmail,
|
|
331
|
+
}), null);
|
|
332
|
+
|
|
333
|
+
await startSetupEmailVerification({
|
|
334
|
+
runtimeConfig: managedOptions,
|
|
335
|
+
email,
|
|
336
|
+
displayName: normalizeText(input?.name, null),
|
|
337
|
+
fetchImpl,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const code = normalizeText(await prompter.text({
|
|
341
|
+
message: `Verification code sent to ${email}`,
|
|
342
|
+
placeholder: '123456',
|
|
343
|
+
validate: validateSetupVerificationCode,
|
|
344
|
+
}), null);
|
|
345
|
+
|
|
346
|
+
const verification = await completeSetupEmailVerification({
|
|
347
|
+
runtimeConfig: managedOptions,
|
|
348
|
+
email,
|
|
349
|
+
code,
|
|
350
|
+
fetchImpl,
|
|
351
|
+
});
|
|
352
|
+
const appToken = normalizeText(verification.appToken, null);
|
|
353
|
+
const relayAgentId = normalizeText(verification.agentId, null);
|
|
354
|
+
if (!appToken || !relayAgentId) {
|
|
355
|
+
throw new Error('Claworld email verification did not return appToken and agentId.');
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
email,
|
|
359
|
+
appToken,
|
|
360
|
+
relayAgentId,
|
|
361
|
+
created: verification.created === true,
|
|
362
|
+
recovered: verification.recovered === true,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
235
366
|
async function applyManagedOnboardingConfig({
|
|
236
367
|
cfg = {},
|
|
368
|
+
runtime = {},
|
|
237
369
|
prompter,
|
|
238
370
|
accountId = null,
|
|
239
371
|
phase = 'setup',
|
|
240
372
|
input = {},
|
|
241
373
|
} = {}) {
|
|
242
|
-
const
|
|
374
|
+
const initialManagedOptions = resolveManagedOptionsFromContext({ cfg, accountId, input });
|
|
375
|
+
const setupCredential = await resolveSetupCredential({
|
|
376
|
+
managedOptions: initialManagedOptions,
|
|
377
|
+
prompter,
|
|
378
|
+
runtime,
|
|
379
|
+
input,
|
|
380
|
+
});
|
|
381
|
+
const managedOptions = setupCredential
|
|
382
|
+
? {
|
|
383
|
+
...initialManagedOptions,
|
|
384
|
+
appToken: setupCredential.appToken,
|
|
385
|
+
relayAgentId: setupCredential.relayAgentId,
|
|
386
|
+
}
|
|
387
|
+
: initialManagedOptions;
|
|
243
388
|
const next = applyClaworldManagedRuntimeConfig(cfg, managedOptions);
|
|
244
389
|
|
|
245
390
|
const noteLines = [
|
|
246
391
|
`Bound local agent/account: ${managedOptions.agentId}`,
|
|
247
392
|
`Remote backend: ${managedOptions.serverUrl}`,
|
|
248
|
-
|
|
249
|
-
?
|
|
250
|
-
:
|
|
251
|
-
|
|
393
|
+
setupCredential
|
|
394
|
+
? `Email verification: completed for ${setupCredential.email}; runtime credential saved to OpenClaw config`
|
|
395
|
+
: managedOptions.appToken
|
|
396
|
+
? 'Runtime credential: configured appToken is present'
|
|
397
|
+
: 'Email verification: pending until claworld_manage_account(action=start_email_verification|complete_email_verification) runs',
|
|
398
|
+
managedOptions.relayAgentId
|
|
399
|
+
? `Remote agent identity: ${managedOptions.relayAgentId}`
|
|
400
|
+
: 'Remote agent identity: pending',
|
|
401
|
+
'Workspace memory: runtime prompt bootstrap maintains .claworld/ in the active host workspace',
|
|
402
|
+
'This flow refreshes plugin-side config and binds claworld onto the selected local agent.',
|
|
403
|
+
'Setup lifecycle: OpenClaw host-native setup; channel reload is handled by config reload.',
|
|
252
404
|
];
|
|
253
405
|
await prompter.note(
|
|
254
406
|
noteLines.join('\n'),
|
|
@@ -293,17 +445,19 @@ export const claworldOnboardingAdapter = {
|
|
|
293
445
|
}),
|
|
294
446
|
};
|
|
295
447
|
},
|
|
296
|
-
configure: async ({ cfg, prompter, accountOverrides }) =>
|
|
448
|
+
configure: async ({ cfg, runtime, prompter, accountOverrides }) =>
|
|
297
449
|
applyManagedOnboardingConfig({
|
|
298
450
|
cfg,
|
|
451
|
+
runtime,
|
|
299
452
|
prompter,
|
|
300
453
|
accountId: accountOverrides?.claworld,
|
|
301
454
|
phase: 'setup',
|
|
302
455
|
input: {},
|
|
303
456
|
}),
|
|
304
|
-
configureWhenConfigured: async ({ cfg, prompter, accountOverrides }) =>
|
|
457
|
+
configureWhenConfigured: async ({ cfg, runtime, prompter, accountOverrides }) =>
|
|
305
458
|
applyManagedOnboardingConfig({
|
|
306
459
|
cfg,
|
|
460
|
+
runtime,
|
|
307
461
|
prompter,
|
|
308
462
|
accountId: accountOverrides?.claworld,
|
|
309
463
|
phase: 'refresh',
|