clawmini 0.0.3 → 0.0.5

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 (333) hide show
  1. package/README.md +19 -0
  2. package/dist/adapter-discord/index.d.mts.map +1 -1
  3. package/dist/adapter-discord/index.mjs +398 -193
  4. package/dist/adapter-discord/index.mjs.map +1 -1
  5. package/dist/adapter-google-chat/index.d.mts +5 -0
  6. package/dist/adapter-google-chat/index.d.mts.map +1 -0
  7. package/dist/adapter-google-chat/index.mjs +1077 -0
  8. package/dist/adapter-google-chat/index.mjs.map +1 -0
  9. package/dist/cli/index.mjs +107 -14
  10. package/dist/cli/index.mjs.map +1 -1
  11. package/dist/cli/lite.mjs +175 -16
  12. package/dist/cli/lite.mjs.map +1 -1
  13. package/dist/cli/propose-policy.d.mts +1 -0
  14. package/dist/cli/propose-policy.mjs +7159 -0
  15. package/dist/cli/propose-policy.mjs.map +1 -0
  16. package/dist/daemon/index.d.mts.map +1 -1
  17. package/dist/daemon/index.mjs +1427 -513
  18. package/dist/daemon/index.mjs.map +1 -1
  19. package/dist/{lite-oSYSvaOr.mjs → lite-CBxOT1y5.mjs} +101 -24
  20. package/dist/lite-CBxOT1y5.mjs.map +1 -0
  21. package/dist/routing-D8rTxtaV.mjs +245 -0
  22. package/dist/routing-D8rTxtaV.mjs.map +1 -0
  23. package/dist/web/_app/immutable/assets/0.C-4eziNy.css +1 -0
  24. package/dist/web/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
  25. package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +1 -0
  26. package/dist/web/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
  27. package/{web/.svelte-kit/output/client/_app/immutable/chunks/8YNcRyEk.js → dist/web/_app/immutable/chunks/C20lZMGz.js} +1 -1
  28. package/dist/web/_app/immutable/chunks/C9lbZ-kT.js +1 -0
  29. package/dist/web/_app/immutable/chunks/CK9JZLaG.js +2 -0
  30. package/dist/web/_app/immutable/chunks/CME08kGM.js +1 -0
  31. package/dist/web/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
  32. package/dist/web/_app/immutable/chunks/Ck3rYNON.js +1 -0
  33. package/dist/web/_app/immutable/chunks/DMtIqaiV.js +2 -0
  34. package/dist/web/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
  35. package/dist/web/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
  36. package/dist/web/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
  37. package/dist/web/_app/immutable/chunks/DsIToJCP.js +1 -0
  38. package/dist/web/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
  39. package/{web/.svelte-kit/output/client/_app/immutable/entry/app.DO5eYwVz.js → dist/web/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
  40. package/dist/web/_app/immutable/entry/start.DuxJo6av.js +1 -0
  41. package/dist/web/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
  42. package/dist/web/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
  43. package/dist/web/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
  44. package/dist/web/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
  45. package/dist/web/_app/immutable/nodes/4.DLarELN4.js +60 -0
  46. package/dist/web/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
  47. package/dist/web/_app/version.json +1 -1
  48. package/dist/web/index.html +12 -12
  49. package/dist/{workspace-DjoNjhW0.mjs → workspace-BJmJBfKi.mjs} +103 -11
  50. package/dist/workspace-BJmJBfKi.mjs.map +1 -0
  51. package/docs/14_google_chat_adapter/development_log.md +40 -0
  52. package/docs/14_google_chat_adapter/notes.md +28 -0
  53. package/docs/14_google_chat_adapter/prd.md +35 -0
  54. package/docs/14_google_chat_adapter/questions.md +9 -0
  55. package/docs/14_google_chat_adapter/tickets.md +117 -0
  56. package/docs/15_sandbox_policies/tickets.md +33 -0
  57. package/docs/16_session_timeout/development_log.md +20 -0
  58. package/docs/16_session_timeout/notes.md +44 -0
  59. package/docs/16_session_timeout/prd.md +106 -0
  60. package/docs/16_session_timeout/questions.md +10 -0
  61. package/docs/16_session_timeout/tickets.md +64 -0
  62. package/docs/17_auto_approve_policy/development_log.md +29 -0
  63. package/docs/17_auto_approve_policy/notes.md +25 -0
  64. package/docs/17_auto_approve_policy/prd.md +34 -0
  65. package/docs/17_auto_approve_policy/questions.md +10 -0
  66. package/docs/17_auto_approve_policy/tickets.md +11 -0
  67. package/docs/18_clawmini_skills/development_log.md +36 -0
  68. package/docs/18_clawmini_skills/notes.md +8 -0
  69. package/docs/18_clawmini_skills/prd.md +45 -0
  70. package/docs/18_clawmini_skills/questions.md +10 -0
  71. package/docs/18_clawmini_skills/tickets.md +55 -0
  72. package/docs/19_subagents/development_log.md +69 -0
  73. package/docs/19_subagents/notes.md +18 -0
  74. package/docs/19_subagents/prd.md +156 -0
  75. package/docs/19_subagents/questions.md +13 -0
  76. package/docs/19_subagents/tickets.md +113 -0
  77. package/docs/20_chat_logs_cleanup/development_log.md +50 -0
  78. package/docs/20_chat_logs_cleanup/notes.md +43 -0
  79. package/docs/20_chat_logs_cleanup/prd.md +232 -0
  80. package/docs/20_chat_logs_cleanup/questions.md +2 -0
  81. package/docs/20_chat_logs_cleanup/tickets.md +98 -0
  82. package/docs/20_webui_markdown/development_log.md +36 -0
  83. package/docs/20_webui_markdown/notes.md +23 -0
  84. package/docs/20_webui_markdown/prd.md +49 -0
  85. package/docs/20_webui_markdown/questions.md +10 -0
  86. package/docs/20_webui_markdown/tickets.md +55 -0
  87. package/docs/21_adapter_filtering/development_log.md +29 -0
  88. package/docs/21_adapter_filtering/notes.md +25 -0
  89. package/docs/21_adapter_filtering/prd.md +44 -0
  90. package/docs/21_adapter_filtering/questions.md +12 -0
  91. package/docs/21_adapter_filtering/tickets.md +38 -0
  92. package/docs/21_built_in_routers/development_log.md +17 -0
  93. package/docs/21_built_in_routers/notes.md +27 -0
  94. package/docs/21_built_in_routers/prd.md +34 -0
  95. package/docs/21_built_in_routers/questions.md +4 -0
  96. package/docs/21_built_in_routers/tickets.md +25 -0
  97. package/docs/21_fancy_policies/development_log.md +38 -0
  98. package/docs/21_fancy_policies/notes.md +27 -0
  99. package/docs/21_fancy_policies/prd.md +58 -0
  100. package/docs/21_fancy_policies/questions.md +6 -0
  101. package/docs/21_fancy_policies/tickets.md +48 -0
  102. package/docs/22_adapter_multi_chat/development_log.md +76 -0
  103. package/docs/22_adapter_multi_chat/notes.md +42 -0
  104. package/docs/22_adapter_multi_chat/prd.md +76 -0
  105. package/docs/22_adapter_multi_chat/questions.md +16 -0
  106. package/docs/22_adapter_multi_chat/tickets.md +164 -0
  107. package/docs/23_custom_token_env/development_log.md +31 -0
  108. package/docs/23_custom_token_env/notes.md +16 -0
  109. package/docs/23_custom_token_env/prd.md +42 -0
  110. package/docs/23_custom_token_env/questions.md +8 -0
  111. package/docs/23_custom_token_env/tickets.md +54 -0
  112. package/docs/guides/discord_adapter_setup.md +15 -2
  113. package/docs/guides/google_chat_adapter_setup.md +145 -0
  114. package/napkin.md +5 -0
  115. package/package.json +7 -2
  116. package/src/adapter-discord/config.test.ts +27 -8
  117. package/src/adapter-discord/config.ts +6 -8
  118. package/src/adapter-discord/forwarder.test.ts +307 -114
  119. package/src/adapter-discord/forwarder.ts +260 -75
  120. package/src/adapter-discord/index.test.ts +278 -0
  121. package/src/adapter-discord/index.ts +160 -30
  122. package/src/adapter-discord/interactions.test.ts +96 -0
  123. package/src/adapter-discord/interactions.ts +156 -0
  124. package/src/adapter-discord/state.test.ts +9 -8
  125. package/src/adapter-discord/state.ts +51 -8
  126. package/src/adapter-google-chat/auth.test.ts +87 -0
  127. package/src/adapter-google-chat/auth.ts +132 -0
  128. package/src/adapter-google-chat/cards.ts +71 -0
  129. package/src/adapter-google-chat/client.test.ts +561 -0
  130. package/src/adapter-google-chat/client.ts +430 -0
  131. package/src/adapter-google-chat/config.test.ts +187 -0
  132. package/src/adapter-google-chat/config.ts +82 -0
  133. package/src/adapter-google-chat/cron.test.ts +143 -0
  134. package/src/adapter-google-chat/cron.ts +81 -0
  135. package/src/adapter-google-chat/forwarder.test.ts +537 -0
  136. package/src/adapter-google-chat/forwarder.ts +349 -0
  137. package/src/adapter-google-chat/index.test.ts +62 -0
  138. package/src/adapter-google-chat/index.ts +61 -0
  139. package/src/adapter-google-chat/state.test.ts +96 -0
  140. package/src/adapter-google-chat/state.ts +85 -0
  141. package/src/adapter-google-chat/subscriptions.ts +124 -0
  142. package/src/adapter-google-chat/upload.ts +88 -0
  143. package/src/adapter-google-chat/utils.test.ts +111 -0
  144. package/src/adapter-google-chat/utils.ts +133 -0
  145. package/src/cli/commands/init.ts +0 -7
  146. package/src/cli/commands/messages.ts +18 -3
  147. package/src/cli/commands/policies.ts +70 -0
  148. package/src/cli/commands/skills.ts +71 -0
  149. package/src/cli/commands/web-api/chats.ts +5 -1
  150. package/src/cli/e2e/basic.test.ts +1 -1
  151. package/src/cli/e2e/cron.test.ts +1 -1
  152. package/src/cli/e2e/daemon.test.ts +132 -4
  153. package/src/cli/e2e/export-lite-func.test.ts +54 -31
  154. package/src/cli/e2e/fallbacks.test.ts +8 -6
  155. package/src/cli/e2e/init.test.ts +7 -0
  156. package/src/cli/e2e/messages.test.ts +90 -55
  157. package/src/cli/e2e/propose-policy.test.ts +203 -0
  158. package/src/cli/e2e/requests.test.ts +15 -0
  159. package/src/cli/e2e/session-timeout.test.ts +192 -0
  160. package/src/cli/e2e/skills.test.ts +55 -0
  161. package/src/cli/e2e/slash-new.test.ts +93 -0
  162. package/src/cli/e2e/subagents.test.ts +106 -0
  163. package/src/cli/index.ts +4 -0
  164. package/src/cli/lite.ts +51 -11
  165. package/src/cli/propose-policy.ts +91 -0
  166. package/src/cli/subagent-commands.ts +215 -0
  167. package/src/daemon/agent/agent-context.ts +89 -0
  168. package/src/daemon/agent/agent-extractors.ts +68 -0
  169. package/src/daemon/agent/agent-runner.ts +153 -0
  170. package/src/daemon/agent/agent-session.ts +261 -0
  171. package/src/daemon/agent/chat-logger.test.ts +158 -0
  172. package/src/daemon/agent/chat-logger.ts +188 -0
  173. package/src/daemon/agent/task-scheduler.test.ts +202 -0
  174. package/src/daemon/agent/task-scheduler.ts +276 -0
  175. package/src/daemon/agent/types.ts +84 -0
  176. package/src/daemon/agent/utils.ts +7 -0
  177. package/src/daemon/api/agent-router.ts +166 -18
  178. package/src/daemon/api/index.test.ts +50 -18
  179. package/src/daemon/api/policy-request.test.ts +39 -2
  180. package/src/daemon/api/subagent-router.test.ts +108 -0
  181. package/src/daemon/api/subagent-router.ts +296 -0
  182. package/src/daemon/api/subagent-utils.test.ts +56 -0
  183. package/src/daemon/api/subagent-utils.ts +130 -0
  184. package/src/daemon/api/user-router.ts +30 -13
  185. package/src/daemon/auth.ts +1 -0
  186. package/src/daemon/chats.ts +6 -0
  187. package/src/daemon/cron.test.ts +66 -1
  188. package/src/daemon/cron.ts +35 -8
  189. package/src/daemon/index.ts +23 -0
  190. package/src/daemon/message-agent.test.ts +11 -25
  191. package/src/daemon/message-extraction.test.ts +10 -27
  192. package/src/daemon/message-fallbacks.test.ts +13 -35
  193. package/src/daemon/message-interruption.test.ts +70 -53
  194. package/src/daemon/message-jobs.test.ts +138 -0
  195. package/src/daemon/message-queue.test.ts +30 -43
  196. package/src/daemon/message-router.test.ts +12 -11
  197. package/src/daemon/message-session.test.ts +41 -28
  198. package/src/daemon/message-typing.test.ts +19 -6
  199. package/src/daemon/message.ts +103 -515
  200. package/src/daemon/policy-request-service.ts +8 -3
  201. package/src/daemon/policy-utils.ts +19 -1
  202. package/src/daemon/queue.ts +16 -0
  203. package/src/daemon/request-store.test.ts +4 -0
  204. package/src/daemon/routers/session-timeout.test.ts +122 -0
  205. package/src/daemon/routers/session-timeout.ts +71 -0
  206. package/src/daemon/routers/slash-new.ts +3 -1
  207. package/src/daemon/routers/slash-policies.test.ts +26 -13
  208. package/src/daemon/routers/slash-policies.ts +39 -29
  209. package/src/daemon/routers/types.ts +8 -0
  210. package/src/daemon/routers.ts +64 -2
  211. package/src/daemon/utils/spawn.ts +6 -8
  212. package/src/shared/adapters/commands.test.ts +155 -0
  213. package/src/shared/adapters/commands.ts +125 -0
  214. package/src/shared/adapters/filtering.test.ts +111 -0
  215. package/src/shared/adapters/filtering.ts +57 -0
  216. package/src/shared/adapters/routing.test.ts +144 -0
  217. package/src/shared/adapters/routing.ts +109 -0
  218. package/src/shared/agent-utils.ts +10 -0
  219. package/src/shared/chats.test.ts +145 -3
  220. package/src/shared/chats.ts +215 -18
  221. package/src/shared/config.ts +67 -15
  222. package/src/shared/lite.ts +22 -18
  223. package/src/shared/policies.ts +7 -0
  224. package/src/shared/workspace.test.ts +45 -1
  225. package/src/shared/workspace.ts +119 -6
  226. package/templates/debug/settings.json +5 -2
  227. package/templates/environments/cladding/env.json +2 -2
  228. package/templates/gemini/.gemini/hooks/check-subagents.mjs +23 -0
  229. package/templates/gemini/.gemini/hooks/clawmini-logging.sh +17 -0
  230. package/templates/gemini/.gemini/hooks/insert-pending.sh +9 -0
  231. package/templates/gemini/.gemini/settings.json +50 -0
  232. package/templates/gemini/settings.json +22 -8
  233. package/templates/gemini-claw/.gemini/base-system.md +100 -0
  234. package/templates/gemini-claw/.gemini/hooks/check-subagents.mjs +23 -0
  235. package/templates/gemini-claw/.gemini/hooks/clawmini-logging.sh +1 -1
  236. package/templates/gemini-claw/.gemini/settings.json +13 -0
  237. package/templates/gemini-claw/.gemini/subagent-system.md +7 -0
  238. package/templates/gemini-claw/.gemini/system.md +3 -99
  239. package/templates/gemini-claw/settings.json +27 -22
  240. package/templates/skills/clawmini-requests/SKILL.md +92 -0
  241. package/templates/skills/clawmini-subagents/SKILL.md +79 -0
  242. package/templates/skills/skill-creator/SKILL.md +60 -0
  243. package/tsdown.config.ts +10 -1
  244. package/web/.svelte-kit/generated/server/internal.js +2 -1
  245. package/web/.svelte-kit/non-ambient.d.ts +2 -0
  246. package/web/.svelte-kit/output/client/.vite/manifest.json +141 -138
  247. package/web/.svelte-kit/output/client/_app/immutable/assets/0.C-4eziNy.css +1 -0
  248. package/web/.svelte-kit/output/client/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
  249. package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +1 -0
  250. package/web/.svelte-kit/output/client/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
  251. package/{dist/web/_app/immutable/chunks/8YNcRyEk.js → web/.svelte-kit/output/client/_app/immutable/chunks/C20lZMGz.js} +1 -1
  252. package/web/.svelte-kit/output/client/_app/immutable/chunks/C9lbZ-kT.js +1 -0
  253. package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +2 -0
  254. package/web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js +1 -0
  255. package/web/.svelte-kit/output/client/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
  256. package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +1 -0
  257. package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +2 -0
  258. package/web/.svelte-kit/output/client/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
  259. package/web/.svelte-kit/output/client/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
  260. package/web/.svelte-kit/output/client/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
  261. package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +1 -0
  262. package/web/.svelte-kit/output/client/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
  263. package/{dist/web/_app/immutable/entry/app.DO5eYwVz.js → web/.svelte-kit/output/client/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
  264. package/web/.svelte-kit/output/client/_app/immutable/entry/start.DuxJo6av.js +1 -0
  265. package/web/.svelte-kit/output/client/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
  266. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
  267. package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
  268. package/web/.svelte-kit/output/client/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
  269. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.DLarELN4.js +60 -0
  270. package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
  271. package/web/.svelte-kit/output/client/_app/version.json +1 -1
  272. package/web/.svelte-kit/output/server/.vite/manifest.json +12 -3
  273. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.C-4eziNy.css +1 -0
  274. package/web/.svelte-kit/output/server/_app/immutable/assets/_page.Cc_xwLNl.css +1 -0
  275. package/web/.svelte-kit/output/server/chunks/app-state.svelte.js +5 -0
  276. package/web/.svelte-kit/output/server/chunks/bot.js +4 -4
  277. package/web/.svelte-kit/output/server/chunks/client.js +2 -1
  278. package/web/.svelte-kit/output/server/chunks/exports.js +0 -1
  279. package/web/.svelte-kit/output/server/chunks/internal.js +2 -1
  280. package/web/.svelte-kit/output/server/chunks/root.js +482 -392
  281. package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +57 -7
  282. package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.svelte.js +234 -9
  283. package/web/.svelte-kit/output/server/index.js +82 -10
  284. package/web/.svelte-kit/output/server/manifest-full.js +1 -1
  285. package/web/.svelte-kit/output/server/manifest.js +1 -1
  286. package/web/.svelte-kit/output/server/nodes/0.js +2 -2
  287. package/web/.svelte-kit/output/server/nodes/1.js +1 -1
  288. package/web/.svelte-kit/output/server/nodes/2.js +1 -1
  289. package/web/.svelte-kit/output/server/nodes/3.js +1 -1
  290. package/web/.svelte-kit/output/server/nodes/4.js +2 -2
  291. package/web/.svelte-kit/output/server/nodes/5.js +1 -1
  292. package/web/.svelte-kit/types/src/routes/$types.d.ts +1 -2
  293. package/web/.svelte-kit/types/src/routes/agents/$types.d.ts +1 -2
  294. package/web/.svelte-kit/types/src/routes/chats/[id]/$types.d.ts +1 -2
  295. package/web/.svelte-kit/types/src/routes/chats/[id]/settings/$types.d.ts +1 -2
  296. package/web/package.json +8 -0
  297. package/web/src/lib/app-state.svelte.ts +5 -1
  298. package/web/src/lib/components/app/markdown-renderer.svelte +56 -0
  299. package/web/src/lib/components/app/markdown-renderer.svelte.spec.ts +44 -0
  300. package/web/src/lib/components/app/message-content.svelte +16 -0
  301. package/web/src/lib/types.ts +67 -3
  302. package/web/src/routes/+layout.svelte +31 -1
  303. package/web/src/routes/chats/[id]/+page.svelte +167 -18
  304. package/web/src/routes/chats/[id]/page.svelte.spec.ts +58 -7
  305. package/dist/lite-oSYSvaOr.mjs.map +0 -1
  306. package/dist/web/_app/immutable/assets/0.GI4C4dpV.css +0 -1
  307. package/dist/web/_app/immutable/chunks/B5abRDXp.js +0 -1
  308. package/dist/web/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
  309. package/dist/web/_app/immutable/chunks/BmUXQ3wy.js +0 -2
  310. package/dist/web/_app/immutable/chunks/C3k55nDF.js +0 -1
  311. package/dist/web/_app/immutable/chunks/CpaGRn9L.js +0 -1
  312. package/dist/web/_app/immutable/chunks/DG5RZBw-.js +0 -2
  313. package/dist/web/_app/immutable/chunks/DQoygso7.js +0 -1
  314. package/dist/web/_app/immutable/entry/start.D48mVn1m.js +0 -1
  315. package/dist/web/_app/immutable/nodes/0.B-0CcADM.js +0 -1
  316. package/dist/web/_app/immutable/nodes/1.FixKgvRO.js +0 -1
  317. package/dist/web/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
  318. package/dist/workspace-DjoNjhW0.mjs.map +0 -1
  319. package/src/daemon/message-verbosity.test.ts +0 -127
  320. package/web/.svelte-kit/output/client/_app/immutable/assets/0.GI4C4dpV.css +0 -1
  321. package/web/.svelte-kit/output/client/_app/immutable/chunks/B5abRDXp.js +0 -1
  322. package/web/.svelte-kit/output/client/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
  323. package/web/.svelte-kit/output/client/_app/immutable/chunks/BmUXQ3wy.js +0 -2
  324. package/web/.svelte-kit/output/client/_app/immutable/chunks/C3k55nDF.js +0 -1
  325. package/web/.svelte-kit/output/client/_app/immutable/chunks/CpaGRn9L.js +0 -1
  326. package/web/.svelte-kit/output/client/_app/immutable/chunks/DG5RZBw-.js +0 -2
  327. package/web/.svelte-kit/output/client/_app/immutable/chunks/DQoygso7.js +0 -1
  328. package/web/.svelte-kit/output/client/_app/immutable/entry/start.D48mVn1m.js +0 -1
  329. package/web/.svelte-kit/output/client/_app/immutable/nodes/0.B-0CcADM.js +0 -1
  330. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.FixKgvRO.js +0 -1
  331. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
  332. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.GI4C4dpV.css +0 -1
  333. /package/templates/{gemini-claw/.gemini/skills → skills}/clawmini-jobs/SKILL.md +0 -0
@@ -0,0 +1,1077 @@
1
+ #!/usr/bin/env node
2
+ import { c as getClawminiDir, d as getSocketPath, f as getWorkspaceRoot } from "../workspace-BJmJBfKi.mjs";
3
+ import { t as createUnixSocketFetch } from "../fetch-Cn1XNyiO.mjs";
4
+ import { a as createUnixSocketEventSource, i as shouldDisplayMessage, n as handleAdapterCommand, r as formatMessage, t as handleRoutingCommand } from "../routing-D8rTxtaV.mjs";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import fs$1 from "node:fs/promises";
8
+ import { z } from "zod";
9
+ import { createTRPCClient, httpLink, httpSubscriptionLink, splitLink } from "@trpc/client";
10
+ import http from "node:http";
11
+ import crypto from "node:crypto";
12
+ import { PubSub } from "@google-cloud/pubsub";
13
+ import { google } from "googleapis";
14
+ import mime from "mime-types";
15
+
16
+ //#region src/adapter-google-chat/config.ts
17
+ const GoogleChatConfigSchema = z.looseObject({
18
+ projectId: z.string().min(1, "GCP Project ID is required."),
19
+ subscriptionName: z.string().min(1, "Pub/Sub Subscription Name is required."),
20
+ topicName: z.string().min(1, "Pub/Sub Topic Name is required."),
21
+ authorizedUsers: z.array(z.string()).min(1, "At least one Authorized User is required."),
22
+ maxAttachmentSizeMB: z.number().default(25).optional(),
23
+ chatId: z.string().default("default").optional(),
24
+ directMessageName: z.string().optional(),
25
+ driveUploadEnabled: z.boolean().default(true).optional(),
26
+ requireMention: z.boolean().default(false),
27
+ oauthClientId: z.string().optional(),
28
+ oauthClientSecret: z.string().optional()
29
+ });
30
+ function getGoogleChatConfigPath(startDir = process.cwd()) {
31
+ return path.join(getClawminiDir(startDir), "adapters", "google-chat", "config.json");
32
+ }
33
+ async function readGoogleChatConfig(startDir = process.cwd()) {
34
+ const configPath = getGoogleChatConfigPath(startDir);
35
+ try {
36
+ const data = await fs$1.readFile(configPath, "utf-8");
37
+ const parsed = JSON.parse(data);
38
+ return GoogleChatConfigSchema.parse(parsed);
39
+ } catch (err) {
40
+ if (err.code === "ENOENT") return null;
41
+ throw err;
42
+ }
43
+ }
44
+ async function updateGoogleChatConfig(config, startDir = process.cwd()) {
45
+ const configPath = getGoogleChatConfigPath(startDir);
46
+ await fs$1.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
47
+ }
48
+ async function initGoogleChatConfig(startDir = process.cwd()) {
49
+ const configPath = getGoogleChatConfigPath(startDir);
50
+ const configDir = path.dirname(configPath);
51
+ await fs$1.mkdir(configDir, { recursive: true });
52
+ if (fs.existsSync(configPath)) {
53
+ console.log(`Config file already exists at ${configPath}`);
54
+ return;
55
+ }
56
+ await fs$1.writeFile(configPath, JSON.stringify({
57
+ projectId: "YOUR_PROJECT_ID",
58
+ topicName: "YOUR_TOPIC_NAME",
59
+ subscriptionName: "YOUR_SUBSCRIPTION_NAME",
60
+ authorizedUsers: ["user@example.com"],
61
+ chatId: "default",
62
+ requireMention: false,
63
+ oauthClientId: "YOUR_OAUTH_CLIENT_ID",
64
+ oauthClientSecret: "YOUR_OAUTH_CLIENT_SECRET"
65
+ }, null, 2), "utf-8");
66
+ console.log(`Created template configuration file at ${configPath}`);
67
+ console.log("Please update it with your actual GCP Project ID, Pub/Sub Topic Name, Pub/Sub Subscription Name, and Authorized Users.");
68
+ }
69
+ function isAuthorized(userIdOrEmail, authorizedUsers) {
70
+ return authorizedUsers.some((u) => u.toLowerCase() === userIdOrEmail.toLowerCase());
71
+ }
72
+
73
+ //#endregion
74
+ //#region src/adapter-google-chat/state.ts
75
+ const GoogleChatStateSchema = z.object({
76
+ lastSyncedMessageIds: z.record(z.string(), z.string()).optional(),
77
+ channelChatMap: z.record(z.string(), z.object({
78
+ chatId: z.string().nullable().optional(),
79
+ subscriptionId: z.string().optional(),
80
+ expirationDate: z.string().optional(),
81
+ requireMention: z.boolean().optional()
82
+ })).optional(),
83
+ oauthTokens: z.any().optional(),
84
+ filters: z.record(z.string(), z.boolean()).optional()
85
+ });
86
+ function getGoogleChatStatePath(startDir = process.cwd()) {
87
+ return path.join(getClawminiDir(startDir), "adapters", "google-chat", "state.json");
88
+ }
89
+ async function readGoogleChatState(startDir = process.cwd()) {
90
+ const statePath = getGoogleChatStatePath(startDir);
91
+ try {
92
+ const data = await fs$1.readFile(statePath, "utf-8");
93
+ const parsed = JSON.parse(data);
94
+ if (parsed.lastSyncedMessageId && !parsed.lastSyncedMessageIds) parsed.lastSyncedMessageIds = { default: parsed.lastSyncedMessageId };
95
+ if (parsed.driveOauthTokens && !parsed.oauthTokens) {
96
+ parsed.oauthTokens = parsed.driveOauthTokens;
97
+ delete parsed.driveOauthTokens;
98
+ }
99
+ if (parsed.channelChatMap) {
100
+ for (const [key, value] of Object.entries(parsed.channelChatMap)) if (typeof value === "string") parsed.channelChatMap[key] = { chatId: value };
101
+ }
102
+ return GoogleChatStateSchema.parse(parsed);
103
+ } catch (err) {
104
+ if (err.code === "ENOENT") return { oauthTokens: void 0 };
105
+ throw err;
106
+ }
107
+ }
108
+ let stateUpdatePromise = Promise.resolve();
109
+ function updateGoogleChatState(updates, startDir = process.cwd()) {
110
+ return new Promise((resolve, reject) => {
111
+ stateUpdatePromise = stateUpdatePromise.then(async () => {
112
+ try {
113
+ const currentState = await readGoogleChatState(startDir);
114
+ const resolvedUpdates = typeof updates === "function" ? updates(currentState) : updates;
115
+ const newState = {
116
+ ...currentState,
117
+ ...resolvedUpdates
118
+ };
119
+ const statePath = getGoogleChatStatePath(startDir);
120
+ const dir = path.dirname(statePath);
121
+ await fs$1.mkdir(dir, { recursive: true });
122
+ await fs$1.writeFile(statePath, JSON.stringify(newState, null, 2), "utf-8");
123
+ resolve(newState);
124
+ } catch (err) {
125
+ console.error(`Failed to write Google Chat state:`, err);
126
+ reject(err);
127
+ }
128
+ });
129
+ });
130
+ }
131
+
132
+ //#endregion
133
+ //#region src/adapter-google-chat/utils.ts
134
+ let authClient$1 = null;
135
+ function buildPolicyCard(logMessage) {
136
+ const policyId = "requestId" in logMessage && logMessage.requestId || logMessage.id;
137
+ return [{
138
+ cardId: logMessage.id,
139
+ card: {
140
+ header: {
141
+ title: "Action Required: Policy Approval",
142
+ subtitle: "A request needs your review."
143
+ },
144
+ sections: [{ widgets: [{ textParagraph: { text: logMessage.content || "Please review this request." } }, { buttonList: { buttons: [{
145
+ text: "Approve",
146
+ color: {
147
+ red: 0,
148
+ green: .5,
149
+ blue: 0,
150
+ alpha: 1
151
+ },
152
+ onClick: { action: {
153
+ function: "approve",
154
+ parameters: [{
155
+ key: "policyId",
156
+ value: policyId
157
+ }]
158
+ } }
159
+ }, {
160
+ text: "Reject",
161
+ color: {
162
+ red: .8,
163
+ green: 0,
164
+ blue: 0,
165
+ alpha: 1
166
+ },
167
+ onClick: { action: {
168
+ function: "reject",
169
+ parameters: [{
170
+ key: "policyId",
171
+ value: policyId
172
+ }]
173
+ } }
174
+ }] } }] }]
175
+ }
176
+ }];
177
+ }
178
+ function chunkString(str, size) {
179
+ const chunks = [];
180
+ const chars = Array.from(str);
181
+ for (let i = 0; i < chars.length; i += size) chunks.push(chars.slice(i, i + size).join(""));
182
+ return chunks;
183
+ }
184
+ /**
185
+ * Downloads a file attachment securely using Application Default Credentials (ADC).
186
+ * @param resourceName The resourceName of the attachment data to download.
187
+ * @param maxAttachmentSizeMB The maximum allowed attachment size in MB (defaults to 25).
188
+ * @returns A Buffer containing the file data.
189
+ */
190
+ async function downloadAttachment(resourceName, maxAttachmentSizeMB = 25) {
191
+ if (!authClient$1) authClient$1 = await google.auth.getClient({ scopes: ["https://www.googleapis.com/auth/chat.bot"] });
192
+ const client = authClient$1;
193
+ const url = `https://chat.googleapis.com/v1/media/${resourceName}?alt=media`;
194
+ const response = await client.request({
195
+ url,
196
+ method: "GET",
197
+ responseType: "stream"
198
+ });
199
+ return new Promise((resolve, reject) => {
200
+ const chunks = [];
201
+ let totalBytes = 0;
202
+ const maxSizeBytes = maxAttachmentSizeMB * 1024 * 1024;
203
+ response.data.on("data", (chunk) => {
204
+ totalBytes += chunk.length;
205
+ if (totalBytes > maxSizeBytes) {
206
+ response.data.destroy();
207
+ reject(/* @__PURE__ */ new Error(`Attachment exceeds maximum size of ${maxSizeBytes} bytes: ${totalBytes} bytes`));
208
+ } else chunks.push(chunk);
209
+ });
210
+ response.data.on("end", () => {
211
+ resolve(Buffer.concat(chunks));
212
+ });
213
+ response.data.on("error", (err) => {
214
+ reject(err);
215
+ });
216
+ });
217
+ }
218
+
219
+ //#endregion
220
+ //#region src/adapter-google-chat/auth.ts
221
+ let authClient = null;
222
+ async function getAuthClient() {
223
+ if (!authClient) authClient = await google.auth.getClient({ scopes: ["https://www.googleapis.com/auth/chat.bot"] });
224
+ return authClient;
225
+ }
226
+ let userAuthClient = null;
227
+ let userAuthPromise = null;
228
+ async function getUserAuthClient(config) {
229
+ if (userAuthClient) return userAuthClient;
230
+ if (userAuthPromise) return userAuthPromise;
231
+ if (!config.oauthClientId || !config.oauthClientSecret) {
232
+ console.error("DEBUG config:", config);
233
+ throw new Error("oauthClientId and oauthClientSecret are required in config.json for user authentication.");
234
+ }
235
+ userAuthPromise = (async () => {
236
+ const oauth2Client = new google.auth.OAuth2(config.oauthClientId, config.oauthClientSecret, "http://localhost:31338/oauth2callback");
237
+ oauth2Client.on("tokens", async (tokens) => {
238
+ try {
239
+ await updateGoogleChatState({ oauthTokens: {
240
+ ...(await readGoogleChatState()).oauthTokens,
241
+ ...tokens
242
+ } });
243
+ } catch (err) {
244
+ console.error("Failed to save refreshed Google User tokens", err);
245
+ }
246
+ });
247
+ const state = await readGoogleChatState();
248
+ if (state.oauthTokens) {
249
+ oauth2Client.setCredentials(state.oauthTokens);
250
+ userAuthClient = oauth2Client;
251
+ userAuthPromise = null;
252
+ return oauth2Client;
253
+ }
254
+ const authUrl = oauth2Client.generateAuthUrl({
255
+ access_type: "offline",
256
+ scope: ["https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/chat.messages.readonly"],
257
+ prompt: "consent"
258
+ });
259
+ console.log("\n======================================================");
260
+ console.log("Google User Authorization Required!");
261
+ console.log("Please visit the following URL to authorize this bot:");
262
+ console.log(authUrl);
263
+ console.log("======================================================\n");
264
+ return new Promise((resolve, reject) => {
265
+ let timeoutId;
266
+ const server = http.createServer(async (req, res) => {
267
+ if (req.url?.startsWith("/oauth2callback")) {
268
+ const code = new URL(req.url, "http://localhost:31338").searchParams.get("code");
269
+ if (code) {
270
+ res.end("Authentication successful! You can close this window.");
271
+ clearTimeout(timeoutId);
272
+ server.close();
273
+ try {
274
+ const { tokens } = await oauth2Client.getToken(code);
275
+ oauth2Client.setCredentials(tokens);
276
+ await updateGoogleChatState({ oauthTokens: tokens });
277
+ console.log("Google User authorization successful!");
278
+ userAuthClient = oauth2Client;
279
+ userAuthPromise = null;
280
+ resolve(oauth2Client);
281
+ } catch (err) {
282
+ console.error("Failed to get token", err);
283
+ userAuthPromise = null;
284
+ reject(err);
285
+ }
286
+ } else {
287
+ res.end("Authentication failed!");
288
+ clearTimeout(timeoutId);
289
+ server.close();
290
+ userAuthPromise = null;
291
+ reject(/* @__PURE__ */ new Error("No code provided in OAuth callback"));
292
+ }
293
+ }
294
+ });
295
+ server.on("error", (err) => {
296
+ console.error("Failed to start local OAuth server on port 31338", err);
297
+ clearTimeout(timeoutId);
298
+ userAuthPromise = null;
299
+ reject(err);
300
+ });
301
+ server.listen(31338, "127.0.0.1", () => {
302
+ timeoutId = setTimeout(() => {
303
+ server.close();
304
+ userAuthPromise = null;
305
+ console.error("Google User authorization timed out after 5 minutes.");
306
+ reject(/* @__PURE__ */ new Error("Google User authorization timed out."));
307
+ }, 300 * 1e3);
308
+ });
309
+ });
310
+ })();
311
+ return userAuthPromise;
312
+ }
313
+
314
+ //#endregion
315
+ //#region src/adapter-google-chat/subscriptions.ts
316
+ async function handleAddedToSpace(spaceName, externalContextId, spaceType, targetChatId, mappedChatId, config) {
317
+ if (spaceType !== "DIRECT_MESSAGE") try {
318
+ const token = (await (await getUserAuthClient(config)).getAccessToken()).token;
319
+ if (token) {
320
+ const res = await fetch("https://workspaceevents.googleapis.com/v1/subscriptions", {
321
+ method: "POST",
322
+ headers: {
323
+ Authorization: `Bearer ${token}`,
324
+ "Content-Type": "application/json"
325
+ },
326
+ body: JSON.stringify({
327
+ targetResource: `//chat.googleapis.com/${spaceName}`,
328
+ eventTypes: ["google.workspace.chat.message.v1.created"],
329
+ payloadOptions: { includeResource: true },
330
+ notificationEndpoint: { pubsubTopic: `projects/${config.projectId}/topics/${config.topicName}` }
331
+ })
332
+ });
333
+ if (res.ok) {
334
+ const subData = await res.json();
335
+ await updateGoogleChatState((latestState) => {
336
+ const currentMap = latestState.channelChatMap || {};
337
+ return { channelChatMap: {
338
+ ...currentMap,
339
+ [externalContextId]: {
340
+ ...currentMap[externalContextId] || {},
341
+ subscriptionId: subData.name,
342
+ expirationDate: subData.expireTime
343
+ }
344
+ } };
345
+ });
346
+ console.log(`Created subscription ${subData.name} for space ${externalContextId}`);
347
+ } else {
348
+ const errText = await res.text();
349
+ console.error(`Failed to create subscription for space ${externalContextId}:`, errText);
350
+ }
351
+ }
352
+ } catch (err) {
353
+ console.error("Error setting up subscription on ADDED_TO_SPACE:", err);
354
+ }
355
+ if (targetChatId && mappedChatId) try {
356
+ const authClient = await getAuthClient();
357
+ await google.chat({
358
+ version: "v1",
359
+ auth: authClient
360
+ }).spaces.messages.create({
361
+ parent: externalContextId,
362
+ requestBody: { text: `Hello! I am currently mapped to chat \`${targetChatId}\`.` }
363
+ });
364
+ } catch (err) {
365
+ console.error("Failed to send greeting on ADDED_TO_SPACE:", err);
366
+ }
367
+ }
368
+ async function handleRemovedFromSpace(externalContextId, currentState, config) {
369
+ const subId = currentState.channelChatMap?.[externalContextId]?.subscriptionId;
370
+ if (subId) try {
371
+ const token = (await (await getUserAuthClient(config)).getAccessToken()).token;
372
+ if (token) {
373
+ const res = await fetch(`https://workspaceevents.googleapis.com/v1/${subId}`, {
374
+ method: "DELETE",
375
+ headers: { Authorization: `Bearer ${token}` }
376
+ });
377
+ if (res.ok) console.log(`Deleted subscription ${subId}`);
378
+ else {
379
+ const errText = await res.text();
380
+ console.error(`Failed to delete subscription ${subId}:`, errText);
381
+ }
382
+ }
383
+ } catch (err) {
384
+ console.error("Error tearing down subscription on REMOVED_FROM_SPACE:", err);
385
+ }
386
+ await updateGoogleChatState((latestState) => {
387
+ const map = { ...latestState.channelChatMap || {} };
388
+ const entry = map[externalContextId];
389
+ if (entry) if (!entry.chatId) delete map[externalContextId];
390
+ else {
391
+ delete entry.subscriptionId;
392
+ delete entry.expirationDate;
393
+ }
394
+ return { channelChatMap: map };
395
+ });
396
+ }
397
+
398
+ //#endregion
399
+ //#region src/adapter-google-chat/cards.ts
400
+ async function handleCardClicked(event, targetChatId, trpc) {
401
+ const action = event.action;
402
+ if (!action) return;
403
+ const methodName = action.actionMethodName;
404
+ const policyId = (action.parameters || []).find((p) => p.key === "policyId")?.value;
405
+ if (policyId && (methodName === "approve" || methodName === "reject")) {
406
+ const cmd = methodName === "approve" ? `/approve ${policyId}` : `/reject ${policyId}`;
407
+ if (event.message?.name) try {
408
+ const chatApi = google.chat({
409
+ version: "v1",
410
+ auth: await getAuthClient()
411
+ });
412
+ const updatedCards = (event.message.cardsV2 || []).map((c) => {
413
+ if (c.card?.sections) c.card.sections = c.card.sections.map((s) => {
414
+ if (s.widgets) s.widgets = s.widgets.filter((w) => !w.buttonList);
415
+ return s;
416
+ });
417
+ if (c.card?.header) {
418
+ const statusText = methodName === "approve" ? "Approved" : "Rejected";
419
+ c.card.header.subtitle = `Policy ${statusText}`;
420
+ }
421
+ return c;
422
+ });
423
+ await chatApi.spaces.messages.update({
424
+ name: event.message.name,
425
+ updateMask: "cardsV2",
426
+ requestBody: { cardsV2: updatedCards }
427
+ });
428
+ } catch (updateErr) {
429
+ console.error(`Failed to update card for policy ${policyId}:`, updateErr);
430
+ }
431
+ await trpc.sendMessage.mutate({
432
+ type: "send-message",
433
+ client: "cli",
434
+ data: {
435
+ message: cmd,
436
+ chatId: targetChatId,
437
+ adapter: "google-chat",
438
+ noWait: true
439
+ }
440
+ });
441
+ console.log(`Forwarded ${methodName} for policy ${policyId} to daemon.`);
442
+ }
443
+ }
444
+
445
+ //#endregion
446
+ //#region src/adapter-google-chat/client.ts
447
+ function getTRPCClient(options = {}) {
448
+ const socketPath = options.socketPath ?? getSocketPath();
449
+ if (!fs.existsSync(socketPath)) throw new Error(`Daemon not running. Socket not found at ${socketPath}`);
450
+ const customFetch = createUnixSocketFetch(socketPath);
451
+ return createTRPCClient({ links: [splitLink({
452
+ condition(op) {
453
+ return op.type === "subscription";
454
+ },
455
+ true: httpSubscriptionLink({
456
+ url: "http://localhost",
457
+ EventSource: createUnixSocketEventSource(socketPath)
458
+ }),
459
+ false: httpLink({
460
+ url: "http://localhost",
461
+ fetch: customFetch
462
+ })
463
+ })] });
464
+ }
465
+ function startGoogleChatIngestion(config, trpc, filteringConfig) {
466
+ const subscription = new PubSub({ projectId: config.projectId }).subscription(config.subscriptionName);
467
+ const seenMessageIds = /* @__PURE__ */ new Map();
468
+ setInterval(() => {
469
+ const now = Date.now();
470
+ for (const [id, ts] of seenMessageIds.entries()) if (now - ts > 600 * 1e3) seenMessageIds.delete(id);
471
+ }, 300 * 1e3).unref();
472
+ subscription.on("message", async (message) => {
473
+ const downloadedFiles = [];
474
+ try {
475
+ const dataString = message.data.toString("utf8");
476
+ const parsedData = JSON.parse(dataString);
477
+ const isWorkspaceEvent = message.attributes && message.attributes["ce-type"] === "google.workspace.chat.message.v1.created";
478
+ const eventType = isWorkspaceEvent ? "MESSAGE" : parsedData.type;
479
+ const eventMessage = isWorkspaceEvent ? parsedData.message || parsedData : parsedData.message;
480
+ const email = (isWorkspaceEvent ? eventMessage?.sender?.email : parsedData.user?.email || eventMessage?.sender?.email) || "";
481
+ const senderName = eventMessage?.sender?.name || parsedData.user?.name || "";
482
+ const space = isWorkspaceEvent ? eventMessage?.space : parsedData.space || eventMessage?.space;
483
+ const senderType = eventMessage?.sender?.type || "";
484
+ const messageId = eventMessage?.name || "";
485
+ const text = (eventMessage?.argumentText || eventMessage?.text || "").trim();
486
+ if (senderType === "BOT") return void message.ack();
487
+ if (messageId) {
488
+ if (seenMessageIds.has(messageId)) return void message.ack();
489
+ seenMessageIds.set(messageId, Date.now());
490
+ }
491
+ if (eventType !== "MESSAGE" && eventType !== "CARD_CLICKED" && eventType !== "ADDED_TO_SPACE" && eventType !== "REMOVED_FROM_SPACE") {
492
+ message.ack();
493
+ return;
494
+ }
495
+ let isUserAuthorized = false;
496
+ let authorizedByEmail = false;
497
+ if (email && isAuthorized(email, config.authorizedUsers)) {
498
+ isUserAuthorized = true;
499
+ authorizedByEmail = true;
500
+ } else if (senderName && isAuthorized(senderName, config.authorizedUsers)) isUserAuthorized = true;
501
+ if (!isUserAuthorized) {
502
+ console.log(`Unauthorized or missing identifier: email=${email}, name=${senderName}`);
503
+ console.log("DEBUG missing identifier parsedData:", JSON.stringify(parsedData, null, 2));
504
+ message.ack();
505
+ return;
506
+ }
507
+ if (authorizedByEmail && senderName && !isAuthorized(senderName, config.authorizedUsers)) {
508
+ console.log(`Automatically authorizing user ID ${senderName} based on authorized email ${email}`);
509
+ config.authorizedUsers.push(senderName);
510
+ updateGoogleChatConfig(config).catch((err) => console.error("Failed to update config with new user ID:", err));
511
+ }
512
+ const identifier = email || senderName;
513
+ const spaceName = space?.name;
514
+ if (!spaceName) {
515
+ console.log("Ignoring message: Could not determine space name.");
516
+ message.ack();
517
+ return;
518
+ }
519
+ const currentState = await readGoogleChatState();
520
+ const externalContextId = spaceName;
521
+ const mappedChatId = currentState.channelChatMap?.[externalContextId]?.chatId;
522
+ const isRoutingCommand = text.startsWith("/chat") || text.startsWith("/agent");
523
+ if (eventType === "ADDED_TO_SPACE") {
524
+ await handleAddedToSpace(spaceName, externalContextId, space?.type, mappedChatId, mappedChatId, config);
525
+ if (!text) {
526
+ message.ack();
527
+ return;
528
+ }
529
+ }
530
+ if (eventType === "REMOVED_FROM_SPACE") {
531
+ await handleRemovedFromSpace(externalContextId, currentState, config);
532
+ message.ack();
533
+ return;
534
+ }
535
+ if (isRoutingCommand) {
536
+ const routingResult = await handleRoutingCommand(text, externalContextId, Object.fromEntries(Object.entries(currentState.channelChatMap || {}).map(([k, v]) => [k, v.chatId || ""])), "google-chat", trpc);
537
+ if (routingResult) {
538
+ if (routingResult.type === "mapped") await updateGoogleChatState((latestState) => ({ channelChatMap: {
539
+ ...latestState.channelChatMap || {},
540
+ [externalContextId]: {
541
+ ...latestState.channelChatMap?.[externalContextId] || {},
542
+ chatId: routingResult.newChatId
543
+ }
544
+ } }));
545
+ try {
546
+ const authClient = await getAuthClient();
547
+ await google.chat({
548
+ version: "v1",
549
+ auth: authClient
550
+ }).spaces.messages.create({
551
+ parent: externalContextId,
552
+ requestBody: { text: routingResult.text }
553
+ });
554
+ } catch (err) {
555
+ console.error("Failed to send routing command reply:", err);
556
+ }
557
+ message.ack();
558
+ return;
559
+ }
560
+ }
561
+ let targetChatId = mappedChatId;
562
+ if (!targetChatId && !isRoutingCommand) if (!currentState.channelChatMap || Object.values(currentState.channelChatMap).every((entry) => !entry.chatId)) {
563
+ targetChatId = config.chatId || "default";
564
+ console.log(`First contact detected. Automatically mapping space ${externalContextId} to chat ${targetChatId}.`);
565
+ await updateGoogleChatState((latestState) => ({ channelChatMap: {
566
+ ...latestState.channelChatMap || {},
567
+ [externalContextId]: {
568
+ ...latestState.channelChatMap?.[externalContextId] || {},
569
+ chatId: targetChatId
570
+ }
571
+ } }));
572
+ } else {
573
+ const isDirectMessage = space?.type === "DIRECT_MESSAGE" || space?.singleUserBotDm === true;
574
+ const isMentioned = Array.isArray(eventMessage?.annotations) && eventMessage.annotations.some((a) => a.type === "USER_MENTION");
575
+ const isSlashCommand = text.startsWith("/");
576
+ if (isDirectMessage || isMentioned || isSlashCommand) {
577
+ console.log(`Unmapped space ${externalContextId}, sending first contact warning.`);
578
+ try {
579
+ const authClient = await getAuthClient();
580
+ await google.chat({
581
+ version: "v1",
582
+ auth: authClient
583
+ }).spaces.messages.create({
584
+ parent: externalContextId,
585
+ requestBody: { text: "This channel/space is not currently mapped to a daemon chat. Please use `/chat [chat-id]` or `/agent [agent-id]` to map it." }
586
+ });
587
+ } catch (err) {
588
+ console.error("Failed to send first contact warning:", err);
589
+ }
590
+ } else console.log(`Unmapped space ${externalContextId}, silently ignoring background message.`);
591
+ message.ack();
592
+ return;
593
+ }
594
+ if (!targetChatId) targetChatId = config.chatId || "default";
595
+ if (!(space?.type === "DIRECT_MESSAGE" || space?.singleUserBotDm === true) && eventType === "MESSAGE") {
596
+ const channelConfig = currentState.channelChatMap?.[externalContextId];
597
+ if ((channelConfig?.requireMention !== void 0 ? channelConfig.requireMention : config.requireMention) && !isRoutingCommand) {
598
+ const isMentioned = Array.isArray(eventMessage?.annotations) && eventMessage.annotations.some((a) => a.type === "USER_MENTION" && a.userMention?.user?.type === "BOT");
599
+ let isReplyToBot = false;
600
+ if (eventMessage?.threadReply && eventMessage.thread?.name) try {
601
+ const authClient = await getAuthClient();
602
+ isReplyToBot = (await google.chat({
603
+ version: "v1",
604
+ auth: authClient
605
+ }).spaces.messages.list({
606
+ parent: externalContextId,
607
+ filter: `thread.name="${eventMessage.thread.name}"`
608
+ })).data.messages?.some((m) => m.sender?.type === "BOT" || m.annotations?.some((a) => a.type === "USER_MENTION" && a.userMention?.user?.type === "BOT")) ?? false;
609
+ } catch (err) {
610
+ console.error("Failed to fetch thread messages for mention check:", err);
611
+ }
612
+ if (!isMentioned && !isReplyToBot) {
613
+ message.ack();
614
+ return;
615
+ }
616
+ }
617
+ }
618
+ if (eventType === "CARD_CLICKED") {
619
+ await handleCardClicked(parsedData, targetChatId, trpc);
620
+ message.ack();
621
+ return;
622
+ }
623
+ const commandResult = await handleAdapterCommand(text, filteringConfig, trpc, targetChatId);
624
+ if (commandResult) {
625
+ let resultText = "";
626
+ if (commandResult.type === "text") {
627
+ if (commandResult.newConfig) {
628
+ filteringConfig.filters = commandResult.newConfig.filters;
629
+ await updateGoogleChatState({ filters: filteringConfig.filters });
630
+ }
631
+ resultText = commandResult.text;
632
+ } else if (commandResult.type === "debug") resultText = commandResult.messages.length === 0 ? "No ignored background messages found." : `**Debug Output (${commandResult.messages.length} ignored messages):**\n\n` + commandResult.messages.map((msg) => formatMessage(msg)).join("\n\n---\n\n");
633
+ const authClient = await getAuthClient();
634
+ await google.chat({
635
+ version: "v1",
636
+ auth: authClient
637
+ }).spaces.messages.create({
638
+ parent: spaceName,
639
+ requestBody: { text: resultText }
640
+ });
641
+ message.ack();
642
+ return;
643
+ }
644
+ const attachments = eventMessage?.attachment || [];
645
+ if (attachments.length > 0) {
646
+ const tmpDir = path.join(getClawminiDir(process.cwd()), "tmp", "google-chat");
647
+ await fs$1.mkdir(tmpDir, { recursive: true });
648
+ for (const att of attachments) {
649
+ const resourceName = att.attachmentDataRef?.resourceName;
650
+ if (resourceName) try {
651
+ const buffer = await downloadAttachment(resourceName, config.maxAttachmentSizeMB);
652
+ const uniqueName = `${crypto.randomUUID()}-${att.contentName || "attachment"}`;
653
+ const filePath = path.join(tmpDir, uniqueName);
654
+ await fs$1.writeFile(filePath, buffer);
655
+ downloadedFiles.push(filePath);
656
+ } catch (err) {
657
+ console.error(`Error downloading attachment:`, err);
658
+ }
659
+ }
660
+ }
661
+ await trpc.sendMessage.mutate({
662
+ type: "send-message",
663
+ client: "cli",
664
+ data: {
665
+ message: text,
666
+ chatId: targetChatId,
667
+ files: downloadedFiles.length > 0 ? downloadedFiles : void 0,
668
+ adapter: "google-chat",
669
+ noWait: true
670
+ }
671
+ });
672
+ console.log(`Forwarded message from ${identifier} to daemon.`);
673
+ message.ack();
674
+ } catch (error) {
675
+ console.error("Error processing Pub/Sub message:", error);
676
+ for (const file of downloadedFiles) try {
677
+ await fs$1.unlink(file);
678
+ } catch (unlinkErr) {
679
+ console.error(`Failed to delete downloaded file ${file} after error:`, unlinkErr);
680
+ }
681
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
682
+ message.nack();
683
+ }
684
+ });
685
+ subscription.on("error", (error) => {
686
+ console.error("Pub/Sub subscription error:", error);
687
+ });
688
+ return subscription;
689
+ }
690
+
691
+ //#endregion
692
+ //#region src/adapter-google-chat/upload.ts
693
+ async function uploadFilesToDrive(files, config) {
694
+ const driveClient = await getUserAuthClient(config);
695
+ const driveApi = google.drive({
696
+ version: "v3",
697
+ auth: driveClient
698
+ });
699
+ const workspaceRoot = getWorkspaceRoot(process.cwd());
700
+ let folderId;
701
+ try {
702
+ const queryRes = await driveApi.files.list({
703
+ q: "mimeType='application/vnd.google-apps.folder' and name='Clawmini Uploads' and trashed=false",
704
+ fields: "files(id)"
705
+ });
706
+ if (queryRes.data.files && queryRes.data.files.length > 0) folderId = queryRes.data.files[0].id;
707
+ else {
708
+ const folderRes = await driveApi.files.create({
709
+ requestBody: {
710
+ name: "Clawmini Uploads",
711
+ mimeType: "application/vnd.google-apps.folder"
712
+ },
713
+ fields: "id"
714
+ });
715
+ if (folderRes.data.id) folderId = folderRes.data.id;
716
+ }
717
+ } catch (err) {
718
+ console.error("Failed to create or find Clawmini Uploads folder", err);
719
+ }
720
+ const uploadPromises = files.map(async (fileRelPath) => {
721
+ const filePath = path.resolve(workspaceRoot, fileRelPath);
722
+ if (!fs.existsSync(filePath)) return null;
723
+ const fileName = path.basename(filePath);
724
+ const mimeType = mime.lookup(filePath) || "application/octet-stream";
725
+ try {
726
+ const driveRes = await driveApi.files.create({
727
+ requestBody: {
728
+ name: fileName,
729
+ ...folderId ? { parents: [folderId] } : {}
730
+ },
731
+ media: {
732
+ mimeType,
733
+ body: fs.createReadStream(filePath)
734
+ },
735
+ fields: "id, webViewLink"
736
+ });
737
+ if (driveRes.data.id && driveRes.data.webViewLink) {
738
+ const fileId = driveRes.data.id;
739
+ try {
740
+ await Promise.all(config.authorizedUsers.map((email) => driveApi.permissions.create({
741
+ fileId,
742
+ requestBody: {
743
+ type: "user",
744
+ role: "reader",
745
+ emailAddress: email
746
+ },
747
+ sendNotificationEmail: false
748
+ })));
749
+ } catch (err) {
750
+ console.error(`Failed to grant permissions for ${fileName}`, err);
751
+ }
752
+ return driveRes.data.webViewLink;
753
+ }
754
+ return null;
755
+ } catch (err) {
756
+ console.error(`Failed to upload file ${fileName} to Google Drive`, err);
757
+ return `*(Failed to upload to Drive: ${fileName})*`;
758
+ }
759
+ });
760
+ return (await Promise.all(uploadPromises)).filter((r) => r !== null);
761
+ }
762
+
763
+ //#endregion
764
+ //#region src/adapter-google-chat/forwarder.ts
765
+ async function startDaemonToGoogleChatForwarder(trpc, config, filteringConfig, signal) {
766
+ const defaultChatId = config.chatId || "default";
767
+ const activeSubscriptions = /* @__PURE__ */ new Map();
768
+ let currentLastSyncedMessageIds = (await readGoogleChatState()).lastSyncedMessageIds || {};
769
+ const saveLastMessageId = async (chatId, id) => {
770
+ currentLastSyncedMessageIds = {
771
+ ...currentLastSyncedMessageIds,
772
+ [chatId]: id
773
+ };
774
+ return updateGoogleChatState((state) => ({ lastSyncedMessageIds: {
775
+ ...state.lastSyncedMessageIds,
776
+ ...currentLastSyncedMessageIds
777
+ } }));
778
+ };
779
+ const startSubscriptionForChat = async (chatId) => {
780
+ if (activeSubscriptions.has(chatId)) return;
781
+ if (signal?.aborted) return;
782
+ let lastMessageId = currentLastSyncedMessageIds[chatId];
783
+ if (!lastMessageId) try {
784
+ const messages = await trpc.getMessages.query({
785
+ chatId,
786
+ limit: 1
787
+ });
788
+ if (Array.isArray(messages) && messages.length > 0) {
789
+ const lastMsg = messages[messages.length - 1];
790
+ if (lastMsg) {
791
+ await saveLastMessageId(chatId, lastMsg.id);
792
+ lastMessageId = lastMsg.id;
793
+ }
794
+ }
795
+ } catch (error) {
796
+ if (signal?.aborted) return;
797
+ console.error(`Failed to fetch initial messages from daemon for ${chatId}:`, error);
798
+ }
799
+ console.log(`Starting daemon-to-google-chat forwarder for chat ${chatId}, lastMessageId: ${lastMessageId}`);
800
+ let retryDelay = 1e3;
801
+ const maxRetryDelay = 3e4;
802
+ let subscription = null;
803
+ let messageQueue = Promise.resolve();
804
+ const connect = () => {
805
+ if (signal?.aborted || !activeSubscriptions.has(chatId)) return;
806
+ subscription = trpc.waitForMessages.subscribe({
807
+ chatId,
808
+ lastMessageId
809
+ }, {
810
+ onData: (messages) => {
811
+ retryDelay = 1e3;
812
+ if (!Array.isArray(messages) || messages.length === 0) return;
813
+ messageQueue = messageQueue.then(async () => {
814
+ for (const rawMessage of messages) {
815
+ if (signal?.aborted || !activeSubscriptions.has(chatId)) break;
816
+ const message = rawMessage;
817
+ if (shouldDisplayMessage(message, filteringConfig)) {
818
+ const logMessage = message;
819
+ const currentState = await readGoogleChatState();
820
+ let activeSpaceName;
821
+ if (!activeSpaceName && currentState.channelChatMap) {
822
+ const entry = Object.entries(currentState.channelChatMap).find(([_, mapChatId]) => mapChatId?.chatId === chatId);
823
+ if (entry) activeSpaceName = entry[0];
824
+ }
825
+ if (logMessage.role === "policy" && logMessage.status === "pending") {
826
+ if (!activeSpaceName) {
827
+ console.warn("No active Google Chat space to reply to. Ignoring policy request:", logMessage.content);
828
+ await saveLastMessageId(chatId, logMessage.id).catch(console.error);
829
+ lastMessageId = logMessage.id;
830
+ continue;
831
+ }
832
+ try {
833
+ const client = await getAuthClient();
834
+ const chatApi = google.chat({
835
+ version: "v1",
836
+ auth: client
837
+ });
838
+ try {
839
+ await chatApi.spaces.messages.create({
840
+ parent: activeSpaceName,
841
+ requestBody: {
842
+ text: "",
843
+ cardsV2: buildPolicyCard(logMessage)
844
+ }
845
+ });
846
+ } catch (richError) {
847
+ console.warn("Failed to send rich policy request to Google Chat, falling back to plain text:", richError);
848
+ const policyId = "requestId" in logMessage && logMessage.requestId || logMessage.id;
849
+ await chatApi.spaces.messages.create({
850
+ parent: activeSpaceName,
851
+ requestBody: { text: `Action Required: Policy Request\n\n${logMessage.content || "A pending policy request requires your attention."}\n\nApprove: \`/approve ${policyId}\`\nReject: \`/reject ${policyId} <optional_rationale>\`` }
852
+ });
853
+ }
854
+ } catch (error) {
855
+ console.error("Failed to send policy request to Google Chat:", error);
856
+ }
857
+ await saveLastMessageId(chatId, logMessage.id).catch(console.error);
858
+ lastMessageId = logMessage.id;
859
+ continue;
860
+ }
861
+ const hasContent = !!logMessage.content?.trim();
862
+ const files = "files" in logMessage ? logMessage.files : void 0;
863
+ const hasFiles = Array.isArray(files) && files.length > 0;
864
+ if ("level" in logMessage && logMessage.level === "verbose" || !hasContent && !hasFiles) {
865
+ await saveLastMessageId(chatId, logMessage.id).catch(console.error);
866
+ lastMessageId = logMessage.id;
867
+ continue;
868
+ }
869
+ if (!activeSpaceName) {
870
+ console.warn("No active Google Chat space to reply to. Ignoring message:", logMessage.content);
871
+ await saveLastMessageId(chatId, logMessage.id).catch(console.error);
872
+ lastMessageId = logMessage.id;
873
+ continue;
874
+ }
875
+ try {
876
+ const client = await getAuthClient();
877
+ const chatApi = google.chat({
878
+ version: "v1",
879
+ auth: client
880
+ });
881
+ let text = formatMessage(logMessage) || "";
882
+ if (hasFiles && files) {
883
+ const fileNames = files.map((f) => path.basename(f)).join(", ");
884
+ if (config.driveUploadEnabled !== false && config.oauthClientId && config.oauthClientSecret) {
885
+ text += `\n\n`;
886
+ try {
887
+ const uploadResults = await uploadFilesToDrive(files, config);
888
+ for (const result of uploadResults) text += `${result}\n`;
889
+ } catch (driveAuthErr) {
890
+ console.error("Drive API/Auth Failed, degrading to local files output:", driveAuthErr);
891
+ text += `*(Files generated: ${fileNames})*`;
892
+ }
893
+ } else text += `\n\n*(Files generated: ${fileNames})*`;
894
+ }
895
+ if (text.length > 4e3) {
896
+ const chunks = chunkString(text, 4e3);
897
+ for (let i = 0; i < chunks.length; i++) {
898
+ if (signal?.aborted || !activeSubscriptions.has(chatId)) break;
899
+ await chatApi.spaces.messages.create({
900
+ parent: activeSpaceName,
901
+ requestBody: { text: chunks[i] }
902
+ });
903
+ }
904
+ } else await chatApi.spaces.messages.create({
905
+ parent: activeSpaceName,
906
+ requestBody: { text }
907
+ });
908
+ } catch (error) {
909
+ console.error("Failed to send message to Google Chat:", error);
910
+ }
911
+ }
912
+ await saveLastMessageId(chatId, message.id).catch(console.error);
913
+ lastMessageId = message.id;
914
+ }
915
+ }).catch((error) => {
916
+ console.error("Message queue failed, forcing reconnect...", error);
917
+ subscription?.unsubscribe();
918
+ subscription = null;
919
+ if (signal?.aborted || !activeSubscriptions.has(chatId)) return;
920
+ setTimeout(() => {
921
+ retryDelay = Math.min(retryDelay * 2, maxRetryDelay);
922
+ connect();
923
+ }, retryDelay);
924
+ });
925
+ },
926
+ onError: (error) => {
927
+ console.error(`Error in daemon-to-google-chat forwarder subscription for ${chatId}. Retrying in ${retryDelay}ms.`, error);
928
+ subscription?.unsubscribe();
929
+ subscription = null;
930
+ if (signal?.aborted || !activeSubscriptions.has(chatId)) return;
931
+ setTimeout(() => {
932
+ retryDelay = Math.min(retryDelay * 2, maxRetryDelay);
933
+ connect();
934
+ }, retryDelay);
935
+ },
936
+ onComplete: () => {
937
+ subscription = null;
938
+ if (!signal?.aborted && activeSubscriptions.has(chatId)) setTimeout(() => connect(), retryDelay);
939
+ }
940
+ });
941
+ };
942
+ activeSubscriptions.set(chatId, { unsubscribe: () => subscription?.unsubscribe() });
943
+ connect();
944
+ };
945
+ const syncSubscriptions = async () => {
946
+ if (signal?.aborted) return;
947
+ const state = await readGoogleChatState();
948
+ if (state.lastSyncedMessageIds) currentLastSyncedMessageIds = {
949
+ ...state.lastSyncedMessageIds,
950
+ ...currentLastSyncedMessageIds
951
+ };
952
+ const targetChatIds = /* @__PURE__ */ new Set();
953
+ targetChatIds.add(defaultChatId);
954
+ if (state.channelChatMap) {
955
+ for (const mappedEntry of Object.values(state.channelChatMap)) if (mappedEntry.chatId) targetChatIds.add(mappedEntry.chatId);
956
+ }
957
+ for (const targetChatId of targetChatIds) if (!activeSubscriptions.has(targetChatId)) startSubscriptionForChat(targetChatId);
958
+ for (const [activeChatId, sub] of activeSubscriptions.entries()) if (!targetChatIds.has(activeChatId)) {
959
+ sub.unsubscribe();
960
+ activeSubscriptions.delete(activeChatId);
961
+ }
962
+ };
963
+ return new Promise((resolve) => {
964
+ syncSubscriptions().catch(console.error);
965
+ const statePath = getGoogleChatStatePath();
966
+ const stateDir = path.dirname(statePath);
967
+ if (!fs.existsSync(stateDir)) fs.mkdirSync(stateDir, { recursive: true });
968
+ let debounceTimer = null;
969
+ const watcher = fs.watch(stateDir, (eventType, filename) => {
970
+ if (filename === path.basename(statePath)) {
971
+ if (debounceTimer) clearTimeout(debounceTimer);
972
+ debounceTimer = setTimeout(() => {
973
+ syncSubscriptions().catch(console.error);
974
+ }, 200);
975
+ }
976
+ });
977
+ signal?.addEventListener("abort", () => {
978
+ if (debounceTimer) clearTimeout(debounceTimer);
979
+ watcher.close();
980
+ for (const sub of activeSubscriptions.values()) sub.unsubscribe();
981
+ resolve();
982
+ });
983
+ });
984
+ }
985
+
986
+ //#endregion
987
+ //#region src/adapter-google-chat/cron.ts
988
+ function startSubscriptionRenewalCron(config) {
989
+ return setInterval(async () => {
990
+ try {
991
+ await renewExpiringSubscriptions(config);
992
+ } catch (err) {
993
+ console.error("Error in subscription renewal cron:", err);
994
+ }
995
+ }, 1e3 * 60 * 60);
996
+ }
997
+ async function renewExpiringSubscriptions(config) {
998
+ const state = await readGoogleChatState();
999
+ if (!state.channelChatMap) return;
1000
+ const now = Date.now();
1001
+ const FORTY_EIGHT_HOURS_MS = 2880 * 60 * 1e3;
1002
+ for (const [externalContextId, entry] of Object.entries(state.channelChatMap)) if (entry.subscriptionId && entry.expirationDate) {
1003
+ if (new Date(entry.expirationDate).getTime() - now < FORTY_EIGHT_HOURS_MS) {
1004
+ console.log(`Renewing expiring subscription ${entry.subscriptionId} for space ${externalContextId}`);
1005
+ try {
1006
+ const token = (await (await getUserAuthClient(config)).getAccessToken()).token;
1007
+ if (token) {
1008
+ const res = await fetch(`https://workspaceevents.googleapis.com/v1/${entry.subscriptionId}?updateMask=ttl`, {
1009
+ method: "PATCH",
1010
+ headers: {
1011
+ Authorization: `Bearer ${token}`,
1012
+ "Content-Type": "application/json"
1013
+ },
1014
+ body: JSON.stringify({ ttl: "604800s" })
1015
+ });
1016
+ if (res.ok) {
1017
+ const subData = await res.json();
1018
+ await updateGoogleChatState((latestState) => {
1019
+ const currentMap = latestState.channelChatMap || {};
1020
+ return { channelChatMap: {
1021
+ ...currentMap,
1022
+ [externalContextId]: {
1023
+ ...currentMap[externalContextId] || {},
1024
+ expirationDate: subData.expireTime
1025
+ }
1026
+ } };
1027
+ });
1028
+ console.log(`Successfully renewed subscription ${entry.subscriptionId}`);
1029
+ } else {
1030
+ const errText = await res.text();
1031
+ console.error(`Failed to renew subscription ${entry.subscriptionId}:`, errText);
1032
+ }
1033
+ }
1034
+ } catch (err) {
1035
+ console.error(`Error renewing subscription ${entry.subscriptionId}:`, err);
1036
+ }
1037
+ }
1038
+ }
1039
+ }
1040
+
1041
+ //#endregion
1042
+ //#region src/adapter-google-chat/index.ts
1043
+ async function main() {
1044
+ if (process.argv.slice(2)[0] === "init") {
1045
+ await initGoogleChatConfig();
1046
+ return;
1047
+ }
1048
+ console.log("Google Chat Adapter starting...");
1049
+ const config = await readGoogleChatConfig();
1050
+ if (!config) {
1051
+ console.error("Failed to load Google Chat configuration. Please ensure .clawmini/adapters/google-chat/config.json exists and is valid.");
1052
+ process.exit(1);
1053
+ }
1054
+ if (config.oauthClientId && config.oauthClientSecret) try {
1055
+ console.log("Initializing Google User Authentication...");
1056
+ await getUserAuthClient(config);
1057
+ } catch (err) {
1058
+ console.error("Failed to initialize Google User authentication:", err);
1059
+ process.exit(1);
1060
+ }
1061
+ const trpc = getTRPCClient();
1062
+ const filteringConfig = { filters: (await readGoogleChatState()).filters };
1063
+ startGoogleChatIngestion(config, trpc, filteringConfig);
1064
+ console.log(`Listening to Pub/Sub subscription: ${config.subscriptionName}`);
1065
+ startDaemonToGoogleChatForwarder(trpc, config, filteringConfig).catch((error) => {
1066
+ console.error("Error in daemon-to-google-chat forwarder:", error);
1067
+ });
1068
+ startSubscriptionRenewalCron(config);
1069
+ }
1070
+ if (process.env.NODE_ENV !== "test") main().catch((error) => {
1071
+ console.error("Unhandled error in Google Chat Adapter:", error);
1072
+ process.exit(1);
1073
+ });
1074
+
1075
+ //#endregion
1076
+ export { main };
1077
+ //# sourceMappingURL=index.mjs.map