clawmini 0.0.7 → 0.0.9

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 (367) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +14 -0
  3. package/.github/workflows/release.yml +49 -0
  4. package/CHANGELOG.md +36 -0
  5. package/README.md +5 -4
  6. package/dist/adapter-discord/index.d.mts.map +1 -1
  7. package/dist/adapter-discord/index.mjs +465 -282
  8. package/dist/adapter-discord/index.mjs.map +1 -1
  9. package/dist/adapter-google-chat/index.mjs +367 -243
  10. package/dist/adapter-google-chat/index.mjs.map +1 -1
  11. package/dist/cli/index.mjs +684 -24
  12. package/dist/cli/index.mjs.map +1 -1
  13. package/dist/cli/lite.mjs +43 -13
  14. package/dist/cli/lite.mjs.map +1 -1
  15. package/dist/cli/{propose-policy.mjs → manage-policies.mjs} +270 -47
  16. package/dist/cli/manage-policies.mjs.map +1 -0
  17. package/dist/cli/run-host.d.mts +1 -0
  18. package/dist/cli/run-host.mjs +3090 -0
  19. package/dist/cli/run-host.mjs.map +1 -0
  20. package/dist/config-CPFQIGdG.mjs +57 -0
  21. package/dist/config-CPFQIGdG.mjs.map +1 -0
  22. package/dist/config-Dvl-Pov4.mjs +76 -0
  23. package/dist/config-Dvl-Pov4.mjs.map +1 -0
  24. package/dist/daemon/index.d.mts.map +1 -1
  25. package/dist/daemon/index.mjs +970 -332
  26. package/dist/daemon/index.mjs.map +1 -1
  27. package/dist/supervisor-actions-CiW56eLi.mjs +843 -0
  28. package/dist/supervisor-actions-CiW56eLi.mjs.map +1 -0
  29. package/dist/turn-log-buffer-DRgW53gl.mjs +767 -0
  30. package/dist/turn-log-buffer-DRgW53gl.mjs.map +1 -0
  31. package/dist/web/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
  32. package/dist/web/_app/immutable/chunks/BhRSsUCh.js +2 -0
  33. package/dist/web/_app/immutable/chunks/BiLeM2i1.js +1 -0
  34. package/{web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js → dist/web/_app/immutable/chunks/BmBj85Ll.js} +1 -1
  35. package/dist/web/_app/immutable/chunks/BrERcKAH.js +1 -0
  36. package/dist/web/_app/immutable/chunks/Bv9252RM.js +1 -0
  37. package/dist/web/_app/immutable/chunks/CIXNBPKi.js +1 -0
  38. package/dist/web/_app/immutable/chunks/DISKL3GN.js +2 -0
  39. package/dist/web/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
  40. package/dist/web/_app/immutable/chunks/DnQ3vS13.js +1 -0
  41. package/dist/web/_app/immutable/chunks/KsloHTKS.js +1 -0
  42. package/{web/.svelte-kit/output/client/_app/immutable/chunks/Ck-be5J2.js → dist/web/_app/immutable/chunks/RsHsUj-8.js} +2 -2
  43. package/dist/web/_app/immutable/chunks/{G_zz-Gou.js → wpfV79dV.js} +1 -1
  44. package/dist/web/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
  45. package/dist/web/_app/immutable/entry/start.Di0-Jhte.js +1 -0
  46. package/dist/web/_app/immutable/nodes/{0.CYS8iApT.js → 0.DYyUA1au.js} +1 -1
  47. package/dist/web/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
  48. package/dist/web/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
  49. package/{web/.svelte-kit/output/client/_app/immutable/nodes/3.Dr0ot9sV.js → dist/web/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
  50. package/dist/web/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
  51. package/dist/web/_app/immutable/nodes/{5.BBGQ_i84.js → 5.DLbPVJY2.js} +1 -1
  52. package/dist/web/_app/version.json +1 -1
  53. package/dist/web/index.html +12 -12
  54. package/dist/workspace-oWmVh5mi.mjs +1001 -0
  55. package/dist/workspace-oWmVh5mi.mjs.map +1 -0
  56. package/docs/23_adapter_slash_autocomplete/development_log.md +19 -0
  57. package/docs/23_adapter_slash_autocomplete/notes.md +18 -0
  58. package/docs/23_adapter_slash_autocomplete/prd.md +46 -0
  59. package/docs/23_adapter_slash_autocomplete/questions.md +6 -0
  60. package/docs/23_adapter_slash_autocomplete/tickets.md +21 -0
  61. package/docs/24_subagent_job_policy_fixes/development_log.md +22 -0
  62. package/docs/24_subagent_job_policy_fixes/notes.md +28 -0
  63. package/docs/24_subagent_job_policy_fixes/prd.md +59 -0
  64. package/docs/24_subagent_job_policy_fixes/questions.md +3 -0
  65. package/docs/24_subagent_job_policy_fixes/tickets.md +49 -0
  66. package/docs/25_e2e_test_improvements/development_log.md +30 -0
  67. package/docs/25_e2e_test_improvements/notes.md +29 -0
  68. package/docs/25_e2e_test_improvements/prd.md +43 -0
  69. package/docs/25_e2e_test_improvements/questions.md +12 -0
  70. package/docs/25_e2e_test_improvements/tickets-2.md +22 -0
  71. package/docs/25_e2e_test_improvements/tickets.md +22 -0
  72. package/docs/25_policy_cwd/development_log.md +30 -0
  73. package/docs/25_policy_cwd/notes.md +28 -0
  74. package/docs/25_policy_cwd/prd.md +77 -0
  75. package/docs/25_policy_cwd/questions.md +6 -0
  76. package/docs/25_policy_cwd/tickets.md +77 -0
  77. package/docs/CLI_REFERENCE.md +3 -1
  78. package/docs/PHILOSOPHY.md +35 -0
  79. package/docs/adapter-visibility/SPEC.md +461 -0
  80. package/docs/adapter-visibility/SPEC_v2.md +202 -0
  81. package/docs/auto-update/SPEC.md +344 -0
  82. package/docs/backups/SPEC.md +296 -0
  83. package/docs/backups/clawmini.gitignore +69 -0
  84. package/docs/guides/assets/clawmini-avatar.png +0 -0
  85. package/docs/guides/backups.md +332 -0
  86. package/docs/guides/discord_adapter_setup.md +1 -1
  87. package/docs/guides/google_chat_adapter_setup.md +81 -0
  88. package/docs/unified-startup/SPEC.md +203 -0
  89. package/e2e/_helpers/test-environment.test.ts +49 -0
  90. package/e2e/_helpers/test-environment.ts +548 -0
  91. package/e2e/adapters/_google-chat-fixtures.ts +340 -0
  92. package/{src/cli/e2e → e2e/adapters}/adapter-discord.test.ts +22 -23
  93. package/e2e/adapters/adapter-google-chat-downtime.test.ts +157 -0
  94. package/e2e/adapters/adapter-google-chat-inbound.test.ts +697 -0
  95. package/e2e/adapters/adapter-google-chat-outbound.test.ts +297 -0
  96. package/e2e/adapters/adapter-google-chat-roundtrip.test.ts +56 -0
  97. package/e2e/adapters/adapter-google-chat-threads.test.ts +1078 -0
  98. package/e2e/agents/custom-api-env.test.ts +80 -0
  99. package/e2e/agents/export-lite-func.test.ts +104 -0
  100. package/e2e/agents/fallbacks.test.ts +124 -0
  101. package/e2e/agents/interrupt.test.ts +50 -0
  102. package/e2e/agents/no-reply-necessary.test.ts +57 -0
  103. package/e2e/agents/session-timeout-subagents.test.ts +76 -0
  104. package/e2e/agents/subagent-authorization.test.ts +246 -0
  105. package/e2e/agents/subagent-env.test.ts +49 -0
  106. package/e2e/agents/subagent-lifecycle.test.ts +782 -0
  107. package/e2e/agents/subagents-depth.test.ts +47 -0
  108. package/e2e/cli/agents.test.ts +176 -0
  109. package/e2e/cli/auto-update.test.ts +741 -0
  110. package/e2e/cli/basic.test.ts +44 -0
  111. package/{src/cli/e2e → e2e/cli}/export-lite.test.ts +16 -12
  112. package/e2e/cli/init-gitignore.test.ts +86 -0
  113. package/e2e/cli/init.test.ts +76 -0
  114. package/e2e/cli/messages.test.ts +363 -0
  115. package/e2e/cli/serve.test.ts +76 -0
  116. package/{src/cli/e2e → e2e/cli}/skills.test.ts +11 -10
  117. package/{src/cli/e2e → e2e/daemon}/daemon.test.ts +57 -195
  118. package/e2e/jobs/agent-jobs.test.ts +216 -0
  119. package/e2e/jobs/cron.test.ts +64 -0
  120. package/e2e/jobs/restart.test.ts +108 -0
  121. package/e2e/policies/approval-session.test.ts +69 -0
  122. package/e2e/policies/auto-create-policies-file.test.ts +35 -0
  123. package/e2e/policies/builtin-manage-policies.test.ts +184 -0
  124. package/e2e/policies/builtin-run-host.test.ts +180 -0
  125. package/e2e/policies/environment-policies.test.ts +177 -0
  126. package/e2e/policies/manage-policies.test.ts +566 -0
  127. package/e2e/policies/output-size.test.ts +98 -0
  128. package/e2e/policies/policies-context-cwd.test.ts +160 -0
  129. package/e2e/policies/relative-script-path.test.ts +60 -0
  130. package/e2e/policies/requests-show.test.ts +135 -0
  131. package/e2e/policies/requests.test.ts +208 -0
  132. package/e2e/policies/slash-policies.test.ts +308 -0
  133. package/e2e/policies/startup-cleanup.test.ts +48 -0
  134. package/e2e/routers/session-timeout.test.ts +106 -0
  135. package/e2e/routers/slash-model.test.ts +152 -0
  136. package/e2e/routers/slash-new.test.ts +50 -0
  137. package/e2e/routers/slash-restart-adapter.test.ts +96 -0
  138. package/e2e/routers/slash-restart.test.ts +114 -0
  139. package/e2e/routers/slash-shutdown.test.ts +55 -0
  140. package/e2e/routers/slash-stop.test.ts +232 -0
  141. package/e2e/routers/slash-upgrade.test.ts +88 -0
  142. package/{src/cli/e2e → e2e/sandbox}/environments.test.ts +14 -13
  143. package/eslint.config.js +6 -0
  144. package/napkin.md +1 -1
  145. package/package.json +8 -3
  146. package/src/adapter-discord/commands.test.ts +42 -0
  147. package/src/adapter-discord/commands.ts +33 -0
  148. package/src/adapter-discord/config.ts +12 -0
  149. package/src/adapter-discord/forwarder.test.ts +499 -21
  150. package/src/adapter-discord/forwarder.ts +343 -124
  151. package/src/adapter-discord/inbound-cache.test.ts +47 -0
  152. package/src/adapter-discord/inbound-cache.ts +37 -0
  153. package/src/adapter-discord/index.test.ts +67 -2
  154. package/src/adapter-discord/index.ts +84 -216
  155. package/src/adapter-discord/interactions.test.ts +54 -3
  156. package/src/adapter-discord/interactions.ts +97 -53
  157. package/src/adapter-discord/processMessage.ts +239 -0
  158. package/src/adapter-discord/state.ts +1 -0
  159. package/src/adapter-google-chat/auth.test.ts +9 -5
  160. package/src/adapter-google-chat/auth.ts +29 -23
  161. package/src/adapter-google-chat/cards.ts +7 -2
  162. package/src/adapter-google-chat/client.test.ts +37 -2
  163. package/src/adapter-google-chat/client.ts +138 -38
  164. package/src/adapter-google-chat/config.ts +19 -0
  165. package/src/adapter-google-chat/forwarder.test.ts +81 -56
  166. package/src/adapter-google-chat/forwarder.ts +394 -185
  167. package/src/adapter-google-chat/inbound-cache.test.ts +61 -0
  168. package/src/adapter-google-chat/inbound-cache.ts +36 -0
  169. package/src/adapter-google-chat/state.test.ts +1 -0
  170. package/src/adapter-google-chat/state.ts +9 -1
  171. package/src/adapter-google-chat/subscriptions.ts +8 -6
  172. package/src/cli/builtin-policies.ts +44 -0
  173. package/src/cli/commands/agents.ts +59 -5
  174. package/src/cli/commands/down.ts +54 -2
  175. package/src/cli/commands/environments.ts +8 -2
  176. package/src/cli/commands/init.ts +31 -0
  177. package/src/cli/commands/logs.ts +116 -0
  178. package/src/cli/commands/policies.ts +6 -4
  179. package/src/cli/commands/serve.test.ts +67 -0
  180. package/src/cli/commands/serve.ts +284 -0
  181. package/src/cli/commands/up.ts +122 -2
  182. package/src/cli/commands/web-api/agents.ts +3 -2
  183. package/src/cli/index.ts +4 -0
  184. package/src/cli/install-detection.test.ts +72 -0
  185. package/src/cli/install-detection.ts +48 -0
  186. package/src/cli/lite.ts +54 -22
  187. package/src/cli/manage-policies-utils.ts +104 -0
  188. package/src/cli/manage-policies.ts +291 -0
  189. package/src/cli/run-host.ts +45 -0
  190. package/src/cli/supervisor-actions.ts +267 -0
  191. package/src/cli/supervisor-control.test.ts +129 -0
  192. package/src/cli/supervisor-control.ts +155 -0
  193. package/src/cli/supervisor-pid.ts +68 -0
  194. package/src/cli/supervisor.ts +277 -0
  195. package/src/daemon/agent/agent-context.ts +11 -11
  196. package/src/daemon/agent/agent-session.ts +8 -1
  197. package/src/daemon/agent/chat-logger.test.ts +78 -9
  198. package/src/daemon/agent/chat-logger.ts +25 -5
  199. package/src/daemon/agent/turn-registry.test.ts +89 -0
  200. package/src/daemon/agent/turn-registry.ts +94 -0
  201. package/src/daemon/agent/types.ts +2 -0
  202. package/src/daemon/api/agent-policy-endpoints.ts +263 -0
  203. package/src/daemon/api/agent-router.ts +47 -126
  204. package/src/daemon/api/index.test.ts +1 -0
  205. package/src/daemon/api/policy-request.test.ts +7 -5
  206. package/src/daemon/api/router-utils.ts +6 -5
  207. package/src/daemon/api/subagent-router.ts +110 -74
  208. package/src/daemon/api/subagent-utils.test.ts +60 -0
  209. package/src/daemon/api/subagent-utils.ts +113 -87
  210. package/src/daemon/api/user-router.ts +34 -8
  211. package/src/daemon/auth.ts +1 -0
  212. package/src/daemon/cron.test.ts +62 -4
  213. package/src/daemon/cron.ts +42 -16
  214. package/src/daemon/events.ts +65 -0
  215. package/src/daemon/index.ts +24 -1
  216. package/src/daemon/message-interruption.test.ts +1 -0
  217. package/src/daemon/message-jobs.test.ts +1 -0
  218. package/src/daemon/message.ts +78 -14
  219. package/src/daemon/observation.test.ts +26 -18
  220. package/src/daemon/pending-replies.test.ts +112 -0
  221. package/src/daemon/pending-replies.ts +162 -0
  222. package/src/daemon/policy-request-service.ts +3 -1
  223. package/src/daemon/policy-utils.test.ts +66 -1
  224. package/src/daemon/policy-utils.ts +126 -1
  225. package/src/daemon/request-store.ts +31 -0
  226. package/src/daemon/routers/session-timeout.ts +4 -0
  227. package/src/daemon/routers/slash-model.test.ts +344 -0
  228. package/src/daemon/routers/slash-model.ts +207 -0
  229. package/src/daemon/routers/slash-policies.test.ts +38 -32
  230. package/src/daemon/routers/slash-policies.ts +84 -33
  231. package/src/daemon/routers/slash-restart.test.ts +69 -0
  232. package/src/daemon/routers/slash-restart.ts +36 -0
  233. package/src/daemon/routers/slash-shutdown.test.ts +50 -0
  234. package/src/daemon/routers/slash-shutdown.ts +28 -0
  235. package/src/daemon/routers/slash-upgrade.test.ts +116 -0
  236. package/src/daemon/routers/slash-upgrade.ts +76 -0
  237. package/src/daemon/routers/types.ts +7 -0
  238. package/src/daemon/routers.ts +16 -0
  239. package/src/shared/adapters/blockquote.test.ts +28 -0
  240. package/src/shared/adapters/blockquote.ts +20 -0
  241. package/src/shared/adapters/filtering.test.ts +224 -10
  242. package/src/shared/adapters/filtering.ts +95 -7
  243. package/src/shared/adapters/inbound-cache.test.ts +48 -0
  244. package/src/shared/adapters/inbound-cache.ts +54 -0
  245. package/src/shared/adapters/turn-log-buffer.ts +266 -0
  246. package/src/shared/adapters/turn-log.test.ts +389 -0
  247. package/src/shared/adapters/turn-log.ts +357 -0
  248. package/src/shared/agent-utils.ts +12 -5
  249. package/src/shared/chats.test.ts +4 -0
  250. package/src/shared/chats.ts +9 -0
  251. package/src/shared/config.ts +16 -1
  252. package/src/shared/lite.ts +76 -2
  253. package/src/shared/policies.ts +26 -0
  254. package/src/shared/template-manifest.ts +267 -0
  255. package/src/shared/utils/shell.ts +61 -0
  256. package/src/shared/version.ts +34 -0
  257. package/src/shared/workspace.test.ts +217 -0
  258. package/src/shared/workspace.ts +626 -48
  259. package/templates/environments/cladding/allowlist-domain.mjs +125 -0
  260. package/templates/environments/cladding/env.json +21 -1
  261. package/templates/environments/cladding/run-with-network.mjs +54 -0
  262. package/templates/environments/macos-proxy/allowlist-domain.mjs +95 -0
  263. package/templates/environments/macos-proxy/env.json +8 -1
  264. package/templates/environments/macos-proxy/proxy.mjs +42 -13
  265. package/templates/gemini/template.json +5 -0
  266. package/templates/gemini-claw/template.json +13 -0
  267. package/templates/skills/clawmini-requests/SKILL.md +69 -10
  268. package/templates/skills/run-host/SKILL.md +51 -0
  269. package/templates/skills/skill-creator/SKILL.md +4 -3
  270. package/templates/skills/skill-creator/scripts/validate.sh +52 -0
  271. package/tsdown.config.ts +10 -1
  272. package/vitest.config.ts +2 -2
  273. package/web/.svelte-kit/ambient.d.ts +292 -176
  274. package/web/.svelte-kit/generated/server/internal.js +1 -1
  275. package/web/.svelte-kit/output/client/.vite/manifest.json +127 -137
  276. package/web/.svelte-kit/output/client/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
  277. package/web/.svelte-kit/output/client/_app/immutable/chunks/BhRSsUCh.js +2 -0
  278. package/web/.svelte-kit/output/client/_app/immutable/chunks/BiLeM2i1.js +1 -0
  279. package/{dist/web/_app/immutable/chunks/CME08kGM.js → web/.svelte-kit/output/client/_app/immutable/chunks/BmBj85Ll.js} +1 -1
  280. package/web/.svelte-kit/output/client/_app/immutable/chunks/BrERcKAH.js +1 -0
  281. package/web/.svelte-kit/output/client/_app/immutable/chunks/Bv9252RM.js +1 -0
  282. package/web/.svelte-kit/output/client/_app/immutable/chunks/CIXNBPKi.js +1 -0
  283. package/web/.svelte-kit/output/client/_app/immutable/chunks/DISKL3GN.js +2 -0
  284. package/web/.svelte-kit/output/client/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
  285. package/web/.svelte-kit/output/client/_app/immutable/chunks/DnQ3vS13.js +1 -0
  286. package/web/.svelte-kit/output/client/_app/immutable/chunks/KsloHTKS.js +1 -0
  287. package/{dist/web/_app/immutable/chunks/Ck-be5J2.js → web/.svelte-kit/output/client/_app/immutable/chunks/RsHsUj-8.js} +2 -2
  288. package/web/.svelte-kit/output/client/_app/immutable/chunks/{G_zz-Gou.js → wpfV79dV.js} +1 -1
  289. package/web/.svelte-kit/output/client/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
  290. package/web/.svelte-kit/output/client/_app/immutable/entry/start.Di0-Jhte.js +1 -0
  291. package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.CYS8iApT.js → 0.DYyUA1au.js} +1 -1
  292. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
  293. package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
  294. package/{dist/web/_app/immutable/nodes/3.Dr0ot9sV.js → web/.svelte-kit/output/client/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
  295. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
  296. package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.BBGQ_i84.js → 5.DLbPVJY2.js} +1 -1
  297. package/web/.svelte-kit/output/client/_app/version.json +1 -1
  298. package/web/.svelte-kit/output/server/.vite/manifest.json +12 -10
  299. package/web/.svelte-kit/output/server/chunks/Icon.js +1 -1
  300. package/web/.svelte-kit/output/server/chunks/client.js +1 -1
  301. package/web/.svelte-kit/output/server/chunks/exports.js +1 -1
  302. package/web/.svelte-kit/output/server/chunks/index-server.js +2 -1
  303. package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
  304. package/web/.svelte-kit/output/server/chunks/render-context.js +77 -0
  305. package/web/.svelte-kit/output/server/chunks/root.js +739 -788
  306. package/web/.svelte-kit/output/server/chunks/shared.js +234 -21
  307. package/web/.svelte-kit/output/server/index.js +126 -90
  308. package/web/.svelte-kit/output/server/manifest-full.js +1 -1
  309. package/web/.svelte-kit/output/server/manifest.js +1 -1
  310. package/web/.svelte-kit/output/server/nodes/0.js +1 -1
  311. package/web/.svelte-kit/output/server/nodes/1.js +1 -1
  312. package/web/.svelte-kit/output/server/nodes/2.js +1 -1
  313. package/web/.svelte-kit/output/server/nodes/3.js +1 -1
  314. package/web/.svelte-kit/output/server/nodes/4.js +1 -1
  315. package/web/.svelte-kit/output/server/nodes/5.js +1 -1
  316. package/web/.svelte-kit/output/server/remote-entry.js +245 -81
  317. package/web/.svelte-kit/tsconfig.json +4 -1
  318. package/dist/cli/propose-policy.mjs.map +0 -1
  319. package/dist/lite-CBxOT1y5.mjs +0 -241
  320. package/dist/lite-CBxOT1y5.mjs.map +0 -1
  321. package/dist/routing-D8rTxtaV.mjs +0 -245
  322. package/dist/routing-D8rTxtaV.mjs.map +0 -1
  323. package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +0 -1
  324. package/dist/web/_app/immutable/chunks/BmRlVmv6.js +0 -1
  325. package/dist/web/_app/immutable/chunks/CK9JZLaG.js +0 -2
  326. package/dist/web/_app/immutable/chunks/Ck3rYNON.js +0 -1
  327. package/dist/web/_app/immutable/chunks/DMtIqaiV.js +0 -2
  328. package/dist/web/_app/immutable/chunks/DhD271EB.js +0 -1
  329. package/dist/web/_app/immutable/chunks/DpuLqk8d.js +0 -1
  330. package/dist/web/_app/immutable/chunks/DsIToJCP.js +0 -1
  331. package/dist/web/_app/immutable/chunks/bBmtyQMj.js +0 -1
  332. package/dist/web/_app/immutable/entry/app.CJmSwntr.js +0 -2
  333. package/dist/web/_app/immutable/entry/start.ZpUrT2ak.js +0 -1
  334. package/dist/web/_app/immutable/nodes/1.Bli0Hqzn.js +0 -1
  335. package/dist/web/_app/immutable/nodes/4.oBhvQhcA.js +0 -60
  336. package/dist/workspace-BJmJBfKi.mjs +0 -456
  337. package/dist/workspace-BJmJBfKi.mjs.map +0 -1
  338. package/src/cli/e2e/agents.test.ts +0 -140
  339. package/src/cli/e2e/basic.test.ts +0 -43
  340. package/src/cli/e2e/cron.test.ts +0 -132
  341. package/src/cli/e2e/export-lite-func.test.ts +0 -206
  342. package/src/cli/e2e/fallbacks.test.ts +0 -175
  343. package/src/cli/e2e/init.test.ts +0 -77
  344. package/src/cli/e2e/messages.test.ts +0 -332
  345. package/src/cli/e2e/propose-policy.test.ts +0 -203
  346. package/src/cli/e2e/requests.test.ts +0 -180
  347. package/src/cli/e2e/session-timeout.test.ts +0 -192
  348. package/src/cli/e2e/slash-new.test.ts +0 -93
  349. package/src/cli/e2e/subagents.test.ts +0 -106
  350. package/src/cli/e2e/utils.ts +0 -66
  351. package/src/cli/propose-policy.ts +0 -91
  352. package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +0 -1
  353. package/web/.svelte-kit/output/client/_app/immutable/chunks/BmRlVmv6.js +0 -1
  354. package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +0 -2
  355. package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +0 -1
  356. package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +0 -2
  357. package/web/.svelte-kit/output/client/_app/immutable/chunks/DhD271EB.js +0 -1
  358. package/web/.svelte-kit/output/client/_app/immutable/chunks/DpuLqk8d.js +0 -1
  359. package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +0 -1
  360. package/web/.svelte-kit/output/client/_app/immutable/chunks/bBmtyQMj.js +0 -1
  361. package/web/.svelte-kit/output/client/_app/immutable/entry/app.CJmSwntr.js +0 -2
  362. package/web/.svelte-kit/output/client/_app/immutable/entry/start.ZpUrT2ak.js +0 -1
  363. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.Bli0Hqzn.js +0 -1
  364. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.oBhvQhcA.js +0 -60
  365. package/web/.svelte-kit/output/server/chunks/false.js +0 -4
  366. /package/dist/cli/{propose-policy.d.mts → manage-policies.d.mts} +0 -0
  367. /package/{src/cli/e2e → e2e/_helpers}/global-setup.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["fsPromises","isAuthorized","fsPromises","isAuthorized","fs"],"sources":["../../src/adapter-discord/config.ts","../../src/adapter-discord/state.ts","../../src/adapter-discord/interactions.ts","../../src/adapter-discord/client.ts","../../src/adapter-discord/forwarder.ts","../../src/adapter-discord/index.ts"],"sourcesContent":["import fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport { getClawminiDir } from '../shared/workspace.js';\nimport fs from 'node:fs';\n\nexport const DiscordConfigSchema = z.looseObject({\n botToken: z.string().min(1, 'Discord Bot Token is required.'),\n authorizedUserId: z.string().min(1, 'Authorized Discord User ID is required.'),\n chatId: z.string().default('default'),\n maxAttachmentSizeMB: z.number().default(25),\n requireMention: z.boolean().default(false),\n});\n\nexport type DiscordConfig = z.infer<typeof DiscordConfigSchema>;\n\nexport function getDiscordConfigPath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'discord', 'config.json');\n}\n\nexport async function readDiscordConfig(startDir = process.cwd()): Promise<DiscordConfig | null> {\n const configPath = getDiscordConfigPath(startDir);\n try {\n const data = await fsPromises.readFile(configPath, 'utf-8');\n const parsed = JSON.parse(data);\n return DiscordConfigSchema.parse(parsed);\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return null;\n }\n throw err;\n }\n}\n\nexport async function initDiscordConfig(startDir = process.cwd()): Promise<void> {\n const configPath = getDiscordConfigPath(startDir);\n const configDir = path.dirname(configPath);\n\n await fsPromises.mkdir(configDir, { recursive: true });\n\n if (fs.existsSync(configPath)) {\n console.log(`Config file already exists at ${configPath}`);\n return;\n }\n\n const templateConfig = {\n botToken: 'YOUR_DISCORD_BOT_TOKEN',\n authorizedUserId: 'YOUR_DISCORD_USER_ID',\n chatId: 'default',\n };\n\n await fsPromises.writeFile(configPath, JSON.stringify(templateConfig, null, 2), 'utf-8');\n console.log(`Created template configuration file at ${configPath}`);\n console.log('Please update it with your actual Discord Bot Token and User ID.');\n}\n\nexport function isAuthorized(userId: string, authorizedUserId: string): boolean {\n return userId === authorizedUserId;\n}\n","import fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport { getClawminiDir } from '../shared/workspace.js';\n\nexport const DiscordStateSchema = z.object({\n lastSyncedMessageIds: z.record(z.string(), z.string()).optional(),\n channelChatMap: z\n .record(\n z.string(),\n z.object({\n chatId: z.string().nullable().optional(),\n requireMention: z.boolean().optional(),\n })\n )\n .optional(),\n filters: z.record(z.string(), z.boolean()).optional(),\n});\n\nexport type DiscordState = z.infer<typeof DiscordStateSchema>;\n\nexport function getDiscordStatePath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'discord', 'state.json');\n}\n\nexport async function readDiscordState(startDir = process.cwd()): Promise<DiscordState> {\n const statePath = getDiscordStatePath(startDir);\n try {\n const data = await fsPromises.readFile(statePath, 'utf-8');\n const parsed = JSON.parse(data);\n\n // Migrate legacy state\n if (parsed.lastSyncedMessageId && !parsed.lastSyncedMessageIds) {\n parsed.lastSyncedMessageIds = { default: parsed.lastSyncedMessageId };\n }\n if (parsed.channelChatMap) {\n for (const [key, value] of Object.entries(parsed.channelChatMap)) {\n if (typeof value === 'string') {\n parsed.channelChatMap[key] = { chatId: value };\n }\n }\n }\n\n return DiscordStateSchema.parse(parsed);\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw err;\n }\n}\n\nexport async function writeDiscordState(\n state: DiscordState,\n startDir = process.cwd()\n): Promise<void> {\n const statePath = getDiscordStatePath(startDir);\n const dir = path.dirname(statePath);\n try {\n await fsPromises.mkdir(dir, { recursive: true });\n await fsPromises.writeFile(statePath, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n console.error(`Failed to write Discord state to ${statePath}:`, err);\n }\n}\n\nlet stateUpdatePromise = Promise.resolve();\n\nexport function updateDiscordState(\n updates: Partial<DiscordState> | ((state: DiscordState) => Partial<DiscordState>),\n startDir = process.cwd()\n): Promise<DiscordState> {\n return new Promise((resolve, reject) => {\n stateUpdatePromise = stateUpdatePromise.then(async () => {\n try {\n const currentState = await readDiscordState(startDir);\n const resolvedUpdates = typeof updates === 'function' ? updates(currentState) : updates;\n const newState = { ...currentState, ...resolvedUpdates };\n await writeDiscordState(newState, startDir);\n resolve(newState);\n } catch (err) {\n console.error(`Failed to write Discord state:`, err);\n reject(err);\n }\n });\n });\n}\n","import {\n ActionRowBuilder,\n ModalBuilder,\n TextInputBuilder,\n TextInputStyle,\n type Interaction,\n} from 'discord.js';\nimport { readDiscordState } from './state.js';\nimport type { DiscordConfig } from './config.js';\n\nfunction isAuthorized(userId: string, authorizedUserId: string): boolean {\n return userId === authorizedUserId;\n}\n\nexport async function handleDiscordInteraction(\n interaction: Interaction,\n config: DiscordConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n trpc: any\n) {\n if (!interaction.isButton() && !interaction.isModalSubmit()) return;\n\n if (!isAuthorized(interaction.user.id, config.authorizedUserId)) {\n if (interaction.isRepliable()) {\n await interaction.reply({\n content: 'You are not authorized to perform this action.',\n ephemeral: true,\n });\n }\n return;\n }\n\n if (interaction.isButton()) {\n if (\n interaction.customId.startsWith('approve_') ||\n interaction.customId.startsWith('approve|')\n ) {\n let policyId, explicitChatId;\n if (interaction.customId.startsWith('approve|')) {\n const parts = interaction.customId.split('|');\n policyId = parts[1];\n explicitChatId = parts[2] || undefined;\n } else {\n policyId = interaction.customId.replace('approve_', '');\n }\n\n await interaction.update({ components: [] });\n await interaction.followUp({ content: `Approving policy ${policyId}...`, ephemeral: true });\n try {\n const currentState = await readDiscordState();\n const targetChatId =\n explicitChatId ||\n (interaction.channelId\n ? currentState.channelChatMap?.[interaction.channelId]?.chatId || config.chatId\n : config.chatId);\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: `/approve ${policyId}`,\n chatId: targetChatId,\n adapter: 'discord',\n noWait: true,\n },\n });\n } catch (error) {\n console.error('Failed to send approve command to daemon:', error);\n await interaction.followUp({\n content: `Failed to approve policy ${policyId}.`,\n ephemeral: true,\n });\n }\n } else if (\n interaction.customId.startsWith('reject_') ||\n interaction.customId.startsWith('reject|')\n ) {\n let policyId, explicitChatId;\n if (interaction.customId.startsWith('reject|')) {\n const parts = interaction.customId.split('|');\n policyId = parts[1];\n explicitChatId = parts[2] || '';\n } else {\n policyId = interaction.customId.replace('reject_', '');\n explicitChatId = '';\n }\n\n const modal = new ModalBuilder()\n .setCustomId(`modal_reject|${policyId}|${explicitChatId}`)\n .setTitle('Reject Policy');\n\n const rationaleInput = new TextInputBuilder()\n .setCustomId('rationale')\n .setLabel('Rationale (optional)')\n .setStyle(TextInputStyle.Paragraph)\n .setRequired(false);\n\n const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(rationaleInput);\n modal.addComponents(actionRow);\n\n await interaction.showModal(modal);\n }\n } else if (interaction.isModalSubmit()) {\n if (\n interaction.customId.startsWith('modal_reject_') ||\n interaction.customId.startsWith('modal_reject|')\n ) {\n let policyId, explicitChatId;\n if (interaction.customId.startsWith('modal_reject|')) {\n const parts = interaction.customId.split('|');\n policyId = parts[1];\n explicitChatId = parts[2] || undefined;\n } else {\n policyId = interaction.customId.replace('modal_reject_', '');\n }\n const rationale = interaction.fields.getTextInputValue('rationale');\n\n const command = rationale ? `/reject ${policyId} ${rationale}` : `/reject ${policyId}`;\n\n if (interaction.isFromMessage()) {\n await interaction.update({ components: [] });\n await interaction.followUp({\n content: `Rejecting policy ${policyId}...`,\n ephemeral: true,\n });\n } else {\n await interaction.reply({ content: `Rejecting policy ${policyId}...`, ephemeral: true });\n }\n\n try {\n const currentState = await readDiscordState();\n const targetChatId =\n explicitChatId ||\n (interaction.channelId\n ? currentState.channelChatMap?.[interaction.channelId]?.chatId || config.chatId\n : config.chatId);\n\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: command,\n chatId: targetChatId,\n adapter: 'discord',\n noWait: true,\n },\n });\n } catch (error) {\n console.error('Failed to send reject command to daemon:', error);\n await interaction.followUp({\n content: `Failed to reject policy ${policyId}.`,\n ephemeral: true,\n });\n }\n }\n }\n}\n","import { createTRPCClient, httpLink, splitLink, httpSubscriptionLink } from '@trpc/client';\nimport type { UserRouter as AppRouter } from '../daemon/api/index.js';\nimport { getSocketPath } from '../shared/workspace.js';\nimport { createUnixSocketFetch } from '../shared/fetch.js';\nimport { createUnixSocketEventSource } from '../shared/event-source.js';\nimport fs from 'node:fs';\n\n/**\n * Creates a TRPC client that connects to the Clawmini daemon via a Unix socket.\n *\n * @param options - Configuration options for the client.\n * @returns A TRPC client instance for the AppRouter.\n */\nexport function getTRPCClient(options: { socketPath?: string } = {}) {\n const socketPath = options.socketPath ?? getSocketPath();\n\n if (!fs.existsSync(socketPath)) {\n throw new Error(`Daemon not running. Socket not found at ${socketPath}`);\n }\n\n const customFetch = createUnixSocketFetch(socketPath);\n const CustomEventSource = createUnixSocketEventSource(socketPath);\n\n return createTRPCClient<AppRouter>({\n links: [\n splitLink({\n condition(op) {\n return op.type === 'subscription';\n },\n true: httpSubscriptionLink({\n url: 'http://localhost',\n EventSource: CustomEventSource,\n }),\n false: httpLink({\n url: 'http://localhost',\n fetch: customFetch,\n }),\n }),\n ],\n });\n}\n","/* eslint-disable max-lines */\nimport type {\n Client,\n MessageCreateOptions,\n TextChannel,\n DMChannel,\n NewsChannel,\n ThreadChannel,\n VoiceChannel,\n StageChannel,\n} from 'discord.js';\nimport { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } from 'discord.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport type { getTRPCClient } from './client.js';\nimport { readDiscordState, updateDiscordState, getDiscordStatePath } from './state.js';\nimport type { ChatMessage } from '../shared/chats.js';\nimport { getWorkspaceRoot } from '../shared/workspace.js';\nimport {\n shouldDisplayMessage,\n formatMessage,\n type FilteringConfig,\n} from '../shared/adapters/filtering.js';\n\nasync function resolveDiscordDestination(\n client: Client,\n discordUserId: string,\n chatId: string\n): Promise<TextChannel | DMChannel | NewsChannel | ThreadChannel | VoiceChannel | StageChannel> {\n const state = await readDiscordState();\n const channelChatMap = state.channelChatMap || {};\n\n let targetDiscordChannelId: string | undefined;\n for (const [channelId, mappedChatId] of Object.entries(channelChatMap)) {\n if (mappedChatId?.chatId === chatId) {\n targetDiscordChannelId = channelId;\n break;\n }\n }\n\n if (targetDiscordChannelId) {\n try {\n const channel = await client.channels.fetch(targetDiscordChannelId);\n if (channel && channel.isTextBased() && !channel.isDMBased()) {\n return channel as TextChannel | NewsChannel | ThreadChannel | VoiceChannel | StageChannel;\n }\n } catch (error) {\n console.warn(\n `Failed to fetch mapped channel ${targetDiscordChannelId} for chat ${chatId}, falling back to DM.`,\n error\n );\n }\n }\n\n const user = await client.users.fetch(discordUserId);\n return user.createDM();\n}\n\nexport async function startDaemonToDiscordForwarder(\n client: Client,\n trpc: ReturnType<typeof getTRPCClient>,\n discordUserId: string,\n options: {\n chatId?: string;\n signal?: AbortSignal;\n config?: FilteringConfig;\n } = {}\n) {\n const defaultChatId = options.chatId ?? 'default';\n const signal = options.signal;\n const config = options.config ?? {};\n\n const activeSubscriptions = new Map<string, { unsubscribe: () => void }>();\n const activeTypingSubscriptions = new Map<string, { unsubscribe: () => void }>();\n let currentLastSyncedMessageIds = (await readDiscordState()).lastSyncedMessageIds || {};\n\n const saveLastMessageId = async (chatId: string, id: string) => {\n currentLastSyncedMessageIds = { ...currentLastSyncedMessageIds, [chatId]: id };\n return updateDiscordState((state) => ({\n lastSyncedMessageIds: {\n ...state.lastSyncedMessageIds,\n ...currentLastSyncedMessageIds,\n },\n }));\n };\n\n const startSubscriptionForChat = async (chatId: string) => {\n if (activeSubscriptions.has(chatId)) return;\n if (signal?.aborted) return;\n\n let lastMessageId = currentLastSyncedMessageIds[chatId];\n\n if (!lastMessageId) {\n try {\n const messages = await trpc.getMessages.query({ chatId, limit: 1 });\n if (Array.isArray(messages) && messages.length > 0) {\n const lastMsg = messages[messages.length - 1];\n if (lastMsg) {\n await saveLastMessageId(chatId, lastMsg.id);\n lastMessageId = lastMsg.id;\n }\n }\n } catch (error) {\n if (signal?.aborted) return;\n console.error(`Failed to fetch initial messages from daemon for ${chatId}:`, error);\n }\n }\n\n console.log(\n `Starting daemon-to-discord forwarder for chat ${chatId}, lastMessageId: ${lastMessageId}`\n );\n\n let retryDelay = 1000;\n const maxRetryDelay = 30000;\n\n let subscription: { unsubscribe: () => void } | null = null;\n let messageQueue = Promise.resolve();\n\n const connect = () => {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n subscription = trpc.waitForMessages.subscribe(\n { chatId, lastMessageId },\n {\n onData: (messages) => {\n retryDelay = 1000; // Reset retry delay on successful data\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return;\n }\n\n // Queue processing to ensure sequential execution\n messageQueue = messageQueue.then(async () => {\n for (const rawMessage of messages) {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) break;\n\n const message = rawMessage as ChatMessage;\n\n const isDisplayed = shouldDisplayMessage(message, config);\n\n if (isDisplayed) {\n const logMessage = message;\n const isPolicyRequest =\n logMessage.role === 'policy' && logMessage.status === 'pending';\n\n if (isPolicyRequest) {\n try {\n const dm = await resolveDiscordDestination(client, discordUserId, chatId);\n\n const embed = new EmbedBuilder()\n .setTitle('Action Required: Policy Request')\n .setDescription(\n logMessage.content || 'A pending policy request requires your attention.'\n )\n .setColor(Colors.Yellow);\n\n const policyId =\n ('requestId' in logMessage && logMessage.requestId) || logMessage.id;\n const row = new ActionRowBuilder<ButtonBuilder>().addComponents(\n new ButtonBuilder()\n .setCustomId(`approve|${policyId}|${chatId}`)\n .setLabel('Approve')\n .setStyle(ButtonStyle.Success),\n new ButtonBuilder()\n .setCustomId(`reject|${policyId}|${chatId}`)\n .setLabel('Reject')\n .setStyle(ButtonStyle.Danger)\n );\n\n const optionsMsg: MessageCreateOptions = {\n embeds: [embed],\n components: [row],\n };\n\n try {\n await dm.send(optionsMsg);\n } catch (richError) {\n console.warn(\n `Failed to send rich message to Discord user ${discordUserId}, falling back to plain text:`,\n richError\n );\n await dm.send({\n content: `Action Required: Policy Request\\n\\n${logMessage.content || 'A pending policy request requires your attention.'}\\n\\nApprove: \\`/approve ${policyId}\\`\\nReject: \\`/reject ${policyId} <optional_rationale>\\``,\n });\n }\n } catch (error) {\n console.error(\n `Failed to send message to Discord user ${discordUserId}:`,\n error\n );\n }\n\n await saveLastMessageId(chatId, logMessage.id).catch(console.error);\n lastMessageId = logMessage.id;\n continue;\n }\n\n if ('level' in logMessage && logMessage.level === 'verbose') {\n await saveLastMessageId(chatId, logMessage.id).catch(console.error);\n lastMessageId = logMessage.id;\n continue;\n }\n\n const hasContent = !!logMessage.content?.trim();\n const files = 'files' in logMessage ? (logMessage.files as string[]) : undefined;\n const hasFiles = Array.isArray(files) && files.length > 0;\n\n // The daemon stores logMessage.files as paths relative to the WORKSPACE directory\n // (the directory containing .clawmini). We must resolve these against the current\n // workspace root so discord.js can successfully locate and read the files.\n let absoluteFiles: string[] = [];\n if (hasFiles && files) {\n const workspaceRoot = getWorkspaceRoot(process.cwd());\n absoluteFiles = files.map((f) => path.resolve(workspaceRoot, f));\n }\n\n if (!hasContent && !hasFiles) {\n await saveLastMessageId(chatId, logMessage.id).catch(console.error);\n lastMessageId = logMessage.id;\n continue;\n }\n\n try {\n const dm = await resolveDiscordDestination(client, discordUserId, chatId);\n const formattedContent = formatMessage(message);\n\n if (formattedContent && formattedContent.length > 2000) {\n const chunks = chunkString(formattedContent, 2000);\n for (let i = 0; i < chunks.length; i++) {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) break;\n const chunkOptions: MessageCreateOptions = { content: chunks[i] as string };\n if (i === chunks.length - 1 && hasFiles) {\n chunkOptions.files = absoluteFiles;\n }\n await dm.send(chunkOptions);\n }\n } else {\n const optionsMsg: MessageCreateOptions = {};\n if (formattedContent) {\n optionsMsg.content = formattedContent;\n }\n if (hasFiles) {\n optionsMsg.files = absoluteFiles;\n }\n await dm.send(optionsMsg);\n }\n } catch (error) {\n console.error(\n `Failed to send message to Discord user ${discordUserId}:`,\n error\n );\n break; // don't advance lastMessageId\n }\n }\n\n await saveLastMessageId(chatId, message.id).catch(console.error);\n lastMessageId = message.id;\n }\n });\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord forwarder subscription for ${chatId}. Retrying in ${retryDelay}ms.`,\n error\n );\n subscription?.unsubscribe();\n subscription = null;\n\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n setTimeout(() => {\n retryDelay = Math.min(retryDelay * 2, maxRetryDelay);\n connect();\n }, retryDelay);\n },\n onComplete: () => {\n subscription = null;\n if (!signal?.aborted && activeSubscriptions.has(chatId)) {\n setTimeout(() => connect(), retryDelay);\n }\n },\n }\n );\n };\n\n let typingSubscription: { unsubscribe: () => void } | null = null;\n let typingRetryDelay = 1000;\n\n const connectTyping = () => {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n typingSubscription = trpc.waitForTyping.subscribe(\n { chatId },\n {\n onData: async (event) => {\n typingRetryDelay = 1000; // Reset retry delay on successful data\n if (!event) return;\n\n try {\n const dm = await resolveDiscordDestination(client, discordUserId, chatId);\n if (dm.sendTyping) {\n await dm.sendTyping();\n }\n } catch (error) {\n console.error(\n `Failed to send typing indicator to Discord user ${discordUserId}:`,\n error\n );\n }\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord typing forwarder subscription for ${chatId}. Retrying in ${typingRetryDelay}ms.`,\n error\n );\n typingSubscription?.unsubscribe();\n typingSubscription = null;\n\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n setTimeout(() => {\n typingRetryDelay = Math.min(typingRetryDelay * 2, maxRetryDelay);\n connectTyping();\n }, typingRetryDelay);\n },\n onComplete: () => {\n typingSubscription = null;\n if (!signal?.aborted && activeSubscriptions.has(chatId)) {\n setTimeout(() => connectTyping(), typingRetryDelay);\n }\n },\n }\n );\n };\n\n activeSubscriptions.set(chatId, {\n unsubscribe: () => subscription?.unsubscribe(),\n });\n activeTypingSubscriptions.set(chatId, {\n unsubscribe: () => typingSubscription?.unsubscribe(),\n });\n\n connect();\n connectTyping();\n };\n\n const syncSubscriptions = async () => {\n if (signal?.aborted) return;\n const state = await readDiscordState();\n\n // Update local copy of last message IDs\n if (state.lastSyncedMessageIds) {\n currentLastSyncedMessageIds = {\n ...currentLastSyncedMessageIds,\n ...state.lastSyncedMessageIds,\n };\n }\n\n const targetChatIds = new Set<string>();\n targetChatIds.add(defaultChatId);\n\n if (state.channelChatMap) {\n for (const mappedEntry of Object.values(state.channelChatMap)) {\n if (mappedEntry.chatId) {\n targetChatIds.add(mappedEntry.chatId);\n }\n }\n }\n\n // Start new subscriptions\n for (const targetChatId of targetChatIds) {\n if (!activeSubscriptions.has(targetChatId)) {\n startSubscriptionForChat(targetChatId);\n }\n }\n\n // Teardown old subscriptions\n for (const [activeChatId, sub] of activeSubscriptions.entries()) {\n if (!targetChatIds.has(activeChatId)) {\n sub.unsubscribe();\n activeSubscriptions.delete(activeChatId);\n activeTypingSubscriptions.get(activeChatId)?.unsubscribe();\n activeTypingSubscriptions.delete(activeChatId);\n }\n }\n };\n\n return new Promise<void>((resolve) => {\n syncSubscriptions().catch(console.error);\n\n const statePath = getDiscordStatePath();\n const stateDir = path.dirname(statePath);\n if (!fs.existsSync(stateDir)) {\n fs.mkdirSync(stateDir, { recursive: true });\n }\n let debounceTimer: NodeJS.Timeout | null = null;\n const watcher = fs.watch(stateDir, (eventType: string, filename: string | null) => {\n if (filename === path.basename(statePath)) {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n syncSubscriptions().catch(console.error);\n }, 200);\n }\n });\n\n signal?.addEventListener('abort', () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher.close();\n for (const sub of activeSubscriptions.values()) sub.unsubscribe();\n for (const sub of activeTypingSubscriptions.values()) sub.unsubscribe();\n resolve();\n });\n });\n}\n\nfunction chunkString(str: string, size: number): string[] {\n const chunks: string[] = [];\n const chars = Array.from(str);\n for (let i = 0; i < chars.length; i += size) {\n chunks.push(chars.slice(i, i + size).join(''));\n }\n return chunks;\n}\n","#!/usr/bin/env node\n\nimport { Client, Events, GatewayIntentBits, Partials } from 'discord.js';\nimport { readDiscordConfig, isAuthorized, initDiscordConfig } from './config.js';\nimport { readDiscordState, updateDiscordState } from './state.js';\nimport { handleDiscordInteraction } from './interactions.js';\nimport { getTRPCClient } from './client.js';\nimport { startDaemonToDiscordForwarder } from './forwarder.js';\nimport { getClawminiDir } from '../shared/workspace.js';\nimport { handleAdapterCommand, type CommandTrpcClient } from '../shared/adapters/commands.js';\nimport { formatMessage, type FilteringConfig } from '../shared/adapters/filtering.js';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { handleRoutingCommand, type RoutingTrpcClient } from '../shared/adapters/routing.js';\n\nexport async function main() {\n const args = process.argv.slice(2);\n\n if (args[0] === 'init') {\n await initDiscordConfig();\n return;\n }\n\n console.log('Discord Adapter starting...');\n\n const config = await readDiscordConfig();\n if (!config) {\n console.error(\n 'Failed to load Discord configuration. Please ensure .clawmini/adapters/discord/config.json exists and is valid.'\n );\n process.exit(1);\n }\n\n const trpc = getTRPCClient();\n\n const client = new Client({\n intents: [\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n ],\n partials: [Partials.Channel],\n });\n\n const state = await readDiscordState();\n const filteringConfig: FilteringConfig = { filters: state.filters };\n\n client.once(Events.ClientReady, (readyClient) => {\n console.log(`Ready! Logged in as ${readyClient.user.tag}`);\n\n // Start forwarding from daemon to Discord\n startDaemonToDiscordForwarder(readyClient, trpc, config.authorizedUserId, {\n chatId: config.chatId,\n config: filteringConfig,\n }).catch((error) => {\n console.error('Error in daemon-to-discord forwarder:', error);\n });\n });\n\n client.on(Events.MessageCreate, async (message) => {\n // Ignore messages from the bot itself\n if (message.author.id === client.user?.id) return;\n if (message.author.bot) return;\n\n const externalContextId = message.channelId;\n const currentState = await readDiscordState();\n const mappedChatId = currentState.channelChatMap?.[externalContextId]?.chatId;\n const isRoutingCommand =\n message.content.startsWith('/chat') || message.content.startsWith('/agent');\n\n // Enforce requireMention config for guild messages\n if (message.guild) {\n const channelConfig = currentState.channelChatMap?.[externalContextId];\n const requiresMention =\n channelConfig?.requireMention !== undefined\n ? channelConfig.requireMention\n : config.requireMention;\n\n if (requiresMention) {\n const isMentioned = message.mentions.has(client.user!.id);\n let isReplyToBot = false;\n\n if (message.reference && message.reference.messageId) {\n try {\n const referencedMessage = await message.channel.messages.fetch(\n message.reference.messageId\n );\n isReplyToBot = referencedMessage.author.id === client.user!.id;\n } catch (err) {\n console.error('Failed to fetch referenced message for mention check:', err);\n }\n }\n\n if (!isMentioned && !isReplyToBot) {\n return;\n }\n }\n }\n\n // Check if the user is authorized\n if (!isAuthorized(message.author.id, config.authorizedUserId)) {\n console.log(\n `Unauthorized message from ${message.author.tag} (${message.author.id}) ignored.`\n );\n return;\n }\n\n console.log(`Received message from ${message.author.tag}: ${message.content}`);\n\n if (isRoutingCommand) {\n const stringChatMap = Object.fromEntries(\n Object.entries(currentState.channelChatMap || {}).map(([k, v]) => [k, v.chatId || ''])\n );\n const routingResult = await handleRoutingCommand(\n message.content,\n externalContextId,\n stringChatMap,\n 'discord',\n trpc as unknown as RoutingTrpcClient\n );\n\n if (routingResult) {\n if (routingResult.type === 'mapped') {\n await updateDiscordState((latestState) => ({\n channelChatMap: {\n ...(latestState.channelChatMap || {}),\n [externalContextId]: {\n ...(latestState.channelChatMap?.[externalContextId] || {}),\n chatId: routingResult.newChatId,\n },\n },\n }));\n }\n await message.reply(routingResult.text);\n return;\n }\n }\n\n let targetChatId = mappedChatId;\n\n if (!targetChatId && !isRoutingCommand) {\n const isFirstEverMessage =\n !currentState.channelChatMap ||\n Object.values(currentState.channelChatMap).every((entry) => !entry.chatId);\n\n if (isFirstEverMessage) {\n targetChatId = config.chatId || 'default';\n console.log(\n `First contact detected. Automatically mapping channel ${externalContextId} to chat ${targetChatId}.`\n );\n await updateDiscordState((latestState) => ({\n channelChatMap: {\n ...(latestState.channelChatMap || {}),\n [externalContextId]: {\n ...(latestState.channelChatMap?.[externalContextId] || {}),\n chatId: targetChatId as string,\n },\n },\n }));\n } else {\n const isDirectMessage = !message.guild;\n const isMentioned = message.mentions.has(client.user!.id);\n const isSlashCommand = message.content.startsWith('/');\n if (isDirectMessage || isMentioned || isSlashCommand) {\n console.log(`Unmapped channel ${externalContextId}, sending first contact warning.`);\n await message.reply(\n 'This channel/space is not currently mapped to a daemon chat. Please use `/chat [chat-id]` or `/agent [agent-id]` to map it.'\n );\n } else {\n console.log(\n `Unmapped channel ${externalContextId}, silently ignoring background message.`\n );\n }\n return;\n }\n }\n\n // Fallback typing safeguard\n if (!targetChatId) targetChatId = config.chatId || 'default';\n\n const commandResult = await handleAdapterCommand(\n message.content,\n filteringConfig,\n trpc as unknown as CommandTrpcClient,\n targetChatId\n );\n\n if (commandResult) {\n if (commandResult.type === 'text') {\n if (commandResult.newConfig) {\n filteringConfig.filters = commandResult.newConfig.filters;\n await updateDiscordState({ filters: filteringConfig.filters });\n }\n await message.reply(commandResult.text);\n } else if (commandResult.type === 'debug') {\n const formatted =\n commandResult.messages.length === 0\n ? 'No ignored background messages found.'\n : `**Debug Output (${commandResult.messages.length} ignored messages):**\\n\\n` +\n commandResult.messages.map((msg) => formatMessage(msg)).join('\\n\\n---\\n\\n');\n await message.reply(formatted);\n }\n return;\n }\n\n const downloadedFiles: string[] = [];\n if (message.attachments.size > 0) {\n const tmpDir = path.join(getClawminiDir(process.cwd()), 'tmp', 'discord');\n await fs.mkdir(tmpDir, { recursive: true });\n const maxSizeMB = config.maxAttachmentSizeMB ?? 25;\n const maxSizeBytes = maxSizeMB * 1024 * 1024;\n\n for (const attachment of message.attachments.values()) {\n if (attachment.size > maxSizeBytes) {\n console.warn(\n `Attachment ${attachment.name} exceeds size limit (${maxSizeMB}MB). Ignoring.`\n );\n await message.reply(\n `Warning: Attachment ${attachment.name} exceeds the size limit of ${maxSizeMB}MB and was ignored.`\n );\n continue;\n }\n\n try {\n const res = await fetch(attachment.url);\n if (!res.ok) {\n console.error(`Failed to download attachment ${attachment.name}`);\n continue;\n }\n\n const uniqueName = `${Date.now()}-${attachment.name}`;\n const filePath = path.join(tmpDir, uniqueName);\n const arrayBuffer = await res.arrayBuffer();\n await fs.writeFile(filePath, Buffer.from(arrayBuffer));\n downloadedFiles.push(filePath);\n } catch (err) {\n console.error(`Error downloading attachment ${attachment.name}:`, err);\n }\n }\n }\n\n let finalContent = message.content;\n\n if (message.reference && message.reference.messageId) {\n try {\n const referencedMessage = await message.fetchReference();\n if (referencedMessage && referencedMessage.content) {\n const quotedContent = referencedMessage.content\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n');\n finalContent = `${quotedContent}\\n${finalContent}`;\n }\n } catch (err) {\n console.error('Failed to fetch referenced message:', err);\n }\n }\n\n console.log(`Forwarding message to daemon: ${finalContent}`);\n try {\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: finalContent,\n chatId: targetChatId,\n files: downloadedFiles.length > 0 ? downloadedFiles : undefined,\n adapter: 'discord',\n noWait: true,\n },\n });\n console.log('Message forwarded to daemon successfully.');\n } catch (error) {\n console.error('Failed to forward message to daemon:', error);\n }\n });\n\n client.on(Events.InteractionCreate, async (interaction) => {\n await handleDiscordInteraction(interaction, config, trpc as unknown as CommandTrpcClient);\n });\n\n try {\n await client.login(config.botToken);\n } catch (error) {\n console.error('Failed to login to Discord:', error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error('Unhandled error in Discord Adapter:', error);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;AAMA,MAAa,sBAAsB,EAAE,YAAY;CAC/C,UAAU,EAAE,QAAQ,CAAC,IAAI,GAAG,iCAAiC;CAC7D,kBAAkB,EAAE,QAAQ,CAAC,IAAI,GAAG,0CAA0C;CAC9E,QAAQ,EAAE,QAAQ,CAAC,QAAQ,UAAU;CACrC,qBAAqB,EAAE,QAAQ,CAAC,QAAQ,GAAG;CAC3C,gBAAgB,EAAE,SAAS,CAAC,QAAQ,MAAM;CAC3C,CAAC;AAIF,SAAgB,qBAAqB,WAAW,QAAQ,KAAK,EAAU;AACrE,QAAO,KAAK,KAAK,eAAe,SAAS,EAAE,YAAY,WAAW,cAAc;;AAGlF,eAAsB,kBAAkB,WAAW,QAAQ,KAAK,EAAiC;CAC/F,MAAM,aAAa,qBAAqB,SAAS;AACjD,KAAI;EACF,MAAM,OAAO,MAAMA,KAAW,SAAS,YAAY,QAAQ;EAC3D,MAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,SAAO,oBAAoB,MAAM,OAAO;UACjC,KAAc;AACrB,MAAK,IAA8B,SAAS,SAC1C,QAAO;AAET,QAAM;;;AAIV,eAAsB,kBAAkB,WAAW,QAAQ,KAAK,EAAiB;CAC/E,MAAM,aAAa,qBAAqB,SAAS;CACjD,MAAM,YAAY,KAAK,QAAQ,WAAW;AAE1C,OAAMA,KAAW,MAAM,WAAW,EAAE,WAAW,MAAM,CAAC;AAEtD,KAAI,GAAG,WAAW,WAAW,EAAE;AAC7B,UAAQ,IAAI,iCAAiC,aAAa;AAC1D;;AASF,OAAMA,KAAW,UAAU,YAAY,KAAK,UANrB;EACrB,UAAU;EACV,kBAAkB;EAClB,QAAQ;EACT,EAEqE,MAAM,EAAE,EAAE,QAAQ;AACxF,SAAQ,IAAI,0CAA0C,aAAa;AACnE,SAAQ,IAAI,mEAAmE;;AAGjF,SAAgBC,eAAa,QAAgB,kBAAmC;AAC9E,QAAO,WAAW;;;;;ACpDpB,MAAa,qBAAqB,EAAE,OAAO;CACzC,sBAAsB,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC,UAAU;CACjE,gBAAgB,EACb,OACC,EAAE,QAAQ,EACV,EAAE,OAAO;EACP,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU;EACxC,gBAAgB,EAAE,SAAS,CAAC,UAAU;EACvC,CAAC,CACH,CACA,UAAU;CACb,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU;CACtD,CAAC;AAIF,SAAgB,oBAAoB,WAAW,QAAQ,KAAK,EAAU;AACpE,QAAO,KAAK,KAAK,eAAe,SAAS,EAAE,YAAY,WAAW,aAAa;;AAGjF,eAAsB,iBAAiB,WAAW,QAAQ,KAAK,EAAyB;CACtF,MAAM,YAAY,oBAAoB,SAAS;AAC/C,KAAI;EACF,MAAM,OAAO,MAAMC,KAAW,SAAS,WAAW,QAAQ;EAC1D,MAAM,SAAS,KAAK,MAAM,KAAK;AAG/B,MAAI,OAAO,uBAAuB,CAAC,OAAO,qBACxC,QAAO,uBAAuB,EAAE,SAAS,OAAO,qBAAqB;AAEvE,MAAI,OAAO,gBACT;QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,eAAe,CAC9D,KAAI,OAAO,UAAU,SACnB,QAAO,eAAe,OAAO,EAAE,QAAQ,OAAO;;AAKpD,SAAO,mBAAmB,MAAM,OAAO;UAChC,KAAc;AACrB,MAAK,IAA8B,SAAS,SAC1C,QAAO,EAAE;AAEX,QAAM;;;AAIV,eAAsB,kBACpB,OACA,WAAW,QAAQ,KAAK,EACT;CACf,MAAM,YAAY,oBAAoB,SAAS;CAC/C,MAAM,MAAM,KAAK,QAAQ,UAAU;AACnC,KAAI;AACF,QAAMA,KAAW,MAAM,KAAK,EAAE,WAAW,MAAM,CAAC;AAChD,QAAMA,KAAW,UAAU,WAAW,KAAK,UAAU,OAAO,MAAM,EAAE,EAAE,QAAQ;UACvE,KAAK;AACZ,UAAQ,MAAM,oCAAoC,UAAU,IAAI,IAAI;;;AAIxE,IAAI,qBAAqB,QAAQ,SAAS;AAE1C,SAAgB,mBACd,SACA,WAAW,QAAQ,KAAK,EACD;AACvB,QAAO,IAAI,SAAS,SAAS,WAAW;AACtC,uBAAqB,mBAAmB,KAAK,YAAY;AACvD,OAAI;IACF,MAAM,eAAe,MAAM,iBAAiB,SAAS;IACrD,MAAM,kBAAkB,OAAO,YAAY,aAAa,QAAQ,aAAa,GAAG;IAChF,MAAM,WAAW;KAAE,GAAG;KAAc,GAAG;KAAiB;AACxD,UAAM,kBAAkB,UAAU,SAAS;AAC3C,YAAQ,SAAS;YACV,KAAK;AACZ,YAAQ,MAAM,kCAAkC,IAAI;AACpD,WAAO,IAAI;;IAEb;GACF;;;;;AC3EJ,SAAS,aAAa,QAAgB,kBAAmC;AACvE,QAAO,WAAW;;AAGpB,eAAsB,yBACpB,aACA,QAEA,MACA;AACA,KAAI,CAAC,YAAY,UAAU,IAAI,CAAC,YAAY,eAAe,CAAE;AAE7D,KAAI,CAAC,aAAa,YAAY,KAAK,IAAI,OAAO,iBAAiB,EAAE;AAC/D,MAAI,YAAY,aAAa,CAC3B,OAAM,YAAY,MAAM;GACtB,SAAS;GACT,WAAW;GACZ,CAAC;AAEJ;;AAGF,KAAI,YAAY,UAAU,EACxB;MACE,YAAY,SAAS,WAAW,WAAW,IAC3C,YAAY,SAAS,WAAW,WAAW,EAC3C;GACA,IAAI,UAAU;AACd,OAAI,YAAY,SAAS,WAAW,WAAW,EAAE;IAC/C,MAAM,QAAQ,YAAY,SAAS,MAAM,IAAI;AAC7C,eAAW,MAAM;AACjB,qBAAiB,MAAM,MAAM;SAE7B,YAAW,YAAY,SAAS,QAAQ,YAAY,GAAG;AAGzD,SAAM,YAAY,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC;AAC5C,SAAM,YAAY,SAAS;IAAE,SAAS,oBAAoB,SAAS;IAAM,WAAW;IAAM,CAAC;AAC3F,OAAI;IACF,MAAM,eAAe,MAAM,kBAAkB;IAC7C,MAAM,eACJ,mBACC,YAAY,YACT,aAAa,iBAAiB,YAAY,YAAY,UAAU,OAAO,SACvE,OAAO;AACb,UAAM,KAAK,YAAY,OAAO;KAC5B,MAAM;KACN,QAAQ;KACR,MAAM;MACJ,SAAS,YAAY;MACrB,QAAQ;MACR,SAAS;MACT,QAAQ;MACT;KACF,CAAC;YACK,OAAO;AACd,YAAQ,MAAM,6CAA6C,MAAM;AACjE,UAAM,YAAY,SAAS;KACzB,SAAS,4BAA4B,SAAS;KAC9C,WAAW;KACZ,CAAC;;aAGJ,YAAY,SAAS,WAAW,UAAU,IAC1C,YAAY,SAAS,WAAW,UAAU,EAC1C;GACA,IAAI,UAAU;AACd,OAAI,YAAY,SAAS,WAAW,UAAU,EAAE;IAC9C,MAAM,QAAQ,YAAY,SAAS,MAAM,IAAI;AAC7C,eAAW,MAAM;AACjB,qBAAiB,MAAM,MAAM;UACxB;AACL,eAAW,YAAY,SAAS,QAAQ,WAAW,GAAG;AACtD,qBAAiB;;GAGnB,MAAM,QAAQ,IAAI,cAAc,CAC7B,YAAY,gBAAgB,SAAS,GAAG,iBAAiB,CACzD,SAAS,gBAAgB;GAE5B,MAAM,iBAAiB,IAAI,kBAAkB,CAC1C,YAAY,YAAY,CACxB,SAAS,uBAAuB,CAChC,SAAS,eAAe,UAAU,CAClC,YAAY,MAAM;GAErB,MAAM,YAAY,IAAI,kBAAoC,CAAC,cAAc,eAAe;AACxF,SAAM,cAAc,UAAU;AAE9B,SAAM,YAAY,UAAU,MAAM;;YAE3B,YAAY,eAAe,EACpC;MACE,YAAY,SAAS,WAAW,gBAAgB,IAChD,YAAY,SAAS,WAAW,gBAAgB,EAChD;GACA,IAAI,UAAU;AACd,OAAI,YAAY,SAAS,WAAW,gBAAgB,EAAE;IACpD,MAAM,QAAQ,YAAY,SAAS,MAAM,IAAI;AAC7C,eAAW,MAAM;AACjB,qBAAiB,MAAM,MAAM;SAE7B,YAAW,YAAY,SAAS,QAAQ,iBAAiB,GAAG;GAE9D,MAAM,YAAY,YAAY,OAAO,kBAAkB,YAAY;GAEnE,MAAM,UAAU,YAAY,WAAW,SAAS,GAAG,cAAc,WAAW;AAE5E,OAAI,YAAY,eAAe,EAAE;AAC/B,UAAM,YAAY,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC;AAC5C,UAAM,YAAY,SAAS;KACzB,SAAS,oBAAoB,SAAS;KACtC,WAAW;KACZ,CAAC;SAEF,OAAM,YAAY,MAAM;IAAE,SAAS,oBAAoB,SAAS;IAAM,WAAW;IAAM,CAAC;AAG1F,OAAI;IACF,MAAM,eAAe,MAAM,kBAAkB;IAC7C,MAAM,eACJ,mBACC,YAAY,YACT,aAAa,iBAAiB,YAAY,YAAY,UAAU,OAAO,SACvE,OAAO;AAEb,UAAM,KAAK,YAAY,OAAO;KAC5B,MAAM;KACN,QAAQ;KACR,MAAM;MACJ,SAAS;MACT,QAAQ;MACR,SAAS;MACT,QAAQ;MACT;KACF,CAAC;YACK,OAAO;AACd,YAAQ,MAAM,4CAA4C,MAAM;AAChE,UAAM,YAAY,SAAS;KACzB,SAAS,2BAA2B,SAAS;KAC7C,WAAW;KACZ,CAAC;;;;;;;;;;;;;;AC1IV,SAAgB,cAAc,UAAmC,EAAE,EAAE;CACnE,MAAM,aAAa,QAAQ,cAAc,eAAe;AAExD,KAAI,CAAC,GAAG,WAAW,WAAW,CAC5B,OAAM,IAAI,MAAM,2CAA2C,aAAa;CAG1E,MAAM,cAAc,sBAAsB,WAAW;AAGrD,QAAO,iBAA4B,EACjC,OAAO,CACL,UAAU;EACR,UAAU,IAAI;AACZ,UAAO,GAAG,SAAS;;EAErB,MAAM,qBAAqB;GACzB,KAAK;GACL,aAVkB,4BAA4B,WAAW;GAW1D,CAAC;EACF,OAAO,SAAS;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACH,CAAC,CACH,EACF,CAAC;;;;;ACfJ,eAAe,0BACb,QACA,eACA,QAC8F;CAE9F,MAAM,kBADQ,MAAM,kBAAkB,EACT,kBAAkB,EAAE;CAEjD,IAAI;AACJ,MAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO,QAAQ,eAAe,CACpE,KAAI,cAAc,WAAW,QAAQ;AACnC,2BAAyB;AACzB;;AAIJ,KAAI,uBACF,KAAI;EACF,MAAM,UAAU,MAAM,OAAO,SAAS,MAAM,uBAAuB;AACnE,MAAI,WAAW,QAAQ,aAAa,IAAI,CAAC,QAAQ,WAAW,CAC1D,QAAO;UAEF,OAAO;AACd,UAAQ,KACN,kCAAkC,uBAAuB,YAAY,OAAO,wBAC5E,MACD;;AAKL,SADa,MAAM,OAAO,MAAM,MAAM,cAAc,EACxC,UAAU;;AAGxB,eAAsB,8BACpB,QACA,MACA,eACA,UAII,EAAE,EACN;CACA,MAAM,gBAAgB,QAAQ,UAAU;CACxC,MAAM,SAAS,QAAQ;CACvB,MAAM,SAAS,QAAQ,UAAU,EAAE;CAEnC,MAAM,sCAAsB,IAAI,KAA0C;CAC1E,MAAM,4CAA4B,IAAI,KAA0C;CAChF,IAAI,+BAA+B,MAAM,kBAAkB,EAAE,wBAAwB,EAAE;CAEvF,MAAM,oBAAoB,OAAO,QAAgB,OAAe;AAC9D,gCAA8B;GAAE,GAAG;IAA8B,SAAS;GAAI;AAC9E,SAAO,oBAAoB,WAAW,EACpC,sBAAsB;GACpB,GAAG,MAAM;GACT,GAAG;GACJ,EACF,EAAE;;CAGL,MAAM,2BAA2B,OAAO,WAAmB;AACzD,MAAI,oBAAoB,IAAI,OAAO,CAAE;AACrC,MAAI,QAAQ,QAAS;EAErB,IAAI,gBAAgB,4BAA4B;AAEhD,MAAI,CAAC,cACH,KAAI;GACF,MAAM,WAAW,MAAM,KAAK,YAAY,MAAM;IAAE;IAAQ,OAAO;IAAG,CAAC;AACnE,OAAI,MAAM,QAAQ,SAAS,IAAI,SAAS,SAAS,GAAG;IAClD,MAAM,UAAU,SAAS,SAAS,SAAS;AAC3C,QAAI,SAAS;AACX,WAAM,kBAAkB,QAAQ,QAAQ,GAAG;AAC3C,qBAAgB,QAAQ;;;WAGrB,OAAO;AACd,OAAI,QAAQ,QAAS;AACrB,WAAQ,MAAM,oDAAoD,OAAO,IAAI,MAAM;;AAIvF,UAAQ,IACN,iDAAiD,OAAO,mBAAmB,gBAC5E;EAED,IAAI,aAAa;EACjB,MAAM,gBAAgB;EAEtB,IAAI,eAAmD;EACvD,IAAI,eAAe,QAAQ,SAAS;EAEpC,MAAM,gBAAgB;AACpB,OAAI,QAAQ,WAAW,CAAC,oBAAoB,IAAI,OAAO,CACrD;AAGF,kBAAe,KAAK,gBAAgB,UAClC;IAAE;IAAQ;IAAe,EACzB;IACE,SAAS,aAAa;AACpB,kBAAa;AAEb,SAAI,CAAC,MAAM,QAAQ,SAAS,IAAI,SAAS,WAAW,EAClD;AAIF,oBAAe,aAAa,KAAK,YAAY;AAC3C,WAAK,MAAM,cAAc,UAAU;AACjC,WAAI,QAAQ,WAAW,CAAC,oBAAoB,IAAI,OAAO,CAAE;OAEzD,MAAM,UAAU;AAIhB,WAFoB,qBAAqB,SAAS,OAAO,EAExC;QACf,MAAM,aAAa;AAInB,YAFE,WAAW,SAAS,YAAY,WAAW,WAAW,WAEnC;AACnB,aAAI;UACF,MAAM,KAAK,MAAM,0BAA0B,QAAQ,eAAe,OAAO;UAEzE,MAAM,QAAQ,IAAI,cAAc,CAC7B,SAAS,kCAAkC,CAC3C,eACC,WAAW,WAAW,oDACvB,CACA,SAAS,OAAO,OAAO;UAE1B,MAAM,WACH,eAAe,cAAc,WAAW,aAAc,WAAW;UACpE,MAAM,MAAM,IAAI,kBAAiC,CAAC,cAChD,IAAI,eAAe,CAChB,YAAY,WAAW,SAAS,GAAG,SAAS,CAC5C,SAAS,UAAU,CACnB,SAAS,YAAY,QAAQ,EAChC,IAAI,eAAe,CAChB,YAAY,UAAU,SAAS,GAAG,SAAS,CAC3C,SAAS,SAAS,CAClB,SAAS,YAAY,OAAO,CAChC;UAED,MAAM,aAAmC;WACvC,QAAQ,CAAC,MAAM;WACf,YAAY,CAAC,IAAI;WAClB;AAED,cAAI;AACF,iBAAM,GAAG,KAAK,WAAW;mBAClB,WAAW;AAClB,mBAAQ,KACN,+CAA+C,cAAc,gCAC7D,UACD;AACD,iBAAM,GAAG,KAAK,EACZ,SAAS,sCAAsC,WAAW,WAAW,oDAAoD,0BAA0B,SAAS,wBAAwB,SAAS,0BAC9L,CAAC;;kBAEG,OAAO;AACd,kBAAQ,MACN,0CAA0C,cAAc,IACxD,MACD;;AAGH,eAAM,kBAAkB,QAAQ,WAAW,GAAG,CAAC,MAAM,QAAQ,MAAM;AACnE,yBAAgB,WAAW;AAC3B;;AAGF,YAAI,WAAW,cAAc,WAAW,UAAU,WAAW;AAC3D,eAAM,kBAAkB,QAAQ,WAAW,GAAG,CAAC,MAAM,QAAQ,MAAM;AACnE,yBAAgB,WAAW;AAC3B;;QAGF,MAAM,aAAa,CAAC,CAAC,WAAW,SAAS,MAAM;QAC/C,MAAM,QAAQ,WAAW,aAAc,WAAW,QAAqB;QACvE,MAAM,WAAW,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS;QAKxD,IAAI,gBAA0B,EAAE;AAChC,YAAI,YAAY,OAAO;SACrB,MAAM,gBAAgB,iBAAiB,QAAQ,KAAK,CAAC;AACrD,yBAAgB,MAAM,KAAK,MAAM,KAAK,QAAQ,eAAe,EAAE,CAAC;;AAGlE,YAAI,CAAC,cAAc,CAAC,UAAU;AAC5B,eAAM,kBAAkB,QAAQ,WAAW,GAAG,CAAC,MAAM,QAAQ,MAAM;AACnE,yBAAgB,WAAW;AAC3B;;AAGF,YAAI;SACF,MAAM,KAAK,MAAM,0BAA0B,QAAQ,eAAe,OAAO;SACzE,MAAM,mBAAmB,cAAc,QAAQ;AAE/C,aAAI,oBAAoB,iBAAiB,SAAS,KAAM;UACtD,MAAM,SAAS,YAAY,kBAAkB,IAAK;AAClD,eAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,eAAI,QAAQ,WAAW,CAAC,oBAAoB,IAAI,OAAO,CAAE;WACzD,MAAM,eAAqC,EAAE,SAAS,OAAO,IAAc;AAC3E,eAAI,MAAM,OAAO,SAAS,KAAK,SAC7B,cAAa,QAAQ;AAEvB,iBAAM,GAAG,KAAK,aAAa;;gBAExB;UACL,MAAM,aAAmC,EAAE;AAC3C,cAAI,iBACF,YAAW,UAAU;AAEvB,cAAI,SACF,YAAW,QAAQ;AAErB,gBAAM,GAAG,KAAK,WAAW;;iBAEpB,OAAO;AACd,iBAAQ,MACN,0CAA0C,cAAc,IACxD,MACD;AACD;;;AAIJ,aAAM,kBAAkB,QAAQ,QAAQ,GAAG,CAAC,MAAM,QAAQ,MAAM;AAChE,uBAAgB,QAAQ;;OAE1B;;IAEJ,UAAU,UAAU;AAClB,aAAQ,MACN,yDAAyD,OAAO,gBAAgB,WAAW,MAC3F,MACD;AACD,mBAAc,aAAa;AAC3B,oBAAe;AAEf,SAAI,QAAQ,WAAW,CAAC,oBAAoB,IAAI,OAAO,CACrD;AAGF,sBAAiB;AACf,mBAAa,KAAK,IAAI,aAAa,GAAG,cAAc;AACpD,eAAS;QACR,WAAW;;IAEhB,kBAAkB;AAChB,oBAAe;AACf,SAAI,CAAC,QAAQ,WAAW,oBAAoB,IAAI,OAAO,CACrD,kBAAiB,SAAS,EAAE,WAAW;;IAG5C,CACF;;EAGH,IAAI,qBAAyD;EAC7D,IAAI,mBAAmB;EAEvB,MAAM,sBAAsB;AAC1B,OAAI,QAAQ,WAAW,CAAC,oBAAoB,IAAI,OAAO,CACrD;AAGF,wBAAqB,KAAK,cAAc,UACtC,EAAE,QAAQ,EACV;IACE,QAAQ,OAAO,UAAU;AACvB,wBAAmB;AACnB,SAAI,CAAC,MAAO;AAEZ,SAAI;MACF,MAAM,KAAK,MAAM,0BAA0B,QAAQ,eAAe,OAAO;AACzE,UAAI,GAAG,WACL,OAAM,GAAG,YAAY;cAEhB,OAAO;AACd,cAAQ,MACN,mDAAmD,cAAc,IACjE,MACD;;;IAGL,UAAU,UAAU;AAClB,aAAQ,MACN,gEAAgE,OAAO,gBAAgB,iBAAiB,MACxG,MACD;AACD,yBAAoB,aAAa;AACjC,0BAAqB;AAErB,SAAI,QAAQ,WAAW,CAAC,oBAAoB,IAAI,OAAO,CACrD;AAGF,sBAAiB;AACf,yBAAmB,KAAK,IAAI,mBAAmB,GAAG,cAAc;AAChE,qBAAe;QACd,iBAAiB;;IAEtB,kBAAkB;AAChB,0BAAqB;AACrB,SAAI,CAAC,QAAQ,WAAW,oBAAoB,IAAI,OAAO,CACrD,kBAAiB,eAAe,EAAE,iBAAiB;;IAGxD,CACF;;AAGH,sBAAoB,IAAI,QAAQ,EAC9B,mBAAmB,cAAc,aAAa,EAC/C,CAAC;AACF,4BAA0B,IAAI,QAAQ,EACpC,mBAAmB,oBAAoB,aAAa,EACrD,CAAC;AAEF,WAAS;AACT,iBAAe;;CAGjB,MAAM,oBAAoB,YAAY;AACpC,MAAI,QAAQ,QAAS;EACrB,MAAM,QAAQ,MAAM,kBAAkB;AAGtC,MAAI,MAAM,qBACR,+BAA8B;GAC5B,GAAG;GACH,GAAG,MAAM;GACV;EAGH,MAAM,gCAAgB,IAAI,KAAa;AACvC,gBAAc,IAAI,cAAc;AAEhC,MAAI,MAAM,gBACR;QAAK,MAAM,eAAe,OAAO,OAAO,MAAM,eAAe,CAC3D,KAAI,YAAY,OACd,eAAc,IAAI,YAAY,OAAO;;AAM3C,OAAK,MAAM,gBAAgB,cACzB,KAAI,CAAC,oBAAoB,IAAI,aAAa,CACxC,0BAAyB,aAAa;AAK1C,OAAK,MAAM,CAAC,cAAc,QAAQ,oBAAoB,SAAS,CAC7D,KAAI,CAAC,cAAc,IAAI,aAAa,EAAE;AACpC,OAAI,aAAa;AACjB,uBAAoB,OAAO,aAAa;AACxC,6BAA0B,IAAI,aAAa,EAAE,aAAa;AAC1D,6BAA0B,OAAO,aAAa;;;AAKpD,QAAO,IAAI,SAAe,YAAY;AACpC,qBAAmB,CAAC,MAAM,QAAQ,MAAM;EAExC,MAAM,YAAY,qBAAqB;EACvC,MAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,MAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,IAAG,UAAU,UAAU,EAAE,WAAW,MAAM,CAAC;EAE7C,IAAI,gBAAuC;EAC3C,MAAM,UAAU,GAAG,MAAM,WAAW,WAAmB,aAA4B;AACjF,OAAI,aAAa,KAAK,SAAS,UAAU,EAAE;AACzC,QAAI,cAAe,cAAa,cAAc;AAC9C,oBAAgB,iBAAiB;AAC/B,wBAAmB,CAAC,MAAM,QAAQ,MAAM;OACvC,IAAI;;IAET;AAEF,UAAQ,iBAAiB,eAAe;AACtC,OAAI,cAAe,cAAa,cAAc;AAC9C,WAAQ,OAAO;AACf,QAAK,MAAM,OAAO,oBAAoB,QAAQ,CAAE,KAAI,aAAa;AACjE,QAAK,MAAM,OAAO,0BAA0B,QAAQ,CAAE,KAAI,aAAa;AACvE,YAAS;IACT;GACF;;AAGJ,SAAS,YAAY,KAAa,MAAwB;CACxD,MAAM,SAAmB,EAAE;CAC3B,MAAM,QAAQ,MAAM,KAAK,IAAI;AAC7B,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,KACrC,QAAO,KAAK,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC;AAEhD,QAAO;;;;;AC9ZT,eAAsB,OAAO;AAG3B,KAFa,QAAQ,KAAK,MAAM,EAAE,CAEzB,OAAO,QAAQ;AACtB,QAAM,mBAAmB;AACzB;;AAGF,SAAQ,IAAI,8BAA8B;CAE1C,MAAM,SAAS,MAAM,mBAAmB;AACxC,KAAI,CAAC,QAAQ;AACX,UAAQ,MACN,kHACD;AACD,UAAQ,KAAK,EAAE;;CAGjB,MAAM,OAAO,eAAe;CAE5B,MAAM,SAAS,IAAI,OAAO;EACxB,SAAS;GACP,kBAAkB;GAClB,kBAAkB;GAClB,kBAAkB;GAClB,kBAAkB;GACnB;EACD,UAAU,CAAC,SAAS,QAAQ;EAC7B,CAAC;CAGF,MAAM,kBAAmC,EAAE,UAD7B,MAAM,kBAAkB,EACoB,SAAS;AAEnE,QAAO,KAAK,OAAO,cAAc,gBAAgB;AAC/C,UAAQ,IAAI,uBAAuB,YAAY,KAAK,MAAM;AAG1D,gCAA8B,aAAa,MAAM,OAAO,kBAAkB;GACxE,QAAQ,OAAO;GACf,QAAQ;GACT,CAAC,CAAC,OAAO,UAAU;AAClB,WAAQ,MAAM,yCAAyC,MAAM;IAC7D;GACF;AAEF,QAAO,GAAG,OAAO,eAAe,OAAO,YAAY;AAEjD,MAAI,QAAQ,OAAO,OAAO,OAAO,MAAM,GAAI;AAC3C,MAAI,QAAQ,OAAO,IAAK;EAExB,MAAM,oBAAoB,QAAQ;EAClC,MAAM,eAAe,MAAM,kBAAkB;EAC7C,MAAM,eAAe,aAAa,iBAAiB,oBAAoB;EACvE,MAAM,mBACJ,QAAQ,QAAQ,WAAW,QAAQ,IAAI,QAAQ,QAAQ,WAAW,SAAS;AAG7E,MAAI,QAAQ,OAAO;GACjB,MAAM,gBAAgB,aAAa,iBAAiB;AAMpD,OAJE,eAAe,mBAAmB,SAC9B,cAAc,iBACd,OAAO,gBAEQ;IACnB,MAAM,cAAc,QAAQ,SAAS,IAAI,OAAO,KAAM,GAAG;IACzD,IAAI,eAAe;AAEnB,QAAI,QAAQ,aAAa,QAAQ,UAAU,UACzC,KAAI;AAIF,qBAH0B,MAAM,QAAQ,QAAQ,SAAS,MACvD,QAAQ,UAAU,UACnB,EACgC,OAAO,OAAO,OAAO,KAAM;aACrD,KAAK;AACZ,aAAQ,MAAM,yDAAyD,IAAI;;AAI/E,QAAI,CAAC,eAAe,CAAC,aACnB;;;AAMN,MAAI,CAACC,eAAa,QAAQ,OAAO,IAAI,OAAO,iBAAiB,EAAE;AAC7D,WAAQ,IACN,6BAA6B,QAAQ,OAAO,IAAI,IAAI,QAAQ,OAAO,GAAG,YACvE;AACD;;AAGF,UAAQ,IAAI,yBAAyB,QAAQ,OAAO,IAAI,IAAI,QAAQ,UAAU;AAE9E,MAAI,kBAAkB;GACpB,MAAM,gBAAgB,OAAO,YAC3B,OAAO,QAAQ,aAAa,kBAAkB,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,CAAC,CACvF;GACD,MAAM,gBAAgB,MAAM,qBAC1B,QAAQ,SACR,mBACA,eACA,WACA,KACD;AAED,OAAI,eAAe;AACjB,QAAI,cAAc,SAAS,SACzB,OAAM,oBAAoB,iBAAiB,EACzC,gBAAgB;KACd,GAAI,YAAY,kBAAkB,EAAE;MACnC,oBAAoB;MACnB,GAAI,YAAY,iBAAiB,sBAAsB,EAAE;MACzD,QAAQ,cAAc;MACvB;KACF,EACF,EAAE;AAEL,UAAM,QAAQ,MAAM,cAAc,KAAK;AACvC;;;EAIJ,IAAI,eAAe;AAEnB,MAAI,CAAC,gBAAgB,CAAC,iBAKpB,KAHE,CAAC,aAAa,kBACd,OAAO,OAAO,aAAa,eAAe,CAAC,OAAO,UAAU,CAAC,MAAM,OAAO,EAEpD;AACtB,kBAAe,OAAO,UAAU;AAChC,WAAQ,IACN,yDAAyD,kBAAkB,WAAW,aAAa,GACpG;AACD,SAAM,oBAAoB,iBAAiB,EACzC,gBAAgB;IACd,GAAI,YAAY,kBAAkB,EAAE;KACnC,oBAAoB;KACnB,GAAI,YAAY,iBAAiB,sBAAsB,EAAE;KACzD,QAAQ;KACT;IACF,EACF,EAAE;SACE;GACL,MAAM,kBAAkB,CAAC,QAAQ;GACjC,MAAM,cAAc,QAAQ,SAAS,IAAI,OAAO,KAAM,GAAG;GACzD,MAAM,iBAAiB,QAAQ,QAAQ,WAAW,IAAI;AACtD,OAAI,mBAAmB,eAAe,gBAAgB;AACpD,YAAQ,IAAI,oBAAoB,kBAAkB,kCAAkC;AACpF,UAAM,QAAQ,MACZ,8HACD;SAED,SAAQ,IACN,oBAAoB,kBAAkB,yCACvC;AAEH;;AAKJ,MAAI,CAAC,aAAc,gBAAe,OAAO,UAAU;EAEnD,MAAM,gBAAgB,MAAM,qBAC1B,QAAQ,SACR,iBACA,MACA,aACD;AAED,MAAI,eAAe;AACjB,OAAI,cAAc,SAAS,QAAQ;AACjC,QAAI,cAAc,WAAW;AAC3B,qBAAgB,UAAU,cAAc,UAAU;AAClD,WAAM,mBAAmB,EAAE,SAAS,gBAAgB,SAAS,CAAC;;AAEhE,UAAM,QAAQ,MAAM,cAAc,KAAK;cAC9B,cAAc,SAAS,SAAS;IACzC,MAAM,YACJ,cAAc,SAAS,WAAW,IAC9B,0CACA,mBAAmB,cAAc,SAAS,OAAO,6BACjD,cAAc,SAAS,KAAK,QAAQ,cAAc,IAAI,CAAC,CAAC,KAAK,cAAc;AACjF,UAAM,QAAQ,MAAM,UAAU;;AAEhC;;EAGF,MAAM,kBAA4B,EAAE;AACpC,MAAI,QAAQ,YAAY,OAAO,GAAG;GAChC,MAAM,SAAS,KAAK,KAAK,eAAe,QAAQ,KAAK,CAAC,EAAE,OAAO,UAAU;AACzE,SAAMC,KAAG,MAAM,QAAQ,EAAE,WAAW,MAAM,CAAC;GAC3C,MAAM,YAAY,OAAO,uBAAuB;GAChD,MAAM,eAAe,YAAY,OAAO;AAExC,QAAK,MAAM,cAAc,QAAQ,YAAY,QAAQ,EAAE;AACrD,QAAI,WAAW,OAAO,cAAc;AAClC,aAAQ,KACN,cAAc,WAAW,KAAK,uBAAuB,UAAU,gBAChE;AACD,WAAM,QAAQ,MACZ,uBAAuB,WAAW,KAAK,6BAA6B,UAAU,qBAC/E;AACD;;AAGF,QAAI;KACF,MAAM,MAAM,MAAM,MAAM,WAAW,IAAI;AACvC,SAAI,CAAC,IAAI,IAAI;AACX,cAAQ,MAAM,iCAAiC,WAAW,OAAO;AACjE;;KAGF,MAAM,aAAa,GAAG,KAAK,KAAK,CAAC,GAAG,WAAW;KAC/C,MAAM,WAAW,KAAK,KAAK,QAAQ,WAAW;KAC9C,MAAM,cAAc,MAAM,IAAI,aAAa;AAC3C,WAAMA,KAAG,UAAU,UAAU,OAAO,KAAK,YAAY,CAAC;AACtD,qBAAgB,KAAK,SAAS;aACvB,KAAK;AACZ,aAAQ,MAAM,gCAAgC,WAAW,KAAK,IAAI,IAAI;;;;EAK5E,IAAI,eAAe,QAAQ;AAE3B,MAAI,QAAQ,aAAa,QAAQ,UAAU,UACzC,KAAI;GACF,MAAM,oBAAoB,MAAM,QAAQ,gBAAgB;AACxD,OAAI,qBAAqB,kBAAkB,QAKzC,gBAAe,GAJO,kBAAkB,QACrC,MAAM,KAAK,CACX,KAAK,SAAS,KAAK,OAAO,CAC1B,KAAK,KAAK,CACmB,IAAI;WAE/B,KAAK;AACZ,WAAQ,MAAM,uCAAuC,IAAI;;AAI7D,UAAQ,IAAI,iCAAiC,eAAe;AAC5D,MAAI;AACF,SAAM,KAAK,YAAY,OAAO;IAC5B,MAAM;IACN,QAAQ;IACR,MAAM;KACJ,SAAS;KACT,QAAQ;KACR,OAAO,gBAAgB,SAAS,IAAI,kBAAkB;KACtD,SAAS;KACT,QAAQ;KACT;IACF,CAAC;AACF,WAAQ,IAAI,4CAA4C;WACjD,OAAO;AACd,WAAQ,MAAM,wCAAwC,MAAM;;GAE9D;AAEF,QAAO,GAAG,OAAO,mBAAmB,OAAO,gBAAgB;AACzD,QAAM,yBAAyB,aAAa,QAAQ,KAAqC;GACzF;AAEF,KAAI;AACF,QAAM,OAAO,MAAM,OAAO,SAAS;UAC5B,OAAO;AACd,UAAQ,MAAM,+BAA+B,MAAM;AACnD,UAAQ,KAAK,EAAE;;;AAInB,MAAM,CAAC,OAAO,UAAU;AACtB,SAAQ,MAAM,uCAAuC,MAAM;AAC3D,SAAQ,KAAK,EAAE;EACf"}
