@xfxstudio/claworld 0.1.3 → 0.1.5

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.
@@ -1,9 +1,7 @@
1
1
  import os from 'os';
2
2
  import path from 'path';
3
3
  import {
4
- DEFAULT_CLAWORLD_TOOL_PROFILE,
5
4
  expandUserPath,
6
- normalizeClaworldToolProfile,
7
5
  } from '../plugin/managed-config.js';
8
6
  import {
9
7
  CLAWORLD_DOCTOR_COMMAND,
@@ -40,7 +38,6 @@ Install options:
40
38
  --agent-id <id> Managed local OpenClaw agent id (default: claworld)
41
39
  --workspace <path> Managed agent workspace path
42
40
  --display-name <name> Managed display name override
43
- --tool-profile <name> minimal | default | full (default: ${DEFAULT_CLAWORLD_TOOL_PROFILE})
44
41
  --repo-root <path> Local repo root when using --plugin-install-mode link|copy
45
42
  --plugin-install-mode <m> npm | link | copy | skip (default: npm)
46
43
  --plugin-source <value> npm package or local path (default: ${CLAWORLD_INSTALLER_PACKAGE_NAME})
@@ -54,7 +51,6 @@ Update options:
54
51
  --agent-id <id> Managed local OpenClaw agent id (default: claworld)
55
52
  --workspace <path> Managed agent workspace path
56
53
  --display-name <name> Managed display name override
57
- --tool-profile <name> minimal | default | full (default: ${DEFAULT_CLAWORLD_TOOL_PROFILE})
58
54
  Doctor options:
59
55
  --config <path> OpenClaw config path (default: ${DEFAULT_OPENCLAW_CONFIG_PATH})
60
56
  --state-dir <path> Optional OPENCLAW_STATE_DIR for OpenClaw commands
@@ -95,7 +91,6 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
95
91
  agentId: 'claworld',
96
92
  workspace: null,
97
93
  displayName: null,
98
- toolProfile: DEFAULT_CLAWORLD_TOOL_PROFILE,
99
94
  repoRoot: null,
100
95
  pluginInstallMode: 'npm',
101
96
  pluginInstallSource: CLAWORLD_INSTALLER_PACKAGE_NAME,
@@ -110,7 +105,6 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
110
105
  agentId: 'claworld',
111
106
  workspace: null,
112
107
  displayName: null,
113
- toolProfile: DEFAULT_CLAWORLD_TOOL_PROFILE,
114
108
  },
