agim-cli 1.0.1

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 (453) hide show
  1. package/CHANGELOG.md +1234 -0
  2. package/LICENSE +21 -0
  3. package/README.md +422 -0
  4. package/README.zh-CN.md +414 -0
  5. package/dist/cli-ui/cmd-handlers.d.ts +11 -0
  6. package/dist/cli-ui/cmd-handlers.d.ts.map +1 -0
  7. package/dist/cli-ui/cmd-handlers.js +240 -0
  8. package/dist/cli-ui/cmd-handlers.js.map +1 -0
  9. package/dist/cli-ui/config-wizard.d.ts +3 -0
  10. package/dist/cli-ui/config-wizard.d.ts.map +1 -0
  11. package/dist/cli-ui/config-wizard.js +851 -0
  12. package/dist/cli-ui/config-wizard.js.map +1 -0
  13. package/dist/cli-ui/entry-menu.d.ts +28 -0
  14. package/dist/cli-ui/entry-menu.d.ts.map +1 -0
  15. package/dist/cli-ui/entry-menu.js +50 -0
  16. package/dist/cli-ui/entry-menu.js.map +1 -0
  17. package/dist/cli-ui/env-file.d.ts +35 -0
  18. package/dist/cli-ui/env-file.d.ts.map +1 -0
  19. package/dist/cli-ui/env-file.js +163 -0
  20. package/dist/cli-ui/env-file.js.map +1 -0
  21. package/dist/cli-ui/i18n.d.ts +204 -0
  22. package/dist/cli-ui/i18n.d.ts.map +1 -0
  23. package/dist/cli-ui/i18n.js +455 -0
  24. package/dist/cli-ui/i18n.js.map +1 -0
  25. package/dist/cli-ui/lang-picker.d.ts +10 -0
  26. package/dist/cli-ui/lang-picker.d.ts.map +1 -0
  27. package/dist/cli-ui/lang-picker.js +33 -0
  28. package/dist/cli-ui/lang-picker.js.map +1 -0
  29. package/dist/cli-ui/paths.d.ts +4 -0
  30. package/dist/cli-ui/paths.d.ts.map +1 -0
  31. package/dist/cli-ui/paths.js +11 -0
  32. package/dist/cli-ui/paths.js.map +1 -0
  33. package/dist/cli-ui/prompts.d.ts +65 -0
  34. package/dist/cli-ui/prompts.d.ts.map +1 -0
  35. package/dist/cli-ui/prompts.js +125 -0
  36. package/dist/cli-ui/prompts.js.map +1 -0
  37. package/dist/cli-ui/service.d.ts +41 -0
  38. package/dist/cli-ui/service.d.ts.map +1 -0
  39. package/dist/cli-ui/service.js +241 -0
  40. package/dist/cli-ui/service.js.map +1 -0
  41. package/dist/cli.d.ts +3 -0
  42. package/dist/cli.d.ts.map +1 -0
  43. package/dist/cli.js +1143 -0
  44. package/dist/cli.js.map +1 -0
  45. package/dist/core/acp-server.d.ts +8 -0
  46. package/dist/core/acp-server.d.ts.map +1 -0
  47. package/dist/core/acp-server.js +266 -0
  48. package/dist/core/acp-server.js.map +1 -0
  49. package/dist/core/agent-base.d.ts +94 -0
  50. package/dist/core/agent-base.d.ts.map +1 -0
  51. package/dist/core/agent-base.js +373 -0
  52. package/dist/core/agent-base.js.map +1 -0
  53. package/dist/core/agent-cwd.d.ts +48 -0
  54. package/dist/core/agent-cwd.d.ts.map +1 -0
  55. package/dist/core/agent-cwd.js +181 -0
  56. package/dist/core/agent-cwd.js.map +1 -0
  57. package/dist/core/agent-helper.d.ts +65 -0
  58. package/dist/core/agent-helper.d.ts.map +1 -0
  59. package/dist/core/agent-helper.js +150 -0
  60. package/dist/core/agent-helper.js.map +1 -0
  61. package/dist/core/agim-paths.d.ts +10 -0
  62. package/dist/core/agim-paths.d.ts.map +1 -0
  63. package/dist/core/agim-paths.js +64 -0
  64. package/dist/core/agim-paths.js.map +1 -0
  65. package/dist/core/approval-bus.d.ts +300 -0
  66. package/dist/core/approval-bus.d.ts.map +1 -0
  67. package/dist/core/approval-bus.js +990 -0
  68. package/dist/core/approval-bus.js.map +1 -0
  69. package/dist/core/approval-router.d.ts +101 -0
  70. package/dist/core/approval-router.d.ts.map +1 -0
  71. package/dist/core/approval-router.js +540 -0
  72. package/dist/core/approval-router.js.map +1 -0
  73. package/dist/core/audit-log.d.ts +55 -0
  74. package/dist/core/audit-log.d.ts.map +1 -0
  75. package/dist/core/audit-log.js +203 -0
  76. package/dist/core/audit-log.js.map +1 -0
  77. package/dist/core/bgjob-reader.d.ts +65 -0
  78. package/dist/core/bgjob-reader.d.ts.map +1 -0
  79. package/dist/core/bgjob-reader.js +212 -0
  80. package/dist/core/bgjob-reader.js.map +1 -0
  81. package/dist/core/circuit-breaker.d.ts +37 -0
  82. package/dist/core/circuit-breaker.d.ts.map +1 -0
  83. package/dist/core/circuit-breaker.js +115 -0
  84. package/dist/core/circuit-breaker.js.map +1 -0
  85. package/dist/core/commands/agent.d.ts +4 -0
  86. package/dist/core/commands/agent.d.ts.map +1 -0
  87. package/dist/core/commands/agent.js +40 -0
  88. package/dist/core/commands/agent.js.map +1 -0
  89. package/dist/core/commands/approval.d.ts +3 -0
  90. package/dist/core/commands/approval.d.ts.map +1 -0
  91. package/dist/core/commands/approval.js +85 -0
  92. package/dist/core/commands/approval.js.map +1 -0
  93. package/dist/core/commands/audit.d.ts +3 -0
  94. package/dist/core/commands/audit.d.ts.map +1 -0
  95. package/dist/core/commands/audit.js +84 -0
  96. package/dist/core/commands/audit.js.map +1 -0
  97. package/dist/core/commands/builtin.d.ts +3 -0
  98. package/dist/core/commands/builtin.d.ts.map +1 -0
  99. package/dist/core/commands/builtin.js +304 -0
  100. package/dist/core/commands/builtin.js.map +1 -0
  101. package/dist/core/commands/cron.d.ts +3 -0
  102. package/dist/core/commands/cron.d.ts.map +1 -0
  103. package/dist/core/commands/cron.js +128 -0
  104. package/dist/core/commands/cron.js.map +1 -0
  105. package/dist/core/commands/job.d.ts +3 -0
  106. package/dist/core/commands/job.d.ts.map +1 -0
  107. package/dist/core/commands/job.js +195 -0
  108. package/dist/core/commands/job.js.map +1 -0
  109. package/dist/core/commands/memo.d.ts +3 -0
  110. package/dist/core/commands/memo.d.ts.map +1 -0
  111. package/dist/core/commands/memo.js +151 -0
  112. package/dist/core/commands/memo.js.map +1 -0
  113. package/dist/core/commands/model.d.ts +9 -0
  114. package/dist/core/commands/model.d.ts.map +1 -0
  115. package/dist/core/commands/model.js +183 -0
  116. package/dist/core/commands/model.js.map +1 -0
  117. package/dist/core/commands/plan.d.ts +3 -0
  118. package/dist/core/commands/plan.d.ts.map +1 -0
  119. package/dist/core/commands/plan.js +75 -0
  120. package/dist/core/commands/plan.js.map +1 -0
  121. package/dist/core/commands/remind.d.ts +3 -0
  122. package/dist/core/commands/remind.d.ts.map +1 -0
  123. package/dist/core/commands/remind.js +271 -0
  124. package/dist/core/commands/remind.js.map +1 -0
  125. package/dist/core/commands/router.d.ts +3 -0
  126. package/dist/core/commands/router.d.ts.map +1 -0
  127. package/dist/core/commands/router.js +71 -0
  128. package/dist/core/commands/router.js.map +1 -0
  129. package/dist/core/commands/sessions.d.ts +3 -0
  130. package/dist/core/commands/sessions.d.ts.map +1 -0
  131. package/dist/core/commands/sessions.js +88 -0
  132. package/dist/core/commands/sessions.js.map +1 -0
  133. package/dist/core/commands/stats.d.ts +3 -0
  134. package/dist/core/commands/stats.d.ts.map +1 -0
  135. package/dist/core/commands/stats.js +73 -0
  136. package/dist/core/commands/stats.js.map +1 -0
  137. package/dist/core/commands/think.d.ts +3 -0
  138. package/dist/core/commands/think.d.ts.map +1 -0
  139. package/dist/core/commands/think.js +28 -0
  140. package/dist/core/commands/think.js.map +1 -0
  141. package/dist/core/commands/workspaces.d.ts +3 -0
  142. package/dist/core/commands/workspaces.d.ts.map +1 -0
  143. package/dist/core/commands/workspaces.js +47 -0
  144. package/dist/core/commands/workspaces.js.map +1 -0
  145. package/dist/core/config-schema.d.ts +60 -0
  146. package/dist/core/config-schema.d.ts.map +1 -0
  147. package/dist/core/config-schema.js +75 -0
  148. package/dist/core/config-schema.js.map +1 -0
  149. package/dist/core/coord-systems.d.ts +65 -0
  150. package/dist/core/coord-systems.d.ts.map +1 -0
  151. package/dist/core/coord-systems.js +229 -0
  152. package/dist/core/coord-systems.js.map +1 -0
  153. package/dist/core/cron.d.ts +29 -0
  154. package/dist/core/cron.d.ts.map +1 -0
  155. package/dist/core/cron.js +184 -0
  156. package/dist/core/cron.js.map +1 -0
  157. package/dist/core/event-bus.d.ts +80 -0
  158. package/dist/core/event-bus.d.ts.map +1 -0
  159. package/dist/core/event-bus.js +62 -0
  160. package/dist/core/event-bus.js.map +1 -0
  161. package/dist/core/intent-llm.d.ts +27 -0
  162. package/dist/core/intent-llm.d.ts.map +1 -0
  163. package/dist/core/intent-llm.js +170 -0
  164. package/dist/core/intent-llm.js.map +1 -0
  165. package/dist/core/intent.d.ts +12 -0
  166. package/dist/core/intent.d.ts.map +1 -0
  167. package/dist/core/intent.js +187 -0
  168. package/dist/core/intent.js.map +1 -0
  169. package/dist/core/job-board.d.ts +82 -0
  170. package/dist/core/job-board.d.ts.map +1 -0
  171. package/dist/core/job-board.js +379 -0
  172. package/dist/core/job-board.js.map +1 -0
  173. package/dist/core/location-context.d.ts +32 -0
  174. package/dist/core/location-context.d.ts.map +1 -0
  175. package/dist/core/location-context.js +69 -0
  176. package/dist/core/location-context.js.map +1 -0
  177. package/dist/core/location-token.d.ts +57 -0
  178. package/dist/core/location-token.d.ts.map +1 -0
  179. package/dist/core/location-token.js +128 -0
  180. package/dist/core/location-token.js.map +1 -0
  181. package/dist/core/logger.d.ts +6 -0
  182. package/dist/core/logger.d.ts.map +1 -0
  183. package/dist/core/logger.js +54 -0
  184. package/dist/core/logger.js.map +1 -0
  185. package/dist/core/memo-rpc.d.ts +13 -0
  186. package/dist/core/memo-rpc.d.ts.map +1 -0
  187. package/dist/core/memo-rpc.js +288 -0
  188. package/dist/core/memo-rpc.js.map +1 -0
  189. package/dist/core/memos.d.ts +163 -0
  190. package/dist/core/memos.d.ts.map +1 -0
  191. package/dist/core/memos.js +502 -0
  192. package/dist/core/memos.js.map +1 -0
  193. package/dist/core/metrics.d.ts +55 -0
  194. package/dist/core/metrics.d.ts.map +1 -0
  195. package/dist/core/metrics.js +291 -0
  196. package/dist/core/metrics.js.map +1 -0
  197. package/dist/core/onboarding.d.ts +99 -0
  198. package/dist/core/onboarding.d.ts.map +1 -0
  199. package/dist/core/onboarding.js +426 -0
  200. package/dist/core/onboarding.js.map +1 -0
  201. package/dist/core/pending-reminder.d.ts +25 -0
  202. package/dist/core/pending-reminder.d.ts.map +1 -0
  203. package/dist/core/pending-reminder.js +53 -0
  204. package/dist/core/pending-reminder.js.map +1 -0
  205. package/dist/core/rate-limiter.d.ts +44 -0
  206. package/dist/core/rate-limiter.d.ts.map +1 -0
  207. package/dist/core/rate-limiter.js +115 -0
  208. package/dist/core/rate-limiter.js.map +1 -0
  209. package/dist/core/registry.d.ts +32 -0
  210. package/dist/core/registry.d.ts.map +1 -0
  211. package/dist/core/registry.js +126 -0
  212. package/dist/core/registry.js.map +1 -0
  213. package/dist/core/remind-intent.d.ts +25 -0
  214. package/dist/core/remind-intent.d.ts.map +1 -0
  215. package/dist/core/remind-intent.js +196 -0
  216. package/dist/core/remind-intent.js.map +1 -0
  217. package/dist/core/reminder-rpc.d.ts +17 -0
  218. package/dist/core/reminder-rpc.d.ts.map +1 -0
  219. package/dist/core/reminder-rpc.js +169 -0
  220. package/dist/core/reminder-rpc.js.map +1 -0
  221. package/dist/core/reminders.d.ts +159 -0
  222. package/dist/core/reminders.d.ts.map +1 -0
  223. package/dist/core/reminders.js +977 -0
  224. package/dist/core/reminders.js.map +1 -0
  225. package/dist/core/router.d.ts +55 -0
  226. package/dist/core/router.d.ts.map +1 -0
  227. package/dist/core/router.js +497 -0
  228. package/dist/core/router.js.map +1 -0
  229. package/dist/core/schedule.d.ts +65 -0
  230. package/dist/core/schedule.d.ts.map +1 -0
  231. package/dist/core/schedule.js +323 -0
  232. package/dist/core/schedule.js.map +1 -0
  233. package/dist/core/session.d.ts +182 -0
  234. package/dist/core/session.d.ts.map +1 -0
  235. package/dist/core/session.js +807 -0
  236. package/dist/core/session.js.map +1 -0
  237. package/dist/core/sqlite-helper.d.ts +37 -0
  238. package/dist/core/sqlite-helper.d.ts.map +1 -0
  239. package/dist/core/sqlite-helper.js +79 -0
  240. package/dist/core/sqlite-helper.js.map +1 -0
  241. package/dist/core/transcribe.d.ts +25 -0
  242. package/dist/core/transcribe.d.ts.map +1 -0
  243. package/dist/core/transcribe.js +217 -0
  244. package/dist/core/transcribe.js.map +1 -0
  245. package/dist/core/types.d.ts +360 -0
  246. package/dist/core/types.d.ts.map +1 -0
  247. package/dist/core/types.js +3 -0
  248. package/dist/core/types.js.map +1 -0
  249. package/dist/core/workspace.d.ts +67 -0
  250. package/dist/core/workspace.d.ts.map +1 -0
  251. package/dist/core/workspace.js +113 -0
  252. package/dist/core/workspace.js.map +1 -0
  253. package/dist/index.d.ts +5 -0
  254. package/dist/index.d.ts.map +1 -0
  255. package/dist/index.js +6 -0
  256. package/dist/index.js.map +1 -0
  257. package/dist/plugins/agents/acp/acp-adapter.d.ts +16 -0
  258. package/dist/plugins/agents/acp/acp-adapter.d.ts.map +1 -0
  259. package/dist/plugins/agents/acp/acp-adapter.js +49 -0
  260. package/dist/plugins/agents/acp/acp-adapter.js.map +1 -0
  261. package/dist/plugins/agents/acp/acp-client.d.ts +32 -0
  262. package/dist/plugins/agents/acp/acp-client.d.ts.map +1 -0
  263. package/dist/plugins/agents/acp/acp-client.js +177 -0
  264. package/dist/plugins/agents/acp/acp-client.js.map +1 -0
  265. package/dist/plugins/agents/acp/discovery.d.ts +19 -0
  266. package/dist/plugins/agents/acp/discovery.d.ts.map +1 -0
  267. package/dist/plugins/agents/acp/discovery.js +111 -0
  268. package/dist/plugins/agents/acp/discovery.js.map +1 -0
  269. package/dist/plugins/agents/acp/index.d.ts +4 -0
  270. package/dist/plugins/agents/acp/index.d.ts.map +1 -0
  271. package/dist/plugins/agents/acp/index.js +4 -0
  272. package/dist/plugins/agents/acp/index.js.map +1 -0
  273. package/dist/plugins/agents/acp/types.d.ts +62 -0
  274. package/dist/plugins/agents/acp/types.d.ts.map +1 -0
  275. package/dist/plugins/agents/acp/types.js +5 -0
  276. package/dist/plugins/agents/acp/types.js.map +1 -0
  277. package/dist/plugins/agents/claude-code/index.d.ts +25 -0
  278. package/dist/plugins/agents/claude-code/index.d.ts.map +1 -0
  279. package/dist/plugins/agents/claude-code/index.js +184 -0
  280. package/dist/plugins/agents/claude-code/index.js.map +1 -0
  281. package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts +59 -0
  282. package/dist/plugins/agents/claude-code/mcp-approval-server.d.ts.map +1 -0
  283. package/dist/plugins/agents/claude-code/mcp-approval-server.js +645 -0
  284. package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -0
  285. package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts +28 -0
  286. package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts.map +1 -0
  287. package/dist/plugins/agents/codex/build-mcp-cli-args.js +74 -0
  288. package/dist/plugins/agents/codex/build-mcp-cli-args.js.map +1 -0
  289. package/dist/plugins/agents/codex/index.d.ts +53 -0
  290. package/dist/plugins/agents/codex/index.d.ts.map +1 -0
  291. package/dist/plugins/agents/codex/index.js +341 -0
  292. package/dist/plugins/agents/codex/index.js.map +1 -0
  293. package/dist/plugins/agents/copilot/index.d.ts +35 -0
  294. package/dist/plugins/agents/copilot/index.d.ts.map +1 -0
  295. package/dist/plugins/agents/copilot/index.js +182 -0
  296. package/dist/plugins/agents/copilot/index.js.map +1 -0
  297. package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts +11 -0
  298. package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts.map +1 -0
  299. package/dist/plugins/agents/opencode/ensure-mcp-config.js +100 -0
  300. package/dist/plugins/agents/opencode/ensure-mcp-config.js.map +1 -0
  301. package/dist/plugins/agents/opencode/index.d.ts +5 -0
  302. package/dist/plugins/agents/opencode/index.d.ts.map +1 -0
  303. package/dist/plugins/agents/opencode/index.js +30 -0
  304. package/dist/plugins/agents/opencode/index.js.map +1 -0
  305. package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts +166 -0
  306. package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -0
  307. package/dist/plugins/agents/opencode/opencode-http-adapter.js +682 -0
  308. package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -0
  309. package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts +32 -0
  310. package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts.map +1 -0
  311. package/dist/plugins/agents/opencode/opencode-stdio-adapter.js +137 -0
  312. package/dist/plugins/agents/opencode/opencode-stdio-adapter.js.map +1 -0
  313. package/dist/plugins/agents/opencode/serve-manager.d.ts +27 -0
  314. package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -0
  315. package/dist/plugins/agents/opencode/serve-manager.js +194 -0
  316. package/dist/plugins/agents/opencode/serve-manager.js.map +1 -0
  317. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts +57 -0
  318. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts.map +1 -0
  319. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js +409 -0
  320. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js.map +1 -0
  321. package/dist/plugins/messengers/dingtalk/dingtalk-client.d.ts +48 -0
  322. package/dist/plugins/messengers/dingtalk/dingtalk-client.d.ts.map +1 -0
  323. package/dist/plugins/messengers/dingtalk/dingtalk-client.js +236 -0
  324. package/dist/plugins/messengers/dingtalk/dingtalk-client.js.map +1 -0
  325. package/dist/plugins/messengers/dingtalk/index.d.ts +3 -0
  326. package/dist/plugins/messengers/dingtalk/index.d.ts.map +1 -0
  327. package/dist/plugins/messengers/dingtalk/index.js +3 -0
  328. package/dist/plugins/messengers/dingtalk/index.js.map +1 -0
  329. package/dist/plugins/messengers/dingtalk/link-coords.d.ts +23 -0
  330. package/dist/plugins/messengers/dingtalk/link-coords.d.ts.map +1 -0
  331. package/dist/plugins/messengers/dingtalk/link-coords.js +89 -0
  332. package/dist/plugins/messengers/dingtalk/link-coords.js.map +1 -0
  333. package/dist/plugins/messengers/dingtalk/media-store.d.ts +16 -0
  334. package/dist/plugins/messengers/dingtalk/media-store.d.ts.map +1 -0
  335. package/dist/plugins/messengers/dingtalk/media-store.js +77 -0
  336. package/dist/plugins/messengers/dingtalk/media-store.js.map +1 -0
  337. package/dist/plugins/messengers/dingtalk/types.d.ts +82 -0
  338. package/dist/plugins/messengers/dingtalk/types.d.ts.map +1 -0
  339. package/dist/plugins/messengers/dingtalk/types.js +14 -0
  340. package/dist/plugins/messengers/dingtalk/types.js.map +1 -0
  341. package/dist/plugins/messengers/discord/discord-adapter.d.ts +21 -0
  342. package/dist/plugins/messengers/discord/discord-adapter.d.ts.map +1 -0
  343. package/dist/plugins/messengers/discord/discord-adapter.js +238 -0
  344. package/dist/plugins/messengers/discord/discord-adapter.js.map +1 -0
  345. package/dist/plugins/messengers/discord/index.d.ts +4 -0
  346. package/dist/plugins/messengers/discord/index.d.ts.map +1 -0
  347. package/dist/plugins/messengers/discord/index.js +4 -0
  348. package/dist/plugins/messengers/discord/index.js.map +1 -0
  349. package/dist/plugins/messengers/discord/markdown-to-discord.d.ts +11 -0
  350. package/dist/plugins/messengers/discord/markdown-to-discord.d.ts.map +1 -0
  351. package/dist/plugins/messengers/discord/markdown-to-discord.js +59 -0
  352. package/dist/plugins/messengers/discord/markdown-to-discord.js.map +1 -0
  353. package/dist/plugins/messengers/discord/types.d.ts +9 -0
  354. package/dist/plugins/messengers/discord/types.d.ts.map +1 -0
  355. package/dist/plugins/messengers/discord/types.js +3 -0
  356. package/dist/plugins/messengers/discord/types.js.map +1 -0
  357. package/dist/plugins/messengers/email/email-adapter.d.ts +33 -0
  358. package/dist/plugins/messengers/email/email-adapter.d.ts.map +1 -0
  359. package/dist/plugins/messengers/email/email-adapter.js +137 -0
  360. package/dist/plugins/messengers/email/email-adapter.js.map +1 -0
  361. package/dist/plugins/messengers/feishu/card-builder.d.ts +23 -0
  362. package/dist/plugins/messengers/feishu/card-builder.d.ts.map +1 -0
  363. package/dist/plugins/messengers/feishu/card-builder.js +89 -0
  364. package/dist/plugins/messengers/feishu/card-builder.js.map +1 -0
  365. package/dist/plugins/messengers/feishu/feishu-adapter.d.ts +23 -0
  366. package/dist/plugins/messengers/feishu/feishu-adapter.d.ts.map +1 -0
  367. package/dist/plugins/messengers/feishu/feishu-adapter.js +250 -0
  368. package/dist/plugins/messengers/feishu/feishu-adapter.js.map +1 -0
  369. package/dist/plugins/messengers/feishu/feishu-client.d.ts +43 -0
  370. package/dist/plugins/messengers/feishu/feishu-client.d.ts.map +1 -0
  371. package/dist/plugins/messengers/feishu/feishu-client.js +118 -0
  372. package/dist/plugins/messengers/feishu/feishu-client.js.map +1 -0
  373. package/dist/plugins/messengers/feishu/index.d.ts +4 -0
  374. package/dist/plugins/messengers/feishu/index.d.ts.map +1 -0
  375. package/dist/plugins/messengers/feishu/index.js +4 -0
  376. package/dist/plugins/messengers/feishu/index.js.map +1 -0
  377. package/dist/plugins/messengers/feishu/types.d.ts +113 -0
  378. package/dist/plugins/messengers/feishu/types.d.ts.map +1 -0
  379. package/dist/plugins/messengers/feishu/types.js +4 -0
  380. package/dist/plugins/messengers/feishu/types.js.map +1 -0
  381. package/dist/plugins/messengers/telegram/index.d.ts +4 -0
  382. package/dist/plugins/messengers/telegram/index.d.ts.map +1 -0
  383. package/dist/plugins/messengers/telegram/index.js +4 -0
  384. package/dist/plugins/messengers/telegram/index.js.map +1 -0
  385. package/dist/plugins/messengers/telegram/markdown-to-html.d.ts +5 -0
  386. package/dist/plugins/messengers/telegram/markdown-to-html.d.ts.map +1 -0
  387. package/dist/plugins/messengers/telegram/markdown-to-html.js +186 -0
  388. package/dist/plugins/messengers/telegram/markdown-to-html.js.map +1 -0
  389. package/dist/plugins/messengers/telegram/media-download.d.ts +59 -0
  390. package/dist/plugins/messengers/telegram/media-download.d.ts.map +1 -0
  391. package/dist/plugins/messengers/telegram/media-download.js +228 -0
  392. package/dist/plugins/messengers/telegram/media-download.js.map +1 -0
  393. package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +77 -0
  394. package/dist/plugins/messengers/telegram/telegram-adapter.d.ts.map +1 -0
  395. package/dist/plugins/messengers/telegram/telegram-adapter.js +880 -0
  396. package/dist/plugins/messengers/telegram/telegram-adapter.js.map +1 -0
  397. package/dist/plugins/messengers/telegram/types.d.ts +47 -0
  398. package/dist/plugins/messengers/telegram/types.d.ts.map +1 -0
  399. package/dist/plugins/messengers/telegram/types.js +3 -0
  400. package/dist/plugins/messengers/telegram/types.js.map +1 -0
  401. package/dist/plugins/messengers/wechat/context-store.d.ts +18 -0
  402. package/dist/plugins/messengers/wechat/context-store.d.ts.map +1 -0
  403. package/dist/plugins/messengers/wechat/context-store.js +105 -0
  404. package/dist/plugins/messengers/wechat/context-store.js.map +1 -0
  405. package/dist/plugins/messengers/wechat/ilink-adapter.d.ts +71 -0
  406. package/dist/plugins/messengers/wechat/ilink-adapter.d.ts.map +1 -0
  407. package/dist/plugins/messengers/wechat/ilink-adapter.js +664 -0
  408. package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -0
  409. package/dist/plugins/messengers/wechat/ilink-client.d.ts +75 -0
  410. package/dist/plugins/messengers/wechat/ilink-client.d.ts.map +1 -0
  411. package/dist/plugins/messengers/wechat/ilink-client.js +331 -0
  412. package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -0
  413. package/dist/plugins/messengers/wechat/ilink-types.d.ts +181 -0
  414. package/dist/plugins/messengers/wechat/ilink-types.d.ts.map +1 -0
  415. package/dist/plugins/messengers/wechat/ilink-types.js +22 -0
  416. package/dist/plugins/messengers/wechat/ilink-types.js.map +1 -0
  417. package/dist/plugins/messengers/wechat/media-download.d.ts +32 -0
  418. package/dist/plugins/messengers/wechat/media-download.d.ts.map +1 -0
  419. package/dist/plugins/messengers/wechat/media-download.js +78 -0
  420. package/dist/plugins/messengers/wechat/media-download.js.map +1 -0
  421. package/dist/scripts/migrate-gcj02-to-wgs84.d.ts +3 -0
  422. package/dist/scripts/migrate-gcj02-to-wgs84.d.ts.map +1 -0
  423. package/dist/scripts/migrate-gcj02-to-wgs84.js +52 -0
  424. package/dist/scripts/migrate-gcj02-to-wgs84.js.map +1 -0
  425. package/dist/utils/backoff.d.ts +35 -0
  426. package/dist/utils/backoff.d.ts.map +1 -0
  427. package/dist/utils/backoff.js +59 -0
  428. package/dist/utils/backoff.js.map +1 -0
  429. package/dist/utils/cross-platform.d.ts +26 -0
  430. package/dist/utils/cross-platform.d.ts.map +1 -0
  431. package/dist/utils/cross-platform.js +58 -0
  432. package/dist/utils/cross-platform.js.map +1 -0
  433. package/dist/utils/message-split.d.ts +14 -0
  434. package/dist/utils/message-split.d.ts.map +1 -0
  435. package/dist/utils/message-split.js +65 -0
  436. package/dist/utils/message-split.js.map +1 -0
  437. package/dist/utils/safe-equal.d.ts +2 -0
  438. package/dist/utils/safe-equal.d.ts.map +1 -0
  439. package/dist/utils/safe-equal.js +11 -0
  440. package/dist/utils/safe-equal.js.map +1 -0
  441. package/dist/web/public/_app.js +196 -0
  442. package/dist/web/public/index.html +936 -0
  443. package/dist/web/public/loc.html +305 -0
  444. package/dist/web/public/login.html +106 -0
  445. package/dist/web/public/memos.html +271 -0
  446. package/dist/web/public/reminders.html +234 -0
  447. package/dist/web/public/settings.html +1355 -0
  448. package/dist/web/public/tasks.html +1835 -0
  449. package/dist/web/server.d.ts +12 -0
  450. package/dist/web/server.d.ts.map +1 -0
  451. package/dist/web/server.js +2399 -0
  452. package/dist/web/server.js.map +1 -0
  453. package/package.json +92 -0
