@lotaber_wang/openclaw-dc-plugin 0.1.14 → 0.1.15
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 +6 -5
- package/index.js +110 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
- package/scripts/postinstall.js +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
请这样安装:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.
|
|
12
|
+
openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.15
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
不要这样安装:
|
|
@@ -67,7 +67,7 @@ openclaw gateway restart
|
|
|
67
67
|
## 推荐安装流程
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.
|
|
70
|
+
openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.15
|
|
71
71
|
openclaw plugins inspect openclaw-dc-plugin
|
|
72
72
|
echo 'TapTap DC 插件已安装完成。OpenClaw 接下来如需重启 Gateway,应先通过飞书或其他通信插件通知用户;重启完成后即可使用 taptap_dc_* 工具。'
|
|
73
73
|
openclaw gateway restart
|
|
@@ -77,7 +77,7 @@ openclaw gateway restart
|
|
|
77
77
|
|
|
78
78
|
- `install` 负责把插件包装进 OpenClaw
|
|
79
79
|
- `inspect` 用来确认插件元信息、skills、tools 是否已被 Gateway 识别
|
|
80
|
-
- 从 `0.1.
|
|
80
|
+
- 从 `0.1.15` 开始,插件包不再声明 `openclaw` 的 `peerDependencies`,避免误用 `npm install` 时把 OpenClaw 宿主大依赖树一起拉下来
|
|
81
81
|
- 如果有人误用 `npm install` 或 `npm install -g`,插件包会在 `postinstall` 阶段打印醒目的纠正提示
|
|
82
82
|
- 如果宿主判断需要重启 Gateway,必须先通过飞书或其他通信插件通知用户,再重启
|
|
83
83
|
- 如果 10-30 秒后还没生效,再手动执行 `gateway restart`
|
|
@@ -147,7 +147,7 @@ openclaw gateway restart
|
|
|
147
147
|
|
|
148
148
|
如果安装后看不到 `taptap_dc_*` 工具,优先按这个顺序排查:
|
|
149
149
|
|
|
150
|
-
1. 确认安装的是 `@lotaber_wang/openclaw-dc-plugin@0.1.
|
|
150
|
+
1. 确认安装的是 `@lotaber_wang/openclaw-dc-plugin@0.1.15` 或更新版本
|
|
151
151
|
2. 执行 `openclaw plugins inspect openclaw-dc-plugin`
|
|
152
152
|
3. 如果宿主要求重启 Gateway,先通过飞书或其他通信插件向用户发送安装完成提示
|
|
153
153
|
4. 再执行 `openclaw gateway restart`
|
|
@@ -175,7 +175,7 @@ openclaw gateway restart
|
|
|
175
175
|
- OpenClaw 进程是否有临时目录写权限
|
|
176
176
|
- OpenClaw 是否已经完成 Gateway 重启
|
|
177
177
|
|
|
178
|
-
从 `0.1.
|
|
178
|
+
从 `0.1.15` 开始,插件安装链路与 bridge 会额外做这些兼容处理:
|
|
179
179
|
|
|
180
180
|
- 在 `package.json` 中补充 `openclaw.install.npmSpec`,让安装链路更稳定
|
|
181
181
|
- 在 `package.json` 的 `openclaw.install` 中补充 `preferredCommand` / `doNotUseCommands` / `wrongInstallHint`
|
|
@@ -194,3 +194,4 @@ openclaw gateway restart
|
|
|
194
194
|
- 如果拿到的是半截 JSON,会先继续等待后续分片,而不是立刻按失败处理
|
|
195
195
|
- 过滤 PTY 场景下被回显到 stdout 的请求消息
|
|
196
196
|
- 授权结果会把裸授权直链放在最前面,并在 `details.preferred_auth_url` / `details.auth_links` 中重复返回,降低宿主偶发吞链路时的影响
|
|
197
|
+
- 如果原始 tool 调用直接抛出“缺少认证信息”错误,bridge 也会从错误文本里提取 `wrapped_auth_url`,并补出 `preferred_auth_url`、手机端点击链接,以及“从 code 参数 decodeURIComponent 得到直链”的解析提示
|
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { TapTapMcpBridge } from './lib/mcp-bridge.js';
|
|
|
5
5
|
const RESTART_NOTICE =
|
|
6
6
|
'TapTap DC 插件已安装完成。OpenClaw 接下来如需重启 Gateway,应先通过飞书或其他通信插件通知用户;重启完成后即可使用 taptap_dc_* 工具。';
|
|
7
7
|
const PREFERRED_INSTALL_COMMAND =
|
|
8
|
-
'openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.
|
|
8
|
+
'openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.15';
|
|
9
9
|
const WRONG_INSTALL_HINT =
|
|
10
10
|
'这是 OpenClaw 插件包,不是普通 npm CLI 包。请不要直接用 npm install,改用 openclaw plugins install。';
|
|
11
11
|
|
|
@@ -100,6 +100,29 @@ function decodeWrappedAuthUrl(value) {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
function extractUrlsFromText(value) {
|
|
104
|
+
if (!value || typeof value !== 'string') {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const matches = value.match(/https?:\/\/[^\s"'<>]+/g) || [];
|
|
109
|
+
return matches.map((item) => item.replace(/[),.;]+$/g, ''));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function buildAuthLinkParseHint(wrappedAuthUrl, directAuthUrl, preferredAuthUrl) {
|
|
113
|
+
return {
|
|
114
|
+
mobile_click_url: preferredAuthUrl || directAuthUrl || wrappedAuthUrl || null,
|
|
115
|
+
wrapped_auth_url: wrappedAuthUrl || null,
|
|
116
|
+
direct_auth_url: directAuthUrl || null,
|
|
117
|
+
parse_rule:
|
|
118
|
+
wrappedAuthUrl && directAuthUrl
|
|
119
|
+
? '如果只有 wrapped_auth_url,请读取其中的 code 参数,并执行一次 decodeURIComponent(code),得到 direct_auth_url。手机端优先打开 direct_auth_url。'
|
|
120
|
+
: '如果当前是手机端会话,请优先展示 preferred_auth_url;如果宿主吞掉超链接,就直接输出这条裸 URL。',
|
|
121
|
+
display_rule:
|
|
122
|
+
'如果当前是手机端或移动端对话,请把 mobile_click_url 单独作为一条消息再次发给用户,便于直接点击授权。',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
103
126
|
function enrichAuthPayload(authPayload) {
|
|
104
127
|
if (!authPayload || typeof authPayload !== 'object') {
|
|
105
128
|
return authPayload;
|
|
@@ -154,6 +177,11 @@ function enrichAuthPayload(authPayload) {
|
|
|
154
177
|
authorization_url: preferredAuthUrl,
|
|
155
178
|
mobile_auth_url: preferredAuthUrl,
|
|
156
179
|
auth_links: authLinks,
|
|
180
|
+
auth_link_parse_hint: buildAuthLinkParseHint(
|
|
181
|
+
wrappedAuthUrl,
|
|
182
|
+
directAuthUrl,
|
|
183
|
+
preferredAuthUrl
|
|
184
|
+
),
|
|
157
185
|
next_action:
|
|
158
186
|
'优先打开 preferred_auth_url 完成授权;完成后调用 taptap_dc_complete_authorization。',
|
|
159
187
|
};
|
|
@@ -364,9 +392,79 @@ function buildAuthGuideText(authPayload) {
|
|
|
364
392
|
lines.push(`授权页直链:${qrcodeUrl}`);
|
|
365
393
|
}
|
|
366
394
|
|
|
395
|
+
lines.push(
|
|
396
|
+
'',
|
|
397
|
+
'给 Agent / 龙虾的额外处理提示:',
|
|
398
|
+
'- 如果当前是手机端对话,请把 `preferred_auth_url` 或 `mobile_auth_url` 单独再发一条消息给用户,方便直接点击授权。',
|
|
399
|
+
'- 如果你只拿到了 TapTap 包装授权页(`wrapped_auth_url`),请取其中的 `code` 参数,再执行一次 `decodeURIComponent(code)`,即可得到更适合手机端直接点击的 `direct_auth_url`。',
|
|
400
|
+
'- 如果宿主把 markdown 链接吞掉了,请直接输出 `details.preferred_auth_url` 这条裸 URL,不要只说“请扫码”。'
|
|
401
|
+
);
|
|
402
|
+
|
|
367
403
|
return lines.join('\n');
|
|
368
404
|
}
|
|
369
405
|
|
|
406
|
+
function looksLikeAuthErrorMessage(message) {
|
|
407
|
+
if (!message || typeof message !== 'string') {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return (
|
|
412
|
+
message.includes('缺少认证信息') ||
|
|
413
|
+
message.includes('需要 TapTap 授权') ||
|
|
414
|
+
message.includes('当前没有有效的 TapTap 认证信息') ||
|
|
415
|
+
message.includes('complete_oauth_authorization') ||
|
|
416
|
+
extractUrlsFromText(message).some((url) => url.includes('tap-qrcode'))
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function extractAuthPayloadFromErrorMessage(message) {
|
|
421
|
+
if (!looksLikeAuthErrorMessage(message)) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const urls = extractUrlsFromText(message);
|
|
426
|
+
if (urls.length === 0) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const wrappedAuthUrl =
|
|
431
|
+
urls.find((url) => url.includes('tap-qrcode')) ||
|
|
432
|
+
urls.find((url) => tryParseUrl(url)?.searchParams?.has('code')) ||
|
|
433
|
+
null;
|
|
434
|
+
|
|
435
|
+
const decodedDirectUrl = decodeWrappedAuthUrl(wrappedAuthUrl);
|
|
436
|
+
const directAuthUrl =
|
|
437
|
+
urls.find((url) => url !== wrappedAuthUrl && !url.includes('tap-qrcode')) || decodedDirectUrl;
|
|
438
|
+
|
|
439
|
+
return enrichAuthPayload({
|
|
440
|
+
auth_url: wrappedAuthUrl,
|
|
441
|
+
wrapped_auth_url: wrappedAuthUrl,
|
|
442
|
+
direct_auth_url: directAuthUrl,
|
|
443
|
+
preferred_auth_url: directAuthUrl || wrappedAuthUrl,
|
|
444
|
+
source: 'bridge_error_message',
|
|
445
|
+
original_error_message: message,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function buildAuthRecoveryTextFromError(message) {
|
|
450
|
+
const authPayload = extractAuthPayloadFromErrorMessage(message);
|
|
451
|
+
if (!authPayload) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return {
|
|
456
|
+
text: [
|
|
457
|
+
'当前工具调用失败,但桥接层已经识别到这是“缺少 TapTap 授权信息”的场景。',
|
|
458
|
+
'',
|
|
459
|
+
buildAuthGuideText(authPayload),
|
|
460
|
+
'',
|
|
461
|
+
'原始错误摘要:',
|
|
462
|
+
message,
|
|
463
|
+
].join('\n'),
|
|
464
|
+
details: authPayload,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
370
468
|
async function callJsonTool(bridge, name, args = {}) {
|
|
371
469
|
const text = await bridge.callTool(name, args);
|
|
372
470
|
const normalized = normalizeJsonText(text);
|
|
@@ -452,12 +550,22 @@ function registerProxyTool(api, bridge, definition) {
|
|
|
452
550
|
parsed: normalizedParsed,
|
|
453
551
|
});
|
|
454
552
|
} catch (error) {
|
|
553
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
554
|
+
const authRecovery = buildAuthRecoveryTextFromError(message);
|
|
555
|
+
if (authRecovery) {
|
|
556
|
+
return toolResult(authRecovery.text, {
|
|
557
|
+
mcpToolName: definition.mcpToolName,
|
|
558
|
+
auth_recovery: authRecovery.details,
|
|
559
|
+
original_error_message: message,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
455
563
|
return toolResult(
|
|
456
564
|
JSON.stringify(
|
|
457
565
|
{
|
|
458
566
|
ok: false,
|
|
459
567
|
error: 'PLUGIN_PROXY_ERROR',
|
|
460
|
-
message
|
|
568
|
+
message,
|
|
461
569
|
},
|
|
462
570
|
null,
|
|
463
571
|
2
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-dc-plugin",
|
|
3
3
|
"name": "TapTap DC",
|
|
4
4
|
"description": "面向 OpenClaw 的 TapTap DC 插件。请使用 openclaw plugins install 安装,不要直接 npm install;如需重启 Gateway,应先通过飞书或其他通信插件通知用户。",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.15",
|
|
6
6
|
"enabledByDefault": true,
|
|
7
7
|
"skills": ["./skills"],
|
|
8
8
|
"configSchema": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lotaber_wang/openclaw-dc-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TapTap DC 的 OpenClaw 插件。请使用 openclaw plugins install 安装,不要直接 npm install;如需重启 Gateway,应先通过飞书或其他通信插件通知用户。",
|
|
6
6
|
"main": "index.js",
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
],
|
|
14
14
|
"install": {
|
|
15
15
|
"npmSpec": "@lotaber_wang/openclaw-dc-plugin",
|
|
16
|
-
"preferredCommand": "openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.
|
|
16
|
+
"preferredCommand": "openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.15",
|
|
17
17
|
"doNotUseCommands": [
|
|
18
18
|
"npm install @lotaber_wang/openclaw-dc-plugin",
|
|
19
19
|
"npm install -g @lotaber_wang/openclaw-dc-plugin"
|
|
20
20
|
],
|
|
21
|
-
"wrongInstallHint": "这是 OpenClaw 插件包,不是普通 npm CLI 包。请改用 openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.
|
|
21
|
+
"wrongInstallHint": "这是 OpenClaw 插件包,不是普通 npm CLI 包。请改用 openclaw plugins install @lotaber_wang/openclaw-dc-plugin@0.1.15。",
|
|
22
22
|
"postInstallMessage": "TapTap DC 插件已安装完成。OpenClaw 接下来如需重启 Gateway,应先通过飞书或其他通信插件通知用户;重启完成后即可使用 taptap_dc_* 工具。",
|
|
23
23
|
"restartRequired": true,
|
|
24
24
|
"restartCommand": "openclaw gateway restart",
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import process from 'node:process';
|
|
2
2
|
|
|
3
3
|
const PACKAGE_NAME = '@lotaber_wang/openclaw-dc-plugin';
|
|
4
|
-
const PACKAGE_VERSION = '0.1.
|
|
4
|
+
const PACKAGE_VERSION = '0.1.15';
|
|
5
5
|
const PREFERRED_COMMAND = `openclaw plugins install ${PACKAGE_NAME}@${PACKAGE_VERSION}`;
|
|
6
6
|
const DISCOURAGED_COMMANDS = [
|
|
7
7
|
`npm install ${PACKAGE_NAME}`,
|