@fased/fased 0.1.36 → 0.1.37

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 (244) hide show
  1. package/config/capability-catalog.json +241 -0
  2. package/config/dependency-ownership.json +130 -0
  3. package/config/official-channel-catalog.json +39 -0
  4. package/dist/agents/tools/web-fetch-utils.js +2 -1
  5. package/dist/agents/tools/web-fetch-visibility.js +3 -1
  6. package/dist/brand.js +1 -1
  7. package/dist/browser/pw-session.js +2 -1
  8. package/dist/browser/pw-tools-core.state.js +3 -2
  9. package/dist/browser/runtime-dependency.js +27 -0
  10. package/dist/build-info.json +3 -3
  11. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  12. package/dist/capabilities/catalog.js +228 -0
  13. package/dist/cli/components-cli.js +105 -0
  14. package/dist/cli/hooks-cli.js +1 -1
  15. package/dist/cli/plugins-cli.js +3 -3
  16. package/dist/cli/program/register.subclis.js +9 -0
  17. package/dist/cli/update-cli/update-command.js +1 -1
  18. package/dist/commands/doctor-capabilities.js +26 -0
  19. package/dist/commands/doctor.js +2 -0
  20. package/dist/control-ui/assets/{app-DXYMrRJ9.js → app-JBrTSsNu.js} +1480 -1465
  21. package/dist/control-ui/assets/{index-iGQkJE0l.js → index-H-2DWAnH.js} +3 -3
  22. package/dist/control-ui/index.html +1 -1
  23. package/dist/gateway/method-scopes.js +1 -0
  24. package/dist/gateway/server-methods/plugins-marketplace.js +1 -1
  25. package/dist/gateway/server-methods/services.js +8 -0
  26. package/dist/gateway/server-methods-list.js +1 -0
  27. package/dist/infra/optional-runtime-dependency.js +46 -0
  28. package/dist/media/image-ops.js +6 -1
  29. package/dist/media/input-files.js +11 -2
  30. package/dist/media/mime.js +6 -1
  31. package/dist/memory/sqlite-vec.js +7 -1
  32. package/dist/plugin-sdk/{accounts-VqAX3HJ0.js → accounts-BwkH5bTD.js} +1 -1
  33. package/dist/plugin-sdk/{accounts-COY-15zJ.js → accounts-C5BjfxoO.js} +1 -1
  34. package/dist/plugin-sdk/{accounts-Zgt0NP54.js → accounts-RT6y7n3H.js} +1 -1
  35. package/dist/plugin-sdk/{actions-lB3PCwsz.js → actions-BrU_JMqM.js} +2 -2
  36. package/dist/plugin-sdk/{actions-BI5QViLk.js → actions-CUdVHzeJ.js} +2 -2
  37. package/dist/plugin-sdk/{active-listener-DKZiSaRA.js → active-listener-CE8t5g6l.js} +1 -1
  38. package/dist/plugin-sdk/{active-listener-D6_pdTMC.js → active-listener-Dx1SEGDn.js} +1 -1
  39. package/dist/plugin-sdk/{audio-preflight-Dx8J7XhV.js → audio-preflight-C8SbY4fV.js} +22 -22
  40. package/dist/plugin-sdk/{audio-preflight-CeRstduc.js → audio-preflight-CuABlLDL.js} +22 -22
  41. package/dist/plugin-sdk/{audit-BImNOQvk.js → audit-DxB2Kml5.js} +11 -11
  42. package/dist/plugin-sdk/{audit-CKWkq0Un.js → audit-sSeRDwJb.js} +11 -11
  43. package/dist/plugin-sdk/channel-plugin-common.js +3 -2
  44. package/dist/plugin-sdk/{chunk-skAJZWCT.js → chunk-KCxbJLsV.js} +1 -1
  45. package/dist/plugin-sdk/{chunk-Cjw4712g.js → chunk-M2d7r-Zt.js} +1 -1
  46. package/dist/plugin-sdk/{chunk-items-Df5811D0.js → chunk-items-BGbYyNvO.js} +1 -1
  47. package/dist/plugin-sdk/command-status.js +22 -22
  48. package/dist/plugin-sdk/{commands-registry-5J619bQ2.js → commands-registry-CdT-nl7v.js} +2 -2
  49. package/dist/plugin-sdk/{commands-registry-CoLAT03J.js → commands-registry-DoWdYAJd.js} +2 -2
  50. package/dist/plugin-sdk/{common-CSTxewqY.js → common-Cpw-vuuM.js} +1 -1
  51. package/dist/plugin-sdk/{common-BiF0sTnY.js → common-DJWrErdE.js} +1 -1
  52. package/dist/plugin-sdk/{config-BxVjLTIv.js → config-C0qggNKQ.js} +7 -7
  53. package/dist/plugin-sdk/{config-TFokWwvO.js → config-CgwTaper.js} +45 -2
  54. package/dist/plugin-sdk/{config-DXlISPlx.js → config-DtqAN2L3.js} +45 -2
  55. package/dist/plugin-sdk/{config-DgD5T-Ui.js → config-g1MG9Bet.js} +7 -7
  56. package/dist/plugin-sdk/discord.js +2 -1
  57. package/dist/plugin-sdk/{fetch-guard-DPMynms8.js → fetch-guard-BLdujDnt.js} +1 -1
  58. package/dist/plugin-sdk/{fetch-guard-COLmW2TM.js → fetch-guard-DTKgMN9f.js} +1 -1
  59. package/dist/plugin-sdk/{handle-action-C-UndB8E.js → handle-action-B61D85yo.js} +12 -12
  60. package/dist/plugin-sdk/{handle-action-hhufKxmU.js → handle-action-CjcxGzQD.js} +12 -12
  61. package/dist/plugin-sdk/index.js +22 -22
  62. package/dist/plugin-sdk/{login-DL1oBBfL.js → login-CB_nCjX3.js} +3 -3
  63. package/dist/plugin-sdk/{login-YveoqEvH.js → login-CfRfRNc7.js} +2 -2
  64. package/dist/plugin-sdk/{login-Dnxas1dI.js → login-CzUuDd1v.js} +3 -3
  65. package/dist/plugin-sdk/{login-qr-CVQsGWKq.js → login-qr-D7MEpFza.js} +3 -3
  66. package/dist/plugin-sdk/{login-qr-B343JNXJ.js → login-qr-DgxfBFVN.js} +3 -3
  67. package/dist/plugin-sdk/{manager-BytwRIfK.js → manager-9see0IX5.js} +8 -3
  68. package/dist/plugin-sdk/{manager-BZjd_PCt.js → manager-D2kZ0Cps.js} +8 -3
  69. package/dist/plugin-sdk/{markdown-tables-krKiU4cT.js → markdown-tables-CCSD52rA.js} +1 -1
  70. package/dist/plugin-sdk/{markdown-tables-9rJDQ1X-.js → markdown-tables-DWUNvLrc.js} +1 -1
  71. package/dist/plugin-sdk/{media-D7ZkWU-A.js → media-C7YT4DeU.js} +13 -4
  72. package/dist/plugin-sdk/{media-C6C2c9a4.js → media-Cxw-xLGU.js} +13 -4
  73. package/dist/plugin-sdk/{monitor-CVQNDfhs.js → monitor-9X7wapUN.js} +27 -27
  74. package/dist/plugin-sdk/{monitor-BCxkQBoh.js → monitor-B3IfJzKX.js} +26 -26
  75. package/dist/plugin-sdk/{monitor-BzDW50H6.js → monitor-CTjAST_W.js} +27 -27
  76. package/dist/plugin-sdk/{monitor-BsLMfn3U.js → monitor-tYFfy2u-.js} +26 -26
  77. package/dist/plugin-sdk/{openresponses-http-BB67Z4QM.js → openresponses-http-DEB2fEya.js} +22 -22
  78. package/dist/plugin-sdk/{openresponses-http-NE76GGhj.js → openresponses-http-YgMg1jnp.js} +22 -22
  79. package/dist/plugin-sdk/{ssrf-u0Ul7okY.js → optional-runtime-dependency-szS49voX.js} +46 -2
  80. package/dist/plugin-sdk/{outbound-PGNWU6T-.js → outbound-BCxOxdi-.js} +6 -6
  81. package/dist/plugin-sdk/{outbound-BHWJD9q0.js → outbound-JIwQbpRY.js} +6 -6
  82. package/dist/plugin-sdk/{outbound-attachment-BVzfhqnk.js → outbound-attachment-C-jSFaEB.js} +1 -1
  83. package/dist/plugin-sdk/{outbound-attachment-ClMvNW17.js → outbound-attachment-D6tj5Y5H.js} +1 -1
  84. package/dist/plugin-sdk/{pi-embedded-runner-DQ6UPx6-.js → pi-embedded-runner-CUVk8CIj.js} +72 -60
  85. package/dist/plugin-sdk/{pi-model-discovery-D51L5E9I.js → pi-model-discovery-DadlvsZW.js} +1 -1
  86. package/dist/plugin-sdk/{pi-model-discovery-runtime-DxoFm4Vd.js → pi-model-discovery-runtime-C5ssE6EW.js} +1 -1
  87. package/dist/plugin-sdk/{pi-model-discovery-runtime-DRuh4PNV.js → pi-model-discovery-runtime-DAaOPt64.js} +2 -2
  88. package/dist/plugin-sdk/{pi-model-discovery-runtime-CQOauapl.js → pi-model-discovery-runtime-LB-5lX5L.js} +1 -1
  89. package/dist/plugin-sdk/{pi-model-discovery-runtime-BTWgkx4x.js → pi-model-discovery-runtime-gd77b0UF.js} +2 -2
  90. package/dist/plugin-sdk/{pi-model-discovery-CkH5l9X5.js → pi-model-discovery-yifTIDIn.js} +1 -1
  91. package/dist/plugin-sdk/{pw-ai-DZs6uYRd.js → pw-ai-SNCI9UXT.js} +6 -5
  92. package/dist/plugin-sdk/{pw-ai-Cn-EUPZK.js → pw-ai-sH1Pi-Fh.js} +6 -5
  93. package/dist/plugin-sdk/{registry-B4HvWzob.js → registry-DNkJsNsz.js} +4 -3
  94. package/dist/plugin-sdk/{replies-jDMUBsNO.js → replies-fvzN5wnU.js} +2 -2
  95. package/dist/plugin-sdk/{replies-B_LW9c9f.js → replies-zebgZCHX.js} +2 -2
  96. package/dist/plugin-sdk/{resolve-route-_YZHbS-z.js → resolve-route-CNhTJG_2.js} +1 -1
  97. package/dist/plugin-sdk/{resolve-route-DlHzggnG.js → resolve-route-DO0WR4nB.js} +1 -1
  98. package/dist/plugin-sdk/{resolve-utils-zBhVX3Vx.js → resolve-utils-EFP1DYqG.js} +1 -1
  99. package/dist/plugin-sdk/{retry-policy-DGLs5ebP.js → retry-policy-BLYEgIwP.js} +1 -1
  100. package/dist/plugin-sdk/{retry-policy-DaodShGa.js → retry-policy-sM01QZT2.js} +1 -1
  101. package/dist/plugin-sdk/{runtime-Dd0sswuW.js → runtime-BPyuAmka.js} +4 -3
  102. package/dist/plugin-sdk/{paths-DW-U2r7Y.js → runtime-dependency-B-1u41Ph.js} +27 -3
  103. package/dist/plugin-sdk/{paths-CBCpJ5bu.js → runtime-dependency-Csswyv5r.js} +27 -3
  104. package/dist/plugin-sdk/sat-runtime.js +1 -0
  105. package/dist/plugin-sdk/{send-8remZhsH.js → send-B09HRfHN.js} +6 -6
  106. package/dist/plugin-sdk/{send-DaaAscWj.js → send-BBYcgXA4.js} +5 -5
  107. package/dist/plugin-sdk/{send-DFTB0cnx.js → send-BQXQA81e.js} +6 -6
  108. package/dist/plugin-sdk/{send-CtMVvMJs.js → send-BzFdvD_i.js} +6 -6
  109. package/dist/plugin-sdk/{send-Di9irjS-.js → send-C3u-F_8s.js} +6 -6
  110. package/dist/plugin-sdk/{send-Dl88ZKq2.js → send-D3836_UN.js} +6 -6
  111. package/dist/plugin-sdk/{send-ifgZCHVB.js → send-D7tr-EsH.js} +5 -5
  112. package/dist/plugin-sdk/{send-DvUpYh0d.js → send-DRGzRdI3.js} +6 -6
  113. package/dist/plugin-sdk/{send-D2jlPeKH.js → send-DfkPKz_0.js} +4 -4
  114. package/dist/plugin-sdk/{send-QSt6nbny.js → send-DsxFXrCO.js} +4 -4
  115. package/dist/plugin-sdk/{session-CknrceVU.js → session-DG_bYisw.js} +2 -2
  116. package/dist/plugin-sdk/{session-CyRTcJ8N.js → session-EIStzK0E.js} +2 -2
  117. package/dist/plugin-sdk/{skill-commands-DHxkTA0s.js → skill-commands-CkgGmWBS.js} +2 -2
  118. package/dist/plugin-sdk/{skill-commands-CLXAG5sU.js → skill-commands-hyZA0LE3.js} +2 -2
  119. package/dist/plugin-sdk/{slack-BpJXkwxF.js → slack-C0WZVJPZ.js} +34 -34
  120. package/dist/plugin-sdk/{slack-Br9c6Yzs.js → slack-DtlPw_PN.js} +34 -34
  121. package/dist/plugin-sdk/{slack-actions-8tLGt1Ht.js → slack-actions-BQawWGTJ.js} +11 -11
  122. package/dist/plugin-sdk/{slack-actions-CDSSRo8Y.js → slack-actions-DDMszx56.js} +11 -11
  123. package/dist/plugin-sdk/slack.js +2 -1
  124. package/dist/plugin-sdk/src/brand.d.ts +2 -2
  125. package/dist/plugin-sdk/src/browser/runtime-dependency.d.ts +3 -0
  126. package/dist/plugin-sdk/src/infra/optional-runtime-dependency.d.ts +6 -0
  127. package/dist/plugin-sdk/{ssrf-fG4UHKBw.js → ssrf-Cce6LubA.js} +41 -7
  128. package/dist/plugin-sdk/{status-DoxnzyMC.js → status-CIiBeb9B.js} +72 -60
  129. package/dist/plugin-sdk/{sticker-cache-zmJ39ByC.js → sticker-cache-9houHChV.js} +3 -3
  130. package/dist/plugin-sdk/{sticker-cache-D7WcMYsF.js → sticker-cache-Dwi-XsgB.js} +3 -3
  131. package/dist/plugin-sdk/{tables-CkxblF0u.js → tables-BD7H5ug-.js} +1 -1
  132. package/dist/plugin-sdk/{tables-RBtf8G4P.js → tables-CJE8kB35.js} +1 -1
  133. package/dist/plugin-sdk/{telegram-actions-DAeYXSLk.js → telegram-actions-Bu1edXF2.js} +25 -25
  134. package/dist/plugin-sdk/{telegram-actions-BDeS3ocd.js → telegram-actions-CRXVO8lG.js} +25 -25
  135. package/dist/plugin-sdk/telegram.js +2 -1
  136. package/dist/plugin-sdk/{thread-bindings.lifecycle-DsB94WbE.js → thread-bindings.lifecycle-Djem8FWF.js} +2 -2
  137. package/dist/plugin-sdk/{thread-bindings.lifecycle-DMhV3TsR.js → thread-bindings.lifecycle-gmHv3hc7.js} +2 -2
  138. package/dist/plugin-sdk/{thread-bindings.state-DYWpy7hJ.js → thread-bindings.state-CNT2vxm3.js} +2 -2
  139. package/dist/plugin-sdk/{thread-bindings.state-DG5cBaRn.js → thread-bindings.state-D8kN2X6H.js} +2 -2
  140. package/dist/plugin-sdk/{web-IJ4NoGPJ.js → web-DCrVQr6y.js} +26 -26
  141. package/dist/plugin-sdk/{web-DJwacWQo.js → web-Ds6OWw3C.js} +26 -26
  142. package/dist/plugin-sdk/{whatsapp-actions-DAY8hWpD.js → whatsapp-actions-68Mfs2dJ.js} +12 -12
  143. package/dist/plugin-sdk/{whatsapp-actions-6opfo-oB.js → whatsapp-actions-DRqtzvTO.js} +12 -12
  144. package/dist/plugin-sdk/whatsapp.js +6 -5
  145. package/dist/plugin-sdk/{wsl-B2euLEc2.js → wsl-DcM2PgSS.js} +3 -3
  146. package/dist/plugin-sdk/{wsl-B8eyviuv.js → wsl-PXrdWitE.js} +3 -3
  147. package/dist/plugins/update.js +1 -1
  148. package/dist/tts/tts-core.js +6 -1
  149. package/dist/wizard/onboarding.finalize.js +9 -0
  150. package/extensions/acpx/package.json +1 -1
  151. package/extensions/bluebubbles/package.json +1 -1
  152. package/extensions/copilot-proxy/package.json +1 -1
  153. package/extensions/diagnostics-otel/package.json +1 -1
  154. package/extensions/fased-federation/package.json +1 -1
  155. package/extensions/google-gemini-cli-auth/package.json +1 -1
  156. package/extensions/imessage/package.json +1 -1
  157. package/extensions/irc/package.json +1 -1
  158. package/extensions/line/package.json +1 -1
  159. package/extensions/llm-task/package.json +1 -1
  160. package/extensions/lobster/package.json +1 -1
  161. package/extensions/matrix/CHANGELOG.md +6 -0
  162. package/extensions/matrix/package.json +1 -1
  163. package/extensions/mattermost/package.json +1 -1
  164. package/extensions/memory-core/package.json +2 -2
  165. package/extensions/memory-lancedb/package.json +1 -1
  166. package/extensions/minimax-portal-auth/package.json +1 -1
  167. package/extensions/msteams/CHANGELOG.md +6 -0
  168. package/extensions/msteams/package.json +1 -1
  169. package/extensions/nextcloud-talk/package.json +1 -1
  170. package/extensions/nostr/CHANGELOG.md +6 -0
  171. package/extensions/nostr/package.json +1 -1
  172. package/extensions/open-prose/package.json +1 -1
  173. package/extensions/sat-mining/package.json +1 -1
  174. package/extensions/signal/package.json +1 -1
  175. package/extensions/synology-chat/package.json +1 -1
  176. package/extensions/tlon/package.json +1 -1
  177. package/extensions/twitch/CHANGELOG.md +6 -0
  178. package/extensions/twitch/package.json +1 -1
  179. package/extensions/voice-call/CHANGELOG.md +6 -0
  180. package/extensions/voice-call/package.json +1 -1
  181. package/extensions/zalo/CHANGELOG.md +6 -0
  182. package/extensions/zalo/package.json +1 -1
  183. package/extensions/zalouser/CHANGELOG.md +6 -0
  184. package/extensions/zalouser/package.json +1 -1
  185. package/package.json +22 -15
  186. package/extensions/feishu/fased.plugin.json +0 -10
  187. package/extensions/feishu/index.ts +0 -63
  188. package/extensions/feishu/package.json +0 -33
  189. package/extensions/feishu/skills/feishu-doc/SKILL.md +0 -211
  190. package/extensions/feishu/skills/feishu-doc/references/block-types.md +0 -103
  191. package/extensions/feishu/skills/feishu-drive/SKILL.md +0 -97
  192. package/extensions/feishu/skills/feishu-perm/SKILL.md +0 -119
  193. package/extensions/feishu/skills/feishu-wiki/SKILL.md +0 -111
  194. package/extensions/feishu/src/accounts.ts +0 -159
  195. package/extensions/feishu/src/bitable.ts +0 -713
  196. package/extensions/feishu/src/bot.ts +0 -979
  197. package/extensions/feishu/src/channel.ts +0 -359
  198. package/extensions/feishu/src/client.ts +0 -118
  199. package/extensions/feishu/src/config-schema.ts +0 -226
  200. package/extensions/feishu/src/dedup.ts +0 -54
  201. package/extensions/feishu/src/directory.ts +0 -177
  202. package/extensions/feishu/src/doc-schema.ts +0 -122
  203. package/extensions/feishu/src/docx.ts +0 -998
  204. package/extensions/feishu/src/drive-schema.ts +0 -46
  205. package/extensions/feishu/src/drive.ts +0 -232
  206. package/extensions/feishu/src/dynamic-agent.ts +0 -131
  207. package/extensions/feishu/src/external-keys.ts +0 -19
  208. package/extensions/feishu/src/media.ts +0 -447
  209. package/extensions/feishu/src/mention.ts +0 -133
  210. package/extensions/feishu/src/monitor.ts +0 -434
  211. package/extensions/feishu/src/onboarding.ts +0 -430
  212. package/extensions/feishu/src/outbound.ts +0 -56
  213. package/extensions/feishu/src/perm-schema.ts +0 -52
  214. package/extensions/feishu/src/perm.ts +0 -180
  215. package/extensions/feishu/src/policy.ts +0 -116
  216. package/extensions/feishu/src/probe.ts +0 -44
  217. package/extensions/feishu/src/reactions.ts +0 -160
  218. package/extensions/feishu/src/reply-dispatcher.ts +0 -239
  219. package/extensions/feishu/src/runtime.ts +0 -14
  220. package/extensions/feishu/src/send-result.ts +0 -29
  221. package/extensions/feishu/src/send-target.ts +0 -25
  222. package/extensions/feishu/src/send.ts +0 -313
  223. package/extensions/feishu/src/streaming-card.ts +0 -218
  224. package/extensions/feishu/src/targets.ts +0 -78
  225. package/extensions/feishu/src/tool-account.ts +0 -58
  226. package/extensions/feishu/src/tools-config.ts +0 -21
  227. package/extensions/feishu/src/types.ts +0 -81
  228. package/extensions/feishu/src/typing.ts +0 -80
  229. package/extensions/feishu/src/wiki-schema.ts +0 -55
  230. package/extensions/feishu/src/wiki.ts +0 -237
  231. package/extensions/googlechat/fased.plugin.json +0 -9
  232. package/extensions/googlechat/index.ts +0 -19
  233. package/extensions/googlechat/package.json +0 -37
  234. package/extensions/googlechat/src/accounts.ts +0 -147
  235. package/extensions/googlechat/src/actions.ts +0 -176
  236. package/extensions/googlechat/src/api.ts +0 -282
  237. package/extensions/googlechat/src/auth.ts +0 -137
  238. package/extensions/googlechat/src/channel.ts +0 -591
  239. package/extensions/googlechat/src/monitor.ts +0 -996
  240. package/extensions/googlechat/src/onboarding.ts +0 -344
  241. package/extensions/googlechat/src/runtime.ts +0 -14
  242. package/extensions/googlechat/src/targets.ts +0 -65
  243. package/extensions/googlechat/src/types.config.ts +0 -3
  244. package/extensions/googlechat/src/types.ts +0 -73
