@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.
@@ -1,16 +1,16 @@
1
1
  import {
2
- CLAWORLD_DOCTOR_COMMAND,
3
- CLAWORLD_INSTALLER_COMMAND,
4
2
  CLAWORLD_INSTALLER_PACKAGE_NAME,
5
3
  CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
6
- CLAWORLD_UNINSTALL_COMMAND,
7
- CLAWORLD_UPDATE_COMMAND,
8
4
  } from '../../openclaw/installer/constants.js';
9
5
 
10
6
  const DEFAULT_INSTALL_CHANNEL_ID = 'claworld';
11
7
  const DEFAULT_INSTALL_ACCOUNT_ID = 'claworld';
12
8
  const DEFAULT_INSTALL_LOCAL_AGENT_ID = 'main';
13
9
  const DEFAULT_ACTIVATION_DISPLAY_NAME = 'Claworld Agent';
10
+ const CLAWORLD_HOST_NATIVE_INSTALL_COMMAND = `openclaw plugins install ${CLAWORLD_INSTALLER_PACKAGE_NAME}`;
11
+ const CLAWORLD_HOST_NATIVE_SETUP_COMMAND = 'openclaw channels add --channel claworld';
12
+ const CLAWORLD_HOST_NATIVE_ONBOARD_COMMAND = 'openclaw onboard';
13
+ const CLAWORLD_HOST_NATIVE_INSPECT_COMMAND = 'openclaw plugins info claworld';
14
14
 
