@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.
- package/config/capability-catalog.json +241 -0
- package/config/dependency-ownership.json +130 -0
- package/config/official-channel-catalog.json +39 -0
- package/dist/agents/tools/web-fetch-utils.js +2 -1
- package/dist/agents/tools/web-fetch-visibility.js +3 -1
- package/dist/brand.js +1 -1
- package/dist/browser/pw-session.js +2 -1
- package/dist/browser/pw-tools-core.state.js +3 -2
- package/dist/browser/runtime-dependency.js +27 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/capabilities/catalog.js +228 -0
- package/dist/cli/components-cli.js +105 -0
- package/dist/cli/hooks-cli.js +1 -1
- package/dist/cli/plugins-cli.js +3 -3
- package/dist/cli/program/register.subclis.js +9 -0
- package/dist/cli/update-cli/update-command.js +1 -1
- package/dist/commands/doctor-capabilities.js +26 -0
- package/dist/commands/doctor.js +2 -0
- package/dist/control-ui/assets/{app-DXYMrRJ9.js → app-JBrTSsNu.js} +1480 -1465
- package/dist/control-ui/assets/{index-iGQkJE0l.js → index-H-2DWAnH.js} +3 -3
- package/dist/control-ui/index.html +1 -1
- package/dist/gateway/method-scopes.js +1 -0
- package/dist/gateway/server-methods/plugins-marketplace.js +1 -1
- package/dist/gateway/server-methods/services.js +8 -0
- package/dist/gateway/server-methods-list.js +1 -0
- package/dist/infra/optional-runtime-dependency.js +46 -0
- package/dist/media/image-ops.js +6 -1
- package/dist/media/input-files.js +11 -2
- package/dist/media/mime.js +6 -1
- package/dist/memory/sqlite-vec.js +7 -1
- package/dist/plugin-sdk/{accounts-VqAX3HJ0.js → accounts-BwkH5bTD.js} +1 -1
- package/dist/plugin-sdk/{accounts-COY-15zJ.js → accounts-C5BjfxoO.js} +1 -1
- package/dist/plugin-sdk/{accounts-Zgt0NP54.js → accounts-RT6y7n3H.js} +1 -1
- package/dist/plugin-sdk/{actions-lB3PCwsz.js → actions-BrU_JMqM.js} +2 -2
- package/dist/plugin-sdk/{actions-BI5QViLk.js → actions-CUdVHzeJ.js} +2 -2
- package/dist/plugin-sdk/{active-listener-DKZiSaRA.js → active-listener-CE8t5g6l.js} +1 -1
- package/dist/plugin-sdk/{active-listener-D6_pdTMC.js → active-listener-Dx1SEGDn.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-Dx8J7XhV.js → audio-preflight-C8SbY4fV.js} +22 -22
- package/dist/plugin-sdk/{audio-preflight-CeRstduc.js → audio-preflight-CuABlLDL.js} +22 -22
- package/dist/plugin-sdk/{audit-BImNOQvk.js → audit-DxB2Kml5.js} +11 -11
- package/dist/plugin-sdk/{audit-CKWkq0Un.js → audit-sSeRDwJb.js} +11 -11
- package/dist/plugin-sdk/channel-plugin-common.js +3 -2
- package/dist/plugin-sdk/{chunk-skAJZWCT.js → chunk-KCxbJLsV.js} +1 -1
- package/dist/plugin-sdk/{chunk-Cjw4712g.js → chunk-M2d7r-Zt.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-Df5811D0.js → chunk-items-BGbYyNvO.js} +1 -1
- package/dist/plugin-sdk/command-status.js +22 -22
- package/dist/plugin-sdk/{commands-registry-5J619bQ2.js → commands-registry-CdT-nl7v.js} +2 -2
- package/dist/plugin-sdk/{commands-registry-CoLAT03J.js → commands-registry-DoWdYAJd.js} +2 -2
- package/dist/plugin-sdk/{common-CSTxewqY.js → common-Cpw-vuuM.js} +1 -1
- package/dist/plugin-sdk/{common-BiF0sTnY.js → common-DJWrErdE.js} +1 -1
- package/dist/plugin-sdk/{config-BxVjLTIv.js → config-C0qggNKQ.js} +7 -7
- package/dist/plugin-sdk/{config-TFokWwvO.js → config-CgwTaper.js} +45 -2
- package/dist/plugin-sdk/{config-DXlISPlx.js → config-DtqAN2L3.js} +45 -2
- package/dist/plugin-sdk/{config-DgD5T-Ui.js → config-g1MG9Bet.js} +7 -7
- package/dist/plugin-sdk/discord.js +2 -1
- package/dist/plugin-sdk/{fetch-guard-DPMynms8.js → fetch-guard-BLdujDnt.js} +1 -1
- package/dist/plugin-sdk/{fetch-guard-COLmW2TM.js → fetch-guard-DTKgMN9f.js} +1 -1
- package/dist/plugin-sdk/{handle-action-C-UndB8E.js → handle-action-B61D85yo.js} +12 -12
- package/dist/plugin-sdk/{handle-action-hhufKxmU.js → handle-action-CjcxGzQD.js} +12 -12
- package/dist/plugin-sdk/index.js +22 -22
- package/dist/plugin-sdk/{login-DL1oBBfL.js → login-CB_nCjX3.js} +3 -3
- package/dist/plugin-sdk/{login-YveoqEvH.js → login-CfRfRNc7.js} +2 -2
- package/dist/plugin-sdk/{login-Dnxas1dI.js → login-CzUuDd1v.js} +3 -3
- package/dist/plugin-sdk/{login-qr-CVQsGWKq.js → login-qr-D7MEpFza.js} +3 -3
- package/dist/plugin-sdk/{login-qr-B343JNXJ.js → login-qr-DgxfBFVN.js} +3 -3
- package/dist/plugin-sdk/{manager-BytwRIfK.js → manager-9see0IX5.js} +8 -3
- package/dist/plugin-sdk/{manager-BZjd_PCt.js → manager-D2kZ0Cps.js} +8 -3
- package/dist/plugin-sdk/{markdown-tables-krKiU4cT.js → markdown-tables-CCSD52rA.js} +1 -1
- package/dist/plugin-sdk/{markdown-tables-9rJDQ1X-.js → markdown-tables-DWUNvLrc.js} +1 -1
- package/dist/plugin-sdk/{media-D7ZkWU-A.js → media-C7YT4DeU.js} +13 -4
- package/dist/plugin-sdk/{media-C6C2c9a4.js → media-Cxw-xLGU.js} +13 -4
- package/dist/plugin-sdk/{monitor-CVQNDfhs.js → monitor-9X7wapUN.js} +27 -27
- package/dist/plugin-sdk/{monitor-BCxkQBoh.js → monitor-B3IfJzKX.js} +26 -26
- package/dist/plugin-sdk/{monitor-BzDW50H6.js → monitor-CTjAST_W.js} +27 -27
- package/dist/plugin-sdk/{monitor-BsLMfn3U.js → monitor-tYFfy2u-.js} +26 -26
- package/dist/plugin-sdk/{openresponses-http-BB67Z4QM.js → openresponses-http-DEB2fEya.js} +22 -22
- package/dist/plugin-sdk/{openresponses-http-NE76GGhj.js → openresponses-http-YgMg1jnp.js} +22 -22
- package/dist/plugin-sdk/{ssrf-u0Ul7okY.js → optional-runtime-dependency-szS49voX.js} +46 -2
- package/dist/plugin-sdk/{outbound-PGNWU6T-.js → outbound-BCxOxdi-.js} +6 -6
- package/dist/plugin-sdk/{outbound-BHWJD9q0.js → outbound-JIwQbpRY.js} +6 -6
- package/dist/plugin-sdk/{outbound-attachment-BVzfhqnk.js → outbound-attachment-C-jSFaEB.js} +1 -1
- package/dist/plugin-sdk/{outbound-attachment-ClMvNW17.js → outbound-attachment-D6tj5Y5H.js} +1 -1
- package/dist/plugin-sdk/{pi-embedded-runner-DQ6UPx6-.js → pi-embedded-runner-CUVk8CIj.js} +72 -60
- package/dist/plugin-sdk/{pi-model-discovery-D51L5E9I.js → pi-model-discovery-DadlvsZW.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DxoFm4Vd.js → pi-model-discovery-runtime-C5ssE6EW.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DRuh4PNV.js → pi-model-discovery-runtime-DAaOPt64.js} +2 -2
- package/dist/plugin-sdk/{pi-model-discovery-runtime-CQOauapl.js → pi-model-discovery-runtime-LB-5lX5L.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-BTWgkx4x.js → pi-model-discovery-runtime-gd77b0UF.js} +2 -2
- package/dist/plugin-sdk/{pi-model-discovery-CkH5l9X5.js → pi-model-discovery-yifTIDIn.js} +1 -1
- package/dist/plugin-sdk/{pw-ai-DZs6uYRd.js → pw-ai-SNCI9UXT.js} +6 -5
- package/dist/plugin-sdk/{pw-ai-Cn-EUPZK.js → pw-ai-sH1Pi-Fh.js} +6 -5
- package/dist/plugin-sdk/{registry-B4HvWzob.js → registry-DNkJsNsz.js} +4 -3
- package/dist/plugin-sdk/{replies-jDMUBsNO.js → replies-fvzN5wnU.js} +2 -2
- package/dist/plugin-sdk/{replies-B_LW9c9f.js → replies-zebgZCHX.js} +2 -2
- package/dist/plugin-sdk/{resolve-route-_YZHbS-z.js → resolve-route-CNhTJG_2.js} +1 -1
- package/dist/plugin-sdk/{resolve-route-DlHzggnG.js → resolve-route-DO0WR4nB.js} +1 -1
- package/dist/plugin-sdk/{resolve-utils-zBhVX3Vx.js → resolve-utils-EFP1DYqG.js} +1 -1
- package/dist/plugin-sdk/{retry-policy-DGLs5ebP.js → retry-policy-BLYEgIwP.js} +1 -1
- package/dist/plugin-sdk/{retry-policy-DaodShGa.js → retry-policy-sM01QZT2.js} +1 -1
- package/dist/plugin-sdk/{runtime-Dd0sswuW.js → runtime-BPyuAmka.js} +4 -3
- package/dist/plugin-sdk/{paths-DW-U2r7Y.js → runtime-dependency-B-1u41Ph.js} +27 -3
- package/dist/plugin-sdk/{paths-CBCpJ5bu.js → runtime-dependency-Csswyv5r.js} +27 -3
- package/dist/plugin-sdk/sat-runtime.js +1 -0
- package/dist/plugin-sdk/{send-8remZhsH.js → send-B09HRfHN.js} +6 -6
- package/dist/plugin-sdk/{send-DaaAscWj.js → send-BBYcgXA4.js} +5 -5
- package/dist/plugin-sdk/{send-DFTB0cnx.js → send-BQXQA81e.js} +6 -6
- package/dist/plugin-sdk/{send-CtMVvMJs.js → send-BzFdvD_i.js} +6 -6
- package/dist/plugin-sdk/{send-Di9irjS-.js → send-C3u-F_8s.js} +6 -6
- package/dist/plugin-sdk/{send-Dl88ZKq2.js → send-D3836_UN.js} +6 -6
- package/dist/plugin-sdk/{send-ifgZCHVB.js → send-D7tr-EsH.js} +5 -5
- package/dist/plugin-sdk/{send-DvUpYh0d.js → send-DRGzRdI3.js} +6 -6
- package/dist/plugin-sdk/{send-D2jlPeKH.js → send-DfkPKz_0.js} +4 -4
- package/dist/plugin-sdk/{send-QSt6nbny.js → send-DsxFXrCO.js} +4 -4
- package/dist/plugin-sdk/{session-CknrceVU.js → session-DG_bYisw.js} +2 -2
- package/dist/plugin-sdk/{session-CyRTcJ8N.js → session-EIStzK0E.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-DHxkTA0s.js → skill-commands-CkgGmWBS.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-CLXAG5sU.js → skill-commands-hyZA0LE3.js} +2 -2
- package/dist/plugin-sdk/{slack-BpJXkwxF.js → slack-C0WZVJPZ.js} +34 -34
- package/dist/plugin-sdk/{slack-Br9c6Yzs.js → slack-DtlPw_PN.js} +34 -34
- package/dist/plugin-sdk/{slack-actions-8tLGt1Ht.js → slack-actions-BQawWGTJ.js} +11 -11
- package/dist/plugin-sdk/{slack-actions-CDSSRo8Y.js → slack-actions-DDMszx56.js} +11 -11
- package/dist/plugin-sdk/slack.js +2 -1
- package/dist/plugin-sdk/src/brand.d.ts +2 -2
- package/dist/plugin-sdk/src/browser/runtime-dependency.d.ts +3 -0
- package/dist/plugin-sdk/src/infra/optional-runtime-dependency.d.ts +6 -0
- package/dist/plugin-sdk/{ssrf-fG4UHKBw.js → ssrf-Cce6LubA.js} +41 -7
- package/dist/plugin-sdk/{status-DoxnzyMC.js → status-CIiBeb9B.js} +72 -60
- package/dist/plugin-sdk/{sticker-cache-zmJ39ByC.js → sticker-cache-9houHChV.js} +3 -3
- package/dist/plugin-sdk/{sticker-cache-D7WcMYsF.js → sticker-cache-Dwi-XsgB.js} +3 -3
- package/dist/plugin-sdk/{tables-CkxblF0u.js → tables-BD7H5ug-.js} +1 -1
- package/dist/plugin-sdk/{tables-RBtf8G4P.js → tables-CJE8kB35.js} +1 -1
- package/dist/plugin-sdk/{telegram-actions-DAeYXSLk.js → telegram-actions-Bu1edXF2.js} +25 -25
- package/dist/plugin-sdk/{telegram-actions-BDeS3ocd.js → telegram-actions-CRXVO8lG.js} +25 -25
- package/dist/plugin-sdk/telegram.js +2 -1
- package/dist/plugin-sdk/{thread-bindings.lifecycle-DsB94WbE.js → thread-bindings.lifecycle-Djem8FWF.js} +2 -2
- package/dist/plugin-sdk/{thread-bindings.lifecycle-DMhV3TsR.js → thread-bindings.lifecycle-gmHv3hc7.js} +2 -2
- package/dist/plugin-sdk/{thread-bindings.state-DYWpy7hJ.js → thread-bindings.state-CNT2vxm3.js} +2 -2
- package/dist/plugin-sdk/{thread-bindings.state-DG5cBaRn.js → thread-bindings.state-D8kN2X6H.js} +2 -2
- package/dist/plugin-sdk/{web-IJ4NoGPJ.js → web-DCrVQr6y.js} +26 -26
- package/dist/plugin-sdk/{web-DJwacWQo.js → web-Ds6OWw3C.js} +26 -26
- package/dist/plugin-sdk/{whatsapp-actions-DAY8hWpD.js → whatsapp-actions-68Mfs2dJ.js} +12 -12
- package/dist/plugin-sdk/{whatsapp-actions-6opfo-oB.js → whatsapp-actions-DRqtzvTO.js} +12 -12
- package/dist/plugin-sdk/whatsapp.js +6 -5
- package/dist/plugin-sdk/{wsl-B2euLEc2.js → wsl-DcM2PgSS.js} +3 -3
- package/dist/plugin-sdk/{wsl-B8eyviuv.js → wsl-PXrdWitE.js} +3 -3
- package/dist/plugins/update.js +1 -1
- package/dist/tts/tts-core.js +6 -1
- package/dist/wizard/onboarding.finalize.js +9 -0
- package/extensions/acpx/package.json +1 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +6 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +6 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +6 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +6 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +6 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +6 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +6 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +22 -15
- package/extensions/feishu/fased.plugin.json +0 -10
- package/extensions/feishu/index.ts +0 -63
- package/extensions/feishu/package.json +0 -33
- package/extensions/feishu/skills/feishu-doc/SKILL.md +0 -211
- package/extensions/feishu/skills/feishu-doc/references/block-types.md +0 -103
- package/extensions/feishu/skills/feishu-drive/SKILL.md +0 -97
- package/extensions/feishu/skills/feishu-perm/SKILL.md +0 -119
- package/extensions/feishu/skills/feishu-wiki/SKILL.md +0 -111
- package/extensions/feishu/src/accounts.ts +0 -159
- package/extensions/feishu/src/bitable.ts +0 -713
- package/extensions/feishu/src/bot.ts +0 -979
- package/extensions/feishu/src/channel.ts +0 -359
- package/extensions/feishu/src/client.ts +0 -118
- package/extensions/feishu/src/config-schema.ts +0 -226
- package/extensions/feishu/src/dedup.ts +0 -54
- package/extensions/feishu/src/directory.ts +0 -177
- package/extensions/feishu/src/doc-schema.ts +0 -122
- package/extensions/feishu/src/docx.ts +0 -998
- package/extensions/feishu/src/drive-schema.ts +0 -46
- package/extensions/feishu/src/drive.ts +0 -232
- package/extensions/feishu/src/dynamic-agent.ts +0 -131
- package/extensions/feishu/src/external-keys.ts +0 -19
- package/extensions/feishu/src/media.ts +0 -447
- package/extensions/feishu/src/mention.ts +0 -133
- package/extensions/feishu/src/monitor.ts +0 -434
- package/extensions/feishu/src/onboarding.ts +0 -430
- package/extensions/feishu/src/outbound.ts +0 -56
- package/extensions/feishu/src/perm-schema.ts +0 -52
- package/extensions/feishu/src/perm.ts +0 -180
- package/extensions/feishu/src/policy.ts +0 -116
- package/extensions/feishu/src/probe.ts +0 -44
- package/extensions/feishu/src/reactions.ts +0 -160
- package/extensions/feishu/src/reply-dispatcher.ts +0 -239
- package/extensions/feishu/src/runtime.ts +0 -14
- package/extensions/feishu/src/send-result.ts +0 -29
- package/extensions/feishu/src/send-target.ts +0 -25
- package/extensions/feishu/src/send.ts +0 -313
- package/extensions/feishu/src/streaming-card.ts +0 -218
- package/extensions/feishu/src/targets.ts +0 -78
- package/extensions/feishu/src/tool-account.ts +0 -58
- package/extensions/feishu/src/tools-config.ts +0 -21
- package/extensions/feishu/src/types.ts +0 -81
- package/extensions/feishu/src/typing.ts +0 -80
- package/extensions/feishu/src/wiki-schema.ts +0 -55
- package/extensions/feishu/src/wiki.ts +0 -237
- package/extensions/googlechat/fased.plugin.json +0 -9
- package/extensions/googlechat/index.ts +0 -19
- package/extensions/googlechat/package.json +0 -37
- package/extensions/googlechat/src/accounts.ts +0 -147
- package/extensions/googlechat/src/actions.ts +0 -176
- package/extensions/googlechat/src/api.ts +0 -282
- package/extensions/googlechat/src/auth.ts +0 -137
- package/extensions/googlechat/src/channel.ts +0 -591
- package/extensions/googlechat/src/monitor.ts +0 -996
- package/extensions/googlechat/src/onboarding.ts +0 -344
- package/extensions/googlechat/src/runtime.ts +0 -14
- package/extensions/googlechat/src/targets.ts +0 -65
- package/extensions/googlechat/src/types.config.ts +0 -3
- package/extensions/googlechat/src/types.ts +0 -73
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import type { ChannelMeta, ChannelPlugin, FasedAgentConfig } from "fased/plugin-sdk";
|
|
2
|
-
import {
|
|
3
|
-
buildBaseChannelStatusSummary,
|
|
4
|
-
createDefaultChannelRuntimeState,
|
|
5
|
-
DEFAULT_ACCOUNT_ID,
|
|
6
|
-
PAIRING_APPROVED_MESSAGE,
|
|
7
|
-
resolveAllowlistProviderRuntimeGroupPolicy,
|
|
8
|
-
resolveDefaultGroupPolicy,
|
|
9
|
-
} from "fased/plugin-sdk";
|
|
10
|
-
import {
|
|
11
|
-
resolveFeishuAccount,
|
|
12
|
-
resolveFeishuCredentials,
|
|
13
|
-
listFeishuAccountIds,
|
|
14
|
-
resolveDefaultFeishuAccountId,
|
|
15
|
-
} from "./accounts.js";
|
|
16
|
-
import {
|
|
17
|
-
listFeishuDirectoryPeers,
|
|
18
|
-
listFeishuDirectoryGroups,
|
|
19
|
-
listFeishuDirectoryPeersLive,
|
|
20
|
-
listFeishuDirectoryGroupsLive,
|
|
21
|
-
} from "./directory.js";
|
|
22
|
-
import { feishuOnboardingAdapter } from "./onboarding.js";
|
|
23
|
-
import { feishuOutbound } from "./outbound.js";
|
|
24
|
-
import { resolveFeishuGroupToolPolicy } from "./policy.js";
|
|
25
|
-
import { probeFeishu } from "./probe.js";
|
|
26
|
-
import { sendMessageFeishu } from "./send.js";
|
|
27
|
-
import { normalizeFeishuTarget, looksLikeFeishuId, formatFeishuTarget } from "./targets.js";
|
|
28
|
-
import type { ResolvedFeishuAccount, FeishuConfig } from "./types.js";
|
|
29
|
-
|
|
30
|
-
const meta: ChannelMeta = {
|
|
31
|
-
id: "feishu",
|
|
32
|
-
label: "Feishu",
|
|
33
|
-
selectionLabel: "Feishu/Lark (飞书)",
|
|
34
|
-
docsPath: "/channels/feishu",
|
|
35
|
-
docsLabel: "feishu",
|
|
36
|
-
blurb: "飞书/Lark enterprise messaging.",
|
|
37
|
-
aliases: ["lark"],
|
|
38
|
-
order: 70,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
42
|
-
id: "feishu",
|
|
43
|
-
meta: {
|
|
44
|
-
...meta,
|
|
45
|
-
},
|
|
46
|
-
pairing: {
|
|
47
|
-
idLabel: "feishuUserId",
|
|
48
|
-
normalizeAllowEntry: (entry) => entry.replace(/^(feishu|user|open_id):/i, ""),
|
|
49
|
-
notifyApproval: async ({ cfg, id }) => {
|
|
50
|
-
await sendMessageFeishu({
|
|
51
|
-
cfg,
|
|
52
|
-
to: id,
|
|
53
|
-
text: PAIRING_APPROVED_MESSAGE,
|
|
54
|
-
});
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
capabilities: {
|
|
58
|
-
chatTypes: ["direct", "channel"],
|
|
59
|
-
polls: false,
|
|
60
|
-
threads: true,
|
|
61
|
-
media: true,
|
|
62
|
-
reactions: true,
|
|
63
|
-
edit: true,
|
|
64
|
-
reply: true,
|
|
65
|
-
},
|
|
66
|
-
agentPrompt: {
|
|
67
|
-
messageToolHints: () => [
|
|
68
|
-
"- Feishu targeting: omit `target` to reply to the current conversation (auto-inferred). Explicit targets: `user:open_id` or `chat:chat_id`.",
|
|
69
|
-
"- Feishu supports interactive cards for rich messages.",
|
|
70
|
-
],
|
|
71
|
-
},
|
|
72
|
-
groups: {
|
|
73
|
-
resolveToolPolicy: resolveFeishuGroupToolPolicy,
|
|
74
|
-
},
|
|
75
|
-
reload: { configPrefixes: ["channels.feishu"] },
|
|
76
|
-
configSchema: {
|
|
77
|
-
schema: {
|
|
78
|
-
type: "object",
|
|
79
|
-
additionalProperties: false,
|
|
80
|
-
properties: {
|
|
81
|
-
enabled: { type: "boolean" },
|
|
82
|
-
appId: { type: "string" },
|
|
83
|
-
appSecret: { type: "string" },
|
|
84
|
-
encryptKey: { type: "string" },
|
|
85
|
-
verificationToken: { type: "string" },
|
|
86
|
-
domain: {
|
|
87
|
-
oneOf: [
|
|
88
|
-
{ type: "string", enum: ["feishu", "lark"] },
|
|
89
|
-
{ type: "string", format: "uri", pattern: "^https://" },
|
|
90
|
-
],
|
|
91
|
-
},
|
|
92
|
-
connectionMode: { type: "string", enum: ["websocket", "webhook"] },
|
|
93
|
-
webhookPath: { type: "string" },
|
|
94
|
-
webhookHost: { type: "string" },
|
|
95
|
-
webhookPort: { type: "integer", minimum: 1 },
|
|
96
|
-
dmPolicy: { type: "string", enum: ["open", "pairing", "allowlist"] },
|
|
97
|
-
allowFrom: { type: "array", items: { oneOf: [{ type: "string" }, { type: "number" }] } },
|
|
98
|
-
groupPolicy: { type: "string", enum: ["open", "allowlist", "disabled"] },
|
|
99
|
-
groupAllowFrom: {
|
|
100
|
-
type: "array",
|
|
101
|
-
items: { oneOf: [{ type: "string" }, { type: "number" }] },
|
|
102
|
-
},
|
|
103
|
-
requireMention: { type: "boolean" },
|
|
104
|
-
topicSessionMode: { type: "string", enum: ["disabled", "enabled"] },
|
|
105
|
-
historyLimit: { type: "integer", minimum: 0 },
|
|
106
|
-
dmHistoryLimit: { type: "integer", minimum: 0 },
|
|
107
|
-
textChunkLimit: { type: "integer", minimum: 1 },
|
|
108
|
-
chunkMode: { type: "string", enum: ["length", "newline"] },
|
|
109
|
-
mediaMaxMb: { type: "number", minimum: 0 },
|
|
110
|
-
renderMode: { type: "string", enum: ["auto", "raw", "card"] },
|
|
111
|
-
accounts: {
|
|
112
|
-
type: "object",
|
|
113
|
-
additionalProperties: {
|
|
114
|
-
type: "object",
|
|
115
|
-
properties: {
|
|
116
|
-
enabled: { type: "boolean" },
|
|
117
|
-
name: { type: "string" },
|
|
118
|
-
appId: { type: "string" },
|
|
119
|
-
appSecret: { type: "string" },
|
|
120
|
-
encryptKey: { type: "string" },
|
|
121
|
-
verificationToken: { type: "string" },
|
|
122
|
-
domain: { type: "string", enum: ["feishu", "lark"] },
|
|
123
|
-
connectionMode: { type: "string", enum: ["websocket", "webhook"] },
|
|
124
|
-
webhookHost: { type: "string" },
|
|
125
|
-
webhookPath: { type: "string" },
|
|
126
|
-
webhookPort: { type: "integer", minimum: 1 },
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
config: {
|
|
134
|
-
listAccountIds: (cfg) => listFeishuAccountIds(cfg),
|
|
135
|
-
resolveAccount: (cfg, accountId) => resolveFeishuAccount({ cfg, accountId }),
|
|
136
|
-
defaultAccountId: (cfg) => resolveDefaultFeishuAccountId(cfg),
|
|
137
|
-
setAccountEnabled: ({ cfg, accountId, enabled }) => {
|
|
138
|
-
const account = resolveFeishuAccount({ cfg, accountId });
|
|
139
|
-
const isDefault = accountId === DEFAULT_ACCOUNT_ID;
|
|
140
|
-
|
|
141
|
-
if (isDefault) {
|
|
142
|
-
// For default account, set top-level enabled
|
|
143
|
-
return {
|
|
144
|
-
...cfg,
|
|
145
|
-
channels: {
|
|
146
|
-
...cfg.channels,
|
|
147
|
-
feishu: {
|
|
148
|
-
...cfg.channels?.feishu,
|
|
149
|
-
enabled,
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// For named accounts, set enabled in accounts[accountId]
|
|
156
|
-
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
|
|
157
|
-
return {
|
|
158
|
-
...cfg,
|
|
159
|
-
channels: {
|
|
160
|
-
...cfg.channels,
|
|
161
|
-
feishu: {
|
|
162
|
-
...feishuCfg,
|
|
163
|
-
accounts: {
|
|
164
|
-
...feishuCfg?.accounts,
|
|
165
|
-
[accountId]: {
|
|
166
|
-
...feishuCfg?.accounts?.[accountId],
|
|
167
|
-
enabled,
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
},
|
|
174
|
-
deleteAccount: ({ cfg, accountId }) => {
|
|
175
|
-
const isDefault = accountId === DEFAULT_ACCOUNT_ID;
|
|
176
|
-
|
|
177
|
-
if (isDefault) {
|
|
178
|
-
// Delete entire feishu config
|
|
179
|
-
const next = { ...cfg } as FasedAgentConfig;
|
|
180
|
-
const nextChannels = { ...cfg.channels };
|
|
181
|
-
delete (nextChannels as Record<string, unknown>).feishu;
|
|
182
|
-
if (Object.keys(nextChannels).length > 0) {
|
|
183
|
-
next.channels = nextChannels;
|
|
184
|
-
} else {
|
|
185
|
-
delete next.channels;
|
|
186
|
-
}
|
|
187
|
-
return next;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Delete specific account from accounts
|
|
191
|
-
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
|
|
192
|
-
const accounts = { ...feishuCfg?.accounts };
|
|
193
|
-
delete accounts[accountId];
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
...cfg,
|
|
197
|
-
channels: {
|
|
198
|
-
...cfg.channels,
|
|
199
|
-
feishu: {
|
|
200
|
-
...feishuCfg,
|
|
201
|
-
accounts: Object.keys(accounts).length > 0 ? accounts : undefined,
|
|
202
|
-
},
|
|
203
|
-
},
|
|
204
|
-
};
|
|
205
|
-
},
|
|
206
|
-
isConfigured: (account) => account.configured,
|
|
207
|
-
describeAccount: (account) => ({
|
|
208
|
-
accountId: account.accountId,
|
|
209
|
-
enabled: account.enabled,
|
|
210
|
-
configured: account.configured,
|
|
211
|
-
name: account.name,
|
|
212
|
-
appId: account.appId,
|
|
213
|
-
domain: account.domain,
|
|
214
|
-
}),
|
|
215
|
-
resolveAllowFrom: ({ cfg, accountId }) => {
|
|
216
|
-
const account = resolveFeishuAccount({ cfg, accountId });
|
|
217
|
-
return (account.config?.allowFrom ?? []).map((entry) => String(entry));
|
|
218
|
-
},
|
|
219
|
-
formatAllowFrom: ({ allowFrom }) =>
|
|
220
|
-
allowFrom
|
|
221
|
-
.map((entry) => String(entry).trim())
|
|
222
|
-
.filter(Boolean)
|
|
223
|
-
.map((entry) => entry.toLowerCase()),
|
|
224
|
-
},
|
|
225
|
-
security: {
|
|
226
|
-
collectWarnings: ({ cfg, accountId }) => {
|
|
227
|
-
const account = resolveFeishuAccount({ cfg, accountId });
|
|
228
|
-
const feishuCfg = account.config;
|
|
229
|
-
const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
|
|
230
|
-
const { groupPolicy } = resolveAllowlistProviderRuntimeGroupPolicy({
|
|
231
|
-
providerConfigPresent: cfg.channels?.feishu !== undefined,
|
|
232
|
-
groupPolicy: feishuCfg?.groupPolicy,
|
|
233
|
-
defaultGroupPolicy,
|
|
234
|
-
});
|
|
235
|
-
if (groupPolicy !== "open") return [];
|
|
236
|
-
return [
|
|
237
|
-
`- Feishu[${account.accountId}] groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.feishu.groupPolicy="allowlist" + channels.feishu.groupAllowFrom to restrict senders.`,
|
|
238
|
-
];
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
setup: {
|
|
242
|
-
resolveAccountId: () => DEFAULT_ACCOUNT_ID,
|
|
243
|
-
applyAccountConfig: ({ cfg, accountId }) => {
|
|
244
|
-
const isDefault = !accountId || accountId === DEFAULT_ACCOUNT_ID;
|
|
245
|
-
|
|
246
|
-
if (isDefault) {
|
|
247
|
-
return {
|
|
248
|
-
...cfg,
|
|
249
|
-
channels: {
|
|
250
|
-
...cfg.channels,
|
|
251
|
-
feishu: {
|
|
252
|
-
...cfg.channels?.feishu,
|
|
253
|
-
enabled: true,
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
|
|
260
|
-
return {
|
|
261
|
-
...cfg,
|
|
262
|
-
channels: {
|
|
263
|
-
...cfg.channels,
|
|
264
|
-
feishu: {
|
|
265
|
-
...feishuCfg,
|
|
266
|
-
accounts: {
|
|
267
|
-
...feishuCfg?.accounts,
|
|
268
|
-
[accountId]: {
|
|
269
|
-
...feishuCfg?.accounts?.[accountId],
|
|
270
|
-
enabled: true,
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
},
|
|
277
|
-
},
|
|
278
|
-
onboarding: feishuOnboardingAdapter,
|
|
279
|
-
messaging: {
|
|
280
|
-
normalizeTarget: (raw) => normalizeFeishuTarget(raw) ?? undefined,
|
|
281
|
-
targetResolver: {
|
|
282
|
-
looksLikeId: looksLikeFeishuId,
|
|
283
|
-
hint: "<chatId|user:openId|chat:chatId>",
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
directory: {
|
|
287
|
-
self: async () => null,
|
|
288
|
-
listPeers: async ({ cfg, query, limit, accountId }) =>
|
|
289
|
-
listFeishuDirectoryPeers({
|
|
290
|
-
cfg,
|
|
291
|
-
query: query ?? undefined,
|
|
292
|
-
limit: limit ?? undefined,
|
|
293
|
-
accountId: accountId ?? undefined,
|
|
294
|
-
}),
|
|
295
|
-
listGroups: async ({ cfg, query, limit, accountId }) =>
|
|
296
|
-
listFeishuDirectoryGroups({
|
|
297
|
-
cfg,
|
|
298
|
-
query: query ?? undefined,
|
|
299
|
-
limit: limit ?? undefined,
|
|
300
|
-
accountId: accountId ?? undefined,
|
|
301
|
-
}),
|
|
302
|
-
listPeersLive: async ({ cfg, query, limit, accountId }) =>
|
|
303
|
-
listFeishuDirectoryPeersLive({
|
|
304
|
-
cfg,
|
|
305
|
-
query: query ?? undefined,
|
|
306
|
-
limit: limit ?? undefined,
|
|
307
|
-
accountId: accountId ?? undefined,
|
|
308
|
-
}),
|
|
309
|
-
listGroupsLive: async ({ cfg, query, limit, accountId }) =>
|
|
310
|
-
listFeishuDirectoryGroupsLive({
|
|
311
|
-
cfg,
|
|
312
|
-
query: query ?? undefined,
|
|
313
|
-
limit: limit ?? undefined,
|
|
314
|
-
accountId: accountId ?? undefined,
|
|
315
|
-
}),
|
|
316
|
-
},
|
|
317
|
-
outbound: feishuOutbound,
|
|
318
|
-
status: {
|
|
319
|
-
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID, { port: null }),
|
|
320
|
-
buildChannelSummary: ({ snapshot }) => ({
|
|
321
|
-
...buildBaseChannelStatusSummary(snapshot),
|
|
322
|
-
port: snapshot.port ?? null,
|
|
323
|
-
probe: snapshot.probe,
|
|
324
|
-
lastProbeAt: snapshot.lastProbeAt ?? null,
|
|
325
|
-
}),
|
|
326
|
-
probeAccount: async ({ account }) => await probeFeishu(account),
|
|
327
|
-
buildAccountSnapshot: ({ account, runtime, probe }) => ({
|
|
328
|
-
accountId: account.accountId,
|
|
329
|
-
enabled: account.enabled,
|
|
330
|
-
configured: account.configured,
|
|
331
|
-
name: account.name,
|
|
332
|
-
appId: account.appId,
|
|
333
|
-
domain: account.domain,
|
|
334
|
-
running: runtime?.running ?? false,
|
|
335
|
-
lastStartAt: runtime?.lastStartAt ?? null,
|
|
336
|
-
lastStopAt: runtime?.lastStopAt ?? null,
|
|
337
|
-
lastError: runtime?.lastError ?? null,
|
|
338
|
-
port: runtime?.port ?? null,
|
|
339
|
-
probe,
|
|
340
|
-
}),
|
|
341
|
-
},
|
|
342
|
-
gateway: {
|
|
343
|
-
startAccount: async (ctx) => {
|
|
344
|
-
const { monitorFeishuProvider } = await import("./monitor.js");
|
|
345
|
-
const account = resolveFeishuAccount({ cfg: ctx.cfg, accountId: ctx.accountId });
|
|
346
|
-
const port = account.config?.webhookPort ?? null;
|
|
347
|
-
ctx.setStatus({ accountId: ctx.accountId, port });
|
|
348
|
-
ctx.log?.info(
|
|
349
|
-
`starting feishu[${ctx.accountId}] (mode: ${account.config?.connectionMode ?? "websocket"})`,
|
|
350
|
-
);
|
|
351
|
-
return monitorFeishuProvider({
|
|
352
|
-
config: ctx.cfg,
|
|
353
|
-
runtime: ctx.runtime,
|
|
354
|
-
abortSignal: ctx.abortSignal,
|
|
355
|
-
accountId: ctx.accountId,
|
|
356
|
-
});
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
};
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
2
|
-
import type { FeishuDomain, ResolvedFeishuAccount } from "./types.js";
|
|
3
|
-
|
|
4
|
-
// Multi-account client cache
|
|
5
|
-
const clientCache = new Map<
|
|
6
|
-
string,
|
|
7
|
-
{
|
|
8
|
-
client: Lark.Client;
|
|
9
|
-
config: { appId: string; appSecret: string; domain?: FeishuDomain };
|
|
10
|
-
}
|
|
11
|
-
>();
|
|
12
|
-
|
|
13
|
-
function resolveDomain(domain: FeishuDomain | undefined): Lark.Domain | string {
|
|
14
|
-
if (domain === "lark") {
|
|
15
|
-
return Lark.Domain.Lark;
|
|
16
|
-
}
|
|
17
|
-
if (domain === "feishu" || !domain) {
|
|
18
|
-
return Lark.Domain.Feishu;
|
|
19
|
-
}
|
|
20
|
-
return domain.replace(/\/+$/, ""); // Custom URL for private deployment
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Credentials needed to create a Feishu client.
|
|
25
|
-
* Both FeishuConfig and ResolvedFeishuAccount satisfy this interface.
|
|
26
|
-
*/
|
|
27
|
-
export type FeishuClientCredentials = {
|
|
28
|
-
accountId?: string;
|
|
29
|
-
appId?: string;
|
|
30
|
-
appSecret?: string;
|
|
31
|
-
domain?: FeishuDomain;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Create or get a cached Feishu client for an account.
|
|
36
|
-
* Accepts any object with appId, appSecret, and optional domain/accountId.
|
|
37
|
-
*/
|
|
38
|
-
export function createFeishuClient(creds: FeishuClientCredentials): Lark.Client {
|
|
39
|
-
const { accountId = "default", appId, appSecret, domain } = creds;
|
|
40
|
-
|
|
41
|
-
if (!appId || !appSecret) {
|
|
42
|
-
throw new Error(`Feishu credentials not configured for account "${accountId}"`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Check cache
|
|
46
|
-
const cached = clientCache.get(accountId);
|
|
47
|
-
if (
|
|
48
|
-
cached &&
|
|
49
|
-
cached.config.appId === appId &&
|
|
50
|
-
cached.config.appSecret === appSecret &&
|
|
51
|
-
cached.config.domain === domain
|
|
52
|
-
) {
|
|
53
|
-
return cached.client;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Create new client
|
|
57
|
-
const client = new Lark.Client({
|
|
58
|
-
appId,
|
|
59
|
-
appSecret,
|
|
60
|
-
appType: Lark.AppType.SelfBuild,
|
|
61
|
-
domain: resolveDomain(domain),
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Cache it
|
|
65
|
-
clientCache.set(accountId, {
|
|
66
|
-
client,
|
|
67
|
-
config: { appId, appSecret, domain },
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
return client;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Create a Feishu WebSocket client for an account.
|
|
75
|
-
* Note: WSClient is not cached since each call creates a new connection.
|
|
76
|
-
*/
|
|
77
|
-
export function createFeishuWSClient(account: ResolvedFeishuAccount): Lark.WSClient {
|
|
78
|
-
const { accountId, appId, appSecret, domain } = account;
|
|
79
|
-
|
|
80
|
-
if (!appId || !appSecret) {
|
|
81
|
-
throw new Error(`Feishu credentials not configured for account "${accountId}"`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return new Lark.WSClient({
|
|
85
|
-
appId,
|
|
86
|
-
appSecret,
|
|
87
|
-
domain: resolveDomain(domain),
|
|
88
|
-
loggerLevel: Lark.LoggerLevel.info,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Create an event dispatcher for an account.
|
|
94
|
-
*/
|
|
95
|
-
export function createEventDispatcher(account: ResolvedFeishuAccount): Lark.EventDispatcher {
|
|
96
|
-
return new Lark.EventDispatcher({
|
|
97
|
-
encryptKey: account.encryptKey,
|
|
98
|
-
verificationToken: account.verificationToken,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get a cached client for an account (if exists).
|
|
104
|
-
*/
|
|
105
|
-
export function getFeishuClient(accountId: string): Lark.Client | null {
|
|
106
|
-
return clientCache.get(accountId)?.client ?? null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Clear client cache for a specific account or all accounts.
|
|
111
|
-
*/
|
|
112
|
-
export function clearClientCache(accountId?: string): void {
|
|
113
|
-
if (accountId) {
|
|
114
|
-
clientCache.delete(accountId);
|
|
115
|
-
} else {
|
|
116
|
-
clientCache.clear();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export { z };
|
|
3
|
-
|
|
4
|
-
const DmPolicySchema = z.enum(["open", "pairing", "allowlist"]);
|
|
5
|
-
const GroupPolicySchema = z.enum(["open", "allowlist", "disabled"]);
|
|
6
|
-
const FeishuDomainSchema = z.union([
|
|
7
|
-
z.enum(["feishu", "lark"]),
|
|
8
|
-
z.string().url().startsWith("https://"),
|
|
9
|
-
]);
|
|
10
|
-
const FeishuConnectionModeSchema = z.enum(["websocket", "webhook"]);
|
|
11
|
-
|
|
12
|
-
const ToolPolicySchema = z
|
|
13
|
-
.object({
|
|
14
|
-
allow: z.array(z.string()).optional(),
|
|
15
|
-
deny: z.array(z.string()).optional(),
|
|
16
|
-
})
|
|
17
|
-
.strict()
|
|
18
|
-
.optional();
|
|
19
|
-
|
|
20
|
-
const DmConfigSchema = z
|
|
21
|
-
.object({
|
|
22
|
-
enabled: z.boolean().optional(),
|
|
23
|
-
systemPrompt: z.string().optional(),
|
|
24
|
-
})
|
|
25
|
-
.strict()
|
|
26
|
-
.optional();
|
|
27
|
-
|
|
28
|
-
const MarkdownConfigSchema = z
|
|
29
|
-
.object({
|
|
30
|
-
mode: z.enum(["native", "escape", "strip"]).optional(),
|
|
31
|
-
tableMode: z.enum(["native", "ascii", "simple"]).optional(),
|
|
32
|
-
})
|
|
33
|
-
.strict()
|
|
34
|
-
.optional();
|
|
35
|
-
|
|
36
|
-
// Message render mode: auto (default) = detect markdown, raw = plain text, card = always card
|
|
37
|
-
const RenderModeSchema = z.enum(["auto", "raw", "card"]).optional();
|
|
38
|
-
|
|
39
|
-
// Streaming card mode: when enabled, card replies use Feishu's Card Kit streaming API
|
|
40
|
-
// for incremental text display with a "Thinking..." placeholder
|
|
41
|
-
const StreamingModeSchema = z.boolean().optional();
|
|
42
|
-
|
|
43
|
-
const BlockStreamingCoalesceSchema = z
|
|
44
|
-
.object({
|
|
45
|
-
enabled: z.boolean().optional(),
|
|
46
|
-
minDelayMs: z.number().int().positive().optional(),
|
|
47
|
-
maxDelayMs: z.number().int().positive().optional(),
|
|
48
|
-
})
|
|
49
|
-
.strict()
|
|
50
|
-
.optional();
|
|
51
|
-
|
|
52
|
-
const ChannelHeartbeatVisibilitySchema = z
|
|
53
|
-
.object({
|
|
54
|
-
visibility: z.enum(["visible", "hidden"]).optional(),
|
|
55
|
-
intervalMs: z.number().int().positive().optional(),
|
|
56
|
-
})
|
|
57
|
-
.strict()
|
|
58
|
-
.optional();
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Dynamic agent creation configuration.
|
|
62
|
-
* When enabled, a new agent is created for each unique DM user.
|
|
63
|
-
*/
|
|
64
|
-
const DynamicAgentCreationSchema = z
|
|
65
|
-
.object({
|
|
66
|
-
enabled: z.boolean().optional(),
|
|
67
|
-
workspaceTemplate: z.string().optional(),
|
|
68
|
-
agentDirTemplate: z.string().optional(),
|
|
69
|
-
maxAgents: z.number().int().positive().optional(),
|
|
70
|
-
})
|
|
71
|
-
.strict()
|
|
72
|
-
.optional();
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Feishu tools configuration.
|
|
76
|
-
* Controls which tool categories are enabled.
|
|
77
|
-
*
|
|
78
|
-
* Dependencies:
|
|
79
|
-
* - wiki requires doc (wiki content is edited via doc tools)
|
|
80
|
-
* - perm can work independently but is typically used with drive
|
|
81
|
-
*/
|
|
82
|
-
const FeishuToolsConfigSchema = z
|
|
83
|
-
.object({
|
|
84
|
-
doc: z.boolean().optional(), // Document operations (default: true)
|
|
85
|
-
wiki: z.boolean().optional(), // Knowledge base operations (default: true, requires doc)
|
|
86
|
-
drive: z.boolean().optional(), // Cloud storage operations (default: true)
|
|
87
|
-
perm: z.boolean().optional(), // Permission management (default: false, sensitive)
|
|
88
|
-
scopes: z.boolean().optional(), // App scopes diagnostic (default: true)
|
|
89
|
-
})
|
|
90
|
-
.strict()
|
|
91
|
-
.optional();
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Topic session isolation mode for group chats.
|
|
95
|
-
* - "disabled" (default): All messages in a group share one session
|
|
96
|
-
* - "enabled": Messages in different topics get separate sessions
|
|
97
|
-
*
|
|
98
|
-
* When enabled, the session key becomes `chat:{chatId}:topic:{rootId}`
|
|
99
|
-
* for messages within a topic thread, allowing isolated conversations.
|
|
100
|
-
*/
|
|
101
|
-
const TopicSessionModeSchema = z.enum(["disabled", "enabled"]).optional();
|
|
102
|
-
|
|
103
|
-
export const FeishuGroupSchema = z
|
|
104
|
-
.object({
|
|
105
|
-
requireMention: z.boolean().optional(),
|
|
106
|
-
tools: ToolPolicySchema,
|
|
107
|
-
skills: z.array(z.string()).optional(),
|
|
108
|
-
enabled: z.boolean().optional(),
|
|
109
|
-
allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
110
|
-
systemPrompt: z.string().optional(),
|
|
111
|
-
topicSessionMode: TopicSessionModeSchema,
|
|
112
|
-
})
|
|
113
|
-
.strict();
|
|
114
|
-
|
|
115
|
-
const FeishuSharedConfigShape = {
|
|
116
|
-
webhookHost: z.string().optional(),
|
|
117
|
-
webhookPort: z.number().int().positive().optional(),
|
|
118
|
-
capabilities: z.array(z.string()).optional(),
|
|
119
|
-
markdown: MarkdownConfigSchema,
|
|
120
|
-
configWrites: z.boolean().optional(),
|
|
121
|
-
dmPolicy: DmPolicySchema.optional(),
|
|
122
|
-
allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
123
|
-
groupPolicy: GroupPolicySchema.optional(),
|
|
124
|
-
groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
125
|
-
requireMention: z.boolean().optional(),
|
|
126
|
-
groups: z.record(z.string(), FeishuGroupSchema.optional()).optional(),
|
|
127
|
-
historyLimit: z.number().int().min(0).optional(),
|
|
128
|
-
dmHistoryLimit: z.number().int().min(0).optional(),
|
|
129
|
-
dms: z.record(z.string(), DmConfigSchema).optional(),
|
|
130
|
-
textChunkLimit: z.number().int().positive().optional(),
|
|
131
|
-
chunkMode: z.enum(["length", "newline"]).optional(),
|
|
132
|
-
blockStreamingCoalesce: BlockStreamingCoalesceSchema,
|
|
133
|
-
mediaMaxMb: z.number().positive().optional(),
|
|
134
|
-
heartbeat: ChannelHeartbeatVisibilitySchema,
|
|
135
|
-
renderMode: RenderModeSchema,
|
|
136
|
-
streaming: StreamingModeSchema,
|
|
137
|
-
tools: FeishuToolsConfigSchema,
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Per-account configuration.
|
|
142
|
-
* All fields are optional - missing fields inherit from top-level config.
|
|
143
|
-
*/
|
|
144
|
-
export const FeishuAccountConfigSchema = z
|
|
145
|
-
.object({
|
|
146
|
-
enabled: z.boolean().optional(),
|
|
147
|
-
name: z.string().optional(), // Display name for this account
|
|
148
|
-
appId: z.string().optional(),
|
|
149
|
-
appSecret: z.string().optional(),
|
|
150
|
-
encryptKey: z.string().optional(),
|
|
151
|
-
verificationToken: z.string().optional(),
|
|
152
|
-
domain: FeishuDomainSchema.optional(),
|
|
153
|
-
connectionMode: FeishuConnectionModeSchema.optional(),
|
|
154
|
-
webhookPath: z.string().optional(),
|
|
155
|
-
...FeishuSharedConfigShape,
|
|
156
|
-
})
|
|
157
|
-
.strict();
|
|
158
|
-
|
|
159
|
-
export const FeishuConfigSchema = z
|
|
160
|
-
.object({
|
|
161
|
-
enabled: z.boolean().optional(),
|
|
162
|
-
// Top-level credentials (backward compatible for single-account mode)
|
|
163
|
-
appId: z.string().optional(),
|
|
164
|
-
appSecret: z.string().optional(),
|
|
165
|
-
encryptKey: z.string().optional(),
|
|
166
|
-
verificationToken: z.string().optional(),
|
|
167
|
-
domain: FeishuDomainSchema.optional().default("feishu"),
|
|
168
|
-
connectionMode: FeishuConnectionModeSchema.optional().default("websocket"),
|
|
169
|
-
webhookPath: z.string().optional().default("/feishu/events"),
|
|
170
|
-
...FeishuSharedConfigShape,
|
|
171
|
-
dmPolicy: DmPolicySchema.optional().default("pairing"),
|
|
172
|
-
groupPolicy: GroupPolicySchema.optional().default("allowlist"),
|
|
173
|
-
requireMention: z.boolean().optional().default(true),
|
|
174
|
-
topicSessionMode: TopicSessionModeSchema,
|
|
175
|
-
// Dynamic agent creation for DM users
|
|
176
|
-
dynamicAgentCreation: DynamicAgentCreationSchema,
|
|
177
|
-
// Multi-account configuration
|
|
178
|
-
accounts: z.record(z.string(), FeishuAccountConfigSchema.optional()).optional(),
|
|
179
|
-
})
|
|
180
|
-
.strict()
|
|
181
|
-
.superRefine((value, ctx) => {
|
|
182
|
-
const defaultConnectionMode = value.connectionMode ?? "websocket";
|
|
183
|
-
const defaultVerificationToken = value.verificationToken?.trim();
|
|
184
|
-
if (defaultConnectionMode === "webhook" && !defaultVerificationToken) {
|
|
185
|
-
ctx.addIssue({
|
|
186
|
-
code: z.ZodIssueCode.custom,
|
|
187
|
-
path: ["verificationToken"],
|
|
188
|
-
message:
|
|
189
|
-
'channels.feishu.connectionMode="webhook" requires channels.feishu.verificationToken',
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
for (const [accountId, account] of Object.entries(value.accounts ?? {})) {
|
|
194
|
-
if (!account) {
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
const accountConnectionMode = account.connectionMode ?? defaultConnectionMode;
|
|
198
|
-
if (accountConnectionMode !== "webhook") {
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
const accountVerificationToken =
|
|
202
|
-
account.verificationToken?.trim() || defaultVerificationToken;
|
|
203
|
-
if (!accountVerificationToken) {
|
|
204
|
-
ctx.addIssue({
|
|
205
|
-
code: z.ZodIssueCode.custom,
|
|
206
|
-
path: ["accounts", accountId, "verificationToken"],
|
|
207
|
-
message:
|
|
208
|
-
`channels.feishu.accounts.${accountId}.connectionMode="webhook" requires ` +
|
|
209
|
-
"a verificationToken (account-level or top-level)",
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (value.dmPolicy === "open") {
|
|
215
|
-
const allowFrom = value.allowFrom ?? [];
|
|
216
|
-
const hasWildcard = allowFrom.some((entry) => String(entry).trim() === "*");
|
|
217
|
-
if (!hasWildcard) {
|
|
218
|
-
ctx.addIssue({
|
|
219
|
-
code: z.ZodIssueCode.custom,
|
|
220
|
-
path: ["allowFrom"],
|
|
221
|
-
message:
|
|
222
|
-
'channels.feishu.dmPolicy="open" requires channels.feishu.allowFrom to include "*"',
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
});
|