im-hub-pro 0.2.29

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 (384) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +497 -0
  3. package/README.zh-CN.md +496 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +921 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/core/acp-server.d.ts +8 -0
  9. package/dist/core/acp-server.d.ts.map +1 -0
  10. package/dist/core/acp-server.js +266 -0
  11. package/dist/core/acp-server.js.map +1 -0
  12. package/dist/core/agent-base.d.ts +94 -0
  13. package/dist/core/agent-base.d.ts.map +1 -0
  14. package/dist/core/agent-base.js +374 -0
  15. package/dist/core/agent-base.js.map +1 -0
  16. package/dist/core/agent-cwd.d.ts +45 -0
  17. package/dist/core/agent-cwd.d.ts.map +1 -0
  18. package/dist/core/agent-cwd.js +178 -0
  19. package/dist/core/agent-cwd.js.map +1 -0
  20. package/dist/core/agent-cwd.test.d.ts +2 -0
  21. package/dist/core/agent-cwd.test.d.ts.map +1 -0
  22. package/dist/core/agent-cwd.test.js +149 -0
  23. package/dist/core/agent-cwd.test.js.map +1 -0
  24. package/dist/core/approval-bus.d.ts +232 -0
  25. package/dist/core/approval-bus.d.ts.map +1 -0
  26. package/dist/core/approval-bus.js +703 -0
  27. package/dist/core/approval-bus.js.map +1 -0
  28. package/dist/core/approval-bus.synthetic.test.d.ts +2 -0
  29. package/dist/core/approval-bus.synthetic.test.d.ts.map +1 -0
  30. package/dist/core/approval-bus.synthetic.test.js +182 -0
  31. package/dist/core/approval-bus.synthetic.test.js.map +1 -0
  32. package/dist/core/approval-bus.test.d.ts +2 -0
  33. package/dist/core/approval-bus.test.d.ts.map +1 -0
  34. package/dist/core/approval-bus.test.js +537 -0
  35. package/dist/core/approval-bus.test.js.map +1 -0
  36. package/dist/core/approval-router.d.ts +95 -0
  37. package/dist/core/approval-router.d.ts.map +1 -0
  38. package/dist/core/approval-router.js +450 -0
  39. package/dist/core/approval-router.js.map +1 -0
  40. package/dist/core/approval-router.test.d.ts +2 -0
  41. package/dist/core/approval-router.test.d.ts.map +1 -0
  42. package/dist/core/approval-router.test.js +413 -0
  43. package/dist/core/approval-router.test.js.map +1 -0
  44. package/dist/core/audit-log.d.ts +55 -0
  45. package/dist/core/audit-log.d.ts.map +1 -0
  46. package/dist/core/audit-log.js +203 -0
  47. package/dist/core/audit-log.js.map +1 -0
  48. package/dist/core/bgjob-reader.d.ts +65 -0
  49. package/dist/core/bgjob-reader.d.ts.map +1 -0
  50. package/dist/core/bgjob-reader.js +212 -0
  51. package/dist/core/bgjob-reader.js.map +1 -0
  52. package/dist/core/bgjob-reader.test.d.ts +2 -0
  53. package/dist/core/bgjob-reader.test.d.ts.map +1 -0
  54. package/dist/core/bgjob-reader.test.js +178 -0
  55. package/dist/core/bgjob-reader.test.js.map +1 -0
  56. package/dist/core/circuit-breaker.d.ts +37 -0
  57. package/dist/core/circuit-breaker.d.ts.map +1 -0
  58. package/dist/core/circuit-breaker.js +115 -0
  59. package/dist/core/circuit-breaker.js.map +1 -0
  60. package/dist/core/commands/agent.d.ts +4 -0
  61. package/dist/core/commands/agent.d.ts.map +1 -0
  62. package/dist/core/commands/agent.js +21 -0
  63. package/dist/core/commands/agent.js.map +1 -0
  64. package/dist/core/commands/approval.d.ts +3 -0
  65. package/dist/core/commands/approval.d.ts.map +1 -0
  66. package/dist/core/commands/approval.js +44 -0
  67. package/dist/core/commands/approval.js.map +1 -0
  68. package/dist/core/commands/approval.test.d.ts +2 -0
  69. package/dist/core/commands/approval.test.d.ts.map +1 -0
  70. package/dist/core/commands/approval.test.js +85 -0
  71. package/dist/core/commands/approval.test.js.map +1 -0
  72. package/dist/core/commands/audit.d.ts +3 -0
  73. package/dist/core/commands/audit.d.ts.map +1 -0
  74. package/dist/core/commands/audit.js +84 -0
  75. package/dist/core/commands/audit.js.map +1 -0
  76. package/dist/core/commands/builtin.d.ts +3 -0
  77. package/dist/core/commands/builtin.d.ts.map +1 -0
  78. package/dist/core/commands/builtin.js +26 -0
  79. package/dist/core/commands/builtin.js.map +1 -0
  80. package/dist/core/commands/job.d.ts +3 -0
  81. package/dist/core/commands/job.d.ts.map +1 -0
  82. package/dist/core/commands/job.js +195 -0
  83. package/dist/core/commands/job.js.map +1 -0
  84. package/dist/core/commands/model.d.ts +9 -0
  85. package/dist/core/commands/model.d.ts.map +1 -0
  86. package/dist/core/commands/model.js +183 -0
  87. package/dist/core/commands/model.js.map +1 -0
  88. package/dist/core/commands/plan.d.ts +3 -0
  89. package/dist/core/commands/plan.d.ts.map +1 -0
  90. package/dist/core/commands/plan.js +75 -0
  91. package/dist/core/commands/plan.js.map +1 -0
  92. package/dist/core/commands/plan.test.d.ts +2 -0
  93. package/dist/core/commands/plan.test.d.ts.map +1 -0
  94. package/dist/core/commands/plan.test.js +122 -0
  95. package/dist/core/commands/plan.test.js.map +1 -0
  96. package/dist/core/commands/router.d.ts +3 -0
  97. package/dist/core/commands/router.d.ts.map +1 -0
  98. package/dist/core/commands/router.js +71 -0
  99. package/dist/core/commands/router.js.map +1 -0
  100. package/dist/core/commands/schedule.d.ts +3 -0
  101. package/dist/core/commands/schedule.d.ts.map +1 -0
  102. package/dist/core/commands/schedule.js +123 -0
  103. package/dist/core/commands/schedule.js.map +1 -0
  104. package/dist/core/commands/sessions.d.ts +3 -0
  105. package/dist/core/commands/sessions.d.ts.map +1 -0
  106. package/dist/core/commands/sessions.js +88 -0
  107. package/dist/core/commands/sessions.js.map +1 -0
  108. package/dist/core/commands/stats.d.ts +3 -0
  109. package/dist/core/commands/stats.d.ts.map +1 -0
  110. package/dist/core/commands/stats.js +73 -0
  111. package/dist/core/commands/stats.js.map +1 -0
  112. package/dist/core/commands/think.d.ts +3 -0
  113. package/dist/core/commands/think.d.ts.map +1 -0
  114. package/dist/core/commands/think.js +28 -0
  115. package/dist/core/commands/think.js.map +1 -0
  116. package/dist/core/commands/workspaces.d.ts +3 -0
  117. package/dist/core/commands/workspaces.d.ts.map +1 -0
  118. package/dist/core/commands/workspaces.js +47 -0
  119. package/dist/core/commands/workspaces.js.map +1 -0
  120. package/dist/core/config-schema.d.ts +58 -0
  121. package/dist/core/config-schema.d.ts.map +1 -0
  122. package/dist/core/config-schema.js +63 -0
  123. package/dist/core/config-schema.js.map +1 -0
  124. package/dist/core/cron.d.ts +29 -0
  125. package/dist/core/cron.d.ts.map +1 -0
  126. package/dist/core/cron.js +184 -0
  127. package/dist/core/cron.js.map +1 -0
  128. package/dist/core/event-bus.d.ts +80 -0
  129. package/dist/core/event-bus.d.ts.map +1 -0
  130. package/dist/core/event-bus.js +62 -0
  131. package/dist/core/event-bus.js.map +1 -0
  132. package/dist/core/intent-llm.d.ts +27 -0
  133. package/dist/core/intent-llm.d.ts.map +1 -0
  134. package/dist/core/intent-llm.js +170 -0
  135. package/dist/core/intent-llm.js.map +1 -0
  136. package/dist/core/intent.d.ts +12 -0
  137. package/dist/core/intent.d.ts.map +1 -0
  138. package/dist/core/intent.js +187 -0
  139. package/dist/core/intent.js.map +1 -0
  140. package/dist/core/job-board.d.ts +84 -0
  141. package/dist/core/job-board.d.ts.map +1 -0
  142. package/dist/core/job-board.js +379 -0
  143. package/dist/core/job-board.js.map +1 -0
  144. package/dist/core/logger.d.ts +6 -0
  145. package/dist/core/logger.d.ts.map +1 -0
  146. package/dist/core/logger.js +54 -0
  147. package/dist/core/logger.js.map +1 -0
  148. package/dist/core/metrics.d.ts +55 -0
  149. package/dist/core/metrics.d.ts.map +1 -0
  150. package/dist/core/metrics.js +291 -0
  151. package/dist/core/metrics.js.map +1 -0
  152. package/dist/core/onboarding.d.ts +94 -0
  153. package/dist/core/onboarding.d.ts.map +1 -0
  154. package/dist/core/onboarding.js +426 -0
  155. package/dist/core/onboarding.js.map +1 -0
  156. package/dist/core/onboarding.test.d.ts +2 -0
  157. package/dist/core/onboarding.test.d.ts.map +1 -0
  158. package/dist/core/onboarding.test.js +112 -0
  159. package/dist/core/onboarding.test.js.map +1 -0
  160. package/dist/core/rate-limiter.d.ts +44 -0
  161. package/dist/core/rate-limiter.d.ts.map +1 -0
  162. package/dist/core/rate-limiter.js +115 -0
  163. package/dist/core/rate-limiter.js.map +1 -0
  164. package/dist/core/registry.d.ts +32 -0
  165. package/dist/core/registry.d.ts.map +1 -0
  166. package/dist/core/registry.js +122 -0
  167. package/dist/core/registry.js.map +1 -0
  168. package/dist/core/router.d.ts +41 -0
  169. package/dist/core/router.d.ts.map +1 -0
  170. package/dist/core/router.js +431 -0
  171. package/dist/core/router.js.map +1 -0
  172. package/dist/core/schedule.d.ts +65 -0
  173. package/dist/core/schedule.d.ts.map +1 -0
  174. package/dist/core/schedule.js +316 -0
  175. package/dist/core/schedule.js.map +1 -0
  176. package/dist/core/session-subtasks.test.d.ts +2 -0
  177. package/dist/core/session-subtasks.test.d.ts.map +1 -0
  178. package/dist/core/session-subtasks.test.js +88 -0
  179. package/dist/core/session-subtasks.test.js.map +1 -0
  180. package/dist/core/session.d.ts +182 -0
  181. package/dist/core/session.d.ts.map +1 -0
  182. package/dist/core/session.js +774 -0
  183. package/dist/core/session.js.map +1 -0
  184. package/dist/core/sqlite-helper.d.ts +37 -0
  185. package/dist/core/sqlite-helper.d.ts.map +1 -0
  186. package/dist/core/sqlite-helper.js +79 -0
  187. package/dist/core/sqlite-helper.js.map +1 -0
  188. package/dist/core/transcribe.d.ts +25 -0
  189. package/dist/core/transcribe.d.ts.map +1 -0
  190. package/dist/core/transcribe.js +217 -0
  191. package/dist/core/transcribe.js.map +1 -0
  192. package/dist/core/transcribe.test.d.ts +2 -0
  193. package/dist/core/transcribe.test.d.ts.map +1 -0
  194. package/dist/core/transcribe.test.js +163 -0
  195. package/dist/core/transcribe.test.js.map +1 -0
  196. package/dist/core/types.d.ts +352 -0
  197. package/dist/core/types.d.ts.map +1 -0
  198. package/dist/core/types.js +3 -0
  199. package/dist/core/types.js.map +1 -0
  200. package/dist/core/workspace.d.ts +67 -0
  201. package/dist/core/workspace.d.ts.map +1 -0
  202. package/dist/core/workspace.js +113 -0
  203. package/dist/core/workspace.js.map +1 -0
  204. package/dist/index.d.ts +5 -0
  205. package/dist/index.d.ts.map +1 -0
  206. package/dist/index.js +6 -0
  207. package/dist/index.js.map +1 -0
  208. package/dist/plugins/agents/acp/acp-adapter.d.ts +16 -0
  209. package/dist/plugins/agents/acp/acp-adapter.d.ts.map +1 -0
  210. package/dist/plugins/agents/acp/acp-adapter.js +49 -0
  211. package/dist/plugins/agents/acp/acp-adapter.js.map +1 -0
  212. package/dist/plugins/agents/acp/acp-client.d.ts +32 -0
  213. package/dist/plugins/agents/acp/acp-client.d.ts.map +1 -0
  214. package/dist/plugins/agents/acp/acp-client.js +175 -0
  215. package/dist/plugins/agents/acp/acp-client.js.map +1 -0
  216. package/dist/plugins/agents/acp/discovery.d.ts +19 -0
  217. package/dist/plugins/agents/acp/discovery.d.ts.map +1 -0
  218. package/dist/plugins/agents/acp/discovery.js +109 -0
  219. package/dist/plugins/agents/acp/discovery.js.map +1 -0
  220. package/dist/plugins/agents/acp/index.d.ts +4 -0
  221. package/dist/plugins/agents/acp/index.d.ts.map +1 -0
  222. package/dist/plugins/agents/acp/index.js +4 -0
  223. package/dist/plugins/agents/acp/index.js.map +1 -0
  224. package/dist/plugins/agents/acp/types.d.ts +62 -0
  225. package/dist/plugins/agents/acp/types.d.ts.map +1 -0
  226. package/dist/plugins/agents/acp/types.js +5 -0
  227. package/dist/plugins/agents/acp/types.js.map +1 -0
  228. package/dist/plugins/agents/claude-code/adapter.test.d.ts +2 -0
  229. package/dist/plugins/agents/claude-code/adapter.test.d.ts.map +1 -0
  230. package/dist/plugins/agents/claude-code/adapter.test.js +195 -0
  231. package/dist/plugins/agents/claude-code/adapter.test.js.map +1 -0
  232. package/dist/plugins/agents/claude-code/index.d.ts +25 -0
  233. package/dist/plugins/agents/claude-code/index.d.ts.map +1 -0
  234. package/dist/plugins/agents/claude-code/index.js +184 -0
  235. package/dist/plugins/agents/claude-code/index.js.map +1 -0
  236. package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts +42 -0
  237. package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts.map +1 -0
  238. package/dist/plugins/agents/claude-code/mcp-approval-server.js +235 -0
  239. package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -0
  240. package/dist/plugins/agents/claude-code/mcp-approval-server.test.d.ts +2 -0
  241. package/dist/plugins/agents/claude-code/mcp-approval-server.test.d.ts.map +1 -0
  242. package/dist/plugins/agents/claude-code/mcp-approval-server.test.js +188 -0
  243. package/dist/plugins/agents/claude-code/mcp-approval-server.test.js.map +1 -0
  244. package/dist/plugins/agents/codex/adapter.test.d.ts +2 -0
  245. package/dist/plugins/agents/codex/adapter.test.d.ts.map +1 -0
  246. package/dist/plugins/agents/codex/adapter.test.js +192 -0
  247. package/dist/plugins/agents/codex/adapter.test.js.map +1 -0
  248. package/dist/plugins/agents/codex/index.d.ts +37 -0
  249. package/dist/plugins/agents/codex/index.d.ts.map +1 -0
  250. package/dist/plugins/agents/codex/index.js +254 -0
  251. package/dist/plugins/agents/codex/index.js.map +1 -0
  252. package/dist/plugins/agents/copilot/index.d.ts +35 -0
  253. package/dist/plugins/agents/copilot/index.d.ts.map +1 -0
  254. package/dist/plugins/agents/copilot/index.js +182 -0
  255. package/dist/plugins/agents/copilot/index.js.map +1 -0
  256. package/dist/plugins/agents/opencode/adapter.test.d.ts +2 -0
  257. package/dist/plugins/agents/opencode/adapter.test.d.ts.map +1 -0
  258. package/dist/plugins/agents/opencode/adapter.test.js +139 -0
  259. package/dist/plugins/agents/opencode/adapter.test.js.map +1 -0
  260. package/dist/plugins/agents/opencode/http-adapter.test.d.ts +2 -0
  261. package/dist/plugins/agents/opencode/http-adapter.test.d.ts.map +1 -0
  262. package/dist/plugins/agents/opencode/http-adapter.test.js +492 -0
  263. package/dist/plugins/agents/opencode/http-adapter.test.js.map +1 -0
  264. package/dist/plugins/agents/opencode/index.d.ts +5 -0
  265. package/dist/plugins/agents/opencode/index.d.ts.map +1 -0
  266. package/dist/plugins/agents/opencode/index.js +30 -0
  267. package/dist/plugins/agents/opencode/index.js.map +1 -0
  268. package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts +138 -0
  269. package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -0
  270. package/dist/plugins/agents/opencode/opencode-http-adapter.js +549 -0
  271. package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -0
  272. package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts +24 -0
  273. package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts.map +1 -0
  274. package/dist/plugins/agents/opencode/opencode-stdio-adapter.js +103 -0
  275. package/dist/plugins/agents/opencode/opencode-stdio-adapter.js.map +1 -0
  276. package/dist/plugins/agents/opencode/serve-manager.d.ts +27 -0
  277. package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -0
  278. package/dist/plugins/agents/opencode/serve-manager.js +190 -0
  279. package/dist/plugins/agents/opencode/serve-manager.js.map +1 -0
  280. package/dist/plugins/messengers/discord/discord-adapter.d.ts +22 -0
  281. package/dist/plugins/messengers/discord/discord-adapter.d.ts.map +1 -0
  282. package/dist/plugins/messengers/discord/discord-adapter.js +241 -0
  283. package/dist/plugins/messengers/discord/discord-adapter.js.map +1 -0
  284. package/dist/plugins/messengers/discord/discord-adapter.test.d.ts +2 -0
  285. package/dist/plugins/messengers/discord/discord-adapter.test.d.ts.map +1 -0
  286. package/dist/plugins/messengers/discord/discord-adapter.test.js +332 -0
  287. package/dist/plugins/messengers/discord/discord-adapter.test.js.map +1 -0
  288. package/dist/plugins/messengers/discord/index.d.ts +4 -0
  289. package/dist/plugins/messengers/discord/index.d.ts.map +1 -0
  290. package/dist/plugins/messengers/discord/index.js +4 -0
  291. package/dist/plugins/messengers/discord/index.js.map +1 -0
  292. package/dist/plugins/messengers/discord/markdown-to-discord.d.ts +11 -0
  293. package/dist/plugins/messengers/discord/markdown-to-discord.d.ts.map +1 -0
  294. package/dist/plugins/messengers/discord/markdown-to-discord.js +59 -0
  295. package/dist/plugins/messengers/discord/markdown-to-discord.js.map +1 -0
  296. package/dist/plugins/messengers/discord/types.d.ts +9 -0
  297. package/dist/plugins/messengers/discord/types.d.ts.map +1 -0
  298. package/dist/plugins/messengers/discord/types.js +3 -0
  299. package/dist/plugins/messengers/discord/types.js.map +1 -0
  300. package/dist/plugins/messengers/feishu/card-builder.d.ts +23 -0
  301. package/dist/plugins/messengers/feishu/card-builder.d.ts.map +1 -0
  302. package/dist/plugins/messengers/feishu/card-builder.js +89 -0
  303. package/dist/plugins/messengers/feishu/card-builder.js.map +1 -0
  304. package/dist/plugins/messengers/feishu/feishu-adapter.d.ts +33 -0
  305. package/dist/plugins/messengers/feishu/feishu-adapter.d.ts.map +1 -0
  306. package/dist/plugins/messengers/feishu/feishu-adapter.js +195 -0
  307. package/dist/plugins/messengers/feishu/feishu-adapter.js.map +1 -0
  308. package/dist/plugins/messengers/feishu/feishu-client.d.ts +44 -0
  309. package/dist/plugins/messengers/feishu/feishu-client.d.ts.map +1 -0
  310. package/dist/plugins/messengers/feishu/feishu-client.js +120 -0
  311. package/dist/plugins/messengers/feishu/feishu-client.js.map +1 -0
  312. package/dist/plugins/messengers/feishu/feishu-dedup.test.d.ts +2 -0
  313. package/dist/plugins/messengers/feishu/feishu-dedup.test.d.ts.map +1 -0
  314. package/dist/plugins/messengers/feishu/feishu-dedup.test.js +70 -0
  315. package/dist/plugins/messengers/feishu/feishu-dedup.test.js.map +1 -0
  316. package/dist/plugins/messengers/feishu/index.d.ts +4 -0
  317. package/dist/plugins/messengers/feishu/index.d.ts.map +1 -0
  318. package/dist/plugins/messengers/feishu/index.js +4 -0
  319. package/dist/plugins/messengers/feishu/index.js.map +1 -0
  320. package/dist/plugins/messengers/feishu/types.d.ts +113 -0
  321. package/dist/plugins/messengers/feishu/types.d.ts.map +1 -0
  322. package/dist/plugins/messengers/feishu/types.js +4 -0
  323. package/dist/plugins/messengers/feishu/types.js.map +1 -0
  324. package/dist/plugins/messengers/telegram/index.d.ts +4 -0
  325. package/dist/plugins/messengers/telegram/index.d.ts.map +1 -0
  326. package/dist/plugins/messengers/telegram/index.js +4 -0
  327. package/dist/plugins/messengers/telegram/index.js.map +1 -0
  328. package/dist/plugins/messengers/telegram/markdown-to-html.d.ts +5 -0
  329. package/dist/plugins/messengers/telegram/markdown-to-html.d.ts.map +1 -0
  330. package/dist/plugins/messengers/telegram/markdown-to-html.js +186 -0
  331. package/dist/plugins/messengers/telegram/markdown-to-html.js.map +1 -0
  332. package/dist/plugins/messengers/telegram/media-download.d.ts +51 -0
  333. package/dist/plugins/messengers/telegram/media-download.d.ts.map +1 -0
  334. package/dist/plugins/messengers/telegram/media-download.js +224 -0
  335. package/dist/plugins/messengers/telegram/media-download.js.map +1 -0
  336. package/dist/plugins/messengers/telegram/media-download.test.d.ts +2 -0
  337. package/dist/plugins/messengers/telegram/media-download.test.d.ts.map +1 -0
  338. package/dist/plugins/messengers/telegram/media-download.test.js +125 -0
  339. package/dist/plugins/messengers/telegram/media-download.test.js.map +1 -0
  340. package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +62 -0
  341. package/dist/plugins/messengers/telegram/telegram-adapter.d.ts.map +1 -0
  342. package/dist/plugins/messengers/telegram/telegram-adapter.js +653 -0
  343. package/dist/plugins/messengers/telegram/telegram-adapter.js.map +1 -0
  344. package/dist/plugins/messengers/telegram/types.d.ts +47 -0
  345. package/dist/plugins/messengers/telegram/types.d.ts.map +1 -0
  346. package/dist/plugins/messengers/telegram/types.js +3 -0
  347. package/dist/plugins/messengers/telegram/types.js.map +1 -0
  348. package/dist/plugins/messengers/wechat/ilink-adapter.d.ts +68 -0
  349. package/dist/plugins/messengers/wechat/ilink-adapter.d.ts.map +1 -0
  350. package/dist/plugins/messengers/wechat/ilink-adapter.js +483 -0
  351. package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -0
  352. package/dist/plugins/messengers/wechat/ilink-client.d.ts +66 -0
  353. package/dist/plugins/messengers/wechat/ilink-client.d.ts.map +1 -0
  354. package/dist/plugins/messengers/wechat/ilink-client.js +288 -0
  355. package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -0
  356. package/dist/plugins/messengers/wechat/ilink-types.d.ts +173 -0
  357. package/dist/plugins/messengers/wechat/ilink-types.d.ts.map +1 -0
  358. package/dist/plugins/messengers/wechat/ilink-types.js +12 -0
  359. package/dist/plugins/messengers/wechat/ilink-types.js.map +1 -0
  360. package/dist/utils/backoff.d.ts +35 -0
  361. package/dist/utils/backoff.d.ts.map +1 -0
  362. package/dist/utils/backoff.js +59 -0
  363. package/dist/utils/backoff.js.map +1 -0
  364. package/dist/utils/cross-platform.d.ts +26 -0
  365. package/dist/utils/cross-platform.d.ts.map +1 -0
  366. package/dist/utils/cross-platform.js +58 -0
  367. package/dist/utils/cross-platform.js.map +1 -0
  368. package/dist/utils/message-split.d.ts +14 -0
  369. package/dist/utils/message-split.d.ts.map +1 -0
  370. package/dist/utils/message-split.js +65 -0
  371. package/dist/utils/message-split.js.map +1 -0
  372. package/dist/utils/safe-equal.d.ts +2 -0
  373. package/dist/utils/safe-equal.d.ts.map +1 -0
  374. package/dist/utils/safe-equal.js +11 -0
  375. package/dist/utils/safe-equal.js.map +1 -0
  376. package/dist/web/public/_app.js +196 -0
  377. package/dist/web/public/index.html +935 -0
  378. package/dist/web/public/settings.html +1181 -0
  379. package/dist/web/public/tasks.html +1827 -0
  380. package/dist/web/server.d.ts +11 -0
  381. package/dist/web/server.d.ts.map +1 -0
  382. package/dist/web/server.js +1820 -0
  383. package/dist/web/server.js.map +1 -0
  384. package/package.json +73 -0