@@ -1,591 +0,0 @@
1
- import {
2
- applyAccountNameToChannelSection,
3
- buildChannelConfigSchema,
4
- DEFAULT_ACCOUNT_ID,
5
- deleteAccountFromConfigSection,
6
- formatPairingApproveHint,
7
- getChatChannelMeta,
8
- migrateBaseNameToDefaultAccount,
9
- missingTargetError,
10
- normalizeAccountId,
11
- PAIRING_APPROVED_MESSAGE,
12
- resolveChannelMediaMaxBytes,
13
- resolveGoogleChatGroupRequireMention,
14
- resolveAllowlistProviderRuntimeGroupPolicy,
15
- resolveDefaultGroupPolicy,
16
- setAccountEnabledInConfigSection,
17
- type ChannelDock,
18
- type ChannelMessageActionAdapter,
19
- type ChannelPlugin,
20
- type ChannelStatusIssue,
21
- type FasedAgentConfig,
22
- } from "fased/plugin-sdk";
23
- import { GoogleChatConfigSchema } from "fased/plugin-sdk";
24
- import {
25
- listGoogleChatAccountIds,
26
- resolveDefaultGoogleChatAccountId,
27
- resolveGoogleChatAccount,
28
- type ResolvedGoogleChatAccount,
29
- } from "./accounts.js";
30
- import { googlechatMessageActions } from "./actions.js";
31
- import { sendGoogleChatMessage, uploadGoogleChatAttachment, probeGoogleChat } from "./api.js";
32
- import { resolveGoogleChatWebhookPath, startGoogleChatMonitor } from "./monitor.js";
33
- import { googlechatOnboardingAdapter } from "./onboarding.js";
34
- import { getGoogleChatRuntime } from "./runtime.js";
35
- import {
36
- isGoogleChatSpaceTarget,
37
- isGoogleChatUserTarget,
38
- normalizeGoogleChatTarget,
39
- resolveGoogleChatOutboundSpace,
40
- } from "./targets.js";
41
-
42
- const meta = getChatChannelMeta("googlechat");
43
-
44
- const isGoogleChatAccountConfigured = (account: ResolvedGoogleChatAccount): boolean =>
45
- account.credentialSource !== "none" &&
46
- Boolean(account.config.webhookPath?.trim() || account.config.webhookUrl?.trim()) &&
47
- Boolean(
48
- (account.config.audienceType === "app-url" ||
49
- account.config.audienceType === "project-number") &&
50
- account.config.audience?.trim(),
51
- );
52
-
53
- const formatAllowFromEntry = (entry: string) =>
54
- entry
55
- .trim()
56
- .replace(/^(googlechat|google-chat|gchat):/i, "")
57
- .replace(/^user:/i, "")
58
- .replace(/^users\//i, "")
59
- .toLowerCase();
60
-
61
- export const googlechatDock: ChannelDock = {
62
- id: "googlechat",
63
- capabilities: {
64
- chatTypes: ["direct", "group", "thread"],
65
- reactions: true,
66
- media: true,
67
- threads: true,
68
- blockStreaming: true,
69
- },
70
- outbound: { textChunkLimit: 4000 },
71
- config: {
72
- resolveAllowFrom: ({ cfg, accountId }) =>
73
- (resolveGoogleChatAccount({ cfg: cfg, accountId }).config.dm?.allowFrom ?? []).map((entry) =>
74
- String(entry),
75
- ),
76
- formatAllowFrom: ({ allowFrom }) =>
77
- allowFrom
78
- .map((entry) => String(entry))
79
- .filter(Boolean)
80
- .map(formatAllowFromEntry),
81
- },
82
- groups: {
83
- resolveRequireMention: resolveGoogleChatGroupRequireMention,
84
- },
85
- threading: {
86
- resolveReplyToMode: ({ cfg }) => cfg.channels?.["googlechat"]?.replyToMode ?? "off",
87
- buildToolContext: ({ context, hasRepliedRef }) => {
88
- const threadId = context.MessageThreadId ?? context.ReplyToId;
89
- return {
90
- currentChannelId: context.To?.trim() || undefined,
91
- currentThreadTs: threadId != null ? String(threadId) : undefined,
92
- hasRepliedRef,
93
- };
94
- },
95
- },
96
- };
97
-
98
- const googlechatActions: ChannelMessageActionAdapter = {
99
- listActions: (ctx) => googlechatMessageActions.listActions?.(ctx) ?? [],
100
- extractToolSend: (ctx) => googlechatMessageActions.extractToolSend?.(ctx) ?? null,
101
- handleAction: async (ctx) => {
102
- if (!googlechatMessageActions.handleAction) {
103
- throw new Error("Google Chat actions are not available.");
104
- }
105
- return await googlechatMessageActions.handleAction(ctx);
106
- },
107
- };
108
-
109
- export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
110
- id: "googlechat",
111
- meta: { ...meta },
112
- onboarding: googlechatOnboardingAdapter,
113
- pairing: {
114
- idLabel: "googlechatUserId",
115
- normalizeAllowEntry: (entry) => formatAllowFromEntry(entry),
116
- notifyApproval: async ({ cfg, id }) => {
117
- const account = resolveGoogleChatAccount({ cfg: cfg });
118
- if (account.credentialSource === "none") {
119
- return;
120
- }
121
- const user = normalizeGoogleChatTarget(id) ?? id;
122
- const target = isGoogleChatUserTarget(user) ? user : `users/${user}`;
123
- const space = await resolveGoogleChatOutboundSpace({ account, target });
124
- await sendGoogleChatMessage({
125
- account,
126
- space,
127
- text: PAIRING_APPROVED_MESSAGE,
128
- });
129
- },
130
- },
131
- capabilities: {
132
- chatTypes: ["direct", "group", "thread"],
133
- reactions: true,
134
- threads: true,
135
- media: true,
136
- nativeCommands: false,
137
- blockStreaming: true,
138
- },
139
- streaming: {
140
- blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
141
- },
142
- reload: { configPrefixes: ["channels.googlechat"] },
143
- configSchema: buildChannelConfigSchema(GoogleChatConfigSchema),
144
- config: {
145
- listAccountIds: (cfg) => listGoogleChatAccountIds(cfg),
146
- resolveAccount: (cfg, accountId) => resolveGoogleChatAccount({ cfg: cfg, accountId }),
147
- defaultAccountId: (cfg) => resolveDefaultGoogleChatAccountId(cfg),
148
- setAccountEnabled: ({ cfg, accountId, enabled }) =>
149
- setAccountEnabledInConfigSection({
150
- cfg: cfg,
151
- sectionKey: "googlechat",
152
- accountId,
153
- enabled,
154
- allowTopLevel: true,
155
- }),
156
- deleteAccount: ({ cfg, accountId }) =>
157
- deleteAccountFromConfigSection({
158
- cfg: cfg,
159
- sectionKey: "googlechat",
160
- accountId,
161
- clearBaseFields: [
162
- "serviceAccount",
163
- "serviceAccountFile",
164
- "audienceType",
165
- "audience",
166
- "webhookPath",
167
- "webhookUrl",
168
- "botUser",
169
- "name",
170
- ],
171
- }),
172
- isConfigured: (account) => isGoogleChatAccountConfigured(account),
173
- describeAccount: (account) => ({
174
- accountId: account.accountId,
175
- name: account.name,
176
- enabled: account.enabled,
177
- configured: isGoogleChatAccountConfigured(account),
178
- credentialSource: account.credentialSource,
179
- }),
180
- resolveAllowFrom: ({ cfg, accountId }) =>
181
- (
182
- resolveGoogleChatAccount({
183
- cfg: cfg,
184
- accountId,
185
- }).config.dm?.allowFrom ?? []
186
- ).map((entry) => String(entry)),
187
- formatAllowFrom: ({ allowFrom }) =>
188
- allowFrom
189
- .map((entry) => String(entry))
190
- .filter(Boolean)
191
- .map(formatAllowFromEntry),
192
- resolveDefaultTo: ({ cfg, accountId }) =>
193
- resolveGoogleChatAccount({ cfg, accountId }).config.defaultTo?.trim() || undefined,
194
- },
195
- security: {
196
- resolveDmPolicy: ({ cfg, accountId, account }) => {
197
- const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;
198
- const useAccountPath = Boolean(cfg.channels?.["googlechat"]?.accounts?.[resolvedAccountId]);
199
- const allowFromPath = useAccountPath
200
- ? `channels.googlechat.accounts.${resolvedAccountId}.dm.`
201
- : "channels.googlechat.dm.";
202
- return {
203
- policy: account.config.dm?.policy ?? "pairing",
204
- allowFrom: account.config.dm?.allowFrom ?? [],
205
- allowFromPath,
206
- approveHint: formatPairingApproveHint("googlechat"),
207
- normalizeEntry: (raw) => formatAllowFromEntry(raw),
208
- };
209
- },
210
- collectWarnings: ({ account, cfg }) => {
211
- const warnings: string[] = [];
212
- const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
213
- const { groupPolicy } = resolveAllowlistProviderRuntimeGroupPolicy({
214
- providerConfigPresent: cfg.channels?.googlechat !== undefined,
215
- groupPolicy: account.config.groupPolicy,
216
- defaultGroupPolicy,
217
- });
218
- if (groupPolicy === "open") {
219
- warnings.push(
220
- `- Google Chat spaces: groupPolicy="open" allows any space to trigger (mention-gated). Set channels.googlechat.groupPolicy="allowlist" and configure channels.googlechat.groups.`,
221
- );
222
- }
223
- if (account.config.dm?.policy === "open") {
224
- warnings.push(
225
- `- Google Chat DMs are open to anyone. Set channels.googlechat.dm.policy="pairing" or "allowlist".`,
226
- );
227
- }
228
- return warnings;
229
- },
230
- },
231
- groups: {
232
- resolveRequireMention: resolveGoogleChatGroupRequireMention,
233
- },
234
- threading: {
235
- resolveReplyToMode: ({ cfg }) => cfg.channels?.["googlechat"]?.replyToMode ?? "off",
236
- },
237
- messaging: {
238
- normalizeTarget: normalizeGoogleChatTarget,
239
- targetResolver: {
240
- looksLikeId: (raw, normalized) => {
241
- const value = normalized ?? raw.trim();
242
- return isGoogleChatSpaceTarget(value) || isGoogleChatUserTarget(value);
243
- },
244
- hint: "<spaces/{space}|users/{user}>",
245
- },
246
- },
247
- directory: {
248
- self: async () => null,
249
- listPeers: async ({ cfg, accountId, query, limit }) => {
250
- const account = resolveGoogleChatAccount({
251
- cfg: cfg,
252
- accountId,
253
- });
254
- const q = query?.trim().toLowerCase() || "";
255
- const allowFrom = account.config.dm?.allowFrom ?? [];
256
- const peers = Array.from(
257
- new Set(
258
- allowFrom
259
- .map((entry) => String(entry).trim())
260
- .filter((entry) => Boolean(entry) && entry !== "*")
261
- .map((entry) => normalizeGoogleChatTarget(entry) ?? entry),
262
- ),
263
- )
264
- .filter((id) => (q ? id.toLowerCase().includes(q) : true))
265
- .slice(0, limit && limit > 0 ? limit : undefined)
266
- .map((id) => ({ kind: "user", id }) as const);
267
- return peers;
268
- },
269
- listGroups: async ({ cfg, accountId, query, limit }) => {
270
- const account = resolveGoogleChatAccount({
271
- cfg: cfg,
272
- accountId,
273
- });
274
- const groups = account.config.groups ?? {};
275
- const q = query?.trim().toLowerCase() || "";
276
- const entries = Object.keys(groups)
277
- .filter((key) => key && key !== "*")
278
- .filter((key) => (q ? key.toLowerCase().includes(q) : true))
279
- .slice(0, limit && limit > 0 ? limit : undefined)
280
- .map((id) => ({ kind: "group", id }) as const);
281
- return entries;
282
- },
283
- },
284
- resolver: {
285
- resolveTargets: async ({ inputs, kind }) => {
286
- const resolved = inputs.map((input) => {
287
- const normalized = normalizeGoogleChatTarget(input);
288
- if (!normalized) {
289
- return { input, resolved: false, note: "empty target" };
290
- }
291
- if (kind === "user" && isGoogleChatUserTarget(normalized)) {
292
- return { input, resolved: true, id: normalized };
293
- }
294
- if (kind === "group" && isGoogleChatSpaceTarget(normalized)) {
295
- return { input, resolved: true, id: normalized };
296
- }
297
- return {
298
- input,
299
- resolved: false,
300
- note: "use spaces/{space} or users/{user}",
301
- };
302
- });
303
- return resolved;
304
- },
305
- },
306
- actions: googlechatActions,
307
- setup: {
308
- resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
309
- applyAccountName: ({ cfg, accountId, name }) =>
310
- applyAccountNameToChannelSection({
311
- cfg: cfg,
312
- channelKey: "googlechat",
313
- accountId,
314
- name,
315
- }),
316
- validateInput: ({ accountId, input }) => {
317
- if (input.useEnv && accountId !== DEFAULT_ACCOUNT_ID) {
318
- return "GOOGLE_CHAT_SERVICE_ACCOUNT env vars can only be used for the default account.";
319
- }
320
- if (!input.useEnv && !input.token && !input.tokenFile) {
321
- return "Google Chat requires --token (service account JSON) or --token-file.";
322
- }
323
- return null;
324
- },
325
- applyAccountConfig: ({ cfg, accountId, input }) => {
326
- const namedConfig = applyAccountNameToChannelSection({
327
- cfg: cfg,
328
- channelKey: "googlechat",
329
- accountId,
330
- name: input.name,
331
- });
332
- const next =
333
- accountId !== DEFAULT_ACCOUNT_ID
334
- ? migrateBaseNameToDefaultAccount({
335
- cfg: namedConfig,
336
- channelKey: "googlechat",
337
- })
338
- : namedConfig;
339
- const patch = input.useEnv
340
- ? {}
341
- : input.tokenFile
342
- ? { serviceAccountFile: input.tokenFile }
343
- : input.token
344
- ? { serviceAccount: input.token }
345
- : {};
346
- const audienceType = input.audienceType?.trim();
347
- const audience = input.audience?.trim();
348
- const webhookPath = input.webhookPath?.trim();
349
- const webhookUrl = input.webhookUrl?.trim();
350
- const configPatch = {
351
- ...patch,
352
- ...(audienceType ? { audienceType } : {}),
353
- ...(audience ? { audience } : {}),
354
- ...(webhookPath ? { webhookPath } : {}),
355
- ...(webhookUrl ? { webhookUrl } : {}),
356
- };
357
- if (accountId === DEFAULT_ACCOUNT_ID) {
358
- return {
359
- ...next,
360
- channels: {
361
- ...next.channels,
362
- googlechat: {
363
- ...next.channels?.["googlechat"],
364
- enabled: true,
365
- ...configPatch,
366
- },
367
- },
368
- } as FasedAgentConfig;
369
- }
370
- return {
371
- ...next,
372
- channels: {
373
- ...next.channels,
374
- googlechat: {
375
- ...next.channels?.["googlechat"],
376
- enabled: true,
377
- accounts: {
378
- ...next.channels?.["googlechat"]?.accounts,
379
- [accountId]: {
380
- ...next.channels?.["googlechat"]?.accounts?.[accountId],
381
- enabled: true,
382
- ...configPatch,
383
- },
384
- },
385
- },
386
- },
387
- } as FasedAgentConfig;
388
- },
389
- },
390
- outbound: {
391
- deliveryMode: "direct",
392
- chunker: (text, limit) => getGoogleChatRuntime().channel.text.chunkMarkdownText(text, limit),
393
- chunkerMode: "markdown",
394
- textChunkLimit: 4000,
395
- resolveTarget: ({ to }) => {
396
- const trimmed = to?.trim() ?? "";
397
-
398
- if (trimmed) {
399
- const normalized = normalizeGoogleChatTarget(trimmed);
400
- if (!normalized) {
401
- return {
402
- ok: false,
403
- error: missingTargetError("Google Chat", "<spaces/{space}|users/{user}>"),
404
- };
405
- }
406
- return { ok: true, to: normalized };
407
- }
408
-
409
- return {
410
- ok: false,
411
- error: missingTargetError("Google Chat", "<spaces/{space}|users/{user}>"),
412
- };
413
- },
414
- sendText: async ({ cfg, to, text, accountId, replyToId, threadId }) => {
415
- const account = resolveGoogleChatAccount({
416
- cfg: cfg,
417
- accountId,
418
- });
419
- const space = await resolveGoogleChatOutboundSpace({ account, target: to });
420
- const thread = (threadId ?? replyToId ?? undefined) as string | undefined;
421
- const result = await sendGoogleChatMessage({
422
- account,
423
- space,
424
- text,
425
- thread,
426
- });
427
- return {
428
- channel: "googlechat",
429
- messageId: result?.messageName ?? "",
430
- chatId: space,
431
- };
432
- },
433
- sendMedia: async ({ cfg, to, text, mediaUrl, accountId, replyToId, threadId }) => {
434
- if (!mediaUrl) {
435
- throw new Error("Google Chat mediaUrl is required.");
436
- }
437
- const account = resolveGoogleChatAccount({
438
- cfg: cfg,
439
- accountId,
440
- });
441
- const space = await resolveGoogleChatOutboundSpace({ account, target: to });
442
- const thread = (threadId ?? replyToId ?? undefined) as string | undefined;
443
- const runtime = getGoogleChatRuntime();
444
- const maxBytes = resolveChannelMediaMaxBytes({
445
- cfg: cfg,
446
- resolveChannelLimitMb: ({ cfg, accountId }) =>
447
- (
448
- cfg.channels?.["googlechat"] as
449
- | { accounts?: Record<string, { mediaMaxMb?: number }>; mediaMaxMb?: number }
450
- | undefined
451
- )?.accounts?.[accountId]?.mediaMaxMb ??
452
- (cfg.channels?.["googlechat"] as { mediaMaxMb?: number } | undefined)?.mediaMaxMb,
453
- accountId,
454
- });
455
- const loaded = await runtime.channel.media.fetchRemoteMedia({
456
- url: mediaUrl,
457
- maxBytes: maxBytes ?? (account.config.mediaMaxMb ?? 20) * 1024 * 1024,
458
- });
459
- const upload = await uploadGoogleChatAttachment({
460
- account,
461
- space,
462
- filename: loaded.fileName ?? "attachment",
463
- buffer: loaded.buffer,
464
- contentType: loaded.contentType,
465
- });
466
- const result = await sendGoogleChatMessage({
467
- account,
468
- space,
469
- text,
470
- thread,
471
- attachments: upload.attachmentUploadToken
472
- ? [{ attachmentUploadToken: upload.attachmentUploadToken, contentName: loaded.fileName }]
473
- : undefined,
474
- });
475
- return {
476
- channel: "googlechat",
477
- messageId: result?.messageName ?? "",
478
- chatId: space,
479
- };
480
- },
481
- },
482
- status: {
483
- defaultRuntime: {
484
- accountId: DEFAULT_ACCOUNT_ID,
485
- running: false,
486
- lastStartAt: null,
487
- lastStopAt: null,
488
- lastError: null,
489
- },
490
- collectStatusIssues: (accounts): ChannelStatusIssue[] =>
491
- accounts.flatMap((entry) => {
492
- const accountId = String(entry.accountId ?? DEFAULT_ACCOUNT_ID);
493
- const enabled = entry.enabled !== false;
494
- const configured = entry.configured === true;
495
- if (!enabled || !configured) {
496
- return [];
497
- }
498
- const issues: ChannelStatusIssue[] = [];
499
- if (!entry.audience) {
500
- issues.push({
501
- channel: "googlechat",
502
- accountId,
503
- kind: "config",
504
- message: "Google Chat audience is missing (set channels.googlechat.audience).",
505
- fix: "Set channels.googlechat.audienceType and channels.googlechat.audience.",
506
- });
507
- }
508
- if (!entry.audienceType) {
509
- issues.push({
510
- channel: "googlechat",
511
- accountId,
512
- kind: "config",
513
- message: "Google Chat audienceType is missing (app-url or project-number).",
514
- fix: "Set channels.googlechat.audienceType and channels.googlechat.audience.",
515
- });
516
- }
517
- return issues;
518
- }),
519
- buildChannelSummary: ({ snapshot }) => ({
520
- configured: snapshot.configured ?? false,
521
- credentialSource: snapshot.credentialSource ?? "none",
522
- audienceType: snapshot.audienceType ?? null,
523
- audience: snapshot.audience ?? null,
524
- webhookPath: snapshot.webhookPath ?? null,
525
- webhookUrl: snapshot.webhookUrl ?? null,
526
- running: snapshot.running ?? false,
527
- lastStartAt: snapshot.lastStartAt ?? null,
528
- lastStopAt: snapshot.lastStopAt ?? null,
529
- lastError: snapshot.lastError ?? null,
530
- probe: snapshot.probe,
531
- lastProbeAt: snapshot.lastProbeAt ?? null,
532
- }),
533
- probeAccount: async ({ account }) => probeGoogleChat(account),
534
- buildAccountSnapshot: ({ account, runtime, probe }) => ({
535
- accountId: account.accountId,
536
- name: account.name,
537
- enabled: account.enabled,
538
- configured: isGoogleChatAccountConfigured(account),
539
- credentialSource: account.credentialSource,
540
- audienceType: account.config.audienceType,
541
- audience: account.config.audience,
542
- webhookPath: account.config.webhookPath,
543
- webhookUrl: account.config.webhookUrl,
544
- running: runtime?.running ?? false,
545
- lastStartAt: runtime?.lastStartAt ?? null,
546
- lastStopAt: runtime?.lastStopAt ?? null,
547
- lastError: runtime?.lastError ?? null,
548
- lastInboundAt: runtime?.lastInboundAt ?? null,
549
- lastOutboundAt: runtime?.lastOutboundAt ?? null,
550
- dmPolicy: account.config.dm?.policy ?? "pairing",
551
- probe,
552
- }),
553
- },
554
- gateway: {
555
- startAccount: async (ctx) => {
556
- const account = ctx.account;
557
- ctx.log?.info(`[${account.accountId}] starting Google Chat webhook`);
558
- ctx.setStatus({
559
- accountId: account.accountId,
560
- running: true,
561
- lastStartAt: Date.now(),
562
- webhookPath: resolveGoogleChatWebhookPath({ account }),
563
- audienceType: account.config.audienceType,
564
- audience: account.config.audience,
565
- });
566
- const unregister = await startGoogleChatMonitor({
567
- account,
568
- config: ctx.cfg,
569
- runtime: ctx.runtime,
570
- abortSignal: ctx.abortSignal,
571
- webhookPath: account.config.webhookPath,
572
- webhookUrl: account.config.webhookUrl,
573
- statusSink: (patch) => ctx.setStatus({ accountId: account.accountId, ...patch }),
574
- });
575
- // Keep the promise pending until abort (webhook mode is passive).
576
- await new Promise<void>((resolve) => {
577
- if (ctx.abortSignal.aborted) {
578
- resolve();
579
- return;
580
- }
581
- ctx.abortSignal.addEventListener("abort", () => resolve(), { once: true });
582
- });
583
- unregister?.();
584
- ctx.setStatus({
585
- accountId: account.accountId,
586
- running: false,
587
- lastStopAt: Date.now(),
588
- });
589
- },
590
- },
591
- };