@xfxstudio/claworld 0.2.9 → 0.2.10-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +48 -4
  13. package/src/openclaw/installer/constants.js +1 -0
  14. package/src/openclaw/installer/core.js +247 -71
  15. package/src/openclaw/installer/doctor.js +31 -17
  16. package/src/openclaw/plugin/account-identity.js +1 -2
  17. package/src/openclaw/plugin/claworld-channel-plugin.js +453 -263
  18. package/src/openclaw/plugin/config-schema.js +9 -23
  19. package/src/openclaw/plugin/managed-config.js +294 -84
  20. package/src/openclaw/plugin/onboarding.js +37 -45
  21. package/src/openclaw/plugin/register.js +124 -13
  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 +16 -26
  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
@@ -13,8 +13,6 @@ import {
13
13
  const REQUIRED_KEYS = ['enabled', 'serverUrl', 'apiKey', 'accountId'];
14
14
 
15
15
  export const CLAWORLD_CHANNEL_ID = 'claworld';
16
- const LOCAL_AGENT_CODE_PATTERN = '^[A-Za-z0-9._:+~-]+(?:@[A-Za-z0-9._:+~-]+)?$';
17
- const LOCAL_AGENT_CODE_REGEX = new RegExp(LOCAL_AGENT_CODE_PATTERN, 'i');
18
16
 
19
17
  const AGENT_REGISTRATION_SCHEMA = {
20
18
  type: 'object',
@@ -25,22 +23,16 @@ const AGENT_REGISTRATION_SCHEMA = {
25
23
  description: 'Enable relay agent registration when this account does not already have an app token.',
26
24
  default: false,
27
25
  },
28
- agentCode: {
29
- type: 'string',
30
- minLength: 1,
31
- pattern: LOCAL_AGENT_CODE_PATTERN,
32
- description: 'Unique Claworld identity handle. Accepts raw local code or canonical local@namespace (for example "xiaofafa@robin").',
33
- },
34
26
  displayName: {
35
27
  type: 'string',
36
28
  minLength: 1,
37
- description: 'Display name to use when the relay agent is created or refreshed.',
29
+ description: 'Public display name to use when the relay agent is created or refreshed.',
38
30
  },
39
31
  },
40
32
  };
41
33
 
42
34
  export const LOCAL_AGENT_BOOTSTRAP_SCHEMA = AGENT_REGISTRATION_SCHEMA;
43
- export const LOCAL_AGENT_BOOTSTRAP_REQUIRED = ['agentCode'];
35
+ export const LOCAL_AGENT_BOOTSTRAP_REQUIRED = ['displayName'];
44
36
 
45
37
  export const MANUAL_RELAY_BINDING_SCHEMA = {
46
38
  type: 'object',
@@ -61,10 +53,10 @@ export const MANUAL_RELAY_BINDING_SCHEMA = {
61
53
  minLength: 1,
62
54
  description: 'Legacy alias for appToken.',
63
55
  },
64
- defaultToAddress: {
56
+ defaultTargetAgentId: {
65
57
  type: 'string',
66
58
  minLength: 1,
67
- description: 'Default relay target address (for example alice@robin) for minimal outbound testing.',
59
+ description: 'Default relay target agentId for minimal outbound testing.',
68
60
  },
69
61
  },
70
62
  };
@@ -183,7 +175,6 @@ const SINGLE_ACCOUNT_PROPERTIES = {
183
175
  },
184
176
  },
185
177
  registration: AGENT_REGISTRATION_SCHEMA,
186
- localAgent: LOCAL_AGENT_BOOTSTRAP_SCHEMA,
187
178
  relay: MANUAL_RELAY_BINDING_SCHEMA,
188
179
  };
189
180
 