@@ -0,0 +1,936 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>im-hub-pro — Agent Chat</title>
7
+ <!-- Shared utilities: theme manager (applies before first paint), error
8
+ boundary (surfaces silent script failures), i18n + api helpers. -->
9
+ <script src="/_app.js"></script>
10
+ <script>
11
+ // i18n — detect browser language, store preference in localStorage
12
+ const LANGS = { en: 'English', zh: '中文' };
13
+ const savedLang = localStorage.getItem('im-hub-lang');
14
+ const browserLang = navigator.language.startsWith('zh') ? 'zh' : 'en';
15
+ window.__lang = savedLang && LANGS[savedLang] ? savedLang : browserLang;
16
+ document.documentElement.lang = window.__lang === 'zh' ? 'zh-CN' : 'en';
17
+
18
+ const T = {
19
+ en: {
20
+ title: 'im-hub-pro — Agent Chat',
21
+ connecting: 'Connecting...',
22
+ connected: 'Connected',
23
+ disconnected: 'Disconnected',
24
+ connError: 'Connection error',
25
+ loadingAgents: 'Loading agents...',
26
+ newChat: 'New Chat',
27
+ welcomeTitle: 'im-hub-pro Agent Chat',
28
+ welcomeDesc: 'Select an agent and start chatting. Your locally installed AI coding agents are ready.',
29
+ inputPlaceholder: 'Type a message... (Enter to send, Shift+Enter for newline)',
30
+ send: 'Send',
31
+ you: 'You',
32
+ assistant: 'Assistant',
33
+ approvalTitle: 'Tool approval request',
34
+ approvalToolLabel: 'Tool',
35
+ approvalInputLabel: 'Input',
36
+ approvalAllow: 'Allow',
37
+ approvalDeny: 'Deny',
38
+ approvalAllowAll: 'Allow + auto for similar',
39
+ approvalAutoAllowing: 'Auto-allowing in {s}s — click Deny to reject',
40
+ approvalAllowed: '✅ Allowed',
41
+ approvalAllowedPinned: '✅ Allowed (auto-allow rule pinned)',
42
+ approvalDenied: '❌ Denied',
43
+ approvalDeniedRevoked: '❌ Denied (auto-allow rule revoked)',
44
+ approvalExpired: '⏱ Timed out (auto-denied)',
45
+ },
46
+ zh: {
47
+ title: 'im-hub-pro — Agent 对话',
48
+ connecting: '连接中...',
49
+ connected: '已连接',
50
+ disconnected: '已断开',
51
+ connError: '连接错误',
52
+ loadingAgents: '加载 Agent...',
53
+ newChat: '新对话',
54
+ welcomeTitle: 'im-hub-pro Agent 对话',
55
+ welcomeDesc: '选择一个 Agent 开始对话,本地安装的 AI 编程助手已就绪。',
56
+ inputPlaceholder: '输入消息...(Enter 发送,Shift+Enter 换行)',
57
+ send: '发送',
58
+ you: '你',
59
+ assistant: '助手',
60
+ approvalTitle: '工具调用审批',
61
+ approvalToolLabel: '工具',
62
+ approvalInputLabel: '入参',
63
+ approvalAllow: '批准',
64
+ approvalDeny: '拒绝',
65
+ approvalAllowAll: '批准并自动放行后续同类',
66
+ approvalAutoAllowing: '将在 {s}s 内自动放行 — 点击拒绝可阻止',
67
+ approvalAllowed: '✅ 已批准',
68
+ approvalAllowedPinned: '✅ 已批准(已启用自动放行)',
69
+ approvalDenied: '❌ 已拒绝',
70
+ approvalDeniedRevoked: '❌ 已拒绝(已撤销自动放行)',
71
+ approvalExpired: '⏱ 已超时(自动拒绝)',
72
+ },
73
+ };
74
+ function t(key) { return T[window.__lang][key] || T.en[key] || key; }
75
+ document.addEventListener('DOMContentLoaded', () => { document.title = t('title'); });
76
+ </script>
77
+ <style>
78
+ /* Three-state theming. `:root` defaults to light; explicit
79
+ data-theme="dark" forces dark; `prefers-color-scheme: dark` only
80
+ applies when the attribute is absent (mode === 'system'). */
81
+ :root {
82
+ color-scheme: light dark;
83
+ /* light defaults */
84
+ --bg: #f8f9fb;
85
+ --surface: #ffffff;
86
+ --surface2: #f1f3f6;
87
+ --border: #e1e4e8;
88
+ --text: #1a1f2e;
89
+ --text-dim: #6b7280;
90
+ --accent: #6366f1;
91
+ --accent-dim: #818cf8;
92
+ --user-bg: #eef2ff;
93
+ --assistant-bg: #ffffff;
94
+ --code-bg: #f1f5f9;
95
+ --green: #16a34a;
96
+ --red: #dc2626;
97
+ --yellow: #ca8a04;
98
+ }
99
+ :root[data-theme="dark"] {
100
+ --bg: #0a0a0a;
101
+ --surface: #141414;
102
+ --surface2: #1e1e1e;
103
+ --border: #2a2a2a;
104
+ --text: #e5e5e5;
105
+ --text-dim: #888;
106
+ --accent: #6366f1;
107
+ --accent-dim: #4f46e5;
108
+ --user-bg: #1a1a2e;
109
+ --assistant-bg: #1e1e1e;
110
+ --code-bg: #0d0d0d;
111
+ --green: #22c55e;
112
+ --red: #ef4444;
113
+ --yellow: #eab308;
114
+ }
115
+ @media (prefers-color-scheme: dark) {
116
+ :root:not([data-theme]) {
117
+ --bg: #0a0a0a;
118
+ --surface: #141414;
119
+ --surface2: #1e1e1e;
120
+ --border: #2a2a2a;
121
+ --text: #e5e5e5;
122
+ --text-dim: #888;
123
+ --accent-dim: #4f46e5;
124
+ --user-bg: #1a1a2e;
125
+ --assistant-bg: #1e1e1e;
126
+ --code-bg: #0d0d0d;
127
+ --green: #22c55e;
128
+ --red: #ef4444;
129
+ --yellow: #eab308;
130
+ }
131
+ }
132
+
133
+ * { margin: 0; padding: 0; box-sizing: border-box; }
134
+
135
+ body {
136
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
137
+ background: var(--bg);
138
+ color: var(--text);
139
+ height: 100vh;
140
+ display: flex;
141
+ flex-direction: column;
142
+ }
143
+
144
+ /* Header */
145
+ .header {
146
+ display: flex;
147
+ align-items: center;
148
+ justify-content: space-between;
149
+ padding: 12px 20px;
150
+ border-bottom: 1px solid var(--border);
151
+ background: var(--surface);
152
+ }
153
+ .header-left {
154
+ display: flex;
155
+ align-items: center;
156
+ gap: 12px;
157
+ }
158
+ .logo {
159
+ font-weight: 700;
160
+ font-size: 16px;
161
+ color: var(--accent);
162
+ }
163
+ .status-dot {
164
+ width: 8px;
165
+ height: 8px;
166
+ border-radius: 50%;
167
+ background: var(--yellow);
168
+ display: inline-block;
169
+ }
170
+ .status-dot.connected { background: var(--green); }
171
+ .status-dot.disconnected { background: var(--red); }
172
+ .status-text { font-size: 12px; color: var(--text-dim); }
173
+ .header-right { display: flex; align-items: center; gap: 10px; }
174
+
175
+ /* Agent selector */
176
+ .agent-select {
177
+ background: var(--surface2);
178
+ color: var(--text);
179
+ border: 1px solid var(--border);
180
+ border-radius: 6px;
181
+ padding: 6px 10px;
182
+ font-size: 13px;
183
+ cursor: pointer;
184
+ outline: none;
185
+ }
186
+ .agent-select:focus { border-color: var(--accent); }
187
+
188
+ .btn {
189
+ background: var(--surface2);
190
+ color: var(--text-dim);
191
+ border: 1px solid var(--border);
192
+ border-radius: 6px;
193
+ padding: 6px 10px;
194
+ font-size: 12px;
195
+ cursor: pointer;
196
+ }
197
+ .btn:hover { color: var(--text); border-color: var(--text-dim); }
198
+
199
+ /* Language selector */
200
+ .lang-select {
201
+ background: var(--surface2);
202
+ color: var(--text-dim);
203
+ border: 1px solid var(--border);
204
+ border-radius: 6px;
205
+ padding: 4px 6px;
206
+ font-size: 12px;
207
+ cursor: pointer;
208
+ outline: none;
209
+ }
210
+ .lang-select:hover { color: var(--text); }
211
+
212
+ /* Messages */
213
+ .messages {
214
+ flex: 1;
215
+ overflow-y: auto;
216
+ padding: 20px;
217
+ display: flex;
218
+ flex-direction: column;
219
+ gap: 16px;
220
+ }
221
+
222
+ .message {
223
+ max-width: 85%;
224
+ padding: 12px 16px;
225
+ border-radius: 12px;
226
+ font-size: 14px;
227
+ line-height: 1.6;
228
+ white-space: pre-wrap;
229
+ word-break: break-word;
230
+ }
231
+ .message.user {
232
+ align-self: flex-end;
233
+ background: var(--user-bg);
234
+ border-bottom-right-radius: 4px;
235
+ }
236
+ .message.assistant {
237
+ align-self: flex-start;
238
+ background: var(--assistant-bg);
239
+ border-bottom-left-radius: 4px;
240
+ }
241
+ .message.assistant code {
242
+ background: var(--code-bg);
243
+ padding: 2px 6px;
244
+ border-radius: 4px;
245
+ font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
246
+ font-size: 13px;
247
+ }
248
+ .message.assistant pre {
249
+ background: var(--code-bg);
250
+ padding: 12px 16px;
251
+ border-radius: 8px;
252
+ overflow-x: auto;
253
+ margin: 8px 0;
254
+ }
255
+ .message.assistant pre code {
256
+ background: none;
257
+ padding: 0;
258
+ }
259
+
260
+ .message-label {
261
+ font-size: 11px;
262
+ color: var(--text-dim);
263
+ margin-bottom: 4px;
264
+ font-weight: 600;
265
+ }
266
+
267
+ /* Typing indicator */
268
+ .typing {
269
+ align-self: flex-start;
270
+ padding: 12px 16px;
271
+ color: var(--text-dim);
272
+ font-size: 13px;
273
+ }
274
+ .typing span {
275
+ animation: blink 1.4s infinite;
276
+ }
277
+ .typing span:nth-child(2) { animation-delay: 0.2s; }
278
+ .typing span:nth-child(3) { animation-delay: 0.4s; }
279
+ @keyframes blink {
280
+ 0%, 60%, 100% { opacity: 0.2; }
281
+ 30% { opacity: 1; }
282
+ }
283
+
284
+ /* Welcome screen */
285
+ .welcome {
286
+ flex: 1;
287
+ display: flex;
288
+ flex-direction: column;
289
+ align-items: center;
290
+ justify-content: center;
291
+ gap: 16px;
292
+ color: var(--text-dim);
293
+ }
294
+ .welcome h2 { color: var(--text); font-size: 20px; }
295
+ .welcome p { font-size: 14px; max-width: 400px; text-align: center; }
296
+
297
+ /* Input area */
298
+ .input-area {
299
+ padding: 16px 20px;
300
+ border-top: 1px solid var(--border);
301
+ background: var(--surface);
302
+ }
303
+ .input-wrapper {
304
+ display: flex;
305
+ gap: 8px;
306
+ align-items: flex-end;
307
+ }
308
+ .input-wrapper textarea {
309
+ flex: 1;
310
+ background: var(--surface2);
311
+ color: var(--text);
312
+ border: 1px solid var(--border);
313
+ border-radius: 10px;
314
+ padding: 10px 14px;
315
+ font-size: 14px;
316
+ font-family: inherit;
317
+ resize: none;
318
+ outline: none;
319
+ max-height: 150px;
320
+ min-height: 42px;
321
+ }
322
+ .input-wrapper textarea:focus { border-color: var(--accent); }
323
+ .input-wrapper textarea::placeholder { color: var(--text-dim); }
324
+
325
+ .send-btn {
326
+ background: var(--accent);
327
+ color: white;
328
+ border: none;
329
+ border-radius: 10px;
330
+ padding: 10px 16px;
331
+ font-size: 14px;
332
+ cursor: pointer;
333
+ white-space: nowrap;
334
+ }
335
+ .send-btn:hover { background: var(--accent-dim); }
336
+ .send-btn:disabled {
337
+ background: var(--surface2);
338
+ color: var(--text-dim);
339
+ cursor: not-allowed;
340
+ }
341
+
342
+ /* Scrollbar */
343
+ .messages::-webkit-scrollbar { width: 6px; }
344
+ .messages::-webkit-scrollbar-track { background: transparent; }
345
+ .messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
346
+
347
+ /* In-chat HITL approval card. Mirrors the IM card's structure (Telegram
348
+ inline-keyboard variant) so the cross-platform UX is consistent. */
349
+ .approval-card {
350
+ border: 1px solid var(--accent);
351
+ background: var(--surface);
352
+ border-radius: 10px;
353
+ padding: 14px 16px;
354
+ margin: 8px 0;
355
+ max-width: 720px;
356
+ box-shadow: 0 1px 3px rgba(0,0,0,.06);
357
+ }
358
+ .approval-card.auto-allow { border-color: var(--yellow); }
359
+ .approval-card.resolved { opacity: .85; }
360
+ .approval-card .ac-title {
361
+ font-weight: 600;
362
+ font-size: 14px;
363
+ margin-bottom: 8px;
364
+ display: flex;
365
+ align-items: center;
366
+ gap: 6px;
367
+ }
368
+ .approval-card .ac-row { font-size: 13px; margin: 4px 0; color: var(--text-dim); }
369
+ .approval-card .ac-row b { color: var(--text); margin-right: 6px; }
370
+ .approval-card .ac-input {
371
+ background: var(--code-bg);
372
+ border-radius: 6px;
373
+ padding: 8px 10px;
374
+ font: 12px/1.5 'SF Mono', Menlo, Consolas, monospace;
375
+ white-space: pre-wrap;
376
+ word-break: break-word;
377
+ max-height: 180px;
378
+ overflow: auto;
379
+ margin: 6px 0 10px;
380
+ color: var(--text);
381
+ }
382
+ .approval-card .ac-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
383
+ .approval-card .ac-btn {
384
+ border: 1px solid var(--border);
385
+ background: var(--surface2);
386
+ color: var(--text);
387
+ padding: 6px 14px;
388
+ border-radius: 6px;
389
+ cursor: pointer;
390
+ font-size: 13px;
391
+ }
392
+ .approval-card .ac-btn:hover { border-color: var(--accent); }
393
+ .approval-card .ac-btn.allow { background: var(--green); border-color: var(--green); color: #fff; }
394
+ .approval-card .ac-btn.deny { background: var(--red); border-color: var(--red); color: #fff; }
395
+ .approval-card .ac-btn:disabled { opacity: .5; cursor: not-allowed; }
396
+ .approval-card .ac-grace {
397
+ color: var(--yellow);
398
+ font-size: 13px;
399
+ margin-bottom: 8px;
400
+ font-weight: 500;
401
+ }
402
+ .approval-card .ac-outcome {
403
+ font-size: 13px;
404
+ margin-top: 8px;
405
+ padding-top: 8px;
406
+ border-top: 1px solid var(--border);
407
+ color: var(--text-dim);
408
+ }
409
+ </style>
410
+ </head>
411
+ <body>
412
+ <div class="header">
413
+ <div class="header-left">
414
+ <span class="logo">im-hub-pro</span>
415
+ <span class="status-dot" id="statusDot"></span>
416
+ <span class="status-text" id="statusText"></span>
417
+ </div>
418
+ <div class="header-right">
419
+ <select class="lang-select" id="langSelect">
420
+ <option value="en">EN</option>
421
+ <option value="zh">中文</option>
422
+ </select>
423
+ <select class="agent-select" id="agentSelect" disabled>
424
+ <option value=""></option>
425
+ </select>
426
+ <button type="button" class="btn" id="newChatBtn"></button>
427
+ <button class="btn" id="theme-toggle" type="button" aria-label="Toggle color theme"></button>
428
+ <a class="btn" href="/tasks" title="Tasks" style="text-decoration:none;font-size:16px;line-height:1">&#9776;</a>
429
+ <a class="btn" href="/reminders" title="Reminders" style="text-decoration:none;font-size:14px;line-height:1">🔔</a>
430
+ <a class="btn" href="/memos" title="Memos" style="text-decoration:none;font-size:14px;line-height:1">📋</a>
431
+ <a class="btn" href="/settings" title="Settings" style="text-decoration:none;font-size:16px;line-height:1">&#9881;</a>
432
+ </div>
433
+ </div>
434
+
435
+ <div class="messages" id="messages">
436
+ <div class="welcome" id="welcome">
437
+ <h2 id="welcomeTitle"></h2>
438
+ <p id="welcomeDesc"></p>
439
+ </div>
440
+ </div>
441
+
442
+ <div class="input-area">
443
+ <div class="input-wrapper">
444
+ <textarea
445
+ id="input"
446
+ rows="1"
447
+ disabled
448
+ ></textarea>
449
+ <button type="button" class="send-btn" id="sendBtn" disabled></button>
450
+ </div>
451
+ </div>
452
+
453
+ <script>
454
+ // Apply i18n to static elements
455
+ function applyLang() {
456
+ document.title = t('title');
457
+ document.documentElement.lang = window.__lang === 'zh' ? 'zh-CN' : 'en';
458
+ statusText.textContent = statusText.dataset.state ? t(statusText.dataset.state) : t('connecting');
459
+ const opt = agentSelect.querySelector('option[value=""]');
460
+ if (opt) opt.textContent = t('loadingAgents');
461
+ newChatBtn.textContent = t('newChat');
462
+ inputEl.placeholder = t('inputPlaceholder');
463
+ sendBtn.textContent = t('send');
464
+ const wt = document.getElementById('welcomeTitle');
465
+ const wd = document.getElementById('welcomeDesc');
466
+ if (wt) wt.textContent = t('welcomeTitle');
467
+ if (wd) wd.textContent = t('welcomeDesc');
468
+ }
469
+
470
+ // State
471
+ let ws = null;
472
+ let currentAgent = '';
473
+ let isStreaming = false;
474
+ let streamingEl = null;
475
+ let streamingText = '';
476
+ let _reconnectTimer = null;
477
+
478
+ // DOM
479
+ const messagesEl = document.getElementById('messages');
480
+ const welcomeEl = document.getElementById('welcome');
481
+ const inputEl = document.getElementById('input');
482
+ const sendBtn = document.getElementById('sendBtn');
483
+ const agentSelect = document.getElementById('agentSelect');
484
+ const statusDot = document.getElementById('statusDot');
485
+ const statusText = document.getElementById('statusText');
486
+ const newChatBtn = document.getElementById('newChatBtn');
487
+ const langSelect = document.getElementById('langSelect');
488
+
489
+ // Theme toggle (light / dark / system). _app.js applied the theme
490
+ // synchronously in <head>; here we wire the button so clicks cycle
491
+ // through the three modes and the icon/label re-renders.
492
+ if (window.imhub) imhub.theme.bindToggle(document.getElementById('theme-toggle'));
493
+
494
+ // Language selector
495
+ langSelect.value = window.__lang;
496
+ langSelect.addEventListener('change', () => {
497
+ window.__lang = langSelect.value;
498
+ localStorage.setItem('im-hub-lang', window.__lang);
499
+ applyLang();
500
+ });
501
+
502
+ // Connect
503
+ function connect() {
504
+ const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
505
+ ws = new WebSocket(`${protocol}//${location.host}/`);
506
+
507
+ ws.onopen = () => {
508
+ setStatus('connected', t('connected'));
509
+ inputEl.disabled = false;
510
+ sendBtn.disabled = false;
511
+ };
512
+
513
+ ws.onmessage = (e) => {
514
+ const msg = JSON.parse(e.data);
515
+ handleMessage(msg);
516
+ };
517
+
518
+ ws.onclose = () => {
519
+ setStatus('disconnected', t('disconnected'));
520
+ inputEl.disabled = true;
521
+ sendBtn.disabled = true;
522
+ _reconnectTimer = setTimeout(connect, 3000);
523
+ };
524
+
525
+ ws.onerror = () => {
526
+ setStatus('disconnected', t('connError'));
527
+ };
528
+ }
529
+
530
+ // Handle server messages
531
+ function handleMessage(msg) {
532
+ switch (msg.type) {
533
+ case 'init':
534
+ agentSelect.innerHTML = '';
535
+ msg.agents.forEach(name => {
536
+ const opt = document.createElement('option');
537
+ opt.value = name;
538
+ opt.textContent = name;
539
+ if (name === msg.defaultAgent) opt.selected = true;
540
+ agentSelect.appendChild(opt);
541
+ });
542
+ agentSelect.disabled = false;
543
+ currentAgent = msg.defaultAgent;
544
+ break;
545
+
546
+ case 'history':
547
+ hideWelcome();
548
+ if (msg.agent) {
549
+ currentAgent = msg.agent;
550
+ agentSelect.value = msg.agent;
551
+ }
552
+ msg.messages.forEach(m => {
553
+ addMessage(m.role, m.content, false);
554
+ });
555
+ scrollToBottom();
556
+ break;
557
+
558
+ case 'agents':
559
+ agentSelect.innerHTML = '';
560
+ msg.agents.forEach(name => {
561
+ const opt = document.createElement('option');
562
+ opt.value = name;
563
+ opt.textContent = name;
564
+ if (name === currentAgent) opt.selected = true;
565
+ agentSelect.appendChild(opt);
566
+ });
567
+ agentSelect.disabled = false;
568
+ break;
569
+
570
+ case 'chunk':
571
+ if (!isStreaming) {
572
+ hideWelcome();
573
+ startStreaming();
574
+ }
575
+ streamingText += msg.text;
576
+ updateStreamingEl();
577
+ scrollToBottom();
578
+ break;
579
+
580
+ case 'done':
581
+ if (isStreaming) {
582
+ finishStreaming();
583
+ } else if (msg.text) {
584
+ hideWelcome();
585
+ addMessage('assistant', msg.text);
586
+ scrollToBottom();
587
+ }
588
+ break;
589
+
590
+ case 'error':
591
+ if (isStreaming) finishStreaming();
592
+ addMessage('assistant', `\u274c ${msg.message}`);
593
+ scrollToBottom();
594
+ break;
595
+
596
+ case 'agent-switched':
597
+ currentAgent = msg.agent;
598
+ agentSelect.value = msg.agent;
599
+ break;
600
+
601
+ // HITL approval messages relayed by the synthetic 'web' messenger
602
+ // (registered on the server in startWebServer). approval-router
603
+ // calls our messenger.sendApprovalCard / sendMessage / editApprovalCard
604
+ // — those become the three WS message types below.
605
+ case 'approval-text':
606
+ // Fallback / receipt path. Render as a system message.
607
+ hideWelcome();
608
+ addSystemMessage(msg.text);
609
+ scrollToBottom();
610
+ break;
611
+ case 'approval-card':
612
+ hideWelcome();
613
+ renderApprovalCard(msg.messageId, msg.prompt);
614
+ scrollToBottom();
615
+ break;
616
+ case 'approval-card-edit':
617
+ editApprovalCard(msg.messageId, msg.outcome);
618
+ break;
619
+ }
620
+ }
621
+
622
+ // Send message
623
+ function sendMessage() {
624
+ const text = inputEl.value.trim();
625
+ if (!text || !ws || ws.readyState !== ws.OPEN) return;
626
+
627
+ hideWelcome();
628
+ addMessage('user', text);
629
+
630
+ ws.send(JSON.stringify({
631
+ type: 'message',
632
+ text,
633
+ agent: currentAgent,
634
+ }));
635
+
636
+ inputEl.value = '';
637
+ autoResize();
638
+ }
639
+
640
+ // Streaming helpers
641
+ function startStreaming() {
642
+ isStreaming = true;
643
+ streamingText = '';
644
+
645
+ const wrapper = document.createElement('div');
646
+ wrapper.innerHTML = `<div class="message-label">${t('assistant')}</div>`;
647
+ streamingEl = document.createElement('div');
648
+ streamingEl.className = 'message assistant';
649
+ wrapper.appendChild(streamingEl);
650
+ messagesEl.appendChild(wrapper);
651
+ }
652
+
653
+ function updateStreamingEl() {
654
+ if (!streamingEl) return;
655
+ streamingEl.textContent = streamingText;
656
+ }
657
+
658
+ function finishStreaming() {
659
+ isStreaming = false;
660
+ if (streamingEl) {
661
+ streamingEl.innerHTML = renderMarkdown(streamingText);
662
+ }
663
+ streamingEl = null;
664
+ saveHistory();
665
+ }
666
+
667
+ // Message helpers
668
+ /**
669
+ * System / receipt-style message bubble. Used for `approval-text` so the
670
+ * "✅ Allowed" / "⏱ Timed out" notices the bus emits show up in the
671
+ * conversation flow without a "user / assistant" label.
672
+ */
673
+ function addSystemMessage(text) {
674
+ hideWelcome();
675
+ const wrapper = document.createElement('div');
676
+ wrapper.style.cssText = 'margin:6px 0; color:var(--text-dim); font-size:13px;';
677
+ wrapper.textContent = text;
678
+ messagesEl.appendChild(wrapper);
679
+ }
680
+
681
+ /** Active approval cards keyed by server-issued messageId, so the
682
+ * `approval-card-edit` handler can find the same DOM node and
683
+ * collapse it to an outcome stamp. */
684
+ const approvalCards = new Map();
685
+
686
+ function renderApprovalCard(messageId, prompt) {
687
+ const isAuto = prompt.mode === 'auto-allow';
688
+ const card = document.createElement('div');
689
+ card.className = `approval-card${isAuto ? ' auto-allow' : ''}`;
690
+ card.dataset.cardId = messageId;
691
+ card.innerHTML = `
692
+ <div class="ac-title">🔐 <span data-slot="title"></span></div>
693
+ ${isAuto ? `<div class="ac-grace" data-slot="grace"></div>` : ''}
694
+ <div class="ac-row"><b data-slot="tool-label"></b><code data-slot="tool"></code></div>
695
+ <div class="ac-row"><b data-slot="input-label"></b></div>
696
+ <pre class="ac-input" data-slot="input"></pre>
697
+ <div class="ac-actions" data-slot="actions"></div>
698
+ `;
699
+ card.querySelector('[data-slot="title"]').textContent = t('approvalTitle');
700
+ card.querySelector('[data-slot="tool-label"]').textContent = `${t('approvalToolLabel')}:`;
701
+ card.querySelector('[data-slot="tool"]').textContent = prompt.toolName;
702
+ card.querySelector('[data-slot="input-label"]').textContent = `${t('approvalInputLabel')}:`;
703
+ card.querySelector('[data-slot="input"]').textContent = prompt.inputJson;
704
+
705
+ const send = (choice) => {
706
+ // Soft disable: dim and ignore further clicks for 800 ms while the
707
+ // server round-trips. We deliberately do NOT hard-disable — if the
708
+ // server returns an error (e.g. 'approval handler not bound'), the
709
+ // card stays usable so the user can retry once they fix it. The
710
+ // success path replaces the buttons via `approval-card-edit` anyway.
711
+ card.querySelectorAll('button').forEach((b) => {
712
+ b.style.opacity = '0.6';
713
+ b.style.pointerEvents = 'none';
714
+ });
715
+ setTimeout(() => {
716
+ card.querySelectorAll('button').forEach((b) => {
717
+ b.style.opacity = '';
718
+ b.style.pointerEvents = '';
719
+ });
720
+ }, 800);
721
+ const payload = { type: 'approval-action', messageId, data: `apv:${prompt.reqId}:${choice}` };
722
+ try { console.debug?.('[approval] click', payload); } catch {}
723
+ if (ws.readyState !== WebSocket.OPEN) {
724
+ imhub?.showError?.('WebSocket not connected — click ignored');
725
+ return;
726
+ }
727
+ ws.send(JSON.stringify(payload));
728
+ };
729
+
730
+ const actions = card.querySelector('[data-slot="actions"]');
731
+ if (isAuto) {
732
+ // Auto-allow grace mode: only Deny is meaningful (Allow happens
733
+ // automatically on grace expiry).
734
+ const denyBtn = document.createElement('button');
735
+ denyBtn.className = 'ac-btn deny';
736
+ denyBtn.textContent = t('approvalDeny');
737
+ denyBtn.onclick = () => send('n');
738
+ actions.appendChild(denyBtn);
739
+
740
+ // Live countdown.
741
+ let s = Number(prompt.graceSeconds) || 5;
742
+ const grace = card.querySelector('[data-slot="grace"]');
743
+ const refreshGrace = () => { grace.textContent = t('approvalAutoAllowing').replace('{s}', String(s)); };
744
+ refreshGrace();
745
+ const tick = setInterval(() => {
746
+ s = Math.max(0, s - 1);
747
+ refreshGrace();
748
+ if (s <= 0) clearInterval(tick);
749
+ }, 1000);
750
+ card._graceTimer = tick;
751
+ } else {
752
+ const allowBtn = document.createElement('button');
753
+ allowBtn.className = 'ac-btn allow';
754
+ allowBtn.textContent = t('approvalAllow');
755
+ allowBtn.onclick = () => send('y');
756
+
757
+ const denyBtn = document.createElement('button');
758
+ denyBtn.className = 'ac-btn deny';
759
+ denyBtn.textContent = t('approvalDeny');
760
+ denyBtn.onclick = () => send('n');
761
+
762
+ const allowAllBtn = document.createElement('button');
763
+ allowAllBtn.className = 'ac-btn';
764
+ allowAllBtn.textContent = t('approvalAllowAll');
765
+ allowAllBtn.onclick = () => send('a');
766
+
767
+ actions.appendChild(allowBtn);
768
+ actions.appendChild(denyBtn);
769
+ actions.appendChild(allowAllBtn);
770
+ }
771
+
772
+ messagesEl.appendChild(card);
773
+ approvalCards.set(messageId, card);
774
+ }
775
+
776
+ function editApprovalCard(messageId, outcome) {
777
+ const card = approvalCards.get(messageId);
778
+ if (!card) return;
779
+ card.classList.add('resolved');
780
+ // Stop any countdown if this was an auto-allow card.
781
+ if (card._graceTimer) { clearInterval(card._graceTimer); card._graceTimer = null; }
782
+ const grace = card.querySelector('[data-slot="grace"]');
783
+ if (grace) grace.remove();
784
+ // Disable any remaining live buttons.
785
+ card.querySelectorAll('.ac-actions button').forEach(b => { b.disabled = true; });
786
+ const actions = card.querySelector('[data-slot="actions"]');
787
+ if (actions) actions.remove();
788
+ const stamp = document.createElement('div');
789
+ stamp.className = 'ac-outcome';
790
+ const KEY = {
791
+ allowed: 'approvalAllowed',
792
+ 'allowed-pinned': 'approvalAllowedPinned',
793
+ denied: 'approvalDenied',
794
+ 'denied-revoked': 'approvalDeniedRevoked',
795
+ expired: 'approvalExpired',
796
+ };
797
+ const text = t(KEY[outcome.decision] || 'approvalAllowed');
798
+ const by = outcome.byUserDisplay ? ` · ${outcome.byUserDisplay}` : '';
799
+ stamp.textContent = `${text}${by}`;
800
+ card.appendChild(stamp);
801
+ // Keep the card around for visual continuity, but free the map slot
802
+ // so a same-id replay doesn't double-edit it.
803
+ approvalCards.delete(messageId);
804
+ }
805
+
806
+ function addMessage(role, content, save = true) {
807
+ hideWelcome();
808
+
809
+ const wrapper = document.createElement('div');
810
+ const label = document.createElement('div');
811
+ label.className = 'message-label';
812
+ label.textContent = role === 'user' ? t('you') : t('assistant');
813
+
814
+ const el = document.createElement('div');
815
+ el.className = `message ${role}`;
816
+
817
+ if (role === 'assistant') {
818
+ el.innerHTML = renderMarkdown(content);
819
+ } else {
820
+ el.textContent = content;
821
+ }
822
+
823
+ wrapper.appendChild(label);
824
+ wrapper.appendChild(el);
825
+ messagesEl.appendChild(wrapper);
826
+
827
+ if (save) saveHistory();
828
+ }
829
+
830
+ // Basic markdown rendering
831
+ function renderMarkdown(text) {
832
+ if (!text) return '';
833
+ let html = escapeHtml(text);
834
+
835
+ html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_, _lang, code) => {
836
+ return `<pre><code>${code.trim()}</code></pre>`;
837
+ });
838
+
839
+ html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
840
+ html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
841
+ html = html.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, '<em>$1</em>');
842
+
843
+ return html;
844
+ }
845
+
846
+ function escapeHtml(text) {
847
+ return text
848
+ .replace(/&/g, '&amp;')
849
+ .replace(/</g, '&lt;')
850
+ .replace(/>/g, '&gt;');
851
+ }
852
+
853
+ function hideWelcome() {
854
+ if (welcomeEl) welcomeEl.remove();
855
+ }
856
+
857
+ function scrollToBottom() {
858
+ requestAnimationFrame(() => {
859
+ messagesEl.scrollTop = messagesEl.scrollHeight;
860
+ });
861
+ }
862
+
863
+ // Status
864
+ function setStatus(state, text) {
865
+ statusDot.className = `status-dot ${state}`;
866
+ statusText.textContent = text;
867
+ statusText.dataset.state = state === 'connected' ? 'connected' : state === 'disconnected' ? 'disconnected' : 'connecting';
868
+ }
869
+
870
+ // LocalStorage persistence
871
+ function saveHistory() {
872
+ const msgs = [];
873
+ messagesEl.querySelectorAll('.message').forEach(el => {
874
+ const role = el.classList.contains('user') ? 'user' : 'assistant';
875
+ msgs.push({ role, content: el.textContent });
876
+ });
877
+ try {
878
+ localStorage.setItem('im-hub-history', JSON.stringify(msgs));
879
+ } catch {}
880
+ }
881
+
882
+ function loadHistory() {
883
+ try {
884
+ const saved = localStorage.getItem('im-hub-history');
885
+ if (saved) {
886
+ const msgs = JSON.parse(saved);
887
+ if (msgs.length > 0) {
888
+ hideWelcome();
889
+ msgs.forEach(m => { addMessage(m.role, m.content, false); });
890
+ scrollToBottom();
891
+ }
892
+ }
893
+ } catch {}
894
+ }
895
+
896
+ // Auto-resize textarea
897
+ function autoResize() {
898
+ inputEl.style.height = 'auto';
899
+ inputEl.style.height = `${Math.min(inputEl.scrollHeight, 150)}px`;
900
+ }
901
+
902
+ // Event listeners
903
+ inputEl.addEventListener('input', autoResize);
904
+
905
+ inputEl.addEventListener('keydown', (e) => {
906
+ if (e.key === 'Enter' && !e.shiftKey && !e.isComposing) {
907
+ e.preventDefault();
908
+ sendMessage();
909
+ }
910
+ });
911
+
912
+ sendBtn.addEventListener('click', sendMessage);
913
+
914
+ agentSelect.addEventListener('change', () => {
915
+ const agent = agentSelect.value;
916
+ if (agent && agent !== currentAgent && ws?.readyState === WebSocket.OPEN) {
917
+ currentAgent = agent;
918
+ ws.send(JSON.stringify({ type: 'switch-agent', agent }));
919
+ }
920
+ });
921
+
922
+ newChatBtn.addEventListener('click', () => {
923
+ messagesEl.innerHTML = '';
924
+ localStorage.removeItem('im-hub-history');
925
+ if (ws?.readyState === WebSocket.OPEN) {
926
+ ws.send(JSON.stringify({ type: 'message', text: '/new' }));
927
+ }
928
+ });
929
+
930
+ // Init
931
+ applyLang();
932
+ loadHistory();
933
+ connect();
934
+ </script>
935
+ </body>
936
+ </html>