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.
- package/README.md +19 -0
- package/dist/adapter-discord/index.d.mts.map +1 -1
- package/dist/adapter-discord/index.mjs +398 -193
- package/dist/adapter-discord/index.mjs.map +1 -1
- package/dist/adapter-google-chat/index.d.mts +5 -0
- package/dist/adapter-google-chat/index.d.mts.map +1 -0
- package/dist/adapter-google-chat/index.mjs +1077 -0
- package/dist/adapter-google-chat/index.mjs.map +1 -0
- package/dist/cli/index.mjs +107 -14
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lite.mjs +175 -16
- package/dist/cli/lite.mjs.map +1 -1
- package/dist/cli/propose-policy.d.mts +1 -0
- package/dist/cli/propose-policy.mjs +7159 -0
- package/dist/cli/propose-policy.mjs.map +1 -0
- package/dist/daemon/index.d.mts.map +1 -1
- package/dist/daemon/index.mjs +1427 -513
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/{lite-oSYSvaOr.mjs → lite-CBxOT1y5.mjs} +101 -24
- package/dist/lite-CBxOT1y5.mjs.map +1 -0
- package/dist/routing-D8rTxtaV.mjs +245 -0
- package/dist/routing-D8rTxtaV.mjs.map +1 -0
- package/dist/web/_app/immutable/assets/0.C-4eziNy.css +1 -0
- package/dist/web/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
- package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +1 -0
- package/dist/web/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/8YNcRyEk.js → dist/web/_app/immutable/chunks/C20lZMGz.js} +1 -1
- package/dist/web/_app/immutable/chunks/C9lbZ-kT.js +1 -0
- package/dist/web/_app/immutable/chunks/CK9JZLaG.js +2 -0
- package/dist/web/_app/immutable/chunks/CME08kGM.js +1 -0
- package/dist/web/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
- package/dist/web/_app/immutable/chunks/Ck3rYNON.js +1 -0
- package/dist/web/_app/immutable/chunks/DMtIqaiV.js +2 -0
- package/dist/web/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
- package/dist/web/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
- package/dist/web/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
- package/dist/web/_app/immutable/chunks/DsIToJCP.js +1 -0
- package/dist/web/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/entry/app.DO5eYwVz.js → dist/web/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
- package/dist/web/_app/immutable/entry/start.DuxJo6av.js +1 -0
- package/dist/web/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
- package/dist/web/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
- package/dist/web/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
- package/dist/web/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
- package/dist/web/_app/immutable/nodes/4.DLarELN4.js +60 -0
- package/dist/web/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +12 -12
- package/dist/{workspace-DjoNjhW0.mjs → workspace-BJmJBfKi.mjs} +103 -11
- package/dist/workspace-BJmJBfKi.mjs.map +1 -0
- package/docs/14_google_chat_adapter/development_log.md +40 -0
- package/docs/14_google_chat_adapter/notes.md +28 -0
- package/docs/14_google_chat_adapter/prd.md +35 -0
- package/docs/14_google_chat_adapter/questions.md +9 -0
- package/docs/14_google_chat_adapter/tickets.md +117 -0
- package/docs/15_sandbox_policies/tickets.md +33 -0
- package/docs/16_session_timeout/development_log.md +20 -0
- package/docs/16_session_timeout/notes.md +44 -0
- package/docs/16_session_timeout/prd.md +106 -0
- package/docs/16_session_timeout/questions.md +10 -0
- package/docs/16_session_timeout/tickets.md +64 -0
- package/docs/17_auto_approve_policy/development_log.md +29 -0
- package/docs/17_auto_approve_policy/notes.md +25 -0
- package/docs/17_auto_approve_policy/prd.md +34 -0
- package/docs/17_auto_approve_policy/questions.md +10 -0
- package/docs/17_auto_approve_policy/tickets.md +11 -0
- package/docs/18_clawmini_skills/development_log.md +36 -0
- package/docs/18_clawmini_skills/notes.md +8 -0
- package/docs/18_clawmini_skills/prd.md +45 -0
- package/docs/18_clawmini_skills/questions.md +10 -0
- package/docs/18_clawmini_skills/tickets.md +55 -0
- package/docs/19_subagents/development_log.md +69 -0
- package/docs/19_subagents/notes.md +18 -0
- package/docs/19_subagents/prd.md +156 -0
- package/docs/19_subagents/questions.md +13 -0
- package/docs/19_subagents/tickets.md +113 -0
- package/docs/20_chat_logs_cleanup/development_log.md +50 -0
- package/docs/20_chat_logs_cleanup/notes.md +43 -0
- package/docs/20_chat_logs_cleanup/prd.md +232 -0
- package/docs/20_chat_logs_cleanup/questions.md +2 -0
- package/docs/20_chat_logs_cleanup/tickets.md +98 -0
- package/docs/20_webui_markdown/development_log.md +36 -0
- package/docs/20_webui_markdown/notes.md +23 -0
- package/docs/20_webui_markdown/prd.md +49 -0
- package/docs/20_webui_markdown/questions.md +10 -0
- package/docs/20_webui_markdown/tickets.md +55 -0
- package/docs/21_adapter_filtering/development_log.md +29 -0
- package/docs/21_adapter_filtering/notes.md +25 -0
- package/docs/21_adapter_filtering/prd.md +44 -0
- package/docs/21_adapter_filtering/questions.md +12 -0
- package/docs/21_adapter_filtering/tickets.md +38 -0
- package/docs/21_built_in_routers/development_log.md +17 -0
- package/docs/21_built_in_routers/notes.md +27 -0
- package/docs/21_built_in_routers/prd.md +34 -0
- package/docs/21_built_in_routers/questions.md +4 -0
- package/docs/21_built_in_routers/tickets.md +25 -0
- package/docs/21_fancy_policies/development_log.md +38 -0
- package/docs/21_fancy_policies/notes.md +27 -0
- package/docs/21_fancy_policies/prd.md +58 -0
- package/docs/21_fancy_policies/questions.md +6 -0
- package/docs/21_fancy_policies/tickets.md +48 -0
- package/docs/22_adapter_multi_chat/development_log.md +76 -0
- package/docs/22_adapter_multi_chat/notes.md +42 -0
- package/docs/22_adapter_multi_chat/prd.md +76 -0
- package/docs/22_adapter_multi_chat/questions.md +16 -0
- package/docs/22_adapter_multi_chat/tickets.md +164 -0
- package/docs/23_custom_token_env/development_log.md +31 -0
- package/docs/23_custom_token_env/notes.md +16 -0
- package/docs/23_custom_token_env/prd.md +42 -0
- package/docs/23_custom_token_env/questions.md +8 -0
- package/docs/23_custom_token_env/tickets.md +54 -0
- package/docs/guides/discord_adapter_setup.md +15 -2
- package/docs/guides/google_chat_adapter_setup.md +145 -0
- package/napkin.md +5 -0
- package/package.json +7 -2
- package/src/adapter-discord/config.test.ts +27 -8
- package/src/adapter-discord/config.ts +6 -8
- package/src/adapter-discord/forwarder.test.ts +307 -114
- package/src/adapter-discord/forwarder.ts +260 -75
- package/src/adapter-discord/index.test.ts +278 -0
- package/src/adapter-discord/index.ts +160 -30
- package/src/adapter-discord/interactions.test.ts +96 -0
- package/src/adapter-discord/interactions.ts +156 -0
- package/src/adapter-discord/state.test.ts +9 -8
- package/src/adapter-discord/state.ts +51 -8
- package/src/adapter-google-chat/auth.test.ts +87 -0
- package/src/adapter-google-chat/auth.ts +132 -0
- package/src/adapter-google-chat/cards.ts +71 -0
- package/src/adapter-google-chat/client.test.ts +561 -0
- package/src/adapter-google-chat/client.ts +430 -0
- package/src/adapter-google-chat/config.test.ts +187 -0
- package/src/adapter-google-chat/config.ts +82 -0
- package/src/adapter-google-chat/cron.test.ts +143 -0
- package/src/adapter-google-chat/cron.ts +81 -0
- package/src/adapter-google-chat/forwarder.test.ts +537 -0
- package/src/adapter-google-chat/forwarder.ts +349 -0
- package/src/adapter-google-chat/index.test.ts +62 -0
- package/src/adapter-google-chat/index.ts +61 -0
- package/src/adapter-google-chat/state.test.ts +96 -0
- package/src/adapter-google-chat/state.ts +85 -0
- package/src/adapter-google-chat/subscriptions.ts +124 -0
- package/src/adapter-google-chat/upload.ts +88 -0
- package/src/adapter-google-chat/utils.test.ts +111 -0
- package/src/adapter-google-chat/utils.ts +133 -0
- package/src/cli/commands/init.ts +0 -7
- package/src/cli/commands/messages.ts +18 -3
- package/src/cli/commands/policies.ts +70 -0
- package/src/cli/commands/skills.ts +71 -0
- package/src/cli/commands/web-api/chats.ts +5 -1
- package/src/cli/e2e/basic.test.ts +1 -1
- package/src/cli/e2e/cron.test.ts +1 -1
- package/src/cli/e2e/daemon.test.ts +132 -4
- package/src/cli/e2e/export-lite-func.test.ts +54 -31
- package/src/cli/e2e/fallbacks.test.ts +8 -6
- package/src/cli/e2e/init.test.ts +7 -0
- package/src/cli/e2e/messages.test.ts +90 -55
- package/src/cli/e2e/propose-policy.test.ts +203 -0
- package/src/cli/e2e/requests.test.ts +15 -0
- package/src/cli/e2e/session-timeout.test.ts +192 -0
- package/src/cli/e2e/skills.test.ts +55 -0
- package/src/cli/e2e/slash-new.test.ts +93 -0
- package/src/cli/e2e/subagents.test.ts +106 -0
- package/src/cli/index.ts +4 -0
- package/src/cli/lite.ts +51 -11
- package/src/cli/propose-policy.ts +91 -0
- package/src/cli/subagent-commands.ts +215 -0
- package/src/daemon/agent/agent-context.ts +89 -0
- package/src/daemon/agent/agent-extractors.ts +68 -0
- package/src/daemon/agent/agent-runner.ts +153 -0
- package/src/daemon/agent/agent-session.ts +261 -0
- package/src/daemon/agent/chat-logger.test.ts +158 -0
- package/src/daemon/agent/chat-logger.ts +188 -0
- package/src/daemon/agent/task-scheduler.test.ts +202 -0
- package/src/daemon/agent/task-scheduler.ts +276 -0
- package/src/daemon/agent/types.ts +84 -0
- package/src/daemon/agent/utils.ts +7 -0
- package/src/daemon/api/agent-router.ts +166 -18
- package/src/daemon/api/index.test.ts +50 -18
- package/src/daemon/api/policy-request.test.ts +39 -2
- package/src/daemon/api/subagent-router.test.ts +108 -0
- package/src/daemon/api/subagent-router.ts +296 -0
- package/src/daemon/api/subagent-utils.test.ts +56 -0
- package/src/daemon/api/subagent-utils.ts +130 -0
- package/src/daemon/api/user-router.ts +30 -13
- package/src/daemon/auth.ts +1 -0
- package/src/daemon/chats.ts +6 -0
- package/src/daemon/cron.test.ts +66 -1
- package/src/daemon/cron.ts +35 -8
- package/src/daemon/index.ts +23 -0
- package/src/daemon/message-agent.test.ts +11 -25
- package/src/daemon/message-extraction.test.ts +10 -27
- package/src/daemon/message-fallbacks.test.ts +13 -35
- package/src/daemon/message-interruption.test.ts +70 -53
- package/src/daemon/message-jobs.test.ts +138 -0
- package/src/daemon/message-queue.test.ts +30 -43
- package/src/daemon/message-router.test.ts +12 -11
- package/src/daemon/message-session.test.ts +41 -28
- package/src/daemon/message-typing.test.ts +19 -6
- package/src/daemon/message.ts +103 -515
- package/src/daemon/policy-request-service.ts +8 -3
- package/src/daemon/policy-utils.ts +19 -1
- package/src/daemon/queue.ts +16 -0
- package/src/daemon/request-store.test.ts +4 -0
- package/src/daemon/routers/session-timeout.test.ts +122 -0
- package/src/daemon/routers/session-timeout.ts +71 -0
- package/src/daemon/routers/slash-new.ts +3 -1
- package/src/daemon/routers/slash-policies.test.ts +26 -13
- package/src/daemon/routers/slash-policies.ts +39 -29
- package/src/daemon/routers/types.ts +8 -0
- package/src/daemon/routers.ts +64 -2
- package/src/daemon/utils/spawn.ts +6 -8
- package/src/shared/adapters/commands.test.ts +155 -0
- package/src/shared/adapters/commands.ts +125 -0
- package/src/shared/adapters/filtering.test.ts +111 -0
- package/src/shared/adapters/filtering.ts +57 -0
- package/src/shared/adapters/routing.test.ts +144 -0
- package/src/shared/adapters/routing.ts +109 -0
- package/src/shared/agent-utils.ts +10 -0
- package/src/shared/chats.test.ts +145 -3
- package/src/shared/chats.ts +215 -18
- package/src/shared/config.ts +67 -15
- package/src/shared/lite.ts +22 -18
- package/src/shared/policies.ts +7 -0
- package/src/shared/workspace.test.ts +45 -1
- package/src/shared/workspace.ts +119 -6
- package/templates/debug/settings.json +5 -2
- package/templates/environments/cladding/env.json +2 -2
- package/templates/gemini/.gemini/hooks/check-subagents.mjs +23 -0
- package/templates/gemini/.gemini/hooks/clawmini-logging.sh +17 -0
- package/templates/gemini/.gemini/hooks/insert-pending.sh +9 -0
- package/templates/gemini/.gemini/settings.json +50 -0
- package/templates/gemini/settings.json +22 -8
- package/templates/gemini-claw/.gemini/base-system.md +100 -0
- package/templates/gemini-claw/.gemini/hooks/check-subagents.mjs +23 -0
- package/templates/gemini-claw/.gemini/hooks/clawmini-logging.sh +1 -1
- package/templates/gemini-claw/.gemini/settings.json +13 -0
- package/templates/gemini-claw/.gemini/subagent-system.md +7 -0
- package/templates/gemini-claw/.gemini/system.md +3 -99
- package/templates/gemini-claw/settings.json +27 -22
- package/templates/skills/clawmini-requests/SKILL.md +92 -0
- package/templates/skills/clawmini-subagents/SKILL.md +79 -0
- package/templates/skills/skill-creator/SKILL.md +60 -0
- package/tsdown.config.ts +10 -1
- package/web/.svelte-kit/generated/server/internal.js +2 -1
- package/web/.svelte-kit/non-ambient.d.ts +2 -0
- package/web/.svelte-kit/output/client/.vite/manifest.json +141 -138
- package/web/.svelte-kit/output/client/_app/immutable/assets/0.C-4eziNy.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
- package/{dist/web/_app/immutable/chunks/8YNcRyEk.js → web/.svelte-kit/output/client/_app/immutable/chunks/C20lZMGz.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/C9lbZ-kT.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
- package/{dist/web/_app/immutable/entry/app.DO5eYwVz.js → web/.svelte-kit/output/client/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.DuxJo6av.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.DLarELN4.js +60 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
- package/web/.svelte-kit/output/client/_app/version.json +1 -1
- package/web/.svelte-kit/output/server/.vite/manifest.json +12 -3
- package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.C-4eziNy.css +1 -0
- package/web/.svelte-kit/output/server/_app/immutable/assets/_page.Cc_xwLNl.css +1 -0
- package/web/.svelte-kit/output/server/chunks/app-state.svelte.js +5 -0
- package/web/.svelte-kit/output/server/chunks/bot.js +4 -4
- package/web/.svelte-kit/output/server/chunks/client.js +2 -1
- package/web/.svelte-kit/output/server/chunks/exports.js +0 -1
- package/web/.svelte-kit/output/server/chunks/internal.js +2 -1
- package/web/.svelte-kit/output/server/chunks/root.js +482 -392
- package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +57 -7
- package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.svelte.js +234 -9
- package/web/.svelte-kit/output/server/index.js +82 -10
- package/web/.svelte-kit/output/server/manifest-full.js +1 -1
- package/web/.svelte-kit/output/server/manifest.js +1 -1
- package/web/.svelte-kit/output/server/nodes/0.js +2 -2
- package/web/.svelte-kit/output/server/nodes/1.js +1 -1
- package/web/.svelte-kit/output/server/nodes/2.js +1 -1
- package/web/.svelte-kit/output/server/nodes/3.js +1 -1
- package/web/.svelte-kit/output/server/nodes/4.js +2 -2
- package/web/.svelte-kit/output/server/nodes/5.js +1 -1
- package/web/.svelte-kit/types/src/routes/$types.d.ts +1 -2
- package/web/.svelte-kit/types/src/routes/agents/$types.d.ts +1 -2
- package/web/.svelte-kit/types/src/routes/chats/[id]/$types.d.ts +1 -2
- package/web/.svelte-kit/types/src/routes/chats/[id]/settings/$types.d.ts +1 -2
- package/web/package.json +8 -0
- package/web/src/lib/app-state.svelte.ts +5 -1
- package/web/src/lib/components/app/markdown-renderer.svelte +56 -0
- package/web/src/lib/components/app/markdown-renderer.svelte.spec.ts +44 -0
- package/web/src/lib/components/app/message-content.svelte +16 -0
- package/web/src/lib/types.ts +67 -3
- package/web/src/routes/+layout.svelte +31 -1
- package/web/src/routes/chats/[id]/+page.svelte +167 -18
- package/web/src/routes/chats/[id]/page.svelte.spec.ts +58 -7
- package/dist/lite-oSYSvaOr.mjs.map +0 -1
- package/dist/web/_app/immutable/assets/0.GI4C4dpV.css +0 -1
- package/dist/web/_app/immutable/chunks/B5abRDXp.js +0 -1
- package/dist/web/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
- package/dist/web/_app/immutable/chunks/BmUXQ3wy.js +0 -2
- package/dist/web/_app/immutable/chunks/C3k55nDF.js +0 -1
- package/dist/web/_app/immutable/chunks/CpaGRn9L.js +0 -1
- package/dist/web/_app/immutable/chunks/DG5RZBw-.js +0 -2
- package/dist/web/_app/immutable/chunks/DQoygso7.js +0 -1
- package/dist/web/_app/immutable/entry/start.D48mVn1m.js +0 -1
- package/dist/web/_app/immutable/nodes/0.B-0CcADM.js +0 -1
- package/dist/web/_app/immutable/nodes/1.FixKgvRO.js +0 -1
- package/dist/web/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
- package/dist/workspace-DjoNjhW0.mjs.map +0 -1
- package/src/daemon/message-verbosity.test.ts +0 -127
- package/web/.svelte-kit/output/client/_app/immutable/assets/0.GI4C4dpV.css +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B5abRDXp.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BmUXQ3wy.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/C3k55nDF.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CpaGRn9L.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DG5RZBw-.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DQoygso7.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.D48mVn1m.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/0.B-0CcADM.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.FixKgvRO.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
- package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.GI4C4dpV.css +0 -1
- /package/templates/{gemini-claw/.gemini/skills → skills}/clawmini-jobs/SKILL.md +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["fsPromises","fsPromises","authClient","fsPromises"],"sources":["../../src/adapter-google-chat/config.ts","../../src/adapter-google-chat/state.ts","../../src/adapter-google-chat/utils.ts","../../src/adapter-google-chat/auth.ts","../../src/adapter-google-chat/subscriptions.ts","../../src/adapter-google-chat/cards.ts","../../src/adapter-google-chat/client.ts","../../src/adapter-google-chat/upload.ts","../../src/adapter-google-chat/forwarder.ts","../../src/adapter-google-chat/cron.ts","../../src/adapter-google-chat/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 GoogleChatConfigSchema = z.looseObject({\n projectId: z.string().min(1, 'GCP Project ID is required.'),\n subscriptionName: z.string().min(1, 'Pub/Sub Subscription Name is required.'),\n topicName: z.string().min(1, 'Pub/Sub Topic Name is required.'),\n authorizedUsers: z.array(z.string()).min(1, 'At least one Authorized User is required.'),\n maxAttachmentSizeMB: z.number().default(25).optional(),\n chatId: z.string().default('default').optional(),\n directMessageName: z.string().optional(),\n driveUploadEnabled: z.boolean().default(true).optional(),\n requireMention: z.boolean().default(false),\n oauthClientId: z.string().optional(),\n oauthClientSecret: z.string().optional(),\n});\n\nexport type GoogleChatConfig = z.infer<typeof GoogleChatConfigSchema>;\n\nexport function getGoogleChatConfigPath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'google-chat', 'config.json');\n}\n\nexport async function readGoogleChatConfig(\n startDir = process.cwd()\n): Promise<GoogleChatConfig | null> {\n const configPath = getGoogleChatConfigPath(startDir);\n try {\n const data = await fsPromises.readFile(configPath, 'utf-8');\n const parsed = JSON.parse(data);\n return GoogleChatConfigSchema.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 updateGoogleChatConfig(\n config: GoogleChatConfig,\n startDir = process.cwd()\n): Promise<void> {\n const configPath = getGoogleChatConfigPath(startDir);\n await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\n}\n\nexport async function initGoogleChatConfig(startDir = process.cwd()): Promise<void> {\n const configPath = getGoogleChatConfigPath(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 projectId: 'YOUR_PROJECT_ID',\n topicName: 'YOUR_TOPIC_NAME',\n subscriptionName: 'YOUR_SUBSCRIPTION_NAME',\n authorizedUsers: ['user@example.com'],\n chatId: 'default',\n requireMention: false,\n oauthClientId: 'YOUR_OAUTH_CLIENT_ID',\n oauthClientSecret: 'YOUR_OAUTH_CLIENT_SECRET',\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(\n 'Please update it with your actual GCP Project ID, Pub/Sub Topic Name, Pub/Sub Subscription Name, and Authorized Users.'\n );\n}\n\nexport function isAuthorized(userIdOrEmail: string, authorizedUsers: string[]): boolean {\n return authorizedUsers.some((u) => u.toLowerCase() === userIdOrEmail.toLowerCase());\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 GoogleChatStateSchema = 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 subscriptionId: z.string().optional(),\n expirationDate: z.string().optional(),\n requireMention: z.boolean().optional(),\n })\n )\n .optional(),\n oauthTokens: z.any().optional(),\n filters: z.record(z.string(), z.boolean()).optional(),\n});\n\nexport type GoogleChatState = z.infer<typeof GoogleChatStateSchema>;\n\nexport function getGoogleChatStatePath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'google-chat', 'state.json');\n}\n\nexport async function readGoogleChatState(startDir = process.cwd()): Promise<GoogleChatState> {\n const statePath = getGoogleChatStatePath(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.driveOauthTokens && !parsed.oauthTokens) {\n parsed.oauthTokens = parsed.driveOauthTokens;\n delete parsed.driveOauthTokens;\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 GoogleChatStateSchema.parse(parsed);\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n oauthTokens: undefined,\n };\n }\n throw err;\n }\n}\n\nlet stateUpdatePromise = Promise.resolve();\n\nexport function updateGoogleChatState(\n updates: Partial<GoogleChatState> | ((state: GoogleChatState) => Partial<GoogleChatState>),\n startDir = process.cwd()\n): Promise<GoogleChatState> {\n return new Promise((resolve, reject) => {\n stateUpdatePromise = stateUpdatePromise.then(async () => {\n try {\n const currentState = await readGoogleChatState(startDir);\n const resolvedUpdates = typeof updates === 'function' ? updates(currentState) : updates;\n const newState = { ...currentState, ...resolvedUpdates };\n const statePath = getGoogleChatStatePath(startDir);\n const dir = path.dirname(statePath);\n await fsPromises.mkdir(dir, { recursive: true });\n await fsPromises.writeFile(statePath, JSON.stringify(newState, null, 2), 'utf-8');\n resolve(newState);\n } catch (err) {\n console.error(`Failed to write Google Chat state:`, err);\n reject(err);\n }\n });\n });\n}\n","import { google } from 'googleapis';\nimport type { Readable } from 'node:stream';\nimport type { ChatMessage } from '../shared/chats.js';\n\nlet authClient: Awaited<ReturnType<typeof google.auth.getClient>> | null = null;\n\nexport function resetAuthClient(): void {\n authClient = null;\n}\n\nexport function buildPolicyCard(logMessage: ChatMessage) {\n const policyId = ('requestId' in logMessage && logMessage.requestId) || logMessage.id;\n return [\n {\n cardId: logMessage.id,\n card: {\n header: {\n title: 'Action Required: Policy Approval',\n subtitle: 'A request needs your review.',\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: logMessage.content || 'Please review this request.',\n },\n },\n {\n buttonList: {\n buttons: [\n {\n text: 'Approve',\n color: {\n red: 0,\n green: 0.5,\n blue: 0,\n alpha: 1,\n },\n onClick: {\n action: {\n function: 'approve',\n parameters: [{ key: 'policyId', value: policyId }],\n },\n },\n },\n {\n text: 'Reject',\n color: {\n red: 0.8,\n green: 0,\n blue: 0,\n alpha: 1,\n },\n onClick: {\n action: {\n function: 'reject',\n parameters: [{ key: 'policyId', value: policyId }],\n },\n },\n },\n ],\n },\n },\n ],\n },\n ],\n },\n },\n ];\n}\n\nexport function 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\n/**\n * Downloads a file attachment securely using Application Default Credentials (ADC).\n * @param resourceName The resourceName of the attachment data to download.\n * @param maxAttachmentSizeMB The maximum allowed attachment size in MB (defaults to 25).\n * @returns A Buffer containing the file data.\n */\nexport async function downloadAttachment(\n resourceName: string,\n maxAttachmentSizeMB: number = 25\n): Promise<Buffer> {\n // Use ADC to authenticate\n if (!authClient) {\n authClient = await google.auth.getClient({\n scopes: ['https://www.googleapis.com/auth/chat.bot'],\n });\n }\n const client = authClient;\n\n const url = `https://chat.googleapis.com/v1/media/${resourceName}?alt=media`;\n\n const response = await client.request<Readable>({\n url,\n method: 'GET',\n responseType: 'stream',\n });\n\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n const maxSizeBytes = maxAttachmentSizeMB * 1024 * 1024;\n\n response.data.on('data', (chunk: Buffer) => {\n totalBytes += chunk.length;\n if (totalBytes > maxSizeBytes) {\n response.data.destroy();\n reject(\n new Error(`Attachment exceeds maximum size of ${maxSizeBytes} bytes: ${totalBytes} bytes`)\n );\n } else {\n chunks.push(chunk);\n }\n });\n\n response.data.on('end', () => {\n resolve(Buffer.concat(chunks));\n });\n\n response.data.on('error', (err: Error) => {\n reject(err);\n });\n });\n}\n","import { google } from 'googleapis';\nimport http from 'node:http';\nimport type { GoogleChatConfig } from './config.js';\nimport { readGoogleChatState, updateGoogleChatState } from './state.js';\n\nlet authClient: Awaited<ReturnType<typeof google.auth.getClient>> | null = null;\nexport async function getAuthClient() {\n if (!authClient) {\n authClient = await google.auth.getClient({\n scopes: ['https://www.googleapis.com/auth/chat.bot'],\n });\n }\n return authClient;\n}\n\nlet userAuthClient: InstanceType<typeof google.auth.OAuth2> | null = null;\nlet userAuthPromise: Promise<InstanceType<typeof google.auth.OAuth2>> | null = null;\n\nexport async function getUserAuthClient(config: GoogleChatConfig) {\n if (userAuthClient) return userAuthClient;\n if (userAuthPromise) return userAuthPromise;\n\n if (!config.oauthClientId || !config.oauthClientSecret) {\n console.error('DEBUG config:', config);\n throw new Error(\n 'oauthClientId and oauthClientSecret are required in config.json for user authentication.'\n );\n }\n\n userAuthPromise = (async () => {\n const oauth2Client = new google.auth.OAuth2(\n config.oauthClientId,\n config.oauthClientSecret,\n 'http://localhost:31338/oauth2callback'\n );\n\n oauth2Client.on('tokens', async (tokens) => {\n try {\n const currentState = await readGoogleChatState();\n await updateGoogleChatState({\n oauthTokens: {\n ...currentState.oauthTokens,\n ...tokens,\n },\n });\n } catch (err) {\n console.error('Failed to save refreshed Google User tokens', err);\n }\n });\n\n const state = await readGoogleChatState();\n if (state.oauthTokens) {\n oauth2Client.setCredentials(state.oauthTokens);\n userAuthClient = oauth2Client;\n userAuthPromise = null;\n return oauth2Client;\n }\n\n const authUrl = oauth2Client.generateAuthUrl({\n access_type: 'offline',\n scope: [\n 'https://www.googleapis.com/auth/drive.file',\n 'https://www.googleapis.com/auth/chat.messages.readonly',\n ],\n prompt: 'consent',\n });\n\n console.log('\\n======================================================');\n console.log('Google User Authorization Required!');\n console.log('Please visit the following URL to authorize this bot:');\n console.log(authUrl);\n console.log('======================================================\\n');\n\n return new Promise<typeof oauth2Client>((resolve, reject) => {\n let timeoutId: NodeJS.Timeout;\n\n const server = http.createServer(async (req, res) => {\n if (req.url?.startsWith('/oauth2callback')) {\n const url = new URL(req.url, 'http://localhost:31338');\n const code = url.searchParams.get('code');\n if (code) {\n res.end('Authentication successful! You can close this window.');\n clearTimeout(timeoutId);\n server.close();\n try {\n const { tokens } = await oauth2Client.getToken(code);\n oauth2Client.setCredentials(tokens);\n\n await updateGoogleChatState({ oauthTokens: tokens });\n\n console.log('Google User authorization successful!');\n userAuthClient = oauth2Client;\n userAuthPromise = null;\n resolve(oauth2Client);\n } catch (err) {\n console.error('Failed to get token', err);\n userAuthPromise = null;\n reject(err);\n }\n } else {\n res.end('Authentication failed!');\n clearTimeout(timeoutId);\n server.close();\n userAuthPromise = null;\n reject(new Error('No code provided in OAuth callback'));\n }\n }\n });\n\n server.on('error', (err) => {\n console.error('Failed to start local OAuth server on port 31338', err);\n clearTimeout(timeoutId);\n userAuthPromise = null;\n reject(err);\n });\n\n server.listen(31338, '127.0.0.1', () => {\n timeoutId = setTimeout(\n () => {\n server.close();\n userAuthPromise = null;\n console.error('Google User authorization timed out after 5 minutes.');\n reject(new Error('Google User authorization timed out.'));\n },\n 5 * 60 * 1000\n );\n });\n });\n })();\n\n return userAuthPromise;\n}\n","import { google } from 'googleapis';\nimport type { GoogleChatConfig } from './config.js';\nimport { getAuthClient, getUserAuthClient } from './auth.js';\nimport { updateGoogleChatState, type GoogleChatState } from './state.js';\n\nexport async function handleAddedToSpace(\n spaceName: string,\n externalContextId: string,\n spaceType: string | undefined,\n targetChatId: string | null | undefined,\n mappedChatId: string | null | undefined,\n config: GoogleChatConfig\n) {\n if (spaceType !== 'DIRECT_MESSAGE') {\n try {\n const userAuthClient = await getUserAuthClient(config);\n const tokenResponse = await userAuthClient.getAccessToken();\n const token = tokenResponse.token;\n\n if (token) {\n const res = await fetch('https://workspaceevents.googleapis.com/v1/subscriptions', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n targetResource: `//chat.googleapis.com/${spaceName}`,\n eventTypes: ['google.workspace.chat.message.v1.created'],\n payloadOptions: { includeResource: true },\n notificationEndpoint: {\n pubsubTopic: `projects/${config.projectId}/topics/${config.topicName}`,\n },\n }),\n });\n\n if (res.ok) {\n const subData = (await res.json()) as { name: string; expireTime: string };\n await updateGoogleChatState((latestState) => {\n const currentMap = latestState.channelChatMap || {};\n return {\n channelChatMap: {\n ...currentMap,\n [externalContextId]: {\n ...(currentMap[externalContextId] || {}),\n subscriptionId: subData.name,\n expirationDate: subData.expireTime,\n },\n },\n };\n });\n console.log(`Created subscription ${subData.name} for space ${externalContextId}`);\n } else {\n const errText = await res.text();\n console.error(`Failed to create subscription for space ${externalContextId}:`, errText);\n }\n }\n } catch (err) {\n console.error('Error setting up subscription on ADDED_TO_SPACE:', err);\n }\n }\n\n if (targetChatId && mappedChatId) {\n try {\n const authClient = await getAuthClient();\n const chatApi = google.chat({ version: 'v1', auth: authClient });\n await chatApi.spaces.messages.create({\n parent: externalContextId,\n requestBody: {\n text: `Hello! I am currently mapped to chat \\`${targetChatId}\\`.`,\n },\n });\n } catch (err) {\n console.error('Failed to send greeting on ADDED_TO_SPACE:', err);\n }\n }\n}\n\nexport async function handleRemovedFromSpace(\n externalContextId: string,\n currentState: GoogleChatState,\n config: GoogleChatConfig\n) {\n const subId = currentState.channelChatMap?.[externalContextId]?.subscriptionId;\n if (subId) {\n try {\n const userAuthClient = await getUserAuthClient(config);\n const tokenResponse = await userAuthClient.getAccessToken();\n const token = tokenResponse.token;\n\n if (token) {\n const res = await fetch(`https://workspaceevents.googleapis.com/v1/${subId}`, {\n method: 'DELETE',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (res.ok) {\n console.log(`Deleted subscription ${subId}`);\n } else {\n const errText = await res.text();\n console.error(`Failed to delete subscription ${subId}:`, errText);\n }\n }\n } catch (err) {\n console.error('Error tearing down subscription on REMOVED_FROM_SPACE:', err);\n }\n }\n\n await updateGoogleChatState((latestState) => {\n const map = { ...(latestState.channelChatMap || {}) };\n const entry = map[externalContextId];\n if (entry) {\n if (!entry.chatId) {\n delete map[externalContextId];\n } else {\n delete entry.subscriptionId;\n delete entry.expirationDate;\n }\n }\n return { channelChatMap: map };\n });\n}\n","import { google } from 'googleapis';\nimport { getAuthClient } from './auth.js';\nimport type { RoutingTrpcClient } from '../shared/adapters/routing.js';\n\nexport async function handleCardClicked(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: any,\n targetChatId: string,\n trpc: RoutingTrpcClient\n) {\n const action = event.action;\n if (!action) return;\n\n const methodName = action.actionMethodName;\n const params = action.parameters || [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const policyIdParam = params.find((p: any) => p.key === 'policyId');\n const policyId = policyIdParam?.value;\n\n if (policyId && (methodName === 'approve' || methodName === 'reject')) {\n const cmd = methodName === 'approve' ? `/approve ${policyId}` : `/reject ${policyId}`;\n\n if (event.message?.name) {\n try {\n const chatApi = google.chat({ version: 'v1', auth: await getAuthClient() });\n\n const originalCards = event.message.cardsV2 || [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const updatedCards = originalCards.map((c: any) => {\n if (c.card?.sections) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n c.card.sections = c.card.sections.map((s: any) => {\n if (s.widgets) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n s.widgets = s.widgets.filter((w: any) => !w.buttonList);\n }\n return s;\n });\n }\n if (c.card?.header) {\n const statusText = methodName === 'approve' ? 'Approved' : 'Rejected';\n c.card.header.subtitle = `Policy ${statusText}`;\n }\n return c;\n });\n\n await chatApi.spaces.messages.update({\n name: event.message.name,\n updateMask: 'cardsV2',\n requestBody: {\n cardsV2: updatedCards,\n },\n });\n } catch (updateErr) {\n console.error(`Failed to update card for policy ${policyId}:`, updateErr);\n }\n }\n\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: cmd,\n chatId: targetChatId,\n adapter: 'google-chat',\n noWait: true,\n },\n });\n console.log(`Forwarded ${methodName} for policy ${policyId} to daemon.`);\n }\n}\n","/* eslint-disable max-lines */\nimport { PubSub, Message } from '@google-cloud/pubsub';\nimport { createTRPCClient, httpLink, splitLink, httpSubscriptionLink } from '@trpc/client';\nimport fs from 'node:fs';\nimport fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\n\nimport type { UserRouter as AppRouter } from '../daemon/api/index.js';\nimport { getSocketPath, getClawminiDir } from '../shared/workspace.js';\nimport { createUnixSocketFetch } from '../shared/fetch.js';\nimport { createUnixSocketEventSource } from '../shared/event-source.js';\nimport type { GoogleChatConfig } from './config.js';\nimport { isAuthorized, updateGoogleChatConfig } from './config.js';\nimport { readGoogleChatState, updateGoogleChatState } from './state.js';\nimport { downloadAttachment } from './utils.js';\nimport { handleAdapterCommand, type CommandTrpcClient } from '../shared/adapters/commands.js';\nimport { formatMessage, type FilteringConfig } from '../shared/adapters/filtering.js';\nimport { google } from 'googleapis';\nimport { getAuthClient } from './auth.js';\nimport { handleRoutingCommand, type RoutingTrpcClient } from '../shared/adapters/routing.js';\n\nimport { handleAddedToSpace, handleRemovedFromSpace } from './subscriptions.js';\nimport { handleCardClicked } from './cards.js';\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\nexport function startGoogleChatIngestion(\n config: GoogleChatConfig,\n trpc: ReturnType<typeof getTRPCClient>,\n filteringConfig: FilteringConfig\n) {\n const pubsub = new PubSub({ projectId: config.projectId });\n const subscription = pubsub.subscription(config.subscriptionName);\n\n const seenMessageIds = new Map<string, number>();\n\n // Periodically clean up deduplication cache every 5 minutes\n setInterval(\n () => {\n const now = Date.now();\n for (const [id, ts] of seenMessageIds.entries()) {\n if (now - ts > 10 * 60 * 1000) {\n seenMessageIds.delete(id);\n }\n }\n },\n 5 * 60 * 1000\n ).unref();\n\n subscription.on('message', async (message: Message) => {\n const downloadedFiles: string[] = [];\n try {\n const dataString = message.data.toString('utf8');\n const parsedData = JSON.parse(dataString);\n\n const isWorkspaceEvent =\n message.attributes &&\n message.attributes['ce-type'] === 'google.workspace.chat.message.v1.created';\n\n const eventType = isWorkspaceEvent ? 'MESSAGE' : parsedData.type;\n\n const eventMessage = isWorkspaceEvent ? parsedData.message || parsedData : parsedData.message;\n const email =\n (isWorkspaceEvent\n ? eventMessage?.sender?.email\n : parsedData.user?.email || eventMessage?.sender?.email) || '';\n const senderName = eventMessage?.sender?.name || parsedData.user?.name || '';\n\n const space = isWorkspaceEvent\n ? eventMessage?.space\n : parsedData.space || eventMessage?.space;\n const senderType = eventMessage?.sender?.type || '';\n const messageId = eventMessage?.name || '';\n const text = (eventMessage?.argumentText || eventMessage?.text || '').trim();\n\n if (senderType === 'BOT') return void message.ack();\n\n if (messageId) {\n if (seenMessageIds.has(messageId)) return void message.ack();\n seenMessageIds.set(messageId, Date.now());\n }\n\n // Only handle MESSAGE, CARD_CLICKED, ADDED_TO_SPACE, and REMOVED_FROM_SPACE events\n if (\n eventType !== 'MESSAGE' &&\n eventType !== 'CARD_CLICKED' &&\n eventType !== 'ADDED_TO_SPACE' &&\n eventType !== 'REMOVED_FROM_SPACE'\n ) {\n message.ack();\n return;\n }\n\n let isUserAuthorized = false;\n let authorizedByEmail = false;\n\n if (email && isAuthorized(email, config.authorizedUsers)) {\n isUserAuthorized = true;\n authorizedByEmail = true;\n } else if (senderName && isAuthorized(senderName, config.authorizedUsers)) {\n isUserAuthorized = true;\n }\n\n if (!isUserAuthorized) {\n console.log(`Unauthorized or missing identifier: email=${email}, name=${senderName}`);\n console.log('DEBUG missing identifier parsedData:', JSON.stringify(parsedData, null, 2));\n message.ack();\n return;\n }\n\n // Automatically authorize user IDs if associated an authorized email\n if (authorizedByEmail && senderName && !isAuthorized(senderName, config.authorizedUsers)) {\n console.log(\n `Automatically authorizing user ID ${senderName} based on authorized email ${email}`\n );\n config.authorizedUsers.push(senderName);\n updateGoogleChatConfig(config).catch((err) =>\n console.error('Failed to update config with new user ID:', err)\n );\n }\n\n const identifier = email || senderName;\n\n const spaceName = space?.name;\n\n if (!spaceName) {\n console.log('Ignoring message: Could not determine space name.');\n message.ack();\n return;\n }\n\n const currentState = await readGoogleChatState();\n\n const externalContextId = spaceName;\n const mappedChatId = currentState.channelChatMap?.[externalContextId]?.chatId;\n const isRoutingCommand = text.startsWith('/chat') || text.startsWith('/agent');\n\n if (eventType === 'ADDED_TO_SPACE') {\n await handleAddedToSpace(\n spaceName as string,\n externalContextId,\n space?.type,\n mappedChatId,\n mappedChatId,\n config\n );\n if (!text) {\n message.ack();\n return;\n }\n }\n\n if (eventType === 'REMOVED_FROM_SPACE') {\n await handleRemovedFromSpace(externalContextId, currentState, config);\n message.ack();\n return;\n }\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 text,\n externalContextId,\n stringChatMap,\n 'google-chat',\n trpc as unknown as RoutingTrpcClient\n );\n\n if (routingResult) {\n if (routingResult.type === 'mapped') {\n await updateGoogleChatState((latestState) => ({\n channelChatMap: {\n ...(latestState.channelChatMap || {}),\n [externalContextId]: {\n ...(latestState.channelChatMap?.[externalContextId] || {}),\n chatId: routingResult.newChatId,\n },\n },\n }));\n }\n\n try {\n const authClient = await getAuthClient();\n const chatApi = google.chat({ version: 'v1', auth: authClient });\n await chatApi.spaces.messages.create({\n parent: externalContextId,\n requestBody: { text: routingResult.text },\n });\n } catch (err) {\n console.error('Failed to send routing command reply:', err);\n }\n\n message.ack();\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 space ${externalContextId} to chat ${targetChatId}.`\n );\n await updateGoogleChatState((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 =\n space?.type === 'DIRECT_MESSAGE' || space?.singleUserBotDm === true;\n const isMentioned =\n Array.isArray(eventMessage?.annotations) &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n eventMessage.annotations.some((a: any) => a.type === 'USER_MENTION');\n const isSlashCommand = text.startsWith('/');\n if (isDirectMessage || isMentioned || isSlashCommand) {\n console.log(`Unmapped space ${externalContextId}, sending first contact warning.`);\n try {\n const authClient = await getAuthClient();\n const chatApi = google.chat({ version: 'v1', auth: authClient });\n await chatApi.spaces.messages.create({\n parent: externalContextId,\n requestBody: {\n text: '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 });\n } catch (err) {\n console.error('Failed to send first contact warning:', err);\n }\n } else {\n console.log(\n `Unmapped space ${externalContextId}, silently ignoring background message.`\n );\n }\n message.ack();\n return;\n }\n }\n\n // Fallback typing safeguard\n if (!targetChatId) targetChatId = config.chatId || 'default';\n\n const isDirectMessage = space?.type === 'DIRECT_MESSAGE' || space?.singleUserBotDm === true;\n if (!isDirectMessage && eventType === 'MESSAGE') {\n const channelConfig = currentState.channelChatMap?.[externalContextId];\n const requiresMention =\n channelConfig?.requireMention !== undefined\n ? channelConfig.requireMention\n : config.requireMention;\n\n if (requiresMention && !isRoutingCommand) {\n const isMentioned =\n Array.isArray(eventMessage?.annotations) &&\n eventMessage.annotations.some(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (a: any) => a.type === 'USER_MENTION' && a.userMention?.user?.type === 'BOT'\n );\n\n let isReplyToBot = false;\n if (eventMessage?.threadReply && eventMessage.thread?.name) {\n try {\n const authClient = await getAuthClient();\n const chatApi = google.chat({ version: 'v1', auth: authClient });\n const response = await chatApi.spaces.messages.list({\n parent: externalContextId,\n filter: `thread.name=\"${eventMessage.thread.name}\"`,\n });\n isReplyToBot =\n response.data.messages?.some(\n (m) =>\n m.sender?.type === 'BOT' ||\n m.annotations?.some(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (a: any) => a.type === 'USER_MENTION' && a.userMention?.user?.type === 'BOT'\n )\n ) ?? false;\n } catch (err) {\n console.error('Failed to fetch thread messages for mention check:', err);\n }\n }\n\n // If requireMention is true and it's not a DM, ignore if not mentioned and not a thread reply to the bot.\n if (!isMentioned && !isReplyToBot) {\n message.ack();\n return;\n }\n }\n }\n\n if (eventType === 'CARD_CLICKED') {\n await handleCardClicked(\n parsedData,\n targetChatId as string,\n trpc as unknown as RoutingTrpcClient\n );\n message.ack();\n return;\n }\n\n const commandResult = await handleAdapterCommand(\n text,\n filteringConfig,\n trpc as unknown as CommandTrpcClient,\n targetChatId\n );\n\n if (commandResult) {\n let resultText = '';\n if (commandResult.type === 'text') {\n if (commandResult.newConfig) {\n filteringConfig.filters = commandResult.newConfig.filters;\n await updateGoogleChatState({ filters: filteringConfig.filters });\n }\n resultText = commandResult.text;\n } else if (commandResult.type === 'debug') {\n resultText =\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 }\n\n const authClient = await getAuthClient();\n const chatApi = google.chat({ version: 'v1', auth: authClient });\n await chatApi.spaces.messages.create({\n parent: spaceName as string,\n requestBody: { text: resultText },\n });\n message.ack();\n return;\n }\n const attachments = eventMessage?.attachment || [];\n\n if (attachments.length > 0) {\n const tmpDir = path.join(getClawminiDir(process.cwd()), 'tmp', 'google-chat');\n await fsPromises.mkdir(tmpDir, { recursive: true });\n\n for (const att of attachments) {\n const resourceName = att.attachmentDataRef?.resourceName;\n if (resourceName) {\n try {\n const buffer = await downloadAttachment(resourceName, config.maxAttachmentSizeMB);\n const uniqueName = `${crypto.randomUUID()}-${att.contentName || 'attachment'}`;\n const filePath = path.join(tmpDir, uniqueName);\n await fsPromises.writeFile(filePath, buffer);\n downloadedFiles.push(filePath);\n } catch (err) {\n console.error(`Error downloading attachment:`, err);\n }\n }\n }\n }\n\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: text,\n chatId: targetChatId,\n files: downloadedFiles.length > 0 ? downloadedFiles : undefined,\n adapter: 'google-chat',\n noWait: true,\n },\n });\n\n console.log(`Forwarded message from ${identifier} to daemon.`);\n message.ack();\n } catch (error) {\n console.error('Error processing Pub/Sub message:', error);\n for (const file of downloadedFiles) {\n try {\n await fsPromises.unlink(file);\n } catch (unlinkErr) {\n console.error(`Failed to delete downloaded file ${file} after error:`, unlinkErr);\n }\n }\n // Add a brief artificial delay before nacking to avoid tight retry loops\n await new Promise((resolve) => setTimeout(resolve, 2000));\n // Nack the message so it can be retried if it's a transient failure\n message.nack();\n }\n });\n\n subscription.on('error', (error) => {\n console.error('Pub/Sub subscription error:', error);\n });\n\n return subscription;\n}\n","import { google } from 'googleapis';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport mime from 'mime-types';\nimport type { GoogleChatConfig } from './config.js';\nimport { getUserAuthClient } from './auth.js';\nimport { getWorkspaceRoot } from '../shared/workspace.js';\n\nexport async function uploadFilesToDrive(\n files: string[],\n config: GoogleChatConfig\n): Promise<string[]> {\n const driveClient = await getUserAuthClient(config);\n const driveApi = google.drive({ version: 'v3', auth: driveClient });\n const workspaceRoot = getWorkspaceRoot(process.cwd());\n\n let folderId: string | undefined;\n try {\n const queryRes = await driveApi.files.list({\n q: \"mimeType='application/vnd.google-apps.folder' and name='Clawmini Uploads' and trashed=false\",\n fields: 'files(id)',\n });\n if (queryRes.data.files && queryRes.data.files.length > 0) {\n folderId = queryRes.data.files[0]!.id!;\n } else {\n const folderRes = await driveApi.files.create({\n requestBody: {\n name: 'Clawmini Uploads',\n mimeType: 'application/vnd.google-apps.folder',\n },\n fields: 'id',\n });\n if (folderRes.data.id) {\n folderId = folderRes.data.id;\n }\n }\n } catch (err) {\n console.error('Failed to create or find Clawmini Uploads folder', err);\n }\n\n const uploadPromises = files.map(async (fileRelPath) => {\n const filePath = path.resolve(workspaceRoot, fileRelPath);\n if (!fs.existsSync(filePath)) return null;\n\n const fileName = path.basename(filePath);\n const mimeType = mime.lookup(filePath) || 'application/octet-stream';\n\n try {\n const driveRes = await driveApi.files.create({\n requestBody: {\n name: fileName,\n ...(folderId ? { parents: [folderId] } : {}),\n },\n media: { mimeType, body: fs.createReadStream(filePath) },\n fields: 'id, webViewLink',\n });\n\n if (driveRes.data.id && driveRes.data.webViewLink) {\n const fileId = driveRes.data.id;\n try {\n await Promise.all(\n config.authorizedUsers.map((email) =>\n driveApi.permissions.create({\n fileId,\n requestBody: {\n type: 'user',\n role: 'reader',\n emailAddress: email,\n },\n sendNotificationEmail: false,\n })\n )\n );\n } catch (err) {\n console.error(`Failed to grant permissions for ${fileName}`, err);\n }\n return driveRes.data.webViewLink;\n }\n return null;\n } catch (err) {\n console.error(`Failed to upload file ${fileName} to Google Drive`, err);\n return `*(Failed to upload to Drive: ${fileName})*`;\n }\n });\n\n const uploadResults = await Promise.all(uploadPromises);\n return uploadResults.filter((r) => r !== null) as string[];\n}\n","/* eslint-disable max-lines */\nimport { google } from 'googleapis';\nimport { getAuthClient } from './auth.js';\nimport type { getTRPCClient } from './client.js';\nimport type { ChatMessage } from '../shared/chats.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport type { GoogleChatConfig } from './config.js';\nimport { readGoogleChatState, updateGoogleChatState, getGoogleChatStatePath } from './state.js';\nimport {\n shouldDisplayMessage,\n formatMessage,\n type FilteringConfig,\n} from '../shared/adapters/filtering.js';\nimport { buildPolicyCard, chunkString } from './utils.js';\nimport { uploadFilesToDrive } from './upload.js';\n\nexport async function startDaemonToGoogleChatForwarder(\n trpc: ReturnType<typeof getTRPCClient>,\n config: GoogleChatConfig,\n filteringConfig: FilteringConfig,\n signal?: AbortSignal\n) {\n const defaultChatId = config.chatId || 'default';\n\n const activeSubscriptions = new Map<string, { unsubscribe: () => void }>();\n let currentLastSyncedMessageIds = (await readGoogleChatState()).lastSyncedMessageIds || {};\n\n const saveLastMessageId = async (chatId: string, id: string) => {\n currentLastSyncedMessageIds = { ...currentLastSyncedMessageIds, [chatId]: id };\n return updateGoogleChatState((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-google-chat 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;\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return;\n }\n\n messageQueue = messageQueue\n .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, filteringConfig);\n\n if (isDisplayed) {\n const logMessage = message;\n\n const currentState = await readGoogleChatState();\n let activeSpaceName: string | undefined;\n\n if (!activeSpaceName && currentState.channelChatMap) {\n const entry = Object.entries(currentState.channelChatMap).find(\n ([_, mapChatId]) => mapChatId?.chatId === chatId\n );\n if (entry) {\n activeSpaceName = entry[0];\n }\n }\n\n // We no longer fallback to config.directMessageName. If it's not mapped, we'll drop it below.\n\n const isPolicyRequest =\n logMessage.role === 'policy' && logMessage.status === 'pending';\n\n if (isPolicyRequest) {\n if (!activeSpaceName) {\n console.warn(\n 'No active Google Chat space to reply to. Ignoring policy request:',\n logMessage.content\n );\n await saveLastMessageId(chatId, logMessage.id).catch(console.error);\n lastMessageId = logMessage.id;\n continue;\n }\n\n try {\n const client = await getAuthClient();\n const chatApi = google.chat({ version: 'v1', auth: client });\n\n try {\n await chatApi.spaces.messages.create({\n parent: activeSpaceName as string,\n requestBody: {\n text: '',\n cardsV2: buildPolicyCard(logMessage),\n },\n });\n } catch (richError) {\n console.warn(\n 'Failed to send rich policy request to Google Chat, falling back to plain text:',\n richError\n );\n const policyId =\n ('requestId' in logMessage && logMessage.requestId) || logMessage.id;\n await chatApi.spaces.messages.create({\n parent: activeSpaceName as string,\n requestBody: {\n 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>\\``,\n },\n });\n }\n } catch (error) {\n console.error('Failed to send policy request to Google Chat:', error);\n }\n\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 =\n 'files' in logMessage ? (logMessage.files as string[]) : undefined;\n const hasFiles = Array.isArray(files) && files.length > 0;\n\n if (\n ('level' in logMessage && logMessage.level === 'verbose') ||\n (!hasContent && !hasFiles)\n ) {\n await saveLastMessageId(chatId, logMessage.id).catch(console.error);\n lastMessageId = logMessage.id;\n continue;\n }\n\n if (!activeSpaceName) {\n console.warn(\n 'No active Google Chat space to reply to. Ignoring message:',\n logMessage.content\n );\n await saveLastMessageId(chatId, logMessage.id).catch(console.error);\n lastMessageId = logMessage.id;\n continue;\n }\n\n try {\n const client = await getAuthClient();\n const chatApi = google.chat({ version: 'v1', auth: client });\n\n let text = formatMessage(logMessage) || '';\n\n if (hasFiles && files) {\n const fileNames = files.map((f) => path.basename(f)).join(', ');\n\n if (\n config.driveUploadEnabled !== false &&\n config.oauthClientId &&\n config.oauthClientSecret\n ) {\n text += `\\n\\n`;\n try {\n const uploadResults = await uploadFilesToDrive(files, config);\n for (const result of uploadResults) {\n text += `${result}\\n`;\n }\n } catch (driveAuthErr) {\n console.error(\n 'Drive API/Auth Failed, degrading to local files output:',\n driveAuthErr\n );\n text += `*(Files generated: ${fileNames})*`;\n }\n } else {\n text += `\\n\\n*(Files generated: ${fileNames})*`;\n }\n }\n\n if (text.length > 4000) {\n const chunks = chunkString(text, 4000);\n for (let i = 0; i < chunks.length; i++) {\n if (signal?.aborted || !activeSubscriptions.has(chatId)) break;\n await chatApi.spaces.messages.create({\n parent: activeSpaceName as string,\n requestBody: { text: chunks[i] as string },\n });\n }\n } else {\n await chatApi.spaces.messages.create({\n parent: activeSpaceName as string,\n requestBody: { text },\n });\n }\n } catch (error) {\n console.error('Failed to send message to Google Chat:', error);\n }\n }\n\n await saveLastMessageId(chatId, message.id).catch(console.error);\n lastMessageId = message.id;\n }\n })\n .catch((error) => {\n console.error('Message queue failed, forcing reconnect...', error);\n subscription?.unsubscribe();\n subscription = null;\n if (signal?.aborted || !activeSubscriptions.has(chatId)) {\n return;\n }\n setTimeout(() => {\n retryDelay = Math.min(retryDelay * 2, maxRetryDelay);\n connect();\n }, retryDelay);\n });\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-google-chat 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 activeSubscriptions.set(chatId, {\n unsubscribe: () => subscription?.unsubscribe(),\n });\n\n connect();\n };\n\n const syncSubscriptions = async () => {\n if (signal?.aborted) return;\n const state = await readGoogleChatState();\n\n // Update local copy of last message IDs\n if (state.lastSyncedMessageIds) {\n currentLastSyncedMessageIds = {\n ...state.lastSyncedMessageIds,\n ...currentLastSyncedMessageIds,\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 for (const targetChatId of targetChatIds) {\n if (!activeSubscriptions.has(targetChatId)) {\n startSubscriptionForChat(targetChatId);\n }\n }\n\n for (const [activeChatId, sub] of activeSubscriptions.entries()) {\n if (!targetChatIds.has(activeChatId)) {\n sub.unsubscribe();\n activeSubscriptions.delete(activeChatId);\n }\n }\n };\n return new Promise<void>((resolve) => {\n syncSubscriptions().catch(console.error);\n\n const statePath = getGoogleChatStatePath();\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, filename) => {\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 resolve();\n });\n });\n}\n","import { readGoogleChatState, updateGoogleChatState } from './state.js';\nimport { getUserAuthClient } from './auth.js';\nimport type { GoogleChatConfig } from './config.js';\n\nexport function startSubscriptionRenewalCron(config: GoogleChatConfig): NodeJS.Timeout {\n // Run every hour\n return setInterval(\n async () => {\n try {\n await renewExpiringSubscriptions(config);\n } catch (err) {\n console.error('Error in subscription renewal cron:', err);\n }\n },\n 1000 * 60 * 60\n );\n}\n\nexport async function renewExpiringSubscriptions(config: GoogleChatConfig): Promise<void> {\n const state = await readGoogleChatState();\n if (!state.channelChatMap) return;\n\n const now = Date.now();\n const FORTY_EIGHT_HOURS_MS = 48 * 60 * 60 * 1000;\n\n for (const [externalContextId, entry] of Object.entries(state.channelChatMap)) {\n if (entry.subscriptionId && entry.expirationDate) {\n const expirationTime = new Date(entry.expirationDate).getTime();\n const timeUntilExpiration = expirationTime - now;\n\n if (timeUntilExpiration < FORTY_EIGHT_HOURS_MS) {\n console.log(\n `Renewing expiring subscription ${entry.subscriptionId} for space ${externalContextId}`\n );\n try {\n const userAuthClient = await getUserAuthClient(config);\n const tokenResponse = await userAuthClient.getAccessToken();\n const token = tokenResponse.token;\n\n if (token) {\n const res = await fetch(\n `https://workspaceevents.googleapis.com/v1/${entry.subscriptionId}?updateMask=ttl`,\n {\n method: 'PATCH',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n ttl: '604800s', // 7 days\n }),\n }\n );\n\n if (res.ok) {\n const subData = (await res.json()) as { expireTime: string };\n await updateGoogleChatState((latestState) => {\n const currentMap = latestState.channelChatMap || {};\n return {\n channelChatMap: {\n ...currentMap,\n [externalContextId]: {\n ...(currentMap[externalContextId] || {}),\n expirationDate: subData.expireTime,\n },\n },\n };\n });\n console.log(`Successfully renewed subscription ${entry.subscriptionId}`);\n } else {\n const errText = await res.text();\n console.error(`Failed to renew subscription ${entry.subscriptionId}:`, errText);\n }\n }\n } catch (err) {\n console.error(`Error renewing subscription ${entry.subscriptionId}:`, err);\n }\n }\n }\n }\n}\n","#!/usr/bin/env node\n\nimport { initGoogleChatConfig, readGoogleChatConfig } from './config.js';\nimport { readGoogleChatState } from './state.js';\nimport { getTRPCClient, startGoogleChatIngestion } from './client.js';\nimport { startDaemonToGoogleChatForwarder } from './forwarder.js';\nimport { getUserAuthClient } from './auth.js';\nimport { startSubscriptionRenewalCron } from './cron.js';\nimport type { FilteringConfig } from '../shared/adapters/filtering.js';\n\nexport async function main() {\n const args = process.argv.slice(2);\n\n if (args[0] === 'init') {\n await initGoogleChatConfig();\n return;\n }\n\n console.log('Google Chat Adapter starting...');\n\n const config = await readGoogleChatConfig();\n if (!config) {\n console.error(\n 'Failed to load Google Chat configuration. Please ensure .clawmini/adapters/google-chat/config.json exists and is valid.'\n );\n process.exit(1);\n }\n\n if (config.oauthClientId && config.oauthClientSecret) {\n try {\n console.log('Initializing Google User Authentication...');\n await getUserAuthClient(config);\n } catch (err) {\n console.error('Failed to initialize Google User authentication:', err);\n process.exit(1);\n }\n }\n\n const trpc = getTRPCClient();\n const state = await readGoogleChatState();\n const filteringConfig: FilteringConfig = { filters: state.filters };\n\n // Start ingestion from Pub/Sub\n startGoogleChatIngestion(config, trpc, filteringConfig);\n console.log(`Listening to Pub/Sub subscription: ${config.subscriptionName}`);\n\n // Start forwarding from daemon to Google Chat API\n startDaemonToGoogleChatForwarder(trpc, config, filteringConfig).catch((error) => {\n console.error('Error in daemon-to-google-chat forwarder:', error);\n });\n\n // Start background cron for renewing Space Subscriptions\n startSubscriptionRenewalCron(config);\n}\n\nif (process.env.NODE_ENV !== 'test') {\n main().catch((error) => {\n console.error('Unhandled error in Google Chat Adapter:', error);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { a as
|
|
2
|
+
import { D as pathIsInsideDir, E as writeSettings, T as writeChatSettings, a as enableEnvironment, c as getClawminiDir, d as getSocketPath, g as readChatSettings, i as deleteAgent, m as listAgents, n as copyAgentSkill, p as isValidAgentId, r as copyAgentSkills, s as getAgent, t as applyTemplateToAgent, w as writeAgentSettings, x as resolveSkillsTemplatePath, y as readSettings } from "../workspace-BJmJBfKi.mjs";
|
|
3
|
+
import { a as writeLiteScript, c as createChat, d as getChatsDir, f as getDefaultChatId, g as setDefaultChatId, h as listChats, i as resolveCompiledScript, l as deleteChat, m as isValidChatId, o as DEFAULT_CHAT_ID, p as getMessages, r as getLiteScriptContent, t as exportLiteToAllEnvironments } from "../lite-CBxOT1y5.mjs";
|
|
4
4
|
import { t as createUnixSocketFetch } from "../fetch-Cn1XNyiO.mjs";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import fs from "node:fs";
|
|
@@ -11,11 +11,18 @@ import { fileURLToPath } from "node:url";
|
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import { createTRPCClient, httpLink } from "@trpc/client";
|
|
13
13
|
import http from "node:http";
|
|
14
|
+
import { promises } from "fs";
|
|
14
15
|
|
|
15
16
|
//#region src/shared/agent-utils.ts
|
|
16
17
|
async function createAgentWithChat(agentId, agentData, template, startDir = process.cwd()) {
|
|
17
18
|
await writeAgentSettings(agentId, agentData, startDir);
|
|
18
19
|
if (template) await applyTemplateToAgent(agentId, template, agentData, startDir);
|
|
20
|
+
try {
|
|
21
|
+
await copyAgentSkills(agentId, startDir);
|
|
22
|
+
console.log(`Copied skills to agent ${agentId}.`);
|
|
23
|
+
} catch (err) {
|
|
24
|
+
console.warn(`Warning: Failed to copy skills to agent ${agentId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
25
|
+
}
|
|
19
26
|
if ((await listChats(startDir)).includes(agentId)) console.warn(`Warning: Chat ${agentId} already exists.`);
|
|
20
27
|
else {
|
|
21
28
|
await createChat(agentId, startDir);
|
|
@@ -50,13 +57,6 @@ const initCmd = new Command("init").description("Initialize a new .clawmini sett
|
|
|
50
57
|
commands: { new: "echo $CLAW_CLI_MESSAGE" },
|
|
51
58
|
env: {}
|
|
52
59
|
},
|
|
53
|
-
routers: [
|
|
54
|
-
"@clawmini/slash-new",
|
|
55
|
-
"@clawmini/slash-stop",
|
|
56
|
-
"@clawmini/slash-interrupt",
|
|
57
|
-
"@clawmini/slash-policies",
|
|
58
|
-
"@clawmini/slash-command"
|
|
59
|
-
],
|
|
60
60
|
api: true
|
|
61
61
|
};
|
|
62
62
|
if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true });
|
|
@@ -156,11 +156,16 @@ messagesCmd.command("send <message>").description("Send a new message").option("
|
|
|
156
156
|
});
|
|
157
157
|
messagesCmd.command("tail").description("View message history").option("-n, --lines <number>", "Number of messages to show", parseInt).option("--json", "Output raw JSONL format").option("-c, --chat <id>", "Specific chat to view").action(async (options) => {
|
|
158
158
|
try {
|
|
159
|
-
const messages = await getMessages(options.chat ?? await getDefaultChatId(), options.lines);
|
|
159
|
+
const messages = await getMessages(options.chat ?? await getDefaultChatId(), options.lines, void 0, (msg) => !msg.subagentId);
|
|
160
160
|
if (options.json) messages.forEach((msg) => console.log(JSON.stringify(msg)));
|
|
161
161
|
else messages.forEach((msg) => {
|
|
162
|
-
if (msg.role === "user") console.log(`[USER] ${msg.content}`);
|
|
163
|
-
else if (msg.role === "
|
|
162
|
+
if (msg.role === "user" || msg.displayRole === "user") console.log(`[USER] ${msg.content}`);
|
|
163
|
+
else if (msg.role === "agent" || msg.displayRole === "agent") console.log(`[AGENT] ${msg.content.trim()}`);
|
|
164
|
+
else if (msg.role === "policy") console.log(`[POLICY] ${msg.commandName} ${msg.args.join(" ")}`);
|
|
165
|
+
else if (msg.role === "tool") console.log(`[TOOL] ${msg.name}`);
|
|
166
|
+
else if (msg.role === "system") {
|
|
167
|
+
if (msg.content) console.log(`[LOG] ${msg.content.trim()}`);
|
|
168
|
+
} else if (msg.role === "command" || msg.role === "legacy_log") {
|
|
164
169
|
if (msg.content) console.log(`[LOG] ${msg.content.trim()}`);
|
|
165
170
|
else if (msg.stderr) console.error(`[STDERR] ${msg.stderr.trim()}`);
|
|
166
171
|
}
|
|
@@ -490,8 +495,12 @@ async function handleApiChats(req, res, urlPath) {
|
|
|
490
495
|
if (req.method === "GET" && chatMatch && chatMatch[1]) {
|
|
491
496
|
const chatId = chatMatch[1];
|
|
492
497
|
try {
|
|
493
|
-
const
|
|
494
|
-
|
|
498
|
+
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
499
|
+
const since = url.searchParams.get("since");
|
|
500
|
+
const before = url.searchParams.get("before");
|
|
501
|
+
const limitParam = url.searchParams.get("limit");
|
|
502
|
+
const parsedLimit = limitParam ? parseInt(limitParam, 10) : void 0;
|
|
503
|
+
let messages = await getMessages(chatId, Number.isNaN(parsedLimit) ? void 0 : parsedLimit, void 0, void 0, before || void 0);
|
|
495
504
|
if (since) {
|
|
496
505
|
const sinceIndex = messages.findIndex((m) => m.id === since);
|
|
497
506
|
if (sinceIndex !== -1) messages = messages.slice(sinceIndex + 1);
|
|
@@ -831,6 +840,88 @@ environmentsCmd.command("disable").description("Disable an environment mapping")
|
|
|
831
840
|
}
|
|
832
841
|
});
|
|
833
842
|
|
|
843
|
+
//#endregion
|
|
844
|
+
//#region src/cli/commands/policies.ts
|
|
845
|
+
const SUPPORTED_POLICIES = ["propose-policy"];
|
|
846
|
+
const policiesCmd = new Command("policies").description("Manage sandbox policies");
|
|
847
|
+
policiesCmd.command("add <name>").description("Add a new policy").action(async (name) => {
|
|
848
|
+
if (!SUPPORTED_POLICIES.includes(name)) handleError$1("add policy", /* @__PURE__ */ new Error(`Unsupported policy: "${name}". Supported policies: ${SUPPORTED_POLICIES.join(", ")}`));
|
|
849
|
+
const dirPath = getClawminiDir();
|
|
850
|
+
const policyScriptsDir = path.join(dirPath, "policy-scripts");
|
|
851
|
+
const policiesPath = path.join(dirPath, "policies.json");
|
|
852
|
+
if (!fs.existsSync(dirPath)) handleError$1("add policy", /* @__PURE__ */ new Error(".clawmini directory not found. Please run \"clawmini init\" first."));
|
|
853
|
+
if (!fs.existsSync(policyScriptsDir)) fs.mkdirSync(policyScriptsDir, { recursive: true });
|
|
854
|
+
let policies = { policies: {} };
|
|
855
|
+
if (fs.existsSync(policiesPath)) policies = JSON.parse(fs.readFileSync(policiesPath, "utf8"));
|
|
856
|
+
policies.policies[name] = {
|
|
857
|
+
description: "Propose a new policy to create",
|
|
858
|
+
command: `./.clawmini/policy-scripts/${name}.js`,
|
|
859
|
+
allowHelp: true
|
|
860
|
+
};
|
|
861
|
+
fs.writeFileSync(policiesPath, JSON.stringify(policies, null, 2));
|
|
862
|
+
console.log(`Registered ${name} in .clawmini/policies.json`);
|
|
863
|
+
try {
|
|
864
|
+
const foundPath = await resolveCompiledScript(name, import.meta.url);
|
|
865
|
+
let scriptContent = fs.readFileSync(foundPath, "utf8");
|
|
866
|
+
if (!scriptContent.startsWith("#!")) scriptContent = "#!/usr/bin/env node\n" + scriptContent;
|
|
867
|
+
const destPath = path.join(policyScriptsDir, `${name}.js`);
|
|
868
|
+
fs.writeFileSync(destPath, scriptContent, { mode: 493 });
|
|
869
|
+
console.log(`Copied ${name} script to ${destPath}`);
|
|
870
|
+
} catch (err) {
|
|
871
|
+
handleError$1("add policy", err);
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
//#endregion
|
|
876
|
+
//#region src/cli/commands/skills.ts
|
|
877
|
+
const skillsCmd = new Command("skills").description("Manage template skills");
|
|
878
|
+
skillsCmd.command("list").description("List available template skills").action(async () => {
|
|
879
|
+
try {
|
|
880
|
+
let skillsDir;
|
|
881
|
+
try {
|
|
882
|
+
skillsDir = await resolveSkillsTemplatePath();
|
|
883
|
+
} catch (err) {
|
|
884
|
+
if (err instanceof Error && err.message.includes("Template not found: skills")) {
|
|
885
|
+
console.error("No skills found. The templates/skills directory does not exist.");
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
throw err;
|
|
889
|
+
}
|
|
890
|
+
let entries;
|
|
891
|
+
try {
|
|
892
|
+
entries = await promises.readdir(skillsDir, { withFileTypes: true });
|
|
893
|
+
} catch (err) {
|
|
894
|
+
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
895
|
+
console.error("No skills found.");
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
throw err;
|
|
899
|
+
}
|
|
900
|
+
const skills = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
901
|
+
if (skills.length === 0) {
|
|
902
|
+
console.error("No skills found.");
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
for (const skill of skills) console.log(`- ${skill}`);
|
|
906
|
+
} catch (err) {
|
|
907
|
+
handleError$1("list skills", err);
|
|
908
|
+
}
|
|
909
|
+
});
|
|
910
|
+
skillsCmd.command("add [skill-name]").description("Add a skill to an agent, overwriting the target skill directory if it exists").option("-a, --agent <agentId>", "Agent ID (defaults to \"default\")").action(async (skillName, options) => {
|
|
911
|
+
try {
|
|
912
|
+
const agentId = options.agent || "default";
|
|
913
|
+
if (skillName) {
|
|
914
|
+
await copyAgentSkill(agentId, skillName, process.cwd(), true);
|
|
915
|
+
console.log(`Successfully added skill '${skillName}' to agent '${agentId}'.`);
|
|
916
|
+
} else {
|
|
917
|
+
await copyAgentSkills(agentId, process.cwd(), true);
|
|
918
|
+
console.log(`Successfully added all skills to agent '${agentId}'.`);
|
|
919
|
+
}
|
|
920
|
+
} catch (err) {
|
|
921
|
+
handleError$1("add skill", err);
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
|
|
834
925
|
//#endregion
|
|
835
926
|
//#region src/cli/index.ts
|
|
836
927
|
const program = new Command();
|
|
@@ -840,11 +931,13 @@ program.addCommand(messagesCmd);
|
|
|
840
931
|
program.addCommand(chatsCmd);
|
|
841
932
|
program.addCommand(agentsCmd);
|
|
842
933
|
program.addCommand(environmentsCmd);
|
|
934
|
+
program.addCommand(skillsCmd);
|
|
843
935
|
program.addCommand(downCmd);
|
|
844
936
|
program.addCommand(upCmd);
|
|
845
937
|
program.addCommand(webCmd);
|
|
846
938
|
program.addCommand(jobsCmd);
|
|
847
939
|
program.addCommand(exportLiteCmd);
|
|
940
|
+
program.addCommand(policiesCmd);
|
|
848
941
|
program.parse();
|
|
849
942
|
|
|
850
943
|
//#endregion
|