@lotaber_wang/openclaw-dc-plugin 0.1.5 → 0.1.6

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
@@ -87,10 +87,11 @@ openclaw plugins install @lotaber_wang/openclaw-dc-plugin
87
87
  - 本机 Node 版本是否 >= 18.14.1
88
88
  - OpenClaw 进程是否有临时目录写权限
89
89
 
90
- 从 `0.1.5` 开始,插件 bridge 会额外做这些兼容处理:
90
+ 从 `0.1.6` 开始,插件 bridge 会额外做这些兼容处理:
91
91
 
92
92
  - `initialize` 超时后自动切换到无缓冲 / PTY 启动策略重试
93
- - `initialize` 默认超时提升到 20 秒,避免宿主启动稍慢时过早失败
93
+ - `initialize` 默认超时提升到 45 秒,避免宿主启动稍慢时过早失败
94
94
  - 兼容解析裸 JSON 输出,不再只接受 `Content-Length` 帧
95
95
  - 启动时如果 stdout 混入人类可读日志,会先自动丢弃噪音再解析协议消息
96
+ - 如果拿到的是半截 JSON,会先继续等待后续分片,而不是立刻按失败处理
96
97
  - 过滤 PTY 场景下被回显到 stdout 的请求消息
package/index.js CHANGED
@@ -697,10 +697,6 @@ const plugin = {
697
697
  for (const definition of toolDefinitions) {
698
698
  registerProxyTool(api, bridge, definition);
699
699
  }
700
-
701
- api.logger.info?.(
702
- `[TapTap DC] OpenClaw plugin v${pluginVersion} initialised with ${toolDefinitions.length} tools`
703
- );
704
700
  },
705
701
  };
706
702
 
package/lib/mcp-bridge.js CHANGED
@@ -9,7 +9,7 @@ import { fileURLToPath } from 'node:url';
9
9
  const require = createRequire(import.meta.url);
10
10
  const HEADER_SEPARATOR = '\r\n\r\n';
11
11
  const RUNTIME_PACKAGE_NAME = '@mikoto_zero/minigame-open-mcp';
12
- const DEFAULT_INIT_TIMEOUT_MS = 20000;
12
+ const DEFAULT_INIT_TIMEOUT_MS = 45000;
13
13
  const ANSI_ESCAPE_REGEX = /\x1B\[[0-?]*[ -/]*[@-~]/g;
14
14
 
15
15
  function readPluginPackageJson() {
@@ -121,6 +121,36 @@ function trimNonProtocolNoise(buffer, logger) {
121
121
  return buffer;
122
122
  }
123
123
 
124
+ function looksLikeJsonRpcPayload(text) {
125
+ return /"jsonrpc"\s*:\s*"2\.0"/.test(text) || /"method"\s*:/.test(text) || /"result"\s*:/.test(text);
126
+ }
127
+
128
+ function safeParseJson(text) {
129
+ try {
130
+ return {
131
+ kind: 'ok',
132
+ value: JSON.parse(text),
133
+ };
134
+ } catch (error) {
135
+ const message = error instanceof Error ? error.message : String(error);
136
+ if (
137
+ message.includes('Unexpected end of JSON input') ||
138
+ message.includes('Unterminated string') ||
139
+ message.includes('Expected double-quoted property name')
140
+ ) {
141
+ return {
142
+ kind: 'incomplete',
143
+ error,
144
+ };
145
+ }
146
+
147
+ return {
148
+ kind: 'invalid',
149
+ error,
150
+ };
151
+ }
152
+ }
153
+
124
154
  function parseBareJsonMessage(buffer) {
125
155
  const text = buffer.toString('utf8');
126
156
  let start = 0;
@@ -196,7 +226,7 @@ function findNextMessageOffset(buffer) {
196
226
  return Math.min(framedIndex, jsonIndex);
197
227
  }
198
228
 
199
- function parseMessageBuffer(buffer, onMessage) {
229
+ function parseMessageBuffer(buffer, onMessage, logger) {
200
230
  let offset = 0;
201
231
 
202
232
  while (offset < buffer.length) {
@@ -221,7 +251,20 @@ function parseMessageBuffer(buffer, onMessage) {
221
251
  }
222
252
 
223
253
  const bodyText = buffer.subarray(bodyStart, bodyEnd).toString('utf8');
224
- onMessage(JSON.parse(bodyText));
254
+ const parsed = safeParseJson(bodyText);
255
+ if (parsed.kind === 'ok') {
256
+ onMessage(parsed.value);
257
+ offset = bodyEnd;
258
+ continue;
259
+ }
260
+
261
+ if (parsed.kind === 'incomplete') {
262
+ break;
263
+ }
264
+
265
+ logger?.info?.(
266
+ `[TapTap DC] Ignoring invalid framed MCP payload: ${bodyText.slice(0, 300)}`
267
+ );
225
268
  offset = bodyEnd;
226
269
  continue;
227
270
  }
@@ -229,7 +272,26 @@ function parseMessageBuffer(buffer, onMessage) {
229
272
 
230
273
  const bareJson = parseBareJsonMessage(buffer.subarray(offset));
231
274
  if (bareJson) {
232
- onMessage(JSON.parse(bareJson.raw));
275
+ const parsed = safeParseJson(bareJson.raw);
276
+ if (parsed.kind === 'ok') {
277
+ if (looksLikeJsonRpcPayload(bareJson.raw)) {
278
+ onMessage(parsed.value);
279
+ } else {
280
+ logger?.info?.(
281
+ `[TapTap DC] Ignoring bare JSON stdout noise: ${bareJson.raw.slice(0, 300)}`
282
+ );
283
+ }
284
+ offset += bareJson.consumedBytes;
285
+ continue;
286
+ }
287
+
288
+ if (parsed.kind === 'incomplete') {
289
+ break;
290
+ }
291
+
292
+ logger?.info?.(
293
+ `[TapTap DC] Ignoring invalid bare JSON payload: ${bareJson.raw.slice(0, 300)}`
294
+ );
233
295
  offset += bareJson.consumedBytes;
234
296
  continue;
235
297
  }
@@ -594,8 +656,10 @@ export class TapTapMcpBridge {
594
656
  try {
595
657
  this.stdoutBuffer = Buffer.concat([this.stdoutBuffer, chunk]);
596
658
  this.stdoutBuffer = trimNonProtocolNoise(this.stdoutBuffer, this.logger);
597
- this.stdoutBuffer = parseMessageBuffer(this.stdoutBuffer, (message) =>
598
- this.handleMessage(message)
659
+ this.stdoutBuffer = parseMessageBuffer(
660
+ this.stdoutBuffer,
661
+ (message) => this.handleMessage(message),
662
+ this.logger
599
663
  );
600
664
  } catch (error) {
601
665
  this.logger?.error?.(
@@ -2,7 +2,7 @@
2
2
  "id": "taptap-dc-plugin",
3
3
  "name": "TapTap DC",
4
4
  "description": "面向 OpenClaw 的 TapTap DC 插件,内置原始数据工具与运营简报 skill。",
5
- "version": "0.1.5",
5
+ "version": "0.1.6",
6
6
  "skills": ["./skills"],
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotaber_wang/openclaw-dc-plugin",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "description": "TapTap DC 的 OpenClaw 插件,内置原始数据工具与运营简报 skill。",
6
6
  "main": "index.js",