@@ -213,10 +204,10 @@ export const claworldChannelConfigJsonSchema = {
213
204
  export const claworldChannelConfigSchema = {
214
205
  channelId: CLAWORLD_CHANNEL_ID,
215
206
  required: REQUIRED_KEYS,
216
- optional: ['name', 'heartbeatSeconds', 'reconnect', 'routing', 'approval', 'testing', 'appToken', 'registration', 'localAgent', 'relay', 'toolProfile', 'defaultAccount', 'accounts'],
207
+ optional: ['name', 'heartbeatSeconds', 'reconnect', 'routing', 'approval', 'testing', 'appToken', 'registration', 'relay', 'toolProfile', 'defaultAccount', 'accounts'],
217
208
  jsonSchema: claworldChannelConfigJsonSchema,
218
209
  description:
219
- '最小 OpenClaw claworld channel 配置;支持单账号或 accounts.<id> 多账号模式。canonical flow uses appToken + registration, while relay/localAgent fields remain compatibility aliases.',
210
+ '最小 OpenClaw claworld channel 配置;支持单账号或 accounts.<id> 多账号模式。canonical flow uses appToken + registration.displayName bootstrap.',
220
211
  routingShape: {
221
212
  sessionTarget: 'mainagent',
222
213
  fallbackTarget: 'mainagent',
@@ -341,11 +332,8 @@ export function validateClaworldChannelConfig(config = {}, accountId = null) {
341
332
  errors.push({ code: 'invalid_fallback_target', value: fallbackTarget });
342
333
  }
343
334
 
344
- if (registration.enabled && !registration.agentCode) {
345
- errors.push({ code: 'missing_local_agent_code' });
346
- }
347
- if (registration.enabled && registration.agentCode && !LOCAL_AGENT_CODE_REGEX.test(String(registration.agentCode).trim())) {
348
- errors.push({ code: 'invalid_local_agent_code', value: registration.agentCode });
335
+ if (registration.enabled && !registration.displayName) {
336
+ errors.push({ code: 'missing_registration_display_name' });
349
337
  }
350
338
 
351
339
  if (candidate.relay?.agentId && !appToken) {
@@ -375,7 +363,7 @@ export function validateClaworldChannelConfig(config = {}, accountId = null) {
375
363
  agentId: candidate.relay?.agentId || null,
376
364
  appToken,
377
365
  credentialToken: appToken,
378
- defaultToAddress: candidate.relay?.defaultToAddress || null,
366
+ defaultTargetAgentId: candidate.relay?.defaultTargetAgentId || null,
379
367
  },
380
368
  });
381
369
 
@@ -407,7 +395,6 @@ export function inspectClaworldChannelAccount(config = {}, accountId = null) {
407
395
  testing: normalized.testing,
408
396
  appToken: normalized.appToken || null,
409
397
  registration: normalized.registration,
410
- localAgent: normalized.localAgent,
411
398
  relay: normalized.relay,
412
399
  defaultAccount: normalized.defaultAccount,
413
400
  bindingStatus,
@@ -435,7 +422,6 @@ export function resolveClaworldRuntimeConfig(config = {}, accountId = null) {
435
422
  ...result.normalized,
436
423
  accountId: result.normalized.accountId || accountId || readDefaultAccountId(config) || 'default',
437
424
  approval: result.normalized.approval,
438
- localAgent: result.normalized.localAgent,
439
425
  relay: result.normalized.relay,
440
426
  };
441
427
  }
@@ -25,6 +25,8 @@ export const DEFAULT_CLAWORLD_FALLBACK_TARGET = 'mainagent';
25
25
  export const CLAWORLD_PLUGIN_TOOL_ALLOW_ENTRY = 'claworld';
26
26
  export const MIN_MANAGED_SESSION_VISIBILITY = 'agent';
27
27
  export const REQUIRED_SANDBOX_SESSION_TOOLS_VISIBILITY = 'all';
28
+ export const CLAWORLD_INSTALLER_STATE_ROOT_KEY = 'claworldInstaller';
29
+ export const CLAWORLD_MANAGED_RUNTIME_BACKUP_VERSION = 1;
28
30
 
29
31
  export const TOOL_PROFILES = CLAWORLD_TOOL_PROFILES;
30
32
 
@@ -49,9 +51,9 @@ export function ensureObject(value) {
49
51
  return value;
50
52
  }
51
53
 
52
- function normalizeRegistrationAgentCode(value, fallback = null) {
54
+ function normalizeRegistrationDisplayName(value, fallback = null) {
53
55
  const normalized = normalizeText(value, fallback);
54
- return normalized ? normalized.toLowerCase() : fallback;
56
+ return normalized || fallback;
55
57
  }
56
58
 
57
59
  export function expandUserPath(input, homeDir = os.homedir()) {
@@ -103,14 +105,6 @@ function mergeManagedPluginToolExposure(existingTools = {}) {
103
105
  };
104
106
  }
105
107
 
106
- function inferRelayDomain(defaultToAddress = null) {
107
- const normalized = normalizeText(defaultToAddress, null);
108
- if (!normalized) return 'relay.local';
109
- const atIndex = normalized.indexOf('@');
110
- if (atIndex <= 0 || atIndex >= normalized.length - 1) return 'relay.local';
111
- return normalized.slice(atIndex + 1).trim().toLowerCase() || 'relay.local';
112
- }
113
-
114
108
  function findAgentIndex(agentList = [], agentId) {
115
109
  return agentList.findIndex((item) => ensureObject(item).id === agentId);
116
110
  }
@@ -130,6 +124,72 @@ function findManagedAccountEntry(config = {}, accountId) {
130
124
  return {};
131
125
  }
132
126
 
127
+ function ensureMutableInstallerStateRoot(installerState = {}) {
128
+ installerState[CLAWORLD_INSTALLER_STATE_ROOT_KEY] = ensureObject(installerState[CLAWORLD_INSTALLER_STATE_ROOT_KEY]);
129
+ const rootState = ensureObject(installerState[CLAWORLD_INSTALLER_STATE_ROOT_KEY]);
130
+ rootState.managedRuntime = ensureObject(rootState.managedRuntime);
131
+ rootState.managedRuntime.accounts = ensureObject(rootState.managedRuntime.accounts);
132
+ installerState[CLAWORLD_INSTALLER_STATE_ROOT_KEY] = rootState;
133
+ return rootState.managedRuntime.accounts;
134
+ }
135
+
136
+ function trimInstallerStateRoot(installerState = {}) {
137
+ const rootState = ensureObject(installerState[CLAWORLD_INSTALLER_STATE_ROOT_KEY]);
138
+ const managedRuntime = ensureObject(rootState.managedRuntime);
139
+ const accounts = ensureObject(managedRuntime.accounts);
140
+ if (Object.keys(accounts).length === 0) {
141
+ delete managedRuntime.accounts;
142
+ } else {
143
+ managedRuntime.accounts = accounts;
144
+ }
145
+ if (Object.keys(managedRuntime).length === 0) {
146
+ delete rootState.managedRuntime;
147
+ } else {
148
+ rootState.managedRuntime = managedRuntime;
149
+ }
150
+ if (Object.keys(rootState).length === 0) {
151
+ delete installerState[CLAWORLD_INSTALLER_STATE_ROOT_KEY];
152
+ } else {
153
+ installerState[CLAWORLD_INSTALLER_STATE_ROOT_KEY] = rootState;
154
+ }
155
+ }
156
+
157
+ export function findClaworldManagedRuntimeBackup(installerState = {}, accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
158
+ const normalizedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
159
+ const rootState = ensureObject(installerState?.[CLAWORLD_INSTALLER_STATE_ROOT_KEY]);
160
+ const managedRuntime = ensureObject(rootState.managedRuntime);
161
+ const accounts = ensureObject(managedRuntime.accounts);
162
+ return ensureObject(accounts[normalizedAccountId]);
163
+ }
164
+
165
+ export function setClaworldManagedRuntimeBackupState(
166
+ installerState = {},
167
+ accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
168
+ value = null,
169
+ ) {
170
+ const normalizedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
171
+ const accounts = ensureMutableInstallerStateRoot(installerState);
172
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
173
+ accounts[normalizedAccountId] = JSON.parse(JSON.stringify(value));
174
+ } else {
175
+ delete accounts[normalizedAccountId];
176
+ }
177
+ trimInstallerStateRoot(installerState);
178
+ return installerState;
179
+ }
180
+
181
+ function removeManagedPluginToolExposure(existingTools = {}) {
182
+ const tools = ensureObject(existingTools);
183
+ const allow = asStringArray(tools.allow).filter((toolName) => toolName !== CLAWORLD_PLUGIN_TOOL_ALLOW_ENTRY);
184
+ const alsoAllow = asStringArray(tools.alsoAllow).filter((toolName) => toolName !== CLAWORLD_PLUGIN_TOOL_ALLOW_ENTRY);
185
+ const nextTools = { ...tools };
186
+ if (allow.length > 0) nextTools.allow = uniqueStrings(allow);
187
+ else delete nextTools.allow;
188
+ if (alsoAllow.length > 0) nextTools.alsoAllow = uniqueStrings(alsoAllow);
189
+ else delete nextTools.alsoAllow;
190
+ return Object.keys(nextTools).length > 0 ? nextTools : null;
191
+ }
192
+
133
193
  const SESSION_VISIBILITY_RANK = Object.freeze({
134
194
  self: 0,
135
195
  tree: 1,
@@ -295,22 +355,21 @@ function buildManagedAccountEntry(options = {}) {
295
355
 
296
356
  if (options.appToken) {
297
357
  base.appToken = options.appToken;
298
- } else {
358
+ } else if (normalizeText(options.registrationDisplayName, null)) {
299
359
  base.registration = {
300
360
  enabled: true,
301
- agentCode: options.registrationAgentCode,
302
- displayName: options.displayName,
361
+ displayName: normalizeText(options.registrationDisplayName, options.displayName),
303
362
  };
304
363
  }
305
364
 
306
- if (!options.defaultToAddress) {
365
+ if (!options.defaultTargetAgentId) {
307
366
  return base;
308
367
  }
309
368
 
310
369
  return {
311
370
  ...base,
312
371
  relay: {
313
- defaultToAddress: options.defaultToAddress,
372
+ defaultTargetAgentId: options.defaultTargetAgentId,
314
373
  },
315
374
  };
316
375
  }
@@ -331,11 +390,11 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
331
390
  ...existingApproval,
332
391
  mode: normalizeChatRequestApprovalMode(options.approvalMode, DEFAULT_CLAWORLD_APPROVAL_MODE),
333
392
  },
334
- ...(options.defaultToAddress
393
+ ...(options.defaultTargetAgentId
335
394
  ? {
336
395
  relay: {
337
396
  ...existingRelay,
338
- defaultToAddress: options.defaultToAddress,
397
+ defaultTargetAgentId: options.defaultTargetAgentId,
339
398
  },
340
399
  }
341
400
  : existingAccount.relay
@@ -345,10 +404,18 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
345
404
  delete merged.toolProfile;
346
405
 
347
406
  if (options.appToken) {
348
- return {
407
+ const withToken = {
349
408
  ...merged,
350
409
  appToken: options.appToken,
351
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;
352
419
  }
353
420
 
354
421
  return {
@@ -356,19 +423,11 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
356
423
  registration: {
357
424
  ...existingRegistration,
358
425
  enabled: true,
359
- agentCode: options.registrationAgentCode,
360
- displayName: options.displayName,
426
+ displayName: normalizeText(options.registrationDisplayName, options.displayName),
361
427
  },
362
428
  };
363
429
  }
364
430
 
365
- export function canonicalRelayAgentCode(registrationAgentCode, defaultToAddress = null) {
366
- const normalizedAgentCode = normalizeRegistrationAgentCode(registrationAgentCode, null);
367
- if (!normalizedAgentCode) return null;
368
- if (normalizedAgentCode.includes('@')) return normalizedAgentCode;
369
- return `${normalizedAgentCode}@${inferRelayDomain(defaultToAddress)}`;
370
- }
371
-
372
431
  export function normalizeClaworldToolProfile(toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE) {
373
432
  const normalized = normalizeText(toolProfile, DEFAULT_CLAWORLD_TOOL_PROFILE);
374
433
  if (normalized === 'world') return 'default';
@@ -455,16 +514,15 @@ function describeToolAllowEntries(toolNames = []) {
455
514
  export function buildWorkspaceAgentsContent({
456
515
  agentId,
457
516
  accountId,
458
- registrationAgentCode,
517
+ registrationDisplayName,
459
518
  appToken = null,
460
- defaultToAddress = null,
519
+ defaultTargetAgentId = null,
461
520
  } = {}) {
462
- const canonicalCode = canonicalRelayAgentCode(registrationAgentCode, defaultToAddress);
463
- const identityLine = canonicalCode
464
- ? `- canonical relay agentCode after bootstrap: \`${canonicalCode}\``
465
- : appToken
466
- ? '- relay identity is resolved from the configured appToken at runtime'
467
- : '- relay identity is resolved during runtime bootstrap';
521
+ const identityLine = appToken
522
+ ? '- relay binding is resolved from the configured appToken at runtime'
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';
468
526
 
469
527
  return `# Claworld Channel Agent
470
528
 
@@ -474,8 +532,9 @@ Routing contract:
474
532
 
475
533
  - local OpenClaw agent id: \`${agentId}\`
476
534
  - claworld account id: \`${accountId}\`
477
- ${registrationAgentCode ? `- registration.agentCode: \`${registrationAgentCode}\`` : '- credential mode: appToken/manual binding'}
535
+ ${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : (appToken ? '- credential mode: appToken/manual binding' : '- credential mode: activation pending')}
478
536
  ${identityLine}
537
+ ${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : '- outbound sends require explicit target agentId inputs'}
479
538
 
480
539
  Operating rules:
481
540
 
@@ -498,22 +557,23 @@ function buildBoundAgentEntry(existingAgent = {}, agentId) {
498
557
  export function buildWorkspaceMemoryContent({
499
558
  agentId,
500
559
  accountId,
501
- registrationAgentCode,
560
+ registrationDisplayName,
502
561
  appToken = null,
503
- defaultToAddress = null,
562
+ defaultTargetAgentId = null,
504
563
  } = {}) {
505
- const canonicalCode = canonicalRelayAgentCode(registrationAgentCode, defaultToAddress);
506
- const identityLine = canonicalCode
507
- ? `- relay identity: \`${canonicalCode}\``
508
- : appToken
509
- ? '- relay identity: resolved from appToken at runtime'
510
- : '- relay identity: assigned during runtime bootstrap';
564
+ const identityLine = appToken
565
+ ? '- relay binding: resolved from appToken at runtime'
566
+ : registrationDisplayName
567
+ ? '- relay binding: assigned during runtime bootstrap'
568
+ : '- relay binding: pending until public identity setup completes';
511
569
 
512
570
  return `# Claworld Memory
513
571
 
514
572
  - workspace owner: \`${agentId}\`
515
573
  - claworld account: \`${accountId}\`
574
+ ${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : ''}
516
575
  ${identityLine}
576
+ ${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : ''}
517
577
 
518
578
  Use this file for durable Claworld-specific notes only.
519
579
 
@@ -527,10 +587,6 @@ export function resolveDefaultManagedWorkspace(agentId = DEFAULT_CLAWORLD_AGENT_
527
587
  return `~/.openclaw/workspace-${agentId}`;
528
588
  }
529
589
 
530
- export function resolveDefaultManagedRegistrationAgentCode(accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
531
- return null;
532
- }
533
-
534
590
  export function resolveDefaultManagedDisplayName(accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
535
591
  return `${titleCase(accountId)} Channel Agent`;
536
592
  }
@@ -551,10 +607,13 @@ export function resolveClaworldManagedRuntimeOptions({
551
607
  accountId = null,
552
608
  input = {},
553
609
  overrides = {},
610
+ installerState = null,
554
611
  } = {}) {
555
612
  const resolvedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
556
613
  const attachToExistingAgent = overrides.attachToExistingAgent !== false;
557
- const inferredAgentId = inferExistingAgentId(cfg, resolvedAccountId);
614
+ const existingBackup = findClaworldManagedRuntimeBackup(installerState, resolvedAccountId);
615
+ const inferredAgentId = inferExistingAgentId(cfg, resolvedAccountId)
616
+ || normalizeText(existingBackup.agentId, null);
558
617
  const agentId = normalizeText(overrides.agentId, inferredAgentId);
559
618
  const existingAgent = findAgentEntry(cfg, agentId);
560
619
  const existingAccount = findManagedAccountEntry(cfg, resolvedAccountId);
@@ -570,23 +629,23 @@ export function resolveClaworldManagedRuntimeOptions({
570
629
  const workspace = normalizeText(
571
630
  explicitWorkspace,
572
631
  replaceManagedRuntime
573
- ? normalizeText(existingAgent?.workspace, defaultWorkspace)
574
- : normalizeText(existingAgent?.workspace, defaultWorkspace),
632
+ ? normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace))
633
+ : normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace)),
575
634
  );
576
635
  const serverUrl = normalizeText(
577
636
  overrides.serverUrl,
578
- normalizeText(input.httpUrl, normalizeText(input.url, DEFAULT_CLAWORLD_SERVER_URL)),
637
+ normalizeText(input.httpUrl, normalizeText(input.url, normalizeText(existingBackup.serverUrl, DEFAULT_CLAWORLD_SERVER_URL))),
579
638
  );
580
- const apiKey = normalizeText(overrides.apiKey, DEFAULT_CLAWORLD_API_KEY);
639
+ const apiKey = normalizeText(overrides.apiKey, normalizeText(existingBackup.apiKey, DEFAULT_CLAWORLD_API_KEY));
581
640
  const explicitAppToken = normalizeText(
582
641
  overrides.appToken,
583
642
  normalizeText(input.appToken, null),
584
643
  );
585
- const explicitRegistrationAgentCode = normalizeRegistrationAgentCode(
586
- overrides.registrationAgentCode,
587
- normalizeRegistrationAgentCode(input.code, null),
644
+ const explicitRegistrationDisplayName = normalizeRegistrationDisplayName(
645
+ overrides.registrationDisplayName,
646
+ normalizeRegistrationDisplayName(input.name, null),
588
647
  );
589
- const appToken = explicitRegistrationAgentCode && !explicitAppToken
648
+ const appToken = explicitRegistrationDisplayName && !explicitAppToken
590
649
  ? null
591
650
  : normalizeText(
592
651
  explicitAppToken,
@@ -594,35 +653,36 @@ export function resolveClaworldManagedRuntimeOptions({
594
653
  existingAccount.appToken,
595
654
  normalizeText(
596
655
  existingAccount?.relay?.appToken,
597
- normalizeText(existingAccount?.relay?.credentialToken, null),
656
+ normalizeText(existingAccount?.relay?.credentialToken, normalizeText(existingBackup.appToken, null)),
598
657
  ),
599
658
  ),
600
659
  );
601
660
  const displayName = normalizeText(
602
661
  overrides.displayName,
603
- normalizeText(input.name, resolveDefaultManagedDisplayName(resolvedAccountId)),
662
+ normalizeText(input.name, normalizeText(existingBackup.displayName, resolveDefaultManagedDisplayName(resolvedAccountId))),
604
663
  );
605
- const name = normalizeText(overrides.name, displayName);
606
- const existingRegistrationAgentCode = normalizeRegistrationAgentCode(
607
- existingAccount?.registration?.agentCode,
608
- normalizeRegistrationAgentCode(existingAccount?.localAgent?.agentCode, null),
664
+ const name = normalizeText(overrides.name, normalizeText(existingBackup.name, displayName));
665
+ const existingRegistrationDisplayName = normalizeRegistrationDisplayName(
666
+ existingAccount?.registration?.displayName,
667
+ normalizeRegistrationDisplayName(
668
+ existingAccount?.localAgent?.displayName,
669
+ normalizeRegistrationDisplayName(existingBackup.registrationDisplayName, null),
670
+ ),
609
671
  );
610
- const registrationAgentCode = appToken && !explicitRegistrationAgentCode
672
+ const registrationDisplayName = appToken && !explicitRegistrationDisplayName
611
673
  ? null
612
- : normalizeRegistrationAgentCode(
613
- explicitRegistrationAgentCode,
614
- normalizeRegistrationAgentCode(
615
- normalizeRegistrationAgentCode(
616
- resolveDefaultManagedRegistrationAgentCode(resolvedAccountId),
617
- existingRegistrationAgentCode,
618
- ),
619
- ),
674
+ : normalizeRegistrationDisplayName(
675
+ explicitRegistrationDisplayName,
676
+ existingRegistrationDisplayName,
620
677
  );
621
678
  const approvalMode = normalizeChatRequestApprovalMode(
622
679
  normalizeText(overrides.approvalMode, null),
623
680
  typeof overrides.autoAccept === 'boolean'
624
681
  ? (overrides.autoAccept ? 'open' : DEFAULT_CLAWORLD_APPROVAL_MODE)
625
- : resolveStoredApprovalMode(existingAccount),
682
+ : normalizeChatRequestApprovalMode(
683
+ normalizeText(existingBackup.approvalMode, null),
684
+ resolveStoredApprovalMode(existingAccount),
685
+ ),
626
686
  );
627
687
 
628
688
  return {
@@ -638,14 +698,14 @@ export function resolveClaworldManagedRuntimeOptions({
638
698
  serverUrl,
639
699
  apiKey,
640
700
  appToken,
641
- registrationAgentCode,
701
+ registrationDisplayName,
642
702
  displayName,
643
703
  name,
644
- defaultToAddress: normalizeText(overrides.defaultToAddress, null),
704
+ defaultTargetAgentId: normalizeText(overrides.defaultTargetAgentId, null),
645
705
  approvalMode,
646
706
  sessionDmScope: normalizeText(
647
707
  overrides.sessionDmScope,
648
- DEFAULT_CLAWORLD_DM_SCOPE,
708
+ normalizeText(existingBackup.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE),
649
709
  ),
650
710
  replaceManagedRuntime,
651
711
  preserveDefaultAccount: overrides.preserveDefaultAccount === true,
@@ -665,10 +725,6 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
665
725
  const sessionDmScope = normalizeText(options.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE);
666
726
  const manageAgentEntry = options.manageAgentEntry === true;
667
727
 
668
- if (!options.appToken && !normalizeText(options.registrationAgentCode, null)) {
669
- throw new Error('claworld registration agentCode is required when appToken is absent');
670
- }
671
-
672
728
  const removedManagedToolNames = new Set([
673
729
  ...CLAWORLD_PUBLIC_TOOL_NAMES,
674
730
  ...CLAWORLD_COMPATIBILITY_TOOL_NAMES,
@@ -829,10 +885,164 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
829
885
  return {
830
886
  config,
831
887
  summary,
832
- canonicalAgentCode: canonicalRelayAgentCode(
833
- options.registrationAgentCode,
834
- options.defaultToAddress,
835
- ),
888
+ bootstrapDisplayName: normalizeText(options.registrationDisplayName, null),
889
+ };
890
+ }
891
+
892
+ export function stripClaworldManagedRuntimeConfig(inputConfig = {}, {
893
+ accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
894
+ agentId = null,
895
+ preserveBackup = true,
896
+ } = {}) {
897
+ const config = JSON.parse(JSON.stringify(ensureObject(inputConfig)));
898
+ const summary = [];
899
+ const resolvedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
900
+ const resolvedAgentId = normalizeText(agentId, inferExistingAgentId(config, resolvedAccountId));
901
+ const existingAgent = findAgentEntry(config, resolvedAgentId);
902
+ const existingAccount = findManagedAccountEntry(config, resolvedAccountId);
903
+ const existingToolProfile = resolveStoredClaworldToolProfile(existingAccount) || inferClaworldToolProfile(config);
904
+ const backup = preserveBackup
905
+ ? {
906
+ version: CLAWORLD_MANAGED_RUNTIME_BACKUP_VERSION,
907
+ accountId: resolvedAccountId,
908
+ agentId: resolvedAgentId,
909
+ workspace: normalizeText(existingAgent?.workspace, null),
910
+ serverUrl: normalizeText(existingAccount.serverUrl, null),
911
+ apiKey: normalizeText(existingAccount.apiKey, null),
912
+ appToken: normalizeText(
913
+ existingAccount.appToken,
914
+ normalizeText(existingAccount?.relay?.appToken, normalizeText(existingAccount?.relay?.credentialToken, null)),
915
+ ),
916
+ displayName: normalizeText(existingAccount.name, normalizeText(existingAgent?.name, null)),
917
+ name: normalizeText(existingAccount.name, null),
918
+ registrationDisplayName: normalizeRegistrationDisplayName(existingAccount?.registration?.displayName, null),
919
+ approvalMode: normalizeChatRequestApprovalMode(existingAccount?.approval?.mode, DEFAULT_CLAWORLD_APPROVAL_MODE),
920
+ sessionDmScope: normalizeText(config?.session?.dmScope, DEFAULT_CLAWORLD_DM_SCOPE),
921
+ toolProfile: existingToolProfile,
922
+ preservedAt: new Date().toISOString(),
923
+ }
924
+ : null;
925
+ if (backup) {
926
+ summary.push(`prepared managed claworld runtime backup for ${resolvedAccountId}`);
927
+ }
928
+
929
+ if (resolvedAgentId) {
930
+ const agentList = Array.isArray(config?.agents?.list) ? [...config.agents.list] : [];
931
+ const agentIndex = findAgentIndex(agentList, resolvedAgentId);
932
+ if (agentIndex >= 0) {
933
+ const nextAgent = { ...ensureObject(agentList[agentIndex]) };
934
+ const nextTools = removeManagedPluginToolExposure(nextAgent.tools);
935
+ if (nextTools) nextAgent.tools = nextTools;
936
+ else delete nextAgent.tools;
937
+ agentList[agentIndex] = nextAgent;
938
+ config.agents = ensureObject(config.agents);
939
+ config.agents.list = agentList;
940
+ summary.push(`removed managed claworld tool exposure from agent ${resolvedAgentId}`);
941
+ }
942
+ }
943
+
944
+ const claworldRoot = ensureObject(config?.channels?.claworld);
945
+ const accounts = ensureObject(claworldRoot.accounts);
946
+ if (Object.prototype.hasOwnProperty.call(accounts, resolvedAccountId)) {
947
+ delete accounts[resolvedAccountId];
948
+ summary.push(`removed channels.claworld.accounts.${resolvedAccountId}`);
949
+ }
950
+ const nextClaworldRoot = { ...claworldRoot };
951
+ if (Object.keys(accounts).length > 0) {
952
+ nextClaworldRoot.accounts = accounts;
953
+ const currentDefaultAccount = normalizeText(nextClaworldRoot.defaultAccount, null);
954
+ if (currentDefaultAccount === resolvedAccountId) {
955
+ nextClaworldRoot.defaultAccount = Object.keys(accounts)[0];
956
+ summary.push(`repointed channels.claworld.defaultAccount to ${nextClaworldRoot.defaultAccount}`);
957
+ }
958
+ } else {
959
+ delete nextClaworldRoot.accounts;
960
+ delete nextClaworldRoot.defaultAccount;
961
+ }
962
+ if (Object.keys(nextClaworldRoot).length > 0) {
963
+ config.channels = ensureObject(config.channels);
964
+ config.channels.claworld = nextClaworldRoot;
965
+ } else if (config.channels && typeof config.channels === 'object' && !Array.isArray(config.channels)) {
966
+ delete config.channels.claworld;
967
+ if (Object.keys(config.channels).length === 0) {
968
+ delete config.channels;
969
+ }
970
+ summary.push('removed channels.claworld root');
971
+ }
972
+
973
+ if (Array.isArray(config.bindings)) {
974
+ const nextBindings = config.bindings.filter((binding) => {
975
+ const candidate = ensureObject(binding);
976
+ const match = ensureObject(candidate.match);
977
+ const bindingChannel = normalizeText(match.channel, null);
978
+ const bindingAccountId = normalizeText(match.accountId, null);
979
+ const bindingAgentId = normalizeText(candidate.agentId, null);
980
+ if (bindingChannel !== 'claworld') return true;
981
+ if (bindingAccountId === resolvedAccountId) return false;
982
+ if (!bindingAccountId && resolvedAgentId && bindingAgentId === resolvedAgentId) return false;
983
+ return true;
984
+ });
985
+ if (nextBindings.length !== config.bindings.length) {
986
+ config.bindings = nextBindings;
987
+ summary.push(`removed claworld bindings for ${resolvedAccountId}`);
988
+ }
989
+ if (config.bindings.length === 0) {
990
+ delete config.bindings;
991
+ }
992
+ }
993
+
994
+ config.plugins = ensureObject(config.plugins);
995
+ const nextPluginAllow = asStringArray(config.plugins.allow).filter((pluginId) => pluginId !== 'claworld');
996
+ if (nextPluginAllow.length > 0) config.plugins.allow = uniqueStrings(nextPluginAllow);
997
+ else delete config.plugins.allow;
998
+
999
+ const nextPluginEntries = ensureObject(config.plugins.entries);
1000
+ if (Object.prototype.hasOwnProperty.call(nextPluginEntries, 'claworld')) {
1001
+ delete nextPluginEntries.claworld;
1002
+ summary.push('removed plugins.entries.claworld');
1003
+ }
1004
+ if (Object.keys(nextPluginEntries).length > 0) config.plugins.entries = nextPluginEntries;
1005
+ else delete config.plugins.entries;
1006
+
1007
+ const nextPluginInstalls = ensureObject(config.plugins.installs);
1008
+ const claworldInstallRecord = ensureObject(nextPluginInstalls.claworld);
1009
+ if (Object.prototype.hasOwnProperty.call(nextPluginInstalls, 'claworld')) {
1010
+ delete nextPluginInstalls.claworld;
1011
+ summary.push('removed plugins.installs.claworld');
1012
+ }
1013
+ if (Object.keys(nextPluginInstalls).length > 0) config.plugins.installs = nextPluginInstalls;
1014
+ else delete config.plugins.installs;
1015
+
1016
+ const nextPluginLoad = ensureObject(config.plugins.load);
1017
+ const sourcePath = normalizeText(claworldInstallRecord.sourcePath, null);
1018
+ const filteredLoadPaths = asStringArray(nextPluginLoad.paths).filter((entry) => entry !== sourcePath);
1019
+ if (sourcePath && filteredLoadPaths.length !== asStringArray(nextPluginLoad.paths).length) {
1020
+ if (filteredLoadPaths.length > 0) {
1021
+ nextPluginLoad.paths = uniqueStrings(filteredLoadPaths);
1022
+ } else {
1023
+ delete nextPluginLoad.paths;
1024
+ }
1025
+ summary.push('removed plugins.load.paths claworld sourcePath');
1026
+ }
1027
+ if (Object.keys(nextPluginLoad).length > 0) config.plugins.load = nextPluginLoad;
1028
+ else delete config.plugins.load;
1029
+
1030
+ const nextPluginSlots = ensureObject(config.plugins.slots);
1031
+ if (normalizeText(nextPluginSlots.memory, null) === 'claworld') {
1032
+ delete nextPluginSlots.memory;
1033
+ summary.push('removed plugins.slots.memory claworld');
1034
+ }
1035
+ if (Object.keys(nextPluginSlots).length > 0) config.plugins.slots = nextPluginSlots;
1036
+ else delete config.plugins.slots;
1037
+
1038
+ if (Object.keys(config.plugins).length === 0) {
1039
+ delete config.plugins;
1040
+ }
1041
+
1042
+ return {
1043
+ config,
1044
+ summary,
1045
+ backup,
836
1046
  };
837
1047
  }
838
1048