@xfxstudio/claworld 0.2.9 → 0.2.10-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/openclaw.plugin.json +7 -63
  3. package/package.json +6 -2
  4. package/skills/claworld-help/SKILL.md +5 -1
  5. package/skills/claworld-join-and-chat/SKILL.md +21 -1
  6. package/skills/claworld-manage-worlds/SKILL.md +81 -10
  7. package/src/lib/agent-profile.js +8 -3
  8. package/src/lib/chat-request.js +0 -1
  9. package/src/lib/policy.js +2 -6
  10. package/src/lib/public-identity.js +175 -0
  11. package/src/lib/relay/kickoff-text.js +1 -0
  12. package/src/openclaw/installer/cli.js +46 -1
  13. package/src/openclaw/installer/constants.js +1 -0
  14. package/src/openclaw/installer/core.js +234 -3
  15. package/src/openclaw/installer/doctor.js +2 -2
  16. package/src/openclaw/plugin/account-identity.js +1 -2
  17. package/src/openclaw/plugin/claworld-channel-plugin.js +270 -255
  18. package/src/openclaw/plugin/config-schema.js +9 -23
  19. package/src/openclaw/plugin/managed-config.js +284 -79
  20. package/src/openclaw/plugin/onboarding.js +22 -42
  21. package/src/openclaw/plugin/register.js +109 -10
  22. package/src/openclaw/plugin/relay-client.js +233 -17
  23. package/src/openclaw/runtime/backend-error-context.js +91 -0
  24. package/src/openclaw/runtime/feedback-helper.js +1 -2
  25. package/src/openclaw/runtime/product-shell-helper.js +43 -9
  26. package/src/openclaw/runtime/tool-contracts.js +26 -3
  27. package/src/openclaw/runtime/tool-inventory.js +7 -0
  28. package/src/openclaw/runtime/world-moderation-helper.js +3 -19
  29. package/src/product-shell/contracts/candidate-feed.js +7 -0
  30. package/src/product-shell/contracts/world-manifest.js +0 -1
  31. package/src/product-shell/contracts/world-orchestration.js +10 -1
  32. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +261 -0
  33. package/src/product-shell/feedback/feedback-routes.js +0 -1
  34. package/src/product-shell/feedback/feedback-service.js +4 -9
  35. package/src/product-shell/index.js +40 -7
  36. package/src/product-shell/matching/matchmaking-service.js +22 -1
  37. package/src/product-shell/membership/membership-service.js +5 -1
  38. package/src/product-shell/onboarding/onboarding-service.js +10 -21
  39. package/src/product-shell/profile/public-identity-routes.js +60 -0
  40. package/src/product-shell/profile/public-identity-service.js +190 -0
  41. package/src/product-shell/search/search-service.js +9 -2
  42. package/src/product-shell/social/chat-request-service.js +22 -7
  43. package/src/product-shell/social/friend-routes.js +1 -1
  44. package/src/product-shell/social/friend-service.js +16 -19
  45. package/src/product-shell/social/social-routes.js +2 -2
  46. package/src/product-shell/social/social-service.js +31 -35
  47. package/src/product-shell/worlds/world-admin-service.js +31 -10
  48. package/src/product-shell/worlds/world-broadcast-service.js +2 -2
  49. package/src/lib/agent-address.js +0 -46
@@ -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,
@@ -298,19 +358,18 @@ function buildManagedAccountEntry(options = {}) {
298
358
  } else {
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
@@ -356,19 +415,11 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
356
415
  registration: {
357
416
  ...existingRegistration,
358
417
  enabled: true,
359
- agentCode: options.registrationAgentCode,
360
- displayName: options.displayName,
418
+ displayName: normalizeText(options.registrationDisplayName, options.displayName),
361
419
  },
362
420
  };
363
421
  }