115
109
  doctor: {
116
110
  openclawBin: env.OPENCLAW_BIN || DEFAULT_OPENCLAW_BIN,
@@ -186,11 +180,6 @@ export function parseInstallerCliArgs(argv = process.argv.slice(2), env = proces
186
180
  options.update.displayName = options.install.displayName;
187
181
  index += 1;
188
182
  break;
189
- case '--tool-profile':
190
- options.install.toolProfile = normalizeClaworldToolProfile(nextValue(remaining, index));
191
- options.update.toolProfile = options.install.toolProfile;
192
- index += 1;
193
- break;
194
183
  case '--repo-root':
195
184
  options.install.repoRoot = path.resolve(expandUserPath(nextValue(remaining, index), homeDir));
196
185
  index += 1;
@@ -12,7 +12,6 @@ import {
12
12
  expandUserPath,
13
13
  normalizeText,
14
14
  resolveClaworldManagedRuntimeOptions,
15
- resolveToolNames,
16
15
  } from '../plugin/managed-config.js';
17
16
  import {
18
17
  defaultClaworldAccountId,
@@ -58,13 +57,7 @@ export function hasManagedBinding(config = {}, { agentId, accountId } = {}) {
58
57
  }
59
58
 
60
59
  export function isManagedToolAllowlistReady(config = {}, options = {}) {
61
- const allow = new Set(
62
- (Array.isArray(config?.tools?.allow) ? config.tools.allow : [])
63
- .map((item) => normalizeText(item, null))
64
- .filter(Boolean),
65
- );
66
- if (allow.has('*')) return true;
67
- return resolveToolNames(options).every((toolName) => allow.has(toolName));
60
+ return true;
68
61
  }
69
62
 
70
63
  export function isRelayBootstrapReady(account = {}) {
@@ -290,7 +290,23 @@ function appendRuntimeOutputPreview(previews, text) {
290
290
  previews.push(preview);
291
291
  }
292
292
 
293
- function buildRelayContinuationText({ finalTexts = [], blockTexts = [] } = {}) {
293
+ function appendPartialContinuationChunk(currentText, chunk) {
294
+ const nextChunk = typeof chunk === 'string' ? chunk : '';
295
+ if (!nextChunk) return currentText;
296
+ const existing = typeof currentText === 'string' ? currentText : '';
297
+ if (!existing) return nextChunk;
298
+ if (nextChunk === existing) return existing;
299
+ if (nextChunk.startsWith(existing)) return nextChunk;
300
+ if (existing.endsWith(nextChunk)) return existing;
301
+ return `${existing}${nextChunk}`;
302
+ }
303
+
304
+ function buildRelayContinuationText({
305
+ finalTexts = [],
306
+ blockTexts = [],
307
+ partialText = '',
308
+ allowPartialFallback = false,
309
+ } = {}) {
294
310
  const sanitizedFinalTexts = finalTexts
295
311
  .map((entry) => sanitizeRelayContinuationText(entry))
296
312
  .filter(Boolean);
@@ -309,6 +325,15 @@ function buildRelayContinuationText({ finalTexts = [], blockTexts = [] } = {}) {
309
325
  source: 'block',
310
326
  };
311
327
  }
328
+ const sanitizedPartialText = allowPartialFallback
329
+ ? sanitizeRelayContinuationText(partialText)
330
+ : '';
331
+ if (sanitizedPartialText) {
332
+ return {
333
+ text: sanitizedPartialText,
334
+ source: 'partial',
335
+ };
336
+ }
312
337
  return {
313
338
  text: '',
314
339
  source: 'none',
@@ -1510,6 +1535,7 @@ function createRelayReplyDispatcher({
1510
1535
  let suppressed = false;
1511
1536
  const finalTexts = [];
1512
1537
  const blockTexts = [];
1538
+ let partialContinuationText = '';
1513
1539
  const runtimeOutputSummary = {
1514
1540
  counts: {
1515
1541
  final: 0,
@@ -1644,7 +1670,13 @@ function createRelayReplyDispatcher({
1644
1670
 
1645
1671
  const markDispatchIdle = async () => {
1646
1672
  if (!replied && !suppressed) {
1647
- const continuation = buildRelayContinuationText({ finalTexts, blockTexts });
1673
+ const continuation = buildRelayContinuationText({
1674
+ finalTexts,
1675
+ blockTexts,
1676
+ partialText: partialContinuationText,
1677
+ allowPartialFallback:
1678
+ runtimeOutputSummary.counts.final > 0 && finalTexts.length === 0 && blockTexts.length === 0,
1679
+ });
1648
1680
  runtimeOutputSummary.relayContinuationSource = continuation.source;
1649
1681
  runtimeOutputSummary.relayContinuationPreview = continuation.text
1650
1682
  ? previewRuntimeOutputText(continuation.text)
@@ -1662,6 +1694,10 @@ function createRelayReplyDispatcher({
1662
1694
  replyOptions: {
1663
1695
  ...dispatchApi.replyOptions,
1664
1696
  onPartialReply: async (payload = {}) => {
1697
+ partialContinuationText = appendPartialContinuationChunk(
1698
+ partialContinuationText,
1699
+ typeof payload?.text === 'string' ? payload.text : '',
1700
+ );
1665
1701
  recordRuntimeTextEvent('partial', payload?.text);
1666
1702
  },
1667
1703
  onReasoningStream: async (payload = {}) => {
@@ -1778,6 +1814,9 @@ async function maybeBridgeDeliveredTurn({
1778
1814
  if (sessionLookupKey && resolvedWorldId && worldCache) {
1779
1815
  worldCache.set(sessionLookupKey, resolvedWorldId);
1780
1816
  }
1817
+ // Gateway reply dispatch stays on the dedicated `claworld` channel surface.
1818
+ // Accept may have been reviewed from another main-agent channel, but live
1819
+ // continuation/generation cannot hop across channels mid-session.
1781
1820
  const route = runtime.channel.routing.resolveAgentRoute({
1782
1821
  cfg: currentCfg,
1783
1822
  channel: 'claworld',
@@ -2343,11 +2382,11 @@ export function createClaworldChannelPlugin({
2343
2382
  meta: {
2344
2383
  id: 'claworld',
2345
2384
  label: 'Claworld',
2346
- selectionLabel: 'Claworld Persona Relay',
2385
+ selectionLabel: 'Claworld Relay Channel',
2347
2386
  detailLabel: 'Claworld A2A Relay Channel',
2348
2387
  docsPath: '/channels/claworld',
2349
2388
  docsLabel: 'claworld',
2350
- blurb: 'Persona/Claworld relay channel backed by persona-backend.',
2389
+ blurb: 'Claworld relay channel backed by the Claworld backend.',
2351
2390
  version: '0.3.0',
2352
2391
  forceAccountBinding: true,
2353
2392
  },
@@ -99,7 +99,7 @@ const SINGLE_ACCOUNT_PROPERTIES = {
99
99
  toolProfile: {
100
100
  type: 'string',
101
101
  enum: ['minimal', 'default', 'world', 'full'],
102
- description: 'Managed Claworld tool visibility profile. Legacy "world" normalizes to "default".',
102
+ description: 'Legacy ignored field retained for backward-compatible config parsing.',
103
103
  },
104
104
  heartbeatSeconds: {
105
105
  type: 'integer',
@@ -2,9 +2,10 @@ import os from 'os';
2
2
  import path from 'path';
3
3
  import {
4
4
  CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
5
- CLAWORLD_OPTIONAL_WORLD_HELPER_TOOL_NAMES,
5
+ CLAWORLD_COMPATIBILITY_TOOL_NAMES,
6
6
  CLAWORLD_PUBLIC_TOOL_NAMES,
7
7
  CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES,
8
+ CLAWORLD_RETIRED_PUBLIC_TOOL_NAMES,
8
9
  CLAWORLD_TOOL_PROFILES,
9
10
  } from '../runtime/tool-inventory.js';
10
11
  import {
@@ -106,12 +107,21 @@ function findManagedAccountEntry(config = {}, accountId) {
106
107
  return {};
107
108
  }
108
109
 
110
+ const MANAGED_LEGACY_BUNDLED_SKILL_NAMES = Object.freeze([
111
+ 'claworld-join-and-chat',
112
+ 'claworld-manage-worlds',
113
+ 'claworld-help',
114
+ ]);
115
+
116
+ function hasOnlyManagedBundledSkills(value) {
117
+ if (!Array.isArray(value) || value.length === 0) return false;
118
+ return value.every((skillName) => MANAGED_LEGACY_BUNDLED_SKILL_NAMES.includes(skillName));
119
+ }
120
+
109
121
  function buildManagedAgentEntry(options = {}) {
110
- const managedSkills = resolveManagedAgentSkills({ toolProfile: options.toolProfile });
111
122
  return {
112
123
  id: options.agentId,
113
124
  workspace: options.workspace,
114
- ...(managedSkills === undefined ? {} : { skills: managedSkills }),
115
125
  ...(options.agentDirExplicit && options.agentDir ? { agentDir: options.agentDir } : {}),
116
126
  };
117
127
  }
@@ -122,7 +132,6 @@ function buildManagedAccountEntry(options = {}) {
122
132
  serverUrl: options.serverUrl,
123
133
  apiKey: options.apiKey,
124
134
  accountId: options.accountId,
125
- toolProfile: options.toolProfile,
126
135
  name: normalizeText(options.name, normalizeText(options.displayName, null)),
127
136
  approval: {
128
137
  mode: normalizeChatRequestApprovalMode(options.approvalMode, DEFAULT_CLAWORLD_APPROVAL_MODE),
@@ -161,7 +170,6 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
161
170
  serverUrl: options.serverUrl,
162
171
  apiKey: options.apiKey,
163
172
  accountId: options.accountId,
164
- toolProfile: options.toolProfile,
165
173
  name: normalizeText(options.name, normalizeText(existingAccount.name, normalizeText(options.displayName, null))),
166
174
  approval: {
167
175
  ...existingApproval,
@@ -178,6 +186,7 @@ function buildMergedAccountEntry(existingAccount = {}, options = {}) {
178
186
  ? { relay: existingRelay }
179
187
  : {}),
180
188
  };
189
+ delete merged.toolProfile;
181
190
 
182
191
  if (options.appToken) {
183
192
  return {
@@ -267,9 +276,15 @@ export function resolveToolNames({ toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE }
267
276
  return [...baseProfile];
268
277
  }
269
278
 
279
+ const MANAGED_BUNDLED_SKILL_NAMES = Object.freeze([
280
+ 'claworld-join-and-chat',
281
+ 'claworld-manage-worlds',
282
+ 'claworld-help',
283
+ ]);
284
+
270
285
  export function resolveManagedAgentSkills({ toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE } = {}) {
271
286
  const normalizedProfile = normalizeClaworldToolProfile(toolProfile);
272
- return normalizedProfile === 'full' ? undefined : [];
287
+ return normalizedProfile === 'full' ? undefined : [...MANAGED_BUNDLED_SKILL_NAMES];
273
288
  }
274
289
 
275
290
  function describeToolAllowEntries(toolNames = []) {
@@ -414,10 +429,6 @@ export function resolveClaworldManagedRuntimeOptions({
414
429
  normalizeText(input.name, resolveDefaultManagedDisplayName(resolvedAccountId)),
415
430
  );
416
431
  const name = normalizeText(overrides.name, displayName);
417
- const explicitToolProfile = normalizeText(
418
- overrides.toolProfile,
419
- normalizeText(input.toolProfile, null),
420
- );
421
432
  const existingRegistrationAgentCode = normalizeRegistrationAgentCode(
422
433
  existingAccount?.registration?.agentCode,
423
434
  normalizeRegistrationAgentCode(existingAccount?.localAgent?.agentCode, null),
@@ -454,11 +465,6 @@ export function resolveClaworldManagedRuntimeOptions({
454
465
  displayName,
455
466
  name,
456
467
  defaultToAddress: normalizeText(overrides.defaultToAddress, null),
457
- toolProfile: resolveManagedToolProfile({
458
- cfg,
459
- existingAccount,
460
- explicitToolProfile,
461
- }),
462
468
  approvalMode,
463
469
  sessionDmScope: normalizeText(
464
470
  overrides.sessionDmScope,
@@ -474,8 +480,6 @@ export function resolveClaworldManagedRuntimeOptions({
474
480
 
475
481
  export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}) {
476
482
  const config = JSON.parse(JSON.stringify(ensureObject(inputConfig)));
477
- const toolProfile = normalizeClaworldToolProfile(options.toolProfile);
478
- const toolNames = resolveToolNames({ toolProfile });
479
483
  const summary = [];
480
484
  const replaceManagedRuntime = options.replaceManagedRuntime !== false;
481
485
  const preserveDefaultAccount = options.preserveDefaultAccount === true;
@@ -485,18 +489,28 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
485
489
  throw new Error('claworld registration agentCode is required when appToken is absent');
486
490
  }
487
491
 
488
- config.tools = ensureObject(config.tools);
489
- const managedOptionalHelperTools = new Set(CLAWORLD_OPTIONAL_WORLD_HELPER_TOOL_NAMES);
490
- const existingAllow = asStringArray(config.tools.allow);
491
- const removedHelperTools = existingAllow.filter((toolName) => managedOptionalHelperTools.has(toolName));
492
- config.tools.allow = uniqueStrings([
493
- ...existingAllow.filter((toolName) => !managedOptionalHelperTools.has(toolName)),
494
- ...toolNames,
492
+ const removedManagedToolNames = new Set([
493
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
494
+ ...CLAWORLD_COMPATIBILITY_TOOL_NAMES,
495
+ ...CLAWORLD_RETIRED_PUBLIC_TOOL_NAMES,
495
496
  ]);
496
- if (removedHelperTools.length > 0) {
497
- summary.push(`tools.allow removed optional helper entries (${removedHelperTools.join(',')})`);
497
+ if (inputConfig?.tools && typeof inputConfig.tools === 'object') {
498
+ config.tools = ensureObject(config.tools);
499
+ const existingAllow = asStringArray(config.tools.allow);
500
+ const filteredAllow = existingAllow.filter((toolName) => !removedManagedToolNames.has(toolName));
501
+ const removedManagedTools = existingAllow.filter((toolName) => removedManagedToolNames.has(toolName));
502
+ if (removedManagedTools.length > 0) {
503
+ if (filteredAllow.length > 0) {
504
+ config.tools.allow = uniqueStrings(filteredAllow);
505
+ } else {
506
+ delete config.tools.allow;
507
+ }
508
+ summary.push(`tools.allow removed managed claworld entries (${removedManagedTools.join(',')})`);
509
+ }
510
+ if (Object.keys(config.tools).length === 0) {
511
+ delete config.tools;
512
+ }
498
513
  }
499
- summary.push(`tools.allow updated for ${toolProfile} profile (${describeToolAllowEntries(toolNames)})`);
500
514
 
501
515
  config.session = ensureObject(config.session);
502
516
  if (!Object.prototype.hasOwnProperty.call(config.session, 'dmScope')) {
@@ -523,7 +537,6 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
523
537
  if (agentIndex >= 0) {
524
538
  const existingAgent = ensureObject(existingAgentList[agentIndex]);
525
539
  const existingAgentDir = normalizeText(existingAgent.agentDir, null);
526
- const managedSkills = resolveManagedAgentSkills({ toolProfile: options.toolProfile });
527
540
  const keepExistingAgentDir = Boolean(
528
541
  existingAgentDir
529
542
  && (
@@ -536,12 +549,11 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
536
549
  id: options.agentId,
537
550
  workspace: normalizeText(existingAgent.workspace, options.workspace),
538
551
  ...(keepExistingAgentDir ? { agentDir: existingAgentDir } : {}),
539
- ...(managedSkills === undefined ? {} : { skills: managedSkills }),
540
552
  };
541
553
  if (!keepExistingAgentDir) {
542
554
  delete nextAgentEntry.agentDir;
543
555
  }
544
- if (managedSkills === undefined) {
556
+ if (hasOnlyManagedBundledSkills(existingAgent.skills)) {
545
557
  delete nextAgentEntry.skills;
546
558
  }
547
559
  existingAgentList[agentIndex] = nextAgentEntry;
@@ -609,7 +621,6 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
609
621
 
610
622
  return {
611
623
  config,
612
- toolNames,
613
624
  summary,
614
625
  canonicalAgentCode: canonicalRelayAgentCode(
615
626
  options.registrationAgentCode,