@xfxstudio/claworld 0.2.11 → 0.2.13
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/README.md +45 -19
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -5
- package/skills/claworld-help/SKILL.md +84 -83
- package/skills/claworld-join-and-chat/SKILL.md +1 -1
- package/src/openclaw/plugin/claworld-channel-plugin.js +94 -9
- package/src/openclaw/plugin/onboarding.js +128 -103
- package/src/openclaw/plugin/register.js +210 -36
- package/src/openclaw/runtime/tool-inventory.js +1 -2
- package/src/product-shell/agent-cards/card-routes.js +64 -0
- package/src/product-shell/agent-cards/card-service.js +287 -0
- package/src/product-shell/agent-cards/spec-builder.js +167 -0
- package/src/product-shell/agent-cards/storage/image-host-storage.js +192 -0
- package/src/product-shell/agent-cards/storage/local-public-storage.js +74 -0
- package/src/product-shell/agent-cards/svg-renderer.js +325 -0
- package/src/product-shell/agent-cards/template-registry.js +131 -0
- package/src/product-shell/index.js +24 -3
- package/src/product-shell/onboarding/onboarding-service.js +27 -25
- package/src/product-shell/profile/profile-service.js +142 -0
- package/src/product-shell/profile/public-identity-routes.js +100 -0
- package/src/product-shell/profile/public-identity-service.js +4 -2
- package/bin/claworld.mjs +0 -9
- package/src/openclaw/installer/cli.js +0 -406
- package/src/openclaw/installer/core.js +0 -2122
- package/src/openclaw/installer/doctor.js +0 -876
- package/src/openclaw/installer/workspace-contract.js +0 -427
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CLAWORLD_ACCOUNT_ID,
|
|
3
|
-
DEFAULT_CLAWORLD_SERVER_URL,
|
|
4
3
|
applyClaworldManagedRuntimeConfig,
|
|
5
4
|
ensureObject,
|
|
6
5
|
normalizeText,
|
|
@@ -11,15 +10,11 @@ import {
|
|
|
11
10
|
inspectClaworldChannelAccount,
|
|
12
11
|
listClaworldAccountIds,
|
|
13
12
|
} from './config-schema.js';
|
|
14
|
-
import {
|
|
15
|
-
buildManagedOnboardingStatus as buildClaworldOnboardingStatus,
|
|
16
|
-
inspectManagedClaworldInstall,
|
|
17
|
-
seedManagedWorkspace as ensureManagedWorkspaceSeed,
|
|
18
|
-
} from '../installer/core.js';
|
|
19
13
|
|
|
20
14
|
function collectUnsupportedSetupFlags(input = {}) {
|
|
21
15
|
const unsupported = [];
|
|
22
16
|
const flagMap = [
|
|
17
|
+
['appToken', '--app-token'],
|
|
23
18
|
['token', '--token'],
|
|
24
19
|
['tokenFile', '--token-file'],
|
|
25
20
|
['botToken', '--bot-token'],
|
|
@@ -54,89 +49,143 @@ function collectUnsupportedSetupFlags(input = {}) {
|
|
|
54
49
|
return unsupported;
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
function validateClaworldSetupInput({
|
|
52
|
+
export function validateClaworldSetupInput({ input = {} } = {}) {
|
|
58
53
|
const unsupportedFlags = collectUnsupportedSetupFlags(input);
|
|
59
54
|
if (unsupportedFlags.length > 0) {
|
|
60
55
|
return (
|
|
61
|
-
'Claworld setup only supports
|
|
62
|
-
`Unsupported flag(s): ${unsupportedFlags.join(', ')}.`
|
|
56
|
+
'Claworld host-native setup only supports an optional local account label and --http-url/--url overrides. '
|
|
57
|
+
+ `Unsupported flag(s): ${unsupportedFlags.join(', ')}.`
|
|
63
58
|
);
|
|
64
59
|
}
|
|
65
60
|
|
|
66
|
-
const inspected = inspectClaworldChannelAccount(cfg, accountId);
|
|
67
|
-
const appToken = normalizeText(
|
|
68
|
-
input.appToken,
|
|
69
|
-
normalizeText(inspected?.appToken, null),
|
|
70
|
-
);
|
|
71
|
-
|
|
72
61
|
const serverUrl = normalizeText(input.httpUrl, normalizeText(input.url, null));
|
|
73
|
-
if (serverUrl) {
|
|
74
|
-
|
|
75
|
-
const parsed = new URL(serverUrl);
|
|
76
|
-
if (!['http:', 'https:', 'ws:', 'wss:'].includes(parsed.protocol)) {
|
|
77
|
-
return `Unsupported Claworld server URL protocol: ${parsed.protocol}`;
|
|
78
|
-
}
|
|
79
|
-
} catch {
|
|
80
|
-
return `Invalid Claworld server URL: ${serverUrl}`;
|
|
81
|
-
}
|
|
62
|
+
if (!serverUrl) {
|
|
63
|
+
return null;
|
|
82
64
|
}
|
|
83
65
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
),
|
|
92
|
-
),
|
|
93
|
-
);
|
|
94
|
-
if (!appToken && !registrationDisplayName) {
|
|
95
|
-
return 'Claworld public display name is required unless you already have an appToken. Use --name <display-name> or --app-token <token>.';
|
|
66
|
+
try {
|
|
67
|
+
const parsed = new URL(serverUrl);
|
|
68
|
+
if (!['http:', 'https:', 'ws:', 'wss:'].includes(parsed.protocol)) {
|
|
69
|
+
return `Unsupported Claworld server URL protocol: ${parsed.protocol}`;
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
return `Invalid Claworld server URL: ${serverUrl}`;
|
|
96
73
|
}
|
|
97
74
|
|
|
98
75
|
return null;
|
|
99
76
|
}
|
|
100
77
|
|
|
101
|
-
function
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
78
|
+
function findAgentEntry(config = {}, agentId) {
|
|
79
|
+
const normalizedAgentId = normalizeText(agentId, null);
|
|
80
|
+
if (!normalizedAgentId) return null;
|
|
81
|
+
const list = Array.isArray(config?.agents?.list) ? config.agents.list : [];
|
|
82
|
+
return list
|
|
83
|
+
.map((entry) => ensureObject(entry))
|
|
84
|
+
.find((entry) => entry.id === normalizedAgentId) || null;
|
|
85
|
+
}
|
|
109
86
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
87
|
+
function hasClaworldBinding(config = {}, { agentId, accountId } = {}) {
|
|
88
|
+
const normalizedAgentId = normalizeText(agentId, null);
|
|
89
|
+
const normalizedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
|
|
90
|
+
const resolvedDefaultAccountId = defaultClaworldAccountId(config) || DEFAULT_CLAWORLD_ACCOUNT_ID;
|
|
91
|
+
const bindings = Array.isArray(config?.bindings) ? config.bindings : [];
|
|
92
|
+
return bindings.some((binding) => {
|
|
93
|
+
const candidate = ensureObject(binding);
|
|
94
|
+
const match = ensureObject(candidate.match);
|
|
95
|
+
const bindingChannel = normalizeText(match.channel, null);
|
|
96
|
+
const bindingAccountId = normalizeText(match.accountId, null);
|
|
97
|
+
const bindingAgentId = normalizeText(candidate.agentId, null);
|
|
98
|
+
if (bindingChannel !== 'claworld') return false;
|
|
99
|
+
if (normalizedAgentId && bindingAgentId !== normalizedAgentId) return false;
|
|
100
|
+
if (bindingAccountId === normalizedAccountId) return true;
|
|
101
|
+
return !bindingAccountId && resolvedDefaultAccountId === normalizedAccountId;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isRelayBootstrapReady(account = {}) {
|
|
106
|
+
return Boolean(
|
|
107
|
+
account?.configured
|
|
108
|
+
&& normalizeText(account?.appToken, null),
|
|
116
109
|
);
|
|
117
|
-
return currentDisplayName
|
|
118
|
-
? { name: currentDisplayName }
|
|
119
|
-
: {};
|
|
120
110
|
}
|
|
121
111
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
112
|
+
export function inspectManagedClaworldInstall({
|
|
113
|
+
cfg = {},
|
|
114
|
+
accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
|
|
115
|
+
input = {},
|
|
116
|
+
overrides = {},
|
|
117
|
+
} = {}) {
|
|
118
|
+
const configuredAccountIds = listClaworldAccountIds(cfg);
|
|
119
|
+
const hasAnyConfig = configuredAccountIds.length > 0 || cfg?.channels?.claworld != null;
|
|
120
|
+
const managedOptions = resolveClaworldManagedRuntimeOptions({
|
|
121
|
+
cfg,
|
|
122
|
+
accountId,
|
|
123
|
+
input,
|
|
124
|
+
overrides,
|
|
125
|
+
});
|
|
126
|
+
const managedAgentPresent = Boolean(findAgentEntry(cfg, managedOptions.agentId));
|
|
127
|
+
const managedBindingPresent = hasClaworldBinding(cfg, managedOptions);
|
|
128
|
+
const managedAccountPresent = configuredAccountIds.includes(managedOptions.accountId);
|
|
129
|
+
const accountStatus = managedAccountPresent
|
|
130
|
+
? inspectClaworldChannelAccount(cfg, managedOptions.accountId)
|
|
131
|
+
: inspectClaworldChannelAccount({}, managedOptions.accountId);
|
|
132
|
+
const activationReady = isRelayBootstrapReady(accountStatus);
|
|
133
|
+
const setupReady = Boolean(
|
|
134
|
+
managedAccountPresent
|
|
135
|
+
&& managedBindingPresent
|
|
136
|
+
&& (managedOptions.manageAgentEntry !== true || managedAgentPresent)
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
let statusLabel = 'needs setup';
|
|
140
|
+
let selectionHint = 'remote relay world channel';
|
|
141
|
+
let quickstartScore = 5;
|
|
142
|
+
|
|
143
|
+
if (setupReady && activationReady) {
|
|
144
|
+
statusLabel = 'configured';
|
|
145
|
+
selectionHint = 'configured · ready';
|
|
146
|
+
quickstartScore = 2;
|
|
147
|
+
} else if (setupReady) {
|
|
148
|
+
statusLabel = 'configured (activation pending)';
|
|
149
|
+
selectionHint = 'configured · activation pending';
|
|
150
|
+
quickstartScore = 3;
|
|
151
|
+
} else if (managedAccountPresent && !managedBindingPresent) {
|
|
152
|
+
statusLabel = 'configured (binding pending)';
|
|
153
|
+
selectionHint = 'configured · binding pending';
|
|
154
|
+
quickstartScore = 4;
|
|
155
|
+
} else if (hasAnyConfig) {
|
|
156
|
+
statusLabel = 'configured (refresh recommended)';
|
|
157
|
+
selectionHint = 'configured · refresh recommended';
|
|
158
|
+
quickstartScore = 4;
|
|
126
159
|
}
|
|
127
160
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
161
|
+
return {
|
|
162
|
+
hasAnyConfig,
|
|
163
|
+
configuredAccountIds,
|
|
164
|
+
defaultAccountId: defaultClaworldAccountId(cfg) || null,
|
|
165
|
+
managedOptions,
|
|
166
|
+
managedAccountPresent,
|
|
167
|
+
managedAgentPresent,
|
|
168
|
+
managedBindingPresent,
|
|
169
|
+
accountStatus,
|
|
170
|
+
activationReady,
|
|
171
|
+
setupReady,
|
|
172
|
+
statusLabel,
|
|
173
|
+
selectionHint,
|
|
174
|
+
quickstartScore,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
137
177
|
|
|
178
|
+
export function buildClaworldOnboardingStatus({
|
|
179
|
+
cfg = {},
|
|
180
|
+
accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
|
|
181
|
+
} = {}) {
|
|
182
|
+
const inspection = inspectManagedClaworldInstall({ cfg, accountId });
|
|
138
183
|
return {
|
|
139
|
-
|
|
184
|
+
configured: inspection.setupReady,
|
|
185
|
+
statusLines: [`Claworld: ${inspection.statusLabel}`],
|
|
186
|
+
selectionHint: inspection.selectionHint,
|
|
187
|
+
quickstartScore: inspection.quickstartScore,
|
|
188
|
+
activationReady: inspection.activationReady,
|
|
140
189
|
};
|
|
141
190
|
}
|
|
142
191
|
|
|
@@ -178,7 +227,7 @@ function resolveManagedOptionsFromContext({ cfg = {}, accountId = null, input =
|
|
|
178
227
|
input: resolvedInput,
|
|
179
228
|
overrides: {
|
|
180
229
|
...overrides,
|
|
181
|
-
...(normalizeText(normalizedInput.name, null) ? {
|
|
230
|
+
...(normalizeText(normalizedInput.name, null) ? { name: normalizedInput.name } : {}),
|
|
182
231
|
},
|
|
183
232
|
});
|
|
184
233
|
}
|
|
@@ -192,19 +241,14 @@ async function applyManagedOnboardingConfig({
|
|
|
192
241
|
} = {}) {
|
|
193
242
|
const managedOptions = resolveManagedOptionsFromContext({ cfg, accountId, input });
|
|
194
243
|
const next = applyClaworldManagedRuntimeConfig(cfg, managedOptions);
|
|
195
|
-
if (managedOptions.manageWorkspace) {
|
|
196
|
-
await ensureManagedWorkspaceSeed(managedOptions);
|
|
197
|
-
}
|
|
198
244
|
|
|
199
245
|
const noteLines = [
|
|
200
246
|
`Bound local agent/account: ${managedOptions.agentId}`,
|
|
201
247
|
`Remote backend: ${managedOptions.serverUrl}`,
|
|
202
248
|
managedOptions.appToken
|
|
203
249
|
? 'Activation state: ready via configured appToken'
|
|
204
|
-
: 'Activation state: pending until
|
|
205
|
-
|
|
206
|
-
? 'This flow refreshes plugin-side config and the dedicated claworld workspace contract. It does not start a backend service.'
|
|
207
|
-
: 'This flow refreshes plugin-side config and binds claworld onto the existing local agent. It does not start a backend service.',
|
|
250
|
+
: 'Activation state: pending until claworld_profile(action=update_identity) runs',
|
|
251
|
+
'This flow refreshes plugin-side config and binds claworld onto the selected local agent. It does not run installer commands or start a backend service.',
|
|
208
252
|
];
|
|
209
253
|
await prompter.note(
|
|
210
254
|
noteLines.join('\n'),
|
|
@@ -230,7 +274,7 @@ export const claworldSetupAdapter = {
|
|
|
230
274
|
return accountIds.length > 0 ? defaultClaworldAccountId(cfg) : DEFAULT_CLAWORLD_ACCOUNT_ID;
|
|
231
275
|
},
|
|
232
276
|
applyAccountName: ({ cfg, accountId, name }) => applyManagedAccountName({ cfg, accountId, name }),
|
|
233
|
-
validateInput: ({
|
|
277
|
+
validateInput: ({ input }) => validateClaworldSetupInput({ input }),
|
|
234
278
|
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
235
279
|
const managedOptions = resolveManagedOptionsFromContext({ cfg, accountId, input });
|
|
236
280
|
return applyClaworldManagedRuntimeConfig(cfg, managedOptions).config;
|
|
@@ -249,39 +293,20 @@ export const claworldOnboardingAdapter = {
|
|
|
249
293
|
}),
|
|
250
294
|
};
|
|
251
295
|
},
|
|
252
|
-
configure: async ({ cfg, prompter, accountOverrides }) =>
|
|
253
|
-
|
|
254
|
-
cfg,
|
|
255
|
-
prompter,
|
|
256
|
-
accountId: accountOverrides?.claworld,
|
|
257
|
-
});
|
|
258
|
-
return await applyManagedOnboardingConfig({
|
|
296
|
+
configure: async ({ cfg, prompter, accountOverrides }) =>
|
|
297
|
+
applyManagedOnboardingConfig({
|
|
259
298
|
cfg,
|
|
260
299
|
prompter,
|
|
261
300
|
accountId: accountOverrides?.claworld,
|
|
262
301
|
phase: 'setup',
|
|
263
|
-
input,
|
|
264
|
-
})
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const input = await collectManagedIdentityInput({
|
|
268
|
-
cfg,
|
|
269
|
-
prompter,
|
|
270
|
-
accountId: accountOverrides?.claworld,
|
|
271
|
-
});
|
|
272
|
-
return await applyManagedOnboardingConfig({
|
|
302
|
+
input: {},
|
|
303
|
+
}),
|
|
304
|
+
configureWhenConfigured: async ({ cfg, prompter, accountOverrides }) =>
|
|
305
|
+
applyManagedOnboardingConfig({
|
|
273
306
|
cfg,
|
|
274
307
|
prompter,
|
|
275
308
|
accountId: accountOverrides?.claworld,
|
|
276
309
|
phase: 'refresh',
|
|
277
|
-
input,
|
|
278
|
-
})
|
|
279
|
-
},
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
export {
|
|
283
|
-
buildClaworldOnboardingStatus,
|
|
284
|
-
ensureManagedWorkspaceSeed,
|
|
285
|
-
inspectManagedClaworldInstall,
|
|
286
|
-
validateClaworldSetupInput,
|
|
310
|
+
input: {},
|
|
311
|
+
}),
|
|
287
312
|
};
|
|
@@ -239,6 +239,17 @@ function integerParam({
|
|
|
239
239
|
};
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
function booleanParam({
|
|
243
|
+
description = null,
|
|
244
|
+
defaultValue = null,
|
|
245
|
+
} = {}) {
|
|
246
|
+
return {
|
|
247
|
+
type: 'boolean',
|
|
248
|
+
...(description ? { description } : {}),
|
|
249
|
+
...(typeof defaultValue === 'boolean' ? { default: defaultValue } : {}),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
242
253
|
function objectParam({
|
|
243
254
|
description = null,
|
|
244
255
|
properties = {},
|
|
@@ -337,6 +348,118 @@ function projectToolManageWorldActionResponse(payload = {}, { accountId = null,
|
|
|
337
348
|
};
|
|
338
349
|
}
|
|
339
350
|
|
|
351
|
+
const PROFILE_ACTIONS = Object.freeze([
|
|
352
|
+
'view',
|
|
353
|
+
'update_identity',
|
|
354
|
+
]);
|
|
355
|
+
|
|
356
|
+
function normalizeProfileAction(value, fallback = null) {
|
|
357
|
+
const normalized = normalizeText(value, fallback);
|
|
358
|
+
return PROFILE_ACTIONS.includes(normalized) ? normalized : fallback;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function inferProfileAction(params = {}) {
|
|
362
|
+
const explicitAction = normalizeProfileAction(params.action, null);
|
|
363
|
+
if (explicitAction) return explicitAction;
|
|
364
|
+
if (normalizeText(params.displayName, null)) return 'update_identity';
|
|
365
|
+
return 'view';
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function projectToolPublicIdentity(payload = null) {
|
|
369
|
+
if (!payload || typeof payload !== 'object') return null;
|
|
370
|
+
return {
|
|
371
|
+
status: payload.status || null,
|
|
372
|
+
ready: payload.ready ?? null,
|
|
373
|
+
publicIdentity: payload.publicIdentity && typeof payload.publicIdentity === 'object'
|
|
374
|
+
? {
|
|
375
|
+
status: payload.publicIdentity.status || null,
|
|
376
|
+
displayIdentity: payload.publicIdentity.displayIdentity || null,
|
|
377
|
+
displayName: payload.publicIdentity.displayName || null,
|
|
378
|
+
code: payload.publicIdentity.code || null,
|
|
379
|
+
confirmedAt: payload.publicIdentity.confirmedAt || null,
|
|
380
|
+
updatedAt: payload.publicIdentity.updatedAt || null,
|
|
381
|
+
}
|
|
382
|
+
: null,
|
|
383
|
+
recommendedDisplayName: payload.recommendedDisplayName || null,
|
|
384
|
+
requiredAction: payload.requiredAction || null,
|
|
385
|
+
nextAction: payload.nextAction || null,
|
|
386
|
+
nextTool: payload.nextTool || null,
|
|
387
|
+
missingFields: Array.isArray(payload.missingFields) ? payload.missingFields : [],
|
|
388
|
+
feedbackSummary: payload.feedbackSummary && typeof payload.feedbackSummary === 'object'
|
|
389
|
+
? {
|
|
390
|
+
totalLikesReceived: Number(payload.feedbackSummary.totalLikesReceived || 0),
|
|
391
|
+
totalDislikesReceived: Number(payload.feedbackSummary.totalDislikesReceived || 0),
|
|
392
|
+
totalLikesGiven: Number(payload.feedbackSummary.totalLikesGiven || 0),
|
|
393
|
+
totalDislikesGiven: Number(payload.feedbackSummary.totalDislikesGiven || 0),
|
|
394
|
+
}
|
|
395
|
+
: null,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function projectToolShareCard(payload = null) {
|
|
400
|
+
const card = payload?.card && typeof payload.card === 'object' ? payload.card : null;
|
|
401
|
+
const imageUrl = normalizeText(card?.imageUrl, normalizeText(payload?.imageUrl, null));
|
|
402
|
+
const downloadUrl = normalizeText(card?.downloadUrl, normalizeText(payload?.downloadUrl, imageUrl));
|
|
403
|
+
const templateId = normalizeText(card?.templateId, normalizeText(payload?.templateId, null));
|
|
404
|
+
const expiresAt = normalizeText(card?.expiresAt, normalizeText(payload?.expiresAt, null));
|
|
405
|
+
const description = normalizeText(card?.description, normalizeText(payload?.description, null));
|
|
406
|
+
if (!imageUrl && !downloadUrl && !templateId && !expiresAt && !description) {
|
|
407
|
+
return {
|
|
408
|
+
status: normalizeText(payload?.status, 'unavailable'),
|
|
409
|
+
reason: normalizeText(payload?.reason, null),
|
|
410
|
+
message: normalizeText(payload?.message, null),
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
status: normalizeText(payload?.status, 'ready'),
|
|
415
|
+
imageUrl,
|
|
416
|
+
downloadUrl,
|
|
417
|
+
templateId,
|
|
418
|
+
expiresAt,
|
|
419
|
+
description,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function projectToolProfileResponse({
|
|
424
|
+
action = 'view',
|
|
425
|
+
accountId = null,
|
|
426
|
+
identityPayload = null,
|
|
427
|
+
shareCard = undefined,
|
|
428
|
+
runtimeActivation = null,
|
|
429
|
+
} = {}) {
|
|
430
|
+
const projectedIdentity = projectToolPublicIdentity(identityPayload);
|
|
431
|
+
const resolvedShareCard = shareCard !== undefined
|
|
432
|
+
? shareCard
|
|
433
|
+
: (identityPayload && Object.prototype.hasOwnProperty.call(identityPayload, 'shareCard')
|
|
434
|
+
? projectToolShareCard(identityPayload.shareCard)
|
|
435
|
+
: undefined);
|
|
436
|
+
const ready = projectedIdentity?.ready === true;
|
|
437
|
+
return {
|
|
438
|
+
action,
|
|
439
|
+
status: ready ? 'ready' : 'pending',
|
|
440
|
+
ready,
|
|
441
|
+
accountId: normalizeText(accountId, null),
|
|
442
|
+
...(projectedIdentity || {
|
|
443
|
+
publicIdentity: null,
|
|
444
|
+
recommendedDisplayName: null,
|
|
445
|
+
requiredAction: null,
|
|
446
|
+
nextAction: null,
|
|
447
|
+
nextTool: null,
|
|
448
|
+
missingFields: [],
|
|
449
|
+
feedbackSummary: null,
|
|
450
|
+
}),
|
|
451
|
+
...(resolvedShareCard !== undefined ? { shareCard: resolvedShareCard } : {}),
|
|
452
|
+
...(runtimeActivation ? { runtimeActivation } : {}),
|
|
453
|
+
...(action === 'update_identity'
|
|
454
|
+
? {
|
|
455
|
+
updated: resolvedShareCard && resolvedShareCard.status === 'ready'
|
|
456
|
+
? ['publicIdentity', 'shareCard']
|
|
457
|
+
: ['publicIdentity'],
|
|
458
|
+
}
|
|
459
|
+
: {}),
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
340
463
|
function buildRegisteredTools(api, plugin) {
|
|
341
464
|
const accountIdProperty = stringParam({
|
|
342
465
|
description: 'Claworld account id to execute the tool against. In managed installs this is usually the dedicated claworld account.',
|
|
@@ -1145,7 +1268,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1145
1268
|
reason: payload.reason || null,
|
|
1146
1269
|
requiredAction: publicIdentity?.requiredAction || (ready ? null : 'set_public_identity'),
|
|
1147
1270
|
nextAction: publicIdentity?.nextAction || (ready ? 'continue_claworld_flow' : 'set_public_identity'),
|
|
1148
|
-
nextTool: publicIdentity?.nextTool || (ready ? null : '
|
|
1271
|
+
nextTool: publicIdentity?.nextTool || (ready ? null : 'claworld_profile'),
|
|
1149
1272
|
missingFields: Array.isArray(publicIdentity?.missingFields) ? publicIdentity.missingFields : [],
|
|
1150
1273
|
accountId: payload.runtimeConfig?.accountId || accountId,
|
|
1151
1274
|
bindingSource: payload.bindingSource || null,
|
|
@@ -1186,59 +1309,110 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1186
1309
|
},
|
|
1187
1310
|
},
|
|
1188
1311
|
{
|
|
1189
|
-
name: '
|
|
1190
|
-
label: 'Claworld
|
|
1191
|
-
description: '
|
|
1312
|
+
name: 'claworld_profile',
|
|
1313
|
+
label: 'Claworld Profile',
|
|
1314
|
+
description: 'View or update the paired Claworld public profile. This surface covers public identity readiness and, when requested, generates a temporary public identity card for sharing.',
|
|
1192
1315
|
metadata: buildToolMetadata({
|
|
1193
|
-
category: '
|
|
1316
|
+
category: 'profile',
|
|
1194
1317
|
usageNotes: [
|
|
1195
|
-
'
|
|
1196
|
-
'Use
|
|
1318
|
+
'Default action is view; omit action to inspect the current public identity state.',
|
|
1319
|
+
'Use action=update_identity after the user confirms a public-facing display name.',
|
|
1320
|
+
'Set generateShareCard=true to return a temporary public identity card URL.',
|
|
1197
1321
|
],
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
category: 'bootstrap',
|
|
1218
|
-
usageNotes: [
|
|
1219
|
-
'Use after the user confirms a public-facing name.',
|
|
1220
|
-
'On first setup, this generates the stable public code and completes identity readiness.',
|
|
1322
|
+
examples: [
|
|
1323
|
+
{
|
|
1324
|
+
title: 'View the current profile state',
|
|
1325
|
+
input: {
|
|
1326
|
+
accountId: 'claworld',
|
|
1327
|
+
action: 'view',
|
|
1328
|
+
},
|
|
1329
|
+
outcome: 'Returns the current public identity and readiness state.',
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
title: 'Update public identity and return a share card',
|
|
1333
|
+
input: {
|
|
1334
|
+
accountId: 'claworld',
|
|
1335
|
+
action: 'update_identity',
|
|
1336
|
+
displayName: '小发发',
|
|
1337
|
+
generateShareCard: true,
|
|
1338
|
+
},
|
|
1339
|
+
outcome: 'Persists the display name, keeps the stable code, and returns a temporary share-card URL.',
|
|
1340
|
+
},
|
|
1221
1341
|
],
|
|
1222
1342
|
}),
|
|
1223
1343
|
parameters: objectParam({
|
|
1224
|
-
description: '
|
|
1225
|
-
required: ['accountId'
|
|
1344
|
+
description: 'View or update the public profile for one Claworld account.',
|
|
1345
|
+
required: ['accountId'],
|
|
1226
1346
|
properties: {
|
|
1227
1347
|
accountId: accountIdProperty,
|
|
1348
|
+
action: stringParam({
|
|
1349
|
+
description: 'Profile action. Defaults to view; inferred as update_identity when displayName is present.',
|
|
1350
|
+
enumValues: PROFILE_ACTIONS,
|
|
1351
|
+
examples: ['view', 'update_identity'],
|
|
1352
|
+
}),
|
|
1228
1353
|
displayName: stringParam({
|
|
1229
|
-
description: 'Public-facing display name. # is reserved and must not appear here.',
|
|
1354
|
+
description: 'Public-facing display name. Required for action=update_identity. # is reserved and must not appear here.',
|
|
1230
1355
|
minLength: 1,
|
|
1231
1356
|
examples: ['Moza', '小发发'],
|
|
1232
1357
|
}),
|
|
1358
|
+
generateShareCard: booleanParam({
|
|
1359
|
+
description: 'When true, return a temporary public identity card URL. Defaults to false for view and true for update_identity.',
|
|
1360
|
+
}),
|
|
1361
|
+
expiresInSeconds: integerParam({
|
|
1362
|
+
description: 'Optional temporary share-card TTL in seconds.',
|
|
1363
|
+
minimum: 1,
|
|
1364
|
+
examples: [7200],
|
|
1365
|
+
}),
|
|
1233
1366
|
},
|
|
1367
|
+
examples: [
|
|
1368
|
+
{
|
|
1369
|
+
accountId: 'claworld',
|
|
1370
|
+
action: 'view',
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
accountId: 'claworld',
|
|
1374
|
+
action: 'update_identity',
|
|
1375
|
+
displayName: '小发发',
|
|
1376
|
+
generateShareCard: true,
|
|
1377
|
+
},
|
|
1378
|
+
],
|
|
1234
1379
|
}),
|
|
1235
1380
|
async execute(_toolCallId, params = {}) {
|
|
1236
1381
|
const context = await resolveToolContext(api, plugin, params, { bindRuntime: false });
|
|
1237
|
-
const
|
|
1382
|
+
const action = inferProfileAction(params);
|
|
1383
|
+
const generateShareCard = typeof params.generateShareCard === 'boolean'
|
|
1384
|
+
? params.generateShareCard
|
|
1385
|
+
: action === 'update_identity';
|
|
1386
|
+
|
|
1387
|
+
if (action === 'update_identity') {
|
|
1388
|
+
const displayName = normalizeText(params.displayName, null);
|
|
1389
|
+
if (!displayName) {
|
|
1390
|
+
requireManageWorldField('displayName', 'displayName is required for action=update_identity');
|
|
1391
|
+
}
|
|
1392
|
+
const payload = await plugin.runtime.productShell.profile.updatePublicIdentity({
|
|
1393
|
+
...context,
|
|
1394
|
+
displayName,
|
|
1395
|
+
generateShareCard,
|
|
1396
|
+
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
1397
|
+
});
|
|
1398
|
+
return buildToolResult(projectToolProfileResponse({
|
|
1399
|
+
action,
|
|
1400
|
+
accountId: context.accountId,
|
|
1401
|
+
identityPayload: payload,
|
|
1402
|
+
runtimeActivation: payload?.runtimeActivation || null,
|
|
1403
|
+
}));
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
const payload = await plugin.runtime.productShell.profile.getPublicIdentity({
|
|
1238
1407
|
...context,
|
|
1239
|
-
|
|
1408
|
+
generateShareCard,
|
|
1409
|
+
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
1240
1410
|
});
|
|
1241
|
-
return buildToolResult(
|
|
1411
|
+
return buildToolResult(projectToolProfileResponse({
|
|
1412
|
+
action,
|
|
1413
|
+
accountId: context.accountId,
|
|
1414
|
+
identityPayload: payload,
|
|
1415
|
+
}));
|
|
1242
1416
|
},
|
|
1243
1417
|
},
|
|
1244
1418
|
].map((tool) => ({
|
|
@@ -12,8 +12,7 @@ export const CLAWORLD_BOOTSTRAP_TOOL_NAMES = Object.freeze([
|
|
|
12
12
|
]);
|
|
13
13
|
|
|
14
14
|
export const CLAWORLD_PROFILE_TOOL_NAMES = Object.freeze([
|
|
15
|
-
'
|
|
16
|
-
'claworld_update_public_identity',
|
|
15
|
+
'claworld_profile',
|
|
17
16
|
]);
|
|
18
17
|
|
|
19
18
|
export const CLAWORLD_FEEDBACK_TOOL_NAMES = Object.freeze([
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolveAuthenticatedAgentId } from '../../lib/http-auth.js';
|
|
2
|
+
|
|
3
|
+
function sendAgentCardError(res, error) {
|
|
4
|
+
const status = Number.isInteger(error?.status) ? error.status : 500;
|
|
5
|
+
if (error?.responseBody && typeof error.responseBody === 'object') {
|
|
6
|
+
return res.status(status).json(error.responseBody);
|
|
7
|
+
}
|
|
8
|
+
const code = typeof error?.code === 'string' ? error.code : 'internal_error';
|
|
9
|
+
return res.status(status).json({ error: code, message: error?.message || code });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function buildAbsoluteUrl(req, publicPath) {
|
|
13
|
+
return `${req.protocol}://${req.get('host')}${publicPath}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function registerAgentCardRoutes(app, { store, agentCardService }) {
|
|
17
|
+
app.get('/v1/meta/agent-cards', (_req, res) => {
|
|
18
|
+
res.json(agentCardService.getManifest());
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
app.post('/v1/agent-cards/render', async (req, res) => {
|
|
22
|
+
const resolvedAgent = resolveAuthenticatedAgentId({
|
|
23
|
+
store,
|
|
24
|
+
req,
|
|
25
|
+
providedAgentId: req.body?.agentId || null,
|
|
26
|
+
fieldName: 'agentId',
|
|
27
|
+
});
|
|
28
|
+
if (!resolvedAgent.ok) {
|
|
29
|
+
return res.status(resolvedAgent.status).json(resolvedAgent.body);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const result = await agentCardService.renderCard({
|
|
34
|
+
agentId: resolvedAgent.agentId,
|
|
35
|
+
publicHandle: req.body?.publicHandle,
|
|
36
|
+
displayName: req.body?.displayName,
|
|
37
|
+
templateId: req.body?.templateId,
|
|
38
|
+
templateVersion: req.body?.templateVersion,
|
|
39
|
+
themeId: req.body?.themeId,
|
|
40
|
+
title: req.body?.title,
|
|
41
|
+
subtitle: req.body?.subtitle,
|
|
42
|
+
ctaLines: req.body?.ctaLines,
|
|
43
|
+
qrTargetUrl: req.body?.qrTargetUrl,
|
|
44
|
+
footerLabel: req.body?.footerLabel,
|
|
45
|
+
badgeText: req.body?.badgeText,
|
|
46
|
+
expiresInSeconds: req.body?.expiresInSeconds,
|
|
47
|
+
forceRegenerate: req.body?.forceRegenerate === true,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const imageUrl = result.card.imageUrl || (result.card.publicPath ? buildAbsoluteUrl(req, result.card.publicPath) : null);
|
|
51
|
+
const downloadUrl = result.card.downloadUrl || imageUrl;
|
|
52
|
+
return res.status(result.cacheHit ? 200 : 201).json({
|
|
53
|
+
...result,
|
|
54
|
+
card: {
|
|
55
|
+
...result.card,
|
|
56
|
+
...(imageUrl ? { imageUrl } : {}),
|
|
57
|
+
...(downloadUrl ? { downloadUrl } : {}),
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return sendAgentCardError(res, error);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|