@xfxstudio/claworld 0.2.7 → 0.2.9
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.
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/openclaw/installer/doctor.js +63 -0
- package/src/openclaw/plugin/claworld-channel-plugin.js +40 -0
- package/src/openclaw/plugin/managed-config.js +110 -0
- package/src/openclaw/plugin/register.js +184 -58
- package/src/openclaw/plugin/relay-client.js +14 -1
- package/src/openclaw/runtime/tool-contracts.js +1 -1
- package/src/openclaw/runtime/tool-inventory.js +2 -1
- package/src/openclaw/runtime/world-moderation-helper.js +2 -0
- package/src/product-shell/worlds/world-admin-service.js +52 -12
- package/src/product-shell/worlds/world-routes.js +1 -0
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -6,8 +6,11 @@ import {
|
|
|
6
6
|
DEFAULT_CLAWORLD_AGENT_ID,
|
|
7
7
|
DEFAULT_CLAWORLD_SERVER_URL,
|
|
8
8
|
expandUserPath,
|
|
9
|
+
getEffectiveAgentSandboxMode,
|
|
10
|
+
MIN_MANAGED_SESSION_VISIBILITY,
|
|
9
11
|
normalizeText,
|
|
10
12
|
resolveClaworldManagedRuntimeOptions,
|
|
13
|
+
sandboxModeNeedsSessionToolsVisibility,
|
|
11
14
|
} from '../plugin/managed-config.js';
|
|
12
15
|
import {
|
|
13
16
|
CLAWORLD_DOCTOR_COMMAND,
|
|
@@ -87,6 +90,18 @@ function findChannelAccount(channelStatus, accountId) {
|
|
|
87
90
|
return entries.find((entry) => entry?.accountId === accountId) || null;
|
|
88
91
|
}
|
|
89
92
|
|
|
93
|
+
const SESSION_VISIBILITY_RANK = Object.freeze({
|
|
94
|
+
self: 0,
|
|
95
|
+
tree: 1,
|
|
96
|
+
agent: 2,
|
|
97
|
+
all: 3,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
function resolveConfiguredSessionVisibility(config = {}) {
|
|
101
|
+
const visibility = normalizeText(config?.tools?.sessions?.visibility, null);
|
|
102
|
+
return Object.prototype.hasOwnProperty.call(SESSION_VISIBILITY_RANK, visibility) ? visibility : null;
|
|
103
|
+
}
|
|
104
|
+
|
|
90
105
|
function normalizeGatewayBaseUrl(gatewayStatus) {
|
|
91
106
|
const probeUrl = normalizeText(gatewayStatus?.gateway?.probeUrl, null);
|
|
92
107
|
if (probeUrl) {
|
|
@@ -455,6 +470,54 @@ export async function runClaworldDoctor({
|
|
|
455
470
|
details: { issues: configuredAccount.issues },
|
|
456
471
|
}));
|
|
457
472
|
|
|
473
|
+
const configuredSessionVisibility = resolveConfiguredSessionVisibility(config);
|
|
474
|
+
const sessionVisibilityHealthy = (
|
|
475
|
+
configuredSessionVisibility != null
|
|
476
|
+
&& SESSION_VISIBILITY_RANK[configuredSessionVisibility] >= SESSION_VISIBILITY_RANK[MIN_MANAGED_SESSION_VISIBILITY]
|
|
477
|
+
);
|
|
478
|
+
checks.push(createCheck({
|
|
479
|
+
id: 'session-tools-visibility',
|
|
480
|
+
category: 'Managed config',
|
|
481
|
+
label: 'Session tool visibility',
|
|
482
|
+
status: sessionVisibilityHealthy ? 'pass' : 'warn',
|
|
483
|
+
summary: sessionVisibilityHealthy
|
|
484
|
+
? `tools.sessions.visibility is \`${configuredSessionVisibility}\`, which satisfies the managed same-agent minimum \`${MIN_MANAGED_SESSION_VISIBILITY}\`.`
|
|
485
|
+
: `tools.sessions.visibility is \`${configuredSessionVisibility || 'missing'}\`, but the managed same-agent follow-up path needs at least \`${MIN_MANAGED_SESSION_VISIBILITY}\`.`,
|
|
486
|
+
action: sessionVisibilityHealthy
|
|
487
|
+
? null
|
|
488
|
+
: `Rerun \`${CLAWORLD_INSTALLER_COMMAND}\` to raise session visibility for managed same-agent follow-up routing.`,
|
|
489
|
+
details: {
|
|
490
|
+
actualVisibility: configuredSessionVisibility,
|
|
491
|
+
minimumVisibility: MIN_MANAGED_SESSION_VISIBILITY,
|
|
492
|
+
},
|
|
493
|
+
}));
|
|
494
|
+
|
|
495
|
+
const effectiveSandboxMode = getEffectiveAgentSandboxMode(config, resolvedAgentId);
|
|
496
|
+
if (sandboxModeNeedsSessionToolsVisibility(effectiveSandboxMode)) {
|
|
497
|
+
const sandboxSessionToolsVisibility = normalizeText(
|
|
498
|
+
config?.agents?.defaults?.sandbox?.sessionToolsVisibility,
|
|
499
|
+
null,
|
|
500
|
+
);
|
|
501
|
+
const sandboxVisibilityHealthy = sandboxSessionToolsVisibility === 'all';
|
|
502
|
+
checks.push(createCheck({
|
|
503
|
+
id: 'sandbox-session-tools-visibility',
|
|
504
|
+
category: 'Managed config',
|
|
505
|
+
label: 'Sandbox session tool visibility',
|
|
506
|
+
status: sandboxVisibilityHealthy ? 'pass' : 'warn',
|
|
507
|
+
summary: sandboxVisibilityHealthy
|
|
508
|
+
? `Effective sandbox mode is \`${effectiveSandboxMode}\` and agents.defaults.sandbox.sessionToolsVisibility is correctly set to \`all\`.`
|
|
509
|
+
: `Effective sandbox mode is \`${effectiveSandboxMode}\`, so agents.defaults.sandbox.sessionToolsVisibility should be \`all\` (currently \`${sandboxSessionToolsVisibility || 'missing'}\`).`,
|
|
510
|
+
action: sandboxVisibilityHealthy
|
|
511
|
+
? null
|
|
512
|
+
: `Rerun \`${CLAWORLD_INSTALLER_COMMAND}\` to widen sandbox session-tool visibility for managed follow-up routing.`,
|
|
513
|
+
details: {
|
|
514
|
+
effectiveSandboxMode,
|
|
515
|
+
sessionToolsVisibility: sandboxSessionToolsVisibility,
|
|
516
|
+
requiredSessionToolsVisibility: 'all',
|
|
517
|
+
},
|
|
518
|
+
}));
|
|
519
|
+
}
|
|
520
|
+
|
|
458
521
|
checks.push(createCheck({
|
|
459
522
|
id: 'app-token',
|
|
460
523
|
category: 'Credentials and runtime',
|
|
@@ -720,6 +720,34 @@ async function acceptChatRequest({
|
|
|
720
720
|
return result.body || {};
|
|
721
721
|
}
|
|
722
722
|
|
|
723
|
+
async function rejectChatRequest({
|
|
724
|
+
runtimeConfig,
|
|
725
|
+
actorAgentId,
|
|
726
|
+
chatRequestId,
|
|
727
|
+
fetchImpl,
|
|
728
|
+
}) {
|
|
729
|
+
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
730
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/chat-requests/${encodeURIComponent(chatRequestId)}/reject`, {
|
|
731
|
+
method: 'POST',
|
|
732
|
+
headers: {
|
|
733
|
+
'content-type': 'application/json',
|
|
734
|
+
...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
|
|
735
|
+
...buildRuntimeAuthHeaders(runtimeConfig),
|
|
736
|
+
},
|
|
737
|
+
body: JSON.stringify({ actorAgentId }),
|
|
738
|
+
});
|
|
739
|
+
if (!result.ok) {
|
|
740
|
+
createRelayRouteError({
|
|
741
|
+
result,
|
|
742
|
+
runtimeConfig,
|
|
743
|
+
code: 'chat_request_reject_failed',
|
|
744
|
+
publicMessage: 'failed to reject chat request',
|
|
745
|
+
context: { actorAgentId, chatRequestId },
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
return result.body || {};
|
|
749
|
+
}
|
|
750
|
+
|
|
723
751
|
async function syncChatRequestApprovalPolicy({
|
|
724
752
|
runtimeConfig,
|
|
725
753
|
fetchImpl,
|
|
@@ -1472,6 +1500,7 @@ function createDeliveryReplyDispatcher({
|
|
|
1472
1500
|
});
|
|
1473
1501
|
|
|
1474
1502
|
const markDispatchIdle = async () => {
|
|
1503
|
+
await dispatchApi.dispatcher.waitForIdle?.();
|
|
1475
1504
|
if (!replied && !suppressed) {
|
|
1476
1505
|
const continuation = buildRelayContinuationText({
|
|
1477
1506
|
finalTexts,
|
|
@@ -2539,6 +2568,15 @@ export function createClaworldChannelPlugin({
|
|
|
2539
2568
|
fetchImpl,
|
|
2540
2569
|
});
|
|
2541
2570
|
},
|
|
2571
|
+
rejectChatRequest: async (context = {}) => {
|
|
2572
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2573
|
+
return rejectChatRequest({
|
|
2574
|
+
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2575
|
+
actorAgentId: resolvedContext.agentId || null,
|
|
2576
|
+
chatRequestId: context.chatRequestId || null,
|
|
2577
|
+
fetchImpl,
|
|
2578
|
+
});
|
|
2579
|
+
},
|
|
2542
2580
|
},
|
|
2543
2581
|
postSetup: {
|
|
2544
2582
|
fetchWorldDirectory: async (context = {}) => {
|
|
@@ -2676,6 +2714,7 @@ export function createClaworldChannelPlugin({
|
|
|
2676
2714
|
mode: context.mode || 'get',
|
|
2677
2715
|
changes: context.changes || null,
|
|
2678
2716
|
enabled: Object.prototype.hasOwnProperty.call(context, 'enabled') ? context.enabled : null,
|
|
2717
|
+
status: context.status || null,
|
|
2679
2718
|
fetchImpl,
|
|
2680
2719
|
logger,
|
|
2681
2720
|
});
|
|
@@ -2864,6 +2903,7 @@ export function createClaworldChannelPlugin({
|
|
|
2864
2903
|
mode: context.mode || 'get',
|
|
2865
2904
|
changes: context.changes || null,
|
|
2866
2905
|
enabled: Object.prototype.hasOwnProperty.call(context, 'enabled') ? context.enabled : null,
|
|
2906
|
+
status: context.status || null,
|
|
2867
2907
|
fetchImpl,
|
|
2868
2908
|
logger,
|
|
2869
2909
|
});
|
|
@@ -23,6 +23,8 @@ export const DEFAULT_CLAWORLD_APPROVAL_MODE = DEFAULT_CHAT_REQUEST_APPROVAL_POLI
|
|
|
23
23
|
export const DEFAULT_CLAWORLD_SESSION_TARGET = 'mainagent';
|
|
24
24
|
export const DEFAULT_CLAWORLD_FALLBACK_TARGET = 'mainagent';
|
|
25
25
|
export const CLAWORLD_PLUGIN_TOOL_ALLOW_ENTRY = 'claworld';
|
|
26
|
+
export const MIN_MANAGED_SESSION_VISIBILITY = 'agent';
|
|
27
|
+
export const REQUIRED_SANDBOX_SESSION_TOOLS_VISIBILITY = 'all';
|
|
26
28
|
|
|
27
29
|
export const TOOL_PROFILES = CLAWORLD_TOOL_PROFILES;
|
|
28
30
|
|
|
@@ -128,6 +130,109 @@ function findManagedAccountEntry(config = {}, accountId) {
|
|
|
128
130
|
return {};
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
const SESSION_VISIBILITY_RANK = Object.freeze({
|
|
134
|
+
self: 0,
|
|
135
|
+
tree: 1,
|
|
136
|
+
agent: 2,
|
|
137
|
+
all: 3,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const SANDBOX_SESSION_TOOLS_VISIBILITY_RANK = Object.freeze({
|
|
141
|
+
spawned: 0,
|
|
142
|
+
all: 1,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
function normalizeSessionVisibility(value, fallback = null) {
|
|
146
|
+
const normalized = normalizeText(value, fallback);
|
|
147
|
+
return Object.prototype.hasOwnProperty.call(SESSION_VISIBILITY_RANK, normalized)
|
|
148
|
+
? normalized
|
|
149
|
+
: fallback;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function normalizeSandboxSessionToolsVisibility(value, fallback = null) {
|
|
153
|
+
const normalized = normalizeText(value, fallback);
|
|
154
|
+
return Object.prototype.hasOwnProperty.call(SANDBOX_SESSION_TOOLS_VISIBILITY_RANK, normalized)
|
|
155
|
+
? normalized
|
|
156
|
+
: fallback;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function compareRankedSetting(value, target, rankMap) {
|
|
160
|
+
const nextValue = normalizeText(value, null);
|
|
161
|
+
const nextTarget = normalizeText(target, null);
|
|
162
|
+
const valueRank = Object.prototype.hasOwnProperty.call(rankMap, nextValue) ? rankMap[nextValue] : null;
|
|
163
|
+
const targetRank = Object.prototype.hasOwnProperty.call(rankMap, nextTarget) ? rankMap[nextTarget] : null;
|
|
164
|
+
if (valueRank == null && targetRank == null) return 0;
|
|
165
|
+
if (valueRank == null) return -1;
|
|
166
|
+
if (targetRank == null) return 1;
|
|
167
|
+
return valueRank - targetRank;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function getEffectiveAgentSandboxMode(config = {}, agentId = DEFAULT_CLAWORLD_AGENT_ID) {
|
|
171
|
+
const normalizedAgentId = normalizeText(agentId, DEFAULT_CLAWORLD_AGENT_ID);
|
|
172
|
+
const agentEntry = findAgentEntry(config, normalizedAgentId);
|
|
173
|
+
const agentSandboxMode = normalizeText(agentEntry?.sandbox?.mode, null);
|
|
174
|
+
if (agentSandboxMode) return agentSandboxMode;
|
|
175
|
+
return normalizeText(config?.agents?.defaults?.sandbox?.mode, 'off');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function sandboxModeNeedsSessionToolsVisibility(mode) {
|
|
179
|
+
return mode === 'all' || mode === 'non-main';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function ensureManagedSessionRoutingVisibility(config = {}, {
|
|
183
|
+
agentId = DEFAULT_CLAWORLD_AGENT_ID,
|
|
184
|
+
summary = [],
|
|
185
|
+
} = {}) {
|
|
186
|
+
config.tools = ensureObject(config.tools);
|
|
187
|
+
const existingSessionTools = ensureObject(config.tools.sessions);
|
|
188
|
+
const existingVisibility = normalizeSessionVisibility(existingSessionTools.visibility, null);
|
|
189
|
+
if (compareRankedSetting(existingVisibility, MIN_MANAGED_SESSION_VISIBILITY, SESSION_VISIBILITY_RANK) < 0) {
|
|
190
|
+
config.tools.sessions = {
|
|
191
|
+
...existingSessionTools,
|
|
192
|
+
visibility: MIN_MANAGED_SESSION_VISIBILITY,
|
|
193
|
+
};
|
|
194
|
+
summary.push(
|
|
195
|
+
existingVisibility
|
|
196
|
+
? `tools.sessions.visibility raised from ${existingVisibility} to ${MIN_MANAGED_SESSION_VISIBILITY}`
|
|
197
|
+
: `tools.sessions.visibility set to ${MIN_MANAGED_SESSION_VISIBILITY}`,
|
|
198
|
+
);
|
|
199
|
+
} else if (Object.keys(existingSessionTools).length > 0) {
|
|
200
|
+
config.tools.sessions = existingSessionTools;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const effectiveSandboxMode = getEffectiveAgentSandboxMode(config, agentId);
|
|
204
|
+
if (!sandboxModeNeedsSessionToolsVisibility(effectiveSandboxMode)) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
config.agents = ensureObject(config.agents);
|
|
209
|
+
config.agents.defaults = ensureObject(config.agents.defaults);
|
|
210
|
+
const existingSandbox = ensureObject(config.agents.defaults.sandbox);
|
|
211
|
+
const existingSessionToolsVisibility = normalizeSandboxSessionToolsVisibility(
|
|
212
|
+
existingSandbox.sessionToolsVisibility,
|
|
213
|
+
null,
|
|
214
|
+
);
|
|
215
|
+
if (
|
|
216
|
+
compareRankedSetting(
|
|
217
|
+
existingSessionToolsVisibility,
|
|
218
|
+
REQUIRED_SANDBOX_SESSION_TOOLS_VISIBILITY,
|
|
219
|
+
SANDBOX_SESSION_TOOLS_VISIBILITY_RANK,
|
|
220
|
+
) < 0
|
|
221
|
+
) {
|
|
222
|
+
config.agents.defaults.sandbox = {
|
|
223
|
+
...existingSandbox,
|
|
224
|
+
sessionToolsVisibility: REQUIRED_SANDBOX_SESSION_TOOLS_VISIBILITY,
|
|
225
|
+
};
|
|
226
|
+
summary.push(
|
|
227
|
+
existingSessionToolsVisibility
|
|
228
|
+
? `agents.defaults.sandbox.sessionToolsVisibility raised from ${existingSessionToolsVisibility} to ${REQUIRED_SANDBOX_SESSION_TOOLS_VISIBILITY}`
|
|
229
|
+
: `agents.defaults.sandbox.sessionToolsVisibility set to ${REQUIRED_SANDBOX_SESSION_TOOLS_VISIBILITY}`,
|
|
230
|
+
);
|
|
231
|
+
} else if (Object.keys(existingSandbox).length > 0) {
|
|
232
|
+
config.agents.defaults.sandbox = existingSandbox;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
131
236
|
function inferExistingAgentId(config = {}, accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
|
|
132
237
|
const bindings = Array.isArray(config?.bindings) ? config.bindings : [];
|
|
133
238
|
const bindingMatch = bindings
|
|
@@ -716,6 +821,11 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
|
|
|
716
821
|
: `reconciled claworld binding for ${options.accountId}`,
|
|
717
822
|
);
|
|
718
823
|
|
|
824
|
+
ensureManagedSessionRoutingVisibility(config, {
|
|
825
|
+
agentId: options.agentId,
|
|
826
|
+
summary,
|
|
827
|
+
});
|
|
828
|
+
|
|
719
829
|
return {
|
|
720
830
|
config,
|
|
721
831
|
summary,
|
|
@@ -266,6 +266,56 @@ function buildToolMetadata({
|
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
const MANAGE_WORLD_ACTIONS = Object.freeze([
|
|
270
|
+
'list',
|
|
271
|
+
'get',
|
|
272
|
+
'update_context',
|
|
273
|
+
'pause',
|
|
274
|
+
'close',
|
|
275
|
+
'resume',
|
|
276
|
+
]);
|
|
277
|
+
|
|
278
|
+
function normalizeManageWorldAction(value, fallback = null) {
|
|
279
|
+
const normalized = normalizeText(value, fallback);
|
|
280
|
+
return MANAGE_WORLD_ACTIONS.includes(normalized) ? normalized : fallback;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function inferManageWorldAction(params = {}) {
|
|
284
|
+
const explicitAction = normalizeManageWorldAction(params.action, null);
|
|
285
|
+
if (explicitAction) return explicitAction;
|
|
286
|
+
if (!normalizeText(params.worldId, null)) return 'list';
|
|
287
|
+
if (normalizeText(params.worldContextText, null) || normalizeText(params.displayName, null)) {
|
|
288
|
+
return 'update_context';
|
|
289
|
+
}
|
|
290
|
+
return 'get';
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function requireManageWorldField(fieldId, message = `${fieldId} is required`) {
|
|
294
|
+
throw createRuntimeBoundaryError({
|
|
295
|
+
code: 'tool_input_invalid',
|
|
296
|
+
category: 'input',
|
|
297
|
+
status: 400,
|
|
298
|
+
message,
|
|
299
|
+
publicMessage: message,
|
|
300
|
+
recoverable: true,
|
|
301
|
+
context: { field: fieldId },
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function projectToolManageWorldActionResponse(payload = {}, { accountId = null, action = null } = {}) {
|
|
306
|
+
const resolvedAction = normalizeManageWorldAction(action, null) || 'get';
|
|
307
|
+
if (resolvedAction === 'list') {
|
|
308
|
+
return {
|
|
309
|
+
action: resolvedAction,
|
|
310
|
+
...projectToolOwnedWorldsResponse(payload, { accountId }),
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
action: resolvedAction,
|
|
315
|
+
...projectToolManagedWorldResponse(payload, { accountId }),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
269
319
|
function buildRegisteredTools(api, plugin) {
|
|
270
320
|
const accountIdProperty = stringParam({
|
|
271
321
|
description: 'Claworld account id to execute the tool against. In managed installs this is usually the dedicated claworld account.',
|
|
@@ -509,67 +559,31 @@ function buildRegisteredTools(api, plugin) {
|
|
|
509
559
|
},
|
|
510
560
|
},
|
|
511
561
|
{
|
|
512
|
-
name: '
|
|
513
|
-
label: 'Claworld
|
|
514
|
-
description: '
|
|
562
|
+
name: 'claworld_manage_world',
|
|
563
|
+
label: 'Claworld Manage World',
|
|
564
|
+
description: 'Unified owner-only world governance tool. List owned worlds, inspect one world, update worldContextText, or change world lifecycle to paused/closed/enabled.',
|
|
515
565
|
metadata: buildToolMetadata({
|
|
516
566
|
category: 'world_management',
|
|
517
567
|
usageNotes: [
|
|
518
|
-
'Use
|
|
519
|
-
'
|
|
520
|
-
'
|
|
568
|
+
'Use action=list to inspect the worlds owned by the current account.',
|
|
569
|
+
'Use action=get to inspect one owned world before changing it.',
|
|
570
|
+
'Use action=update_context to change worldContextText and optional displayName.',
|
|
571
|
+
'Use action=pause, action=close, or action=resume for owner-only lifecycle changes.',
|
|
521
572
|
],
|
|
522
573
|
examples: [
|
|
523
574
|
{
|
|
524
575
|
title: 'List owned worlds',
|
|
525
576
|
input: {
|
|
526
577
|
accountId: 'claworld',
|
|
578
|
+
action: 'list',
|
|
527
579
|
},
|
|
528
580
|
outcome: 'Returns owner-managed worlds for the current account.',
|
|
529
581
|
},
|
|
530
|
-
],
|
|
531
|
-
}),
|
|
532
|
-
parameters: objectParam({
|
|
533
|
-
description: 'Minimal payload for listing worlds owned by the current account.',
|
|
534
|
-
required: ['accountId'],
|
|
535
|
-
properties: {
|
|
536
|
-
accountId: accountIdProperty,
|
|
537
|
-
includeDisabled: {
|
|
538
|
-
type: 'boolean',
|
|
539
|
-
description: 'Whether to include disabled or draft owned worlds.',
|
|
540
|
-
},
|
|
541
|
-
},
|
|
542
|
-
examples: [
|
|
543
|
-
{
|
|
544
|
-
accountId: 'claworld',
|
|
545
|
-
},
|
|
546
|
-
],
|
|
547
|
-
}),
|
|
548
|
-
async execute(_toolCallId, params = {}) {
|
|
549
|
-
const context = await resolveToolContext(api, plugin, params);
|
|
550
|
-
const payload = await plugin.runtime.productShell.moderation.listOwnedWorlds({
|
|
551
|
-
...context,
|
|
552
|
-
includeDisabled: params.includeDisabled !== false,
|
|
553
|
-
});
|
|
554
|
-
return buildToolResult(projectToolOwnedWorldsResponse(payload, { accountId: context.accountId }));
|
|
555
|
-
},
|
|
556
|
-
},
|
|
557
|
-
{
|
|
558
|
-
name: 'claworld_manage_world',
|
|
559
|
-
label: 'Claworld Manage World',
|
|
560
|
-
description: 'Owner-only world management tool. Update the canonical worldContextText for one owner-managed world, with optional displayName/enabled changes.',
|
|
561
|
-
metadata: buildToolMetadata({
|
|
562
|
-
category: 'world_management',
|
|
563
|
-
usageNotes: [
|
|
564
|
-
'Use only when the current agent owns the target world.',
|
|
565
|
-
'This is the minimal management tool on the current public surface.',
|
|
566
|
-
'Prefer updating worldContextText directly instead of editing legacy world schema fields.',
|
|
567
|
-
],
|
|
568
|
-
examples: [
|
|
569
582
|
{
|
|
570
583
|
title: 'Update one owned world context',
|
|
571
584
|
input: {
|
|
572
585
|
accountId: 'claworld',
|
|
586
|
+
action: 'update_context',
|
|
573
587
|
worldId: 'ugc-weekend-debate-club',
|
|
574
588
|
worldContextText: '世界:Weekend Debate Club [ugc-weekend-debate-club]\n简介:A creator-managed world for short structured debates.\n互动规则:Debate one topic at a time and stay concise.',
|
|
575
589
|
},
|
|
@@ -578,29 +592,39 @@ function buildRegisteredTools(api, plugin) {
|
|
|
578
592
|
],
|
|
579
593
|
}),
|
|
580
594
|
parameters: objectParam({
|
|
581
|
-
description: '
|
|
582
|
-
required: ['accountId'
|
|
595
|
+
description: 'Owner-only world governance payload. action=list replaces the old list_owned_worlds tool.',
|
|
596
|
+
required: ['accountId'],
|
|
583
597
|
properties: {
|
|
584
598
|
accountId: accountIdProperty,
|
|
599
|
+
action: stringParam({
|
|
600
|
+
description: 'Owner-only governance action. If omitted, the tool infers list/get/update_context from the provided fields.',
|
|
601
|
+
enumValues: MANAGE_WORLD_ACTIONS,
|
|
602
|
+
examples: ['list'],
|
|
603
|
+
}),
|
|
585
604
|
worldId: worldIdProperty,
|
|
586
605
|
worldContextText: stringParam({
|
|
587
|
-
description: 'Replacement canonical world context text for
|
|
606
|
+
description: 'Replacement canonical world context text for update_context.',
|
|
588
607
|
minLength: 1,
|
|
589
608
|
examples: ['世界:Weekend Debate Club [ugc-weekend-debate-club]\n简介:A creator-managed world for short structured debates.\n互动规则:Debate one topic at a time and stay concise.'],
|
|
590
609
|
}),
|
|
591
610
|
displayName: stringParam({
|
|
592
|
-
description: 'Optional new display name
|
|
611
|
+
description: 'Optional new display name when action=update_context.',
|
|
593
612
|
minLength: 1,
|
|
594
613
|
examples: ['Weekend Debate Club'],
|
|
595
614
|
}),
|
|
596
|
-
|
|
615
|
+
includeDisabled: {
|
|
597
616
|
type: 'boolean',
|
|
598
|
-
description: '
|
|
617
|
+
description: 'Whether action=list should include paused, closed, or draft owned worlds.',
|
|
599
618
|
},
|
|
600
619
|
},
|
|
601
620
|
examples: [
|
|
602
621
|
{
|
|
603
622
|
accountId: 'claworld',
|
|
623
|
+
action: 'list',
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
accountId: 'claworld',
|
|
627
|
+
action: 'update_context',
|
|
604
628
|
worldId: 'ugc-weekend-debate-club',
|
|
605
629
|
worldContextText: '世界:Weekend Debate Club [ugc-weekend-debate-club]\n简介:A creator-managed world for short structured debates.\n互动规则:Debate one topic at a time and stay concise.',
|
|
606
630
|
},
|
|
@@ -608,18 +632,72 @@ function buildRegisteredTools(api, plugin) {
|
|
|
608
632
|
}),
|
|
609
633
|
async execute(_toolCallId, params = {}) {
|
|
610
634
|
const context = await resolveToolContext(api, plugin, params);
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
635
|
+
if (Object.prototype.hasOwnProperty.call(params, 'action')
|
|
636
|
+
&& !normalizeManageWorldAction(params.action, null)) {
|
|
637
|
+
requireManageWorldField('action', 'action must be one of list, get, update_context, pause, close, or resume');
|
|
638
|
+
}
|
|
639
|
+
const action = inferManageWorldAction(params);
|
|
640
|
+
if (action === 'list') {
|
|
641
|
+
const payload = await plugin.runtime.productShell.moderation.listOwnedWorlds({
|
|
642
|
+
...context,
|
|
643
|
+
includeDisabled: params.includeDisabled !== false,
|
|
644
|
+
});
|
|
645
|
+
return buildToolResult(projectToolManageWorldActionResponse(payload, {
|
|
646
|
+
accountId: context.accountId,
|
|
647
|
+
action,
|
|
648
|
+
}));
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const worldId = normalizeText(params.worldId, null);
|
|
652
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
653
|
+
|
|
654
|
+
if (action === 'get') {
|
|
655
|
+
const payload = await plugin.runtime.productShell.moderation.manageWorld({
|
|
656
|
+
...context,
|
|
657
|
+
worldId,
|
|
658
|
+
mode: 'get',
|
|
659
|
+
});
|
|
660
|
+
return buildToolResult(projectToolManageWorldActionResponse(payload, {
|
|
661
|
+
accountId: context.accountId,
|
|
662
|
+
action,
|
|
663
|
+
}));
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (action === 'update_context') {
|
|
667
|
+
const worldContextText = normalizeText(params.worldContextText, null);
|
|
668
|
+
if (!worldContextText) requireManageWorldField('worldContextText');
|
|
669
|
+
const payload = await plugin.runtime.productShell.moderation.manageWorld({
|
|
670
|
+
...context,
|
|
671
|
+
worldId,
|
|
672
|
+
mode: 'patch',
|
|
673
|
+
changes: {
|
|
674
|
+
worldContextText,
|
|
675
|
+
...(normalizeText(params.displayName, null) ? { displayName: normalizeText(params.displayName, null) } : {}),
|
|
676
|
+
},
|
|
677
|
+
});
|
|
678
|
+
return buildToolResult(projectToolManageWorldActionResponse(payload, {
|
|
679
|
+
accountId: context.accountId,
|
|
680
|
+
action,
|
|
681
|
+
}));
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const statusByAction = {
|
|
685
|
+
pause: 'paused',
|
|
686
|
+
close: 'closed',
|
|
687
|
+
resume: 'enabled',
|
|
614
688
|
};
|
|
689
|
+
const status = statusByAction[action] || null;
|
|
615
690
|
const payload = await plugin.runtime.productShell.moderation.manageWorld({
|
|
616
691
|
...context,
|
|
617
|
-
worldId
|
|
692
|
+
worldId,
|
|
618
693
|
mode: 'patch',
|
|
619
|
-
|
|
620
|
-
|
|
694
|
+
status,
|
|
695
|
+
enabled: action === 'resume',
|
|
621
696
|
});
|
|
622
|
-
return buildToolResult(
|
|
697
|
+
return buildToolResult(projectToolManageWorldActionResponse(payload, {
|
|
698
|
+
accountId: context.accountId,
|
|
699
|
+
action,
|
|
700
|
+
}));
|
|
623
701
|
},
|
|
624
702
|
},
|
|
625
703
|
{
|
|
@@ -782,6 +860,54 @@ function buildRegisteredTools(api, plugin) {
|
|
|
782
860
|
return buildToolResult(projectToolChatRequestMutationResponse(payload, { accountId: context.accountId }));
|
|
783
861
|
},
|
|
784
862
|
},
|
|
863
|
+
{
|
|
864
|
+
name: 'claworld_reject_chat_request',
|
|
865
|
+
label: 'Claworld Reject Chat Request',
|
|
866
|
+
description: 'Canonical rejection tool for one inbound chat request. Use this when the current account explicitly declines the request instead of accepting it.',
|
|
867
|
+
metadata: buildToolMetadata({
|
|
868
|
+
category: 'chat_request',
|
|
869
|
+
usageNotes: [
|
|
870
|
+
'Use the chatRequestId returned by claworld_list_chat_requests.',
|
|
871
|
+
'Use only for inbound requests that the current account wants to reject.',
|
|
872
|
+
],
|
|
873
|
+
examples: [
|
|
874
|
+
{
|
|
875
|
+
title: 'Reject one inbound request',
|
|
876
|
+
input: {
|
|
877
|
+
accountId: 'claworld',
|
|
878
|
+
chatRequestId: 'req_demo_1',
|
|
879
|
+
},
|
|
880
|
+
outcome: 'Marks the request rejected and returns the closed request projection.',
|
|
881
|
+
},
|
|
882
|
+
],
|
|
883
|
+
}),
|
|
884
|
+
parameters: objectParam({
|
|
885
|
+
description: 'Reject one inbound chat request for the current account.',
|
|
886
|
+
required: ['accountId', 'chatRequestId'],
|
|
887
|
+
properties: {
|
|
888
|
+
accountId: accountIdProperty,
|
|
889
|
+
chatRequestId: stringParam({
|
|
890
|
+
description: 'Canonical chat request id returned by claworld_list_chat_requests.',
|
|
891
|
+
minLength: 1,
|
|
892
|
+
examples: ['req_demo_1'],
|
|
893
|
+
}),
|
|
894
|
+
},
|
|
895
|
+
examples: [
|
|
896
|
+
{
|
|
897
|
+
accountId: 'claworld',
|
|
898
|
+
chatRequestId: 'req_demo_1',
|
|
899
|
+
},
|
|
900
|
+
],
|
|
901
|
+
}),
|
|
902
|
+
async execute(_toolCallId, params = {}) {
|
|
903
|
+
const context = await resolveToolContext(api, plugin, params);
|
|
904
|
+
const payload = await plugin.helpers.social.rejectChatRequest({
|
|
905
|
+
...context,
|
|
906
|
+
chatRequestId: params.chatRequestId,
|
|
907
|
+
});
|
|
908
|
+
return buildToolResult(projectToolChatRequestMutationResponse(payload, { accountId: context.accountId }));
|
|
909
|
+
},
|
|
910
|
+
},
|
|
785
911
|
{
|
|
786
912
|
name: 'claworld_submit_feedback',
|
|
787
913
|
label: 'Claworld Submit Feedback',
|
|
@@ -564,7 +564,7 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
564
564
|
config,
|
|
565
565
|
agentId,
|
|
566
566
|
credential = null,
|
|
567
|
-
clientVersion = 'claworld-plugin/0.2.
|
|
567
|
+
clientVersion = 'claworld-plugin/0.2.8',
|
|
568
568
|
sessionTarget,
|
|
569
569
|
fallbackTarget,
|
|
570
570
|
} = {}) {
|
|
@@ -978,6 +978,7 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
978
978
|
stage: 'reply_fallback',
|
|
979
979
|
deliveryId: envelope.deliveryId,
|
|
980
980
|
sessionKey: envelope.sessionKey,
|
|
981
|
+
fallbackFrom: error?.code || error?.message || null,
|
|
981
982
|
}),
|
|
982
983
|
});
|
|
983
984
|
}
|
|
@@ -1151,6 +1152,18 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
1151
1152
|
return result;
|
|
1152
1153
|
}
|
|
1153
1154
|
|
|
1155
|
+
async rejectChatRequest(requestId, { actorAgentId, ...options } = {}) {
|
|
1156
|
+
return await this.requestJson(`/v1/chat-requests/${requestId}/reject`, {
|
|
1157
|
+
method: 'POST',
|
|
1158
|
+
headers: buildRuntimeAuthHeaders(this.runtimeConfig, { 'content-type': 'application/json' }),
|
|
1159
|
+
body: JSON.stringify({ actorAgentId, ...options }),
|
|
1160
|
+
}, {
|
|
1161
|
+
code: 'relay_request_reject_failed',
|
|
1162
|
+
message: 'failed to reject relay chat request',
|
|
1163
|
+
publicMessage: 'failed to reject relay chat request',
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1154
1167
|
async deliverMessage({ fromAgentId, toAddress, payload = {}, conversation = {} } = {}) {
|
|
1155
1168
|
return await this.requestJson('/v1/messages', {
|
|
1156
1169
|
method: 'POST',
|
|
@@ -391,7 +391,7 @@ export function projectToolOwnedWorldsResponse(payload = {}, { accountId = null
|
|
|
391
391
|
? payload.items.map((world) => ({
|
|
392
392
|
worldId: world.worldId,
|
|
393
393
|
displayName: world.displayName,
|
|
394
|
-
|
|
394
|
+
worldContextText: normalizeText(world.worldContextText, null),
|
|
395
395
|
enabled: normalizeOptionalBoolean(world.enabled, null),
|
|
396
396
|
status: normalizeText(world.status, null),
|
|
397
397
|
worldRole: projectWorldRole(world.worldRole, null),
|
|
@@ -4,6 +4,7 @@ export const CLAWORLD_CHAT_REQUEST_TOOL_NAMES = Object.freeze([
|
|
|
4
4
|
'claworld_request_chat',
|
|
5
5
|
'claworld_chat_inbox',
|
|
6
6
|
'claworld_accept_chat_request',
|
|
7
|
+
'claworld_reject_chat_request',
|
|
7
8
|
]);
|
|
8
9
|
|
|
9
10
|
export const CLAWORLD_BOOTSTRAP_TOOL_NAMES = Object.freeze([
|
|
@@ -22,11 +23,11 @@ export const CLAWORLD_WORLD_TOOL_NAMES = Object.freeze([
|
|
|
22
23
|
|
|
23
24
|
export const CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES = Object.freeze([
|
|
24
25
|
'claworld_create_world',
|
|
25
|
-
'claworld_list_owned_worlds',
|
|
26
26
|
'claworld_manage_world',
|
|
27
27
|
]);
|
|
28
28
|
|
|
29
29
|
export const CLAWORLD_COMPATIBILITY_TOOL_NAMES = Object.freeze([
|
|
30
|
+
'claworld_list_owned_worlds',
|
|
30
31
|
'claworld_prepare_world_join',
|
|
31
32
|
'claworld_search_world',
|
|
32
33
|
]);
|
|
@@ -287,6 +287,7 @@ export async function manageModeratedWorld({
|
|
|
287
287
|
mode = 'get',
|
|
288
288
|
changes = null,
|
|
289
289
|
enabled = null,
|
|
290
|
+
status = null,
|
|
290
291
|
fetchImpl,
|
|
291
292
|
logger = console,
|
|
292
293
|
} = {}) {
|
|
@@ -340,6 +341,7 @@ export async function manageModeratedWorld({
|
|
|
340
341
|
agentId: resolvedAgentId,
|
|
341
342
|
...(changes && typeof changes === 'object' ? { changes } : {}),
|
|
342
343
|
...(enabled == null ? {} : { enabled }),
|
|
344
|
+
...(normalizeText(status, null) ? { status: normalizeText(status, null) } : {}),
|
|
343
345
|
}),
|
|
344
346
|
});
|
|
345
347
|
|
|
@@ -12,6 +12,36 @@ function normalizeBoolean(value, fallback = false) {
|
|
|
12
12
|
return fallback;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
const OWNER_WORLD_STATUSES = new Set(['draft', 'enabled', 'paused', 'closed', 'disabled']);
|
|
16
|
+
|
|
17
|
+
function normalizeOwnerWorldStatus(value, fallback = null) {
|
|
18
|
+
const normalized = normalizeText(value, fallback);
|
|
19
|
+
return OWNER_WORLD_STATUSES.has(normalized) ? normalized : fallback;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function inferEnabledFromOwnerWorldStatus(status, fallback = null) {
|
|
23
|
+
const normalizedStatus = normalizeOwnerWorldStatus(status, null);
|
|
24
|
+
if (!normalizedStatus) return fallback;
|
|
25
|
+
return normalizedStatus === 'enabled';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function projectOwnerWorldMetaStatus(status, enabled) {
|
|
29
|
+
const normalizedStatus = normalizeOwnerWorldStatus(status, enabled === true ? 'enabled' : 'draft');
|
|
30
|
+
switch (normalizedStatus) {
|
|
31
|
+
case 'enabled':
|
|
32
|
+
return 'creator_enabled';
|
|
33
|
+
case 'paused':
|
|
34
|
+
return 'creator_paused';
|
|
35
|
+
case 'closed':
|
|
36
|
+
return 'creator_closed';
|
|
37
|
+
case 'disabled':
|
|
38
|
+
return 'creator_disabled';
|
|
39
|
+
case 'draft':
|
|
40
|
+
default:
|
|
41
|
+
return 'creator_draft';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
15
45
|
function summarizeWorldContextText(worldContextText, fallback = null) {
|
|
16
46
|
const normalized = normalizeText(worldContextText, null);
|
|
17
47
|
if (!normalized) return fallback;
|
|
@@ -154,7 +184,7 @@ function buildWorldRecord({
|
|
|
154
184
|
status = null,
|
|
155
185
|
existingMetrics = null,
|
|
156
186
|
} = {}) {
|
|
157
|
-
const resolvedStatus = status
|
|
187
|
+
const resolvedStatus = normalizeOwnerWorldStatus(status, enabled ? 'enabled' : 'draft');
|
|
158
188
|
const participantContextField = buildDefaultEntryProfileField();
|
|
159
189
|
const resolvedWorldContextText = buildWorldContextText({
|
|
160
190
|
worldId,
|
|
@@ -186,7 +216,7 @@ function buildWorldRecord({
|
|
|
186
216
|
matching: buildMatchingStrategy(),
|
|
187
217
|
conversationTemplate: buildConversationTemplate(null, null),
|
|
188
218
|
meta: {
|
|
189
|
-
status: resolvedStatus
|
|
219
|
+
status: projectOwnerWorldMetaStatus(resolvedStatus, enabled),
|
|
190
220
|
persistence: 'store',
|
|
191
221
|
},
|
|
192
222
|
creatorAgentId,
|
|
@@ -314,6 +344,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
314
344
|
displayName,
|
|
315
345
|
worldContextText,
|
|
316
346
|
enabled = false,
|
|
347
|
+
status = null,
|
|
317
348
|
} = {}) {
|
|
318
349
|
const storeBacked = assertStore();
|
|
319
350
|
const resolvedOwnerAgentId = assertActorAgent(ownerAgentId || creatorAgentId);
|
|
@@ -330,6 +361,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
330
361
|
summary: summarizeWorldContextText(resolvedWorldContextText, resolvedDisplayName),
|
|
331
362
|
worldContextText: resolvedWorldContextText,
|
|
332
363
|
enabled: normalizeBoolean(enabled, false),
|
|
364
|
+
status: normalizeOwnerWorldStatus(status, normalizeBoolean(enabled, false) ? 'enabled' : 'draft'),
|
|
333
365
|
});
|
|
334
366
|
|
|
335
367
|
const created = await storeBacked.createWorldConfig(worldRecord);
|
|
@@ -367,10 +399,14 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
367
399
|
worldRole: authorization.worldRole,
|
|
368
400
|
});
|
|
369
401
|
},
|
|
370
|
-
async manageWorld({ actorAgentId, creatorAgentId, worldId, changes = null, enabled = null } = {}) {
|
|
402
|
+
async manageWorld({ actorAgentId, creatorAgentId, worldId, changes = null, enabled = null, status = null } = {}) {
|
|
371
403
|
const storeBacked = assertStore();
|
|
372
404
|
const resolvedActorAgentId = assertActorAgent(actorAgentId || creatorAgentId);
|
|
373
405
|
const hasChanges = changes && typeof changes === 'object' && !Array.isArray(changes);
|
|
406
|
+
const normalizedStatus = normalizeOwnerWorldStatus(status, null);
|
|
407
|
+
const resolvedEnabled = normalizedStatus != null
|
|
408
|
+
? inferEnabledFromOwnerWorldStatus(normalizedStatus, null)
|
|
409
|
+
: (enabled == null ? null : normalizeBoolean(enabled, false));
|
|
374
410
|
|
|
375
411
|
const authorization = requireWorldOwner({
|
|
376
412
|
worldId,
|
|
@@ -378,7 +414,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
378
414
|
});
|
|
379
415
|
|
|
380
416
|
const existingWorld = authorization.world;
|
|
381
|
-
if (!hasChanges &&
|
|
417
|
+
if (!hasChanges && resolvedEnabled == null && normalizedStatus == null) {
|
|
382
418
|
return projectManagedWorld(storeBacked, existingWorld, {
|
|
383
419
|
worldRole: authorization.worldRole,
|
|
384
420
|
});
|
|
@@ -397,20 +433,24 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
397
433
|
displayName: nextDisplayName,
|
|
398
434
|
summary: summarizeWorldContextText(nextWorldContextText, nextDisplayName),
|
|
399
435
|
worldContextText: nextWorldContextText,
|
|
400
|
-
enabled:
|
|
401
|
-
status:
|
|
402
|
-
|
|
403
|
-
|
|
436
|
+
enabled: resolvedEnabled == null ? existingWorld.enabled === true : resolvedEnabled,
|
|
437
|
+
status: normalizedStatus || (
|
|
438
|
+
resolvedEnabled == null
|
|
439
|
+
? existingWorld.status
|
|
440
|
+
: (resolvedEnabled ? 'enabled' : 'disabled')
|
|
441
|
+
),
|
|
404
442
|
existingMetrics: existingWorld.metrics || null,
|
|
405
443
|
});
|
|
406
|
-
} else if (
|
|
444
|
+
} else if (resolvedEnabled != null || normalizedStatus != null) {
|
|
445
|
+
const nextEnabled = resolvedEnabled == null ? existingWorld.enabled === true : resolvedEnabled;
|
|
446
|
+
const nextStatus = normalizedStatus || (nextEnabled ? 'enabled' : 'disabled');
|
|
407
447
|
nextRecord = {
|
|
408
448
|
...existingWorld,
|
|
409
|
-
enabled:
|
|
410
|
-
status:
|
|
449
|
+
enabled: nextEnabled,
|
|
450
|
+
status: nextStatus,
|
|
411
451
|
meta: {
|
|
412
452
|
...(existingWorld.meta || {}),
|
|
413
|
-
status:
|
|
453
|
+
status: projectOwnerWorldMetaStatus(nextStatus, nextEnabled),
|
|
414
454
|
},
|
|
415
455
|
};
|
|
416
456
|
}
|
|
@@ -393,6 +393,7 @@ export function registerWorldRoutes(
|
|
|
393
393
|
worldId: req.params.worldId,
|
|
394
394
|
changes: req.body?.changes || null,
|
|
395
395
|
enabled: Object.prototype.hasOwnProperty.call(req.body || {}, 'enabled') ? req.body.enabled : null,
|
|
396
|
+
status: req.body?.status || null,
|
|
396
397
|
});
|
|
397
398
|
res.json(result);
|
|
398
399
|
} catch (error) {
|