im-hub-pro 0.2.33 → 0.2.36

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.
Files changed (165) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +117 -374
  3. package/README.zh-CN.md +118 -374
  4. package/dist/cli.js +29 -20
  5. package/dist/cli.js.map +1 -1
  6. package/dist/core/acp-server.js +6 -6
  7. package/dist/core/acp-server.js.map +1 -1
  8. package/dist/core/agent-base.d.ts.map +1 -1
  9. package/dist/core/agent-base.js +12 -13
  10. package/dist/core/agent-base.js.map +1 -1
  11. package/dist/core/agent-cwd.js +3 -3
  12. package/dist/core/agent-cwd.js.map +1 -1
  13. package/dist/core/agent-cwd.test.js +4 -4
  14. package/dist/core/agent-cwd.test.js.map +1 -1
  15. package/dist/core/approval-bus.d.ts.map +1 -1
  16. package/dist/core/approval-bus.js +12 -10
  17. package/dist/core/approval-bus.js.map +1 -1
  18. package/dist/core/approval-bus.test.js +10 -8
  19. package/dist/core/approval-bus.test.js.map +1 -1
  20. package/dist/core/approval-router.d.ts.map +1 -1
  21. package/dist/core/approval-router.js +1 -1
  22. package/dist/core/approval-router.js.map +1 -1
  23. package/dist/core/approval-router.test.js +16 -16
  24. package/dist/core/approval-router.test.js.map +1 -1
  25. package/dist/core/audit-log.js +2 -2
  26. package/dist/core/audit-log.js.map +1 -1
  27. package/dist/core/bgjob-reader.js +6 -6
  28. package/dist/core/bgjob-reader.js.map +1 -1
  29. package/dist/core/bgjob-reader.test.js +12 -12
  30. package/dist/core/bgjob-reader.test.js.map +1 -1
  31. package/dist/core/commands/approval.test.js +7 -7
  32. package/dist/core/commands/approval.test.js.map +1 -1
  33. package/dist/core/commands/audit.js +1 -1
  34. package/dist/core/commands/audit.js.map +1 -1
  35. package/dist/core/commands/builtin.d.ts.map +1 -1
  36. package/dist/core/commands/builtin.js +4 -2
  37. package/dist/core/commands/builtin.js.map +1 -1
  38. package/dist/core/commands/job.js +8 -8
  39. package/dist/core/commands/job.js.map +1 -1
  40. package/dist/core/commands/model.js +7 -7
  41. package/dist/core/commands/model.js.map +1 -1
  42. package/dist/core/commands/plan.js +2 -2
  43. package/dist/core/commands/plan.js.map +1 -1
  44. package/dist/core/commands/plan.test.js +3 -3
  45. package/dist/core/commands/plan.test.js.map +1 -1
  46. package/dist/core/commands/sessions.js +4 -4
  47. package/dist/core/commands/sessions.js.map +1 -1
  48. package/dist/core/commands/stats.js +2 -2
  49. package/dist/core/commands/stats.js.map +1 -1
  50. package/dist/core/event-bus.d.ts +1 -1
  51. package/dist/core/event-bus.d.ts.map +1 -1
  52. package/dist/core/event-bus.js +1 -1
  53. package/dist/core/event-bus.js.map +1 -1
  54. package/dist/core/intent-llm.js +1 -1
  55. package/dist/core/intent-llm.js.map +1 -1
  56. package/dist/core/job-board.d.ts +1 -3
  57. package/dist/core/job-board.d.ts.map +1 -1
  58. package/dist/core/job-board.js +2 -2
  59. package/dist/core/job-board.js.map +1 -1
  60. package/dist/core/logger.js +1 -1
  61. package/dist/core/logger.js.map +1 -1
  62. package/dist/core/metrics.js +1 -1
  63. package/dist/core/metrics.js.map +1 -1
  64. package/dist/core/onboarding.d.ts.map +1 -1
  65. package/dist/core/onboarding.js +4 -5
  66. package/dist/core/onboarding.js.map +1 -1
  67. package/dist/core/onboarding.test.js +1 -1
  68. package/dist/core/onboarding.test.js.map +1 -1
  69. package/dist/core/router.js +1 -1
  70. package/dist/core/router.js.map +1 -1
  71. package/dist/core/schedule.js +3 -3
  72. package/dist/core/schedule.js.map +1 -1
  73. package/dist/core/session-subtasks.test.js +6 -6
  74. package/dist/core/session-subtasks.test.js.map +1 -1
  75. package/dist/core/session.js +5 -5
  76. package/dist/core/session.js.map +1 -1
  77. package/dist/core/sqlite-helper.js +2 -2
  78. package/dist/core/sqlite-helper.js.map +1 -1
  79. package/dist/core/transcribe.js +5 -5
  80. package/dist/core/transcribe.js.map +1 -1
  81. package/dist/core/transcribe.test.js +3 -3
  82. package/dist/core/transcribe.test.js.map +1 -1
  83. package/dist/plugins/agents/acp/acp-client.d.ts.map +1 -1
  84. package/dist/plugins/agents/acp/acp-client.js +4 -2
  85. package/dist/plugins/agents/acp/acp-client.js.map +1 -1
  86. package/dist/plugins/agents/claude-code/adapter.test.js +10 -10
  87. package/dist/plugins/agents/claude-code/adapter.test.js.map +1 -1
  88. package/dist/plugins/agents/claude-code/index.js +5 -5
  89. package/dist/plugins/agents/claude-code/index.js.map +1 -1
  90. package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts.map +1 -1
  91. package/dist/plugins/agents/claude-code/mcp-approval-server.js +11 -9
  92. package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -1
  93. package/dist/plugins/agents/claude-code/mcp-approval-server.test.js +3 -3
  94. package/dist/plugins/agents/claude-code/mcp-approval-server.test.js.map +1 -1
  95. package/dist/plugins/agents/codex/adapter.test.js +1 -1
  96. package/dist/plugins/agents/codex/adapter.test.js.map +1 -1
  97. package/dist/plugins/agents/codex/index.js +3 -3
  98. package/dist/plugins/agents/codex/index.js.map +1 -1
  99. package/dist/plugins/agents/copilot/index.js +3 -3
  100. package/dist/plugins/agents/copilot/index.js.map +1 -1
  101. package/dist/plugins/agents/opencode/http-adapter.test.js +4 -4
  102. package/dist/plugins/agents/opencode/http-adapter.test.js.map +1 -1
  103. package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts +1 -1
  104. package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -1
  105. package/dist/plugins/agents/opencode/opencode-http-adapter.js +6 -4
  106. package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -1
  107. package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -1
  108. package/dist/plugins/agents/opencode/serve-manager.js +10 -6
  109. package/dist/plugins/agents/opencode/serve-manager.js.map +1 -1
  110. package/dist/plugins/messengers/discord/discord-adapter.d.ts +0 -1
  111. package/dist/plugins/messengers/discord/discord-adapter.d.ts.map +1 -1
  112. package/dist/plugins/messengers/discord/discord-adapter.js +3 -6
  113. package/dist/plugins/messengers/discord/discord-adapter.js.map +1 -1
  114. package/dist/plugins/messengers/discord/discord-adapter.test.js +9 -9
  115. package/dist/plugins/messengers/discord/discord-adapter.test.js.map +1 -1
  116. package/dist/plugins/messengers/feishu/feishu-adapter.d.ts +0 -1
  117. package/dist/plugins/messengers/feishu/feishu-adapter.d.ts.map +1 -1
  118. package/dist/plugins/messengers/feishu/feishu-adapter.js +4 -7
  119. package/dist/plugins/messengers/feishu/feishu-adapter.js.map +1 -1
  120. package/dist/plugins/messengers/feishu/feishu-client.d.ts +0 -1
  121. package/dist/plugins/messengers/feishu/feishu-client.d.ts.map +1 -1
  122. package/dist/plugins/messengers/feishu/feishu-client.js +0 -2
  123. package/dist/plugins/messengers/feishu/feishu-client.js.map +1 -1
  124. package/dist/plugins/messengers/telegram/markdown-to-html.js +3 -3
  125. package/dist/plugins/messengers/telegram/markdown-to-html.js.map +1 -1
  126. package/dist/plugins/messengers/telegram/media-download.js +5 -5
  127. package/dist/plugins/messengers/telegram/media-download.js.map +1 -1
  128. package/dist/plugins/messengers/telegram/media-download.test.js +3 -3
  129. package/dist/plugins/messengers/telegram/media-download.test.js.map +1 -1
  130. package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +15 -0
  131. package/dist/plugins/messengers/telegram/telegram-adapter.d.ts.map +1 -1
  132. package/dist/plugins/messengers/telegram/telegram-adapter.js +165 -8
  133. package/dist/plugins/messengers/telegram/telegram-adapter.js.map +1 -1
  134. package/dist/plugins/messengers/wechat/ilink-adapter.d.ts +10 -0
  135. package/dist/plugins/messengers/wechat/ilink-adapter.d.ts.map +1 -1
  136. package/dist/plugins/messengers/wechat/ilink-adapter.js +167 -17
  137. package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -1
  138. package/dist/plugins/messengers/wechat/ilink-client.d.ts +10 -1
  139. package/dist/plugins/messengers/wechat/ilink-client.d.ts.map +1 -1
  140. package/dist/plugins/messengers/wechat/ilink-client.js +42 -0
  141. package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -1
  142. package/dist/plugins/messengers/wechat/ilink-types.d.ts +8 -0
  143. package/dist/plugins/messengers/wechat/ilink-types.d.ts.map +1 -1
  144. package/dist/plugins/messengers/wechat/ilink-types.js +10 -0
  145. package/dist/plugins/messengers/wechat/ilink-types.js.map +1 -1
  146. package/dist/plugins/messengers/wechat/media-download.d.ts +32 -0
  147. package/dist/plugins/messengers/wechat/media-download.d.ts.map +1 -0
  148. package/dist/plugins/messengers/wechat/media-download.js +78 -0
  149. package/dist/plugins/messengers/wechat/media-download.js.map +1 -0
  150. package/dist/utils/backoff.js +1 -1
  151. package/dist/utils/backoff.js.map +1 -1
  152. package/dist/utils/cross-platform.d.ts +1 -1
  153. package/dist/utils/cross-platform.d.ts.map +1 -1
  154. package/dist/utils/cross-platform.js +3 -3
  155. package/dist/utils/cross-platform.js.map +1 -1
  156. package/dist/utils/safe-equal.js +1 -1
  157. package/dist/utils/safe-equal.js.map +1 -1
  158. package/dist/web/public/_app.js +2 -2
  159. package/dist/web/public/index.html +13 -13
  160. package/dist/web/public/login.html +11 -3
  161. package/dist/web/public/settings.html +20 -20
  162. package/dist/web/public/tasks.html +76 -76
  163. package/dist/web/server.js +12 -12
  164. package/dist/web/server.js.map +1 -1
  165. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.2.35] - 2026-05-09
