@xfxstudio/claworld 0.2.12 → 0.2.14

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 (62) hide show
  1. package/README.md +45 -19
  2. package/index.js +0 -1
  3. package/openclaw.plugin.json +1 -1
  4. package/package.json +1 -5
  5. package/skills/claworld-help/SKILL.md +84 -91
  6. package/skills/claworld-join-and-chat/SKILL.md +9 -9
  7. package/src/openclaw/index.js +0 -3
  8. package/src/openclaw/plugin/account-identity.js +0 -1
  9. package/src/openclaw/plugin/claworld-channel-plugin.js +8 -253
  10. package/src/openclaw/plugin/managed-config.js +1 -7
  11. package/src/openclaw/plugin/onboarding.js +128 -103
  12. package/src/openclaw/plugin/register.js +183 -232
  13. package/src/openclaw/plugin/relay-client.js +8 -5
  14. package/src/openclaw/runtime/product-shell-helper.js +11 -364
  15. package/src/openclaw/runtime/tool-contracts.js +0 -182
  16. package/src/openclaw/runtime/tool-inventory.js +4 -27
  17. package/bin/claworld.mjs +0 -9
  18. package/src/lib/agent-profile.js +0 -74
  19. package/src/lib/http-auth.js +0 -151
  20. package/src/lib/policy.js +0 -114
  21. package/src/openclaw/installer/cli.js +0 -406
  22. package/src/openclaw/installer/constants.js +0 -14
  23. package/src/openclaw/installer/core.js +0 -2122
  24. package/src/openclaw/installer/doctor.js +0 -876
  25. package/src/openclaw/installer/workspace-contract.js +0 -427
  26. package/src/product-shell/agent-cards/card-routes.js +0 -64
  27. package/src/product-shell/agent-cards/card-service.js +0 -287
  28. package/src/product-shell/agent-cards/spec-builder.js +0 -167
  29. package/src/product-shell/agent-cards/storage/image-host-storage.js +0 -192
  30. package/src/product-shell/agent-cards/storage/local-public-storage.js +0 -74
  31. package/src/product-shell/agent-cards/svg-renderer.js +0 -325
  32. package/src/product-shell/agent-cards/template-registry.js +0 -131
  33. package/src/product-shell/catalog/default-world-catalog.js +0 -38
  34. package/src/product-shell/contracts/candidate-feed.js +0 -393
  35. package/src/product-shell/contracts/world-manifest.js +0 -369
  36. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +0 -261
  37. package/src/product-shell/feedback/feedback-contract.js +0 -13
  38. package/src/product-shell/feedback/feedback-routes.js +0 -98
  39. package/src/product-shell/feedback/feedback-service.js +0 -252
  40. package/src/product-shell/index.js +0 -212
  41. package/src/product-shell/matching/matchmaking-service.js +0 -395
  42. package/src/product-shell/membership/membership-service.js +0 -284
  43. package/src/product-shell/onboarding/onboarding-routes.js +0 -37
  44. package/src/product-shell/onboarding/onboarding-service.js +0 -220
  45. package/src/product-shell/orchestration/world-conversation-orchestrator.js +0 -28
  46. package/src/product-shell/profile/profile-service.js +0 -142
  47. package/src/product-shell/profile/public-identity-routes.js +0 -160
  48. package/src/product-shell/profile/public-identity-service.js +0 -192
  49. package/src/product-shell/search/search-service.js +0 -393
  50. package/src/product-shell/social/chat-request-approval-policy.js +0 -332
  51. package/src/product-shell/social/chat-request-routes.js +0 -130
  52. package/src/product-shell/social/chat-request-service.js +0 -723
  53. package/src/product-shell/social/friend-routes.js +0 -82
  54. package/src/product-shell/social/friend-service.js +0 -557
  55. package/src/product-shell/social/social-routes.js +0 -21
  56. package/src/product-shell/social/social-service.js +0 -136
  57. package/src/product-shell/worlds/world-admin-service.js +0 -486
  58. package/src/product-shell/worlds/world-authorization.js +0 -136
  59. package/src/product-shell/worlds/world-broadcast-service.js +0 -296
  60. package/src/product-shell/worlds/world-routes.js +0 -403
  61. package/src/product-shell/worlds/world-service.js +0 -89
  62. package/src/product-shell/worlds/world-text.js +0 -75
