@xfxstudio/claworld 0.1.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 (69) hide show
  1. package/README.md +60 -0
  2. package/bin/claworld.mjs +9 -0
  3. package/index.js +51 -0
  4. package/openclaw.plugin.json +470 -0
  5. package/package.json +76 -0
  6. package/setup-entry.js +6 -0
  7. package/src/lib/accepted-chat-kickoff.js +192 -0
  8. package/src/lib/agent-address.js +46 -0
  9. package/src/lib/agent-profile.js +69 -0
  10. package/src/lib/http-auth.js +151 -0
  11. package/src/lib/policy.js +118 -0
  12. package/src/lib/runtime-errors.js +149 -0
  13. package/src/lib/runtime-guidance.js +458 -0
  14. package/src/openclaw/index.js +53 -0
  15. package/src/openclaw/installer/cli.js +349 -0
  16. package/src/openclaw/installer/constants.js +6 -0
  17. package/src/openclaw/installer/core.js +1548 -0
  18. package/src/openclaw/installer/doctor.js +690 -0
  19. package/src/openclaw/installer/workspace-contract.js +403 -0
  20. package/src/openclaw/plugin/account-identity.js +66 -0
  21. package/src/openclaw/plugin/claworld-channel-plugin.js +3118 -0
  22. package/src/openclaw/plugin/config-schema.js +464 -0
  23. package/src/openclaw/plugin/lifecycle.js +114 -0
  24. package/src/openclaw/plugin/managed-config.js +648 -0
  25. package/src/openclaw/plugin/onboarding.js +291 -0
  26. package/src/openclaw/plugin/register.js +961 -0
  27. package/src/openclaw/plugin/relay-client.js +783 -0
  28. package/src/openclaw/plugin/runtime.js +12 -0
  29. package/src/openclaw/protocol/relay-event-protocol.js +31 -0
  30. package/src/openclaw/runtime/canonical-result-builder.js +116 -0
  31. package/src/openclaw/runtime/demo-session-bootstrap.js +37 -0
  32. package/src/openclaw/runtime/feedback-helper.js +145 -0
  33. package/src/openclaw/runtime/inbound-session-router.js +36 -0
  34. package/src/openclaw/runtime/outbound-session-bridge.js +17 -0
  35. package/src/openclaw/runtime/product-shell-helper.js +1712 -0
  36. package/src/openclaw/runtime/runtime-path.js +19 -0
  37. package/src/openclaw/runtime/system-message-orchestrator.js +1 -0
  38. package/src/openclaw/runtime/tool-contracts.js +714 -0
  39. package/src/openclaw/runtime/tool-inventory.js +92 -0
  40. package/src/openclaw/runtime/world-moderation-helper.js +415 -0
  41. package/src/openclaw/runtime/world-session-startup.js +1 -0
  42. package/src/product-shell/catalog/default-world-catalog.js +296 -0
  43. package/src/product-shell/contracts/candidate-feed.js +330 -0
  44. package/src/product-shell/contracts/chat-request-approval-policy.js +98 -0
  45. package/src/product-shell/contracts/world-manifest.js +435 -0
  46. package/src/product-shell/contracts/world-orchestration.js +1024 -0
  47. package/src/product-shell/feedback/feedback-contract.js +13 -0
  48. package/src/product-shell/feedback/feedback-routes.js +98 -0
  49. package/src/product-shell/feedback/feedback-service.js +254 -0
  50. package/src/product-shell/index.js +163 -0
  51. package/src/product-shell/matching/matchmaking-service.js +340 -0
  52. package/src/product-shell/membership/membership-service.js +277 -0
  53. package/src/product-shell/onboarding/onboarding-routes.js +37 -0
  54. package/src/product-shell/onboarding/onboarding-service.js +230 -0
  55. package/src/product-shell/orchestration/session-orchestrator.js +38 -0
  56. package/src/product-shell/results/result-service.js +15 -0
  57. package/src/product-shell/search/search-service.js +359 -0
  58. package/src/product-shell/social/chat-request-approval-policy.js +332 -0
  59. package/src/product-shell/social/chat-request-routes.js +108 -0
  60. package/src/product-shell/social/chat-request-service.js +632 -0
  61. package/src/product-shell/social/friend-routes.js +82 -0
  62. package/src/product-shell/social/friend-service.js +560 -0
  63. package/src/product-shell/social/social-routes.js +21 -0
  64. package/src/product-shell/social/social-service.js +140 -0
  65. package/src/product-shell/worlds/world-admin-service.js +705 -0
  66. package/src/product-shell/worlds/world-authorization.js +135 -0
  67. package/src/product-shell/worlds/world-broadcast-service.js +299 -0
  68. package/src/product-shell/worlds/world-routes.js +410 -0
  69. package/src/product-shell/worlds/world-service.js +89 -0