1
+ {"version":3,"file":"index.mjs","names":["fs"],"sources":["../../src/adapter-discord/state.ts","../../src/adapter-discord/inbound-cache.ts","../../src/adapter-discord/processMessage.ts","../../src/adapter-discord/interactions.ts","../../src/adapter-discord/client.ts","../../src/adapter-discord/forwarder.ts","../../src/adapter-discord/commands.ts","../../src/adapter-discord/index.ts"],"sourcesContent":["import fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport { getClawminiDir } from '../shared/workspace.js';\n\nexport const DiscordStateSchema = z.object({\n lastSyncedMessageIds: z.record(z.string(), z.string()).optional(),\n channelChatMap: z\n .record(\n z.string(),\n z.object({\n chatId: z.string().nullable().optional(),\n requireMention: z.boolean().optional(),\n threadsDisabled: z.boolean().optional(),\n })\n )\n .optional(),\n filters: z.record(z.string(), z.boolean()).optional(),\n});\n\nexport type DiscordState = z.infer<typeof DiscordStateSchema>;\n\nexport function getDiscordStatePath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'discord', 'state.json');\n}\n\nexport async function readDiscordState(startDir = process.cwd()): Promise<DiscordState> {\n const statePath = getDiscordStatePath(startDir);\n try {\n const data = await fsPromises.readFile(statePath, 'utf-8');\n const parsed = JSON.parse(data);\n\n // Migrate legacy state\n if (parsed.lastSyncedMessageId && !parsed.lastSyncedMessageIds) {\n parsed.lastSyncedMessageIds = { default: parsed.lastSyncedMessageId };\n }\n if (parsed.channelChatMap) {\n for (const [key, value] of Object.entries(parsed.channelChatMap)) {\n if (typeof value === 'string') {\n parsed.channelChatMap[key] = { chatId: value };\n }\n }\n }\n\n return DiscordStateSchema.parse(parsed);\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw err;\n }\n}\n\nexport async function writeDiscordState(\n state: DiscordState,\n startDir = process.cwd()\n): Promise<void> {\n const statePath = getDiscordStatePath(startDir);\n const dir = path.dirname(statePath);\n try {\n await fsPromises.mkdir(dir, { recursive: true });\n await fsPromises.writeFile(statePath, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n console.error(`Failed to write Discord state to ${statePath}:`, err);\n }\n}\n\nlet stateUpdatePromise = Promise.resolve();\n\nexport function updateDiscordState(\n updates: Partial<DiscordState> | ((state: DiscordState) => Partial<DiscordState>),\n startDir = process.cwd()\n): Promise<DiscordState> {\n return new Promise((resolve, reject) => {\n stateUpdatePromise = stateUpdatePromise.then(async () => {\n try {\n const currentState = await readDiscordState(startDir);\n const resolvedUpdates = typeof updates === 'function' ? updates(currentState) : updates;\n const newState = { ...currentState, ...resolvedUpdates };\n await writeDiscordState(newState, startDir);\n resolve(newState);\n } catch (err) {\n console.error(`Failed to write Discord state:`, err);\n reject(err);\n }\n });\n });\n}\n","/**\n * Discord-side wrapper around the shared inbound-message TTL cache.\n *\n * On every inbound user message, the gateway records `{ messageId, channelId\n * }`. The same `messageId` is sent to the daemon as `externalRef` on the\n * `sendMessage` mutation. When the forwarder later sees `turnStarted` with\n * that `externalRef`, it resolves the channel + message id and starts a\n * Discord thread anchored on the user's message.\n */\nimport { createInboundCache } from '../shared/adapters/inbound-cache.js';\n\nexport const INBOUND_TTL_MS = 10 * 60 * 1000; // 10 minutes\n\ninterface DiscordInboundValue {\n channelId: string;\n}\n\nconst cache = createInboundCache<DiscordInboundValue>(INBOUND_TTL_MS);\n\nexport interface DiscordInboundRecord {\n messageId: string;\n channelId: string;\n}\n\nexport function recordInbound(entry: DiscordInboundRecord): void {\n cache.record(entry.messageId, { channelId: entry.channelId });\n}\n\nexport function resolveInbound(messageId: string): DiscordInboundRecord | null {\n const value = cache.resolve(messageId);\n return value ? { messageId, channelId: value.channelId } : null;\n}\n\n/** Test hook: drop all cached records. */\nexport function _resetInboundCacheForTests(): void {\n cache.reset();\n}\n","import { readDiscordState, updateDiscordState } from './state.js';\nimport type { DiscordConfig } from './config.js';\nimport { recordInbound } from './inbound-cache.js';\nimport { handleAdapterCommand, type CommandTrpcClient } from '../shared/adapters/commands.js';\nimport { formatMessage, type FilteringConfig } from '../shared/adapters/filtering.js';\nimport { handleRoutingCommand, type RoutingTrpcClient } from '../shared/adapters/routing.js';\nimport { prependBlockquote } from '../shared/adapters/blockquote.js';\nimport { getClawminiDir } from '../shared/workspace.js';\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\n\nexport type ProcessMessageOptions = {\n mentionsBot?: boolean;\n isReplyToBot?: boolean;\n attachments?: { name: string; size: number; url: string }[];\n referenceContent?: string;\n referenceAuthor?: string;\n explicitChatId?: string;\n /**\n * Discord message id of the inbound. Recorded in the in-memory inbound\n * cache and sent to the daemon as `externalRef` so the forwarder can\n * resolve the user's message and start a Discord thread anchored on it\n * when `turnStarted` arrives.\n */\n messageId?: string;\n};\n\nexport async function processDiscordMessage(\n content: string,\n author: { id: string; tag: string; bot?: boolean },\n channelId: string | null,\n guild: unknown | null,\n reply: (text: string) => Promise<unknown>,\n config: DiscordConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n trpc: any,\n filteringConfig: FilteringConfig,\n options: ProcessMessageOptions = {}\n) {\n if (author.bot) return;\n\n const externalContextId = channelId || 'default';\n const currentState = await readDiscordState();\n const mappedChatId =\n options.explicitChatId || (channelId ? currentState.channelChatMap?.[channelId]?.chatId : null);\n const isRoutingCommand = content.startsWith('/chat') || content.startsWith('/agent');\n\n // Enforce requireMention config for guild messages\n if (guild && channelId) {\n const channelConfig = currentState.channelChatMap?.[channelId];\n const requiresMention =\n channelConfig?.requireMention !== undefined\n ? channelConfig.requireMention\n : config.requireMention;\n\n if (requiresMention) {\n if (!options.mentionsBot && !options.isReplyToBot) {\n return;\n }\n }\n }\n\n function isAuthorized(userId: string, authorizedUserId: string): boolean {\n return userId === authorizedUserId;\n }\n\n // Check if the user is authorized\n if (!isAuthorized(author.id, config.authorizedUserId)) {\n console.log(`Unauthorized message from ${author.tag} (${author.id}) ignored.`);\n return;\n }\n\n console.log(`Received message from ${author.tag}: ${content}`);\n\n if (isRoutingCommand) {\n const stringChatMap = Object.fromEntries(\n Object.entries(currentState.channelChatMap || {}).map(([k, v]) => [k, v.chatId || ''])\n );\n const routingResult = await handleRoutingCommand(\n content,\n externalContextId,\n stringChatMap,\n 'discord',\n trpc as unknown as RoutingTrpcClient\n );\n\n if (routingResult) {\n if (routingResult.type === 'mapped') {\n await updateDiscordState((latestState) => ({\n channelChatMap: {\n ...(latestState.channelChatMap || {}),\n [externalContextId]: {\n ...(latestState.channelChatMap?.[externalContextId] || {}),\n chatId: routingResult.newChatId,\n },\n },\n }));\n }\n await reply(routingResult.text);\n return;\n }\n }\n\n let targetChatId = mappedChatId;\n\n if (!targetChatId && !isRoutingCommand) {\n const isFirstEverMessage =\n !currentState.channelChatMap ||\n Object.values(currentState.channelChatMap).every((entry) => !entry.chatId);\n\n if (isFirstEverMessage) {\n targetChatId = config.chatId || 'default';\n console.log(\n `First contact detected. Automatically mapping channel ${externalContextId} to chat ${targetChatId}.`\n );\n await updateDiscordState((latestState) => ({\n channelChatMap: {\n ...(latestState.channelChatMap || {}),\n [externalContextId]: {\n ...(latestState.channelChatMap?.[externalContextId] || {}),\n chatId: targetChatId as string,\n },\n },\n }));\n } else {\n const isDirectMessage = !guild;\n const isSlashCommand = content.startsWith('/');\n if (isDirectMessage || options.mentionsBot || isSlashCommand) {\n console.log(`Unmapped channel ${externalContextId}, sending first contact warning.`);\n await reply(\n 'This channel/space is not currently mapped to a daemon chat. Please use `/chat [chat-id]` or `/agent [agent-id]` to map it.'\n );\n } else {\n console.log(`Unmapped channel ${externalContextId}, silently ignoring background message.`);\n }\n return;\n }\n }\n\n // Fallback typing safeguard\n if (!targetChatId) targetChatId = config.chatId || 'default';\n\n const commandResult = await handleAdapterCommand(\n content,\n filteringConfig,\n trpc as unknown as CommandTrpcClient,\n targetChatId\n );\n\n if (commandResult) {\n if (commandResult.type === 'text') {\n if (commandResult.newConfig) {\n filteringConfig.filters = commandResult.newConfig.filters;\n await updateDiscordState({ filters: filteringConfig.filters });\n }\n await reply(commandResult.text);\n } else if (commandResult.type === 'debug') {\n // Debug output echoes raw message content (which may include @everyone /\n // @here as a substring). The `reply` lambda already strips mentions, so\n // there's no extra escaping to do here.\n const formatted =\n commandResult.messages.length === 0\n ? 'No ignored background messages found.'\n : `**Debug Output (${commandResult.messages.length} ignored messages):**\\n\\n` +\n commandResult.messages.map((msg) => formatMessage(msg)).join('\\n\\n---\\n\\n');\n await reply(formatted);\n }\n return;\n }\n\n const downloadedFiles: string[] = [];\n if (options.attachments && options.attachments.length > 0) {\n const tmpDir = path.join(getClawminiDir(process.cwd()), 'tmp', 'discord');\n await fs.mkdir(tmpDir, { recursive: true });\n const maxSizeMB = config.maxAttachmentSizeMB ?? 25;\n const maxSizeBytes = maxSizeMB * 1024 * 1024;\n\n for (const attachment of options.attachments) {\n if (attachment.size > maxSizeBytes) {\n console.warn(\n `Attachment ${attachment.name} exceeds size limit (${maxSizeMB}MB). Ignoring.`\n );\n await reply(\n `Warning: Attachment ${attachment.name} exceeds the size limit of ${maxSizeMB}MB and was ignored.`\n );\n continue;\n }\n\n try {\n const res = await fetch(attachment.url);\n if (!res.ok) {\n console.error(`Failed to download attachment ${attachment.name}`);\n continue;\n }\n\n const uniqueName = `${Date.now()}-${attachment.name}`;\n const filePath = path.join(tmpDir, uniqueName);\n const arrayBuffer = await res.arrayBuffer();\n await fs.writeFile(filePath, Buffer.from(arrayBuffer));\n downloadedFiles.push(filePath);\n } catch (err) {\n console.error(`Error downloading attachment ${attachment.name}:`, err);\n }\n }\n }\n\n let finalContent = content;\n\n if (options.referenceContent) {\n finalContent = prependBlockquote(\n options.referenceContent,\n finalContent,\n options.referenceAuthor\n );\n }\n\n console.log(`Forwarding message to daemon: ${finalContent}`);\n if (options.messageId && channelId) {\n recordInbound({ messageId: options.messageId, channelId });\n }\n try {\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: finalContent,\n chatId: targetChatId,\n files: downloadedFiles.length > 0 ? downloadedFiles : undefined,\n adapter: 'discord',\n noWait: true,\n ...(options.messageId ? { externalRef: options.messageId } : {}),\n },\n });\n console.log('Message forwarded to daemon successfully.');\n } catch (error) {\n console.error('Failed to forward message to daemon:', error);\n await reply('Failed to forward message to the daemon. Please check the logs.');\n }\n}\n","import {\n ActionRowBuilder,\n ModalBuilder,\n TextInputBuilder,\n TextInputStyle,\n type Interaction,\n} from 'discord.js';\nimport type { DiscordConfig } from './config.js';\nimport { readDiscordState } from './state.js';\nimport { type FilteringConfig } from '../shared/adapters/filtering.js';\nimport { processDiscordMessage } from './processMessage.js';\n\nfunction isAuthorized(userId: string, authorizedUserId: string): boolean {\n return userId === authorizedUserId;\n}\n\nexport async function handleDiscordInteraction(\n interaction: Interaction,\n config: DiscordConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n trpc: any,\n filteringConfig: FilteringConfig\n) {\n if (\n !interaction.isButton() &&\n !interaction.isModalSubmit() &&\n !interaction.isChatInputCommand()\n ) {\n return;\n }\n\n if (!isAuthorized(interaction.user.id, config.authorizedUserId)) {\n if (interaction.isRepliable()) {\n await interaction.reply({\n content: 'You are not authorized to perform this action.',\n ephemeral: true,\n });\n }\n return;\n }\n\n if (interaction.isChatInputCommand()) {\n const { commandName } = interaction;\n let commandStr = `/${commandName}`;\n\n if (commandName === 'approve' || commandName === 'reject') {\n const policyId = interaction.options.getString('policy_id');\n if (policyId) commandStr += ` ${policyId}`;\n }\n if (commandName === 'reject') {\n const rationale = interaction.options.getString('rationale');\n if (rationale) commandStr += ` ${rationale}`;\n }\n\n await interaction.deferReply({ ephemeral: true });\n\n const currentState = await readDiscordState();\n const targetChatId = interaction.channelId\n ? currentState.channelChatMap?.[interaction.channelId]?.chatId || config.chatId\n : config.chatId;\n\n let replied = false;\n await processDiscordMessage(\n commandStr,\n interaction.user,\n interaction.channelId,\n interaction.guild,\n async (text) => {\n replied = true;\n await interaction.followUp({ content: text, ephemeral: true });\n },\n config,\n trpc,\n filteringConfig,\n { explicitChatId: targetChatId, mentionsBot: true }\n );\n\n if (!replied) {\n await interaction.deleteReply();\n }\n return;\n }\n\n if (interaction.isButton()) {\n if (\n interaction.customId.startsWith('approve_') ||\n interaction.customId.startsWith('approve|')\n ) {\n let policyId, explicitChatId;\n if (interaction.customId.startsWith('approve|')) {\n const parts = interaction.customId.split('|');\n policyId = parts[1];\n explicitChatId = parts[2] || undefined;\n } else {\n policyId = interaction.customId.replace('approve_', '');\n }\n\n await interaction.update({ components: [] });\n await interaction.followUp({ content: `Approving policy ${policyId}...`, ephemeral: true });\n\n const currentState = await readDiscordState();\n const targetChatId =\n explicitChatId ||\n (interaction.channelId\n ? currentState.channelChatMap?.[interaction.channelId]?.chatId || config.chatId\n : config.chatId);\n\n await processDiscordMessage(\n `/approve ${policyId}`,\n interaction.user,\n interaction.channelId,\n interaction.guild,\n async (text) => {\n await interaction.followUp({ content: text, ephemeral: true });\n },\n config,\n trpc,\n filteringConfig,\n { explicitChatId: targetChatId, mentionsBot: true }\n );\n } else if (\n interaction.customId.startsWith('reject_') ||\n interaction.customId.startsWith('reject|')\n ) {\n let policyId, explicitChatId;\n if (interaction.customId.startsWith('reject|')) {\n const parts = interaction.customId.split('|');\n policyId = parts[1];\n explicitChatId = parts[2] || '';\n } else {\n policyId = interaction.customId.replace('reject_', '');\n explicitChatId = '';\n }\n\n const modal = new ModalBuilder()\n .setCustomId(`modal_reject|${policyId}|${explicitChatId}`)\n .setTitle('Reject Policy');\n\n const rationaleInput = new TextInputBuilder()\n .setCustomId('rationale')\n .setLabel('Rationale (optional)')\n .setStyle(TextInputStyle.Paragraph)\n .setRequired(false);\n\n const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(rationaleInput);\n modal.addComponents(actionRow);\n\n await interaction.showModal(modal);\n }\n } else if (interaction.isModalSubmit()) {\n if (\n interaction.customId.startsWith('modal_reject_') ||\n interaction.customId.startsWith('modal_reject|')\n ) {\n let policyId, explicitChatId;\n if (interaction.customId.startsWith('modal_reject|')) {\n const parts = interaction.customId.split('|');\n policyId = parts[1];\n explicitChatId = parts[2] || undefined;\n } else {\n policyId = interaction.customId.replace('modal_reject_', '');\n }\n const rationale = interaction.fields.getTextInputValue('rationale');\n\n const command = rationale ? `/reject ${policyId} ${rationale}` : `/reject ${policyId}`;\n\n if (interaction.isFromMessage()) {\n await interaction.update({ components: [] });\n await interaction.followUp({\n content: `Rejecting policy ${policyId}...`,\n ephemeral: true,\n });\n } else {\n await interaction.deferReply({ ephemeral: true });\n await interaction.followUp({ content: `Rejecting policy ${policyId}...`, ephemeral: true });\n }\n\n const currentState = await readDiscordState();\n const targetChatId =\n explicitChatId ||\n (interaction.channelId\n ? currentState.channelChatMap?.[interaction.channelId]?.chatId || config.chatId\n : config.chatId);\n\n await processDiscordMessage(\n command,\n interaction.user,\n interaction.channelId,\n interaction.guild,\n async (text) => {\n await interaction.followUp({ content: text, ephemeral: true });\n },\n config,\n trpc,\n filteringConfig,\n { explicitChatId: targetChatId, mentionsBot: true }\n );\n }\n }\n}\n","import { createTRPCClient, httpLink, splitLink, httpSubscriptionLink } from '@trpc/client';\nimport type { UserRouter as AppRouter } from '../daemon/api/index.js';\nimport { getSocketPath } from '../shared/workspace.js';\nimport { createUnixSocketFetch } from '../shared/fetch.js';\nimport { createUnixSocketEventSource } from '../shared/event-source.js';\nimport fs from 'node:fs';\n\n/**\n * Creates a TRPC client that connects to the Clawmini daemon via a Unix socket.\n *\n * @param options - Configuration options for the client.\n * @returns A TRPC client instance for the AppRouter.\n */\nexport function getTRPCClient(options: { socketPath?: string } = {}) {\n const socketPath = options.socketPath ?? getSocketPath();\n\n if (!fs.existsSync(socketPath)) {\n throw new Error(`Daemon not running. Socket not found at ${socketPath}`);\n }\n\n const customFetch = createUnixSocketFetch(socketPath);\n const CustomEventSource = createUnixSocketEventSource(socketPath);\n\n return createTRPCClient<AppRouter>({\n links: [\n splitLink({\n condition(op) {\n return op.type === 'subscription';\n },\n true: httpSubscriptionLink({\n url: 'http://localhost',\n EventSource: CustomEventSource,\n }),\n false: httpLink({\n url: 'http://localhost',\n fetch: customFetch,\n }),\n }),\n ],\n });\n}\n","/* eslint-disable max-lines */\nimport type {\n Client,\n MessageCreateOptions,\n TextChannel,\n DMChannel,\n NewsChannel,\n ThreadChannel,\n VoiceChannel,\n StageChannel,\n Message,\n} from 'discord.js';\nimport { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } from 'discord.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport type { getTRPCClient } from './client.js';\nimport type { DiscordConfig } from './config.js';\nimport { readDiscordState, updateDiscordState, getDiscordStatePath } from './state.js';\nimport { resolveInbound } from './inbound-cache.js';\nimport { createTurnLogBuffer, type TurnLogBuffer } from '../shared/adapters/turn-log-buffer.js';\nimport type { ChatMessage } from '../shared/chats.js';\nimport { getWorkspaceRoot } from '../shared/workspace.js';\nimport {\n routeMessage,\n formatMessage,\n type Destination,\n type FilteringConfig,\n} from '../shared/adapters/filtering.js';\n\ntype AnyTextChannel =\n | TextChannel\n | DMChannel\n | NewsChannel\n | ThreadChannel\n | VoiceChannel\n | StageChannel;\n\ninterface ThreadLogOptions {\n maxToolPreview: number;\n maxLogMessageChars: number;\n editDebounceMs: number;\n}\n\nconst DEFAULT_THREAD_LOG_OPTS: ThreadLogOptions = {\n maxToolPreview: 400,\n // Discord caps messages at 2000 chars; leave headroom for the rollover marker.\n maxLogMessageChars: 1800,\n editDebounceMs: 1000,\n};\n\nfunction resolveThreadLogOpts(config?: DiscordConfig): ThreadLogOptions {\n const v = config?.visibility?.threadLog;\n return {\n maxToolPreview: v?.maxToolPreview ?? DEFAULT_THREAD_LOG_OPTS.maxToolPreview,\n maxLogMessageChars: v?.maxLogMessageChars ?? DEFAULT_THREAD_LOG_OPTS.maxLogMessageChars,\n editDebounceMs: v?.editDebounceMs ?? DEFAULT_THREAD_LOG_OPTS.editDebounceMs,\n };\n}\n\n// Suppresses every form of mention (@everyone, @here, role, user) on bot\n// posts. Tool payloads, agent output, and policy descriptions can contain\n// arbitrary text; without this, an `@everyone` substring in (e.g.) a shell\n// command echoed into the activity log would page the entire channel.\nconst NO_MENTIONS = { allowedMentions: { parse: [] as [] } } as const;\n\nasync function resolveDiscordDestination(\n client: Client,\n discordUserId: string,\n chatId: string\n): Promise<AnyTextChannel> {\n const state = await readDiscordState();\n const channelChatMap = state.channelChatMap || {};\n\n let targetDiscordChannelId: string | undefined;\n for (const [channelId, mappedChatId] of Object.entries(channelChatMap)) {\n if (mappedChatId?.chatId === chatId) {\n targetDiscordChannelId = channelId;\n break;\n }\n }\n\n if (targetDiscordChannelId) {\n try {\n const channel = await client.channels.fetch(targetDiscordChannelId);\n if (channel && channel.isTextBased() && !channel.isDMBased()) {\n return channel as TextChannel | NewsChannel | ThreadChannel | VoiceChannel | StageChannel;\n }\n } catch (error) {\n console.warn(\n `Failed to fetch mapped channel ${targetDiscordChannelId} for chat ${chatId}, falling back to DM.`,\n error\n );\n }\n }\n\n const user = await client.users.fetch(discordUserId);\n return user.createDM();\n}\n\nexport async function startDaemonToDiscordForwarder(\n client: Client,\n trpc: ReturnType<typeof getTRPCClient>,\n discordUserId: string,\n options: {\n chatId?: string;\n signal?: AbortSignal;\n config?: FilteringConfig;\n discordConfig?: DiscordConfig;\n } = {}\n) {\n const defaultChatId = options.chatId ?? 'default';\n const signal = options.signal;\n const config = options.config ?? {};\n const threadLogOpts = resolveThreadLogOpts(options.discordConfig);\n const threadsGloballyEnabled = options.discordConfig?.visibility?.threads !== false;\n\n const activeSubscriptions = new Map<string, { unsubscribe: () => void }>();\n const activeTypingSubscriptions = new Map<string, { unsubscribe: () => void }>();\n let currentLastSyncedMessageIds = (await readDiscordState()).lastSyncedMessageIds || {};\n\n const saveLastMessageId = async (chatId: string, id: string) => {\n currentLastSyncedMessageIds = { ...currentLastSyncedMessageIds, [chatId]: id };\n return updateDiscordState((state) => ({\n lastSyncedMessageIds: {\n ...state.lastSyncedMessageIds,\n ...currentLastSyncedMessageIds,\n },\n }));\n };\n\n const postThreaded = async (anchor: ThreadChannel, text: string): Promise<string | undefined> => {\n const sent = await anchor.send({ content: text || '​', ...NO_MENTIONS });\n return sent.id;\n };\n\n const editThreaded = async (\n anchor: ThreadChannel,\n messageId: string,\n text: string\n ): Promise<void> => {\n const msg = await anchor.messages.fetch(messageId);\n await msg.edit({ content: text || '​', ...NO_MENTIONS });\n };\n\n // Discord returns 10008 (Unknown Message) when an activity-log message has\n // been deleted by the user; Cloudflare/HTTP layers may surface a generic\n // 404. Either case means the same thing: open a fresh log message.\n const isMissingMessageError = (err: unknown): boolean => {\n const code = (err as { code?: number; status?: number })?.code ?? 0;\n return code === 404 || code === 10008;\n };\n\n const turnLog: TurnLogBuffer<ThreadChannel> = createTurnLogBuffer<ThreadChannel>({\n postThreaded,\n editThreaded,\n isMissingMessageError,\n options: threadLogOpts,\n threadsEnabled: threadsGloballyEnabled,\n });\n\n const collapseDestination = (dest: Destination, turnId?: string): Destination => {\n // Both the global `visibility.threads: false` kill switch and the\n // per-channel `threadsDisabled` flag mean \"quiet bot\": drop thread-log\n // activity rather than promoting it top-level. Top-level spam is only\n // opt-in via `filters` (e.g. `/show`), matching pre-threaded behavior.\n if (dest.kind !== 'thread-log') return dest;\n if (!threadsGloballyEnabled) return { kind: 'drop' };\n if (turnId && turnLog.threadsDisabledFor(turnId)) return { kind: 'drop' };\n return dest;\n };\n\n const channelThreadsDisabled = async (chatId: string): Promise<boolean> => {\n const state = await readDiscordState();\n for (const [, entry] of Object.entries(state.channelChatMap || {})) {\n if (entry?.chatId === chatId) return entry.threadsDisabled === true;\n }\n return false;\n };\n\n const openThreadForTurn = async (\n externalRef: string | undefined\n ): Promise<ThreadChannel | undefined> => {\n if (!externalRef) return undefined;\n const inbound = resolveInbound(externalRef);\n if (!inbound) return undefined;\n let channel: AnyTextChannel | null;\n try {\n channel = (await client.channels.fetch(inbound.channelId)) as AnyTextChannel | null;\n } catch (err) {\n console.warn(`Failed to fetch channel ${inbound.channelId} for turn anchor:`, err);\n return undefined;\n }\n if (!channel || !channel.isTextBased() || channel.isDMBased() || channel.isThread()) {\n // DMs and existing threads can't host a new thread. Skip silently —\n // proactive turns and DM-only flows simply have no activity log.\n return undefined;\n }\n const guildChannel = channel as TextChannel | NewsChannel;\n let userMessage: Message;\n try {\n userMessage = await guildChannel.messages.fetch(inbound.messageId);\n } catch (err) {\n console.warn(`Failed to fetch user message ${inbound.messageId} for turn anchor:`, err);\n return undefined;\n }\n // Discord allows only one thread per message. The same inbound can anchor\n // multiple turns (e.g. a follow-up turn fanned out from the original\n // request), so reuse an existing thread rather than failing the second\n // turn's activity log.\n if (userMessage.hasThread && userMessage.thread) {\n return userMessage.thread as ThreadChannel;\n }\n try {\n return await userMessage.startThread({\n name: 'Activity log',\n // 1 day. Long agent runs (refactors, builds) outlive the previous\n // 60-minute archive window and end up posting into archived threads\n // that fall off the channel sidebar.\n autoArchiveDuration: 1440,\n });\n } catch (err) {\n // Race: another turn for the same inbound created the thread between\n // our `hasThread` check and `startThread`. Discord returns 160004\n // (THREAD_ALREADY_CREATED_FOR_MESSAGE). Re-fetch and reuse.\n const code = (err as { code?: number })?.code;\n if (code === 160004) {\n try {\n const refreshed = await guildChannel.messages.fetch(inbound.messageId);\n if (refreshed.hasThread && refreshed.thread) {\n return refreshed.thread as ThreadChannel;\n }\n } catch (refetchErr) {\n console.warn(\n `Failed to refetch user message ${inbound.messageId} after thread-exists race:`,\n refetchErr\n );\n }\n }\n console.warn(`Failed to start thread on message ${inbound.messageId}:`, err);\n return undefined;\n }\n };\n\n const handleTurnStarted = async (chatId: string, turnId: string, externalRef?: string) => {\n // Single source of truth for \"is the activity log on for this turn\":\n // global kill switch OR per-channel opt-out. The buffer's `engaged()`\n // and `collapseDestination`'s `threadsDisabledFor()` both consult the\n // ctx flag set here, so we don't have to re-derive it later.\n const threadsDisabled = !threadsGloballyEnabled || (await channelThreadsDisabled(chatId));\n // Skip the API roundtrip when we already know the log is off.\n const anchor = threadsDisabled ? undefined : await openThreadForTurn(externalRef);\n // No anchor and threads enabled: proactive turn (cron, subagent, CLI),\n // DM-only flow, or thread creation failed. Skip start entirely so the\n // buffer doesn't accrue entries it can never flush.\n if (!anchor && !threadsDisabled) return;\n turnLog.start({ turnId, threadsDisabled, anchorThread: anchor });\n };\n\n const handleTurnEnded = async (turnId: string) => {\n await turnLog.end(turnId);\n };\n\n const sendPolicyCard = async (chatId: string, message: ChatMessage): Promise<boolean> => {\n if (message.role !== 'policy' || message.status !== 'pending') return false;\n try {\n const dm = await resolveDiscordDestination(client, discordUserId, chatId);\n\n const embed = new EmbedBuilder()\n .setTitle('Action Required: Policy Request')\n .setDescription(message.content || 'A pending policy request requires your attention.')\n .setColor(Colors.Yellow);\n\n const policyId = ('requestId' in message && message.requestId) || message.id;\n const row = new ActionRowBuilder<ButtonBuilder>().addComponents(\n new ButtonBuilder()\n .setCustomId(`approve|${policyId}|${chatId}`)\n .setLabel('Approve')\n .setStyle(ButtonStyle.Success),\n new ButtonBuilder()\n .setCustomId(`reject|${policyId}|${chatId}`)\n .setLabel('Reject')\n .setStyle(ButtonStyle.Danger)\n );\n\n const optionsMsg: MessageCreateOptions = {\n embeds: [embed],\n components: [row],\n ...NO_MENTIONS,\n };\n\n try {\n await dm.send(optionsMsg);\n } catch (richError) {\n console.warn(\n `Failed to send rich message to Discord user ${discordUserId}, falling back to plain text:`,\n richError\n );\n await dm.send({\n content: `Action Required: Policy Request\\n\\n${\n message.content || 'A pending policy request requires your attention.'\n }\\n\\nApprove: \\`/approve ${policyId}\\`\\nReject: \\`/reject ${policyId} <optional_rationale>\\``,\n ...NO_MENTIONS,\n });\n }\n } catch (error) {\n console.error(`Failed to send message to Discord user ${discordUserId}:`, error);\n }\n return true;\n };\n\n const sendTopLevel = async (chatId: string, message: ChatMessage): Promise<void> => {\n if ('level' in message && (message as { level?: string }).level === 'verbose') return;\n\n const hasContent = !!message.content?.trim();\n const files = 'files' in message ? ((message as { files?: string[] }).files ?? []) : [];\n const hasFiles = Array.isArray(files) && files.length > 0;\n\n let absoluteFiles: string[] = [];\n if (hasFiles) {\n const workspaceRoot = getWorkspaceRoot(process.cwd());\n absoluteFiles = files.map((f) => path.resolve(workspaceRoot, f));\n }\n\n if (!hasContent && !hasFiles) return;\n\n try {\n const dm = await resolveDiscordDestination(client, discordUserId, chatId);\n const formattedContent = formatMessage(message);\n\n if (formattedContent && formattedContent.length > 2000) {\n const chunks = chunkString(formattedContent, 2000);\n for (let i = 0; i < chunks.length; i++) {\n if (signal?.aborted) break;\n const chunkOptions: MessageCreateOptions = {\n content: chunks[i] as string,\n ...NO_MENTIONS,\n };\n if (i === chunks.length - 1 && hasFiles) {\n chunkOptions.files = absoluteFiles;\n }\n await dm.send(chunkOptions);\n }\n } else {\n const optionsMsg: MessageCreateOptions = { ...NO_MENTIONS };\n if (formattedContent) optionsMsg.content = formattedContent;\n if (hasFiles) optionsMsg.files = absoluteFiles;\n await dm.send(optionsMsg);\n }\n } catch (error) {\n console.error(`Failed to send message to Discord user ${discordUserId}:`, error);\n throw error;\n }\n };\n\n const handleMessageForChat = async (chatId: string, message: ChatMessage): Promise<void> => {\n const routed = routeMessage(message, config);\n const effective = collapseDestination(routed, message.turnId);\n\n if (effective.kind === 'drop') return;\n\n if (effective.kind === 'thread-log') {\n if (!message.turnId) {\n console.warn(`thread-log event for ${message.role} has no turnId — dropping.`);\n return;\n }\n // No turn context: turnStarted may have been missed (adapter restart,\n // subscription reconnect) or the turn had no anchor (proactive / DM).\n // Drop silently rather than flooding the chat.\n if (!turnLog.has(message.turnId)) return;\n turnLog.append(message.turnId, message);\n return;\n }\n\n // Top-level.\n if (message.role === 'policy' && message.status === 'pending') {\n await sendPolicyCard(chatId, message);\n return;\n }\n\n await sendTopLevel(chatId, message);\n };\n\n const startSubscriptionForChat = async (chatId: string) => {\n if (activeSubscriptions.has(chatId)) return;\n if (signal?.aborted) return;\n\n let lastMessageId = currentLastSyncedMessageIds[chatId];\n\n if (!lastMessageId) {\n try {\n const messages = await trpc.getMessages.query({ chatId, limit: 1 });\n if (Array.isArray(messages) && messages.length > 0) {\n const lastMsg = messages[messages.length - 1];\n if (lastMsg) {\n await saveLastMessageId(chatId, lastMsg.id);\n lastMessageId = lastMsg.id;\n }\n }\n } catch (error) {\n if (signal?.aborted) return;\n console.error(`Failed to fetch initial messages from daemon for ${chatId}:`, error);\n }\n }\n\n console.log(\n `Starting daemon-to-discord forwarder for chat ${chatId}, lastMessageId: ${lastMessageId}`\n );\n\n let retryDelay = 1000;\n const maxRetryDelay = 30000;\n\n let subscription: { unsubscribe: () => void } | null = null;\n let messageQueue = Promise.resolve();\n\n type StreamItem =\n | { kind: 'message'; message: ChatMessage }\n | {\n kind: 'turn';\n event:\n | { type: 'started'; turnId: string; rootMessageId: string; externalRef?: string }\n | { type: 'ended'; turnId: string; outcome: 'ok' | 'error' };\n };\n\n const connect = () => {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n subscription = trpc.waitForMessages.subscribe(\n { chatId, lastMessageId },\n {\n onData: (items) => {\n retryDelay = 1000; // Reset retry delay on successful data\n\n if (!Array.isArray(items) || items.length === 0) {\n return;\n }\n\n messageQueue = messageQueue\n .then(async () => {\n for (const raw of items) {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) break;\n\n const item = raw as StreamItem;\n if (item.kind === 'turn') {\n // Turn events do disk reads (state.json) and Discord API\n // fetches; either can throw transiently. Catch here so a\n // single bad event doesn't reject the .then and poison\n // the chain — every subsequent batch would silently no-op.\n try {\n if (item.event.type === 'started') {\n await handleTurnStarted(chatId, item.event.turnId, item.event.externalRef);\n } else {\n await handleTurnEnded(item.event.turnId);\n }\n } catch (err) {\n console.error('Failed to handle turn event:', err);\n }\n continue;\n }\n\n const message = item.message;\n try {\n await handleMessageForChat(chatId, message);\n } catch (err) {\n console.error('Failed to handle message:', err);\n // Don't advance lastMessageId on a hard error so we retry on\n // reconnect; matches prior behavior.\n break;\n }\n\n await saveLastMessageId(chatId, message.id).catch(console.error);\n lastMessageId = message.id;\n }\n })\n // Belt-and-suspenders: anything that escapes the per-item\n // try/catches above (sync throw before the loop, etc.) must\n // not leave the chain in a rejected state.\n .catch((err) => console.error('Message queue chain error:', err));\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord forwarder subscription for ${chatId}. Retrying in ${retryDelay}ms.`,\n error\n );\n subscription?.unsubscribe();\n subscription = null;\n\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n setTimeout(() => {\n retryDelay = Math.min(retryDelay * 2, maxRetryDelay);\n connect();\n }, retryDelay);\n },\n onComplete: () => {\n subscription = null;\n if (!signal?.aborted && activeSubscriptions.has(chatId)) {\n setTimeout(() => connect(), retryDelay);\n }\n },\n }\n );\n };\n\n let typingSubscription: { unsubscribe: () => void } | null = null;\n let typingRetryDelay = 1000;\n\n const connectTyping = () => {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n typingSubscription = trpc.waitForTyping.subscribe(\n { chatId },\n {\n onData: async (event) => {\n typingRetryDelay = 1000;\n if (!event) return;\n\n try {\n const dm = await resolveDiscordDestination(client, discordUserId, chatId);\n if (dm.sendTyping) {\n await dm.sendTyping();\n }\n } catch (error) {\n console.error(\n `Failed to send typing indicator to Discord user ${discordUserId}:`,\n error\n );\n }\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord typing forwarder subscription for ${chatId}. Retrying in ${typingRetryDelay}ms.`,\n error\n );\n typingSubscription?.unsubscribe();\n typingSubscription = null;\n\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n\n setTimeout(() => {\n typingRetryDelay = Math.min(typingRetryDelay * 2, maxRetryDelay);\n connectTyping();\n }, typingRetryDelay);\n },\n onComplete: () => {\n typingSubscription = null;\n if (!signal?.aborted && activeSubscriptions.has(chatId)) {\n setTimeout(() => connectTyping(), typingRetryDelay);\n }\n },\n }\n );\n };\n\n activeSubscriptions.set(chatId, {\n unsubscribe: () => subscription?.unsubscribe(),\n });\n activeTypingSubscriptions.set(chatId, {\n unsubscribe: () => typingSubscription?.unsubscribe(),\n });\n\n connect();\n connectTyping();\n };\n\n const syncSubscriptions = async () => {\n if (signal?.aborted) return;\n const state = await readDiscordState();\n\n // Update local copy of last message IDs\n if (state.lastSyncedMessageIds) {\n currentLastSyncedMessageIds = {\n ...currentLastSyncedMessageIds,\n ...state.lastSyncedMessageIds,\n };\n }\n\n const targetChatIds = new Set<string>();\n targetChatIds.add(defaultChatId);\n\n if (state.channelChatMap) {\n for (const mappedEntry of Object.values(state.channelChatMap)) {\n if (mappedEntry.chatId) {\n targetChatIds.add(mappedEntry.chatId);\n }\n }\n }\n\n // Start new subscriptions\n for (const targetChatId of targetChatIds) {\n if (!activeSubscriptions.has(targetChatId)) {\n startSubscriptionForChat(targetChatId);\n }\n }\n\n // Teardown old subscriptions\n for (const [activeChatId, sub] of activeSubscriptions.entries()) {\n if (!targetChatIds.has(activeChatId)) {\n sub.unsubscribe();\n activeSubscriptions.delete(activeChatId);\n activeTypingSubscriptions.get(activeChatId)?.unsubscribe();\n activeTypingSubscriptions.delete(activeChatId);\n }\n }\n };\n\n return new Promise<void>((resolve) => {\n syncSubscriptions().catch(console.error);\n\n const statePath = getDiscordStatePath();\n const stateDir = path.dirname(statePath);\n if (!fs.existsSync(stateDir)) {\n fs.mkdirSync(stateDir, { recursive: true });\n }\n let debounceTimer: NodeJS.Timeout | null = null;\n const watcher = fs.watch(stateDir, (eventType: string, filename: string | null) => {\n if (filename === path.basename(statePath)) {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n syncSubscriptions().catch(console.error);\n }, 200);\n }\n });\n\n signal?.addEventListener('abort', () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher.close();\n for (const sub of activeSubscriptions.values()) sub.unsubscribe();\n for (const sub of activeTypingSubscriptions.values()) sub.unsubscribe();\n turnLog.shutdown();\n resolve();\n });\n });\n}\n\nfunction chunkString(str: string, size: number): string[] {\n const chunks: string[] = [];\n const chars = Array.from(str);\n for (let i = 0; i < chars.length; i += size) {\n chunks.push(chars.slice(i, i + size).join(''));\n }\n return chunks;\n}\n","import { SlashCommandBuilder } from 'discord.js';\n\nexport const slashCommands = [\n new SlashCommandBuilder().setName('new').setDescription('Start a new chat or operation.'),\n new SlashCommandBuilder().setName('stop').setDescription('Stop the current operation.'),\n new SlashCommandBuilder()\n .setName('approve')\n .setDescription('Approve a pending policy request.')\n .addStringOption((option) =>\n option\n .setName('policy_id')\n .setDescription('The ID of the policy to approve')\n .setRequired(true)\n ),\n new SlashCommandBuilder()\n .setName('reject')\n .setDescription('Reject a pending policy request.')\n .addStringOption((option) =>\n option.setName('policy_id').setDescription('The ID of the policy to reject').setRequired(true)\n )\n .addStringOption((option) =>\n option\n .setName('rationale')\n .setDescription('Optional rationale for rejecting the policy')\n .setRequired(false)\n ),\n new SlashCommandBuilder().setName('pending').setDescription('List pending policy requests.'),\n new SlashCommandBuilder().setName('show').setDescription('Show background messages.'),\n new SlashCommandBuilder().setName('hide').setDescription('Hide background messages.'),\n new SlashCommandBuilder()\n .setName('debug')\n .setDescription('Output debug information about ignored background messages.'),\n];\n","#!/usr/bin/env node\n\nimport { Client, Events, GatewayIntentBits, Partials, REST, Routes } from 'discord.js';\nimport { readDiscordConfig, initDiscordConfig } from './config.js';\nimport { readDiscordState } from './state.js';\nimport { handleDiscordInteraction } from './interactions.js';\nimport { getTRPCClient } from './client.js';\nimport { startDaemonToDiscordForwarder } from './forwarder.js';\nimport { slashCommands } from './commands.js';\nimport { type CommandTrpcClient } from '../shared/adapters/commands.js';\nimport { type FilteringConfig } from '../shared/adapters/filtering.js';\n\nimport { processDiscordMessage } from './processMessage.js';\n\nexport async function main() {\n const args = process.argv.slice(2);\n\n if (args[0] === 'init') {\n await initDiscordConfig();\n return;\n }\n\n console.log('Discord Adapter starting...');\n\n const config = await readDiscordConfig();\n if (!config) {\n console.error(\n 'Failed to load Discord configuration. Please ensure .clawmini/adapters/discord/config.json exists and is valid.'\n );\n process.exit(1);\n }\n\n const trpc = getTRPCClient();\n\n const client = new Client({\n intents: [\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n ],\n partials: [Partials.Channel],\n });\n\n const state = await readDiscordState();\n const filteringConfig: FilteringConfig = { filters: state.filters };\n\n client.once(Events.ClientReady, async (readyClient) => {\n console.log(`Ready! Logged in as ${readyClient.user.tag}`);\n\n // Workaround: pre-cache the authorized user's DM channel so inbound\n // DMs aren't dropped before they reach the MessageCreate handler.\n // discord.js >= 14.26 can't construct a partial DMChannel from a\n // MESSAGE_CREATE payload (no `type`, no `recipients`), and the\n // ChannelManager silently drops the dispatch when the channel isn't\n // already in cache. Opening the DM here populates the cache so later\n // events short-circuit to the existing entry.\n // See: https://github.com/discordjs/discord.js/issues/11486\n try {\n const user = await readyClient.users.fetch(config.authorizedUserId);\n await user.createDM();\n } catch (err) {\n console.error(\n `Failed to pre-cache DM channel for authorized user ${config.authorizedUserId}:`,\n err\n );\n }\n\n try {\n const rest = new REST({ version: '10' }).setToken(config.botToken);\n console.log('Started refreshing application (/) commands.');\n await rest.put(Routes.applicationCommands(readyClient.user.id), {\n body: slashCommands.map((cmd) => cmd.toJSON()),\n });\n console.log('Successfully reloaded application (/) commands.');\n } catch (error) {\n console.error('Error registering slash commands:', error);\n }\n\n // Start forwarding from daemon to Discord\n startDaemonToDiscordForwarder(readyClient, trpc, config.authorizedUserId, {\n chatId: config.chatId,\n config: filteringConfig,\n discordConfig: config,\n }).catch((error) => {\n console.error('Error in daemon-to-discord forwarder:', error);\n });\n });\n\n client.on(Events.MessageCreate, async (message) => {\n let isReplyToBot = false;\n let referenceContent: string | undefined;\n let referenceAuthor: string | undefined;\n\n if (message.reference && message.reference.messageId) {\n try {\n const referencedMessage = await message.fetchReference();\n isReplyToBot = referencedMessage?.author.id === client.user!.id;\n referenceContent = referencedMessage?.content;\n if (referencedMessage) {\n if (referencedMessage.author.bot) {\n referenceAuthor = 'Assistant';\n } else if (referencedMessage.author.id !== config.authorizedUserId) {\n referenceAuthor = referencedMessage.author.username;\n }\n }\n } catch (err) {\n console.error('Failed to fetch referenced message for mention check:', err);\n }\n }\n\n const attachments = message.attachments\n ? Array.from(message.attachments.values()).map((att) => ({\n name: att.name,\n size: att.size,\n url: att.url,\n }))\n : [];\n\n await processDiscordMessage(\n message.content,\n message.author,\n message.channelId,\n message.guild,\n async (text) => {\n await message.reply({ content: text, allowedMentions: { parse: [] } });\n },\n config,\n trpc,\n filteringConfig,\n {\n mentionsBot: !!message.mentions?.has(client.user!.id),\n isReplyToBot,\n attachments,\n messageId: message.id,\n ...(referenceContent ? { referenceContent } : {}),\n ...(referenceAuthor ? { referenceAuthor } : {}),\n }\n );\n });\n\n client.on(Events.InteractionCreate, async (interaction) => {\n await handleDiscordInteraction(\n interaction,\n config,\n trpc as unknown as CommandTrpcClient,\n filteringConfig\n );\n });\n\n try {\n await client.login(config.botToken);\n } catch (error) {\n console.error('Failed to login to Discord:', error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error('Unhandled error in Discord Adapter:', error);\n process.exit(1);\n});\n"],"mappings":"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"}