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,305 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
6
+ <title>共享位置 · im-hub</title>
7
+ <!-- Leaflet for the interactive map preview. Loaded from unpkg CDN; both
8
+ the page and Leaflet itself fall back gracefully if the CDN is
9
+ blocked — see the `typeof L === 'undefined'` branch in the script. -->
10
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
11
+ integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
12
+ crossorigin="">
13
+ <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
14
+ integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
15
+ crossorigin=""></script>
16
+ <style>
17
+ * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
18
+ html, body { margin: 0; padding: 0; min-height: 100%; font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif; }
19
+ body { background: linear-gradient(180deg, #eff6ff 0%, #ffffff 60%); color: #0f172a; }
20
+ .wrap { max-width: 480px; margin: 0 auto; padding: 24px 20px; }
21
+ h1 { font-size: 22px; margin: 0 0 6px; font-weight: 600; }
22
+ p { color: #475569; line-height: 1.6; margin: 6px 0; }
23
+ .card { background: white; border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px; margin: 18px 0; }
24
+ .btn { display: block; width: 100%; padding: 13px; font-size: 16px; font-weight: 500; color: white; background: #2563eb; border: 0; border-radius: 8px; cursor: pointer; transition: background 0.15s; }
25
+ .btn:hover { background: #1d4ed8; }
26
+ .btn:disabled { background: #94a3b8; cursor: not-allowed; }
27
+ .btn.secondary { background: white; color: #2563eb; border: 1px solid #cbd5e1; margin-top: 8px; }
28
+ .btn.secondary:hover { background: #eff6ff; }
29
+ .status { padding: 14px; border-radius: 8px; margin-top: 14px; font-size: 14px; line-height: 1.5; word-break: break-all; }
30
+ .status.ok { background: #dcfce7; color: #14532d; border: 1px solid #86efac; }
31
+ .status.err { background: #fee2e2; color: #7f1d1d; border: 1px solid #fca5a5; }
32
+ .status.info { background: #dbeafe; color: #1e3a8a; border: 1px solid #93c5fd; }
33
+ .meta { font-size: 12px; color: #94a3b8; margin-top: 18px; text-align: center; line-height: 1.6; }
34
+ code { background: #f1f5f9; padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, "SFMono-Regular", monospace; font-size: 13px; }
35
+ .icon { font-size: 40px; line-height: 1; margin-bottom: 8px; }
36
+ #map { width: 100%; height: 320px; border-radius: 8px; border: 1px solid #e2e8f0; }
37
+ .coords-row { display:flex; align-items:center; justify-content:space-between; margin-top:12px; padding:10px 12px; background:#f8fafc; border-radius:6px; font-size:13px; color:#334155; font-family: ui-monospace, "SFMono-Regular", monospace; }
38
+ .hint { font-size: 12px; color: #64748b; margin-top: 8px; line-height: 1.5; }
39
+ .note-row { display:none; margin-bottom:12px; padding:10px 12px; background:#eff6ff; border-radius:8px; color:#1e40af; font-size:14px; }
40
+ .leaflet-container { background: #e2e8f0; }
41
+ </style>
42
+ </head>
43
+ <body>
44
+ <div class="wrap">
45
+ <div class="icon">📍</div>
46
+ <h1 id="title">共享当前位置给 bot</h1>
47
+ <p id="subtitle">点击下方按钮,浏览器会询问位置授权。授权后可在地图上微调精确位置。</p>
48
+
49
+ <div id="note-row" class="note-row">
50
+ <span id="note-prefix">正在记录</span>: <strong id="note-text"></strong>
51
+ </div>
52
+
53
+ <!-- Step 1: get permission + initial coords -->
54
+ <div id="card-prep" class="card">
55
+ <button id="share" class="btn" type="button">📍 获取我的位置</button>
56
+ <div id="status" class="status info" style="display:none"></div>
57
+ </div>
58
+
59
+ <!-- Step 2: map preview + drag to fine-tune + confirm -->
60
+ <div id="card-map" class="card" style="display:none">
61
+ <div id="map"></div>
62
+ <div class="coords-row">
63
+ <span id="coords-text">—</span>
64
+ <span id="acc-text" style="color:#64748b"></span>
65
+ </div>
66
+ <p class="hint">📌 长按 marker 拖动,或点击地图任意位置移动 marker,可微调到准确位置。</p>
67
+ <button id="confirm" class="btn" type="button">✅ 确认提交这个位置</button>
68
+ <button id="redo" class="btn secondary" type="button">🔄 重新获取定位</button>
69
+ </div>
70
+
71
+ <!-- Step 3: done -->
72
+ <div id="card-done" class="card" style="display:none">
73
+ <div class="status ok">✅ 位置已发回 IM。可以关闭页面回到聊天查看。</div>
74
+ </div>
75
+
76
+ <p class="meta">
77
+ 链接 10 分钟内有效,单次使用<br>
78
+ 你的坐标只会发回触发本链接的 IM 会话
79
+ </p>
80
+ </div>
81
+
82
+ <script>
83
+ (function () {
84
+ // ── DOM refs ───────────────────────────────────────────────────────
85
+ var status = document.getElementById('status')
86
+ var btnShare = document.getElementById('share')
87
+ var btnConfirm = document.getElementById('confirm')
88
+ var btnRedo = document.getElementById('redo')
89
+ var cardPrep = document.getElementById('card-prep')
90
+ var cardMap = document.getElementById('card-map')
91
+ var cardDone = document.getElementById('card-done')
92
+ var coordsText = document.getElementById('coords-text')
93
+ var accText = document.getElementById('acc-text')
94
+
95
+ // ── Token resolution (supports both /loc?t=… and /l/… shapes) ─────
96
+ var token = ''
97
+ var qp = new URLSearchParams(window.location.search).get('t')
98
+ var pathMatch = window.location.pathname.match(/^\/l\/([A-Za-z0-9_-]+)$/)
99
+ if (qp) {
100
+ token = qp
101
+ } else if (pathMatch) {
102
+ token = pathMatch[1]
103
+ }
104
+
105
+ // ── State ─────────────────────────────────────────────────────────
106
+ var leafletMap = null
107
+ var marker = null
108
+ var currentLat = 0, currentLng = 0, currentAcc = 0
109
+ var leafletAvailable = (typeof L !== 'undefined')
110
+
111
+ function show(kind, html) {
112
+ status.className = 'status ' + kind
113
+ status.innerHTML = html
114
+ status.style.display = 'block'
115
+ }
116
+ function clearStatus() { status.style.display = 'none' }
117
+
118
+ function fmtCoords(lat, lng) {
119
+ return lat.toFixed(6) + ', ' + lng.toFixed(6)
120
+ }
121
+ function updateCoordsDisplay(acc) {
122
+ coordsText.textContent = fmtCoords(currentLat, currentLng)
123
+ if (typeof acc === 'number' && acc > 0) {
124
+ accText.textContent = '初始 ±' + Math.round(acc) + 'm'
125
+ }
126
+ }
127
+
128
+ // ── Pre-flight ────────────────────────────────────────────────────
129
+ if (!token) {
130
+ btnShare.disabled = true
131
+ show('err', '❌ 链接无效(缺少 token)。请回到 IM 重新发送 <code>/location here</code>。')
132
+ return
133
+ }
134
+ if (!('geolocation' in navigator)) {
135
+ btnShare.disabled = true
136
+ show('err', '❌ 浏览器不支持地理位置 API。')
137
+ return
138
+ }
139
+
140
+ // Fetch the pre-filled note for the title bar.
141
+ fetch('/api/loc/info?t=' + encodeURIComponent(token)).then(function (r) {
142
+ if (r.status === 410) {
143
+ btnShare.disabled = true
144
+ show('err', '❌ 链接已过期或已被使用。回到 IM 重新发送 <code>/location here</code> 拿新链接。')
145
+ return null
146
+ }
147
+ return r.ok ? r.json() : null
148
+ }).then(function (j) {
149
+ if (!j) return
150
+ // Two display modes:
151
+ // - augment: token has memo_id → "正在补充'<existing memo's what>'的位置"
152
+ // - create: token has what → "正在记录: <what>"
153
+ var label = j.augmentLabel || j.what || ''
154
+ if (!label) return
155
+ document.getElementById('note-text').textContent = label
156
+ document.getElementById('note-prefix').textContent = j.augmentLabel ? '正在补充' : '正在记录'
157
+ document.getElementById('note-row').style.display = 'block'
158
+ document.getElementById('title').textContent = (j.augmentLabel ? '为"' + label + '"补充位置' : '共享"' + label + '"的位置')
159
+ }).catch(function () { /* network blip — proceed without label */ })
160
+
161
+ // ── Step 1 → Step 2: get permission, switch to map ────────────────
162
+ function captureCoords() {
163
+ btnShare.disabled = true
164
+ btnShare.textContent = '获取定位中…'
165
+ show('info', '⏳ 等待浏览器返回坐标…')
166
+
167
+ navigator.geolocation.getCurrentPosition(
168
+ function (pos) {
169
+ currentLat = pos.coords.latitude
170
+ currentLng = pos.coords.longitude
171
+ currentAcc = pos.coords.accuracy
172
+ clearStatus()
173
+ cardPrep.style.display = 'none'
174
+ cardMap.style.display = 'block'
175
+ updateCoordsDisplay(currentAcc)
176
+
177
+ if (leafletAvailable) {
178
+ renderMap()
179
+ } else {
180
+ fallbackNoMap()
181
+ }
182
+ },
183
+ function (err) {
184
+ btnShare.disabled = false
185
+ btnShare.textContent = '📍 获取我的位置'
186
+ var map = { 1: '你拒绝了授权', 2: '位置不可用', 3: '获取超时' }
187
+ show('err', '❌ ' + (map[err.code] || err.message || '未知错误'))
188
+ },
189
+ { enableHighAccuracy: true, timeout: 15000, maximumAge: 30000 }
190
+ )
191
+ }
192
+
193
+ // CDN blocked / Leaflet missing → no map preview, but still let the
194
+ // user submit the captured coords directly via the same confirm button.
195
+ function fallbackNoMap() {
196
+ document.getElementById('map').style.display = 'none'
197
+ var hintEl = document.querySelector('.hint')
198
+ if (hintEl) hintEl.textContent = '⚠️ 地图加载失败(网络限制?),无法微调。如坐标不准请用「重新获取定位」。'
199
+ }
200
+
201
+ // ── Map render (Leaflet + OSM tiles, WGS-84 native, no key) ───────
202
+ function renderMap() {
203
+ leafletMap = L.map('map', {
204
+ zoomControl: true,
205
+ // Touch-friendly defaults; let drag work even on tap-and-hold.
206
+ tap: true,
207
+ }).setView([currentLat, currentLng], 17)
208
+
209
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
210
+ maxZoom: 19,
211
+ attribution: '© OpenStreetMap',
212
+ }).addTo(leafletMap)
213
+
214
+ // Initial accuracy circle gives the user a sense of GPS uncertainty.
215
+ if (currentAcc > 0) {
216
+ L.circle([currentLat, currentLng], {
217
+ radius: currentAcc,
218
+ color: '#2563eb', fillColor: '#3b82f6', fillOpacity: 0.12, weight: 1,
219
+ }).addTo(leafletMap)
220
+ }
221
+
222
+ marker = L.marker([currentLat, currentLng], {
223
+ draggable: true,
224
+ autoPan: true,
225
+ }).addTo(leafletMap)
226
+
227
+ marker.on('dragend', function () {
228
+ var p = marker.getLatLng()
229
+ currentLat = p.lat; currentLng = p.lng
230
+ updateCoordsDisplay()
231
+ })
232
+
233
+ leafletMap.on('click', function (e) {
234
+ marker.setLatLng(e.latlng)
235
+ currentLat = e.latlng.lat; currentLng = e.latlng.lng
236
+ updateCoordsDisplay()
237
+ // Recenter only if marker drifts close to viewport edge — avoids
238
+ // jarring re-pans for small adjustments.
239
+ var bounds = leafletMap.getBounds().pad(-0.15)
240
+ if (!bounds.contains(e.latlng)) leafletMap.panTo(e.latlng)
241
+ })
242
+
243
+ // Some browsers compute layout AFTER tile load; force a redraw.
244
+ setTimeout(function () { leafletMap.invalidateSize() }, 200)
245
+ }
246
+
247
+ // ── Step 2 → Step 3: submit ───────────────────────────────────────
248
+ function submitCoords() {
249
+ btnConfirm.disabled = true
250
+ btnConfirm.textContent = '提交中…'
251
+ show('info', '⏳ 上传到 bot…')
252
+
253
+ fetch('/api/loc', {
254
+ method: 'POST',
255
+ headers: { 'Content-Type': 'application/json' },
256
+ body: JSON.stringify({
257
+ t: token,
258
+ lat: currentLat,
259
+ lng: currentLng,
260
+ // We send 0 for accuracy when the user has manually adjusted —
261
+ // the GPS-reported accuracy no longer applies. A future tweak:
262
+ // track whether marker was moved and report acc only if not.
263
+ accuracy: currentAcc,
264
+ }),
265
+ }).then(function (r) {
266
+ if (r.ok) {
267
+ cardMap.style.display = 'none'
268
+ cardDone.style.display = 'block'
269
+ clearStatus()
270
+ } else {
271
+ return r.json().catch(function () { return {} }).then(function (j) {
272
+ btnConfirm.disabled = false
273
+ btnConfirm.textContent = '✅ 确认提交这个位置'
274
+ show('err', '❌ ' + (j.error || ('上传失败 (HTTP ' + r.status + ')')))
275
+ })
276
+ }
277
+ }).catch(function (err) {
278
+ btnConfirm.disabled = false
279
+ btnConfirm.textContent = '✅ 确认提交这个位置'
280
+ show('err', '❌ 网络错误:' + (err && err.message || err))
281
+ })
282
+ }
283
+
284
+ // ── Redo: go back to step 1 (re-fetch GPS for higher accuracy) ────
285
+ function redoCapture() {
286
+ if (leafletMap) {
287
+ leafletMap.remove()
288
+ leafletMap = null
289
+ marker = null
290
+ }
291
+ cardMap.style.display = 'none'
292
+ cardPrep.style.display = 'block'
293
+ btnShare.disabled = false
294
+ btnShare.textContent = '📍 获取我的位置'
295
+ clearStatus()
296
+ }
297
+
298
+ // ── Wire up ───────────────────────────────────────────────────────
299
+ btnShare.addEventListener('click', captureCoords)
300
+ btnConfirm.addEventListener('click', submitCoords)
301
+ btnRedo.addEventListener('click', redoCapture)
302
+ })()
303
+ </script>
304
+ </body>
305
+ </html>
@@ -0,0 +1,106 @@
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 — Login</title>
7
+ <script src="/_app.js"></script>
8
+ <script>
9
+ const savedLang = localStorage.getItem('im-hub-lang');
10
+ const browserLang = navigator.language.startsWith('zh') ? 'zh' : 'en';
11
+ window.__lang = savedLang || browserLang;
12
+ document.documentElement.lang = window.__lang === 'zh' ? 'zh-CN' : 'en';
13
+ </script>
14
+ <style>
15
+ :root {
16
+ --bg: #f8f9fa; --fg: #1a1a2e; --card-bg: #fff;
17
+ --border: #dee2e6; --accent: #0d6efd; --accent-hover: #0b5ed7;
18
+ --input-bg: #fff; --input-border: #ced4da;
19
+ --error-bg: #f8d7da; --error-fg: #842029;
20
+ }
21
+ :root[data-theme="dark"] {
22
+ --bg: #0d1117; --fg: #c9d1d9; --card-bg: #161b22;
23
+ --border: #30363d; --accent: #58a6ff; --accent-hover: #79b8ff;
24
+ --input-bg: #0d1117; --input-border: #30363d;
25
+ --error-bg: #3d1418; --error-fg: #f8d7da;
26
+ }
27
+ @media (prefers-color-scheme: dark) {
28
+ :root:not([data-theme="light"]) {
29
+ --bg: #0d1117; --fg: #c9d1d9; --card-bg: #161b22;
30
+ --border: #30363d; --accent: #58a6ff; --accent-hover: #79b8ff;
31
+ --input-bg: #0d1117; --input-border: #30363d;
32
+ --error-bg: #3d1418; --error-fg: #f8d7da;
33
+ }
34
+ }
35
+ * { box-sizing: border-box; margin: 0; padding: 0; }
36
+ body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
37
+ background: var(--bg); color: var(--fg); display: flex; align-items: center;
38
+ justify-content: center; min-height: 100vh; }
39
+ .card { background: var(--card-bg); border: 1px solid var(--border);
40
+ border-radius: 12px; padding: 2rem; max-width: 400px; width: 90%; box-shadow: 0 4px 24px rgba(0,0,0,.08); }
41
+ h1 { font-size: 1.25rem; margin-bottom: .5rem; }
42
+ p { font-size: .875rem; color: var(--fg); opacity: .7; margin-bottom: 1.5rem; }
43
+ label { display: block; font-size: .875rem; margin-bottom: .25rem; font-weight: 500; }
44
+ input[type="password"] { width: 100%; padding: .5rem .75rem; border: 1px solid var(--input-border);
45
+ border-radius: 6px; background: var(--input-bg); color: var(--fg); font-size: .875rem;
46
+ margin-bottom: 1rem; }
47
+ button { width: 100%; padding: .5rem 1rem; background: var(--accent); color: #fff;
48
+ border: none; border-radius: 6px; font-size: .875rem; cursor: pointer; font-weight: 500; }
49
+ button:hover { background: var(--accent-hover); }
50
+ .error { display: none; background: var(--error-bg); color: var(--error-fg);
51
+ padding: .5rem .75rem; border-radius: 6px; font-size: .8rem; margin-bottom: 1rem; }
52
+ .hint { font-size: .75rem; opacity: .5; margin-top: 1rem; text-align: center; }
53
+ </style>
54
+ </head>
55
+ <body>
56
+ <div class="card">
57
+ <h1 data-i18n="loginTitle">im-hub-pro</h1>
58
+ <p data-i18n="loginDesc">Enter the web console token to continue.</p>
59
+ <div class="error" id="error"></div>
60
+ <form id="form">
61
+ <label for="token" data-i18n="tokenLabel">Token</label>
62
+ <input type="password" id="token" autocomplete="off" >
63
+ <button type="submit" data-i18n="loginBtn">Log in</button>
64
+ </form>
65
+ <div class="hint" data-i18n="tokenHint">Find your token in ~/.im-hub/web-token</div>
66
+ </div>
67
+ <script>
68
+ const T = {
69
+ en: { loginTitle:'im-hub-pro', loginDesc:'Enter the web console token to continue.',
70
+ tokenLabel:'Token', loginBtn:'Log in', tokenHint:'Find your token in ~/.im-hub/web-token',
71
+ badToken:'Invalid token', networkErr:'Network error — is the server running?' },
72
+ zh: { loginTitle:'im-hub-pro', loginDesc:'请输入控制台 token 以继续。',
73
+ tokenLabel:'Token', loginBtn:'登录', tokenHint:'Token 位于 ~/.im-hub/web-token',
74
+ badToken:'Token 无效', networkErr:'网络错误 — 服务是否正在运行?' },
75
+ };
76
+ const L = T[window.__lang] || T.en;
77
+ window.imhub.i18n.apply(L);
78
+
79
+ const form = document.getElementById('form');
80
+ const errEl = document.getElementById('error');
81
+ form.addEventListener('submit', async (e) => {
82
+ e.preventDefault();
83
+ errEl.style.display = 'none';
84
+ const token = document.getElementById('token').value.trim();
85
+ if (!token) return;
86
+ try {
87
+ const res = await fetch('/api/auth/login', {
88
+ method: 'POST',
89
+ headers: { 'Content-Type': 'application/json' },
90
+ body: JSON.stringify({ token }),
91
+ });
92
+ if (res.ok) {
93
+ const dest = new URLSearchParams(location.search).get('next') || '/';
94
+ location.href = dest;
95
+ } else {
96
+ errEl.textContent = L.badToken;
97
+ errEl.style.display = 'block';
98
+ }
99
+ } catch {
100
+ errEl.textContent = L.networkErr;
101
+ errEl.style.display = 'block';
102
+ }
103
+ });
104
+ </script>
105
+ </body>
106
+ </html>
@@ -0,0 +1,271 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>im-hub-pro — Memos</title>
7
+ <script src="/_app.js"></script>
8
+ <style>
9
+ :root {
10
+ --bg: #fafafa; --fg: #222; --muted: #666; --border: #e5e7eb;
11
+ --card: #fff; --accent: #2563eb; --danger: #dc2626; --warn: #d97706;
12
+ --geo: #059669;
13
+ }
14
+ [data-theme="dark"] {
15
+ --bg: #1a1a1a; --fg: #e5e5e5; --muted: #999; --border: #333;
16
+ --card: #242424; --accent: #60a5fa; --danger: #f87171; --warn: #fbbf24;
17
+ --geo: #34d399;
18
+ }
19
+ body {
20
+ font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif;
21
+ background: var(--bg); color: var(--fg); margin: 0; padding: 0;
22
+ }
23
+ header {
24
+ display: flex; align-items: center; justify-content: space-between;
25
+ padding: 14px 20px; border-bottom: 1px solid var(--border); background: var(--card);
26
+ }
27
+ header h1 { margin: 0; font-size: 18px; font-weight: 600; }
28
+ header nav a {
29
+ color: var(--muted); text-decoration: none; padding: 4px 10px;
30
+ border-radius: 4px; font-size: 13px; margin-left: 4px;
31
+ }
32
+ header nav a:hover { background: var(--bg); color: var(--fg); }
33
+ main { padding: 20px; max-width: 980px; margin: 0 auto; }
34
+ .toolbar {
35
+ display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap;
36
+ align-items: center;
37
+ }
38
+ .toolbar input[type="text"] {
39
+ flex: 1; min-width: 200px;
40
+ padding: 7px 12px; border: 1px solid var(--border); border-radius: 6px;
41
+ background: var(--card); color: var(--fg); font-size: 14px;
42
+ }
43
+ .toolbar input[type="text"]:focus { outline: none; border-color: var(--accent); }
44
+ .filter-btn {
45
+ padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px;
46
+ background: transparent; color: var(--muted); cursor: pointer;
47
+ font-size: 13px; transition: all 0.15s;
48
+ }
49
+ .filter-btn:hover { color: var(--fg); border-color: var(--fg); }
50
+ .filter-btn.active { background: var(--accent); color: white; border-color: var(--accent); }
51
+ .stats { color: var(--muted); font-size: 12px; }
52
+ .memo {
53
+ background: var(--card); border: 1px solid var(--border); border-radius: 8px;
54
+ padding: 12px 16px; margin-bottom: 10px;
55
+ display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
56
+ }
57
+ .memo .body { flex: 1; min-width: 0; }
58
+ .memo .what {
59
+ font-weight: 600; margin-bottom: 4px;
60
+ display: flex; align-items: center; gap: 8px;
61
+ }
62
+ .memo .icon { font-size: 16px; }
63
+ .memo .id { color: var(--muted); font-size: 11px; font-weight: normal; }
64
+ .memo .original {
65
+ color: var(--muted); margin-bottom: 6px; font-size: 13px;
66
+ border-left: 2px solid var(--border); padding-left: 8px;
67
+ }
68
+ .memo .meta {
69
+ color: var(--muted); font-size: 12px; margin-top: 4px;
70
+ display: flex; gap: 12px; flex-wrap: wrap;
71
+ }
72
+ .memo .meta .who::before { content: '👤 '; }
73
+ .memo .meta .when::before { content: '🗓 '; }
74
+ .memo .meta .geo { color: var(--geo); }
75
+ .memo .meta .geo::before { content: '📍 '; }
76
+ .memo .meta .platform { opacity: 0.7; }
77
+ .memo .meta .expires { color: var(--warn); }
78
+ .memo .meta .expires::before { content: '⏳ '; }
79
+ .memo .maps { margin-top: 6px; font-size: 12px; display: flex; gap: 12px; flex-wrap: wrap; }
80
+ .memo .maps a { color: var(--accent); text-decoration: none; }
81
+ .memo .maps a:hover { text-decoration: underline; }
82
+ .actions { display: flex; gap: 6px; flex-shrink: 0; }
83
+ .btn {
84
+ padding: 5px 10px; border: 1px solid var(--border); border-radius: 5px;
85
+ background: transparent; color: var(--fg); cursor: pointer; font-size: 12px;
86
+ }
87
+ .btn:hover { border-color: var(--accent); color: var(--accent); }
88
+ .btn.danger:hover { border-color: var(--danger); color: var(--danger); }
89
+ .empty { color: var(--muted); text-align: center; padding: 60px 0; }
90
+ .toast {
91
+ position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
92
+ background: var(--card); border: 1px solid var(--border); padding: 10px 16px;
93
+ border-radius: 6px; font-size: 13px;
94
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
95
+ transition: opacity 0.2s;
96
+ }
97
+ .toast.error { color: var(--danger); border-color: var(--danger); }
98
+ @media (max-width: 600px) {
99
+ .memo { flex-direction: column; }
100
+ .actions { width: 100%; justify-content: flex-end; }
101
+ }
102
+ </style>
103
+ </head>
104
+ <body>
105
+ <header>
106
+ <h1>📋 Memos</h1>
107
+ <nav>
108
+ <a href="/">Chat</a>
109
+ <a href="/tasks">Tasks</a>
110
+ <a href="/reminders">Reminders</a>
111
+ <a href="/settings">Settings</a>
112
+ </nav>
113
+ </header>
114
+ <main>
115
+ <div class="toolbar">
116
+ <input type="text" id="q" placeholder="搜索内容(what / memo / who / 地址 …)" />
117
+ <button type="button" class="filter-btn active" data-filter="all">全部</button>
118
+ <button type="button" class="filter-btn" data-filter="geo">有位置</button>
119
+ <button type="button" class="filter-btn" data-filter="expired">已过期</button>
120
+ <span class="stats" id="stats"></span>
121
+ </div>
122
+ <div id="list"></div>
123
+ </main>
124
+ <div id="toast" class="toast" style="display:none"></div>
125
+
126
+ <script>
127
+ (() => {
128
+ const $list = document.getElementById('list')
129
+ const $toast = document.getElementById('toast')
130
+ const $q = document.getElementById('q')
131
+ const $stats = document.getElementById('stats')
132
+ let currentFilter = 'all'
133
+ let queryStr = ''
134
+ let debounceTimer = null
135
+
136
+ function toast(msg, isErr = false) {
137
+ $toast.textContent = msg
138
+ $toast.className = 'toast' + (isErr ? ' error' : '')
139
+ $toast.style.display = 'block'
140
+ setTimeout(() => { $toast.style.display = 'none' }, 2400)
141
+ }
142
+
143
+ function escapeHtml(s) {
144
+ if (s == null) return ''
145
+ return String(s)
146
+ .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
147
+ .replace(/"/g, '&quot;').replace(/'/g, '&#39;')
148
+ }
149
+
150
+ function fmtTime(iso) {
151
+ if (!iso) return ''
152
+ // memos use 'YYYY-MM-DD HH:MM:SS' (UTC+8 bare-local).
153
+ // Parse via Date and present as local. Worst case display drift is
154
+ // 0 (the user is also in UTC+8 because we already assume that).
155
+ const d = new Date(iso.replace(' ', 'T') + '+08:00')
156
+ if (Number.isNaN(d.getTime())) return iso
157
+ const now = new Date()
158
+ const diffMs = now.getTime() - d.getTime()
159
+ const absMin = Math.abs(Math.round(diffMs / 60000))
160
+ let rel = ''
161
+ if (Math.abs(diffMs) < 60_000) rel = '刚才'
162
+ else if (absMin < 60) rel = `${absMin} 分钟前`
163
+ else if (absMin < 1440) rel = `${(absMin / 60).toFixed(1)} 小时前`
164
+ else rel = `${(absMin / 1440).toFixed(1)} 天前`
165
+ return `${d.toLocaleString()} · ${rel}`
166
+ }
167
+
168
+ async function load() {
169
+ $list.innerHTML = '<div class="empty">加载中…</div>'
170
+ try {
171
+ const params = new URLSearchParams()
172
+ if (queryStr) params.set('query', queryStr)
173
+ if (currentFilter === 'geo') params.set('has_location', 'true')
174
+ if (currentFilter === 'expired') params.set('include_expired', 'true')
175
+ params.set('limit', '200')
176
+ const data = await window.imhub.api(`/api/memos?${params.toString()}`)
177
+ let items = data.memos || []
178
+ if (currentFilter === 'expired') {
179
+ // Only the rows that have an expires_at in the past.
180
+ const now = new Date()
181
+ items = items.filter(m => m.expiresAt && new Date(m.expiresAt.replace(' ', 'T') + '+08:00') < now)
182
+ }
183
+ render(items)
184
+ $stats.textContent = items.length ? `${items.length} 条` : ''
185
+ } catch (err) {
186
+ $list.innerHTML = ''
187
+ toast(`加载失败:${err.message}`, true)
188
+ }
189
+ }
190
+
191
+ function render(items) {
192
+ if (!items.length) {
193
+ $list.innerHTML = `<div class="empty">${queryStr ? '没匹配的 memo' : '还没记下任何 memo。在 IM 里说「记下…」让 agent 帮你存。'}</div>`
194
+ return
195
+ }
196
+ $list.innerHTML = items.map(m => {
197
+ const icon = m.where_lat != null ? '📍' : '📝'
198
+ const idLbl = `<span class="id">#${m.id}</span>`
199
+ const what = `<div class="what"><span class="icon">${icon}</span>${escapeHtml(m.what)} ${idLbl}</div>`
200
+ const original = (m.memo && m.memo !== m.what)
201
+ ? `<div class="original">${escapeHtml(m.memo)}</div>` : ''
202
+ const metaBits = []
203
+ if (m.who) metaBits.push(`<span class="who">${escapeHtml(m.who)}</span>`)
204
+ if (m.whenAt) metaBits.push(`<span class="when">${escapeHtml(m.whenAt)}</span>`)
205
+ else if (m.whenText) metaBits.push(`<span class="when">${escapeHtml(m.whenText)}</span>`)
206
+ if (m.where_label) metaBits.push(`<span class="geo">${escapeHtml(m.where_label)}</span>`)
207
+ else if (m.where_lat != null) metaBits.push(`<span class="geo">${m.where_lat.toFixed(5)}, ${m.where_lng.toFixed(5)}</span>`)
208
+ if (m.platform) metaBits.push(`<span class="platform">${escapeHtml(m.platform)}</span>`)
209
+ if (m.expiresAt) metaBits.push(`<span class="expires">${escapeHtml(m.expiresAt)}</span>`)
210
+ metaBits.push(`<span class="when">${fmtTime(m.createdAt)}</span>`)
211
+ const meta = `<div class="meta">${metaBits.join('')}</div>`
212
+
213
+ let maps = ''
214
+ if (m.mapUrls) {
215
+ maps = `<div class="maps">
216
+ <a href="${m.mapUrls.baidu}" target="_blank">百度地图</a>
217
+ <a href="${m.mapUrls.amap}" target="_blank">高德地图</a>
218
+ <a href="${m.mapUrls.google}" target="_blank">Google</a>
219
+ </div>`
220
+ }
221
+
222
+ return `<div class="memo" data-id="${m.id}">
223
+ <div class="body">${what}${original}${meta}${maps}</div>
224
+ <div class="actions">
225
+ <button type="button" class="btn danger" data-action="delete">删除</button>
226
+ </div>
227
+ </div>`
228
+ }).join('')
229
+ }
230
+
231
+ $list.addEventListener('click', async (e) => {
232
+ const btn = e.target.closest('button[data-action]')
233
+ if (!btn) return
234
+ const card = btn.closest('.memo')
235
+ if (!card) return
236
+ const id = card.dataset.id
237
+ const action = btn.dataset.action
238
+ if (action === 'delete') {
239
+ if (!confirm(`确定删除 memo #${id}?`)) return
240
+ try {
241
+ await window.imhub.api(`/api/memos/${id}`, { method: 'DELETE' })
242
+ toast(`已删除 #${id}`)
243
+ load()
244
+ } catch (err) { toast(`删除失败:${err.message}`, true) }
245
+ }
246
+ })
247
+
248
+ document.querySelectorAll('.filter-btn').forEach(btn => {
249
+ btn.addEventListener('click', () => {
250
+ document.querySelectorAll('.filter-btn').forEach(b => { b.classList.remove('active') })
251
+ btn.classList.add('active')
252
+ currentFilter = btn.dataset.filter
253
+ load()
254
+ })
255
+ })
256
+
257
+ $q.addEventListener('input', () => {
258
+ clearTimeout(debounceTimer)
259
+ debounceTimer = setTimeout(() => {
260
+ queryStr = $q.value.trim()
261
+ load()
262
+ }, 280)
263
+ })
264
+
265
+ load()
266
+ // Auto-refresh every 30s so newly-saved memos show up.
267
+ setInterval(load, 30_000)
268
+ })()
269
+ </script>
270
+ </body>
271
+ </html>