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
@@ -0,0 +1,59 @@
1
+ // Exponential backoff with jitter — used by IM adapter reconnect loops.
2
+ //
3
+ // Why: when an IM platform throws (auth revoked, network blip, server
4
+ // outage) the adapter retries. With fixed delays we have three problems:
5
+ //
6
+ // 1. Auth revoked → infinite fast hammering of the IM API at the same
7
+ // cadence; with backoff the cadence relaxes to capMs.
8
+ // 2. Multi-instance fleet recovering from a network event reconnects
9
+ // in lock-step at the same fixed delay — thundering herd hits the
10
+ // IM platform's load balancer; jitter spreads the storm.
11
+ // 3. Flaky network → CPU spent in tight reconnect loop; longer waits
12
+ // between attempts dampen this.
13
+ //
14
+ // Used by:
15
+ // - telegram-adapter runPollingLoop (was fixed 2s/5s delays)
16
+ // - wechat ilink-adapter polling loop (had exp backoff but no jitter)
17
+ const DEFAULT_BASE_MS = 1_000;
18
+ const DEFAULT_CAP_MS = 60_000;
19
+ const DEFAULT_JITTER = 0.5;
20
+ export class Backoff {
21
+ attempt = 0;
22
+ baseMs;
23
+ capMs;
24
+ jitter;
25
+ random;
26
+ constructor(opts = {}) {
27
+ this.baseMs = Math.max(0, opts.baseMs ?? DEFAULT_BASE_MS);
28
+ this.capMs = Math.max(this.baseMs, opts.capMs ?? DEFAULT_CAP_MS);
29
+ this.jitter = Math.max(0, Math.min(1, opts.jitter ?? DEFAULT_JITTER));
30
+ this.random = opts.random ?? Math.random;
31
+ }
32
+ /**
33
+ * Compute the next delay in ms and increment the attempt counter.
34
+ *
35
+ * - First call: ~baseMs (jittered)
36
+ * - Each call doubles the unjittered exponent until it hits capMs
37
+ * - Then every subsequent call returns ~capMs (jittered)
38
+ *
39
+ * Returns a non-negative integer.
40
+ */
41
+ nextDelayMs() {
42
+ const exp = Math.min(this.capMs, this.baseMs * Math.pow(2, this.attempt));
43
+ this.attempt += 1;
44
+ if (this.jitter === 0)
45
+ return Math.floor(exp);
46
+ // Multiplicative jitter: factor ∈ [1 - jitter, 1 + jitter]
47
+ const factor = 1 + (this.random() * 2 - 1) * this.jitter;
48
+ return Math.max(0, Math.floor(exp * factor));
49
+ }
50
+ /** Reset attempt counter — call after a successful operation. */
51
+ reset() {
52
+ this.attempt = 0;
53
+ }
54
+ /** Diagnostic: current attempt count without bumping. */
55
+ currentAttempt() {
56
+ return this.attempt;
57
+ }
58
+ }
59
+ //# sourceMappingURL=backoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backoff.js","sourceRoot":"","sources":["../../src/utils/backoff.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,sEAAsE;AACtE,yEAAyE;AACzE,EAAE;AACF,wEAAwE;AACxE,2DAA2D;AAC3D,uEAAuE;AACvE,uEAAuE;AACvE,8DAA8D;AAC9D,uEAAuE;AACvE,qCAAqC;AACrC,EAAE;AACF,WAAW;AACX,+DAA+D;AAC/D,wEAAwE;AAexE,MAAM,eAAe,GAAG,KAAK,CAAA;AAC7B,MAAM,cAAc,GAAG,MAAM,CAAA;AAC7B,MAAM,cAAc,GAAG,GAAG,CAAA;AAE1B,MAAM,OAAO,OAAO;IACV,OAAO,GAAG,CAAC,CAAA;IACF,MAAM,CAAQ;IACd,KAAK,CAAQ;IACb,MAAM,CAAQ;IACd,MAAM,CAAc;IAErC,YAAY,OAAuB,EAAE;QACnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC,CAAA;QACzD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,IAAI,cAAc,CAAC,CAAA;QAChE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,CAAA;QACrE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAA;IAC1C,CAAC;IAED;;;;;;;;OAQG;IACH,WAAW;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;QACzE,IAAI,CAAC,OAAO,IAAI,CAAC,CAAA;QACjB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC7C,2DAA2D;QAC3D,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAA;QACxD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAA;IAC9C,CAAC;IAED,iEAAiE;IACjE,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,CAAC,CAAA;IAClB,CAAC;IAED,yDAAyD;IACzD,cAAc;QACZ,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ import { SpawnOptions, ChildProcess } from 'child_process';
2
+ export declare const isWindows: boolean;
3
+ export declare const isMac: boolean;
4
+ export declare const isLinux: boolean;
5
+ /**
6
+ * Cross-platform spawn wrapper that automatically handles Windows compatibility.
7
+ * On Windows, it sets shell: true to enable command execution.
8
+ *
9
+ * Note: When using stdio: ['ignore', 'pipe', 'pipe'], stdout and stderr are guaranteed to be non-null.
10
+ */
11
+ export declare function crossSpawn(command: string, args?: string[], options?: SpawnOptions): ChildProcess;
12
+ /**
13
+ * Get Copilot CLI binary path based on the current platform.
14
+ * Copilot CLI is installed by VS Code extension in different locations per OS.
15
+ */
16
+ export declare function getCopilotBinPath(): string;
17
+ /**
18
+ * Check if a command exists in PATH.
19
+ * Uses 'where' on Windows, 'which' on Unix.
20
+ */
21
+ export declare function commandExists(command: string): Promise<boolean>;
22
+ /**
23
+ * Get the correct newline character for the current platform.
24
+ */
25
+ export declare const EOL: string;
26
+ //# sourceMappingURL=cross-platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-platform.d.ts","sourceRoot":"","sources":["../../src/utils/cross-platform.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAIjE,eAAO,MAAM,SAAS,SAAyB,CAAA;AAC/C,eAAO,MAAM,KAAK,SAA0B,CAAA;AAC5C,eAAO,MAAM,OAAO,SAAyB,CAAA;AAE7C;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAM,EAAO,EACnB,OAAO,GAAE,YAAiB,GACzB,YAAY,CAQd;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAuB1C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED;;GAEG;AACH,eAAO,MAAM,GAAG,QAA4B,CAAA"}
@@ -0,0 +1,58 @@
1
+ // Cross-platform utilities for Windows compatibility
2
+ import { spawn } from 'child_process';
3
+ import { platform, homedir } from 'os';
4
+ import { join } from 'path';
5
+ export const isWindows = platform() === 'win32';
6
+ export const isMac = platform() === 'darwin';
7
+ export const isLinux = platform() === 'linux';
8
+ /**
9
+ * Cross-platform spawn wrapper that automatically handles Windows compatibility.
10
+ * On Windows, it sets shell: true to enable command execution.
11
+ *
12
+ * Note: When using stdio: ['ignore', 'pipe', 'pipe'], stdout and stderr are guaranteed to be non-null.
13
+ */
14
+ export function crossSpawn(command, args = [], options = {}) {
15
+ const spawnOptions = {
16
+ ...options,
17
+ // On Windows, we need shell: true for commands like 'claude', 'opencode', etc.
18
+ // to be found in PATH and executed properly.
19
+ shell: isWindows ? (options.shell ?? true) : options.shell,
20
+ };
21
+ return spawn(command, args, spawnOptions);
22
+ }
23
+ /**
24
+ * Get Copilot CLI binary path based on the current platform.
25
+ * Copilot CLI is installed by VS Code extension in different locations per OS.
26
+ */
27
+ export function getCopilotBinPath() {
28
+ if (isWindows) {
29
+ // Windows: VS Code extensions are in %USERPROFILE%\.vscode\extensions
30
+ // The copilot CLI should be in the global storage
31
+ return join(homedir(), '.vscode', 'extensions', 'github.copilot-chat-*/copilotCli/copilot.exe');
32
+ }
33
+ else if (isMac) {
34
+ // macOS
35
+ return join(homedir(), 'Library/Application Support/Code/User/globalStorage/github.copilot-chat/copilotCli/copilot');
36
+ }
37
+ else {
38
+ // Linux
39
+ return join(homedir(), '.vscode/extensions/github.copilot-chat/copilotCli/copilot');
40
+ }
41
+ }
42
+ /**
43
+ * Check if a command exists in PATH.
44
+ * Uses 'where' on Windows, 'which' on Unix.
45
+ */
46
+ export function commandExists(command) {
47
+ return new Promise((resolve) => {
48
+ const checkCmd = isWindows ? 'where' : 'which';
49
+ const proc = crossSpawn(checkCmd, [command], { stdio: 'ignore' });
50
+ proc.on('close', (code) => resolve(code === 0));
51
+ proc.on('error', () => resolve(false));
52
+ });
53
+ }
54
+ /**
55
+ * Get the correct newline character for the current platform.
56
+ */
57
+ export const EOL = isWindows ? '\r\n' : '\n';
58
+ //# sourceMappingURL=cross-platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-platform.js","sourceRoot":"","sources":["../../src/utils/cross-platform.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAErD,OAAO,EAAE,KAAK,EAA8B,MAAM,eAAe,CAAA;AACjE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,MAAM,CAAC,MAAM,SAAS,GAAG,QAAQ,EAAE,KAAK,OAAO,CAAA;AAC/C,MAAM,CAAC,MAAM,KAAK,GAAG,QAAQ,EAAE,KAAK,QAAQ,CAAA;AAC5C,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,EAAE,KAAK,OAAO,CAAA;AAE7C;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,OAAiB,EAAE,EACnB,UAAwB,EAAE;IAE1B,MAAM,YAAY,GAAiB;QACjC,GAAG,OAAO;QACV,+EAA+E;QAC/E,6CAA6C;QAC7C,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK;KAC3D,CAAA;IACD,OAAO,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,SAAS,EAAE,CAAC;QACd,sEAAsE;QACtE,kDAAkD;QAClD,OAAO,IAAI,CACT,OAAO,EAAE,EACT,SAAS,EACT,YAAY,EACZ,8CAA8C,CAC/C,CAAA;IACH,CAAC;SAAM,IAAI,KAAK,EAAE,CAAC;QACjB,QAAQ;QACR,OAAO,IAAI,CACT,OAAO,EAAE,EACT,4FAA4F,CAC7F,CAAA;IACH,CAAC;SAAM,CAAC;QACN,QAAQ;QACR,OAAO,IAAI,CACT,OAAO,EAAE,EACT,2DAA2D,CAC5D,CAAA;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;QAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QACjE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;QAC/C,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA"}
@@ -0,0 +1,14 @@
1
+ export interface SplitOptions {
2
+ /** Maximum characters per chunk */
3
+ maxLength?: number;
4
+ /** Add continuation marker to split messages */
5
+ addContinuationMarker?: boolean;
6
+ /** Continuation marker text */
7
+ continuationMarker?: string;
8
+ }
9
+ /**
10
+ * Split a long message into chunks that fit within messenger limits.
11
+ * Tries to split at natural boundaries (code blocks, paragraphs, lines).
12
+ */
13
+ export declare function splitMessage(text: string, options?: SplitOptions): string[];
14
+ //# sourceMappingURL=message-split.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-split.d.ts","sourceRoot":"","sources":["../../src/utils/message-split.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gDAAgD;IAChD,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,+BAA+B;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAmBD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,YAAiB,GACzB,MAAM,EAAE,CAkDV"}
@@ -0,0 +1,65 @@
1
+ // Shared message splitting utility
2
+ // Used by WeChat, Telegram, and other messengers with character limits
3
+ /**
4
+ * If `idx` falls between a UTF-16 surrogate pair, step back by 1 so the
5
+ * pair stays whole. JavaScript strings are UTF-16; characters in plane 1+
6
+ * (most emoji, e.g. 😀 U+1F600) are encoded as a high-surrogate +
7
+ * low-surrogate pair (2 code units). Slicing through the boundary yields
8
+ * an orphan surrogate that renders as `□` (or worse, breaks Telegram's
9
+ * HTML parser when the orphan happens to be inside a tag value).
10
+ *
11
+ * Returns the safe split point. Idempotent on already-safe boundaries.
12
+ */
13
+ function safeSplitPoint(s, idx) {
14
+ if (idx <= 0 || idx >= s.length)
15
+ return idx;
16
+ const code = s.charCodeAt(idx - 1);
17
+ if (code >= 0xD800 && code <= 0xDBFF)
18
+ return idx - 1;
19
+ return idx;
20
+ }
21
+ /**
22
+ * Split a long message into chunks that fit within messenger limits.
23
+ * Tries to split at natural boundaries (code blocks, paragraphs, lines).
24
+ */
25
+ export function splitMessage(text, options = {}) {
26
+ const { maxLength = 2000, addContinuationMarker = true, continuationMarker = '\n\n[continued...]', } = options;
27
+ if (text.length <= maxLength) {
28
+ return [text];
29
+ }
30
+ const chunks = [];
31
+ let remaining = text;
32
+ while (remaining.length > maxLength) {
33
+ // Try to split at code block boundary first
34
+ let splitPoint = remaining.lastIndexOf('\n```\n', maxLength);
35
+ if (splitPoint < maxLength / 2) {
36
+ // Try paragraph break
37
+ splitPoint = remaining.lastIndexOf('\n\n', maxLength);
38
+ }
39
+ if (splitPoint < maxLength / 2) {
40
+ // Try line break
41
+ splitPoint = remaining.lastIndexOf('\n', maxLength);
42
+ }
43
+ if (splitPoint < maxLength / 2) {
44
+ // Force split at maxLength
45
+ splitPoint = maxLength;
46
+ }
47
+ // M10: surrogate-pair safety. The natural-boundary searches land on
48
+ // ASCII bytes (newline, backtick) so they're already safe; the forced
49
+ // split at maxLength is the only path that could land mid-pair.
50
+ splitPoint = safeSplitPoint(remaining, splitPoint);
51
+ chunks.push(remaining.slice(0, splitPoint).trim());
52
+ remaining = remaining.slice(splitPoint).trim();
53
+ }
54
+ if (remaining) {
55
+ chunks.push(remaining);
56
+ }
57
+ // Add continuation markers
58
+ if (addContinuationMarker && chunks.length > 1) {
59
+ for (let i = 0; i < chunks.length - 1; i++) {
60
+ chunks[i] += continuationMarker;
61
+ }
62
+ }
63
+ return chunks;
64
+ }
65
+ //# sourceMappingURL=message-split.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-split.js","sourceRoot":"","sources":["../../src/utils/message-split.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,uEAAuE;AAWvE;;;;;;;;;GASG;AACH,SAAS,cAAc,CAAC,CAAS,EAAE,GAAW;IAC5C,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,GAAG,CAAA;IAC3C,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAA;IAClC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;QAAE,OAAO,GAAG,GAAG,CAAC,CAAA;IACpD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,UAAwB,EAAE;IAE1B,MAAM,EACJ,SAAS,GAAG,IAAI,EAChB,qBAAqB,GAAG,IAAI,EAC5B,kBAAkB,GAAG,oBAAoB,GAC1C,GAAG,OAAO,CAAA;IAEX,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAA;IACf,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,SAAS,GAAG,IAAI,CAAA;IAEpB,OAAO,SAAS,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACpC,4CAA4C;QAC5C,IAAI,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAC5D,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YAC/B,sBAAsB;YACtB,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QACvD,CAAC;QACD,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YAC/B,iBAAiB;YACjB,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QACrD,CAAC;QACD,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YAC/B,2BAA2B;YAC3B,UAAU,GAAG,SAAS,CAAA;QACxB,CAAC;QACD,oEAAoE;QACpE,sEAAsE;QACtE,gEAAgE;QAChE,UAAU,GAAG,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAElD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAClD,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAA;IAChD,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACxB,CAAC;IAED,2BAA2B;IAC3B,IAAI,qBAAqB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,MAAM,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAA;QACjC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function safeEqual(a: string, b: string): boolean;
2
+ //# sourceMappingURL=safe-equal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-equal.d.ts","sourceRoot":"","sources":["../../src/utils/safe-equal.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKvD"}
@@ -0,0 +1,11 @@
1
+ // Constant-time string compare for auth-token comparison.
2
+ // Returns false when lengths differ, otherwise defers to crypto.timingSafeEqual.
3
+ import { timingSafeEqual } from 'crypto';
4
+ export function safeEqual(a, b) {
5
+ const bufA = Buffer.from(a);
6
+ const bufB = Buffer.from(b);
7
+ if (bufA.length !== bufB.length)
8
+ return false;
9
+ return timingSafeEqual(bufA, bufB);
10
+ }
11
+ //# sourceMappingURL=safe-equal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-equal.js","sourceRoot":"","sources":["../../src/utils/safe-equal.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,iFAAiF;AAEjF,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAExC,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,CAAS;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAC7C,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AACpC,CAAC"}
@@ -0,0 +1,196 @@
1
+ // im-hub-pro web console — shared utilities (theme / i18n / error boundary / api).
2
+ //
3
+ // Loaded as a CLASSIC script in <head> by every page before any page-specific
4
+ // code, so it sits in the same global lexical scope. Wrapped in an IIFE so the
5
+ // only thing that leaks is `window.imhub`.
6
+ //
7
+ // IMPORTANT: this file is served as `/_app.js` by web/server.ts. It does NOT
8
+ // have access to `window.IMHUB_TOKEN` until the inline <script> tag inside
9
+ // each page <head> runs — make sure `imhub.api(...)` is only called after
10
+ // the inline token bootstrap has executed (i.e. from inside DOMContentLoaded
11
+ // or a deferred page script). Reading `window.__lang` follows the same rule.
12
+
13
+ (() => {
14
+ // ============================================================
15
+ // Error boundary
16
+ // ============================================================
17
+ // Sticky red banner at the top of the viewport whenever a script error
18
+ // or unhandled promise rejection escapes the page-level try/catch. The
19
+ // tasks.html SyntaxError that produced a fully blank page (because the
20
+ // script that fills tab labels / button text never ran) was the
21
+ // motivating example — silent JS death must surface visually.
22
+ let errorBar = null
23
+ function showError(msg) {
24
+ if (!errorBar) {
25
+ errorBar = document.createElement('div')
26
+ errorBar.id = 'imhub-error-bar'
27
+ errorBar.setAttribute('role', 'alert')
28
+ errorBar.style.cssText = [
29
+ 'position:fixed', 'top:0', 'left:0', 'right:0', 'z-index:99999',
30
+ 'padding:8px 16px', 'background:#dc3545', 'color:#fff',
31
+ 'font:13px -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif',
32
+ 'box-shadow:0 2px 8px rgba(0,0,0,.25)',
33
+ 'display:flex', 'align-items:center', 'gap:12px',
34
+ ].join(';')
35
+ errorBar.innerHTML =
36
+ '<span style="flex:1;white-space:pre-wrap;word-break:break-word" data-imhub-error-msg></span>'
37
+ + '<button data-imhub-error-close style="background:rgba(255,255,255,.18);'
38
+ + 'color:#fff;border:none;padding:4px 10px;border-radius:3px;cursor:pointer">'
39
+ + '×</button>'
40
+ const init = () => {
41
+ if (!document.body) return setTimeout(init, 30)
42
+ document.body.prepend(errorBar)
43
+ errorBar.querySelector('[data-imhub-error-close]')
44
+ .addEventListener('click', () => { errorBar.remove(); errorBar = null })
45
+ }
46
+ init()
47
+ }
48
+ const slot = errorBar?.querySelector('[data-imhub-error-msg]')
49
+ if (slot) slot.textContent = String(msg).slice(0, 600)
50
+ }
51
+
52
+ function installErrorBoundary() {
53
+ window.addEventListener('error', (e) => {
54
+ const file = (e.filename || '?').split('/').pop()
55
+ showError(`JS error: ${e.message} (${file}:${e.lineno})`)
56
+ })
57
+ window.addEventListener('unhandledrejection', (e) => {
58
+ const r = e.reason
59
+ const msg = r && (r.message || r.toString && r.toString())
60
+ showError(`Unhandled rejection: ${msg ?? '(no message)'}`)
61
+ })
62
+ }
63
+ installErrorBoundary()
64
+
65
+ // ============================================================
66
+ // Theme manager (light / dark / system three-state)
67
+ // ============================================================
68
+ // Three-state toggle persists in localStorage. `system` removes
69
+ // `[data-theme]` and lets `prefers-color-scheme` decide; `light` /
70
+ // `dark` set the attribute explicitly so CSS `:root[data-theme="..."]`
71
+ // selectors win regardless of OS preference.
72
+ //
73
+ // Applied as early as possible (before first paint) so the page doesn't
74
+ // flash the wrong theme on load. This file is loaded synchronously in
75
+ // <head> precisely for that reason.
76
+ const THEME_KEY = 'im-hub-pro-theme'
77
+ const VALID_MODES = ['system', 'light', 'dark']
78
+
79
+ function getThemeMode() {
80
+ const stored = localStorage.getItem(THEME_KEY)
81
+ return VALID_MODES.includes(stored) ? stored : 'system'
82
+ }
83
+
84
+ function applyTheme() {
85
+ const mode = getThemeMode()
86
+ if (mode === 'system') document.documentElement.removeAttribute('data-theme')
87
+ else document.documentElement.setAttribute('data-theme', mode)
88
+ }
89
+
90
+ function setThemeMode(mode) {
91
+ if (!VALID_MODES.includes(mode)) mode = 'system'
92
+ if (mode === 'system') localStorage.removeItem(THEME_KEY)
93
+ else localStorage.setItem(THEME_KEY, mode)
94
+ applyTheme()
95
+ }
96
+
97
+ function cycleThemeMode() {
98
+ const cur = getThemeMode()
99
+ const next = VALID_MODES[(VALID_MODES.indexOf(cur) + 1) % VALID_MODES.length]
100
+ setThemeMode(next)
101
+ return next
102
+ }
103
+
104
+ function bindThemeToggle(el) {
105
+ if (!el) return
106
+ const ICONS = { system: '🖥', light: '☀', dark: '🌙' }
107
+ const LABELS = {
108
+ en: { system: 'System', light: 'Light', dark: 'Dark', tip: 'Click to cycle theme' },
109
+ zh: { system: '跟随系统', light: '浅色', dark: '深色', tip: '点击切换主题' },
110
+ }
111
+ const lang = (window.__lang === 'zh') ? 'zh' : 'en'
112
+ const L = LABELS[lang]
113
+ function refresh() {
114
+ const m = getThemeMode()
115
+ el.innerHTML = `<span style="font-size:14px">${ICONS[m]}</span> <span>${L[m]}</span>`
116
+ el.title = `${L[m]} — ${L.tip}`
117
+ el.setAttribute('data-theme-mode', m)
118
+ }
119
+ el.style.cursor = 'pointer'
120
+ el.addEventListener('click', () => { cycleThemeMode(); refresh() })
121
+ // Refresh when the OS preference flips (relevant only when mode='system').
122
+ if (window.matchMedia) {
123
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener?.('change', refresh)
124
+ }
125
+ refresh()
126
+ }
127
+
128
+ applyTheme()
129
+
130
+ // ============================================================
131
+ // i18n (data-attribute driven)
132
+ // ============================================================
133
+ // Replaces the previous N×getElementById().textContent= boilerplate.
134
+ // Pages mark elements with `data-i18n="key"` (sets textContent) and
135
+ // optional `data-i18n-attr="placeholder:key1;title:key2"` (sets one or
136
+ // more attributes from the same dictionary). Missing keys leave the
137
+ // element's existing text/attribute intact, so a partial dictionary
138
+ // doesn't blank out the UI.
139
+ function applyI18n(T, root = document) {
140
+ if (!T || typeof T !== 'object') return
141
+ root.querySelectorAll('[data-i18n]').forEach((el) => {
142
+ const key = el.getAttribute('data-i18n')
143
+ if (key && T[key] !== undefined) el.textContent = T[key]
144
+ })
145
+ root.querySelectorAll('[data-i18n-attr]').forEach((el) => {
146
+ const spec = el.getAttribute('data-i18n-attr') || ''
147
+ for (const pair of spec.split(';')) {
148
+ const [attr, key] = pair.split(':').map((s) => (s || '').trim())
149
+ if (attr && key && T[key] !== undefined) el.setAttribute(attr, T[key])
150
+ }
151
+ })
152
+ }
153
+
154
+ // ============================================================
155
+ // API helper
156
+ // ============================================================
157
+ // Auto-attaches X-IM-Hub-Token header. Throws on non-2xx with the
158
+ // server-provided `error` field as the message when present. Always
159
+ // returns parsed JSON on success — pages handle data shape themselves.
160
+ async function apiFetch(path, init = {}) {
161
+ const headers = {
162
+ 'X-IM-Hub-Token': window.IMHUB_TOKEN || '',
163
+ ...(init.headers || {}),
164
+ }
165
+ if (init.body && !headers['Content-Type']) {
166
+ headers['Content-Type'] = 'application/json'
167
+ }
168
+ const res = await fetch(path, { ...init, headers })
169
+ if (!res.ok) {
170
+ let msg = `${res.status} ${res.statusText}`
171
+ try { const j = await res.json(); if (j && j.error) msg = j.error } catch { /* ignore */ }
172
+ const err = new Error(msg)
173
+ err.status = res.status
174
+ throw err
175
+ }
176
+ if (res.status === 204) return null
177
+ const ct = res.headers.get('content-type') || ''
178
+ return ct.includes('application/json') ? res.json() : res.text()
179
+ }
180
+
181
+ // ============================================================
182
+ // Expose
183
+ // ============================================================
184
+ window.imhub = Object.freeze({
185
+ showError,
186
+ theme: {
187
+ get: getThemeMode,
188
+ set: setThemeMode,
189
+ cycle: cycleThemeMode,
190
+ bindToggle: bindThemeToggle,
191
+ apply: applyTheme,
192
+ },
193
+ i18n: { apply: applyI18n },
194
+ api: apiFetch,
195
+ })
196
+ })()