364
422
 
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
423
  export function normalizeClaworldToolProfile(toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE) {
373
424
  const normalized = normalizeText(toolProfile, DEFAULT_CLAWORLD_TOOL_PROFILE);
374
425
  if (normalized === 'world') return 'default';
@@ -455,16 +506,13 @@ function describeToolAllowEntries(toolNames = []) {
455
506
  export function buildWorkspaceAgentsContent({
456
507
  agentId,
457
508
  accountId,
458
- registrationAgentCode,
509
+ registrationDisplayName,
459
510
  appToken = null,
460
- defaultToAddress = null,
511
+ defaultTargetAgentId = null,
461
512
  } = {}) {
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';
513
+ const identityLine = appToken
514
+ ? '- relay binding is resolved from the configured appToken at runtime'
515
+ : '- relay binding is created during runtime bootstrap and persists as backend-issued credentials';
468
516
 
469
517
  return `# Claworld Channel Agent
470
518
 
@@ -474,8 +522,9 @@ Routing contract:
474
522
 
475
523
  - local OpenClaw agent id: \`${agentId}\`
476
524
  - claworld account id: \`${accountId}\`
477
- ${registrationAgentCode ? `- registration.agentCode: \`${registrationAgentCode}\`` : '- credential mode: appToken/manual binding'}
525
+ ${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : '- credential mode: appToken/manual binding'}
478
526
  ${identityLine}
527
+ ${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : '- outbound sends require explicit target agentId inputs'}
479
528
 
480
529
  Operating rules:
481
530
 
@@ -498,22 +547,21 @@ function buildBoundAgentEntry(existingAgent = {}, agentId) {
498
547
  export function buildWorkspaceMemoryContent({
499
548
  agentId,
500
549
  accountId,
501
- registrationAgentCode,
550
+ registrationDisplayName,
502
551
  appToken = null,
503
- defaultToAddress = null,
552
+ defaultTargetAgentId = null,
504
553
  } = {}) {
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';
554
+ const identityLine = appToken
555
+ ? '- relay binding: resolved from appToken at runtime'
556
+ : '- relay binding: assigned during runtime bootstrap';
511
557
 
512
558
  return `# Claworld Memory
513
559
 
514
560
  - workspace owner: \`${agentId}\`
515
561
  - claworld account: \`${accountId}\`
562
+ ${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : ''}
516
563
  ${identityLine}
564
+ ${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : ''}
517
565
 
518
566
  Use this file for durable Claworld-specific notes only.
519
567
 
@@ -527,10 +575,6 @@ export function resolveDefaultManagedWorkspace(agentId = DEFAULT_CLAWORLD_AGENT_
527
575
  return `~/.openclaw/workspace-${agentId}`;
528
576
  }
529
577
 
530
- export function resolveDefaultManagedRegistrationAgentCode(accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
531
- return null;
532
- }
533
-
534
578
  export function resolveDefaultManagedDisplayName(accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
535
579
  return `${titleCase(accountId)} Channel Agent`;
536
580
  }
@@ -551,10 +595,13 @@ export function resolveClaworldManagedRuntimeOptions({
551
595
  accountId = null,
552
596
  input = {},
553
597
  overrides = {},
598
+ installerState = null,
554
599
  } = {}) {
555
600
  const resolvedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
556
601
  const attachToExistingAgent = overrides.attachToExistingAgent !== false;
557
- const inferredAgentId = inferExistingAgentId(cfg, resolvedAccountId);
602
+ const existingBackup = findClaworldManagedRuntimeBackup(installerState, resolvedAccountId);
603
+ const inferredAgentId = inferExistingAgentId(cfg, resolvedAccountId)
604
+ || normalizeText(existingBackup.agentId, null);
558
605
  const agentId = normalizeText(overrides.agentId, inferredAgentId);
559
606
  const existingAgent = findAgentEntry(cfg, agentId);
560
607
  const existingAccount = findManagedAccountEntry(cfg, resolvedAccountId);
@@ -570,23 +617,23 @@ export function resolveClaworldManagedRuntimeOptions({
570
617
  const workspace = normalizeText(
571
618
  explicitWorkspace,
572
619
  replaceManagedRuntime
573
- ? normalizeText(existingAgent?.workspace, defaultWorkspace)
574
- : normalizeText(existingAgent?.workspace, defaultWorkspace),
620
+ ? normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace))
621
+ : normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace)),
575
622
  );
576
623
  const serverUrl = normalizeText(
577
624
  overrides.serverUrl,
578
- normalizeText(input.httpUrl, normalizeText(input.url, DEFAULT_CLAWORLD_SERVER_URL)),
625
+ normalizeText(input.httpUrl, normalizeText(input.url, normalizeText(existingBackup.serverUrl, DEFAULT_CLAWORLD_SERVER_URL))),
579
626
  );
580
- const apiKey = normalizeText(overrides.apiKey, DEFAULT_CLAWORLD_API_KEY);
627
+ const apiKey = normalizeText(overrides.apiKey, normalizeText(existingBackup.apiKey, DEFAULT_CLAWORLD_API_KEY));
581
628
  const explicitAppToken = normalizeText(
582
629
  overrides.appToken,
583
630
  normalizeText(input.appToken, null),
584
631
  );
585
- const explicitRegistrationAgentCode = normalizeRegistrationAgentCode(
586
- overrides.registrationAgentCode,
587
- normalizeRegistrationAgentCode(input.code, null),
632
+ const explicitRegistrationDisplayName = normalizeRegistrationDisplayName(
633
+ overrides.registrationDisplayName,
634
+ normalizeRegistrationDisplayName(input.name, null),
588
635
  );
589
- const appToken = explicitRegistrationAgentCode && !explicitAppToken
636
+ const appToken = explicitRegistrationDisplayName && !explicitAppToken
590
637
  ? null
591
638
  : normalizeText(
592
639
  explicitAppToken,
@@ -594,35 +641,39 @@ export function resolveClaworldManagedRuntimeOptions({
594
641
  existingAccount.appToken,
595
642
  normalizeText(
596
643
  existingAccount?.relay?.appToken,
597
- normalizeText(existingAccount?.relay?.credentialToken, null),
644
+ normalizeText(existingAccount?.relay?.credentialToken, normalizeText(existingBackup.appToken, null)),
598
645
  ),
599
646
  ),
600
647
  );
601
648
  const displayName = normalizeText(
602
649
  overrides.displayName,
603
- normalizeText(input.name, resolveDefaultManagedDisplayName(resolvedAccountId)),
650
+ normalizeText(input.name, normalizeText(existingBackup.displayName, resolveDefaultManagedDisplayName(resolvedAccountId))),
604
651
  );
605
- const name = normalizeText(overrides.name, displayName);
606
- const existingRegistrationAgentCode = normalizeRegistrationAgentCode(
607
- existingAccount?.registration?.agentCode,
608
- normalizeRegistrationAgentCode(existingAccount?.localAgent?.agentCode, null),
652
+ const name = normalizeText(overrides.name, normalizeText(existingBackup.name, displayName));
653
+ const existingRegistrationDisplayName = normalizeRegistrationDisplayName(
654
+ existingAccount?.registration?.displayName,
655
+ normalizeRegistrationDisplayName(
656
+ existingAccount?.localAgent?.displayName,
657
+ normalizeRegistrationDisplayName(existingBackup.registrationDisplayName, null),
658
+ ),
609
659
  );
610
- const registrationAgentCode = appToken && !explicitRegistrationAgentCode
660
+ const registrationDisplayName = appToken && !explicitRegistrationDisplayName
611
661
  ? null
612
- : normalizeRegistrationAgentCode(
613
- explicitRegistrationAgentCode,
614
- normalizeRegistrationAgentCode(
615
- normalizeRegistrationAgentCode(
616
- resolveDefaultManagedRegistrationAgentCode(resolvedAccountId),
617
- existingRegistrationAgentCode,
618
- ),
662
+ : normalizeRegistrationDisplayName(
663
+ explicitRegistrationDisplayName,
664
+ normalizeRegistrationDisplayName(
665
+ existingRegistrationDisplayName,
666
+ displayName,
619
667
  ),
620
668
  );
621
669
  const approvalMode = normalizeChatRequestApprovalMode(
622
670
  normalizeText(overrides.approvalMode, null),
623
671
  typeof overrides.autoAccept === 'boolean'
624
672
  ? (overrides.autoAccept ? 'open' : DEFAULT_CLAWORLD_APPROVAL_MODE)
625
- : resolveStoredApprovalMode(existingAccount),
673
+ : normalizeChatRequestApprovalMode(
674
+ normalizeText(existingBackup.approvalMode, null),
675
+ resolveStoredApprovalMode(existingAccount),
676
+ ),
626
677
  );
627
678
 
628
679
  return {
@@ -638,14 +689,14 @@ export function resolveClaworldManagedRuntimeOptions({
638
689
  serverUrl,
639
690
  apiKey,
640
691
  appToken,
641
- registrationAgentCode,
692
+ registrationDisplayName,
642
693
  displayName,
643
694
  name,
644
- defaultToAddress: normalizeText(overrides.defaultToAddress, null),
695
+ defaultTargetAgentId: normalizeText(overrides.defaultTargetAgentId, null),
645
696
  approvalMode,
646
697
  sessionDmScope: normalizeText(
647
698
  overrides.sessionDmScope,
648
- DEFAULT_CLAWORLD_DM_SCOPE,
699
+ normalizeText(existingBackup.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE),
649
700
  ),
650
701
  replaceManagedRuntime,
651
702
  preserveDefaultAccount: overrides.preserveDefaultAccount === true,
@@ -665,8 +716,8 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
665
716
  const sessionDmScope = normalizeText(options.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE);
666
717
  const manageAgentEntry = options.manageAgentEntry === true;
667
718
 
668
- if (!options.appToken && !normalizeText(options.registrationAgentCode, null)) {
669
- throw new Error('claworld registration agentCode is required when appToken is absent');
719
+ if (!options.appToken && !normalizeText(options.registrationDisplayName, null)) {
720
+ throw new Error('claworld registration displayName is required when appToken is absent');
670
721
  }
671
722
 
672
723
  const removedManagedToolNames = new Set([
@@ -829,10 +880,164 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
829
880
  return {
830
881
  config,
831
882
  summary,
832
- canonicalAgentCode: canonicalRelayAgentCode(
833
- options.registrationAgentCode,
834
- options.defaultToAddress,
835
- ),
883
+ bootstrapDisplayName: normalizeText(options.registrationDisplayName, null),
884
+ };
885
+ }
886
+
887
+ export function stripClaworldManagedRuntimeConfig(inputConfig = {}, {
888
+ accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
889
+ agentId = null,
890
+ preserveBackup = true,
891
+ } = {}) {
892
+ const config = JSON.parse(JSON.stringify(ensureObject(inputConfig)));
893
+ const summary = [];
894
+ const resolvedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
895
+ const resolvedAgentId = normalizeText(agentId, inferExistingAgentId(config, resolvedAccountId));
896
+ const existingAgent = findAgentEntry(config, resolvedAgentId);
897
+ const existingAccount = findManagedAccountEntry(config, resolvedAccountId);
898
+ const existingToolProfile = resolveStoredClaworldToolProfile(existingAccount) || inferClaworldToolProfile(config);
899
+ const backup = preserveBackup
900
+ ? {
901
+ version: CLAWORLD_MANAGED_RUNTIME_BACKUP_VERSION,
902
+ accountId: resolvedAccountId,
903
+ agentId: resolvedAgentId,
904
+ workspace: normalizeText(existingAgent?.workspace, null),
905
+ serverUrl: normalizeText(existingAccount.serverUrl, null),
906
+ apiKey: normalizeText(existingAccount.apiKey, null),
907
+ appToken: normalizeText(
908
+ existingAccount.appToken,
909
+ normalizeText(existingAccount?.relay?.appToken, normalizeText(existingAccount?.relay?.credentialToken, null)),
910
+ ),
911
+ displayName: normalizeText(existingAccount.name, normalizeText(existingAgent?.name, null)),
912
+ name: normalizeText(existingAccount.name, null),
913
+ registrationDisplayName: normalizeRegistrationDisplayName(existingAccount?.registration?.displayName, null),
914
+ approvalMode: normalizeChatRequestApprovalMode(existingAccount?.approval?.mode, DEFAULT_CLAWORLD_APPROVAL_MODE),
915
+ sessionDmScope: normalizeText(config?.session?.dmScope, DEFAULT_CLAWORLD_DM_SCOPE),
916
+ toolProfile: existingToolProfile,
917
+ preservedAt: new Date().toISOString(),
918
+ }
919
+ : null;
920
+ if (backup) {
921
+ summary.push(`prepared managed claworld runtime backup for ${resolvedAccountId}`);
922
+ }
923
+
924
+ if (resolvedAgentId) {
925
+ const agentList = Array.isArray(config?.agents?.list) ? [...config.agents.list] : [];
926
+ const agentIndex = findAgentIndex(agentList, resolvedAgentId);
927
+ if (agentIndex >= 0) {
928
+ const nextAgent = { ...ensureObject(agentList[agentIndex]) };
929
+ const nextTools = removeManagedPluginToolExposure(nextAgent.tools);
930
+ if (nextTools) nextAgent.tools = nextTools;
931
+ else delete nextAgent.tools;
932
+ agentList[agentIndex] = nextAgent;
933
+ config.agents = ensureObject(config.agents);
934
+ config.agents.list = agentList;
935
+ summary.push(`removed managed claworld tool exposure from agent ${resolvedAgentId}`);
936
+ }
937
+ }
938
+
939
+ const claworldRoot = ensureObject(config?.channels?.claworld);
940
+ const accounts = ensureObject(claworldRoot.accounts);
941
+ if (Object.prototype.hasOwnProperty.call(accounts, resolvedAccountId)) {
942
+ delete accounts[resolvedAccountId];
943
+ summary.push(`removed channels.claworld.accounts.${resolvedAccountId}`);
944
+ }
945
+ const nextClaworldRoot = { ...claworldRoot };
946
+ if (Object.keys(accounts).length > 0) {
947
+ nextClaworldRoot.accounts = accounts;
948
+ const currentDefaultAccount = normalizeText(nextClaworldRoot.defaultAccount, null);
949
+ if (currentDefaultAccount === resolvedAccountId) {
950
+ nextClaworldRoot.defaultAccount = Object.keys(accounts)[0];
951
+ summary.push(`repointed channels.claworld.defaultAccount to ${nextClaworldRoot.defaultAccount}`);
952
+ }
953
+ } else {
954
+ delete nextClaworldRoot.accounts;
955
+ delete nextClaworldRoot.defaultAccount;
956
+ }
957
+ if (Object.keys(nextClaworldRoot).length > 0) {
958
+ config.channels = ensureObject(config.channels);
959
+ config.channels.claworld = nextClaworldRoot;
960
+ } else if (config.channels && typeof config.channels === 'object' && !Array.isArray(config.channels)) {
961
+ delete config.channels.claworld;
962
+ if (Object.keys(config.channels).length === 0) {
963
+ delete config.channels;
964
+ }
965
+ summary.push('removed channels.claworld root');
966
+ }
967
+
968
+ if (Array.isArray(config.bindings)) {
969
+ const nextBindings = config.bindings.filter((binding) => {
970
+ const candidate = ensureObject(binding);
971
+ const match = ensureObject(candidate.match);
972
+ const bindingChannel = normalizeText(match.channel, null);
973
+ const bindingAccountId = normalizeText(match.accountId, null);
974
+ const bindingAgentId = normalizeText(candidate.agentId, null);
975
+ if (bindingChannel !== 'claworld') return true;
976
+ if (bindingAccountId === resolvedAccountId) return false;
977
+ if (!bindingAccountId && resolvedAgentId && bindingAgentId === resolvedAgentId) return false;
978
+ return true;
979
+ });
980
+ if (nextBindings.length !== config.bindings.length) {
981
+ config.bindings = nextBindings;
982
+ summary.push(`removed claworld bindings for ${resolvedAccountId}`);
983
+ }
984
+ if (config.bindings.length === 0) {
985
+ delete config.bindings;
986
+ }
987
+ }
988
+
989
+ config.plugins = ensureObject(config.plugins);
990
+ const nextPluginAllow = asStringArray(config.plugins.allow).filter((pluginId) => pluginId !== 'claworld');
991
+ if (nextPluginAllow.length > 0) config.plugins.allow = uniqueStrings(nextPluginAllow);
992
+ else delete config.plugins.allow;
993
+
994
+ const nextPluginEntries = ensureObject(config.plugins.entries);
995
+ if (Object.prototype.hasOwnProperty.call(nextPluginEntries, 'claworld')) {
996
+ delete nextPluginEntries.claworld;
997
+ summary.push('removed plugins.entries.claworld');
998
+ }
999
+ if (Object.keys(nextPluginEntries).length > 0) config.plugins.entries = nextPluginEntries;
1000
+ else delete config.plugins.entries;
1001
+
1002
+ const nextPluginInstalls = ensureObject(config.plugins.installs);
1003
+ const claworldInstallRecord = ensureObject(nextPluginInstalls.claworld);
1004
+ if (Object.prototype.hasOwnProperty.call(nextPluginInstalls, 'claworld')) {
1005
+ delete nextPluginInstalls.claworld;
1006
+ summary.push('removed plugins.installs.claworld');
1007
+ }
1008
+ if (Object.keys(nextPluginInstalls).length > 0) config.plugins.installs = nextPluginInstalls;
1009
+ else delete config.plugins.installs;
1010
+
1011
+ const nextPluginLoad = ensureObject(config.plugins.load);
1012
+ const sourcePath = normalizeText(claworldInstallRecord.sourcePath, null);
1013
+ const filteredLoadPaths = asStringArray(nextPluginLoad.paths).filter((entry) => entry !== sourcePath);
1014
+ if (sourcePath && filteredLoadPaths.length !== asStringArray(nextPluginLoad.paths).length) {
1015
+ if (filteredLoadPaths.length > 0) {
1016
+ nextPluginLoad.paths = uniqueStrings(filteredLoadPaths);
1017
+ } else {
1018
+ delete nextPluginLoad.paths;
1019
+ }
1020
+ summary.push('removed plugins.load.paths claworld sourcePath');
1021
+ }
1022
+ if (Object.keys(nextPluginLoad).length > 0) config.plugins.load = nextPluginLoad;
1023
+ else delete config.plugins.load;
1024
+
1025
+ const nextPluginSlots = ensureObject(config.plugins.slots);
1026
+ if (normalizeText(nextPluginSlots.memory, null) === 'claworld') {
1027
+ delete nextPluginSlots.memory;
1028
+ summary.push('removed plugins.slots.memory claworld');
1029
+ }
1030
+ if (Object.keys(nextPluginSlots).length > 0) config.plugins.slots = nextPluginSlots;
1031
+ else delete config.plugins.slots;
1032
+
1033
+ if (Object.keys(config.plugins).length === 0) {
1034
+ delete config.plugins;
1035
+ }
1036
+
1037
+ return {
1038
+ config,
1039
+ summary,
1040
+ backup,
836
1041
  };
837
1042
  }
838
1043