chatccc 0.2.149 → 0.2.150

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.
@@ -19,12 +19,21 @@
19
19
 
20
20
  ## 卡住自检
21
21
 
22
- 如果你感觉任务已经完成,但发现自己陷入了循环(反复调用相同工具、输出 "stuck in a loop" 等),**立即**调用以下接口:
22
+ 如果你感觉任务已经完成,但发现自己陷入了循环(反复调用相同工具、输出 "stuck in a loop" 等),**立即**调用以下接口。
23
23
 
24
- POST {{stop_stuck_url}}
25
- Content-Type: application/json
24
+ **重要:必须用 heredoc 写临时文件再 curl,禁止在命令行参数中直接写中文 JSON。** Windows 下命令行参数传中文会变成 `?` 乱码。
26
25
 
26
+ ```bash
27
+ cat > /tmp/stop_ccc.json << 'STOPJSON'
27
28
  {"session_id": "{{session_id}}", "final_reply": "<你给用户的最终回复,总结已完成的工作和结果>"}
29
+ STOPJSON
30
+ curl -s -X POST {{stop_stuck_url}} -H "Content-Type: application/json" -d @/tmp/stop_ccc.json
31
+ ```
32
+
33
+ final_reply 注意事项:
34
+ - 把 `<...>` 占位符替换为你的实际回复,不要包含双引号 `"` 和反斜杠 `\`
35
+ - 不要包含换行,用空格代替
36
+ - 保持简短(1-2 句话)
28
37
 
29
38
  调用后停止所有工具调用,直接输出最终回复即可。
30
39
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.149",
3
+ "version": "0.2.150",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -4,6 +4,21 @@ import { TextDecoder } from "node:util";
4
4
  // Windows 下 curl 传中文可能用 GBK 编码而非 UTF-8,按顺序尝试解码
5
5
  const FALLBACK_ENCODINGS = ["gbk", "gb2312", "latin1"];
6
6
 
7
+ /**
8
+ * 检测 UTF-8 解码结果是否看起来像乱码(GBK 字节被误当 UTF-8 解析)。
9
+ * 典型特征:有 Latin-1 补充字符(U+0080-U+00FF)但没有 CJK 字符。
10
+ */
11
+ function hasGarbledPattern(text: string): boolean {
12
+ let latin1Count = 0;
13
+ let cjkCount = 0;
14
+ for (const ch of text) {
15
+ const code = ch.codePointAt(0) ?? 0;
16
+ if (code >= 0x4E00 && code <= 0x9FFF) cjkCount++;
17
+ if (code >= 0x0080 && code <= 0x00FF) latin1Count++;
18
+ }
19
+ return latin1Count > 0 && cjkCount === 0;
20
+ }
21
+
7
22
  function normalizeHeaderValue(value: string | string[] | undefined): string {
8
23
  if (Array.isArray(value)) return value.join("; ");
9
24
  return value ?? "";
@@ -43,7 +58,27 @@ export async function readUtf8JsonBody<T>(req: IncomingMessage, maxBytes: number
43
58
  const body = await readLimitedBodyBuffer(req, maxBytes);
44
59
 
45
60
  // 首选 UTF-8;若 JSON 解析失败则尝试常见中文编码
46
- for (const enc of ["utf-8", ...FALLBACK_ENCODINGS]) {
61
+ // 注意:UTF-8 解码可能"成功"但实际是 GBK 字节被误当 UTF-8 解析,
62
+ // 此时 JSON 也能解析通过但中文变成乱码。通过 hasGarbledPattern 检测
63
+ // 这种"假成功"并回退到 GBK。
64
+ try {
65
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(body);
66
+ const parsed = JSON.parse(text) as T;
67
+ if (hasGarbledPattern(text)) {
68
+ // UTF-8 解码出的文本看起来像乱码,尝试 GBK
69
+ try {
70
+ const gbkText = new TextDecoder("gbk", { fatal: true }).decode(body);
71
+ return JSON.parse(gbkText) as T;
72
+ } catch {
73
+ // GBK 也不行,用 UTF-8 结果
74
+ }
75
+ }
76
+ return parsed;
77
+ } catch {
78
+ // UTF-8 解码失败,尝试其他编码
79
+ }
80
+
81
+ for (const enc of FALLBACK_ENCODINGS) {
47
82
  try {
48
83
  const text = new TextDecoder(enc, { fatal: true }).decode(body);
49
84
  return JSON.parse(text) as T;