@xfxstudio/claworld 0.1.5 → 0.2.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 (54) hide show
  1. package/README.md +12 -29
  2. package/openclaw.plugin.json +5 -29
  3. package/package.json +4 -12
  4. package/skills/claworld-help/SKILL.md +50 -182
  5. package/skills/claworld-join-and-chat/SKILL.md +78 -288
  6. package/skills/claworld-manage-worlds/SKILL.md +71 -288
  7. package/src/lib/chat-request.js +347 -0
  8. package/src/lib/{accepted-chat-kickoff.js → relay/kickoff-text.js} +67 -26
  9. package/src/openclaw/index.js +0 -5
  10. package/src/openclaw/installer/cli.js +18 -9
  11. package/src/openclaw/installer/core.js +12 -6
  12. package/src/openclaw/installer/doctor.js +69 -31
  13. package/src/openclaw/installer/workspace-contract.js +33 -9
  14. package/src/openclaw/plugin/claworld-channel-plugin.js +118 -623
  15. package/src/openclaw/plugin/config-schema.js +3 -15
  16. package/src/openclaw/plugin/managed-config.js +98 -47
  17. package/src/openclaw/plugin/onboarding.js +7 -3
  18. package/src/openclaw/plugin/register.js +37 -336
  19. package/src/openclaw/plugin/relay-client.js +111 -101
  20. package/src/openclaw/protocol/relay-event-protocol.js +34 -22
  21. package/src/openclaw/runtime/canonical-result-builder.js +15 -5
  22. package/src/openclaw/runtime/demo-session-bootstrap.js +0 -4
  23. package/src/openclaw/runtime/feedback-helper.js +3 -2
  24. package/src/openclaw/runtime/inbound-session-router.js +28 -20
  25. package/src/openclaw/runtime/outbound-session-bridge.js +21 -9
  26. package/src/openclaw/runtime/product-shell-helper.js +43 -636
  27. package/src/openclaw/runtime/runtime-path.js +2 -2
  28. package/src/openclaw/runtime/system-message-orchestrator.js +1 -1
  29. package/src/openclaw/runtime/tool-contracts.js +33 -258
  30. package/src/openclaw/runtime/world-moderation-helper.js +11 -65
  31. package/src/product-shell/catalog/default-world-catalog.js +9 -27
  32. package/src/product-shell/contracts/candidate-feed.js +26 -1
  33. package/src/product-shell/contracts/chat-request-approval-policy.js +4 -4
  34. package/src/product-shell/contracts/world-manifest.js +115 -160
  35. package/src/product-shell/contracts/world-orchestration.js +47 -322
  36. package/src/product-shell/feedback/feedback-routes.js +4 -3
  37. package/src/product-shell/feedback/feedback-service.js +11 -8
  38. package/src/product-shell/index.js +5 -6
  39. package/src/product-shell/membership/membership-service.js +125 -147
  40. package/src/product-shell/onboarding/onboarding-service.js +2 -2
  41. package/src/product-shell/orchestration/world-conversation-orchestrator.js +30 -0
  42. package/src/product-shell/orchestration/world-conversation-text.js +231 -0
  43. package/src/product-shell/results/result-service.js +9 -3
  44. package/src/product-shell/search/search-service.js +28 -1
  45. package/src/product-shell/social/chat-request-routes.js +0 -1
  46. package/src/product-shell/social/chat-request-service.js +1 -102
  47. package/src/product-shell/worlds/world-admin-service.js +85 -276
  48. package/src/product-shell/worlds/world-authorization.js +3 -5
  49. package/src/product-shell/worlds/world-routes.js +8 -38
  50. package/src/product-shell/worlds/world-service.js +3 -3
  51. package/src/product-shell/worlds/world-text.js +77 -0
  52. package/src/lib/runtime-guidance.js +0 -457
  53. package/src/openclaw/runtime/world-session-startup.js +0 -1
  54. package/src/product-shell/orchestration/session-orchestrator.js +0 -38
