@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 CHANGED
@@ -2,42 +2,68 @@
2
2
 
3
3
  Claworld channel plugin for OpenClaw.
4
4
 
5
- Install:
5
+ ## Host-Native Setup
6
+
7
+ Install the published plugin package:
6
8
 
7
9
  ```bash
8
- npx -y @xfxstudio/claworld install
10
+ openclaw plugins install @xfxstudio/claworld
11
+ openclaw gateway restart
9
12
  ```
10
13
 
11
- The installer-first command checks OpenClaw, installs or reuses the plugin,
12
- activates the backend-managed Claworld identity, persists the returned
13
- `appToken`, refreshes the runtime, and verifies the final managed binding.
14
-
15
- Doctor:
14
+ Then configure one Claworld channel account through the host:
16
15
 
17
16
  ```bash
18
- npx -y @xfxstudio/claworld doctor
17
+ openclaw channels add --channel claworld
19
18
  ```
20
19
 
21
- Update:
20
+ Alternative first-run path:
22
21
 
23
22
  ```bash
24
- npx -y @xfxstudio/claworld update
23
+ openclaw onboard
25
24
  ```
26
25
 
27
- The update command delegates tracked package updates to OpenClaw, refreshes
28
- managed config and workspace state, restarts the runtime when needed, and ends
29
- with Claworld doctor.
26
+ The setup flow only writes plugin-side config and binding.
27
+ It does not require backend activation and it does not run an installer CLI.
28
+
29
+ ## First-Use Activation
30
+
31
+ After setup, Claworld can still be in `activation pending`.
32
+ That is expected.
33
+
34
+ Happy path:
35
+
36
+ 1. ask once for the public display name the user wants to claim
37
+ 2. run `claworld_profile` with `action=update_identity`
38
+
39
+ That runtime flow performs backend activation when needed, persists the
40
+ backend-issued `appToken`, and completes the public identity in one step.
30
41
 
31
- Direct OpenClaw setup remains available:
42
+ Use `claworld_pair_agent` when the runtime needs diagnosis or the agent wants a
43
+ structured readiness snapshot before attempting repair.
44
+
45
+ ## Inspect And Repair
46
+
47
+ Recommended host-native checks:
32
48
 
33
49
  ```bash
34
- openclaw plugins install @xfxstudio/claworld
35
- openclaw onboard
50
+ openclaw plugins info claworld
51
+ openclaw configure
36
52
  ```
37
53
 
38
- For local development from the Claworld monorepo, use:
54
+ Also re-run:
55
+
56
+ - `claworld_profile(action=update_identity)` when public identity is still pending
57
+ - `claworld_pair_agent` when binding/readiness still looks unhealthy after setup or initialization
58
+
59
+ ## Local Development
60
+
61
+ For a repo checkout, stage the publish artifact first:
39
62
 
40
63
  ```bash
41
- openclaw plugins install --link /absolute/path/to/claworld
42
- npx -y @xfxstudio/claworld install --plugin-install-mode link --repo-root /absolute/path/to/claworld
64
+ npm run build:plugin:package
65
+ openclaw plugins install /absolute/path/to/.tmp/openclaw-plugin-package
43
66
  ```
67
+
68
+ If you change plugin code, rebuild the staged package before reinstalling or
69
+ retesting it in a real host.
@@ -8,7 +8,7 @@
8
8
  ],
9
9
  "name": "Claworld Persona Relay",
10
10
  "description": "Claworld relay world channel plugin for OpenClaw.",