15
15
  function normalizeText(value, fallback = null) {
16
16
  if (value == null) return fallback;
@@ -107,15 +107,15 @@ export function createOnboardingService({ worldService, store = null } = {}) {
107
107
  product: 'claworld',
108
108
  mode: 'agent_install',
109
109
  installer: {
110
- command: CLAWORLD_INSTALLER_COMMAND,
110
+ command: CLAWORLD_HOST_NATIVE_INSTALL_COMMAND,
111
111
  packageName: CLAWORLD_INSTALLER_PACKAGE_NAME,
112
112
  minHostVersion: CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
113
- canonicalFlow: 'installer_first',
113
+ canonicalFlow: 'host_native_setup',
114
114
  lifecycle: {
115
- install: CLAWORLD_INSTALLER_COMMAND,
116
- doctor: CLAWORLD_DOCTOR_COMMAND,
117
- update: CLAWORLD_UPDATE_COMMAND,
118
- uninstall: CLAWORLD_UNINSTALL_COMMAND,
115
+ install: CLAWORLD_HOST_NATIVE_INSTALL_COMMAND,
116
+ configure: CLAWORLD_HOST_NATIVE_SETUP_COMMAND,
117
+ onboard: CLAWORLD_HOST_NATIVE_ONBOARD_COMMAND,
118
+ inspect: CLAWORLD_HOST_NATIVE_INSPECT_COMMAND,
119
119
  },
120
120
  },
121
121
  plugin: {
@@ -139,10 +139,11 @@ export function createOnboardingService({ worldService, store = null } = {}) {
139
139
  },
140
140
  compatibility: {
141
141
  nativeOpenclaw: {
142
- status: 'compatibility_only',
142
+ status: 'preferred',
143
143
  commands: [
144
- 'openclaw onboard',
145
- 'openclaw channels add claworld --app-token <token>',
144
+ CLAWORLD_HOST_NATIVE_INSTALL_COMMAND,
145
+ CLAWORLD_HOST_NATIVE_SETUP_COMMAND,
146
+ CLAWORLD_HOST_NATIVE_ONBOARD_COMMAND,
146
147
  ],
147
148
  },
148
149
  },
@@ -160,14 +161,14 @@ export function createOnboardingService({ worldService, store = null } = {}) {
160
161
  expectedBinding: 'runtime_bound_by_app_token',
161
162
  },
162
163
  steps: [
163
- `run ${CLAWORLD_INSTALLER_COMMAND}`,
164
- 'installer validates OpenClaw availability and minimum host version',
165
- 'installer verifies or installs the claworld OpenClaw plugin package',
166
- 'installer writes or refreshes the managed claworld channel config and binds it to the local main agent by default',
167
- 'installer reloads or starts the runtime and verifies the managed channel shape without requiring backend activation',
168
- 'first-run readiness goes through claworld_pair_agent and then claworld_update_public_identity',
169
- 'claworld_update_public_identity performs activation when needed and completes the public displayName#code identity',
170
- `ongoing lifecycle uses ${CLAWORLD_UPDATE_COMMAND} for tracked package updates plus managed repair, then ${CLAWORLD_DOCTOR_COMMAND} for health confirmation`,
164
+ `run ${CLAWORLD_HOST_NATIVE_INSTALL_COMMAND}`,
165
+ `configure one account with ${CLAWORLD_HOST_NATIVE_SETUP_COMMAND} or ${CLAWORLD_HOST_NATIVE_ONBOARD_COMMAND}`,
166
+ 'host-native setup writes or refreshes the claworld channel config and binding without requiring backend activation',
167
+ `inspect plugin install state with ${CLAWORLD_HOST_NATIVE_INSPECT_COMMAND} when setup needs verification`,
168
+ 'ask once for the desired public display name after setup completes',
169
+ 'claworld_profile(action=update_identity) performs activation when needed, persists the returned appToken, and completes the public displayName#code identity',
170
+ 'use claworld_pair_agent when runtime readiness still looks unhealthy after setup or initialization',
171
+ 'ongoing package updates and removal stay on the OpenClaw host plugin lifecycle instead of a plugin-owned installer CLI',
171
172
  ],
172
173
  recommendedWorlds,
173
174
  status: 'ready',
@@ -181,10 +182,11 @@ export function createOnboardingService({ worldService, store = null } = {}) {
181
182
  return {
182
183
  selectedWorld: selectedWorld ? { worldId: selectedWorld.worldId, displayName: selectedWorld.displayName } : null,
183
184
  actions: [
184
- 'install the claworld plugin and write the managed config shape',
185
- 'run claworld_pair_agent to confirm readiness after install',
186
- 'if public identity is pending, call claworld_update_public_identity',
187
- 'claworld_update_public_identity activates the backend binding when needed and persists the returned appToken',
185
+ 'install the claworld plugin through the OpenClaw host',
186
+ 'configure the claworld channel account and local binding through host-native setup',
187
+ 'ask once for the desired public display name',
188
+ 'call claworld_profile with action=update_identity to finish activation and public naming',
189
+ 'use claworld_pair_agent only when the runtime still needs diagnosis after setup or initialization',
188
190
  'collect required world profile fields',
189
191
  'validate world membership eligibility',
190
192
  'start the first A2A loop or deliver world content',
@@ -0,0 +1,142 @@
1
+ function normalizeBoolean(value, fallback = false) {
2
+ if (typeof value === 'boolean') return value;
3
+ return fallback;
4
+ }
5
+
6
+ function normalizePositiveInteger(value, fallback = null) {
7
+ const normalized = Number(value);
8
+ if (!Number.isFinite(normalized) || normalized <= 0) return fallback;
9
+ return Math.floor(normalized);
10
+ }
11
+
12
+ async function maybeGenerateShareCard({
13
+ agentCardService,
14
+ agentId,
15
+ identityStatus,
16
+ generateShareCard = false,
17
+ expiresInSeconds = null,
18
+ forceRegenerate = true,
19
+ }) {
20
+ if (!generateShareCard) return undefined;
21
+ if (identityStatus?.ready !== true) {
22
+ return {
23
+ status: 'unavailable',
24
+ reason: 'public_identity_not_ready',
25
+ };
26
+ }
27
+
28
+ try {
29
+ return await agentCardService.renderCard({
30
+ agentId,
31
+ expiresInSeconds: normalizePositiveInteger(expiresInSeconds, null),
32
+ forceRegenerate: normalizeBoolean(forceRegenerate, true),
33
+ });
34
+ } catch (error) {
35
+ return {
36
+ status: 'unavailable',
37
+ reason: 'generation_failed',
38
+ message: error?.publicMessage || error?.message || 'share card generation failed',
39
+ };
40
+ }
41
+ }
42
+
43
+ export function createProfileService({
44
+ publicIdentityService,
45
+ agentCardService,
46
+ } = {}) {
47
+ if (!publicIdentityService) {
48
+ throw new Error('profile_service_requires_public_identity_service');
49
+ }
50
+ if (!agentCardService) {
51
+ throw new Error('profile_service_requires_agent_card_service');
52
+ }
53
+
54
+ return {
55
+ getPublicIdentityStatus(input = {}) {
56
+ return publicIdentityService.getPublicIdentityStatus(input);
57
+ },
58
+
59
+ updatePublicIdentity(input = {}) {
60
+ return publicIdentityService.updatePublicIdentity(input);
61
+ },
62
+
63
+ assertPublicIdentityReady(input = {}) {
64
+ return publicIdentityService.assertPublicIdentityReady(input);
65
+ },
66
+
67
+ async getProfile({
68
+ agentId,
69
+ generateShareCard = false,
70
+ expiresInSeconds = null,
71
+ forceRegenerate = true,
72
+ } = {}) {
73
+ const identityStatus = publicIdentityService.getPublicIdentityStatus({ agentId });
74
+ const shareCard = await maybeGenerateShareCard({
75
+ agentCardService,
76
+ agentId,
77
+ identityStatus,
78
+ generateShareCard,
79
+ expiresInSeconds,
80
+ forceRegenerate,
81
+ });
82
+ return shareCard === undefined
83
+ ? identityStatus
84
+ : {
85
+ ...identityStatus,
86
+ shareCard,
87
+ };
88
+ },
89
+
90
+ async updateProfileIdentity({
91
+ agentId,
92
+ displayName,
93
+ generateShareCard = true,
94
+ expiresInSeconds = null,
95
+ forceRegenerate = true,
96
+ } = {}) {
97
+ const identityStatus = await publicIdentityService.updatePublicIdentity({
98
+ agentId,
99
+ displayName,
100
+ });
101
+ const shareCard = await maybeGenerateShareCard({
102
+ agentCardService,
103
+ agentId,
104
+ identityStatus,
105
+ generateShareCard,
106
+ expiresInSeconds,
107
+ forceRegenerate,
108
+ });
109
+ return shareCard === undefined
110
+ ? identityStatus
111
+ : {
112
+ ...identityStatus,
113
+ shareCard,
114
+ };
115
+ },
116
+
117
+ async executeProfileAction({
118
+ action = 'view',
119
+ agentId,
120
+ displayName = null,
121
+ generateShareCard = false,
122
+ expiresInSeconds = null,
123
+ forceRegenerate = true,
124
+ } = {}) {
125
+ if (action === 'update_identity') {
126
+ return this.updateProfileIdentity({
127
+ agentId,
128
+ displayName,
129
+ generateShareCard,
130
+ expiresInSeconds,
131
+ forceRegenerate,
132
+ });
133
+ }
134
+ return this.getProfile({
135
+ agentId,
136
+ generateShareCard,
137
+ expiresInSeconds,
138
+ forceRegenerate,
139
+ });
140
+ },
141
+ };
142
+ }
@@ -1,5 +1,45 @@
1
1
  import { resolveAuthenticatedAgentId } from '../../lib/http-auth.js';
2
2
 
3
+ function normalizeBoolean(value, fallback = false) {
4
+ if (typeof value === 'boolean') return value;
5
+ if (typeof value === 'string') {
6
+ const normalized = value.trim().toLowerCase();
7
+ if (normalized === 'true') return true;
8
+ if (normalized === 'false') return false;
9
+ }
10
+ return fallback;
11
+ }
12
+
13
+ function normalizePositiveInteger(value, fallback = null) {
14
+ const normalized = Number(value);
15
+ if (!Number.isFinite(normalized) || normalized <= 0) return fallback;
16
+ return Math.floor(normalized);
17
+ }
18
+
19
+ function buildAbsoluteUrl(req, publicPath) {
20
+ return `${req.protocol}://${req.get('host')}${publicPath}`;
21
+ }
22
+
23
+ function normalizeShareCard(req, shareCard = undefined) {
24
+ if (shareCard === undefined) return undefined;
25
+ if (!shareCard || typeof shareCard !== 'object') return shareCard;
26
+
27
+ const card = shareCard.card && typeof shareCard.card === 'object' ? shareCard.card : null;
28
+ if (!card) return shareCard;
29
+
30
+ const imageUrl = card.imageUrl || (card.publicPath ? buildAbsoluteUrl(req, card.publicPath) : null);
31
+ const downloadUrl = card.downloadUrl || imageUrl;
32
+ if (!imageUrl && !downloadUrl) return shareCard;
33
+ return {
34
+ ...shareCard,
35
+ card: {
36
+ ...card,
37
+ ...(imageUrl ? { imageUrl } : {}),
38
+ ...(downloadUrl ? { downloadUrl } : {}),
39
+ },
40
+ };
41
+ }
42
+
3
43
  function sendProfileError(res, error) {
4
44
  const status = Number.isInteger(error?.status) ? error.status : 500;
5
45
  if (error?.responseBody && typeof error.responseBody === 'object') {
@@ -17,6 +57,66 @@ function sendMissingAgentIdentity(res) {
17
57
  }
18
58
 
19
59
  export function registerPublicIdentityRoutes(app, { publicIdentityService, store }) {
60
+ app.get('/v1/profile', async (req, res) => {
61
+ const authAgent = resolveAuthenticatedAgentId({
62
+ store,
63
+ req,
64
+ providedAgentId: req.query.agentId,
65
+ fieldName: 'agentId',
66
+ });
67
+ if (!authAgent.ok) return res.status(authAgent.status).json(authAgent.body);
68
+ if (!authAgent.agentId) return sendMissingAgentIdentity(res);
69
+
70
+ try {
71
+ const result = await publicIdentityService.getProfile({
72
+ agentId: authAgent.agentId,
73
+ generateShareCard: normalizeBoolean(req.query.generateShareCard, false),
74
+ expiresInSeconds: normalizePositiveInteger(req.query.expiresInSeconds, null),
75
+ forceRegenerate: normalizeBoolean(req.query.forceRegenerate, true),
76
+ });
77
+ return res.json({
78
+ ...result,
79
+ ...(Object.prototype.hasOwnProperty.call(result, 'shareCard')
80
+ ? { shareCard: normalizeShareCard(req, result.shareCard) }
81
+ : {}),
82
+ });
83
+ } catch (error) {
84
+ return sendProfileError(res, error);
85
+ }
86
+ });
87
+
88
+ app.post('/v1/profile', async (req, res) => {
89
+ const authAgent = resolveAuthenticatedAgentId({
90
+ store,
91
+ req,
92
+ providedAgentId: req.body?.agentId,
93
+ fieldName: 'agentId',
94
+ });
95
+ if (!authAgent.ok) return res.status(authAgent.status).json(authAgent.body);
96
+ if (!authAgent.agentId) return sendMissingAgentIdentity(res);
97
+
98
+ try {
99
+ const action = String(req.body?.action || '').trim() || (req.body?.displayName ? 'update_identity' : 'view');
100
+ const result = await publicIdentityService.executeProfileAction({
101
+ action,
102
+ agentId: authAgent.agentId,
103
+ displayName: req.body?.displayName,
104
+ generateShareCard: normalizeBoolean(req.body?.generateShareCard, action === 'update_identity'),
105
+ expiresInSeconds: normalizePositiveInteger(req.body?.expiresInSeconds, null),
106
+ forceRegenerate: normalizeBoolean(req.body?.forceRegenerate, true),
107
+ });
108
+ return res.json({
109
+ action,
110
+ ...result,
111
+ ...(Object.prototype.hasOwnProperty.call(result, 'shareCard')
112
+ ? { shareCard: normalizeShareCard(req, result.shareCard) }
113
+ : {}),
114
+ });
115
+ } catch (error) {
116
+ return sendProfileError(res, error);
117
+ }
118
+ });
119
+
20
120
  app.get('/v1/profile/public-identity', (req, res) => {
21
121
  const authAgent = resolveAuthenticatedAgentId({
22
122
  store,
@@ -49,9 +49,11 @@ function createInvalidPublicIdentityRequest(fieldId, message, code = 'invalid_pu
49
49
  return error;
50
50
  }
51
51
 
52
+ const DEFAULT_PUBLIC_IDENTITY_NEXT_TOOL = 'claworld_profile';
53
+
52
54
  function createPublicIdentityIncompleteError(agent, {
53
55
  capability = null,
54
- nextTool = 'claworld_update_public_identity',
56
+ nextTool = DEFAULT_PUBLIC_IDENTITY_NEXT_TOOL,
55
57
  } = {}) {
56
58
  const projected = projectPublicIdentityStatus(agent, { nextTool });
57
59
  const capabilityLabel = normalizeText(capability, 'this Claworld capability');
@@ -73,7 +75,7 @@ function createPublicIdentityIncompleteError(agent, {
73
75
  }
74
76
 
75
77
  function projectPublicIdentityStatus(agent, {
76
- nextTool = 'claworld_update_public_identity',
78
+ nextTool = DEFAULT_PUBLIC_IDENTITY_NEXT_TOOL,
77
79
  conversationFeedbackService = null,
78
80
  } = {}) {
79
81
  const publicIdentity = resolvePublicIdentity(agent);
package/bin/claworld.mjs DELETED
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { runInstallerCli } from '../src/openclaw/installer/cli.js';
4
-
5
- runInstallerCli().catch((error) => {
6
- console.error('Claworld CLI failed');
7
- console.error(error.message || error);
8
- process.exit(1);
9
- });