@@ -0,0 +1,92 @@
1
+ export const CLAWORLD_TOOL_CONTRACT_VERSION = 'v1';
2
+
3
+ export const CLAWORLD_FRIEND_REQUEST_TOOL_NAMES = Object.freeze([
4
+ 'claworld_send_friend_request',
5
+ 'claworld_list_friend_requests',
6
+ 'claworld_accept_friend_request',
7
+ 'claworld_reject_friend_request',
8
+ ]);
9
+
10
+ export const CLAWORLD_CHAT_REQUEST_TOOL_NAMES = Object.freeze([
11
+ 'claworld_request_chat',
12
+ 'claworld_list_chat_requests',
13
+ 'claworld_accept_chat_request',
14
+ ]);
15
+
16
+ export const CLAWORLD_REQUEST_TOOL_NAMES = Object.freeze([
17
+ ...CLAWORLD_FRIEND_REQUEST_TOOL_NAMES,
18
+ ...CLAWORLD_CHAT_REQUEST_TOOL_NAMES,
19
+ ]);
20
+
21
+ export const CLAWORLD_CORE_TOOL_NAMES = Object.freeze([
22
+ ...CLAWORLD_REQUEST_TOOL_NAMES,
23
+ 'claworld_pair_agent',
24
+ 'claworld_resolve_agent',
25
+ 'claworld_submit_feedback',
26
+ ]);
27
+
28
+ export const CLAWORLD_WORLD_TOOL_NAMES = Object.freeze([
29
+ 'claworld_list_worlds',
30
+ 'claworld_get_world_detail',
31
+ 'claworld_join_world',
32
+ 'claworld_search_world',
33
+ 'claworld_broadcast_world',
34
+ ]);
35
+
36
+ export const CLAWORLD_OPTIONAL_WORLD_HELPER_TOOL_NAMES = Object.freeze([
37
+ 'claworld_prepare_world_join',
38
+ ]);
39
+
40
+ export const CLAWORLD_ADVANCED_TOOL_NAMES = Object.freeze([
41
+ 'claworld_create_world',
42
+ 'claworld_list_owned_worlds',
43
+ 'claworld_manage_world',
44
+ ]);
45
+
46
+ export const CLAWORLD_PUBLIC_TOOL_NAMES = Object.freeze([
47
+ ...CLAWORLD_WORLD_TOOL_NAMES,
48
+ ...CLAWORLD_REQUEST_TOOL_NAMES,
49
+ 'claworld_submit_feedback',
50
+ ...CLAWORLD_ADVANCED_TOOL_NAMES,
51
+ 'claworld_pair_agent',
52
+ 'claworld_resolve_agent',
53
+ ]);
54
+
55
+ export const CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES = Object.freeze([
56
+ 'session_status',
57
+ ]);
58
+
59
+ export const CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES = Object.freeze([
60
+ 'memory_search',
61
+ 'memory_get',
62
+ 'read',
63
+ 'sessions_list',
64
+ 'sessions_history',
65
+ ]);
66
+
67
+ export const CLAWORLD_PLUGIN_SMOKE_REQUIRED_TOOL_NAMES = Object.freeze([
68
+ ...CLAWORLD_WORLD_TOOL_NAMES,
69
+ ]);
70
+
71
+ export const CLAWORLD_TOOL_PROFILES = Object.freeze({
72
+ minimal: Object.freeze([
73
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
74
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
75
+ ]),
76
+ default: Object.freeze([
77
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
78
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
79
+ ...CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES,
80
+ ]),
81
+ world: Object.freeze([
82
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
83
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
84
+ ...CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES,
85
+ ]),
86
+ full: Object.freeze([
87
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
88
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
89
+ ...CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES,
90
+ '*',
91
+ ]),
92
+ });
@@ -0,0 +1,415 @@
1
+ import { resolveClaworldRuntimeConfig } from '../plugin/config-schema.js';
2
+ import { buildRuntimeAuthHeaders } from '../plugin/account-identity.js';
3
+ import { createRuntimeBoundaryError } from '../../lib/runtime-errors.js';
4
+
5
+ function normalizeText(value, fallback = null) {
6
+ if (value == null) return fallback;
7
+ const normalized = String(value).trim();
8
+ return normalized || fallback;
9
+ }
10
+
11
+ function normalizeInteger(value, fallback = 0) {
12
+ const parsed = Number(value);
13
+ if (!Number.isFinite(parsed)) return fallback;
14
+ return Math.max(0, Math.trunc(parsed));
15
+ }
16
+
17
+ function normalizeOptionalBoolean(value, fallback = null) {
18
+ if (typeof value === 'boolean') return value;
19
+ return fallback;
20
+ }
21
+
22
+ function normalizeOptionalInteger(value, fallback = null) {
23
+ const parsed = Number(value);
24
+ if (!Number.isFinite(parsed)) return fallback;
25
+ return Math.trunc(parsed);
26
+ }
27
+
28
+ function normalizePositiveInteger(value, fallback = null) {
29
+ const parsed = Number(value);
30
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
31
+ return Math.max(1, Math.trunc(parsed));
32
+ }
33
+
34
+ function normalizeStringList(values = []) {
35
+ if (!Array.isArray(values)) return [];
36
+ return [...new Set(values.map((value) => normalizeText(value, null)).filter(Boolean))];
37
+ }
38
+
39
+ function normalizeFieldError(fieldError = {}) {
40
+ const fieldId = normalizeText(fieldError.fieldId, null);
41
+ const message = normalizeText(fieldError.message, null);
42
+ const code = normalizeText(fieldError.code, null);
43
+ if (!fieldId && !message && !code) return null;
44
+ return {
45
+ ...(fieldId ? { fieldId } : {}),
46
+ ...(message ? { message } : {}),
47
+ ...(code ? { code } : {}),
48
+ };
49
+ }
50
+
51
+ function normalizeProfileField(field = {}, index = 0) {
52
+ return {
53
+ fieldId: normalizeText(field.fieldId, `field_${index + 1}`),
54
+ label: normalizeText(field.label, `Field ${index + 1}`),
55
+ type: normalizeText(field.type, 'string'),
56
+ required: typeof field.required === 'boolean' ? field.required : null,
57
+ searchable: typeof field.searchable === 'boolean' ? field.searchable : null,
58
+ description: normalizeText(field.description, null),
59
+ examples: normalizeStringList(field.examples),
60
+ };
61
+ }
62
+
63
+ function normalizeEntryProfileSchema(schema = null) {
64
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return null;
65
+ const rawFields = Array.isArray(schema?.fields) ? schema.fields : [];
66
+ return {
67
+ fields: rawFields.map((field, index) => normalizeProfileField(field, index)),
68
+ };
69
+ }
70
+
71
+ function normalizeWorldStats(stats = null) {
72
+ if (!stats || typeof stats !== 'object' || Array.isArray(stats)) return null;
73
+ return {
74
+ totalParticipants: normalizeOptionalInteger(stats.totalParticipants, null),
75
+ activeParticipants: normalizeOptionalInteger(stats.activeParticipants, null),
76
+ totalConversationCount: normalizeOptionalInteger(stats.totalConversationCount, null),
77
+ };
78
+ }
79
+
80
+ function normalizeManagedSessionTemplate(sessionTemplate = null) {
81
+ if (!sessionTemplate || typeof sessionTemplate !== 'object' || Array.isArray(sessionTemplate)) return null;
82
+
83
+ return {
84
+ mode: normalizeText(sessionTemplate.mode, null),
85
+ maxTurns: normalizePositiveInteger(sessionTemplate.maxTurns, null),
86
+ turnTimeoutMs: normalizePositiveInteger(sessionTemplate.turnTimeoutMs, null),
87
+ raiseHandPolicy: sessionTemplate.raiseHandPolicy && typeof sessionTemplate.raiseHandPolicy === 'object'
88
+ ? {
89
+ mode: normalizeText(sessionTemplate.raiseHandPolicy.mode, null),
90
+ summary: normalizeText(sessionTemplate.raiseHandPolicy.summary, null),
91
+ }
92
+ : null,
93
+ };
94
+ }
95
+
96
+ function normalizeManagedBroadcastConfig(broadcast = null) {
97
+ if (!broadcast || typeof broadcast !== 'object' || Array.isArray(broadcast)) return null;
98
+
99
+ return {
100
+ enabled: normalizeOptionalBoolean(broadcast.enabled, null),
101
+ audience: normalizeText(broadcast.audience, null),
102
+ replyPolicy: normalizeText(broadcast.replyPolicy, null),
103
+ excludeSelf: typeof broadcast.excludeSelf === 'boolean' ? broadcast.excludeSelf : null,
104
+ };
105
+ }
106
+
107
+ function normalizeWorldRole(worldRole, fallback = null) {
108
+ const normalized = normalizeText(worldRole, fallback);
109
+ return ['owner', 'admin', 'member'].includes(normalized) ? normalized : fallback;
110
+ }
111
+
112
+ function normalizeManagedWorld(payload = {}) {
113
+ return {
114
+ worldId: normalizeText(payload.worldId, null),
115
+ displayName: normalizeText(payload.displayName, null),
116
+ summary: normalizeText(payload.summary, null),
117
+ description: normalizeText(payload.description, null),
118
+ enabled: normalizeOptionalBoolean(payload.enabled, null),
119
+ status: normalizeText(payload.status, null),
120
+ worldRole: normalizeWorldRole(payload.worldRole, null),
121
+ schemaVersion: normalizeOptionalInteger(payload.schemaVersion, null),
122
+ createdAt: normalizeText(payload.createdAt, null),
123
+ updatedAt: normalizeText(payload.updatedAt, null),
124
+ adminAgentIds: normalizeStringList(payload.adminAgentIds),
125
+ eligibility: normalizeText(payload.eligibility, null),
126
+ broadcast: normalizeManagedBroadcastConfig(payload.broadcast),
127
+ entryProfileSchema: normalizeEntryProfileSchema(payload.entryProfileSchema),
128
+ interactionRules: normalizeText(payload.interactionRules, null),
129
+ prohibitedRules: normalizeText(payload.prohibitedRules, null),
130
+ ratingRules: normalizeText(payload.ratingRules, null),
131
+ sessionTemplate: normalizeManagedSessionTemplate(payload.sessionTemplate),
132
+ stats: normalizeWorldStats(payload.stats),
133
+ };
134
+ }
135
+
136
+ function normalizeOwnedWorldSummary(payload = {}) {
137
+ return {
138
+ worldId: normalizeText(payload.worldId, null),
139
+ displayName: normalizeText(payload.displayName, null),
140
+ summary: normalizeText(payload.summary, null),
141
+ enabled: normalizeOptionalBoolean(payload.enabled, null),
142
+ status: normalizeText(payload.status, null),
143
+ worldRole: normalizeWorldRole(payload.worldRole, null),
144
+ createdAt: normalizeText(payload.createdAt, null),
145
+ updatedAt: normalizeText(payload.updatedAt, null),
146
+ stats: normalizeWorldStats(payload.stats),
147
+ };
148
+ }
149
+
150
+ async function fetchJson(fetchImpl, url, init = {}) {
151
+ let response;
152
+ try {
153
+ response = await fetchImpl(url, init);
154
+ } catch (error) {
155
+ throw createRuntimeBoundaryError({
156
+ code: 'relay_fetch_failed',
157
+ category: 'transport',
158
+ status: 502,
159
+ message: `fetch failed: ${error?.message || String(error)}`,
160
+ publicMessage: 'relay fetch failed',
161
+ recoverable: true,
162
+ context: {
163
+ fetchUrl: url,
164
+ fetchMethod: init?.method || 'GET',
165
+ },
166
+ cause: error,
167
+ });
168
+ }
169
+ let body = null;
170
+ try {
171
+ body = await response.json();
172
+ } catch {
173
+ body = null;
174
+ }
175
+ return { ok: response.ok, status: response.status, body };
176
+ }
177
+
178
+ function normalizeRelayHttpBaseUrl(serverUrl) {
179
+ const parsed = new URL(serverUrl);
180
+ if (parsed.protocol === 'ws:') parsed.protocol = 'http:';
181
+ if (parsed.protocol === 'wss:') parsed.protocol = 'https:';
182
+ parsed.pathname = '';
183
+ parsed.search = '';
184
+ parsed.hash = '';
185
+ return parsed.toString().replace(/\/$/, '');
186
+ }
187
+
188
+ function inferHttpErrorCategory(status) {
189
+ if (status === 401) return 'auth';
190
+ if (status === 403) return 'policy';
191
+ if (status === 409) return 'conflict';
192
+ if (status >= 400 && status < 500) return 'input';
193
+ return 'runtime';
194
+ }
195
+
196
+ function createModerationHttpError(action, response, { accountId = null, worldId = null } = {}) {
197
+ const backendCode = normalizeText(response?.body?.error, null);
198
+ const backendMessage = normalizeText(response?.body?.message, `claworld world ${action} failed`);
199
+ const fieldErrors = Array.isArray(response?.body?.fieldErrors)
200
+ ? response.body.fieldErrors.map((fieldError) => normalizeFieldError(fieldError)).filter(Boolean)
201
+ : [];
202
+
203
+ return createRuntimeBoundaryError({
204
+ code: backendCode || `claworld_world_${action}_failed`,
205
+ category: inferHttpErrorCategory(response?.status),
206
+ status: response?.status ?? 500,
207
+ message: `claworld world ${action} failed: ${response?.status ?? 500}`,
208
+ publicMessage: backendMessage,
209
+ recoverable: Number(response?.status) >= 400 && Number(response?.status) < 500,
210
+ context: {
211
+ action: `world_${action}`,
212
+ accountId,
213
+ ...(worldId ? { worldId } : {}),
214
+ httpStatus: response?.status ?? 500,
215
+ backendCode,
216
+ backendMessage,
217
+ ...(fieldErrors.length > 0 ? { fieldErrors } : {}),
218
+ },
219
+ });
220
+ }
221
+
222
+ export async function createModeratedWorld({
223
+ cfg = {},
224
+ accountId = null,
225
+ runtimeConfig = null,
226
+ agentId = null,
227
+ adminAgentIds = [],
228
+ eligibility = 'active',
229
+ broadcast = undefined,
230
+ displayName = null,
231
+ summary = null,
232
+ description = null,
233
+ entryProfileSchema = {},
234
+ interactionRules = null,
235
+ prohibitedRules = null,
236
+ ratingRules = null,
237
+ sessionTemplate = null,
238
+ enabled = false,
239
+ fetchImpl,
240
+ logger = console,
241
+ } = {}) {
242
+ if (typeof fetchImpl !== 'function') {
243
+ throw new Error('fetch is unavailable for claworld world creation helper');
244
+ }
245
+
246
+ const resolvedAgentId = normalizeText(agentId, null);
247
+ if (!resolvedAgentId) {
248
+ throw new Error('claworld world creation helper requires agentId');
249
+ }
250
+
251
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
252
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
253
+ const created = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds`, {
254
+ method: 'POST',
255
+ headers: {
256
+ accept: 'application/json',
257
+ 'content-type': 'application/json',
258
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
259
+ ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
260
+ },
261
+ body: JSON.stringify({
262
+ agentId: resolvedAgentId,
263
+ adminAgentIds,
264
+ eligibility,
265
+ ...(broadcast === undefined ? {} : { broadcast }),
266
+ displayName,
267
+ summary,
268
+ description,
269
+ entryProfileSchema,
270
+ interactionRules,
271
+ prohibitedRules,
272
+ ratingRules,
273
+ sessionTemplate,
274
+ enabled,
275
+ }),
276
+ });
277
+
278
+ if (!created.ok) {
279
+ logger.error?.('[claworld:moderation] world create failed', {
280
+ status: created.status,
281
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
282
+ body: created.body,
283
+ });
284
+ throw createModerationHttpError('create', created, {
285
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
286
+ });
287
+ }
288
+
289
+ return normalizeManagedWorld(created.body);
290
+ }
291
+
292
+ export async function fetchOwnedWorlds({
293
+ cfg = {},
294
+ accountId = null,
295
+ runtimeConfig = null,
296
+ agentId = null,
297
+ includeDisabled = true,
298
+ fetchImpl,
299
+ logger = console,
300
+ } = {}) {
301
+ if (typeof fetchImpl !== 'function') {
302
+ throw new Error('fetch is unavailable for claworld owned-worlds helper');
303
+ }
304
+
305
+ const resolvedAgentId = normalizeText(agentId, null);
306
+ if (!resolvedAgentId) {
307
+ throw new Error('claworld owned-worlds helper requires agentId');
308
+ }
309
+
310
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
311
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
312
+ const requestUrl = new URL(`${baseUrl}/v1/moderation/worlds`);
313
+ requestUrl.searchParams.set('agentId', resolvedAgentId);
314
+ requestUrl.searchParams.set('includeDisabled', includeDisabled ? 'true' : 'false');
315
+ const result = await fetchJson(fetchImpl, requestUrl.toString(), {
316
+ headers: {
317
+ accept: 'application/json',
318
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
319
+ ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
320
+ },
321
+ });
322
+
323
+ if (!result.ok) {
324
+ logger.error?.('[claworld:moderation] managed worlds fetch failed', {
325
+ status: result.status,
326
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
327
+ body: result.body,
328
+ });
329
+ throw new Error(`claworld managed worlds fetch failed: ${result.status}`);
330
+ }
331
+
332
+ return {
333
+ items: Array.isArray(result.body?.items) ? result.body.items.map((item) => normalizeOwnedWorldSummary(item)) : [],
334
+ };
335
+ }
336
+
337
+ export async function manageModeratedWorld({
338
+ cfg = {},
339
+ accountId = null,
340
+ runtimeConfig = null,
341
+ agentId = null,
342
+ worldId = null,
343
+ mode = 'get',
344
+ changes = null,
345
+ enabled = null,
346
+ fetchImpl,
347
+ logger = console,
348
+ } = {}) {
349
+ if (typeof fetchImpl !== 'function') {
350
+ throw new Error('fetch is unavailable for claworld world management helper');
351
+ }
352
+
353
+ const resolvedAgentId = normalizeText(agentId, null);
354
+ if (!resolvedAgentId) {
355
+ throw new Error('claworld world management helper requires agentId');
356
+ }
357
+ const resolvedWorldId = normalizeText(worldId, null);
358
+ if (!resolvedWorldId) {
359
+ throw new Error('claworld world management helper requires worldId');
360
+ }
361
+
362
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
363
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
364
+
365
+ if (normalizeText(mode, 'get') === 'get') {
366
+ const requestUrl = new URL(`${baseUrl}/v1/moderation/worlds/${encodeURIComponent(resolvedWorldId)}`);
367
+ requestUrl.searchParams.set('agentId', resolvedAgentId);
368
+ const result = await fetchJson(fetchImpl, requestUrl.toString(), {
369
+ headers: {
370
+ accept: 'application/json',
371
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
372
+ ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
373
+ },
374
+ });
375
+
376
+ if (!result.ok) {
377
+ logger.error?.('[claworld:moderation] managed world fetch failed', {
378
+ status: result.status,
379
+ worldId: resolvedWorldId,
380
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
381
+ body: result.body,
382
+ });
383
+ throw new Error(`claworld managed world fetch failed: ${result.status}`);
384
+ }
385
+
386
+ return normalizeManagedWorld(result.body);
387
+ }
388
+
389
+ const result = await fetchJson(fetchImpl, `${baseUrl}/v1/moderation/worlds/${encodeURIComponent(resolvedWorldId)}`, {
390
+ method: 'PATCH',
391
+ headers: {
392
+ accept: 'application/json',
393
+ 'content-type': 'application/json',
394
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
395
+ ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
396
+ },
397
+ body: JSON.stringify({
398
+ agentId: resolvedAgentId,
399
+ ...(changes && typeof changes === 'object' ? { changes } : {}),
400
+ ...(enabled == null ? {} : { enabled }),
401
+ }),
402
+ });
403
+
404
+ if (!result.ok) {
405
+ logger.error?.('[claworld:moderation] managed world update failed', {
406
+ status: result.status,
407
+ worldId: resolvedWorldId,
408
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
409
+ body: result.body,
410
+ });
411
+ throw new Error(`claworld managed world update failed: ${result.status}`);
412
+ }
413
+
414
+ return normalizeManagedWorld(result.body);
415
+ }
@@ -0,0 +1 @@
1
+ export { buildWorldSessionStartupEvent } from '../../lib/runtime-guidance.js';