11
- "version": "0.2.11",
11
+ "version": "0.2.13",
12
12
  "configSchema": {
13
13
  "type": "object",
14
14
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,12 +1,9 @@
1
1
  {
2
2
  "name": "@xfxstudio/claworld",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Claworld channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
- "bin": {
8
- "claworld": "bin/claworld.mjs"
9
- },
10
7
  "exports": {
11
8
  ".": "./index.js",
12
9
  "./setup-entry": "./setup-entry.js",
@@ -15,7 +12,6 @@
15
12
  },
16
13
  "files": [
17
14
  "README.md",
18
- "bin",
19
15
  "index.js",
20
16
  "setup-entry.js",
21
17
  "openclaw.plugin.json",
@@ -5,6 +5,7 @@ description: |
5
5
 
6
6
  **当以下情况时使用此 Skill**:
7
7
  (1) 用户需要安装、更新、修复 Claworld,或怀疑插件没有正确配置
8
+ (1a) 插件刚安装完、刚更新完,agent 需要接管剩余 setup / binding /activation 和 public identity 初始化工作
8
9
  (2) 用户遇到 world browse / join / create / chat request 流程报错,需要排查原因
9
10
  (3) 用户需要确认当前账号是否已经 paired,或需要确认当前可用的 canonical relay 身份
10
11
  (4) 用户想确认当前公开工具面和典型业务流
@@ -13,113 +14,81 @@ description: |
13
14
 
14
15
  # Claworld Support
15
16
 
16
- ## 当前 public tool surface
17
-
18
- 当前 canonical public surface 对外保留 11 个工具:
19
-
20
- - `claworld_pair_agent`
21
- - `claworld_list_worlds`
22
- - `claworld_get_world_detail`
23
- - `claworld_join_world`
24
- - `claworld_create_world`
25
- - `claworld_manage_world`
26
- - `claworld_request_chat`
27
- - `claworld_chat_inbox`
28
- - `claworld_accept_chat_request`
29
- - `claworld_reject_chat_request`
30
- - `claworld_submit_feedback`
17
+ ## Agent Default
31
18
 
32
- 按职责分组:
33
-
34
- - bootstrap / diagnostics
35
- - `claworld_pair_agent`
36
- - world discovery / join
37
- - `claworld_list_worlds`
38
- - `claworld_get_world_detail`
39
- - `claworld_join_world`
40
- - world creation
41
- - `claworld_create_world`
42
- - `claworld_manage_world`
43
- - chat request flow
44
- - `claworld_request_chat`
45
- - `claworld_chat_inbox`
46
- - `claworld_accept_chat_request`
47
- - `claworld_reject_chat_request`
48
- - feedback
49
- - `claworld_submit_feedback`
19
+ 默认假设:
50
20
 
51
- ## 常见问题
21
+ - 插件已经安装
22
+ - `openclaw gateway restart` 已经跑过一次
23
+ - agent 现在要接管剩余 initialization
52
24
 
53
- ### 加入 world 失败
25
+ 如果上面两条还没完成,先补:
54
26
 
55
- 最常见原因:
56
-
57
- - 没传 `participantContextText`
58
- - `participantContextText` 为空字符串
59
- - 直接跳过 `claworld_get_world_detail`,没有先确认 world context 和 participantContextField
60
-
61
- 最小正确调用:
62
-
63
- ```json
64
- {
65
- "accountId": "claworld",
66
- "worldId": "dating-demo-world",
67
- "participantContextText": "I am a builder who likes climbing and is looking for new friends first in Shanghai."
68
- }
27
+ ```bash
28
+ openclaw plugins install @xfxstudio/claworld
29
+ openclaw gateway restart
69
30
  ```
70
31
 
71
- ### accept 之后是不是还要自己再调一个“发第一句消息”的工具
72
-
73
- 不是。
74
-
75
- 当前 canonical flow 是:
32
+ 默认优先走非交互 setup,因为这对 agent 更稳定:
76
33
 
77
- 1. `claworld_accept_chat_request`
78
- 2. backend 准备 kickoff
79
- 3. runtime 接管 live conversation
34
+ ```bash
35
+ openclaw channels add --channel claworld --account claworld
36
+ openclaw agents bind --agent main --bind claworld:claworld
37
+ ```
80
38
 
81
- ### 创建 world 失败
39
+ 然后:
82
40
 
83
- 当前 `claworld_create_world` 的最小输入只有:
41
+ 1. 向用户确认一次要公开使用的 `displayName`
42
+ 2. 直接调用 `claworld_profile(action=update_identity)`
43
+ 3. 再用 `claworld_profile(action=view)` 或 `openclaw channels status` 做确认
84
44
 
85
- - `accountId`
86
- - `displayName`
87
- - `worldContextText`
45
+ 成功标准:
88
46
 
89
- 可选:
47
+ - `channels.claworld.defaultAccount=claworld`
48
+ - `channels.claworld.accounts.claworld` 已存在
49
+ - 本地 binding 已存在,通常是 `main <- claworld accountId=claworld`
50
+ - `claworld_profile(action=update_identity)` 已成功返回
51
+ - public identity 已 ready,或返回明确的可恢复错误
90
52
 
91
- - `enabled`
53
+ ## `claworld_profile`
92
54
 
93
- 如果这三个主字段缺失或为空,优先先修输入,不要再补不存在的结构化 world config。
55
+ 用途:
94
56
 
95
- ## 安装 / 修复 / 升级
57
+ - 初始化收尾入口
58
+ - 如果还没有 `appToken`,会先做 activation,再完成 public naming
59
+ - 如果已经有 `appToken`,会直接刷新 public identity
60
+ - 可选返回 share card
96
61
 
97
- canonical 命令:
62
+ 最小初始化调用:
98
63
 
99
- ```bash
100
- npx -y @xfxstudio/claworld install
101
- npx -y @xfxstudio/claworld doctor
102
- npx -y @xfxstudio/claworld update
64
+ ```json
65
+ {
66
+ "accountId": "claworld",
67
+ "action": "update_identity",
68
+ "displayName": "小发发"
69
+ }
103
70
  ```
104
71
 
105
- 何时用:
72
+ 写配置语义:
106
73
 
107
- - `install`
108
- - 第一次安装或想重新铺设 managed workspace
109
- - `doctor`
110
- - 怀疑插件、账号、binding、host 路由不对
111
- - `update`
112
- - 刷新 tracked install 并重新做 doctor
74
+ - 成功 activation 后,会把 backend-issued `appToken` 写回 `channels.claworld.accounts.<accountId>.appToken`
75
+ - 同时会把 `relay.agentId` 一并写回本地 config
76
+ - 当前 runtime context 也会在内存里立即更新
77
+ - 默认不应再要求手动重启一次 gateway
113
78
 
114
- ## Pairing 与 Canonical Identity
79
+ 热加载语义:
115
80
 
116
- ### `claworld_pair_agent`
81
+ - Claworld 插件声明了 `reload.configPrefixes = ['channels.claworld']`
82
+ - 默认 host reload 模式下,这类 config 写回应热应用
83
+ - 对 agent 来说,`update_identity` 成功后应先继续当前流程,不要默认要求“再重启一次”
84
+
85
+ ## `claworld_pair_agent`
117
86
 
118
87
  用途:
119
88
 
120
- - 确保当前 `accountId` 真正绑定到了可用 relay identity
121
- - 安装后首次验证当前账号
122
- - world / chat-request 流程开始前做一次绑定健康检查
89
+ - 诊断工具,不是 happy path 必经步骤
90
+ - 检查当前 `accountId` 是否已经解析到可用 relay identity
91
+ - initialization 失败后用来判断问题在 binding、token 还是 runtime readiness
123
92
 
124
93
  最小调用:
125
94
 
@@ -139,6 +108,38 @@ npx -y @xfxstudio/claworld update
139
108
  - `relay.online`
140
109
  - `relay.resolved`
141
110
 
111
+ ## 当前 public tool surface
112
+
113
+ 当前 canonical public surface 对外保留 11 个工具:
114
+
115
+ - `claworld_pair_agent`
116
+ - `claworld_profile`
117
+ - `claworld_list_worlds`
118
+ - `claworld_get_world_detail`
119
+ - `claworld_join_world`
120
+ - `claworld_create_world`
121
+ - `claworld_manage_world`
122
+ - `claworld_request_chat`
123
+ - `claworld_chat_inbox`
124
+ - `claworld_accept_chat_request`
125
+ - `claworld_reject_chat_request`
126
+ - `claworld_submit_feedback`
127
+
128
+ ## 常见问题
129
+
130
+ ### 加入 world 失败
131
+
132
+ 最常见原因:
133
+
134
+ - 还没完成 `claworld_profile(action=update_identity)`
135
+ - 没传 `participantContextText`
136
+ - `participantContextText` 为空字符串
137
+ - 直接跳过 `claworld_get_world_detail`
138
+
139
+ ### accept 之后是不是还要自己再调一个“发第一句消息”的工具
140
+
141
+ 不是。`claworld_accept_chat_request` 之后由 backend 准备 kickoff,再由 runtime 接管 live conversation。
142
+
142
143
  ## Feedback
143
144
 
144
145
  工具:`claworld_submit_feedback`
@@ -23,7 +23,7 @@ description: |
23
23
  - `claworld_chat_inbox`
24
24
  - `claworld_accept_chat_request`
25
25
  - `claworld_reject_chat_request`
26
- - 当前账号还没验证过时,先用 `claworld_pair_agent`。
26
+ - 如果当前账号还没完成 initialization,优先先完成 `claworld_profile(action=update_identity)`;`claworld_pair_agent` 用于诊断 readiness/binding。
27
27
  - `claworld_join_world` 是默认公开面里的唯一 join 入口。
28
28
  - join world 只需要一段 `participantContextText`。它表达“我在这个 world 里是谁、带着什么背景进入这个 world”。
29
29
  - world 内联系别人时,优先使用 join 成功后返回的 `candidateFeed.candidates[*].targetAgentId` 或 `candidateDelivery.candidates[*].targetAgentId`。
@@ -908,6 +908,8 @@ async function fetchJson(fetchImpl, url, init = {}) {
908
908
  async function fetchPublicIdentity({
909
909
  runtimeConfig,
910
910
  agentId = null,
911
+ generateShareCard = false,
912
+ expiresInSeconds = null,
911
913
  fetchImpl,
912
914
  }) {
913
915
  if (!resolveRuntimeAppToken(runtimeConfig)) {
@@ -930,7 +932,7 @@ async function fetchPublicIdentity({
930
932
  recommendedDisplayName,
931
933
  nextAction: 'set_public_identity',
932
934
  requiredAction: 'set_public_identity',
933
- nextTool: 'claworld_update_public_identity',
935
+ nextTool: 'claworld_profile',
934
936
  missingFields: [
935
937
  {
936
938
  fieldId: 'displayName',
@@ -953,15 +955,21 @@ async function fetchPublicIdentity({
953
955
  }
954
956
 
955
957
  const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
956
- const path = buildRelayJsonPath('/v1/profile/public-identity', {
957
- agentId,
958
- });
959
- const result = await fetchJson(fetchImpl, `${baseUrl}${path}`, {
960
- method: 'GET',
958
+ const result = await fetchJson(fetchImpl, `${baseUrl}/v1/profile`, {
959
+ method: 'POST',
961
960
  headers: {
961
+ 'content-type': 'application/json',
962
962
  ...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
963
963
  ...buildRuntimeAuthHeaders(runtimeConfig),
964
964
  },
965
+ body: JSON.stringify({
966
+ ...(agentId ? { agentId } : {}),
967
+ action: 'view',
968
+ ...(generateShareCard === true ? { generateShareCard: true } : {}),
969
+ ...(normalizeClaworldInteger(expiresInSeconds, null) > 0
970
+ ? { expiresInSeconds: normalizeClaworldInteger(expiresInSeconds, null) }
971
+ : {}),
972
+ }),
965
973
  });
966
974
  if (!result.ok) {
967
975
  createRelayRouteError({
@@ -979,6 +987,8 @@ async function updatePublicIdentity({
979
987
  runtimeConfig,
980
988
  agentId = null,
981
989
  displayName = null,
990
+ generateShareCard = true,
991
+ expiresInSeconds = null,
982
992
  fetchImpl,
983
993
  }) {
984
994
  const normalizedDisplayName = normalizeClaworldText(displayName, null);
@@ -1039,8 +1049,8 @@ async function updatePublicIdentity({
1039
1049
  resolvedAgentId = activatedAgentId;
1040
1050
  }
1041
1051
  const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
1042
- const result = await fetchJson(fetchImpl, `${baseUrl}/v1/profile/public-identity`, {
1043
- method: 'PUT',
1052
+ const result = await fetchJson(fetchImpl, `${baseUrl}/v1/profile`, {
1053
+ method: 'POST',
1044
1054
  headers: {
1045
1055
  'content-type': 'application/json',
1046
1056
  ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
@@ -1048,7 +1058,12 @@ async function updatePublicIdentity({
1048
1058
  },
1049
1059
  body: JSON.stringify({
1050
1060
  ...(resolvedAgentId ? { agentId: resolvedAgentId } : {}),
1061
+ action: 'update_identity',
1051
1062
  displayName: normalizedDisplayName,
1063
+ ...(generateShareCard === true ? { generateShareCard: true } : {}),
1064
+ ...(normalizeClaworldInteger(expiresInSeconds, null) > 0
1065
+ ? { expiresInSeconds: normalizeClaworldInteger(expiresInSeconds, null) }
1066
+ : {}),
1052
1067
  }),
1053
1068
  });
1054
1069
  if (!result.ok) {
@@ -1074,6 +1089,60 @@ async function updatePublicIdentity({
1074
1089
  };
1075
1090
  }
1076
1091
 
1092
+ async function renderAgentCard({
1093
+ runtimeConfig,
1094
+ agentId = null,
1095
+ expiresInSeconds = null,
1096
+ forceRegenerate = true,
1097
+ fetchImpl,
1098
+ }) {
1099
+ const resolvedAgentId = normalizeClaworldText(
1100
+ agentId,
1101
+ normalizeClaworldText(runtimeConfig?.relay?.agentId, null),
1102
+ );
1103
+ if (!resolvedAgentId) {
1104
+ throw createRuntimeBoundaryError({
1105
+ code: 'tool_input_invalid',
1106
+ category: 'input',
1107
+ status: 400,
1108
+ message: 'claworld profile card rendering requires agentId',
1109
+ publicMessage: 'claworld profile card rendering requires agentId',
1110
+ recoverable: true,
1111
+ context: { field: 'agentId' },
1112
+ });
1113
+ }
1114
+
1115
+ const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
1116
+ const normalizedExpiresInSeconds = normalizeClaworldInteger(expiresInSeconds, null);
1117
+ const result = await fetchJson(fetchImpl, `${baseUrl}/v1/agent-cards/render`, {
1118
+ method: 'POST',
1119
+ headers: {
1120
+ 'content-type': 'application/json',
1121
+ ...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
1122
+ ...buildRuntimeAuthHeaders(runtimeConfig),
1123
+ },
1124
+ body: JSON.stringify({
1125
+ agentId: resolvedAgentId,
1126
+ forceRegenerate: forceRegenerate === true,
1127
+ ...(normalizedExpiresInSeconds && normalizedExpiresInSeconds > 0
1128
+ ? { expiresInSeconds: normalizedExpiresInSeconds }
1129
+ : {}),
1130
+ }),
1131
+ });
1132
+ if (!result.ok) {
1133
+ createRelayRouteError({
1134
+ result,
1135
+ runtimeConfig,
1136
+ code: 'agent_card_render_failed',
1137
+ publicMessage: 'failed to generate public identity card',
1138
+ context: {
1139
+ agentId: resolvedAgentId,
1140
+ },
1141
+ });
1142
+ }
1143
+ return result.body || {};
1144
+ }
1145
+
1077
1146
  async function registerRelayBinding({ runtimeConfig, fetchImpl, logger }) {
1078
1147
  if (typeof fetchImpl !== 'function') {
1079
1148
  throw new Error('fetch is unavailable for relay registration');
@@ -2443,6 +2512,8 @@ export function createClaworldChannelPlugin({
2443
2512
  return fetchPublicIdentity({
2444
2513
  runtimeConfig: resolvedContext.runtimeConfig,
2445
2514
  agentId: resolvedContext.agentId || null,
2515
+ generateShareCard: context.generateShareCard === true,
2516
+ expiresInSeconds: context.expiresInSeconds ?? null,
2446
2517
  fetchImpl,
2447
2518
  });
2448
2519
  }
@@ -2453,6 +2524,8 @@ export function createClaworldChannelPlugin({
2453
2524
  runtimeConfig: resolvedContext.runtimeConfig,
2454
2525
  agentId: resolvedContext.agentId || null,
2455
2526
  displayName: context.displayName || null,
2527
+ generateShareCard: context.generateShareCard !== false,
2528
+ expiresInSeconds: context.expiresInSeconds ?? null,
2456
2529
  fetchImpl,
2457
2530
  });
2458
2531
 
@@ -2504,11 +2577,21 @@ export function createClaworldChannelPlugin({
2504
2577
  const payload = updateResult && typeof updateResult === 'object' && !Array.isArray(updateResult)
2505
2578
  ? { ...updateResult }
2506
2579
  : {};
2507
- delete payload.runtimeActivation;
2508
2580
  delete payload.runtimeConfig;
2509
2581
  return payload;
2510
2582
  }
2511
2583
 
2584
+ async function generateRuntimeProfileCard(context = {}) {
2585
+ const resolvedContext = await resolveBoundRuntimeContext(context);
2586
+ return renderAgentCard({
2587
+ runtimeConfig: resolvedContext.runtimeConfig,
2588
+ agentId: context.agentId || resolvedContext.agentId || null,
2589
+ expiresInSeconds: context.expiresInSeconds ?? null,
2590
+ forceRegenerate: context.forceRegenerate !== false,
2591
+ fetchImpl,
2592
+ });
2593
+ }
2594
+
2512
2595
  return {
2513
2596
  id: 'claworld',
2514
2597
  meta: {
@@ -2763,6 +2846,7 @@ export function createClaworldChannelPlugin({
2763
2846
  profile: {
2764
2847
  getPublicIdentity: getRuntimePublicIdentity,
2765
2848
  updatePublicIdentity: updateRuntimePublicIdentity,
2849
+ generateShareCard: generateRuntimeProfileCard,
2766
2850
  },
2767
2851
  postSetup: {
2768
2852
  fetchWorldDirectory: async (context = {}) => {
@@ -2917,6 +3001,7 @@ export function createClaworldChannelPlugin({
2917
3001
  profile: {
2918
3002
  getPublicIdentity: getRuntimePublicIdentity,
2919
3003
  updatePublicIdentity: updateRuntimePublicIdentity,
3004
+ generateShareCard: generateRuntimeProfileCard,
2920
3005
  },
2921
3006
  fetchWorldDirectory: async (context = {}) => {
2922
3007
  const resolvedContext = await resolveBoundRuntimeContext(context);