package/dist/cli.js ADDED
@@ -0,0 +1,921 @@
1
+ #!/usr/bin/env node
2
+ // im-hub-pro CLI
3
+ //
4
+ // NOTE: brand string "im-hub-pro" is user-visible (CLI program name, console
5
+ // banners, help text). On-disk paths (~/.im-hub/, ~/.im-hub-workspaces/),
6
+ // env vars (IMHUB_*), and HTTP headers (X-IM-Hub-Token) intentionally
7
+ // retain the legacy "im-hub" identifier for drop-in compatibility with
8
+ // existing installations. Do not "fix" them.
9
+ import { program } from 'commander';
10
+ import { homedir } from 'os';
11
+ import { join } from 'path';
12
+ import { randomUUID } from 'crypto';
13
+ import { registry } from './core/registry.js';
14
+ import { sessionManager } from './core/session.js';
15
+ import { parseMessage, routeMessage } from './core/router.js';
16
+ import { crossSpawn, isMac, isWindows } from './utils/cross-platform.js';
17
+ import { generateTraceId, createLogger } from './core/logger.js';
18
+ import { validateConfig } from './core/config-schema.js';
19
+ import { workspaceRegistry } from './core/workspace.js';
20
+ import { bootstrapAgentWorkspaces } from './core/agent-cwd.js';
21
+ import { approvalBus } from './core/approval-bus.js';
22
+ import { install as installApprovalRouter, tryHandleApprovalReply, platformToMessengerName } from './core/approval-router.js';
23
+ import { checkMessengerConfig, checkAgentAvailability, runMessengerOnboarding, formatAgentInstallHint, formatMessengerStartError, loadConfig as loadOnboardingConfig, saveConfig as saveOnboardingConfig, } from './core/onboarding.js';
24
+ import { startWebServer } from './web/server.js';
25
+ import { startACPServer } from './core/acp-server.js';
26
+ // Helper to format agent install hint for missing agents
27
+ function formatMissingAgentHint(missing) {
28
+ return formatAgentInstallHint(missing);
29
+ }
30
+ const CONFIG_DIR = join(homedir(), '.im-hub');
31
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
32
+ async function loadConfig() {
33
+ return loadOnboardingConfig();
34
+ }
35
+ async function saveConfig(config) {
36
+ return saveOnboardingConfig(config);
37
+ }
38
+ program
39
+ .name('im-hub-pro')
40
+ .description('Universal messenger-to-agent bridge')
41
+ .version('0.2.18');
42
+ program
43
+ .command('start')
44
+ .description('Start the im-hub-pro server')
45
+ .action(async () => {
46
+ console.log('šŸš€ Starting im-hub-pro...');
47
+ let config = await loadConfig();
48
+ console.log(`Config loaded from ${CONFIG_FILE}`);
49
+ // Validate config schema
50
+ const validation = validateConfig(config);
51
+ if (!validation.ok) {
52
+ console.warn('āš ļø Config schema issues detected:');
53
+ for (const err of validation.errors) {
54
+ console.warn(` - ${err}`);
55
+ }
56
+ console.warn(' im-hub-pro will continue with defaults for invalid fields.\n');
57
+ }
58
+ config = validation.ok ? validation.config : config;
59
+ // Initialize workspace registry
60
+ const rawConfig = config;
61
+ const workspaces = rawConfig.workspaces;
62
+ workspaceRegistry.load({ workspaces: workspaces });
63
+ const wsCount = workspaces?.length || 1;
64
+ console.log(`Workspaces loaded: ${wsCount} workspace(s)`);
65
+ // Initialize session manager
66
+ await sessionManager.start();
67
+ // Start approval-bus before any agent can spawn — failure here is
68
+ // non-fatal: claude-code falls back to legacy --permission-mode dontAsk.
69
+ if (process.env.IMHUB_APPROVAL_DISABLED === '1') {
70
+ console.log('šŸ›‘ Approval bus disabled via IMHUB_APPROVAL_DISABLED=1');
71
+ }
72
+ else {
73
+ try {
74
+ const sockPath = await approvalBus.start();
75
+ console.log(`āœ… Approval bus listening on ${sockPath}`);
76
+ }
77
+ catch (err) {
78
+ const msg = err instanceof Error ? err.message : String(err);
79
+ console.warn(`āš ļø Approval bus failed to start (${msg}); claude-code will fall back to dontAsk mode`);
80
+ }
81
+ }
82
+ // Wire the bus's lifetime counters into /api/metrics (M14). Done even
83
+ // when the bus failed to start — getMetrics() returns zeros, which is
84
+ // the correct Prometheus snapshot for "no approvals processed".
85
+ const { setApprovalBusSnapshotProvider } = await import('./core/metrics.js');
86
+ setApprovalBusSnapshotProvider(() => approvalBus.getMetrics());
87
+ // Load plugins FIRST (agents won't be registered until this runs)
88
+ await registry.loadBuiltInPlugins();
89
+ // Bootstrap per-agent IM workspaces. Idempotent — creates
90
+ // ~/.im-hub-workspaces/<agent>/ and seeds CLAUDE.md / AGENTS.md only if
91
+ // they don't exist yet. See docs/architecture/agent-cwd-and-memory.md.
92
+ try {
93
+ const bootstrapped = await bootstrapAgentWorkspaces();
94
+ for (const { agent, dir } of bootstrapped) {
95
+ console.log(`šŸ“ Agent workspace: ${agent} → ${dir}`);
96
+ }
97
+ }
98
+ catch (err) {
99
+ const msg = err instanceof Error ? err.message : String(err);
100
+ console.warn(`āš ļø Agent workspace bootstrap failed: ${msg}`);
101
+ console.warn(' Agents will fall back to im-hub-pro cwd ("/" under systemd)');
102
+ }
103
+ // Load ACP (remote) agents from config
104
+ if (config.acpAgents?.length) {
105
+ await registry.loadACPAgents(config.acpAgents);
106
+ }
107
+ // Discover ACP agents via .well-known/acp on configured base URLs
108
+ const discoveryUrls = config.acpDiscoveryUrls;
109
+ if (discoveryUrls?.length) {
110
+ await registry.loadDiscoveredACPAgents(discoveryUrls);
111
+ }
112
+ // Start the scheduler (runs cron-due schedules every 30s)
113
+ const { startScheduler } = await import('./core/schedule.js');
114
+ startScheduler();
115
+ // ============================================
116
+ // ONBOARDING CHECKS (before default fill!)
117
+ // ============================================
118
+ // Check messengers BEFORE the default fill
119
+ const onboardingResult = checkMessengerConfig(config);
120
+ if (onboardingResult.needsOnboarding) {
121
+ console.log('šŸ‘‹ No messengers configured.\n');
122
+ const newConfig = await runMessengerOnboarding(config);
123
+ if (!newConfig) {
124
+ console.log('\nāŒ Onboarding cancelled.');
125
+ console.log('Run "im-hub-pro config <messenger>" to configure manually.');
126
+ process.exit(1);
127
+ }
128
+ config = newConfig;
129
+ await saveConfig(config);
130
+ }
131
+ // Check agents (async, AFTER plugins loaded)
132
+ const agentResult = await checkAgentAvailability();
133
+ if (agentResult.allMissing) {
134
+ console.log('\nāš ļø No coding agents found!');
135
+ console.log(formatAgentInstallHint(agentResult.missing));
136
+ console.log('\nInstall at least one agent, then run im-hub-pro start again.');
137
+ process.exit(1);
138
+ }
139
+ else if (agentResult.missing.length > 0) {
140
+ console.log('āš ļø Some agents not available:', agentResult.missing.join(', '));
141
+ console.log(' ' + formatAgentInstallHint(agentResult.missing));
142
+ console.log('');
143
+ }
144
+ // Set defaultAgent to first available installed agent
145
+ if (agentResult.available.length > 0) {
146
+ config.defaultAgent = agentResult.available[0];
147
+ }
148
+ // ============================================
149
+ // START MESSENGERS
150
+ // ============================================
151
+ // Get messengers to start (now config.messengers is populated)
152
+ const messengersToStart = config.messengers.length > 0
153
+ ? config.messengers
154
+ : ['wechat-ilink']; // Fallback default
155
+ // Start messenger adapters
156
+ for (const name of messengersToStart) {
157
+ const messenger = registry.getMessenger(name);
158
+ if (!messenger) {
159
+ console.warn(`āš ļø Messenger "${name}" not found, skipping`);
160
+ continue;
161
+ }
162
+ // Set up message handler
163
+ messenger.onMessage(async (ctx) => {
164
+ const traceId = generateTraceId();
165
+ ctx.traceId = traceId;
166
+ ctx.logger = createLogger({ traceId, platform: ctx.platform, component: 'cli' });
167
+ ctx.logger.info({ event: 'message.received', text: ctx.message.text.substring(0, 120), userId: ctx.message.userId });
168
+ // Approval interception comes BEFORE the agent router. If a pending
169
+ // approval exists for this thread and the message is a y/n-style
170
+ // reply, we resolve the approval and stop. Anything else routes
171
+ // normally (with the side effect of auto-denying any stale pending —
172
+ // see approval-router.ts).
173
+ if (tryHandleApprovalReply(ctx.message.threadId, ctx.message.text)) {
174
+ ctx.logger.info({ event: 'message.consumed_by_approval' });
175
+ return;
176
+ }
177
+ await handleMessage(ctx, config.defaultAgent);
178
+ });
179
+ try {
180
+ await messenger.start();
181
+ console.log(`āœ… Started messenger: ${name}`);
182
+ }
183
+ catch (error) {
184
+ const errMsg = error instanceof Error ? error.message : String(error);
185
+ console.error(`āŒ Failed to start messenger ${name}:`);
186
+ console.error(` ${errMsg}`);
187
+ // Show actionable next step, not stack trace
188
+ const hint = formatMessengerStartError(name, error);
189
+ if (hint !== errMsg) {
190
+ console.error(` ${hint}`);
191
+ }
192
+ }
193
+ }
194
+ // ============================================
195
+ // WIRE APPROVAL ROUTER (after messengers are up)
196
+ // ============================================
197
+ if (approvalBus.getSocketPath()) {
198
+ installApprovalRouter({
199
+ resolveMessenger: (platform) => registry.getMessenger(platformToMessengerName(platform)),
200
+ });
201
+ console.log('āœ… Approval router wired to messengers');
202
+ }
203
+ // ============================================
204
+ // START WEB CHAT SERVER
205
+ // ============================================
206
+ let webServer;
207
+ try {
208
+ webServer = await startWebServer({
209
+ port: config.webPort,
210
+ defaultAgent: config.defaultAgent,
211
+ });
212
+ }
213
+ catch (err) {
214
+ const errMsg = err instanceof Error ? err.message : String(err);
215
+ console.warn(`āš ļø Web chat server failed to start: ${errMsg}`);
216
+ }
217
+ // ============================================
218
+ // START ACP SERVER
219
+ // ============================================
220
+ let acpServer;
221
+ const acpPort = config.acpPort || undefined;
222
+ try {
223
+ acpServer = await startACPServer({
224
+ port: acpPort,
225
+ defaultAgent: config.defaultAgent,
226
+ });
227
+ }
228
+ catch (err) {
229
+ const errMsg = err instanceof Error ? err.message : String(err);
230
+ console.warn(`āš ļø ACP server failed to start: ${errMsg}`);
231
+ }
232
+ console.log('\nāœ… IM hub is running!');
233
+ if (webServer) {
234
+ console.log(` Chat UI: http://localhost:${webServer.port}`);
235
+ }
236
+ if (acpServer) {
237
+ console.log(` ACP Endpoint: http://localhost:${acpServer.port}`);
238
+ }
239
+ console.log('Press Ctrl+C to stop');
240
+ // Keep process alive
241
+ process.on('SIGINT', async () => {
242
+ console.log('\nšŸ‘‹ Shutting down...');
243
+ sessionManager.stop();
244
+ webServer?.close();
245
+ acpServer?.close();
246
+ // Stop all messengers
247
+ for (const name of registry.listMessengers()) {
248
+ const messenger = registry.getMessenger(name);
249
+ if (messenger) {
250
+ await messenger.stop();
251
+ }
252
+ }
253
+ // Stop approval bus last — denies any in-flight approvals so sidecar
254
+ // processes don't hang. Always called even if start() failed earlier.
255
+ try {
256
+ await approvalBus.stop();
257
+ }
258
+ catch { /* ignore */ }
259
+ // L2: stop background sweepers and checkpoint SQLite WAL files before
260
+ // exiting. Without these, the next startup has to recover the WAL
261
+ // (cheap but visible in logs and slows boot).
262
+ try {
263
+ const { stopRetentionSweep, closeAuditDb } = await import('./core/audit-log.js');
264
+ stopRetentionSweep();
265
+ closeAuditDb();
266
+ }
267
+ catch { /* ignore */ }
268
+ try {
269
+ const { stopJobRetentionSweep, closeJobBoardDb } = await import('./core/job-board.js');
270
+ stopJobRetentionSweep();
271
+ closeJobBoardDb();
272
+ }
273
+ catch { /* ignore */ }
274
+ try {
275
+ const { stopScheduler, closeScheduleDb } = await import('./core/schedule.js');
276
+ stopScheduler();
277
+ closeScheduleDb();
278
+ }
279
+ catch { /* ignore */ }
280
+ process.exit(0);
281
+ });
282
+ // Wait forever
283
+ await new Promise(() => { });
284
+ });
285
+ /**
286
+ * Handle incoming message from any messenger
287
+ */
288
+ async function handleMessage(ctx, defaultAgent) {
289
+ const { message, platform, channelId } = ctx;
290
+ const traceId = ctx.traceId || generateTraceId();
291
+ const logger = ctx.logger || createLogger({ traceId, platform, component: 'cli' });
292
+ const messengerName = platform === 'wechat' ? 'wechat-ilink' : platform;
293
+ const messenger = registry.getMessenger(messengerName);
294
+ if (!messenger) {
295
+ console.error(`No messenger found for platform: ${platform}`);
296
+ return;
297
+ }
298
+ // Prefix uses the session's agent at reply time (re-read after routing so
299
+ // a /agent-style switch in this turn is reflected). Lazy so we only hit
300
+ // the session store when we have a result to send.
301
+ const maybePrefix = async (text) => {
302
+ const s = await sessionManager.getExistingSession(platform, ctx.channelId, message.threadId);
303
+ const replyAgent = s?.agent || defaultAgent;
304
+ if (replyAgent && replyAgent !== defaultAgent) {
305
+ return `[${replyAgent}]\n\n${text}`;
306
+ }
307
+ return text;
308
+ };
309
+ const stopTyping = async () => {
310
+ if (messenger.sendTyping) {
311
+ try {
312
+ await messenger.sendTyping(message.threadId, false);
313
+ }
314
+ catch {
315
+ // Ignore typing errors
316
+ }
317
+ }
318
+ };
319
+ // Build route context with trace
320
+ const routeCtx = {
321
+ threadId: message.threadId,
322
+ channelId: ctx.channelId,
323
+ platform,
324
+ defaultAgent,
325
+ traceId,
326
+ logger,
327
+ userId: message.userId,
328
+ };
329
+ // Thinking placeholder — sent if the adapter supports it, dismissed (when
330
+ // the adapter knows how) just before the real response goes out. Skip for
331
+ // y/n-style approval replies which already get a same-thread effect from
332
+ // the resolved approval card; sending "šŸ¤” ę€č€ƒäø­ā€¦" there would just add
333
+ // noise. We approximate that filter by skipping placeholders for messages
334
+ // that look like single-token approval words.
335
+ let dismissThinking;
336
+ const looksLikeApproval = /^\s*[yn]\s*$/i.test(message.text) ||
337
+ /^\s*(批准|ę‹’ē»|åŒę„|äøåŒę„|é€ščæ‡|åÆä»„|äøåÆä»„|äøč”Œ|āœ…|āŒ)\s*$/.test(message.text);
338
+ try {
339
+ if (messenger.sendTyping) {
340
+ messenger.sendTyping(message.threadId, true).catch(() => { });
341
+ }
342
+ const parsed = parseMessage(message.text);
343
+ logger.debug({ event: 'router.parse', parsed: parsed.type });
344
+ // Only show "šŸ¤” ę€č€ƒäø­ā€¦" for messages that will actually go through the
345
+ // agent — built-in/system commands (/help /status /audit /router etc.)
346
+ // respond instantly so a placeholder would race the real reply.
347
+ const willInvokeAgent = (parsed.type === 'default' || parsed.type === 'agent' || parsed.type === 'agentCommand') &&
348
+ !looksLikeApproval;
349
+ // Resolve which agent will actually run, so we know whether to allocate
350
+ // a resumable claude-code session id. For an explicit /agent switch we
351
+ // can read parsed.agent directly; otherwise the active agent comes from
352
+ // the existing sticky session (or default agent if none yet).
353
+ let agentForRun;
354
+ let claudeRunWillResume = false;
355
+ if (willInvokeAgent) {
356
+ const stickySession = await sessionManager.getExistingSession(platform, ctx.channelId, message.threadId);
357
+ if (parsed.type === 'agent') {
358
+ agentForRun = parsed.agent;
359
+ }
360
+ else {
361
+ agentForRun = stickySession?.agent || defaultAgent;
362
+ }
363
+ if (agentForRun === 'claude-code') {
364
+ // Reuse the same UUID across every claude turn in this im-hub-pro
365
+ // session — that's what keeps the displayed id stable AND what
366
+ // gives the user a single `claude --resume <uuid>` they can run
367
+ // any time during the conversation.
368
+ let claudeId = stickySession?.claudeSessionId;
369
+ if (!claudeId) {
370
+ claudeId = randomUUID();
371
+ // Make sure the session row exists, then persist the id on it.
372
+ await sessionManager.getOrCreateSession(platform, ctx.channelId, message.threadId, agentForRun);
373
+ await sessionManager.setClaudeSessionId(platform, ctx.channelId, message.threadId, claudeId);
374
+ }
375
+ routeCtx.agentSessionId = claudeId;
376
+ // First call uses --session-id (creates); subsequent uses --resume
377
+ // (continues). Track via claudeSessionPrimed on the session.
378
+ claudeRunWillResume = !!stickySession?.claudeSessionPrimed;
379
+ routeCtx.agentSessionResume = claudeRunWillResume;
380
+ }
381
+ else if (agentForRun === 'opencode') {
382
+ // opencode generates its own session id (`ses_…`) on first run; we
383
+ // capture it from the JSON event stream rather than pre-allocating.
384
+ // If we already have one for this thread, hand it back so opencode
385
+ // resumes from its own DB and we skip stitching messages into the
386
+ // prompt (router clears history when agentSessionResume is true).
387
+ const ocId = stickySession?.opencodeSessionId;
388
+ if (ocId) {
389
+ routeCtx.agentSessionId = ocId;
390
+ routeCtx.agentSessionResume = true;
391
+ }
392
+ // Make sure the session row exists so the subsequent
393
+ // setOpencodeSessionId callback (fired from the adapter) has
394
+ // somewhere to write to.
395
+ await sessionManager.getOrCreateSession(platform, ctx.channelId, message.threadId, agentForRun);
396
+ }
397
+ else if (agentForRun === 'codex') {
398
+ // codex generates its own thread id (UUID) on first run; we capture
399
+ // it from `thread.started` in the JSON stream. If we already have
400
+ // one, hand it back so codex spawns `exec resume <id>` and continues
401
+ // from ~/.codex/sessions; router clears history under
402
+ // agentSessionResume so we don't double-feed prior turns.
403
+ const cxId = stickySession?.codexSessionId;
404
+ if (cxId) {
405
+ routeCtx.agentSessionId = cxId;
406
+ routeCtx.agentSessionResume = true;
407
+ }
408
+ await sessionManager.getOrCreateSession(platform, ctx.channelId, message.threadId, agentForRun);
409
+ }
410
+ }
411
+ if (willInvokeAgent && messenger.sendThinking) {
412
+ try {
413
+ dismissThinking = await messenger.sendThinking(message.threadId, 'šŸ¤” ę€č€ƒäø­ā€¦');
414
+ }
415
+ catch (err) {
416
+ logger.debug({ err: String(err) }, 'sendThinking failed');
417
+ }
418
+ }
419
+ // Mark primed BEFORE invoking claude. claude writes the session jsonl
420
+ // as soon as the run starts, so even if the run later errors we still
421
+ // need to use --resume on the next turn (or it'll error with "session
422
+ // already exists"). The flag is best-effort: if the spawn itself fails
423
+ // (claude binary missing) the user can /new to reset.
424
+ if (agentForRun === 'claude-code' && !claudeRunWillResume) {
425
+ try {
426
+ await sessionManager.markClaudeSessionPrimed(platform, ctx.channelId, message.threadId);
427
+ }
428
+ catch (err) {
429
+ logger.debug({ err: String(err) }, 'markClaudeSessionPrimed failed');
430
+ }
431
+ }
432
+ const result = await routeMessage(parsed, routeCtx);
433
+ const dismiss = async () => {
434
+ if (dismissThinking) {
435
+ try {
436
+ await dismissThinking();
437
+ }
438
+ catch { /* ignore */ }
439
+ dismissThinking = undefined;
440
+ }
441
+ };
442
+ // Handle response (string or async generator)
443
+ if (typeof result === 'string') {
444
+ await stopTyping();
445
+ await dismiss();
446
+ await messenger.sendMessage(message.threadId, await maybePrefix(result));
447
+ logger.info({ event: 'message.sent', responseLen: result.length });
448
+ }
449
+ else {
450
+ // Stream response chunks
451
+ let fullResponse = '';
452
+ for await (const chunk of result) {
453
+ fullResponse += chunk;
454
+ }
455
+ await stopTyping();
456
+ await dismiss();
457
+ if (fullResponse) {
458
+ await messenger.sendMessage(message.threadId, await maybePrefix(fullResponse));
459
+ logger.info({ event: 'message.sent', responseLen: fullResponse.length });
460
+ }
461
+ else {
462
+ logger.warn({ event: 'message.empty_response' });
463
+ }
464
+ }
465
+ }
466
+ catch (error) {
467
+ const errMsg = error instanceof Error ? error.message : String(error);
468
+ logger.error({ event: 'message.error', error: errMsg });
469
+ await stopTyping();
470
+ if (dismissThinking) {
471
+ try {
472
+ await dismissThinking();
473
+ }
474
+ catch { /* ignore */ }
475
+ }
476
+ try {
477
+ await messenger.sendMessage(message.threadId, 'āŒ An error occurred processing your message.');
478
+ }
479
+ catch {
480
+ // Ignore
481
+ }
482
+ }
483
+ }
484
+ program
485
+ .command('config [component]')
486
+ .description('Configure a messenger or agent')
487
+ .action(async (component) => {
488
+ if (!component) {
489
+ console.log('Available components to configure:');
490
+ console.log('\nMessengers:');
491
+ console.log(' wechat - WeChat adapter');
492
+ console.log(' telegram - Telegram adapter');
493
+ console.log(' feishu - Feishu/Lark adapter');
494
+ console.log(' discord - Discord adapter');
495
+ console.log('\nAgents:');
496
+ console.log(' claude - Claude Code agent');
497
+ console.log(' codex - OpenAI Codex CLI agent');
498
+ console.log(' opencode - OpenCode CLI agent');
499
+ console.log(' copilot - GitHub Copilot CLI agent');
500
+ console.log('\nRemote Agents:');
501
+ console.log(' agent - Add a remote ACP agent');
502
+ console.log('\nUsage: im-hub-pro config <component>');
503
+ return;
504
+ }
505
+ const config = await loadConfig();
506
+ switch (component) {
507
+ case 'wechat':
508
+ console.log('šŸ“± Configuring WeChat adapter...');
509
+ console.log('Fetching QR code...\n');
510
+ // Import the iLink adapter for QR login
511
+ const { ILinkWeChatAdapter } = await import('./plugins/messengers/wechat/ilink-adapter.js');
512
+ const adapter = new ILinkWeChatAdapter();
513
+ try {
514
+ // Get QR code URL and token
515
+ const { qrUrl, qrToken } = await adapter.startQRLogin();
516
+ console.log('šŸ“± Scan this QR code with WeChat:\n');
517
+ console.log(qrUrl);
518
+ console.log('\n');
519
+ // Poll for login status
520
+ const credentials = await adapter.waitForQRLogin(qrToken, (status) => {
521
+ console.log(`[${new Date().toLocaleTimeString()}] ${status}`);
522
+ });
523
+ if (credentials) {
524
+ console.log(`\nāœ… Logged in as ${credentials.userId}`);
525
+ console.log(` Bot ID: ${credentials.accountId}`);
526
+ // Add wechat-ilink to config
527
+ if (!config.messengers.includes('wechat-ilink')) {
528
+ config.messengers.push('wechat-ilink');
529
+ }
530
+ }
531
+ else {
532
+ console.log('\nāŒ Login failed or timed out');
533
+ return;
534
+ }
535
+ }
536
+ catch (error) {
537
+ console.error('\nāŒ Failed to configure WeChat:', error);
538
+ return;
539
+ }
540
+ break;
541
+ case 'claude':
542
+ console.log('šŸ¤– Configuring Claude Code agent...');
543
+ // Check if claude CLI is available
544
+ const checkClaude = crossSpawn('claude', ['--version'], { stdio: 'ignore' });
545
+ checkClaude.on('close', (code) => {
546
+ if (code === 0) {
547
+ console.log('āœ… Claude Code CLI found!');
548
+ }
549
+ else {
550
+ console.log('āŒ Claude Code CLI not found.');
551
+ console.log('Install with: npm install -g @anthropic-ai/claude-code');
552
+ }
553
+ });
554
+ if (!config.agents.includes('claude-code')) {
555
+ config.agents.push('claude-code');
556
+ }
557
+ config.defaultAgent = 'claude-code';
558
+ break;
559
+ case 'codex':
560
+ console.log('šŸ¤– Configuring Codex agent...');
561
+ const checkCodex = crossSpawn('codex', ['--version'], { stdio: 'ignore' });
562
+ checkCodex.on('close', (code) => {
563
+ if (code === 0) {
564
+ console.log('āœ… Codex CLI found!');
565
+ }
566
+ else {
567
+ console.log('āŒ Codex CLI not found.');
568
+ console.log('Install with: npm install -g @openai/codex');
569
+ }
570
+ });
571
+ if (!config.agents.includes('codex')) {
572
+ config.agents.push('codex');
573
+ }
574
+ config.defaultAgent = 'codex';
575
+ break;
576
+ case 'opencode':
577
+ console.log('šŸ¤– Configuring OpenCode agent...');
578
+ const checkOpenCode = crossSpawn('opencode', ['--version'], { stdio: 'ignore' });
579
+ checkOpenCode.on('error', () => {
580
+ console.log('āŒ OpenCode CLI not found.');
581
+ console.log('Install with: npm i -g opencode-ai');
582
+ });
583
+ checkOpenCode.on('close', (code) => {
584
+ if (code === 0) {
585
+ console.log('āœ… OpenCode CLI found!');
586
+ }
587
+ });
588
+ if (!config.agents.includes('opencode')) {
589
+ config.agents.push('opencode');
590
+ }
591
+ config.defaultAgent = 'opencode';
592
+ break;
593
+ case 'telegram':
594
+ console.log('šŸ“± Configuring Telegram adapter...');
595
+ console.log('To get a bot token:');
596
+ console.log('1. Open Telegram and search for @BotFather');
597
+ console.log('2. Send /newbot and follow instructions');
598
+ console.log('3. Copy the bot token\n');
599
+ const { createInterface } = await import('readline');
600
+ const rl = createInterface({
601
+ input: process.stdin,
602
+ output: process.stdout,
603
+ });
604
+ const token = await new Promise((resolve) => {
605
+ rl.question('Enter your bot token: ', (answer) => {
606
+ resolve(answer.trim());
607
+ });
608
+ });
609
+ if (!token) {
610
+ console.log('āŒ Bot token is required');
611
+ return;
612
+ }
613
+ const channelId = await new Promise((resolve) => {
614
+ rl.question('Enter channel ID (optional, press Enter for default): ', (answer) => {
615
+ resolve(answer.trim() || 'default');
616
+ });
617
+ });
618
+ rl.close();
619
+ config.telegram = { botToken: token, channelId };
620
+ if (!config.messengers.includes('telegram')) {
621
+ config.messengers.push('telegram');
622
+ }
623
+ console.log('āœ… Telegram bot token saved');
624
+ console.log(` Channel ID: ${channelId}`);
625
+ break;
626
+ case 'feishu':
627
+ console.log('šŸ“± Configuring Feishu adapter (WebSocket long polling mode)...');
628
+ console.log('To create a Feishu bot:');
629
+ console.log('1. Go to https://open.feishu.cn/app');
630
+ console.log('2. Create a custom bot app');
631
+ console.log('3. Enable Bot capability');
632
+ console.log('4. Configure event subscriptions (Subscribe to "im.message.receive_v1" event)');
633
+ console.log('5. Go to Permissions management and enable: im:message, im:message.p2p_msg:readonly, im:message:send_as_bot');
634
+ console.log('6. Create a version and publish it');
635
+ console.log('7. Copy App ID and App Secret\n');
636
+ const { createInterface: createRl } = await import('readline');
637
+ const feishuRl = createRl({
638
+ input: process.stdin,
639
+ output: process.stdout,
640
+ });
641
+ const appId = await new Promise((resolve) => {
642
+ feishuRl.question('Enter App ID: ', (answer) => {
643
+ resolve(answer.trim());
644
+ });
645
+ });
646
+ const appSecret = await new Promise((resolve) => {
647
+ feishuRl.question('Enter App Secret: ', (answer) => {
648
+ resolve(answer.trim());
649
+ });
650
+ });
651
+ feishuRl.close();
652
+ if (!appId || !appSecret) {
653
+ console.log('āŒ App ID and App Secret are required');
654
+ return;
655
+ }
656
+ config.feishu = {
657
+ appId,
658
+ appSecret
659
+ };
660
+ if (!config.messengers.includes('feishu')) {
661
+ config.messengers.push('feishu');
662
+ }
663
+ console.log('āœ… Feishu bot credentials saved');
664
+ console.log(`\nāœ… Using WebSocket long polling mode - no webhook configuration needed!`);
665
+ console.log(` The bot will automatically connect to Feishu servers.`);
666
+ break;
667
+ case 'discord':
668
+ console.log('šŸ“± Configuring Discord adapter...');
669
+ console.log('To create a Discord bot:');
670
+ console.log('1. Go to https://discord.com/developers/applications');
671
+ console.log('2. Click "New Application" and give it a name');
672
+ console.log('3. Go to "Bot" tab and click "Add Bot"');
673
+ console.log('4. IMPORTANT: Enable "MESSAGE CONTENT INTENT" under Privileged Gateway Intents');
674
+ console.log('5. Click "Reset Token" to get your bot token');
675
+ console.log('6. Use OAuth2 URL Generator to invite the bot to your server\n');
676
+ const { createInterface: createDiscordRl } = await import('readline');
677
+ const discordRl = createDiscordRl({
678
+ input: process.stdin,
679
+ output: process.stdout,
680
+ });
681
+ const discordToken = await new Promise((resolve) => {
682
+ discordRl.question('Enter your bot token: ', (answer) => {
683
+ resolve(answer.trim());
684
+ });
685
+ });
686
+ if (!discordToken) {
687
+ console.log('āŒ Bot token is required');
688
+ discordRl.close();
689
+ return;
690
+ }
691
+ const discordChannelId = await new Promise((resolve) => {
692
+ discordRl.question('Enter channel ID (optional, press Enter for default): ', (answer) => {
693
+ resolve(answer.trim() || 'default');
694
+ });
695
+ });
696
+ const allowedGuilds = await new Promise((resolve) => {
697
+ discordRl.question('Allowed guild IDs (comma-separated, optional): ', (answer) => {
698
+ resolve(answer.trim());
699
+ });
700
+ });
701
+ const allowedChannels = await new Promise((resolve) => {
702
+ discordRl.question('Allowed channel IDs (comma-separated, optional): ', (answer) => {
703
+ resolve(answer.trim());
704
+ });
705
+ });
706
+ discordRl.close();
707
+ config.discord = {
708
+ botToken: discordToken,
709
+ channelId: discordChannelId,
710
+ allowedGuilds: allowedGuilds ? allowedGuilds.split(',').map(s => s.trim()).filter(Boolean) : undefined,
711
+ allowedChannels: allowedChannels ? allowedChannels.split(',').map(s => s.trim()).filter(Boolean) : undefined,
712
+ };
713
+ if (!config.messengers.includes('discord')) {
714
+ config.messengers.push('discord');
715
+ }
716
+ console.log('āœ… Discord bot token saved');
717
+ console.log(` Channel ID: ${discordChannelId}`);
718
+ if (config.discord.allowedGuilds?.length) {
719
+ console.log(` Allowed guilds: ${config.discord.allowedGuilds.join(', ')}`);
720
+ }
721
+ if (config.discord.allowedChannels?.length) {
722
+ console.log(` Allowed channels: ${config.discord.allowedChannels.join(', ')}`);
723
+ }
724
+ break;
725
+ case 'opencode':
726
+ console.log('šŸ¤– Configuring OpenCode agent...');
727
+ // Check if opencode CLI is available
728
+ const openCodeAvailable = await new Promise((resolve) => {
729
+ const proc = crossSpawn('opencode', ['--version'], { stdio: 'ignore' });
730
+ proc.on('error', () => resolve(false));
731
+ proc.on('close', (code) => resolve(code === 0));
732
+ });
733
+ if (openCodeAvailable) {
734
+ console.log('āœ… OpenCode CLI found!');
735
+ console.log('\nTo authenticate, run: opencode auth login');
736
+ }
737
+ else {
738
+ console.log('āŒ OpenCode CLI not found.');
739
+ console.log('Install with: npm i -g opencode-ai@latest');
740
+ console.log('Or visit: https://github.com/anomalyco/opencode');
741
+ }
742
+ if (!config.agents.includes('opencode')) {
743
+ config.agents.push('opencode');
744
+ }
745
+ config.defaultAgent = 'opencode';
746
+ break;
747
+ case 'copilot':
748
+ console.log('šŸ¤– Configuring GitHub Copilot CLI agent...');
749
+ // Check if copilot CLI is available (multiple installation methods)
750
+ const { copilotAdapter } = await import('./plugins/agents/copilot/index.js');
751
+ const copilotAvailable = await copilotAdapter.isAvailable();
752
+ if (copilotAvailable) {
753
+ console.log('āœ… GitHub Copilot CLI found!');
754
+ }
755
+ else {
756
+ console.log('āŒ GitHub Copilot CLI not found.');
757
+ console.log('\nå®‰č£…ę–¹å¼ (选择其一):');
758
+ console.log(' npm i -g @github/copilot');
759
+ console.log(' gh extension install github/gh-copilot');
760
+ if (isMac) {
761
+ console.log(' brew install copilot-cli');
762
+ }
763
+ if (isWindows) {
764
+ console.log(' winget install GitHub.Copilot');
765
+ }
766
+ console.log(' ęˆ–å®‰č£… VS Code Copilot Chat 扩展');
767
+ console.log('\nčÆ¦ęƒ…: https://github.com/features/copilot/cli');
768
+ }
769
+ if (!config.agents.includes('copilot')) {
770
+ config.agents.push('copilot');
771
+ }
772
+ config.defaultAgent = 'copilot';
773
+ break;
774
+ case 'agent':
775
+ console.log('šŸ”Œ Configuring remote ACP agent...');
776
+ console.log('This adds a remote agent that speaks the Agent Communication Protocol.');
777
+ console.log('ACP is an open standard (https://agentcommunicationprotocol.dev)\n');
778
+ const { createInterface: createAgentRl } = await import('readline');
779
+ const agentRl = createAgentRl({ input: process.stdin, output: process.stdout });
780
+ const agentName = await new Promise((resolve) => {
781
+ agentRl.question('Agent name (e.g. openclaw-dev): ', (answer) => resolve(answer.trim()));
782
+ });
783
+ if (!agentName) {
784
+ console.log('āŒ Name is required');
785
+ agentRl.close();
786
+ return;
787
+ }
788
+ const agentAlias = await new Promise((resolve) => {
789
+ agentRl.question('Aliases, comma-separated (optional): ', (answer) => resolve(answer.trim()));
790
+ });
791
+ const endpoint = await new Promise((resolve) => {
792
+ agentRl.question('ACP endpoint URL (e.g. http://localhost:8080): ', (answer) => resolve(answer.trim()));
793
+ });
794
+ if (!endpoint) {
795
+ console.log('āŒ Endpoint is required');
796
+ agentRl.close();
797
+ return;
798
+ }
799
+ console.log('\nAuthentication type:');
800
+ console.log(' 1. none');
801
+ console.log(' 2. apikey');
802
+ console.log(' 3. bearer');
803
+ const authTypeInput = await new Promise((resolve) => {
804
+ agentRl.question('Choose (1-3, default: none): ', (answer) => resolve(answer.trim() || '1'));
805
+ });
806
+ const authTypeMap = { '1': 'none', '2': 'apikey', '3': 'bearer' };
807
+ const authType = authTypeMap[authTypeInput] || 'none';
808
+ let auth;
809
+ if (authType !== 'none') {
810
+ const token = await new Promise((resolve) => {
811
+ agentRl.question('Auth token: ', (answer) => resolve(answer.trim()));
812
+ });
813
+ if (!token) {
814
+ console.log('āŒ Token is required when auth is enabled');
815
+ agentRl.close();
816
+ return;
817
+ }
818
+ auth = { type: authType, token };
819
+ }
820
+ agentRl.close();
821
+ // Validate connection
822
+ console.log('\nšŸ” Testing connection...');
823
+ const { ACPClient } = await import('./plugins/agents/acp/acp-client.js');
824
+ const testClient = new ACPClient({ name: agentName, endpoint, auth: auth });
825
+ try {
826
+ const manifest = await testClient.fetchManifest();
827
+ console.log(`āœ… Connected! Agent: ${manifest.name}`);
828
+ if (manifest.description)
829
+ console.log(` ${manifest.description}`);
830
+ }
831
+ catch (e) {
832
+ console.log(`āš ļø Connection failed: ${e.message}`);
833
+ console.log(' Agent will be saved but may not work until endpoint is available.');
834
+ }
835
+ // Save
836
+ if (!config.acpAgents)
837
+ config.acpAgents = [];
838
+ const existing = config.acpAgents.findIndex(a => a.name === agentName);
839
+ const agentConfig = {
840
+ name: agentName,
841
+ aliases: agentAlias?.split(',').map(s => s.trim()).filter(Boolean) || [],
842
+ endpoint,
843
+ auth,
844
+ enabled: true
845
+ };
846
+ if (existing >= 0) {
847
+ config.acpAgents[existing] = agentConfig;
848
+ }
849
+ else {
850
+ config.acpAgents.push(agentConfig);
851
+ }
852
+ break;
853
+ default:
854
+ console.log(`Unknown component: ${component}`);
855
+ console.log('Run "im-hub-pro config" to see available components.');
856
+ return;
857
+ }
858
+ await saveConfig(config);
859
+ console.log(`\nāœ… Configuration saved to ${CONFIG_FILE}`);
860
+ });
861
+ program
862
+ .command('agents')
863
+ .description('List available agents')
864
+ .action(async () => {
865
+ await registry.loadBuiltInPlugins();
866
+ const config = await loadConfig();
867
+ if (config.acpAgents?.length) {
868
+ await registry.loadACPAgents(config.acpAgents);
869
+ }
870
+ const agents = registry.listAgents();
871
+ if (agents.length === 0) {
872
+ console.log('No agents registered yet.');
873
+ console.log('Run "im-hub-pro config claude" to configure Claude Code.');
874
+ console.log('Run "im-hub-pro config agent" to add a remote ACP agent.');
875
+ return;
876
+ }
877
+ console.log('šŸ¤– Checking agents...\n');
878
+ // Check all agents in parallel to avoid slow sequential timeouts
879
+ const results = await Promise.allSettled(agents.map(async (name) => {
880
+ const agent = registry.getAgent(name);
881
+ const available = await agent?.isAvailable().catch(() => false);
882
+ // Check if this is an ACP agent with extra info
883
+ let info = '';
884
+ try {
885
+ const { ACPAdapter } = await import('./plugins/agents/acp/acp-adapter.js');
886
+ if (agent instanceof ACPAdapter) {
887
+ const manifest = await agent.getManifest().catch(() => undefined);
888
+ if (manifest) {
889
+ info = ` — ${manifest.description || 'Remote ACP agent'}`;
890
+ }
891
+ }
892
+ }
893
+ catch { /* not an ACP agent */ }
894
+ return { name, available, aliases: agent?.aliases || [], info };
895
+ }));
896
+ for (const result of results) {
897
+ if (result.status === 'fulfilled') {
898
+ const { name, available, aliases, info } = result.value;
899
+ const aliasStr = aliases.length ? ` (${aliases.join(', ')})` : '';
900
+ console.log(` ${available ? 'āœ…' : 'āŒ'} ${name}${aliasStr}${info}`);
901
+ }
902
+ }
903
+ });
904
+ program
905
+ .command('messengers')
906
+ .description('List available messengers')
907
+ .action(async () => {
908
+ await registry.loadBuiltInPlugins();
909
+ const messengers = registry.listMessengers();
910
+ if (messengers.length === 0) {
911
+ console.log('No messengers registered yet.');
912
+ console.log('Run "im-hub-pro config wechat" to configure WeChat.');
913
+ return;
914
+ }
915
+ console.log('šŸ“± Available Messengers:\n');
916
+ for (const name of messengers) {
917
+ console.log(` ${name}`);
918
+ }
919
+ });
920
+ program.parse();
921
+ //# sourceMappingURL=cli.js.map