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,163 @@
1
+ /** UTC+8 wall-clock as `YYYY-MM-DD HH:MM:SS` — matches SQLite's `datetime()`
2
+ * output shape so cross-source comparisons are well-defined. */
3
+ export declare function nowSqliteLocal(): string;
4
+ /** Convert an absolute Date (or ms) to the local-storage shape. */
5
+ export declare function toSqliteLocal(d: Date | number): string;
6
+ /** Normalize whatever the agent passes for `when_at` into our storage shape.
7
+ * Accepts: bare ISO (assumed already local), ISO with `Z` or `±HH:MM` offset,
8
+ * or already-normalized "YYYY-MM-DD HH:MM:SS". Output: "YYYY-MM-DD HH:MM:SS"
9
+ * in UTC+8. Falls through unchanged on parse failure rather than throwing
10
+ * so an agent typo doesn't kill the save. */
11
+ export declare function normalizeWhenAt(s: string | null | undefined): string | null;
12
+ export type MemoSource = 'manual' | 'agent' | 'geocoded' | 'browser';
13
+ export interface Memo {
14
+ id: number;
15
+ platform: string;
16
+ channel_id: string;
17
+ thread_id: string;
18
+ user_id: string;
19
+ what: string;
20
+ who: string | null;
21
+ when_at: string | null;
22
+ when_text: string | null;
23
+ where_lat: number | null;
24
+ where_lng: number | null;
25
+ where_label: string | null;
26
+ how: string | null;
27
+ why: string | null;
28
+ /** Free-text full intent — preserves the user's complete phrasing when
29
+ * `what` is an extracted short noun. Optional; null when unset. */
30
+ memo: string | null;
31
+ expires_at: string | null;
32
+ source: MemoSource;
33
+ created_at: string;
34
+ updated_at: string;
35
+ }
36
+ export interface OwnerOpts {
37
+ /** Scope reads/writes/deletes to this user. Empty = unrestricted (tests
38
+ * / non-IM callers only). Production calls always pass userId. */
39
+ userId?: string;
40
+ }
41
+ export interface CreateMemoInput {
42
+ platform: string;
43
+ channelId: string;
44
+ threadId: string;
45
+ userId?: string;
46
+ what: string;
47
+ who?: string | null;
48
+ whenAt?: string | null;
49
+ whenText?: string | null;
50
+ whereLat?: number | null;
51
+ whereLng?: number | null;
52
+ whereLabel?: string | null;
53
+ how?: string | null;
54
+ why?: string | null;
55
+ /** Free-text full intent — preserve user's complete phrasing when `what`
56
+ * is a shorter extracted noun. Optional. */
57
+ memo?: string | null;
58
+ expiresAt?: string | null;
59
+ source?: MemoSource;
60
+ }
61
+ export declare function createMemo(input: CreateMemoInput): number;
62
+ export interface UpdateMemoInput {
63
+ what?: string;
64
+ who?: string | null;
65
+ whenAt?: string | null;
66
+ whenText?: string | null;
67
+ whereLat?: number | null;
68
+ whereLng?: number | null;
69
+ whereLabel?: string | null;
70
+ how?: string | null;
71
+ why?: string | null;
72
+ memo?: string | null;
73
+ expiresAt?: string | null;
74
+ }
75
+ /** Patch-style update — only fields explicitly present in the input are
76
+ * written. Pass `null` to clear a field (vs `undefined` = leave alone). */
77
+ export declare function updateMemo(id: number, input: UpdateMemoInput, opts?: OwnerOpts): boolean;
78
+ export declare function getMemo(id: number, opts?: OwnerOpts): Memo | null;
79
+ export declare function deleteMemo(id: number, opts?: OwnerOpts): boolean;
80
+ export interface SearchOpts extends OwnerOpts {
81
+ /** Free-text — matched as `LIKE %query%` against what / who / where_label /
82
+ * how / why / when_text. Single token; no AND splitting. */
83
+ query?: string;
84
+ /** LIKE filter on `who` only. */
85
+ who?: string;
86
+ /** LIKE filter on `what` only. */
87
+ what?: string;
88
+ /** When true, filter to rows where where_lat IS NOT NULL. */
89
+ hasLocation?: boolean;
90
+ /** ISO range on `when_at` (or fall back to `created_at` when when_at is null). */
91
+ whenAfter?: string;
92
+ whenBefore?: string;
93
+ /** When true, include expired rows in the result. Default: exclude. */
94
+ includeExpired?: boolean;
95
+ limit?: number;
96
+ }
97
+ /**
98
+ * Search memos. All filters are AND-combined. Empty filter set returns the
99
+ * most recent memos (= same as listMemos).
100
+ *
101
+ * Sort: `created_at DESC` (newest first). Future: relevance score.
102
+ *
103
+ * Wildcard escaping: SQL LIKE `%` and `_` in the query become literal chars
104
+ * via `LIKE ESCAPE '\\'` — the user's question-mark or percent doesn't blow
105
+ * the search wide open.
106
+ */
107
+ export declare function searchMemos(opts?: SearchOpts): Memo[];
108
+ /** Recent memos for this user. Convenience wrapper around searchMemos. */
109
+ export declare function listMemos(opts?: OwnerOpts & {
110
+ limit?: number;
111
+ }): Memo[];
112
+ export declare function sweepExpired(): number;
113
+ export declare function startSweepTimer(): void;
114
+ export declare function stopSweepTimer(): void;
115
+ export declare function closeMemosDb(): void;
116
+ export declare function parseCoordPair(input: string): {
117
+ lat: number;
118
+ lng: number;
119
+ } | null;
120
+ export declare function stripCoordPrefix(input: string): string;
121
+ export type GeocodeOutcome = {
122
+ ok: true;
123
+ lat: number;
124
+ lng: number;
125
+ formattedAddress: string;
126
+ } | {
127
+ ok: false;
128
+ reason: 'no_key' | 'quota' | 'signature' | 'not_found' | 'http' | 'unknown';
129
+ status?: number;
130
+ message?: string;
131
+ };
132
+ export declare function geocodeAddress(address: string): Promise<GeocodeOutcome>;
133
+ export declare function isGeocodingAvailable(): boolean;
134
+ export declare function wgs84ToGcj02(lat: number, lng: number): {
135
+ lat: number;
136
+ lng: number;
137
+ };
138
+ /**
139
+ * Reverse of wgs84ToGcj02. Useful when an upstream gives us GCJ-02 coords
140
+ * but our DB convention is WGS-84.
141
+ *
142
+ * Common case: iOS Core Location in China returns GCJ-02 by design (Apple
143
+ * applies the offset to comply with PRC regulations). Telegram on a Chinese
144
+ * iPhone forwards exactly those coords. Without this reverse, the values
145
+ * get re-offset when we build amap/baidu URLs → marker lands 500m–1km off.
146
+ *
147
+ * Math: GCJ→WGS doesn't have a closed-form inverse, so we use the standard
148
+ * Newton's-method-style refinement — compute the forward offset at the
149
+ * GCJ point, subtract to get a candidate WGS point, then iterate. Three
150
+ * passes converge to sub-meter precision for any reasonable input.
151
+ */
152
+ export declare function gcj02ToWgs84(lat: number, lng: number): {
153
+ lat: number;
154
+ lng: number;
155
+ };
156
+ export interface MapUrls {
157
+ baidu: string;
158
+ amap: string;
159
+ google: string;
160
+ }
161
+ export declare function mapUrls(lat: number, lng: number, label?: string, addr?: string): MapUrls;
162
+ export declare function mapUrl(lat: number, lng: number, label?: string, addr?: string): string;
163
+ //# sourceMappingURL=memos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memos.d.ts","sourceRoot":"","sources":["../../src/core/memos.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,502 @@
1
+ // memos.ts — generalized "记下来" memory database.
2
+ //
3
+ // Each memo carries optional 5W1H fields:
4
+ // what — the core thing (REQUIRED, the only required column)
5
+ // who — person / org / role involved
6
+ // when_at — ISO-8601 local datetime, parseable timestamp
7
+ // when_text — raw user phrase if not parseable ("明年5月" etc.)
8
+ // where_lat / where_lng / where_label — geo location (full triple, partial, or none)
9
+ // how — manner / process
10
+ // why — reason / motivation
11
+ //
12
+ // Lifecycle: every row carries an optional `expires_at`. NULL = permanent;
13
+ // otherwise a background sweep purges rows past their expiry. Used to make
14
+ // transient state (parking spot, today's meeting room) self-clean while
15
+ // durable info (birthdays, contacts) persists.
16
+ //
17
+ // Storage: ~/.im-hub/memos.db (SQLite, fail-soft via sqlite-helper).
18
+ // Owner-scoped per (platform, user_id), same pattern as /remind, /cron.
19
+ import { join } from 'node:path';
20
+ import { logger as rootLogger } from './logger.js';
21
+ import { createSqliteHelper } from './sqlite-helper.js';
22
+ import { AGIM_HOME } from './agim-paths.js';
23
+ const log = rootLogger.child({ component: 'memos' });
24
+ const DB_FILE = process.env.IMHUB_MEMOS_DB || join(AGIM_HOME, 'memos.db');
25
+ // ─── Time / timezone ───────────────────────────────────────────────────
26
+ // All timestamps are stored in UTC+8 (Asia/Shanghai) wall-clock format,
27
+ // matching SQLite's `datetime()` shape: "YYYY-MM-DD HH:MM:SS". This keeps
28
+ // JS-set values (expires_at, created_at when overridden) and SQL-set
29
+ // values (`datetime('now', '+8 hours')` in default + sweep + search)
30
+ // lexicographically comparable. UTC+8 matches the deployment's user base
31
+ // (CN); for other regions, the offset is overridable via env.
32
+ const TZ_OFFSET_HOURS = Number(process.env.IMHUB_TZ_OFFSET_HOURS ?? 8);
33
+ const TZ_OFFSET_MS = TZ_OFFSET_HOURS * 3600_000;
34
+ const TZ_SHIFT_SQL = `'+${TZ_OFFSET_HOURS} hours'`; // for datetime('now', ...)
35
+ /** UTC+8 wall-clock as `YYYY-MM-DD HH:MM:SS` — matches SQLite's `datetime()`
36
+ * output shape so cross-source comparisons are well-defined. */
37
+ export function nowSqliteLocal() {
38
+ return new Date(Date.now() + TZ_OFFSET_MS).toISOString().slice(0, 19).replace('T', ' ');
39
+ }
40
+ /** Convert an absolute Date (or ms) to the local-storage shape. */
41
+ export function toSqliteLocal(d) {
42
+ const ms = typeof d === 'number' ? d : d.getTime();
43
+ return new Date(ms + TZ_OFFSET_MS).toISOString().slice(0, 19).replace('T', ' ');
44
+ }
45
+ /** Normalize whatever the agent passes for `when_at` into our storage shape.
46
+ * Accepts: bare ISO (assumed already local), ISO with `Z` or `±HH:MM` offset,
47
+ * or already-normalized "YYYY-MM-DD HH:MM:SS". Output: "YYYY-MM-DD HH:MM:SS"
48
+ * in UTC+8. Falls through unchanged on parse failure rather than throwing
49
+ * so an agent typo doesn't kill the save. */
50
+ export function normalizeWhenAt(s) {
51
+ if (!s)
52
+ return null;
53
+ const trimmed = s.trim();
54
+ if (!trimmed)
55
+ return null;
56
+ // Has explicit TZ marker → parse + convert.
57
+ if (/Z$|[+\-]\d{2}:\d{2}$/.test(trimmed)) {
58
+ const ms = Date.parse(trimmed);
59
+ if (!Number.isFinite(ms))
60
+ return trimmed;
61
+ return toSqliteLocal(ms);
62
+ }
63
+ // Bare — assume already in our local zone. Normalize T→space, trim ms.
64
+ return trimmed.replace('T', ' ').slice(0, 19);
65
+ }
66
+ const helper = createSqliteHelper({
67
+ file: DB_FILE,
68
+ component: 'memos',
69
+ logger: rootLogger,
70
+ schema: `
71
+ CREATE TABLE IF NOT EXISTS memos (
72
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
73
+ platform TEXT NOT NULL,
74
+ channel_id TEXT NOT NULL,
75
+ thread_id TEXT NOT NULL,
76
+ user_id TEXT NOT NULL DEFAULT '',
77
+
78
+ what TEXT NOT NULL,
79
+ who TEXT,
80
+ when_at TEXT,
81
+ when_text TEXT,
82
+ where_lat REAL,
83
+ where_lng REAL,
84
+ where_label TEXT,
85
+ how TEXT,
86
+ why TEXT,
87
+ memo TEXT,
88
+
89
+ expires_at TEXT,
90
+ source TEXT NOT NULL DEFAULT 'agent',
91
+ created_at TEXT NOT NULL DEFAULT (datetime('now', '+8 hours')),
92
+ updated_at TEXT NOT NULL DEFAULT (datetime('now', '+8 hours'))
93
+ );
94
+ -- Idempotent migration for DBs that pre-date the memo column. SQLite
95
+ -- doesn't have ADD COLUMN IF NOT EXISTS; the helper's exec ignores
96
+ -- "duplicate column" errors via the migrate hook below.
97
+ CREATE INDEX IF NOT EXISTS idx_memos_user_recent
98
+ ON memos(platform, user_id, created_at DESC);
99
+ CREATE INDEX IF NOT EXISTS idx_memos_expires
100
+ ON memos(expires_at);
101
+ CREATE INDEX IF NOT EXISTS idx_memos_what ON memos(what);
102
+ CREATE INDEX IF NOT EXISTS idx_memos_who ON memos(who);
103
+ `,
104
+ init: (db) => {
105
+ // ALTER TABLE ADD COLUMN — idempotent: catch "duplicate column" and
106
+ // proceed. New DBs already got the column via CREATE TABLE above;
107
+ // old DBs (created before this column existed) get it here.
108
+ try {
109
+ db.exec("ALTER TABLE memos ADD COLUMN memo TEXT");
110
+ }
111
+ catch (err) {
112
+ const msg = err instanceof Error ? err.message : String(err);
113
+ if (!/duplicate column|already exists/i.test(msg))
114
+ throw err;
115
+ }
116
+ },
117
+ });
118
+ // ─── Validation ─────────────────────────────────────────────────────────
119
+ function assertCoords(lat, lng) {
120
+ if (lat == null && lng == null)
121
+ return; // both null is fine — no location
122
+ if (lat == null || lng == null)
123
+ throw new Error('lat and lng must both be set or both null');
124
+ if (!Number.isFinite(lat) || lat < -90 || lat > 90)
125
+ throw new Error(`invalid latitude: ${lat}`);
126
+ if (!Number.isFinite(lng) || lng < -180 || lng > 180)
127
+ throw new Error(`invalid longitude: ${lng}`);
128
+ }
129
+ export function createMemo(input) {
130
+ if (!input.what || !input.what.trim())
131
+ throw new Error('what is required');
132
+ assertCoords(input.whereLat, input.whereLng);
133
+ const d = helper.get();
134
+ if (!d)
135
+ throw new Error('memos DB unavailable (sqlite disabled?)');
136
+ const now = nowSqliteLocal(); // UTC+8 wall-clock — same shape as SQLite default
137
+ const whenAt = normalizeWhenAt(input.whenAt);
138
+ const expiresAt = normalizeWhenAt(input.expiresAt); // accept agent-supplied ISO with TZ offset
139
+ const stmt = d.prepare(`INSERT INTO memos
140
+ (platform, channel_id, thread_id, user_id,
141
+ what, who, when_at, when_text,
142
+ where_lat, where_lng, where_label,
143
+ how, why, memo,
144
+ expires_at, source,
145
+ created_at, updated_at)
146
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
147
+ const r = stmt.run(input.platform, input.channelId, input.threadId, input.userId ?? '', input.what.trim().slice(0, 200), input.who ?? null, whenAt, input.whenText ?? null, input.whereLat ?? null, input.whereLng ?? null, input.whereLabel ?? null, input.how ?? null, input.why ?? null, input.memo ?? null, expiresAt, input.source ?? 'agent', now, now);
148
+ log.info({
149
+ event: 'memos.created',
150
+ id: r.lastInsertRowid, platform: input.platform, userId: input.userId,
151
+ what: input.what, hasLocation: input.whereLat != null,
152
+ expiresAt, source: input.source,
153
+ });
154
+ return Number(r.lastInsertRowid);
155
+ }
156
+ /** Patch-style update — only fields explicitly present in the input are
157
+ * written. Pass `null` to clear a field (vs `undefined` = leave alone). */
158
+ export function updateMemo(id, input, opts = {}) {
159
+ if (input.what !== undefined && (!input.what || !input.what.trim())) {
160
+ throw new Error('what cannot be empty when updating');
161
+ }
162
+ if (input.whereLat !== undefined || input.whereLng !== undefined) {
163
+ // Only validate if BOTH fields are being set; partial updates of just
164
+ // one half are caller bugs but we don't want to assert against null
165
+ // when the other is being set to null too.
166
+ if (input.whereLat != null && input.whereLng != null) {
167
+ assertCoords(input.whereLat, input.whereLng);
168
+ }
169
+ }
170
+ const d = helper.get();
171
+ if (!d)
172
+ return false;
173
+ const sets = [];
174
+ const args = [];
175
+ const setIf = (col, val) => {
176
+ sets.push(`${col} = ?`);
177
+ args.push(val);
178
+ };
179
+ if (input.what !== undefined)
180
+ setIf('what', input.what.trim().slice(0, 200));
181
+ if (input.who !== undefined)
182
+ setIf('who', input.who);
183
+ if (input.whenAt !== undefined)
184
+ setIf('when_at', input.whenAt === null ? null : normalizeWhenAt(input.whenAt));
185
+ if (input.whenText !== undefined)
186
+ setIf('when_text', input.whenText);
187
+ if (input.whereLat !== undefined)
188
+ setIf('where_lat', input.whereLat);
189
+ if (input.whereLng !== undefined)
190
+ setIf('where_lng', input.whereLng);
191
+ if (input.whereLabel !== undefined)
192
+ setIf('where_label', input.whereLabel);
193
+ if (input.how !== undefined)
194
+ setIf('how', input.how);
195
+ if (input.why !== undefined)
196
+ setIf('why', input.why);
197
+ if (input.memo !== undefined)
198
+ setIf('memo', input.memo);
199
+ if (input.expiresAt !== undefined)
200
+ setIf('expires_at', input.expiresAt === null ? null : normalizeWhenAt(input.expiresAt));
201
+ if (sets.length === 0)
202
+ return false;
203
+ // Stamp updated_at with the same UTC+8 shape as create + sweep.
204
+ sets.push(`updated_at = ?`);
205
+ args.push(nowSqliteLocal());
206
+ const where = opts.userId ? 'id = ? AND user_id = ?' : 'id = ?';
207
+ const sql = `UPDATE memos SET ${sets.join(', ')} WHERE ${where}`;
208
+ args.push(id);
209
+ if (opts.userId)
210
+ args.push(opts.userId);
211
+ try {
212
+ const r = d.prepare(sql).run(...args);
213
+ log.info({ event: 'memos.updated', id, fields: sets.length - 1, changed: r.changes > 0 });
214
+ return r.changes > 0;
215
+ }
216
+ catch (err) {
217
+ log.warn({ event: 'memos.update_failed', err: err instanceof Error ? err.message : String(err) });
218
+ return false;
219
+ }
220
+ }
221
+ export function getMemo(id, opts = {}) {
222
+ return helper.safe((d) => {
223
+ const row = opts.userId
224
+ ? d.prepare('SELECT * FROM memos WHERE id = ? AND user_id = ?').get(id, opts.userId)
225
+ : d.prepare('SELECT * FROM memos WHERE id = ?').get(id);
226
+ return row ?? null;
227
+ }, null);
228
+ }
229
+ export function deleteMemo(id, opts = {}) {
230
+ return helper.safe((d) => {
231
+ const stmt = opts.userId
232
+ ? d.prepare('DELETE FROM memos WHERE id = ? AND user_id = ?')
233
+ : d.prepare('DELETE FROM memos WHERE id = ?');
234
+ const r = opts.userId ? stmt.run(id, opts.userId) : stmt.run(id);
235
+ return r.changes > 0;
236
+ }, false);
237
+ }
238
+ /**
239
+ * Search memos. All filters are AND-combined. Empty filter set returns the
240
+ * most recent memos (= same as listMemos).
241
+ *
242
+ * Sort: `created_at DESC` (newest first). Future: relevance score.
243
+ *
244
+ * Wildcard escaping: SQL LIKE `%` and `_` in the query become literal chars
245
+ * via `LIKE ESCAPE '\\'` — the user's question-mark or percent doesn't blow
246
+ * the search wide open.
247
+ */
248
+ export function searchMemos(opts = {}) {
249
+ const limit = Math.min(Math.max(opts.limit ?? 10, 1), 50);
250
+ const wheres = [];
251
+ const args = [];
252
+ if (opts.userId) {
253
+ wheres.push('user_id = ?');
254
+ args.push(opts.userId);
255
+ }
256
+ if (!opts.includeExpired) {
257
+ // Keep rows where expires_at IS NULL (permanent) OR > now (UTC+8).
258
+ // Comparing UTC+8 stored shape against UTC+8 wall-clock — same TZ both
259
+ // sides, lexicographic compare correct around midnight crossings.
260
+ wheres.push(`(expires_at IS NULL OR expires_at > datetime('now', ${TZ_SHIFT_SQL}))`);
261
+ }
262
+ if (opts.hasLocation)
263
+ wheres.push('where_lat IS NOT NULL');
264
+ const escapeLike = (s) => s.replace(/[\\%_]/g, (c) => `\\${c}`);
265
+ if (opts.query?.trim()) {
266
+ const p = `%${escapeLike(opts.query.trim())}%`;
267
+ wheres.push(`(
268
+ what LIKE ? ESCAPE '\\' OR who LIKE ? ESCAPE '\\' OR
269
+ where_label LIKE ? ESCAPE '\\' OR how LIKE ? ESCAPE '\\' OR
270
+ why LIKE ? ESCAPE '\\' OR when_text LIKE ? ESCAPE '\\' OR
271
+ memo LIKE ? ESCAPE '\\'
272
+ )`);
273
+ for (let i = 0; i < 7; i++)
274
+ args.push(p);
275
+ }
276
+ if (opts.who?.trim()) {
277
+ wheres.push(`who LIKE ? ESCAPE '\\'`);
278
+ args.push(`%${escapeLike(opts.who.trim())}%`);
279
+ }
280
+ if (opts.what?.trim()) {
281
+ wheres.push(`what LIKE ? ESCAPE '\\'`);
282
+ args.push(`%${escapeLike(opts.what.trim())}%`);
283
+ }
284
+ if (opts.whenAfter) {
285
+ const v = normalizeWhenAt(opts.whenAfter);
286
+ if (v) {
287
+ wheres.push(`COALESCE(when_at, created_at) >= ?`);
288
+ args.push(v);
289
+ }
290
+ }
291
+ if (opts.whenBefore) {
292
+ const v = normalizeWhenAt(opts.whenBefore);
293
+ if (v) {
294
+ wheres.push(`COALESCE(when_at, created_at) <= ?`);
295
+ args.push(v);
296
+ }
297
+ }
298
+ const sql = `SELECT * FROM memos${wheres.length ? ' WHERE ' + wheres.join(' AND ') : ''} ORDER BY id DESC LIMIT ?`;
299
+ args.push(limit);
300
+ return helper.safe((d) => d.prepare(sql).all(...args), []);
301
+ }
302
+ /** Recent memos for this user. Convenience wrapper around searchMemos. */
303
+ export function listMemos(opts = {}) {
304
+ return searchMemos({ userId: opts.userId, limit: opts.limit });
305
+ }
306
+ // ─── Expiry sweep ───────────────────────────────────────────────────────
307
+ let sweepTimer = null;
308
+ const SWEEP_INTERVAL_MS = 5 * 60 * 1000; // every 5 min
309
+ export function sweepExpired() {
310
+ return helper.safe((d) => {
311
+ const r = d.prepare(`DELETE FROM memos WHERE expires_at IS NOT NULL AND expires_at <= datetime('now', ${TZ_SHIFT_SQL})`).run();
312
+ if (r.changes > 0)
313
+ log.info({ event: 'memos.sweep', removed: r.changes });
314
+ return r.changes;
315
+ }, 0);
316
+ }
317
+ export function startSweepTimer() {
318
+ if (sweepTimer)
319
+ return;
320
+ // First sweep on startup so anything stale from before this process boot
321
+ // gets cleaned promptly; subsequent sweeps every interval.
322
+ sweepExpired();
323
+ sweepTimer = setInterval(sweepExpired, SWEEP_INTERVAL_MS);
324
+ sweepTimer.unref();
325
+ log.info({ event: 'memos.sweep_timer_started', intervalMs: SWEEP_INTERVAL_MS });
326
+ }
327
+ export function stopSweepTimer() {
328
+ if (sweepTimer) {
329
+ clearInterval(sweepTimer);
330
+ sweepTimer = null;
331
+ }
332
+ }
333
+ export function closeMemosDb() {
334
+ stopSweepTimer();
335
+ helper.close();
336
+ }
337
+ // ─── Coordinate helpers (kept from old locations.ts) ────────────────────
338
+ export function parseCoordPair(input) {
339
+ const trimmed = input.trim();
340
+ const m = trimmed.match(/^(-?\d+(?:\.\d+)?)\s*[,,\s]\s*(-?\d+(?:\.\d+)?)\b/);
341
+ if (!m)
342
+ return null;
343
+ const lat = Number(m[1]);
344
+ const lng = Number(m[2]);
345
+ if (!Number.isFinite(lat) || !Number.isFinite(lng))
346
+ return null;
347
+ if (lat < -90 || lat > 90 || lng < -180 || lng > 180)
348
+ return null;
349
+ return { lat, lng };
350
+ }
351
+ export function stripCoordPrefix(input) {
352
+ return input.replace(/^(-?\d+(?:\.\d+)?)\s*[,,\s]\s*(-?\d+(?:\.\d+)?)\b\s*/, '').trim();
353
+ }
354
+ function classifyStatus(status) {
355
+ if (status === 1 || status === 2 || status === 3 || status === 4)
356
+ return 'not_found';
357
+ if (status === 200 || status === 201 || status === 202)
358
+ return 'signature';
359
+ if (status >= 401 && status <= 405)
360
+ return 'quota';
361
+ if (status === 240 || status === 220 || status === 211 || status === 210)
362
+ return 'quota';
363
+ if (status === 5)
364
+ return 'signature';
365
+ return 'unknown';
366
+ }
367
+ export async function geocodeAddress(address) {
368
+ const ak = process.env.IMHUB_BAIDU_MAP_AK;
369
+ if (!ak) {
370
+ log.debug({ event: 'memos.geocode.no_key' });
371
+ return { ok: false, reason: 'no_key' };
372
+ }
373
+ const url = new URL('https://api.map.baidu.com/geocoding/v3/');
374
+ url.searchParams.set('address', address);
375
+ url.searchParams.set('output', 'json');
376
+ url.searchParams.set('ret_coordtype', 'wgs84ll');
377
+ url.searchParams.set('ak', ak);
378
+ try {
379
+ const ctrl = new AbortController();
380
+ const timer = setTimeout(() => ctrl.abort(), 8000);
381
+ const res = await fetch(url.toString(), { signal: ctrl.signal });
382
+ clearTimeout(timer);
383
+ if (!res.ok)
384
+ return { ok: false, reason: 'http', status: res.status };
385
+ const data = (await res.json());
386
+ if (data.status === 0 && data.result?.location) {
387
+ const { lat, lng } = data.result.location;
388
+ return { ok: true, lat, lng, formattedAddress: address };
389
+ }
390
+ const reason = classifyStatus(data.status);
391
+ log.info({ event: 'memos.geocode.miss', status: data.status, reason, address });
392
+ return { ok: false, reason, status: data.status, message: data.message || data.msg };
393
+ }
394
+ catch (err) {
395
+ return { ok: false, reason: 'unknown', message: err instanceof Error ? err.message : String(err) };
396
+ }
397
+ }
398
+ export function isGeocodingAvailable() {
399
+ return !!process.env.IMHUB_BAIDU_MAP_AK;
400
+ }
401
+ // ─── Map URL builders (Baidu / Amap / Google) ───────────────────────────
402
+ // Same WGS-84 → provider-coords plumbing as before. Stored coords are always
403
+ // WGS-84; each provider URI gets the right coord-type hint.
404
+ export function wgs84ToGcj02(lat, lng) {
405
+ if (outOfChina(lat, lng))
406
+ return { lat, lng };
407
+ const A = 6378245.0;
408
+ const EE = 0.006693421622965943;
409
+ const PI = Math.PI;
410
+ let dLat = transformLat(lng - 105.0, lat - 35.0);
411
+ let dLng = transformLng(lng - 105.0, lat - 35.0);
412
+ const radLat = (lat / 180.0) * PI;
413
+ let magic = Math.sin(radLat);
414
+ magic = 1 - EE * magic * magic;
415
+ const sqrtMagic = Math.sqrt(magic);
416
+ dLat = (dLat * 180.0) / (((A * (1 - EE)) / (magic * sqrtMagic)) * PI);
417
+ dLng = (dLng * 180.0) / ((A / sqrtMagic) * Math.cos(radLat) * PI);
418
+ return { lat: lat + dLat, lng: lng + dLng };
419
+ }
420
+ /**
421
+ * Reverse of wgs84ToGcj02. Useful when an upstream gives us GCJ-02 coords
422
+ * but our DB convention is WGS-84.
423
+ *
424
+ * Common case: iOS Core Location in China returns GCJ-02 by design (Apple
425
+ * applies the offset to comply with PRC regulations). Telegram on a Chinese
426
+ * iPhone forwards exactly those coords. Without this reverse, the values
427
+ * get re-offset when we build amap/baidu URLs → marker lands 500m–1km off.
428
+ *
429
+ * Math: GCJ→WGS doesn't have a closed-form inverse, so we use the standard
430
+ * Newton's-method-style refinement — compute the forward offset at the
431
+ * GCJ point, subtract to get a candidate WGS point, then iterate. Three
432
+ * passes converge to sub-meter precision for any reasonable input.
433
+ */
434
+ export function gcj02ToWgs84(lat, lng) {
435
+ if (outOfChina(lat, lng))
436
+ return { lat, lng };
437
+ let wgsLat = lat;
438
+ let wgsLng = lng;
439
+ for (let i = 0; i < 3; i++) {
440
+ const forward = wgs84ToGcj02(wgsLat, wgsLng);
441
+ wgsLat = lat - (forward.lat - wgsLat);
442
+ wgsLng = lng - (forward.lng - wgsLng);
443
+ }
444
+ return { lat: wgsLat, lng: wgsLng };
445
+ }
446
+ function outOfChina(lat, lng) {
447
+ return lng < 72.004 || lng > 137.8347 || lat < 0.8293 || lat > 55.8271;
448
+ }
449
+ function transformLat(x, y) {
450
+ const PI = Math.PI;
451
+ let r = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
452
+ r += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0;
453
+ r += ((20.0 * Math.sin(y * PI) + 40.0 * Math.sin((y / 3.0) * PI)) * 2.0) / 3.0;
454
+ r += ((160.0 * Math.sin((y / 12.0) * PI) + 320 * Math.sin((y * PI) / 30.0)) * 2.0) / 3.0;
455
+ return r;
456
+ }
457
+ function transformLng(x, y) {
458
+ const PI = Math.PI;
459
+ let r = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
460
+ r += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0;
461
+ r += ((20.0 * Math.sin(x * PI) + 40.0 * Math.sin((x / 3.0) * PI)) * 2.0) / 3.0;
462
+ r += ((150.0 * Math.sin((x / 12.0) * PI) + 300.0 * Math.sin((x / 30.0) * PI)) * 2.0) / 3.0;
463
+ return r;
464
+ }
465
+ export function mapUrls(lat, lng, label = '', addr = '') {
466
+ return {
467
+ baidu: buildBaiduUrl(lat, lng, label, addr),
468
+ amap: buildAmapUrl(lat, lng, label),
469
+ google: buildGoogleUrl(lat, lng),
470
+ };
471
+ }
472
+ export function mapUrl(lat, lng, label = '', addr = '') {
473
+ return buildBaiduUrl(lat, lng, label, addr);
474
+ }
475
+ function buildBaiduUrl(lat, lng, label, addr) {
476
+ const url = new URL('https://api.map.baidu.com/marker');
477
+ url.searchParams.set('location', `${lat},${lng}`);
478
+ if (label)
479
+ url.searchParams.set('title', label);
480
+ if (addr)
481
+ url.searchParams.set('content', addr);
482
+ url.searchParams.set('output', 'html');
483
+ url.searchParams.set('coord_type', 'wgs84');
484
+ url.searchParams.set('src', 'imhub');
485
+ return url.toString();
486
+ }
487
+ function buildAmapUrl(lat, lng, label) {
488
+ const gcj = wgs84ToGcj02(lat, lng);
489
+ const url = new URL('https://uri.amap.com/marker');
490
+ url.searchParams.set('position', `${gcj.lng},${gcj.lat}`);
491
+ if (label)
492
+ url.searchParams.set('name', label);
493
+ url.searchParams.set('src', 'imhub');
494
+ url.searchParams.set('coordinate', 'gaode');
495
+ return url.toString();
496
+ }
497
+ function buildGoogleUrl(lat, lng) {
498
+ const url = new URL('https://www.google.com/maps');
499
+ url.searchParams.set('q', `${lat},${lng}`);
500
+ return url.toString();
501
+ }
502
+ //# sourceMappingURL=memos.js.map