Wechat-ggGitHub
50143077c0
feat: 工具噪音过滤,剥离上游 provider 塞进 text_delta 的工具 IO
...
Z.ai 等聚合代理把服务端内置工具(analyze_image 等)的输入/输出当作
assistant 文本下发,bridge 不加区分地透传到微信,导致后半程消息变成
JSON dump,并加速撞 iLink 11 条配额。本提交在 TurnRouter emit 回调
单点接入 filterToolNoise:三条件 AND(长度 > 400 + ```json 围栏 +
URL/路径)识别工具噪音,行级 tail 提取保留 Claude 的真正旁白。
真实日志回归:7 条命中全部压缩 ~90%,8 条正常样本零误伤。
2026-06-27 21:46:00 +08:00
Wechat-ggGitHub
b7a4ddb897
feat: 持久化发送队列,撞墙内容在用户下次消息时自动补发
...
iLink 服务端硬性约束:每个 context_token 累计 11 条 bot 消息后强制 ret:-2。
这是腾讯反刷屏机制,协议层无解(没有刷新 token 或重置配额的 API),
只能等用户下次发消息带新 context_token 进来才能继续发送。
客户端层缓解(方案 B):
- src/pending-queue.ts: 持久化队列 ~/.wechat-claude-code/pending-queue/<accountId>.json
- src/main.ts: handleMessage 入口 flushPending(),用户新消息到达时按 FIFO 补发;
terminal retry 失败后入队而非丢弃,给用户明确提示"下次回复自动补发"
- src/wechat/api.ts: 接入断路器(30s open)避免持续撞墙;新增 stale session 判别
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 21:27:52 +08:00
Wechat-ggGitHub
75c3f1c3ff
fix: pendingRetry 角色感知 + 流结束终态重试,避免静默丢内容
...
修最终评审发现的两处 Important 问题:
1. 流结束静默丢内容:drain() 的最后一次发送若失败,pendingRetry 没有
下一个 emit 接力,await flushChain 直接 resolve,内容卡住。新增
有上限(3 次,5/10/15s 退避)的终态重试循环,全部失败时打 error
日志 + 通知用户"部分内容因限频未能推送"。
2. 跨角色污染:pendingRetry 原本是 bare string,interstitial 失败后
会被 fuse 到下一次 final 发送里。改成 {text, role} 对象,emitText
先用原本的 role 单独补发,再发当前 role 的新内容。新增 scheduleSend
helper 共享发送+失败保留逻辑。
测试:content_block_stop 用例补充 onTurnEnd 不触发的断言。
行为不变性保留:pendingRetry 仍只在发送失败时设置;anySent/lastSentTime
更新点不变;flushChain 仍串行。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 12:53:14 +08:00
Wechat-ggGitHub
df84d6cc71
feat: main.ts 接入 TurnRouter,最终答案改为按回合整段推送
...
把 sendToClaude 原来的单 textBuffer + 段落边界 flush 逻辑替换为
TurnRouter 状态机:onText 只累积不 flush,onTurnEnd(tool_use) 立即
emit 为 interstitial,其他 stop_reason 攒到 pendingFinal,流结束时
router.drain() 一次性 emit 为 final(splitMessage 按 4000 字硬切)。
真实 trace 验证效果:
- 纯文本 Q&A(1485 字):8 条 → 1 条
- tool_use + 9121 字长答案:59 条 → 4 条
顺带清理死代码:删除 MIN_BATCH_FLUSH_LEN / SOFT_FLUSH_LIMIT /
endsWithStructuralBoundary / onBlockEnd(provider.ts 同步移除字段
和 content_block_stop 回调,测试相应更新)。
限流逻辑、splitMessage、typing、silence warning、文件自动推送
全部不动。emitText 保留了 commit d6d7d62 引入的失败重试语义
(pendingRetry)。
Spec: docs/superpowers/specs/2026-06-20-message-batching-design.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 12:43:36 +08:00
Wechat-ggGitHub
e95272eb37
feat: 新增 TurnRouter 状态机,按 stop_reason 分流 interstitial/final
...
纯逻辑模块,不持 I/O。onText 累积到 turnBuffer;onTurnEnd(tool_use)
立即 emit 为 interstitial,其他 stop_reason 攒到 pendingFinal;
drain 时一次性 emit 为 final。
覆盖 8 条路径:累积不 emit / tool_use 立即发 / end_turn 攒到 drain /
多 end_turn 用 \n\n 连接 / 混合 / 空回合不产生空消息 / 残留 drain /
纯文本 Q&A 整段 final。
下一个任务把 main.ts 接进来。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 12:34:26 +08:00
Wechat-ggGitHub
9b21854dc5
feat: provider 暴露 onTurnEnd 回调,按 stop_reason 标记回合类型
...
handleStreamLine 在收到 message_delta 事件且带 stop_reason 时触发
onTurnEnd(stopReason)。下游可据此区分 'tool_use' 回合(interstitial)
和 'end_turn' / 'max_tokens' 等终态回合(final answer)。
本任务仅暴露信号,不改变任何现有 flush 行为——main.ts 下一任务接入。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 12:31:19 +08:00
Wechat-ggGitHub
8c16c8a539
fix: handleStreamLine 恢复 callback 的 Promise.resolve 安全包装
...
提取时漏掉了原 inline 代码里 Promise.resolve(...).catch(() => {}) 的
包装。main.ts 传的 onText/onBlockEnd 是 async 的,不包装会导致 rejected
promise 变成 unhandled rejection。三处调用点(text_delta / skill 通知 /
content_block_stop)全部恢复包装,行为与重构前完全一致。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 12:27:04 +08:00
Wechat-ggGitHub
7385e4232c
refactor: 提取 handleStreamLine 为可测的纯函数
...
把 claudeQuery 里 rl.on('line') 的 NDJSON 解析 switch 体抽成独立导出函数
handleStreamLine(line, state, callbacks),状态外置到 StreamParserState。
行为完全不变,仅是为后续 onTurnEnd 接入和单元测试铺路。
附首批单元测试覆盖 system init / text_delta / content_block_stop /
assistant 文本累积 / 非法行跳过 5 条路径。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 12:24:36 +08:00
Wechat-ggGitHub
6381afa930
docs: 微信消息分块优化的 spec 与实现计划
...
spec (docs/superpowers/specs/2026-06-20-message-batching-design.md):
按 stop_reason 把 Claude CLI 流式输出分为 interstitial(agent loop 进度,
立即推)和 final(最终答案,结束才推)。真实 trace 验证:纯文本 Q&A
8→1 条,9121 字长答案 59→4 条。限流逻辑不动。
plan (docs/superpowers/plans/2026-06-20-message-batching.md):
4 个 task——提取 handleStreamLine / 加 onTurnEnd / 创建 TurnRouter /
接入 main.ts 并删死代码。每个 task 走 TDD。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 12:17:20 +08:00
Wechat-ggGitHub
d6d7d62a65
fix: preserve unsent chunks on flush failure and apply rate-limit cooldown
...
flushText previously aborted the send loop on the first failure and
dropped all remaining chunks, because the buffer had already been
cleared. Re-enqueue the unsent chunks at the front of the buffer so the
next flush retries them instead of silently losing content.
On ret:-2 rate-limit, push the per-user nextSendTime out by 60s so
subsequent sends queue for the cooldown rather than each one retrying
into the wall and exhausting its own retries.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-20 11:18:36 +08:00
Sl ldyd2077
8aead25c93
fix: support Windows paths in auto-push file detection ( #30 )
...
The extractFilePathsFromText regex only matched macOS/Linux absolute
paths (e.g. /Users/...), causing auto-push to silently fail on Windows
where paths look like C:\Users\... .
Added [A-Za-z]:[\/] pattern to match Windows drive-letter paths
alongside existing Unix and tilde paths.
Co-authored-by: Slldyd2077 <caiyudu123@163.com >
2026-06-11 22:46:19 +08:00
Awesome-GitHub
48e0da29ba
Update README.md
2026-06-10 21:19:16 +08:00
Awesome-GitHub
875fec326e
Update README.md
2026-06-10 21:17:05 +08:00
Awesome-GitHub
63d061e49d
Update README.md
2026-06-10 21:15:41 +08:00
Awesome-GitHub
0028b5b54e
Update README.md
2026-06-10 20:14:54 +08:00
Wechat-ggGitHub
ac3d53dcd8
docs: 重写 README,中文为默认,英文同步更新
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-10 18:02:33 +08:00
Wechat-ggGitHub
da02bd0fd4
docs: 简化安装命令,去掉多余选项
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-10 14:21:09 +08:00
Wechat-ggGitHub
551eb29dab
feat: 支持通过 npx skills add 安装,自动克隆项目源码
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-10 14:05:17 +08:00
Wechat-ggGitHub
857fe1b577
fix: 日志时区修复、限流错误传递、添加日志可视化工具
...
- logger.ts: 修复日志时间戳为 UTC+8,不再显示 Z 时区
- api.ts: sendMessage 限流耗尽重试后抛出错误而非静默丢弃,并提前更新限流计时
- package.json: 添加 visualize 脚本
- src/tools/visualize-logs.ts: 新增日志可视化工具
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-10 10:44:23 +08:00
Wechat-ggGitHub
8412b8f5dc
fix: 恢复 Claude CLI 查询超时为 60 分钟
...
media-writer 等重度 skill 涉及大量 web search 和长文写作,
30 分钟不够用导致任务被超时 kill。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-10 09:15:52 +08:00
Wechat-ggGitHub
70b6e6e356
fix: 修复流式文本丢失和文件推送失败两个问题
...
1. flushText 竞争条件:将 textBuffer 的读取和清空从异步回调内移到调用时同步执行,
避免 sendText 等待期间新 delta 被错误清空导致内容丢失
2. sendFile 吞错:re-throw rate-limit 错误,让 auto-push 重试机制能捕获失败
3. 文件重试策略:改为渐进式 15s→30s→45s 共 3 轮,全部失败后通知用户
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-10 01:50:37 +08:00
Wechat-ggGitHub
943571af0c
fix: 缩短 Claude CLI 查询超时从 60 分钟到 30 分钟
...
media-scout 等 skill 做网络抓取时可能卡住,60 分钟超时太长导致
用户长时间无响应。缩短到 30 分钟避免用户等待过久。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-10 01:14:33 +08:00
Wechat-ggGitHub
59a84aa034
Revert "fix: 修复消息发送限流雪崩和消息丢失两个问题"
...
This reverts commit d5d8d9cbe2 .
2026-06-09 23:01:02 +08:00
Wechat-ggGitHub
d5d8d9cbe2
fix: 修复消息发送限流雪崩和消息丢失两个问题
...
1. api.ts: ret:-2 时推进 nextSendTime 打断雪崩链,重试次数 2→4、退避 5s→30s,最终失败 throw 而非静默丢弃
2. main.ts: flushText 发送成功后再清空 textBuffer,失败时保留内容等待下次 flush 重试
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 22:41:39 +08:00
Wechat-ggGitHub
86e989763a
fix: 微信单条消息上限改为 4000 字符,对齐 openclaw-weixin 官方实现
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 22:01:34 +08:00
Wechat-ggGitHub
fc3d01308b
fix: 降低 flush 最小长度到 30 字符,去掉 3 秒兜底定时器
...
- MIN_BATCH_FLUSH_LEN 从 80 降到 30,减少不必要的卡片合并
- 去掉 3 秒定时器兜底 flush,只保留 5 分钟 keepalive
- 清理不再使用的 lastBufferChangeTime 变量
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 20:34:46 +08:00
Wechat-ggGitHub
028977bdb7
fix: 修复流式推送三个问题——flush 不等待、小卡片被拆分、长消息截断
...
1. flushText() 改为返回 Promise,查询结束后 await flushText() 能正确等待所有缓冲内容发送完毕,不再丢失最终回复
2. 结构边界和 content_block_stop 触发 flush 增加最小长度阈值(80字符),避免"正在"这种极短内容被单独推成一张卡片
3. splitMessage 的回退拆分逻辑增加句号/空格等安全分割点,减少 markdown 格式被截断的情况
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 20:25:36 +08:00
Wechat-ggGitHub
8c358dbb09
fix: 修复流式消息卡死、进度卡片合并、/stop 无法中断三个关键 bug
...
- /stop 和 /clear 现在在 onMessage 回调中直接拦截,绕过串行队列
- 添加 onBlockEnd 回调在 content_block_stop 时 flush,使进度消息分卡推送
- flushChain 添加 .catch() 防止 Promise 链断裂导致后续消息丢失
- 静默提示改为每 5 分钟重复发送
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 19:48:46 +08:00
Wechat-ggGitHub
3b2d441a25
fix: skill 通知文案改为"正在调用 xxx 技能"
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 16:54:11 +08:00
Wechat-ggGitHub
8575230d67
fix: 流式消息推送改为串行 Promise 链,修复短消息无法 flush 的问题
...
- 用 Promise chain 替换 flushing+flushPending 标志位,解决 flush 被丢弃导致消息堆积
- 移除结构边界 flush 的 MIN_FLUSH_LEN 下限,修复 skill 通知等短消息卡在 buffer
- skill 通知消息改为双换行结尾确保触发结构边界检测
- MAX_BUFFER_AGE_MS 从 5s 降至 3s 加快超时 flush
- .gitignore 添加 CLAUDE.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 16:45:27 +08:00
Wechat-ggGitHub
535df1d4d9
fix: 静默提示文案改为"我还在处理,请稍等一下"
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 16:03:36 +08:00
Wechat-ggGitHub
a89b62f859
improve: 去掉自动推送提示消息,优化系统提示词文案
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 15:31:53 +08:00
Wechat-ggGitHub
692026425d
feat: 文件推送到微信(/send 命令 + 自动推送)
...
- 新增 CDN 上传管道(AES-128-ECB 加密 → POST 上传 → 获取下载参数)
- 新增 /send <路径> 命令,支持发送任意本地文件到微信
- 自动检测 Claude 回复中的本地文件路径,推送支持的格式
- 基于 Tencent/OpenClaw 官方实现适配 API 参数和消息格式
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 15:25:42 +08:00
Wechat-ggGitHub
6a640854bf
fix: verify sender identity to prevent unauthorized access
...
Only accept messages from the bound WeChat user (account.userId),
ignoring messages from anyone else (e.g. group members @-ing the bot).
Fixes #23
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 13:15:44 +08:00
Wechat-ggGitHub
7eb8cab6f5
fix: stopTyping 时发送 CANCEL 状态给微信 API
...
之前 stopTyping() 只停止了本地 keepalive 循环,但没有通知微信服务端
停止"正在输入"状态。现在循环退出后会发送 TypingStatus.CANCEL。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 12:58:10 +08:00
Wechat-ggGitHub
41273c66c4
docs: fix README inaccuracies
...
- SDK → CLI: code spawns claude CLI, not @anthropic-ai/claude-agent-sdk
- config.env → config.json: actual filename in code
- Add missing /stop and /version commands to table
- /compact description: "SDK session" → "CLI session"
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 12:54:36 +08:00
Wechat-ggGitHub
2da8c55df8
fix: 卡片感知消息切割 + 结构感知流式 flush
...
splitMessage 改为按 \n\n 空行拆分结构化块,保证项目卡片不被切断;
流式 flush 从定时 3 秒无条件发送改为在卡片边界或软上限时才 flush。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 12:47:21 +08:00
Wechat-ggGitHub
0264d23f6a
fix: 增加查询超时至 1 小时,5 分钟无输出时发送进度提示
...
CLI 超时从 5 分钟改为 1 小时,避免复杂 skill 查询被提前终止。
新增静默检测:连续 5 分钟未向微信发送内容时,自动发送"我还在处理,请稍后"。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 12:12:08 +08:00
Wechat-ggGitHub
abed457176
feat: 消息队列模式 + 新增 /stop 命令
...
- 普通消息不再打断当前查询,改为排队等待(类似 CLI 体验)
- 新增 /stop 命令:打断当前对话并清空排队消息
- /clear 仅打断当前查询,不清空队列
- 帮助文本同步更新
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 11:20:30 +08:00
Wechat-ggGitHub
388c976f2d
feat: 微信端透出 Skill 调用信息,格式为"正在调用 xxx"
...
追踪 NDJSON 流中 Skill 工具的 input_json_delta,解析出 skill 名称后
通过 onText 转发到微信,让用户看到中间的 Skill 调用过程。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 11:12:25 +08:00
Wechat-ggGitHub
664d4c6c55
fix: 微信端流式输出改为定时 flush,不再等到查询结束
...
之前 onText 只积累不发送,flushText 在 claudeQuery 完成后才调用,
导致微信端看不到任何中间输出。现在每 3 秒自动 flush 已积累的文字,
用户在 Claude 处理过程中就能逐步看到回复。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 11:00:33 +08:00
Wechat-ggGitHub
570db576b8
feat: 从 SDK 迁移到 CLI spawn 模式,支持 Skills
...
使用 spawn('claude') 替代 @anthropic-ai/claude-agent-sdk 的 query(),
使微信端能正常使用 Claude Code Skills(Skills 是 CLI 前端功能,
SDK 模式下不会加载)。
- 用 --append-system-prompt 保留默认系统提示词(含 Skills 注入)
- 用 --output-format stream-json 解析 NDJSON 流式输出
- 图片通过临时文件 + file:// 路径传递给 CLI
- 移除 @anthropic-ai/claude-agent-sdk 依赖
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 01:03:21 +08:00
Wechat-ggGitHub
d157a251f6
docs: 更新 README 反映最新功能
...
- 文件支持:从"通知"改为实际下载处理
- 限频:从被动重试改为主动限速
- 移除已废弃的"思考预览"描述
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 00:42:21 +08:00
Wechat-ggGitHub
0907f0c23b
feat: 支持文件消息下载和处理
...
- 新增 downloadFile 函数:下载解密文件并保存到临时目录
- main.ts 提取 FILE 类型消息,下载后告诉 Claude 读取文件路径
- 更新 FileItem 类型支持 media 格式
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 00:40:48 +08:00
Wechat-ggGitHub
a785628697
feat: 用 sendTyping API 实现正确的"正在输入"指示器
...
参考官方 openclaw-weixin 插件实现:
- 通过 ilink/bot/getconfig 获取 typing_ticket(24h 缓存)
- 通过 ilink/bot/sendtyping 发送打字状态(每 5s keepalive)
- 替换掉之前错误的 sendMessage + message_state:1 方式
- 添加 .claude/ 到 .gitignore
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 00:31:54 +08:00
Wechat-ggGitHub
db458961da
fix: 解决 sendMessage 频繁被限流的问题
...
- 添加 per-user 预约制限速器,自动间隔 2.5s 发送
- sendGenerating 改为 fire-and-forget,不再阻塞 Claude 查询
- 缩短重试退避:3s→6s→12s(原 10s→20s→40s)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 00:18:13 +08:00
Wechat-ggGitHub
eb19d9af17
feat: 静默工具调用 + 添加微信输入指示器
...
- 移除工具调用摘要推送到微信的逻辑(onThinking、toolBuffer、flushToolStatus)
- 微信端只展示 Claude 的文字输出,工具调用在后台静默执行
- 收到用户消息后发送 GENERATING 状态,触发微信"正在输入..."指示
- 更新 README 中英文版本的功能描述
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-09 00:06:12 +08:00
Wechat-ggGitHub
703241a871
fix: code review 全量修复 — 安全、性能、ESM 兼容、代码质量
...
- fix(provider): require() 在 ESM 中不可用,改用顶层 import realpathSync
- fix(provider): 移除 shell 字符串拼接命令注入风险,改用 fs.realpathSync
- fix(logger): redact 正则匹配 camelCase 字段名(如 botToken)
- fix(config): 从 .env 改为 JSON 格式,支持多行 systemPrompt
- fix(api): 移除 (res as any) 不必要的类型断言
- fix(accounts): validateAccountId 提取到 store.ts 共享,消除重复
- fix(types): VoiceItem 字段名修正(text/media),匹配实际 API
- fix(media): extractText 使用正确的 voice_item.text 字段
- fix(api): 移除 generateUin 中无用的 uint32 变量
- refactor: 默认工作目录抽至 constants.ts,消除 3 处重复
- refactor: CDN_BASE_URL 移至 constants.ts,解耦 cdn→accounts 反向依赖
- refactor: Agent loop 显示优化 — 分离工具/文本缓冲,▸ 前缀替代 emoji
- refactor: 移除 provider 中 onText 死代码分支和未使用的 dirname import
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-08 01:44:28 +08:00
Wechat-ggGitHub
a8f9aa2d6e
docs: 移除思考预览相关描述
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-08 00:53:04 +08:00
Wechat-ggGitHub
16e3d34ad0
fix: 移除思考预览(thinking preview),不再推送到微信
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-08 00:52:27 +08:00