6
+
7
+ ### Added — WeChat & Telegram rich media support
8
+
9
+ - **WeChat 图片 / 文件 / 语音 / 视频接收**:`handleIncomingMessage` 现在处理 iLink `item_list` 的全部 5 种类型(TEXT=1, IMAGE=2, VOICE=3, FILE=4, VIDEO=5),此前只处理 TEXT。
10
+ - **图片**:通过 iLink CDN 下载到 `~/.im-hub/media/wechat/<userId>/`,转为 `[图片附件:/path]` 标记传递给 Agent
11
+ - **语音**:优先使用微信自带转写(`voice_item.text`),无转写时下载音频后走 OpenAI Whisper 或 whisper.cpp(复用 `src/core/transcribe.ts`)
12
+ - **文件**:下载并保留原始文件名,显示大小,转为 `[文件附件:/path (name, size)]`
13
+ - **视频**:下载并显示时长和大小,转为 `[视频附件:/path (duration, size)]`
14
+ - **混合消息**:同一条消息中的文本 + 媒体项按顺序拼接
15
+ - **Telegram 图片 / 语音增强**:Telegram 适配器的图片下载和语音转写能力在本轮中同步维护和 bugfix。
16
+ - **新文件**:`src/plugins/messengers/wechat/media-download.ts` — 媒体下载辅助,含路径安全检查(拒绝 `../` / `/`)和 20 MB 大小上限
17
+ - **新类型**:`ilink-types.ts` 新增 `ITEM_TYPE` 常量和 `DownloadMediaRequest`
18
+ - **新方法**:`ILinkClient.downloadMedia(cdnMedia)` — 通过 iLink CDN 端点下载二进制媒体
19
+
20
+ ### Tests
21
+
22
+ - 53 个新测试:
23
+ - 31 集成测试(`test/integration/wechat-media-integration.test.ts`)— 端到端验证 `handleIncomingMessage` 对所有媒体类型的处理,含成功 / 失败 / 边界情况
24
+ - 15 单元测试(`test/unit/wechat-media-download.test.ts`)— 下载辅助函数、扩展名推断、CDN 提取、安全防护
25
+ - 8 单元测试(`test/unit/wechat-media-handling.test.ts`)— 类型常量和消息结构验证
26
+ - 全量 950 pass / 0 fail
27
+
28
+ ---
29
+
5
30
  ## [0.2.33] - 2026-05-09