@@ -119,7 +119,7 @@ const SINGLE_ACCOUNT_PROPERTIES = {
119
119
  sessionTarget: {
120
120
  type: 'string',
121
121
  enum: ['subagent', 'mainagent'],
122
- default: 'subagent',
122
+ default: 'mainagent',
123
123
  },
124
124
  fallbackTarget: {
125
125
  type: 'string',
@@ -169,18 +169,6 @@ const SINGLE_ACCOUNT_PROPERTIES = {
169
169
  description: 'Legacy alias. `true` maps to `approval.mode = "open"` and `false` maps to `approval.mode = "manual_review"`.',
170
170
  default: false,
171
171
  },
172
- maxTurns: {
173
- type: 'integer',
174
- minimum: 1,
175
- description: 'Legacy ignored field. Approval policy no longer carries session turn controls.',
176
- default: 4,
177
- },
178
- turnTimeoutMs: {
179
- type: 'integer',
180
- minimum: 1000,
181
- description: 'Legacy ignored field. Approval policy no longer carries session timeout controls.',
182
- default: 30000,
183
- },
184
172
  },
185
173
  },
186
174
  testing: {
@@ -230,7 +218,7 @@ export const claworldChannelConfigSchema = {
230
218
  description:
231
219
  '最小 OpenClaw claworld channel 配置;支持单账号或 accounts.<id> 多账号模式。canonical flow uses appToken + registration, while relay/localAgent fields remain compatibility aliases.',
232
220
  routingShape: {
233
- sessionTarget: 'subagent',
221
+ sessionTarget: 'mainagent',
234
222
  fallbackTarget: 'mainagent',
235
223
  allowHumanInterrupt: true,
236
224
  },
@@ -344,7 +332,7 @@ export function validateClaworldChannelConfig(config = {}, accountId = null) {
344
332
  errors.push({ code: 'invalid_heartbeat_seconds', value: candidate.heartbeatSeconds });
345
333
  }
346
334
 
347
- const sessionTarget = candidate.routing?.sessionTarget || 'subagent';
335
+ const sessionTarget = candidate.routing?.sessionTarget || 'mainagent';
348
336
  const fallbackTarget = candidate.routing?.fallbackTarget || 'mainagent';
349
337
  if (!['subagent', 'mainagent'].includes(sessionTarget)) {
350
338
  errors.push({ code: 'invalid_session_target', value: sessionTarget });
@@ -13,13 +13,15 @@ import {
13
13
  normalizeChatRequestApprovalMode,
14
14
  } from '../../product-shell/contracts/chat-request-approval-policy.js';
15
15
 
16
- export const DEFAULT_CLAWORLD_SERVER_URL = 'https://claworld.zy-sj.com';
16
+ export const DEFAULT_CLAWORLD_SERVER_URL = 'https://clawold.love';
17
17
  export const DEFAULT_CLAWORLD_API_KEY = 'local-test';
18
- export const DEFAULT_CLAWORLD_AGENT_ID = 'claworld';
18
+ export const DEFAULT_CLAWORLD_AGENT_ID = 'main';
19
19
  export const DEFAULT_CLAWORLD_ACCOUNT_ID = 'claworld';
20
20
  export const DEFAULT_CLAWORLD_TOOL_PROFILE = 'default';
21
21
  export const DEFAULT_CLAWORLD_DM_SCOPE = 'per-channel-peer';
22
22
  export const DEFAULT_CLAWORLD_APPROVAL_MODE = DEFAULT_CHAT_REQUEST_APPROVAL_POLICY_MODE;
23
+ export const DEFAULT_CLAWORLD_SESSION_TARGET = 'mainagent';
24
+ export const DEFAULT_CLAWORLD_FALLBACK_TARGET = 'mainagent';
23
25
 
24
26
  export const TOOL_PROFILES = CLAWORLD_TOOL_PROFILES;
25
27
 
@@ -107,6 +109,25 @@ function findManagedAccountEntry(config = {}, accountId) {
107
109
  return {};
108
110
  }
109
111
 
112
+ function inferExistingAgentId(config = {}, accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
113
+ const bindings = Array.isArray(config?.bindings) ? config.bindings : [];
114
+ const bindingMatch = bindings
115
+ .map((item) => ensureObject(item))
116
+ .find((item) => ensureObject(item.match).channel === 'claworld'
117
+ && normalizeText(ensureObject(item.match).accountId, null) === accountId
118
+ && normalizeText(item.agentId, null));
119
+ if (bindingMatch?.agentId) return normalizeText(bindingMatch.agentId, null);
120
+
121
+ const agents = Array.isArray(config?.agents?.list) ? config.agents.list : [];
122
+ if (agents.some((item) => ensureObject(item).id === DEFAULT_CLAWORLD_AGENT_ID)) {
123
+ return DEFAULT_CLAWORLD_AGENT_ID;
124
+ }
125
+ if (agents.length === 1) {
126
+ return normalizeText(ensureObject(agents[0]).id, DEFAULT_CLAWORLD_AGENT_ID);
127
+ }
128
+ return DEFAULT_CLAWORLD_AGENT_ID;
129
+ }
130
+
110
131
  const MANAGED_LEGACY_BUNDLED_SKILL_NAMES = Object.freeze([
111
132
  'claworld-join-and-chat',
112
133
  'claworld-manage-worlds',
@@ -126,6 +147,15 @@ function buildManagedAgentEntry(options = {}) {
126
147
  };
127
148
  }
128
149
 
150
+ function buildManagedRoutingEntry(options = {}, existingRouting = {}) {
151
+ return {
152
+ ...ensureObject(existingRouting),
153
+ sessionTarget: normalizeText(options.sessionTarget, DEFAULT_CLAWORLD_SESSION_TARGET),
154
+ fallbackTarget: normalizeText(options.fallbackTarget, DEFAULT_CLAWORLD_FALLBACK_TARGET),
155
+ allowHumanInterrupt: existingRouting?.allowHumanInterrupt !== false,
156
+ };
157
+ }
158
+
129
159
  function buildManagedAccountEntry(options = {}) {
130
160
  const base = {
131
161
  enabled: true,
@@ -133,6 +163,7 @@ function buildManagedAccountEntry(options = {}) {
133
163
  apiKey: options.apiKey,
134
164
  accountId: options.accountId,
135
165
  name: normalizeText(options.name, normalizeText(options.displayName, null)),
166
+ routing: buildManagedRoutingEntry(options),
136
167
  approval: {
137
168
  mode: normalizeChatRequestApprovalMode(options.approvalMode, DEFAULT_CLAWORLD_APPROVAL_MODE),
138
169
  },
@@ -171,6 +202,7 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
171
202
  apiKey: options.apiKey,
172
203
  accountId: options.accountId,
173
204
  name: normalizeText(options.name, normalizeText(existingAccount.name, normalizeText(options.displayName, null))),
205
+ routing: buildManagedRoutingEntry(options, existingAccount.routing),
174
206
  approval: {
175
207
  ...existingApproval,
176
208
  mode: normalizeChatRequestApprovalMode(options.approvalMode, DEFAULT_CLAWORLD_APPROVAL_MODE),
@@ -352,7 +384,7 @@ ${identityLine}
352
384
 
353
385
  Use this file for durable Claworld-specific notes only.
354
386
 
355
- - keep world rules, pairing context, and recurring counterpart preferences here when they help future Claworld sessions
387
+ - keep world rules, pairing context, and recurring counterpart preferences here when they help future Claworld conversations
356
388
  - do not duplicate a full standalone OpenClaw bootstrap/persona here
357
389
  - prefer channel/world-specific memory over general-purpose assistant memory
358
390
  `;
@@ -388,15 +420,24 @@ export function resolveClaworldManagedRuntimeOptions({
388
420
  overrides = {},
389
421
  } = {}) {
390
422
  const resolvedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
391
- const agentId = normalizeText(overrides.agentId, resolvedAccountId);
423
+ const attachToExistingAgent = overrides.attachToExistingAgent !== false;
424
+ const inferredAgentId = inferExistingAgentId(cfg, resolvedAccountId);
425
+ const agentId = normalizeText(overrides.agentId, inferredAgentId);
392
426
  const existingAgent = findAgentEntry(cfg, agentId);
393
427
  const existingAccount = findManagedAccountEntry(cfg, resolvedAccountId);
394
428
  const replaceManagedRuntime = overrides.replaceManagedRuntime !== false;
395
- const defaultWorkspace = resolveDefaultManagedWorkspace(agentId);
429
+ const explicitWorkspace = normalizeText(overrides.workspace, null);
430
+ const manageAgentEntry = overrides.manageAgentEntry === true
431
+ || overrides.agentDirExplicit === true
432
+ || attachToExistingAgent !== true;
433
+ const manageWorkspace = overrides.manageWorkspace === true
434
+ || Boolean(explicitWorkspace)
435
+ || attachToExistingAgent !== true;
436
+ const defaultWorkspace = manageWorkspace ? resolveDefaultManagedWorkspace(agentId) : null;
396
437
  const workspace = normalizeText(
397
- overrides.workspace,
438
+ explicitWorkspace,
398
439
  replaceManagedRuntime
399
- ? defaultWorkspace
440
+ ? normalizeText(existingAgent?.workspace, defaultWorkspace)
400
441
  : normalizeText(existingAgent?.workspace, defaultWorkspace),
401
442
  );
402
443
  const serverUrl = normalizeText(
@@ -453,9 +494,12 @@ export function resolveClaworldManagedRuntimeOptions({
453
494
 
454
495
  return {
455
496
  repoRoot: normalizeText(overrides.repoRoot, null),
497
+ attachToExistingAgent,
456
498
  agentId,
457
499
  accountId: resolvedAccountId,
458
500
  workspace,
501
+ manageAgentEntry,
502
+ manageWorkspace,
459
503
  agentDir: normalizeText(overrides.agentDir, null),
460
504
  agentDirExplicit: overrides.agentDirExplicit === true,
461
505
  serverUrl,
@@ -475,6 +519,8 @@ export function resolveClaworldManagedRuntimeOptions({
475
519
  forceDefaultAccount: overrides.forceDefaultAccount === true,
476
520
  pluginInstallMode: normalizeText(overrides.pluginInstallMode, 'skip'),
477
521
  installPlugin: overrides.installPlugin !== false,
522
+ sessionTarget: normalizeText(overrides.sessionTarget, DEFAULT_CLAWORLD_SESSION_TARGET),
523
+ fallbackTarget: normalizeText(overrides.fallbackTarget, DEFAULT_CLAWORLD_FALLBACK_TARGET),
478
524
  };
479
525
  }
480
526
 
@@ -484,6 +530,7 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
484
530
  const replaceManagedRuntime = options.replaceManagedRuntime !== false;
485
531
  const preserveDefaultAccount = options.preserveDefaultAccount === true;
486
532
  const sessionDmScope = normalizeText(options.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE);
533
+ const manageAgentEntry = options.manageAgentEntry === true;
487
534
 
488
535
  if (!options.appToken && !normalizeText(options.registrationAgentCode, null)) {
489
536
  throw new Error('claworld registration agentCode is required when appToken is absent');
@@ -520,49 +567,53 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
520
567
 
521
568
  config.agents = ensureObject(config.agents);
522
569
  const existingAgentList = Array.isArray(config.agents.list) ? [...config.agents.list] : [];
523
- const managedAgentEntry = buildManagedAgentEntry(options);
524
- if (replaceManagedRuntime) {
525
- const removedAgentEntries = existingAgentList.filter((item) => ensureObject(item).id === options.agentId).length;
526
- config.agents.list = [
527
- ...existingAgentList.filter((item) => ensureObject(item).id !== options.agentId),
528
- managedAgentEntry,
529
- ];
530
- summary.push(
531
- removedAgentEntries > 0
532
- ? `replaced managed agent entry ${options.agentId}`
533
- : `added workspace-scoped agent entry ${options.agentId}`,
534
- );
535
- } else {
536
- const agentIndex = findAgentIndex(existingAgentList, options.agentId);
537
- if (agentIndex >= 0) {
538
- const existingAgent = ensureObject(existingAgentList[agentIndex]);
539
- const existingAgentDir = normalizeText(existingAgent.agentDir, null);
540
- const keepExistingAgentDir = Boolean(
541
- existingAgentDir
542
- && (
543
- options.agentDirExplicit
544
- || existingAgentDir !== normalizeText(options.agentDir, null)
545
- ),
570
+ if (manageAgentEntry) {
571
+ const managedAgentEntry = buildManagedAgentEntry(options);
572
+ if (replaceManagedRuntime) {
573
+ const removedAgentEntries = existingAgentList.filter((item) => ensureObject(item).id === options.agentId).length;
574
+ config.agents.list = [
575
+ ...existingAgentList.filter((item) => ensureObject(item).id !== options.agentId),
576
+ managedAgentEntry,
577
+ ];
578
+ summary.push(
579
+ removedAgentEntries > 0
580
+ ? `replaced managed agent entry ${options.agentId}`
581
+ : `added workspace-scoped agent entry ${options.agentId}`,
546
582
  );
547
- const nextAgentEntry = {
548
- ...existingAgent,
549
- id: options.agentId,
550
- workspace: normalizeText(existingAgent.workspace, options.workspace),
551
- ...(keepExistingAgentDir ? { agentDir: existingAgentDir } : {}),
552
- };
553
- if (!keepExistingAgentDir) {
554
- delete nextAgentEntry.agentDir;
555
- }
556
- if (hasOnlyManagedBundledSkills(existingAgent.skills)) {
557
- delete nextAgentEntry.skills;
558
- }
559
- existingAgentList[agentIndex] = nextAgentEntry;
560
- summary.push(`updated existing agent entry ${options.agentId}`);
561
583
  } else {
562
- existingAgentList.push(managedAgentEntry);
563
- summary.push(`added workspace-scoped agent entry ${options.agentId}`);
584
+ const agentIndex = findAgentIndex(existingAgentList, options.agentId);
585
+ if (agentIndex >= 0) {
586
+ const existingAgent = ensureObject(existingAgentList[agentIndex]);
587
+ const existingAgentDir = normalizeText(existingAgent.agentDir, null);
588
+ const keepExistingAgentDir = Boolean(
589
+ existingAgentDir
590
+ && (
591
+ options.agentDirExplicit
592
+ || existingAgentDir !== normalizeText(options.agentDir, null)
593
+ ),
594
+ );
595
+ const nextAgentEntry = {
596
+ ...existingAgent,
597
+ id: options.agentId,
598
+ workspace: normalizeText(existingAgent.workspace, options.workspace),
599
+ ...(keepExistingAgentDir ? { agentDir: existingAgentDir } : {}),
600
+ };
601
+ if (!keepExistingAgentDir) {
602
+ delete nextAgentEntry.agentDir;
603
+ }
604
+ if (hasOnlyManagedBundledSkills(existingAgent.skills)) {
605
+ delete nextAgentEntry.skills;
606
+ }
607
+ existingAgentList[agentIndex] = nextAgentEntry;
608
+ summary.push(`updated existing agent entry ${options.agentId}`);
609
+ } else {
610
+ existingAgentList.push(managedAgentEntry);
611
+ summary.push(`added workspace-scoped agent entry ${options.agentId}`);
612
+ }
613
+ config.agents.list = existingAgentList;
564
614
  }
565
- config.agents.list = existingAgentList;
615
+ } else {
616
+ summary.push(`attached claworld account ${options.accountId} to existing local agent ${options.agentId}`);
566
617
  }
567
618
 
568
619
  config.channels = ensureObject(config.channels);
@@ -200,15 +200,19 @@ async function applyManagedOnboardingConfig({
200
200
  } = {}) {
201
201
  const managedOptions = resolveManagedOptionsFromContext({ cfg, accountId, input });
202
202
  const next = applyClaworldManagedRuntimeConfig(cfg, managedOptions);
203
- await ensureManagedWorkspaceSeed(managedOptions);
203
+ if (managedOptions.manageWorkspace) {
204
+ await ensureManagedWorkspaceSeed(managedOptions);
205
+ }
204
206
 
205
207
  const noteLines = [
206
- `Managed local agent/account: ${managedOptions.agentId}`,
208
+ `Bound local agent/account: ${managedOptions.agentId}`,
207
209
  `Remote backend: ${managedOptions.serverUrl}`,
208
210
  managedOptions.registrationAgentCode
209
211
  ? `Bootstrap mode: registration (${managedOptions.registrationAgentCode})`
210
212
  : 'Bootstrap mode: appToken/manual binding',
211
- 'This flow only refreshes plugin-side config and workspace files. It does not start a backend service.',
213
+ managedOptions.manageWorkspace
214
+ ? 'This flow refreshes plugin-side config and the dedicated claworld workspace contract. It does not start a backend service.'
215
+ : 'This flow refreshes plugin-side config and binds claworld onto the existing local agent. It does not start a backend service.',
212
216
  ];
213
217
  await prompter.note(
214
218
  noteLines.join('\n'),