@@ -1,393 +0,0 @@
1
- const DEFAULT_CANDIDATE_FEED_TTL_MS = 6 * 60 * 60 * 1000;
2
- const MAX_CANDIDATE_FEED_LIMIT = 25;
3
- const DEFAULT_CANDIDATE_FEED_LIMIT = 10;
4
-
5
- export const CANDIDATE_OBJECT_FIELDS = Object.freeze([
6
- 'candidateId',
7
- 'worldId',
8
- 'targetAgentId',
9
- 'sourceMembershipId',
10
- 'online',
11
- 'requestChat',
12
- 'profileSummary',
13
- 'compatibilitySignals',
14
- 'deliveryReason',
15
- 'worldFeedbackSummary',
16
- 'expiresAt',
17
- ]);
18
-
19
- export const WORLD_FEEDBACK_SUMMARY_FIELDS = Object.freeze([
20
- 'likesReceived',
21
- 'dislikesReceived',
22
- ]);
23
-
24
- export const DATING_DEMO_SCORING_FIELDS = Object.freeze([
25
- 'joinedAt',
26
- 'rank',
27
- 'score',
28
- 'scoreBreakdown',
29
- 'scoringInputs',
30
- ]);
31
-
32
- export const PROFILE_SUMMARY_FIELDS = Object.freeze([
33
- 'displayName',
34
- 'headline',
35
- 'requiredFields',
36
- 'optionalFields',
37
- ]);
38
-
39
- export const PROFILE_SUMMARY_FIELD_FIELDS = Object.freeze([
40
- 'fieldId',
41
- 'label',
42
- 'value',
43
- ]);
44
-
45
- export const COMPATIBILITY_SIGNAL_FIELDS = Object.freeze([
46
- 'signalId',
47
- 'type',
48
- 'fieldIds',
49
- 'score',
50
- 'summary',
51
- ]);
52
-
53
- export const DELIVERY_REASON_FIELDS = Object.freeze([
54
- 'code',
55
- 'matchedFieldIds',
56
- 'summary',
57
- ]);
58
-
59
- export const LIVE_DELIVERY_EVENT_ENVELOPE_FIELDS = Object.freeze([
60
- 'event',
61
- 'data',
62
- ]);
63
-
64
- export const LIVE_DELIVERY_EVENT_PAYLOAD_FIELDS = Object.freeze([
65
- 'deliveryId',
66
- 'worldId',
67
- 'agentId',
68
- 'viewerMembershipId',
69
- 'deliveredAt',
70
- 'candidate',
71
- ]);
72
-
73
- function normalizeText(value, fallback = null) {
74
- if (value == null) return fallback;
75
- const normalized = String(value).trim();
76
- return normalized || fallback;
77
- }
78
-
79
- function normalizeValue(value, field = {}) {
80
- if (value == null) return null;
81
-
82
- if (field.type === 'string[]') {
83
- if (!Array.isArray(value)) return [];
84
- return [...new Set(value.map((entry) => normalizeText(entry, null)).filter(Boolean))];
85
- }
86
-
87
- const normalized = normalizeText(value, null);
88
- return normalized;
89
- }
90
-
91
- function buildRequestChatPayload(world, candidateMembership) {
92
- const targetAgentId = normalizeText(candidateMembership?.agentId, null);
93
- if (!targetAgentId) return null;
94
-
95
- return {
96
- worldId: world.worldId,
97
- targetAgentId,
98
- };
99
- }
100
-
101
- function normalizeComparableArray(value) {
102
- if (!Array.isArray(value)) return [];
103
- return [...new Set(value.map((entry) => normalizeText(entry, null)?.toLowerCase()).filter(Boolean))];
104
- }
105
-
106
- function normalizeComparableText(value) {
107
- return normalizeText(value, null)?.toLowerCase() || null;
108
- }
109
-
110
- function tokenizeText(value) {
111
- return [...new Set(
112
- String(value || '')
113
- .toLowerCase()
114
- .split(/[^a-z0-9\u4e00-\u9fff]+/i)
115
- .map((entry) => entry.trim())
116
- .filter((entry) => entry.length >= 2),
117
- )];
118
- }
119
-
120
- function projectSummaryField(field = {}, profile = {}) {
121
- const normalizedValue = normalizeValue(profile[field.fieldId], field);
122
- if (normalizedValue == null) return null;
123
- if (Array.isArray(normalizedValue) && normalizedValue.length === 0) return null;
124
-
125
- return {
126
- fieldId: field.fieldId,
127
- label: field.label,
128
- value: normalizedValue,
129
- };
130
- }
131
-
132
- function projectProfileSummary(world, profile = {}, agent = null) {
133
- return {
134
- displayName: normalizeText(agent?.displayName, null),
135
- headline: normalizeText(profile.participantContextText, normalizeText(profile.headline, null)),
136
- requiredFields: world.joinSchema.requiredFields
137
- .map((field) => projectSummaryField(field, profile))
138
- .filter(Boolean),
139
- optionalFields: world.joinSchema.optionalFields
140
- .map((field) => projectSummaryField(field, profile))
141
- .filter(Boolean),
142
- };
143
- }
144
-
145
- function createCompatibilitySignal({ sourceMembershipId, type, fieldIds, score, summary }) {
146
- return {
147
- signalId: `${sourceMembershipId}:${type}:${fieldIds.join('+') || 'world'}`,
148
- type,
149
- fieldIds,
150
- score,
151
- summary,
152
- };
153
- }
154
-
155
- function compareFieldValues(field, viewerValue, candidateValue, sourceMembershipId) {
156
- if (field.fieldId === 'participantContextText') {
157
- const viewerTokens = tokenizeText(viewerValue);
158
- const candidateTokens = tokenizeText(candidateValue);
159
- const sharedItems = viewerTokens.filter((item) => candidateTokens.includes(item));
160
- if (sharedItems.length === 0) return null;
161
-
162
- return createCompatibilitySignal({
163
- sourceMembershipId,
164
- type: 'field_overlap',
165
- fieldIds: [field.fieldId],
166
- score: Math.min(sharedItems.length * 0.08, 0.48),
167
- summary: `Shared context: ${sharedItems.slice(0, 6).join(', ')}.`,
168
- });
169
- }
170
-
171
- if (field.type === 'string[]') {
172
- const viewerItems = normalizeComparableArray(viewerValue);
173
- const candidateItems = normalizeComparableArray(candidateValue);
174
- const sharedItems = viewerItems.filter((item) => candidateItems.includes(item));
175
- if (sharedItems.length === 0) return null;
176
-
177
- return createCompatibilitySignal({
178
- sourceMembershipId,
179
- type: 'field_overlap',
180
- fieldIds: [field.fieldId],
181
- score: field.required ? 0.25 : 0.15,
182
- summary: `Shared ${field.label}: ${sharedItems.slice(0, 3).join(', ')}.`,
183
- });
184
- }
185
-
186
- const normalizedViewerValue = normalizeComparableText(viewerValue);
187
- const normalizedCandidateValue = normalizeComparableText(candidateValue);
188
- if (!normalizedViewerValue || !normalizedCandidateValue) return null;
189
- if (normalizedViewerValue !== normalizedCandidateValue) return null;
190
-
191
- return createCompatibilitySignal({
192
- sourceMembershipId,
193
- type: 'field_alignment',
194
- fieldIds: [field.fieldId],
195
- score: field.required ? 0.35 : 0.1,
196
- summary: `Matching ${field.label}: ${normalizeText(candidateValue, '')}.`.trim(),
197
- });
198
- }
199
-
200
- function buildCompatibilitySignals(world, viewerProfile = {}, candidateProfile = {}, sourceMembershipId) {
201
- const signals = [...world.joinSchema.requiredFields, ...world.joinSchema.optionalFields]
202
- .map((field) => compareFieldValues(field, viewerProfile[field.fieldId], candidateProfile[field.fieldId], sourceMembershipId))
203
- .filter(Boolean);
204
-
205
- if (signals.length > 0) {
206
- return signals.sort((left, right) => right.score - left.score || left.fieldIds[0].localeCompare(right.fieldIds[0]));
207
- }
208
-
209
- return [
210
- createCompatibilitySignal({
211
- sourceMembershipId,
212
- type: 'world_ready',
213
- fieldIds: [],
214
- score: 0.05,
215
- summary: 'Candidate is online with an active world membership and is ready for agent review before live session handoff.',
216
- }),
217
- ];
218
- }
219
-
220
- function buildDeliveryReason(signals = []) {
221
- const matchedFieldIds = [...new Set(signals.flatMap((signal) => signal.fieldIds).filter(Boolean))];
222
-
223
- if (matchedFieldIds.length === 0) {
224
- return {
225
- code: 'world_membership_ready',
226
- matchedFieldIds: [],
227
- summary: 'Delivered for manual review because the candidate is online and active in this world, even though no direct profile overlap signal was detected yet.',
228
- };
229
- }
230
-
231
- return {
232
- code: 'profile_overlap_ready_for_review',
233
- matchedFieldIds,
234
- summary:
235
- `Delivered for agent review because the world found overlap on ${matchedFieldIds.join(', ')} ` +
236
- 'without starting a live session yet.',
237
- };
238
- }
239
-
240
- function resolveCandidateFeedTtlMs(world) {
241
- if (world.matching.cadence === 'on_demand') return 60 * 60 * 1000;
242
- return DEFAULT_CANDIDATE_FEED_TTL_MS;
243
- }
244
-
245
- function calculateRankingScore(signals = []) {
246
- return signals.reduce((total, signal) => total + Number(signal.score || 0), 0);
247
- }
248
-
249
- function resolveCandidateFields(world) {
250
- return world.worldId === 'dating-demo-world'
251
- ? [...CANDIDATE_OBJECT_FIELDS, ...DATING_DEMO_SCORING_FIELDS]
252
- : [...CANDIDATE_OBJECT_FIELDS];
253
- }
254
-
255
- function projectLiveDeliveryEvent(world, candidateFields) {
256
- return {
257
- schemaId: `${world.worldId}.candidate-delivery-event.v1`,
258
- eventName: 'world.candidate.delivered',
259
- envelopeFields: LIVE_DELIVERY_EVENT_ENVELOPE_FIELDS,
260
- payloadFields: LIVE_DELIVERY_EVENT_PAYLOAD_FIELDS,
261
- candidateFieldPath: 'data.candidate',
262
- candidateFields,
263
- candidateModelId: `${world.worldId}.candidate-feed.v1`,
264
- viewerRequirement: 'active_membership',
265
- summary:
266
- 'Future live delivery will reuse the current candidate object inside a push event after delivery workers/subscriptions are added.',
267
- status: 'planned_live_delivery',
268
- };
269
- }
270
-
271
- export function normalizeCandidateFeedLimit(limit) {
272
- const normalized = Number(limit);
273
- if (!Number.isFinite(normalized) || normalized <= 0) return DEFAULT_CANDIDATE_FEED_LIMIT;
274
- return Math.min(MAX_CANDIDATE_FEED_LIMIT, Math.floor(normalized));
275
- }
276
-
277
- export function projectCandidateFeedModel(world) {
278
- const candidateFields = resolveCandidateFields(world);
279
-
280
- return {
281
- modelId: `${world.worldId}.candidate-feed.v1`,
282
- worldId: world.worldId,
283
- deliveryMode: 'agent_review_before_live_session',
284
- viewerRequirement: 'active_membership',
285
- previewRoute: `/v1/worlds/${world.worldId}/candidates?agentId=:agentId`,
286
- candidateFields,
287
- profileSummaryFields: PROFILE_SUMMARY_FIELDS,
288
- profileSummaryFieldShape: PROFILE_SUMMARY_FIELD_FIELDS,
289
- compatibilitySignalFields: COMPATIBILITY_SIGNAL_FIELDS,
290
- deliveryReasonFields: DELIVERY_REASON_FIELDS,
291
- worldFeedbackSummaryFields: WORLD_FEEDBACK_SUMMARY_FIELDS,
292
- requestChatAction: {
293
- action: 'request_chat',
294
- requiredFields: ['worldId', 'targetAgentId'],
295
- summary:
296
- 'After reviewing a candidate, create a world-scoped chat request with worldId and targetAgentId.',
297
- },
298
- liveDeliveryEvent: projectLiveDeliveryEvent(world, candidateFields),
299
- summary:
300
- 'Active online members can review candidate opportunities first, then call request_chat with the selected targetAgentId when they want to start a world-scoped conversation request.',
301
- status: 'phase1_candidate_feed',
302
- };
303
- }
304
-
305
- function projectCandidateOpportunity({
306
- world,
307
- viewerProfile,
308
- candidateMembership,
309
- candidateAgent,
310
- candidatePresence,
311
- expiresAt,
312
- }) {
313
- const profileSnapshot = candidateMembership.profileSnapshot || {};
314
- const compatibilitySignals = buildCompatibilitySignals(
315
- world,
316
- viewerProfile,
317
- profileSnapshot,
318
- candidateMembership.membershipId,
319
- );
320
- const requestChat = buildRequestChatPayload(world, candidateMembership);
321
-
322
- return {
323
- candidateId: `cand_${candidateMembership.membershipId}`,
324
- worldId: world.worldId,
325
- sourceMembershipId: candidateMembership.membershipId,
326
- targetAgentId: requestChat?.targetAgentId || null,
327
- online: candidatePresence?.online === true,
328
- requestChat,
329
- profileSummary: projectProfileSummary(world, profileSnapshot, candidateAgent),
330
- compatibilitySignals,
331
- deliveryReason: buildDeliveryReason(compatibilitySignals),
332
- expiresAt,
333
- };
334
- }
335
-
336
- export function buildCandidateFeed({
337
- world,
338
- viewerMembership,
339
- viewerAgent = null,
340
- candidateMemberships = [],
341
- getAgent = () => null,
342
- getPresence = () => ({ online: true }),
343
- nowMs = Date.now(),
344
- limit = DEFAULT_CANDIDATE_FEED_LIMIT,
345
- }) {
346
- const normalizedNowMs = Number.isFinite(Number(nowMs)) ? Number(nowMs) : Date.now();
347
- const generatedAt = new Date(normalizedNowMs).toISOString();
348
- const expiresAt = new Date(normalizedNowMs + resolveCandidateFeedTtlMs(world)).toISOString();
349
- const normalizedLimit = normalizeCandidateFeedLimit(limit);
350
- const viewerProfile = viewerMembership?.profileSnapshot || viewerAgent?.profile || {};
351
-
352
- const candidates = candidateMemberships
353
- .filter((membership) => membership?.status === 'active' && membership.membershipId !== viewerMembership.membershipId)
354
- .map((membership) => ({
355
- membership,
356
- candidatePresence: getPresence(membership.agentId),
357
- }))
358
- .filter(({ candidatePresence }) => candidatePresence?.online === true)
359
- .map(({ membership, candidatePresence }) => {
360
- const opportunity = projectCandidateOpportunity({
361
- world,
362
- viewerProfile,
363
- candidateMembership: membership,
364
- candidateAgent: getAgent(membership.agentId),
365
- candidatePresence,
366
- expiresAt,
367
- });
368
-
369
- return {
370
- opportunity,
371
- rankingScore: calculateRankingScore(opportunity.compatibilitySignals),
372
- };
373
- })
374
- .sort(
375
- (left, right) =>
376
- right.rankingScore - left.rankingScore
377
- || left.opportunity.candidateId.localeCompare(right.opportunity.candidateId),
378
- )
379
- .slice(0, normalizedLimit)
380
- .map((entry) => entry.opportunity);
381
-
382
- return {
383
- worldId: world.worldId,
384
- viewerMembershipId: viewerMembership.membershipId,
385
- generatedAt,
386
- expiresAt,
387
- deliveryMode: 'agent_review_before_live_session',
388
- nextAction: 'review_candidates_then_request_chat',
389
- candidateModel: projectCandidateFeedModel(world),
390
- candidates,
391
- status: 'feed_ready',
392
- };
393
- }