6
31
 
7
32
  ### Fixed — audit-fixes-7950 follow-up
package/README.md CHANGED
@@ -2,131 +2,69 @@
2
2
 
3
3
  [中文文档](README.zh-CN.md)
4
4
 
5
- **Universal messenger-to-agent bridge** — connect WeChat / Feishu / Telegram / **Discord** to Claude Code / Codex / Copilot / OpenCode, **or any custom agent via ACP**. Single Node.js process, no Docker, no Redis. Browser dashboard, persistent jobs, multi-tenant workspaces, and real human-in-the-loop tool approval over IM.
6
-
7
- > Productized fork of the original [`im-hub`](https://www.npmjs.com/package/im-hub). On-disk config (`~/.im-hub/`), env vars (`IMHUB_*`), and HTTP headers (`X-IM-Hub-Token`) are unchanged — drop-in compatible. See [Migrating from `im-hub`](#migrating-from-im-hub) below.
8
-
9
- ## What's new in v0.2.13 → v0.2.30
10
-
11
- - **Discord adapter** (Gateway WebSocket via `discord.js`)
12
- - **Human-in-the-loop tool approval** — Claude pauses on tool calls; you reply `y`/`n` in the same IM thread, **or click an in-page card from the web chat**
13
- - **Tasks dashboard** at `/tasks` with **Jobs · Background · Subtasks · Schedules · Approvals · Health · Files · Audit** tabs (per-agent filtering, multi-select batch ops, real-time SSE updates)
14
- - **Multi-tenant workspaces** — per-workspace agent whitelist + rate limits, **with full CRUD UI in /settings**, plus command-level ACL on `/job` `/schedule` `/audit` (each user only sees their own)
15
- - **ACP server mode** — im-hub-pro itself is an ACP-compatible agent (`POST /tasks` sync + SSE)
16
- - **Persistent Job Board** + cron scheduler (SQLite, survives restarts) with 30-day retention sweep
17
- - **Smart routing**: intent classifier (CJK + ASCII), circuit breaker, sticky sessions
18
- - **Structured logging** (`pino`) with `traceId` end-to-end + audit log + Prometheus `/api/metrics`
19
- - **Three-state theme** (light / dark / system) on every page — applied before first paint to avoid flash
20
- - **v0.2.16 — Security hardening (P0 + P1)**: timing-safe token compare, Schedule `notify_url` SSRF guard, secret redaction in logs, approval-socket entropy + perms, `Session.addMessage` per-key mutex
21
- - **v0.2.17 — Observability & IM polish (P2 + P3)**: static-page CSP / `X-Frame-Options` / `X-Content-Type-Options`, WebSocket connection cap + backpressure, Prometheus label-cardinality whitelist, new counters (`im_hub_audit_prune_failed_total` / `im_hub_agent_cleanup_failed_total` / `im_hub_approval_*`), UTF-16 surrogate-safe message split, auto-allow fingerprint 5→10 chars, SQLite WAL clean checkpoint on SIGINT
22
- - **v0.2.18 — IM reconnect backoff (M9)**: shared `Backoff` helper (exponential + ±50% jitter) replaces fixed 2s / 5s reconnect delays in Telegram + WeChat polling; defeats thundering-herd on shared network recovery
23
- - **v0.2.19 — Codex sandbox-mode plan + Dashboard filter / Audit tab**: codex now honors `session.planMode` (default sandbox switched to explicit `-s workspace-write`); jobs / subtasks / schedules tabs gain per-agent filter; new Audit tab pulls the SQLite audit log into the dashboard
24
- - **v0.2.20 — Web console PR-A**: three-state theme manager + global error boundary + in-page approval cards (click Allow / Deny / Allow + Auto from the chat UI itself)
25
- - **v0.2.21 — Web console PR-B**: Health tab (per-agent breaker / rate-limiter / latency p50/95/99 / sparkline) + Approvals tab (browse and resolve every pending HITL approval from the dashboard)
26
- - **v0.2.22 — Web console PR-C**: SSE event stream (`/events`) replaces polling for audit / approval / job / metrics events; full Workspace CRUD UI in /settings
27
- - **v0.2.23 — Web console PR-D**: Files tab — read-only browser of `~/.im-hub-workspaces/<agent>/`; Jobs tab gains multi-select + batch cancel / run; settings page header / container restyled
28
- - **v0.2.30 — Production hardening**: active subtask turns now use isolated sub-sessions and native agent sessions; WebSocket chat ingress is serialized per browser connection; session metadata writes use per-key locking; Web UI defaults to loopback binding; config files are written `0600`; Telegram media downloads reject redirects; `im-hub-pro --version` reads the package version
29
-
30
- See [CHANGELOG.md](CHANGELOG.md) and [docs/code-review-2026-05-06-main.md](docs/code-review-2026-05-06-main.md) for the full list.
31
-
32
- ## Web Chat & Tasks Dashboard
5
+ **Universal messenger-to-agent bridge** — connect WeChat / Feishu / Telegram / Discord to Claude Code / Codex / Copilot / OpenCode, or any custom agent via ACP. Single Node.js process, no Docker, no Redis.
33
6
 
34
- ```
35
- im-hub-pro start # Web UI at http://localhost:3000
36
- # / chat (with in-page approval cards)
37
- # /tasks jobs · background · subtasks · schedules
38
- # · approvals · health · files · audit
39
- # /settings agents · messengers · ACP · workspaces
40
- ```
7
+ > Productized fork of the original [`im-hub`](https://www.npmjs.com/package/im-hub). Config dir (`~/.im-hub/`), env vars (`IMHUB_*`), and headers (`X-IM-Hub-Token`) are unchanged — drop-in upgrade. See [Migrating from `im-hub`](#migrating-from-im-hub).
41
8
 
42
- - Real-time streaming via WebSocket; **dashboard pushed via SSE `/events`** (audit / approval / job / metrics)
43
- - Agent switching and chat history
44
- - **Three-state theme** (light / dark / system) with per-tab persistence + global error boundary
45
- - Bilingual UI (English / 中文) — auto-detects browser language
46
- - `/tasks` surfaces persistent jobs, cron schedules, **`~/.claude/bgjobs`** + **`~/.config/opencode/bgjobs`** + **`~/.codex/bgjobs`** background tasks (override via `IMHUB_BGJOB_ROOTS`), every subtask in every session, agent health (breaker · rate-limiter · p50/95/99 · sparkline), pending HITL approvals (resolve from the browser), and a read-only file browser into `~/.im-hub-workspaces/<agent>/`
47
-
48
- ## Features
9
+ ## Highlights
49
10
 
50
- - **Universal multiplexer** — one instance, multiple messengers, multiple agents
51
- - **Custom agent support** — connect any agent via [ACP](https://agentcommunicationprotocol.dev) with `im-hub-pro config agent`, or auto-discover via `/.well-known/acp`
52
- - **Built-in IMs** — WeChat (iLink), Feishu (WebSocket long-poll), Telegram (grammy), **Discord** (discord.js)
53
- - **Built-in CLI agents** — Claude Code, Codex, Copilot, OpenCode (all via shared `AgentBase` adapter)
54
- - **Plugin architecture** — easy to add new messengers / agents
55
- - **TypeScript native** — no Go, no Docker, no Redis
56
- - **JSONL streaming** — real-time agent responses with multi-byte UTF-8 safety
11
+ - **4 messengers, 4+ agents** — WeChat (image / file / voice), Feishu, Telegram, Discord; Claude Code, Codex, Copilot, OpenCode, plus any ACP endpoint
12
+ - **Browser dashboard** — chat UI, tasks panel (jobs / schedules / approvals / health / files / audit), settings page with workspace CRUD
13
+ - **Human-in-the-loop tool approval** — Claude tool calls pause for `y`/`n` in IM or in-page card; works across all platforms
14
+ - **Rich media in WeChat & Telegram** — receive images, files, videos; voice messages transcribed via WeChat STT, OpenAI Whisper, or whisper.cpp
15
+ - **Smart routing** — intent classifier (CJK + ASCII), sticky sessions, circuit breaker, rate limiter
16
+ - **Multi-tenant workspaces** — per-workspace agent whitelist, rate limits, command-level ACL
17
+ - **Persistent jobs & cron** — SQLite-backed, survives restarts, 30-day retention
18
+ - **Observability** — structured logging (pino + traceId), Prometheus metrics, audit log
19
+ - **Security** — timing-safe auth, SSRF guards, credential file permissions, approval socket entropy
57
20
 
58
- ## Installation
59
-
60
- ```bash
61
- npm install -g im-hub-pro
62
- ```
63
-
64
- Requires **Node.js ≥ 18** (production deployments use ≥ 22 LTS — see [`docs/deployment.md`](docs/deployment.md)).
65
-
66
- ### Migrating from `im-hub`
67
-
68
- Your `~/.im-hub/` config dir, `IMHUB_*` env vars, `X-IM-Hub-Token` header, and ACP wire identifiers (`im-hub-gateway`) are unchanged — this is a brand rename only.
69
-
70
- ```bash
71
- npm uninstall -g im-hub
72
- npm install -g im-hub-pro
73
- im-hub-pro start
74
- ```
21
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
75
22
 
76
23
  ## Quick Start
77
24
 
78
25
  ```bash
79
- # 1. Configure at least one messenger
26
+ npm install -g im-hub-pro # Requires Node.js 18 (≥ 22 LTS recommended)
27
+
28
+ # Configure at least one messenger
80
29
  im-hub-pro config wechat # QR-code login
81
30
  im-hub-pro config feishu # App ID + Secret (no webhook needed)
82
31
  im-hub-pro config telegram # @BotFather token
83
32
  im-hub-pro config discord # Bot token; see docs/discord-setup.md
84
33
 
85
- # 2. (Optional) Configure a CLI agent most are auto-detected
86
- im-hub-pro config claude
87
-
88
- # 3. (Optional) Connect a custom remote agent over ACP
34
+ # (Optional) Connect a custom remote agent over ACP
89
35
  im-hub-pro config agent
90
36
 
91
- # 4. Start the bridge
37
+ # Start the bridge
92
38
  im-hub-pro start
93
39
  ```
94
40
 
95
- ### Feishu (WebSocket Long Polling)
96
-
97
- - ✅ No webhook configuration needed
98
- - ✅ No public IP or domain required
99
- - ✅ No ngrok or similar tools needed
100
- - ✅ Works directly from localhost
101
-
102
- ### Discord
41
+ Web UI at `http://localhost:3000` — chat at `/`, tasks at `/tasks`, settings at `/settings`.
103
42
 
104
- See [`docs/discord-setup.md`](docs/discord-setup.md) for the full bot-token / intents / OAuth flow.
105
-
106
- ### Connect Your Own Agent
107
-
108
- im-hub-pro speaks **ACP (Agent Communication Protocol)**, so you can plug in any agent that exposes a standard HTTP endpoint — your own business bots, internal tools, cloud services, anything.
43
+ ### Migrating from `im-hub`
109
44
 
110
45
  ```bash
111
- im-hub-pro config agent
112
- # Interactive setup: name, endpoint URL, auth (none / Bearer / API key)
113
- # Connection is validated automatically; /.well-known/acp is auto-discovered
114
- ```
115
-
116
- After setup, chat with it the same way as built-in agents:
117
-
118
- ```
119
- /myagent analyze the Q1 sales report
46
+ npm uninstall -g im-hub
47
+ npm install -g im-hub-pro
48
+ im-hub-pro start # config, env vars, headers all unchanged
120
49
  ```
121
50
 
122
- ### Use im-hub-pro *as* an agent
51
+ ## Features
123
52
 
124
- im-hub-pro also exposes an ACP server — point any ACP-compliant client at `POST http://localhost:3000/tasks` (sync) or with `?mode=stream` (SSE). Auth is the same `Authorization: Bearer <web-token>`.
53
+ | Category | Details |
54
+ |----------|---------|
55
+ | **Messengers** | WeChat (iLink — image / file / voice / video), Feishu (WebSocket), Telegram (grammy — photo / voice / audio), Discord (discord.js) |
56
+ | **Agents** | Claude Code, Codex, Copilot, OpenCode — all via shared `AgentBase`; any HTTP agent via ACP |
57
+ | **Web UI** | Chat with streaming, three-state theme (light / dark / system), bilingual (EN / 中文), SSE dashboard |
58
+ | **Tool Approval** | Human-in-the-loop over IM + in-page cards; MCP sidecar for Claude |
59
+ | **Jobs** | Persistent SQLite job board + cron scheduler; batch ops; background task reader |
60
+ | **Routing** | Intent classifier, circuit breaker, rate limiter, sticky sessions, LLM judge fallback |
61
+ | **Workspaces** | Multi-tenant; agent whitelist + rate limits; command-level ACL |
62
+ | **Observability** | pino structured logs, traceId, Prometheus `/api/metrics`, SQLite audit log |
63
+ | **ACP** | Client (connect to remote agents) + Server (im-hub-pro itself as an ACP agent) |
125
64
 
126
65
  ## CLI Commands
127
66
 
128
67
  ```
129
- im-hub-pro # Same as 'start'
130
68
  im-hub-pro start # Start the bridge + web UI
131
69
  im-hub-pro config wechat # Configure WeChat
132
70
  im-hub-pro config feishu # Configure Feishu
@@ -136,190 +74,92 @@ im-hub-pro config claude # Configure Claude Code
136
74
  im-hub-pro config agent # Connect a custom ACP agent
137
75
  im-hub-pro agents # List available agents
138
76
  im-hub-pro messengers # List available messengers
139
- im-hub-pro help
140
77
  ```
141
78
 
142
79
  ## Chat Commands
143
80
 
144
- Send these as messages to the bot. Responses are streamed back in the same thread.
145
-
146
81
  | Command | What it does |
147
- |---|---|
148
- | (any text) | Route to the agent (sticky session, intent-classified) |
149
- | `/<agent> <prompt>` | Switch agent and send (e.g. `/cc explain this`, `/oc`, `/cx`, `/co`) |
150
- | `/help` | Show available commands |
151
- | `/agents` | List available agents |
152
- | `/status` | Show connection status |
153
- | `/new` | Start a new conversation (clear context) |
154
- | `/router status\|policy\|explain\|reset` | Inspect routing decisions, predict where a message would go |
155
- | `/audit [n]` | Recent invocations from the audit log |
156
- | `/job ...` | Inspect / cancel persistent jobs |
157
- | `/schedule ...` | List / add / remove cron schedules |
158
- | `/sessions` | List recent sessions for this thread |
159
- | `/model [provider/model]` | View or change the session's model |
160
- | `/models` | List models the current agent supports |
161
- | `/think on\|off\|...` | Toggle "think harder" / extended-thinking modes |
162
- | `/stats` | Per-agent invocation / latency / error stats |
163
- | `y` / `n` / `批准` / `拒绝` | Approve or deny a pending Claude tool call (HITL) |
82
+ |---------|-------------|
83
+ | any text | Route to agent (sticky session, intent-classified) |
84
+ | `/<agent> <prompt>` | Switch agent `/cc`, `/oc`, `/cx`, `/co` |
85
+ | `/new` | New conversation (clear context) |
86
+ | `/model [provider/model]` | View or switch model |
87
+ | `/think on\|off` | Toggle extended thinking |
88
+ | `/job`, `/schedule`, `/audit`, `/stats` | Manage jobs, schedules, audit, stats |
89
+ | `/router status\|explain` | Inspect routing decisions |
90
+ | `y` / `n` / `批准` / `拒绝` | Approve / deny Claude tool call |
164
91
 
165
92
  ## Human-in-the-loop Tool Approval
166
93
 
167
- When a Claude run launched from IM tries to use a tool, im-hub-pro pauses it and posts an approval card to the same IM thread:
94
+ When a Claude run tries to use a tool, im-hub-pro pauses and sends an approval card:
168
95
 
169
96
  ```
170
97
  🔐 Tool approval request
171
98
  Tool: Bash
172
99
  Input: {"command":"rm -rf node_modules"}
173
100
  Reply y to approve / n to deny (auto-deny in 5 min)
174
- req: a3f1c0d2
175
101
  ```
176
102
 
177
- Reply `y`, `n`, `批准`, `拒绝`, etc. the decision flows back through an MCP sidecar to Claude, which resumes (or aborts) accordingly. The same chain works for WeChat, Telegram, Feishu, and Discord with no per-platform changes. Disable with `IMHUB_APPROVAL_DISABLED=1`.
103
+ Reply `y` / `n` in IM, or click Allow / Deny in the web UI. Works identically across WeChat, Telegram, Feishu, and Discord. Disable with `IMHUB_APPROVAL_DISABLED=1`.
178
104
 
179
105
  ## Architecture
180
106
 
181
107
  ```
182
- ┌─── External triggers ───┐
183
- cron 30s tick
184
- webhook /api/notify
185
- REST → /api/invoke
186
- ACP → /tasks (sync/SSE)│
187
- └────────────┬─────────────┘
188
- ┌─ IM ingress ──────────────────────┼───────────────────┐
189
- WeChat iLink (long-poll + heartbeat) │
190
- │ Telegram (grammy) │
191
- Feishu (Lark SDK WebSocket) │
192
- Discord (discord.js Gateway)
193
- │ Web Chat (browser WebSocket) │
194
- └────────────────────────────────┬──────────────────────┘
195
- MessageContext
196
-
197
- ┌── Pre-route gates ────────────────┐
198
- workspace.resolve(userId)
199
- rateLimiter.allow(userKey)
200
- │ traceId + pino child logger │
201
- └────────────────┬───────────────────┘
202
-
203
- ┌── parseMessage + Intent ──────────┐
204
- │ /<cmd> → builtin sub-command │
205
- │ /<agent> → explicit switch
206
- default → classifyIntent │
207
- ├ topic regex (CJK + ASCII) │
208
- │ ├ keyword profile │
209
- │ ├ sticky session bias │
210
- │ └ LLM judge (opt-in fallback) │
211
- └────────────────┬───────────────────┘
212
-
213
- ┌── Agent invocation ───────────────┐
214
- workspace whitelist + circuit
215
- │ breaker + isAvailable cache │
216
- │ AgentBase.sendPrompt → spawnStream │
217
- │ (LineBuffer · true streaming · │
218
- │ abort/timeout · UTF-8 safe) │
219
- └────────────────┬───────────────────┘
220
- ┌──────┬───────┼────────┬─────────┐
221
- ▼ ▼ ▼ ▼ ▼
222
- opencode claude codex copilot ACP remote
223
-
224
- ▼ (if a tool needs approval)
225
- MCP sidecar ─ unix socket ─ approvalBus
226
- └─ approvalRouter → IM thread
227
-
228
- ┌─ Cross-cutting ───────────────────────────────────────┐
229
- │ audit-log (SQLite, 30-day retention) │
230
- │ job-board (SQLite, persistent + AbortController) │
231
- │ scheduler (30s tick → cron → enqueue jobs) │
232
- │ workspaces (per-tenant agent whitelist + limits) │
233
- │ metrics (Prometheus text via /api/metrics) │
234
- │ session (~/.im-hub/sessions/, append-only JSONL) │
235
- │ pino (traceId end-to-end, JSON in production) │
236
- └───────────────────────────────────────────────────────┘
237
- ```
238
-
239
- Single-process, single-instance: SQLite (`audit.db` / `jobs.db` / `schedules.db`) plus a session file tree is the entire persistence layer. No Redis, no MQ.
108
+ ┌─ IM ingress ─────────────────────────────────────┐
109
+ WeChat iLink (long-poll + image/voice/file)
110
+ Telegram (grammy + photo/voice/audio)
111
+ Feishu (Lark SDK WebSocket)
112
+ Discord (discord.js Gateway)
113
+ │ Web Chat (browser WebSocket) │
114
+ └───────────────────────┬──────────────────────────┘
115
+ MessageContext
116
+
117
+ ┌── Pre-route gates ────────────────┐
118
+ workspace · rate limiter · traceId
119
+ └────────────────┬──────────────────┘
120
+
121
+ ┌── Intent router ──────────────────┐
122
+ │ command → builtin │
123
+ /agent → explicit switch │
124
+ default → classify (regex/keyword/
125
+ sticky/LLM judge)
126
+ └────────────────┬──────────────────┘
127
+
128
+ ┌── Agent invocation ───────────────┐
129
+ circuit breaker + spawn stream │
130
+ └───┬──────┬──────┬──────┬──────┬───┘
131
+ ▼ ▼ ▼ ▼
132
+ claude opencode codex copilot ACP
133
+
134
+ (tool approval)
135
+ MCP sidecar approvalBus → IM thread
136
+
137
+ ┌─ Cross-cutting ──────────────────────────────────┐
138
+ │ SQLite (audit · jobs · schedules) │
139
+ session (append-only JSONL) │
140
+ Prometheus metrics · pino structured logging
141
+ └──────────────────────────────────────────────────┘
142
+ ```
143
+
144
+ Single process, zero external dependencies — SQLite + session files are the entire persistence layer.
240
145
 
241
146
  For the full deep-dive see [`docs/architecture/current.md`](docs/architecture/current.md).
242
147
 
243
- ## Project Structure
244
-
245
- ```
246
- im-hub-pro/
247
- ├── src/
248
- │ ├── core/
249
- │ │ ├── types.ts # Plugin interfaces
250
- │ │ ├── registry.ts # Plugin registration
251
- │ │ ├── router.ts # Message routing
252
- │ │ ├── session.ts # Session manager (append-only JSONL)
253
- │ │ ├── workspace.ts # Multi-tenant workspaces
254
- │ │ ├── intent.ts # Intent classifier
255
- │ │ ├── intent-llm.ts # LLM judge fallback (LRU cached)
256
- │ │ ├── circuit-breaker.ts # Per-agent breaker
257
- │ │ ├── rate-limiter.ts # Token-bucket
258
- │ │ ├── job-board.ts # Persistent jobs + cancel
259
- │ │ ├── schedule.ts # Cron tick → job enqueue
260
- │ │ ├── audit-log.ts # SQLite audit
261
- │ │ ├── metrics.ts # Prometheus quantiles
262
- │ │ ├── acp-server.ts # /tasks ACP server
263
- │ │ ├── approval-bus.ts # Tool-approval pub/sub
264
- │ │ ├── approval-router.ts # Approval ↔ IM bridge
265
- │ │ ├── bgjob-reader.ts # ~/.claude + ~/.config/opencode bgjobs
266
- │ │ ├── agent-base.ts # Shared spawn-stream for CLI agents
267
- │ │ ├── config-schema.ts # Zod schema
268
- │ │ ├── logger.ts # pino + traceId
269
- │ │ ├── sqlite-helper.ts # Shared prepare/PRAGMA cache
270
- │ │ └── commands/ # /audit /router /job /schedule /model …
271
- │ ├── plugins/
272
- │ │ ├── messengers/
273
- │ │ │ ├── wechat/ # iLink long-poll
274
- │ │ │ ├── feishu/ # Lark SDK WebSocket
275
- │ │ │ ├── telegram/ # grammy
276
- │ │ │ └── discord/ # discord.js
277
- │ │ └── agents/
278
- │ │ ├── claude-code/ # + MCP approval sidecar
279
- │ │ ├── codex/
280
- │ │ ├── copilot/
281
- │ │ ├── opencode/
282
- │ │ └── acp/ # ACP client + /.well-known discovery
283
- │ ├── index.ts
284
- │ ├── cli.ts
285
- │ └── web/
286
- │ ├── server.ts # HTTP + WS + REST + ACP server
287
- │ └── public/
288
- │ ├── index.html # Chat UI
289
- │ ├── tasks.html # Tasks dashboard
290
- │ └── settings.html # Settings UI
291
- ├── docs/
292
- │ ├── architecture/{current,target}.md
293
- │ ├── adr/{0001,0002,0003}-*.md
294
- │ ├── deployment.md
295
- │ ├── discord-setup.md
296
- │ └── upgrade-plan.md
297
- ├── package.json
298
- ├── tsconfig.json
299
- └── README.md
300
- ```
301
-
302
148
  ## Configuration
303
149
 
304
- Config file: `~/.im-hub/config.json`
150
+ Config file: `~/.im-hub/config.json` (validated by zod at startup)
305
151
 
306
152
  ```json
307
153
  {
308
- "messengers": ["wechat", "discord"],
154
+ "messengers": ["wechat", "telegram"],
309
155
  "agents": ["claude-code", "opencode"],
310
156
  "defaultAgent": "claude-code",
311
- "discord": {
312
- "botToken": "***",
313
- "allowedGuilds": [],
314
- "allowedChannels": []
315
- },
157
+ "telegram": { "botToken": "***" },
316
158
  "acpAgents": [
317
159
  {
318
160
  "name": "my-agent",
319
- "aliases": ["ma"],
320
161
  "endpoint": "https://api.example.com",
321
- "auth": { "type": "bearer", "token": "***" },
322
- "enabled": true
162
+ "auth": { "type": "bearer", "token": "***" }
323
163
  }
324
164
  ],
325
165
  "workspaces": [
@@ -334,12 +174,10 @@ Config file: `~/.im-hub/config.json`
334
174
  }
335
175
  ```
336
176
 
337
- The schema is enforced by `zod` at startup and on every PUT `/api/config` — bad configs reject loudly instead of silently breaking the bridge.
338
-
339
177
  ## Requirements
340
178
 
341
- - **Node.js 18+** (≥ 22 LTS recommended for production)
342
- - **At least one Agent CLI** (or an ACP remote endpoint):
179
+ - **Node.js 18** (≥ 22 LTS recommended)
180
+ - At least one agent CLI or ACP endpoint:
343
181
  - `npm i -g @anthropic-ai/claude-code`
344
182
  - `npm i -g @openai/codex`
345
183
  - `npm i -g @github/copilot`
@@ -348,135 +186,45 @@ The schema is enforced by `zod` at startup and on every PUT `/api/config` — ba
348
186
  ## Development
349
187
 
350
188
  ```bash
351
- git clone https://github.com/benking007/imhub.git
352
- cd imhub
189
+ git clone https://github.com/benking007/imhub.git && cd imhub
353
190
  npm install
354
191
  npm run build # tsc + copy public/
355
192
  npm run dev # tsc --watch
356
193
  npm test # bun test
357
- npm run typecheck # tsc --noEmit (src + tests)
358
- npm start
194
+ npm run lint # biome lint
195
+ npm run typecheck # tsc --noEmit
359
196
  ```
360
197
 
198
+ ## Deployment
199
+
200
+ See [`docs/deployment.md`](docs/deployment.md) for systemd, Docker, nginx, monitoring, and upgrade instructions.
201
+
361
202
  ## Roadmap
362
203
 
363
- ### v0.1.x (MVP)
364
- - [x] WeChat adapter with QR login
365
- - [x] Claude Code, Codex, Copilot, OpenCode agents
366
- - [x] Basic command routing
367
-
368
- ### v0.2.0 Multi-IM
369
- - [x] Feishu adapter
370
- - [x] Telegram adapter
371
- - [x] Session persistence with conversation history
372
- - [x] ACP custom agent support
373
-
374
- ### v0.2.x Web & UI
375
- - [x] Web Chat UI with streaming
376
- - [x] Settings page
377
- - [x] Bilingual UI (EN / 中文)
378
-
379
- ### v0.2.13 — Foundations
380
- - [x] Structured logging (pino) + traceId
381
- - [x] Zod config schema validation
382
- - [x] AgentBase abstraction + healthCheck cache
383
- - [x] Audit log (SQLite) + `/audit`
384
- - [x] Intent classifier + circuit breaker + rate limiter
385
- - [x] ACP server mode (`POST /tasks` sync + SSE)
386
- - [x] `/.well-known/acp` discovery
387
- - [x] Multi-tenant workspaces + agent whitelist
388
- - [x] Persistent Job Board + cron scheduler
389
- - [x] Web `/tasks` panel + REST jobs API
390
- - [x] Prometheus metrics
391
-
392
- ### v0.2.14 — Tool approval
393
- - [x] Human-in-the-loop tool approval over IM
394
- - [x] MCP approval sidecar (claude-code adapter)
395
-
396
- ### v0.2.15 — Discord & Dashboard
397
- - [x] Discord messenger adapter
398
- - [x] Tasks dashboard surfaces Claude / opencode bgjobs
399
- - [x] Flattened subtasks tab
400
-
401
- ### v0.2.16 — Security hardening (P0 + P1)
402
- - [x] Timing-safe REST + WS token compare (shared `safe-equal`)
403
- - [x] Schedule `notify_url` SSRF gate (http(s) only, RFC1918 / loopback / IPv6 ULA blocked) + 10s fetch timeout + redirect:'manual'
404
- - [x] HTML token injection: `JSON.stringify` instead of single-quote splice
405
- - [x] Telegram bot-token redaction in logs (pino `redact.paths` + adapter-level scrub)
406
- - [x] WeChat credential file `0o600` + parent dir `0o700`
407
- - [x] Approval socket path uses 128-bit random + post-listen `chmod 0o600` + stat verification
408
- - [x] Job result size cap (`IMHUB_JOB_RESULT_MAX_BYTES`, default 1 MiB) + UTF-8/JSON safe truncation
409
- - [x] Job-board retention + 6h sweep + `creator_id` / `workspace_id` schema migration
410
- - [x] Multi-tenant ACL on `/job` `/schedule` `/audit` commands (each user sees only their own rows; legacy ownerless rows stay visible for safe upgrades)
411
- - [x] Workspace whitelist enforced on direct command paths, not just routing
412
- - [x] Rate-limiter opportunistic auto-cleanup (no setInterval timer)
413
- - [x] `Session.addMessage` per-key mutex (defeats concurrent read-modify-write race)
414
-
415
- ### v0.2.17 — Observability & IM polish (P2 + P3)
416
- - [x] Static-page security headers (`X-Frame-Options` / `X-Content-Type-Options` / `Referrer-Policy` / CSP)
417
- - [x] `/api/health` declared public (k8s liveness friendly)
418
- - [x] WebSocket connection cap (`IMHUB_MAX_WS_CLIENTS`, default 100) + `bufferedAmount` backpressure (4 MiB highwater)
419
- - [x] Prometheus label-cardinality whitelist (`intent` / `platform` → `'other'` for unknowns)
420
- - [x] New counters: `im_hub_audit_prune_failed_total`, `im_hub_agent_cleanup_failed_total`, `im_hub_approval_pending` / `im_hub_approval_requests_total` / `im_hub_approval_resolved_total{result=allow|deny|timeout}`
421
- - [x] `intent-llm` cache key SHA-256 + 256-char prompt cap (defeats LRU memory bloat)
422
- - [x] Auto-allow fingerprint 5 → 10 chars (`git status` ≠ `git stash` ≠ `git submo`)
423
- - [x] UTF-16 surrogate-safe message split (emoji at boundary no longer renders as `□`)
424
- - [x] Telegram HTML escape covers `'` / `"` (approval-card `<a href="...">` safety)
425
- - [x] approval-bus over-cap deny instead of silent socket destroy
426
- - [x] SQLite WAL clean checkpoint on SIGINT
427
- - [x] traceId 12 hex → 16 hex (`~2^48` → `~2^64`)
428
- - [x] WeChat ilink-client fetch timeouts on remaining 4 callsites
429
- - [x] Discord typing interval companion `AbortController` (no race with `client.destroy()`)
430
- - [x] WeChat `contextTokens` periodic cleanup on heartbeat tick
431
- - [x] CI lockfile fix (Tencent mirror URLs → `https://registry.npmjs.org/`)
432
-
433
- ### v0.2.18 — IM reconnect backoff (M9)
434
- - [x] Shared `Backoff` helper (exponential + ±jitter, RNG-injectable for tests)
435
- - [x] Telegram `runPollingLoop`: fixed 2s / 5s setTimeouts → `Backoff(2s, 60s, 0.5)`; 30s healthy-run threshold resets backoff
436
- - [x] WeChat ilink `pollLoop`: inline `Math.pow(2,n-1)` → `Backoff(2s, 30s, 0.5)`; success path resets
437
-
438
- ### v0.2.19 — Codex sandbox + Dashboard filter / Audit tab
439
- - [x] Codex now honors `session.planMode`; default sandbox `--full-auto` → explicit `-s workspace-write`
440
- - [x] Per-agent filter on Jobs / Subtasks / Schedules tabs (`OwnerOpts.agent` plumbed through)
441
- - [x] New Audit tab in `/tasks` pulling SQLite audit log + `GET /api/audit?agent=&days=&user=&intent=`
442
-
443
- ### v0.2.20 — Web console PR-A: theme + error boundary + in-page approval
444
- - [x] Three-state theme (light / dark / system) applied synchronously in `<head>` to defeat flash
445
- - [x] `_app.js` shared utility: `window.imhub.{theme,i18n,api,showError}` + auto-installed error boundary
446
- - [x] In-chat approval cards on `/` (Allow / Deny / Allow + Auto), routed through the same `approvalBus.resolvePending()` path as Telegram
447
- - [x] `approval-router` `bindButtonHandlerForPlatform(platform)` exported so late-registered messengers (web is one) can wire their button handler
448
-
449
- ### v0.2.21 — Web console PR-B: Health + Approvals tabs
450
- - [x] Health tab: per-agent breaker phase (closed/open/half-open) + rate-limiter remaining + p50/95/99 latency + invocations / success rate / cost / cooldown + 60-poll p95 sparkline
451
- - [x] Approvals tab: list every pending HITL approval (reqId / threadId / tool / age / registeredAt) with browser-side Allow / Deny / Allow + Auto buttons
452
- - [x] Backend: `GET /api/agent-health` / `GET /api/approvals` / `POST /api/approvals/:reqId/resolve`
453
- - [x] `approval-bus.PendingApproval` now carries `input` + `registeredAt`; emits `'approval'` events for SSE
454
-
455
- ### v0.2.22 — Web console PR-C: SSE event stream + Workspace CRUD UI
456
- - [x] `src/core/event-bus.ts` — typed publish/subscribe (audit / approval / job / metrics) with 200-entry replay ring buffer
457
- - [x] `GET /events` SSE endpoint — token via `?token=`, 25s heartbeat, listener-error swallow
458
- - [x] Dashboard `EventSource('/events?token=...')` refreshes only the visible tab; polling kept as fallback; `approval requested` flashes the tab badge
459
- - [x] Settings page Workspace card — list + create / edit / delete (id locked on edit; default row uneditable + undeletable)
460
- - [x] Backend `GET/POST/PATCH/DELETE /api/workspaces` + `WorkspaceRegistry.{remove(id), listFull()}`; mutations persisted back to `~/.im-hub/config.json`
461
-
462
- ### v0.2.23 — Web console PR-D: Files tab + Jobs batch ops + settings polish
463
- - [x] Files tab — read-only browse of `~/.im-hub-workspaces/<agent>/`, two-pane (dir tree + content), 1 MiB cap, NUL-byte binary detect → base64
464
- - [x] Path-traversal defense: agent name whitelisted against `registry.listAgents()`; resolved path must equal or live below `defaultAgentCwd(agent)`
465
- - [x] Jobs tab multi-select + select-all + hidden-until-needed batch toolbar; selection state survives refresh
466
- - [x] `POST /api/jobs/batch-cancel` / `batch-run` accept `{ ids: number[] }` (max 100); per-id failures don't fail the whole request
467
- - [x] Settings header restyle (`.brand` + `.controls` flex groups) — fixes language `<select>` stretching across the bar; container 720→880, sticky header, theme-aware toast / `.btn-danger:hover`
468
-
469
- ### v0.3.0
204
+ ### Done
205
+
206
+ | Version | Theme |
207
+ |---------|-------|
208
+ | v0.1.x | MVP — WeChat + 4 agents + command routing |
209
+ | v0.2.0 | Multi-IM — Feishu, Telegram, sessions, ACP |
210
+ | v0.2.13 | Foundations — logging, audit, intent, jobs, metrics, workspaces |
211
+ | v0.2.14 | Human-in-the-loop tool approval |
212
+ | v0.2.15 | Discord adapter + tasks dashboard |
213
+ | v0.2.16–17 | Security hardening + observability |
214
+ | v0.2.18–19 | IM reconnect backoff, Codex sandbox, dashboard filters |
215
+ | v0.2.20–23 | Web console — theme, approvals, SSE, files, batch ops |
216
+ | v0.2.30 | Production hardening session isolation, serial WS, loopback bind |
217
+ | v0.2.35 | WeChat & Telegram rich media — image / file / voice / video |
218
+
219
+ ### v0.3.0 (next)
220
+
470
221
  - [ ] DingTalk adapter
471
222
  - [ ] Slack adapter
472
- - [ ] Approval cards (Feishu/Discord buttons) instead of plain text
473
- - [ ] Cron `nextOccurrence` internal UTC normalization (DST safety, M5 from CR-2026-05-06)
474
- - [ ] Multi-instance event bus (Redis Streams / NATS) so SSE works across replicas
475
- - [ ] Workspace member picker UI (current CSV input is ops-friendly but error-prone)
476
-
477
- ## Community <a name="wechat-group"></a>
223
+ - [ ] Feishu / Discord button-style approval cards
224
+ - [ ] Multi-instance event bus (Redis Streams / NATS)
225
+ - [ ] Workspace member picker UI
478
226
 
479
- Questions? Feel free to reach out on [X](https://x.com/lijieisme) or join the Discord.
227
+ ## Community
480
228
 
481
229
  <p align="center">
482
230
  <a href="https://discord.gg/R83CXYz5">
@@ -488,11 +236,6 @@ Questions? Feel free to reach out on [X](https://x.com/lijieisme) or join the Di
488
236
  </a>
489
237
  </p>
490
238
 
491
- <p align="center">
492
- <img src="assets/wechat-group" alt="Original author WeChat" width="180"><br>
493
- <sub><i>Original author's contact</i></sub>
494
- </p>
495
-
496
239
  ## License
497
240
 
498
241
  MIT