@xopcai/xopc 0.0.14 → 0.0.16
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/dist/extensions/feishu/src/adapters/onboard-cli.d.ts +7 -0
- package/dist/extensions/feishu/src/adapters/onboard-cli.js +432 -0
- package/dist/extensions/feishu/src/adapters/onboard-cli.js.map +1 -0
- package/dist/extensions/feishu/src/auth/pairing.d.ts +7 -0
- package/dist/extensions/feishu/src/auth/pairing.js +45 -0
- package/dist/extensions/feishu/src/auth/pairing.js.map +1 -0
- package/dist/extensions/feishu/src/auth/paths.d.ts +2 -0
- package/dist/extensions/feishu/src/auth/paths.js +18 -0
- package/dist/extensions/feishu/src/auth/paths.js.map +1 -0
- package/dist/extensions/feishu/src/directory/directory-adapter.d.ts +2 -0
- package/dist/extensions/feishu/src/directory/directory-adapter.js +27 -0
- package/dist/extensions/feishu/src/directory/directory-adapter.js.map +1 -0
- package/dist/extensions/feishu/src/format.d.ts +21 -0
- package/dist/extensions/feishu/src/format.js +99 -0
- package/dist/extensions/feishu/src/format.js.map +1 -0
- package/dist/extensions/feishu/src/index.d.ts +5 -0
- package/dist/extensions/feishu/src/index.js +3 -0
- package/dist/extensions/feishu/src/outbound/actions.d.ts +51 -0
- package/dist/extensions/feishu/src/outbound/actions.js +62 -0
- package/dist/extensions/feishu/src/outbound/actions.js.map +1 -0
- package/dist/extensions/feishu/src/outbound/media-load.d.ts +12 -0
- package/dist/extensions/feishu/src/outbound/media-load.js +125 -0
- package/dist/extensions/feishu/src/outbound/media-load.js.map +1 -0
- package/dist/extensions/feishu/src/outbound/outbound-adapter.d.ts +2 -0
- package/dist/extensions/feishu/src/outbound/outbound-adapter.js +201 -0
- package/dist/extensions/feishu/src/outbound/outbound-adapter.js.map +1 -0
- package/dist/extensions/feishu/src/plugin.d.ts +70 -0
- package/dist/extensions/feishu/src/plugin.js +313 -0
- package/dist/extensions/feishu/src/plugin.js.map +1 -0
- package/dist/extensions/feishu/src/schema/config-schema.d.ts +215 -0
- package/dist/extensions/feishu/src/schema/config-schema.js +198 -0
- package/dist/extensions/feishu/src/schema/config-schema.js.map +1 -0
- package/dist/extensions/feishu/src/state/accounts.d.ts +38 -0
- package/dist/extensions/feishu/src/state/accounts.js +96 -0
- package/dist/extensions/feishu/src/state/accounts.js.map +1 -0
- package/dist/extensions/feishu/src/state/message-bindings.d.ts +11 -0
- package/dist/extensions/feishu/src/state/message-bindings.js +41 -0
- package/dist/extensions/feishu/src/state/message-bindings.js.map +1 -0
- package/dist/extensions/feishu/src/state/thread-bindings.js +46 -0
- package/dist/extensions/feishu/src/state/thread-bindings.js.map +1 -0
- package/dist/extensions/feishu/src/status/doctor.d.ts +2 -0
- package/dist/extensions/feishu/src/status/doctor.js +38 -0
- package/dist/extensions/feishu/src/status/doctor.js.map +1 -0
- package/dist/extensions/feishu/src/status/status-adapter.d.ts +3 -0
- package/dist/extensions/feishu/src/status/status-adapter.js +45 -0
- package/dist/extensions/feishu/src/status/status-adapter.js.map +1 -0
- package/dist/extensions/feishu/src/streaming/streaming-adapter.d.ts +3 -0
- package/dist/extensions/feishu/src/streaming/streaming-adapter.js +242 -0
- package/dist/extensions/feishu/src/streaming/streaming-adapter.js.map +1 -0
- package/dist/extensions/feishu/src/subagent-hooks.js +52 -0
- package/dist/extensions/feishu/src/subagent-hooks.js.map +1 -0
- package/dist/extensions/feishu/src/tools/docx/docx-batch-insert.js +95 -0
- package/dist/extensions/feishu/src/tools/docx/docx-batch-insert.js.map +1 -0
- package/dist/extensions/feishu/src/tools/docx/docx-color-text.js +75 -0
- package/dist/extensions/feishu/src/tools/docx/docx-color-text.js.map +1 -0
- package/dist/extensions/feishu/src/tools/docx/docx-table-ops.js +173 -0
- package/dist/extensions/feishu/src/tools/docx/docx-table-ops.js.map +1 -0
- package/dist/extensions/feishu/src/tools/docx/docx-types.js +1 -0
- package/dist/extensions/feishu/src/tools/tools.d.ts +5 -0
- package/dist/extensions/feishu/src/tools/tools.js +46 -0
- package/dist/extensions/feishu/src/tools/tools.js.map +1 -0
- package/dist/extensions/feishu/src/transport/client/client.d.ts +6 -0
- package/dist/extensions/feishu/src/transport/client/client.js +41 -0
- package/dist/extensions/feishu/src/transport/client/client.js.map +1 -0
- package/dist/extensions/feishu/src/transport/client/lark-sdk-logger.d.ts +13 -0
- package/dist/extensions/feishu/src/transport/client/lark-sdk-logger.js +104 -0
- package/dist/extensions/feishu/src/transport/client/lark-sdk-logger.js.map +1 -0
- package/dist/extensions/feishu/src/transport/reliability/dedupe.d.ts +7 -0
- package/dist/extensions/feishu/src/transport/reliability/dedupe.js +30 -0
- package/dist/extensions/feishu/src/transport/reliability/dedupe.js.map +1 -0
- package/dist/extensions/feishu/src/transport/socket-mode/monitor.d.ts +19 -0
- package/dist/extensions/feishu/src/transport/socket-mode/monitor.js +326 -0
- package/dist/extensions/feishu/src/transport/socket-mode/monitor.js.map +1 -0
- package/dist/extensions/feishu/src/transport/socket-mode/retry.d.ts +1 -0
- package/dist/extensions/feishu/src/transport/socket-mode/retry.js +10 -0
- package/dist/extensions/feishu/src/transport/socket-mode/retry.js.map +1 -0
- package/dist/extensions/feishu/src/transport/text/mentions.d.ts +1 -0
- package/dist/extensions/feishu/src/transport/text/mentions.js +9 -0
- package/dist/extensions/feishu/src/transport/text/mentions.js.map +1 -0
- package/dist/extensions/feishu/src/transport/webhook/monitor.d.ts +19 -0
- package/dist/extensions/feishu/src/transport/webhook/monitor.js +271 -0
- package/dist/extensions/feishu/src/transport/webhook/monitor.js.map +1 -0
- package/dist/extensions/feishu/src/ui/config-surface.d.ts +2 -0
- package/dist/extensions/feishu/src/ui/config-surface.js +6 -0
- package/dist/extensions/feishu/src/ui/config-surface.js.map +1 -0
- package/dist/extensions/feishu/xopc.extension.json +18 -0
- package/dist/extensions/telegram/xopc.extension.json +20 -0
- package/dist/extensions/weixin/xopc.extension.json +17 -0
- package/dist/gateway/static/root/assets/{agents-C2blSFQk.js → agents-Dy5cGVVQ.js} +2 -2
- package/dist/gateway/static/root/assets/{agents-C2blSFQk.js.map → agents-Dy5cGVVQ.js.map} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-Dg7InQ41.js → apps-page-BOpDR0Lz.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-Dg7InQ41.js.map → apps-page-BOpDR0Lz.js.map} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-CrCesccB.js +9 -0
- package/dist/gateway/static/root/assets/channels-settings-CrCesccB.js.map +1 -0
- package/dist/gateway/static/root/assets/{cron-page-B-7O4_QQ.js → cron-page-B_XY0gPt.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-B-7O4_QQ.js.map → cron-page-B_XY0gPt.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-utils-DvRPM814.js → cron-utils-BYdnLwhl.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-DvRPM814.js.map → cron-utils-BYdnLwhl.js.map} +1 -1
- package/dist/gateway/static/root/assets/{dist-DYzyRkRh.js → dist-DvaA5uNp.js} +2 -2
- package/dist/gateway/static/root/assets/{dist-DYzyRkRh.js.map → dist-DvaA5uNp.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DV-NwlaY.js → extension-debug-page-CPSk7gFW.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-DV-NwlaY.js.map → extension-debug-page-CPSk7gFW.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-UUKLJwpo.js → extension-page-COdbk9I6.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-UUKLJwpo.js.map → extension-page-COdbk9I6.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-R4VlbZOj.js → extension-settings-page-BlEz2Ily.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-R4VlbZOj.js.map → extension-settings-page-BlEz2Ily.js.map} +1 -1
- package/dist/gateway/static/root/assets/index-BQNdJlkw.css +1 -0
- package/dist/gateway/static/root/assets/index-tm9ZY35l.js +144 -0
- package/dist/gateway/static/root/assets/{index-BCVqNi5T.js.map → index-tm9ZY35l.js.map} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-BgUDjMge.js → logs-page-LSa0jmLO.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-BgUDjMge.js.map → logs-page-LSa0jmLO.js.map} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-cn2fi_V3.js +2 -0
- package/dist/gateway/static/root/assets/sessions-page-cn2fi_V3.js.map +1 -0
- package/dist/gateway/static/root/assets/{settings-page-Doa_lzdW.js → settings-page-CyHd5szQ.js} +2 -2
- package/dist/gateway/static/root/assets/{settings-page-Doa_lzdW.js.map → settings-page-CyHd5szQ.js.map} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-BdNqg2NG.js → skills-page-irjxwW9u.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-BdNqg2NG.js.map → skills-page-irjxwW9u.js.map} +1 -1
- package/dist/gateway/static/root/channel-icons/feishu.svg +12 -0
- package/dist/gateway/static/root/channel-icons/lark.svg +12 -0
- package/dist/gateway/static/root/channel-icons/telegram.svg +1 -0
- package/dist/gateway/static/root/channel-icons/wechat.svg +1 -0
- package/dist/gateway/static/root/channel-icons/weixin.svg +1 -0
- package/dist/gateway/static/root/index.html +2 -2
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +1 -0
- package/dist/src/agent/agent-manager.js +1 -0
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/service.js +3 -0
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/delegate-tool.d.ts +8 -0
- package/dist/src/agent/tools/delegate-tool.js +60 -2
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +1 -0
- package/dist/src/agent/tools/factory.js +2 -0
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/channels/envelope-timestamp.d.ts +5 -0
- package/dist/src/channels/envelope-timestamp.js +10 -1
- package/dist/src/channels/envelope-timestamp.js.map +1 -1
- package/dist/src/channels/feishu/index.d.ts +5 -0
- package/dist/src/channels/feishu/index.js +4 -0
- package/dist/src/chat-commands/types.d.ts +1 -1
- package/dist/src/extensions/types/hooks.d.ts +46 -1
- package/dist/src/extensions/types/hooks.js +3 -0
- package/dist/src/extensions/types/hooks.js.map +1 -1
- package/dist/src/gateway/service.js +1 -1
- package/dist/src/generated/bundled-channel-plugins.d.ts +2 -1
- package/dist/src/generated/bundled-channel-plugins.js +8 -2
- package/dist/src/generated/bundled-channel-plugins.js.map +1 -1
- package/dist/src/providers/env-keys.js +1 -0
- package/dist/src/providers/env-keys.js.map +1 -1
- package/dist/src/providers/index.js +5 -0
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/session/session-title.js +2 -1
- package/dist/src/session/session-title.js.map +1 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/channels-settings-CHOL7G_P.js +0 -9
- package/dist/gateway/static/root/assets/channels-settings-CHOL7G_P.js.map +0 -1
- package/dist/gateway/static/root/assets/index-BCVqNi5T.js +0 -144
- package/dist/gateway/static/root/assets/index-XbYityMf.css +0 -1
- package/dist/gateway/static/root/assets/sessions-page-L2VUocA4.js +0 -2
- package/dist/gateway/static/root/assets/sessions-page-L2VUocA4.js.map +0 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region extensions/feishu/src/schema/config-schema.ts
|
|
3
|
+
const FeishuAccountConfigSchema = z.object({
|
|
4
|
+
name: z.string().optional(),
|
|
5
|
+
enabled: z.boolean().optional(),
|
|
6
|
+
/** Feishu app credentials */
|
|
7
|
+
appId: z.string().optional(),
|
|
8
|
+
appSecret: z.string().optional(),
|
|
9
|
+
/** feishu | lark | https://open.feishu.cn (custom base) */
|
|
10
|
+
domain: z.union([z.enum(["feishu", "lark"]), z.string().url()]).optional(),
|
|
11
|
+
/** Socket Mode is the default transport in xopc. */
|
|
12
|
+
connectionMode: z.enum(["websocket", "webhook"]).default("websocket").optional(),
|
|
13
|
+
/** Webhook mode transport config (openclaw parity). */
|
|
14
|
+
webhookHost: z.string().optional(),
|
|
15
|
+
webhookPort: z.number().int().positive().optional(),
|
|
16
|
+
webhookPath: z.string().optional(),
|
|
17
|
+
/** Webhook mode secrets (openclaw parity). */
|
|
18
|
+
verificationToken: z.string().optional(),
|
|
19
|
+
encryptKey: z.string().optional(),
|
|
20
|
+
/** Access control */
|
|
21
|
+
dmPolicy: z.enum([
|
|
22
|
+
"pairing",
|
|
23
|
+
"allowlist",
|
|
24
|
+
"open",
|
|
25
|
+
"disabled"
|
|
26
|
+
]).default("pairing").optional(),
|
|
27
|
+
groupPolicy: z.enum([
|
|
28
|
+
"open",
|
|
29
|
+
"disabled",
|
|
30
|
+
"allowlist"
|
|
31
|
+
]).default("allowlist").optional(),
|
|
32
|
+
allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
33
|
+
groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
34
|
+
requireMention: z.boolean().optional(),
|
|
35
|
+
/** Messaging */
|
|
36
|
+
historyLimit: z.number().int().min(0).optional(),
|
|
37
|
+
textChunkLimit: z.number().int().positive().optional(),
|
|
38
|
+
renderMode: z.enum([
|
|
39
|
+
"auto",
|
|
40
|
+
"raw",
|
|
41
|
+
"card"
|
|
42
|
+
]).optional(),
|
|
43
|
+
replyInThread: z.enum(["disabled", "enabled"]).optional(),
|
|
44
|
+
typingIndicator: z.boolean().optional(),
|
|
45
|
+
reactionNotifications: z.enum([
|
|
46
|
+
"off",
|
|
47
|
+
"own",
|
|
48
|
+
"all"
|
|
49
|
+
]).optional(),
|
|
50
|
+
/** Streaming */
|
|
51
|
+
streaming: z.boolean().optional(),
|
|
52
|
+
blockStreamingCoalesce: z.object({
|
|
53
|
+
enabled: z.boolean().optional(),
|
|
54
|
+
minChars: z.number().int().positive().optional(),
|
|
55
|
+
idleMs: z.number().int().positive().optional()
|
|
56
|
+
}).strict().optional(),
|
|
57
|
+
/** Tool gates (parity surface; implementations come later) */
|
|
58
|
+
tools: z.object({
|
|
59
|
+
doc: z.boolean().optional(),
|
|
60
|
+
chat: z.boolean().optional(),
|
|
61
|
+
wiki: z.boolean().optional(),
|
|
62
|
+
drive: z.boolean().optional(),
|
|
63
|
+
perm: z.boolean().optional(),
|
|
64
|
+
bitable: z.boolean().optional(),
|
|
65
|
+
scopes: z.boolean().optional()
|
|
66
|
+
}).strict().optional(),
|
|
67
|
+
actions: z.object({ reactions: z.boolean().optional() }).strict().optional(),
|
|
68
|
+
/** Dynamic agent creation for DMs (parity surface; core wiring comes later) */
|
|
69
|
+
dynamicAgentCreation: z.object({
|
|
70
|
+
enabled: z.boolean().optional(),
|
|
71
|
+
workspaceTemplate: z.string().optional(),
|
|
72
|
+
agentDirTemplate: z.string().optional(),
|
|
73
|
+
maxAgents: z.number().int().positive().optional()
|
|
74
|
+
}).strict().optional()
|
|
75
|
+
});
|
|
76
|
+
const FeishuConfigSchema = z.object({
|
|
77
|
+
enabled: z.boolean().default(false),
|
|
78
|
+
defaultAccount: z.string().optional(),
|
|
79
|
+
/** Single-account shorthand (backward compatible in our own schema) */
|
|
80
|
+
appId: z.string().optional(),
|
|
81
|
+
appSecret: z.string().optional(),
|
|
82
|
+
domain: z.union([z.enum(["feishu", "lark"]), z.string().url()]).default("feishu").optional(),
|
|
83
|
+
connectionMode: z.enum(["websocket", "webhook"]).default("websocket").optional(),
|
|
84
|
+
webhookHost: z.string().optional(),
|
|
85
|
+
webhookPort: z.number().int().positive().optional(),
|
|
86
|
+
webhookPath: z.string().optional(),
|
|
87
|
+
verificationToken: z.string().optional(),
|
|
88
|
+
encryptKey: z.string().optional(),
|
|
89
|
+
dmPolicy: z.enum([
|
|
90
|
+
"pairing",
|
|
91
|
+
"allowlist",
|
|
92
|
+
"open",
|
|
93
|
+
"disabled"
|
|
94
|
+
]).default("pairing").optional(),
|
|
95
|
+
groupPolicy: z.enum([
|
|
96
|
+
"open",
|
|
97
|
+
"disabled",
|
|
98
|
+
"allowlist"
|
|
99
|
+
]).default("allowlist").optional(),
|
|
100
|
+
allowFrom: z.array(z.union([z.string(), z.number()])).default([]).optional(),
|
|
101
|
+
groupAllowFrom: z.array(z.union([z.string(), z.number()])).default([]).optional(),
|
|
102
|
+
requireMention: z.boolean().optional(),
|
|
103
|
+
historyLimit: z.number().int().min(0).default(50).optional(),
|
|
104
|
+
textChunkLimit: z.number().int().positive().default(4e3).optional(),
|
|
105
|
+
reactionNotifications: z.enum([
|
|
106
|
+
"off",
|
|
107
|
+
"own",
|
|
108
|
+
"all"
|
|
109
|
+
]).optional(),
|
|
110
|
+
streaming: z.boolean().optional(),
|
|
111
|
+
blockStreamingCoalesce: z.object({
|
|
112
|
+
enabled: z.boolean().optional(),
|
|
113
|
+
minChars: z.number().int().positive().optional(),
|
|
114
|
+
idleMs: z.number().int().positive().optional()
|
|
115
|
+
}).strict().optional(),
|
|
116
|
+
tools: z.object({
|
|
117
|
+
doc: z.boolean().optional(),
|
|
118
|
+
chat: z.boolean().optional(),
|
|
119
|
+
wiki: z.boolean().optional(),
|
|
120
|
+
drive: z.boolean().optional(),
|
|
121
|
+
perm: z.boolean().optional(),
|
|
122
|
+
bitable: z.boolean().optional(),
|
|
123
|
+
scopes: z.boolean().optional()
|
|
124
|
+
}).strict().optional(),
|
|
125
|
+
actions: z.object({ reactions: z.boolean().optional() }).strict().optional(),
|
|
126
|
+
dynamicAgentCreation: z.object({
|
|
127
|
+
enabled: z.boolean().optional(),
|
|
128
|
+
workspaceTemplate: z.string().optional(),
|
|
129
|
+
agentDirTemplate: z.string().optional(),
|
|
130
|
+
maxAgents: z.number().int().positive().optional()
|
|
131
|
+
}).strict().optional(),
|
|
132
|
+
accounts: z.record(z.string(), FeishuAccountConfigSchema).optional()
|
|
133
|
+
}).superRefine((value, ctx) => {
|
|
134
|
+
if (value.enabled) {
|
|
135
|
+
if (!(value.accounts && Object.keys(value.accounts).length > 0)) {
|
|
136
|
+
if (!value.appId?.trim()) ctx.addIssue({
|
|
137
|
+
code: z.ZodIssueCode.custom,
|
|
138
|
+
path: ["appId"],
|
|
139
|
+
message: "channels.feishu.enabled=true requires channels.feishu.appId (or configure channels.feishu.accounts)"
|
|
140
|
+
});
|
|
141
|
+
if (!value.appSecret?.trim()) ctx.addIssue({
|
|
142
|
+
code: z.ZodIssueCode.custom,
|
|
143
|
+
path: ["appSecret"],
|
|
144
|
+
message: "channels.feishu.enabled=true requires channels.feishu.appSecret (or configure channels.feishu.accounts)"
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (const [id, acc] of Object.entries(value.accounts ?? {})) {
|
|
149
|
+
if (!acc) continue;
|
|
150
|
+
if (acc.enabled === false) continue;
|
|
151
|
+
const effectiveAppId = acc.appId?.trim() || value.appId?.trim() || "";
|
|
152
|
+
const effectiveAppSecret = acc.appSecret?.trim() || value.appSecret?.trim() || "";
|
|
153
|
+
if (!effectiveAppId) ctx.addIssue({
|
|
154
|
+
code: z.ZodIssueCode.custom,
|
|
155
|
+
path: [
|
|
156
|
+
"accounts",
|
|
157
|
+
id,
|
|
158
|
+
"appId"
|
|
159
|
+
],
|
|
160
|
+
message: `channels.feishu.accounts.${id} requires appId (or top-level channels.feishu.appId)`
|
|
161
|
+
});
|
|
162
|
+
if (!effectiveAppSecret) ctx.addIssue({
|
|
163
|
+
code: z.ZodIssueCode.custom,
|
|
164
|
+
path: [
|
|
165
|
+
"accounts",
|
|
166
|
+
id,
|
|
167
|
+
"appSecret"
|
|
168
|
+
],
|
|
169
|
+
message: `channels.feishu.accounts.${id} requires appSecret (or top-level channels.feishu.appSecret)`
|
|
170
|
+
});
|
|
171
|
+
if ((acc.connectionMode ?? value.connectionMode ?? "websocket") === "webhook") {
|
|
172
|
+
const vt = acc.verificationToken?.trim() || value.verificationToken?.trim() || "";
|
|
173
|
+
const ek = acc.encryptKey?.trim() || value.encryptKey?.trim() || "";
|
|
174
|
+
if (!vt) ctx.addIssue({
|
|
175
|
+
code: z.ZodIssueCode.custom,
|
|
176
|
+
path: [
|
|
177
|
+
"accounts",
|
|
178
|
+
id,
|
|
179
|
+
"verificationToken"
|
|
180
|
+
],
|
|
181
|
+
message: `channels.feishu.accounts.${id} webhook mode requires verificationToken (or top-level channels.feishu.verificationToken)`
|
|
182
|
+
});
|
|
183
|
+
if (!ek) ctx.addIssue({
|
|
184
|
+
code: z.ZodIssueCode.custom,
|
|
185
|
+
path: [
|
|
186
|
+
"accounts",
|
|
187
|
+
id,
|
|
188
|
+
"encryptKey"
|
|
189
|
+
],
|
|
190
|
+
message: `channels.feishu.accounts.${id} webhook mode requires encryptKey (or top-level channels.feishu.encryptKey)`
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
//#endregion
|
|
196
|
+
export { FeishuAccountConfigSchema, FeishuConfigSchema };
|
|
197
|
+
|
|
198
|
+
//# sourceMappingURL=config-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema.js","names":[],"sources":["../../../../../extensions/feishu/src/schema/config-schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const FeishuAccountConfigSchema = z.object({\n name: z.string().optional(),\n enabled: z.boolean().optional(),\n\n /** Feishu app credentials */\n appId: z.string().optional(),\n appSecret: z.string().optional(),\n\n /** feishu | lark | https://open.feishu.cn (custom base) */\n domain: z.union([z.enum(['feishu', 'lark']), z.string().url()]).optional(),\n\n /** Socket Mode is the default transport in xopc. */\n connectionMode: z.enum(['websocket', 'webhook']).default('websocket').optional(),\n\n /** Webhook mode transport config (openclaw parity). */\n webhookHost: z.string().optional(),\n webhookPort: z.number().int().positive().optional(),\n webhookPath: z.string().optional(),\n\n /** Webhook mode secrets (openclaw parity). */\n verificationToken: z.string().optional(),\n encryptKey: z.string().optional(),\n\n /** Access control */\n dmPolicy: z.enum(['pairing', 'allowlist', 'open', 'disabled']).default('pairing').optional(),\n groupPolicy: z.enum(['open', 'disabled', 'allowlist']).default('allowlist').optional(),\n allowFrom: z.array(z.union([z.string(), z.number()])).optional(),\n groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),\n requireMention: z.boolean().optional(),\n\n /** Messaging */\n historyLimit: z.number().int().min(0).optional(),\n textChunkLimit: z.number().int().positive().optional(),\n renderMode: z.enum(['auto', 'raw', 'card']).optional(),\n replyInThread: z.enum(['disabled', 'enabled']).optional(),\n typingIndicator: z.boolean().optional(),\n reactionNotifications: z.enum(['off', 'own', 'all']).optional(),\n\n /** Streaming */\n streaming: z.boolean().optional(),\n blockStreamingCoalesce: z\n .object({\n enabled: z.boolean().optional(),\n minChars: z.number().int().positive().optional(),\n idleMs: z.number().int().positive().optional(),\n })\n .strict()\n .optional(),\n\n /** Tool gates (parity surface; implementations come later) */\n tools: z\n .object({\n doc: z.boolean().optional(),\n chat: z.boolean().optional(),\n wiki: z.boolean().optional(),\n drive: z.boolean().optional(),\n perm: z.boolean().optional(),\n bitable: z.boolean().optional(),\n scopes: z.boolean().optional(),\n })\n .strict()\n .optional(),\n\n actions: z\n .object({\n reactions: z.boolean().optional(),\n })\n .strict()\n .optional(),\n\n /** Dynamic agent creation for DMs (parity surface; core wiring comes later) */\n dynamicAgentCreation: z\n .object({\n enabled: z.boolean().optional(),\n workspaceTemplate: z.string().optional(),\n agentDirTemplate: z.string().optional(),\n maxAgents: z.number().int().positive().optional(),\n })\n .strict()\n .optional(),\n});\n\nexport const FeishuConfigSchema = z\n .object({\n enabled: z.boolean().default(false),\n\n defaultAccount: z.string().optional(),\n\n /** Single-account shorthand (backward compatible in our own schema) */\n appId: z.string().optional(),\n appSecret: z.string().optional(),\n domain: z.union([z.enum(['feishu', 'lark']), z.string().url()]).default('feishu').optional(),\n connectionMode: z.enum(['websocket', 'webhook']).default('websocket').optional(),\n\n webhookHost: z.string().optional(),\n webhookPort: z.number().int().positive().optional(),\n webhookPath: z.string().optional(),\n verificationToken: z.string().optional(),\n encryptKey: z.string().optional(),\n\n dmPolicy: z.enum(['pairing', 'allowlist', 'open', 'disabled']).default('pairing').optional(),\n groupPolicy: z.enum(['open', 'disabled', 'allowlist']).default('allowlist').optional(),\n allowFrom: z.array(z.union([z.string(), z.number()])).default([]).optional(),\n groupAllowFrom: z.array(z.union([z.string(), z.number()])).default([]).optional(),\n requireMention: z.boolean().optional(),\n\n historyLimit: z.number().int().min(0).default(50).optional(),\n textChunkLimit: z.number().int().positive().default(4000).optional(),\n reactionNotifications: z.enum(['off', 'own', 'all']).optional(),\n\n streaming: z.boolean().optional(),\n blockStreamingCoalesce: z\n .object({\n enabled: z.boolean().optional(),\n minChars: z.number().int().positive().optional(),\n idleMs: z.number().int().positive().optional(),\n })\n .strict()\n .optional(),\n\n tools: z\n .object({\n doc: z.boolean().optional(),\n chat: z.boolean().optional(),\n wiki: z.boolean().optional(),\n drive: z.boolean().optional(),\n perm: z.boolean().optional(),\n bitable: z.boolean().optional(),\n scopes: z.boolean().optional(),\n })\n .strict()\n .optional(),\n\n actions: z\n .object({\n reactions: z.boolean().optional(),\n })\n .strict()\n .optional(),\n\n dynamicAgentCreation: z\n .object({\n enabled: z.boolean().optional(),\n workspaceTemplate: z.string().optional(),\n agentDirTemplate: z.string().optional(),\n maxAgents: z.number().int().positive().optional(),\n })\n .strict()\n .optional(),\n\n accounts: z.record(z.string(), FeishuAccountConfigSchema).optional(),\n})\n .superRefine((value, ctx) => {\n // Single-account layout required fields when enabled.\n if (value.enabled) {\n const hasNamed = value.accounts && Object.keys(value.accounts).length > 0;\n if (!hasNamed) {\n if (!value.appId?.trim()) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['appId'],\n message: 'channels.feishu.enabled=true requires channels.feishu.appId (or configure channels.feishu.accounts)',\n });\n }\n if (!value.appSecret?.trim()) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['appSecret'],\n message:\n 'channels.feishu.enabled=true requires channels.feishu.appSecret (or configure channels.feishu.accounts)',\n });\n }\n }\n }\n\n // Multi-account required fields when account is enabled.\n for (const [id, acc] of Object.entries(value.accounts ?? {})) {\n if (!acc) continue;\n if (acc.enabled === false) continue;\n const effectiveAppId = acc.appId?.trim() || value.appId?.trim() || '';\n const effectiveAppSecret = acc.appSecret?.trim() || value.appSecret?.trim() || '';\n if (!effectiveAppId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['accounts', id, 'appId'],\n message: `channels.feishu.accounts.${id} requires appId (or top-level channels.feishu.appId)`,\n });\n }\n if (!effectiveAppSecret) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['accounts', id, 'appSecret'],\n message: `channels.feishu.accounts.${id} requires appSecret (or top-level channels.feishu.appSecret)`,\n });\n }\n\n const effectiveConnectionMode = (acc.connectionMode ?? value.connectionMode ?? 'websocket') as\n | 'websocket'\n | 'webhook';\n if (effectiveConnectionMode === 'webhook') {\n const vt = acc.verificationToken?.trim() || value.verificationToken?.trim() || '';\n const ek = acc.encryptKey?.trim() || value.encryptKey?.trim() || '';\n if (!vt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['accounts', id, 'verificationToken'],\n message: `channels.feishu.accounts.${id} webhook mode requires verificationToken (or top-level channels.feishu.verificationToken)`,\n });\n }\n if (!ek) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['accounts', id, 'encryptKey'],\n message: `channels.feishu.accounts.${id} webhook mode requires encryptKey (or top-level channels.feishu.encryptKey)`,\n });\n }\n }\n }\n });\n\nexport type FeishuConfig = z.infer<typeof FeishuConfigSchema>;\nexport type FeishuAccountConfig = z.infer<typeof FeishuAccountConfigSchema>;\n\n"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Config } from '@xopcai/xopc/config/schema.js';
|
|
2
|
+
import type { FeishuConfig } from '../schema/config-schema.js';
|
|
3
|
+
export interface ResolvedFeishuAccount {
|
|
4
|
+
accountId: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
configured: boolean;
|
|
8
|
+
appId?: string;
|
|
9
|
+
appSecret?: string;
|
|
10
|
+
domain: 'feishu' | 'lark' | string;
|
|
11
|
+
connectionMode: 'websocket' | 'webhook';
|
|
12
|
+
webhookHost?: string;
|
|
13
|
+
webhookPort?: number;
|
|
14
|
+
webhookPath?: string;
|
|
15
|
+
verificationToken?: string;
|
|
16
|
+
encryptKey?: string;
|
|
17
|
+
dmPolicy: 'pairing' | 'allowlist' | 'open' | 'disabled';
|
|
18
|
+
groupPolicy: 'open' | 'disabled' | 'allowlist';
|
|
19
|
+
allowFrom?: Array<string | number>;
|
|
20
|
+
groupAllowFrom?: Array<string | number>;
|
|
21
|
+
requireMention?: boolean;
|
|
22
|
+
historyLimit: number;
|
|
23
|
+
textChunkLimit: number;
|
|
24
|
+
renderMode?: 'auto' | 'raw' | 'card';
|
|
25
|
+
reactionNotifications?: 'off' | 'own' | 'all';
|
|
26
|
+
/** Opt-in: only `true` enables Feishu streaming (Thinking… + incremental updates). */
|
|
27
|
+
streaming: boolean;
|
|
28
|
+
blockStreamingCoalesce?: {
|
|
29
|
+
enabled?: boolean;
|
|
30
|
+
minChars?: number;
|
|
31
|
+
idleMs?: number;
|
|
32
|
+
};
|
|
33
|
+
tools?: FeishuConfig['tools'];
|
|
34
|
+
actions?: FeishuConfig['actions'];
|
|
35
|
+
dynamicAgentCreation?: FeishuConfig['dynamicAgentCreation'];
|
|
36
|
+
}
|
|
37
|
+
export declare function listFeishuAccountIds(cfg: Config): string[];
|
|
38
|
+
export declare function resolveFeishuAccount(cfg: Config, accountId?: string | null): ResolvedFeishuAccount;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//#region extensions/feishu/src/state/accounts.ts
|
|
2
|
+
function asFeishuSection(cfg) {
|
|
3
|
+
return cfg.channels?.feishu;
|
|
4
|
+
}
|
|
5
|
+
function listFeishuAccountIds(cfg) {
|
|
6
|
+
const section = asFeishuSection(cfg);
|
|
7
|
+
if (!section) return [];
|
|
8
|
+
const accounts = section.accounts ?? {};
|
|
9
|
+
const keys = Object.keys(accounts);
|
|
10
|
+
if (keys.length > 0) return keys;
|
|
11
|
+
return ["default"];
|
|
12
|
+
}
|
|
13
|
+
function resolveRootAccount(section) {
|
|
14
|
+
return {
|
|
15
|
+
enabled: section.enabled,
|
|
16
|
+
name: "Default Account",
|
|
17
|
+
appId: section.appId,
|
|
18
|
+
appSecret: section.appSecret,
|
|
19
|
+
domain: section.domain,
|
|
20
|
+
connectionMode: section.connectionMode,
|
|
21
|
+
webhookHost: section.webhookHost,
|
|
22
|
+
webhookPort: section.webhookPort,
|
|
23
|
+
webhookPath: section.webhookPath,
|
|
24
|
+
verificationToken: section.verificationToken,
|
|
25
|
+
encryptKey: section.encryptKey,
|
|
26
|
+
dmPolicy: section.dmPolicy,
|
|
27
|
+
groupPolicy: section.groupPolicy,
|
|
28
|
+
allowFrom: section.allowFrom,
|
|
29
|
+
groupAllowFrom: section.groupAllowFrom,
|
|
30
|
+
requireMention: section.requireMention,
|
|
31
|
+
historyLimit: section.historyLimit,
|
|
32
|
+
textChunkLimit: section.textChunkLimit,
|
|
33
|
+
renderMode: section.renderMode,
|
|
34
|
+
reactionNotifications: section.reactionNotifications,
|
|
35
|
+
streaming: section.streaming,
|
|
36
|
+
blockStreamingCoalesce: section.blockStreamingCoalesce,
|
|
37
|
+
tools: section.tools,
|
|
38
|
+
actions: section.actions,
|
|
39
|
+
dynamicAgentCreation: section.dynamicAgentCreation
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function mergeAccount(section, account) {
|
|
43
|
+
const root = resolveRootAccount(section);
|
|
44
|
+
if (!account) return root;
|
|
45
|
+
return {
|
|
46
|
+
...root,
|
|
47
|
+
...account,
|
|
48
|
+
allowFrom: account.allowFrom ?? root.allowFrom,
|
|
49
|
+
groupAllowFrom: account.groupAllowFrom ?? root.groupAllowFrom
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function resolveFeishuAccount(cfg, accountId) {
|
|
53
|
+
const section = asFeishuSection(cfg) ?? { enabled: false };
|
|
54
|
+
const requested = (accountId ?? "").trim();
|
|
55
|
+
const accounts = section.accounts ?? {};
|
|
56
|
+
const hasNamedAccounts = Object.keys(accounts).length > 0;
|
|
57
|
+
const effectiveAccountId = requested || section.defaultAccount || (hasNamedAccounts ? Object.keys(accounts)[0] : "default");
|
|
58
|
+
const merged = mergeAccount(section, hasNamedAccounts ? accounts[effectiveAccountId] : resolveRootAccount(section));
|
|
59
|
+
const enabled = merged.enabled !== false && section.enabled !== false;
|
|
60
|
+
const appId = merged.appId?.trim() || void 0;
|
|
61
|
+
const appSecret = merged.appSecret?.trim() || void 0;
|
|
62
|
+
const configured = Boolean(appId && appSecret);
|
|
63
|
+
return {
|
|
64
|
+
accountId: effectiveAccountId,
|
|
65
|
+
name: merged.name,
|
|
66
|
+
enabled,
|
|
67
|
+
configured,
|
|
68
|
+
appId,
|
|
69
|
+
appSecret,
|
|
70
|
+
domain: merged.domain ?? "feishu",
|
|
71
|
+
connectionMode: merged.connectionMode ?? "websocket",
|
|
72
|
+
webhookHost: merged.webhookHost,
|
|
73
|
+
webhookPort: merged.webhookPort,
|
|
74
|
+
webhookPath: merged.webhookPath,
|
|
75
|
+
verificationToken: merged.verificationToken,
|
|
76
|
+
encryptKey: merged.encryptKey,
|
|
77
|
+
dmPolicy: merged.dmPolicy ?? "pairing",
|
|
78
|
+
groupPolicy: merged.groupPolicy ?? "allowlist",
|
|
79
|
+
allowFrom: merged.allowFrom,
|
|
80
|
+
groupAllowFrom: merged.groupAllowFrom,
|
|
81
|
+
requireMention: merged.requireMention,
|
|
82
|
+
historyLimit: typeof merged.historyLimit === "number" ? merged.historyLimit : 50,
|
|
83
|
+
textChunkLimit: typeof merged.textChunkLimit === "number" ? merged.textChunkLimit : 4e3,
|
|
84
|
+
renderMode: merged.renderMode,
|
|
85
|
+
reactionNotifications: merged.reactionNotifications,
|
|
86
|
+
streaming: merged.streaming === true,
|
|
87
|
+
blockStreamingCoalesce: merged.blockStreamingCoalesce,
|
|
88
|
+
tools: merged.tools,
|
|
89
|
+
actions: merged.actions,
|
|
90
|
+
dynamicAgentCreation: merged.dynamicAgentCreation
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { listFeishuAccountIds, resolveFeishuAccount };
|
|
95
|
+
|
|
96
|
+
//# sourceMappingURL=accounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.js","names":[],"sources":["../../../../../extensions/feishu/src/state/accounts.ts"],"sourcesContent":["import type { Config } from '@xopcai/xopc/config/schema.js';\n\nimport type { FeishuAccountConfig, FeishuConfig } from '../schema/config-schema.js';\n\nexport interface ResolvedFeishuAccount {\n accountId: string;\n name?: string;\n enabled: boolean;\n configured: boolean;\n\n appId?: string;\n appSecret?: string;\n domain: 'feishu' | 'lark' | string;\n connectionMode: 'websocket' | 'webhook';\n\n webhookHost?: string;\n webhookPort?: number;\n webhookPath?: string;\n verificationToken?: string;\n encryptKey?: string;\n\n dmPolicy: 'pairing' | 'allowlist' | 'open' | 'disabled';\n groupPolicy: 'open' | 'disabled' | 'allowlist';\n allowFrom?: Array<string | number>;\n groupAllowFrom?: Array<string | number>;\n requireMention?: boolean;\n\n historyLimit: number;\n textChunkLimit: number;\n renderMode?: 'auto' | 'raw' | 'card';\n\n reactionNotifications?: 'off' | 'own' | 'all';\n\n /** Opt-in: only `true` enables Feishu streaming (Thinking… + incremental updates). */\n streaming: boolean;\n blockStreamingCoalesce?: { enabled?: boolean; minChars?: number; idleMs?: number };\n\n tools?: FeishuConfig['tools'];\n actions?: FeishuConfig['actions'];\n dynamicAgentCreation?: FeishuConfig['dynamicAgentCreation'];\n}\n\nfunction asFeishuSection(cfg: Config): FeishuConfig | undefined {\n return cfg.channels?.feishu as FeishuConfig | undefined;\n}\n\nexport function listFeishuAccountIds(cfg: Config): string[] {\n const section = asFeishuSection(cfg);\n if (!section) return [];\n const accounts = section.accounts ?? {};\n const keys = Object.keys(accounts);\n if (keys.length > 0) return keys;\n // Single-account layout\n return ['default'];\n}\n\nfunction resolveRootAccount(section: FeishuConfig): FeishuAccountConfig {\n return {\n enabled: section.enabled,\n name: 'Default Account',\n appId: section.appId,\n appSecret: section.appSecret,\n domain: section.domain,\n connectionMode: section.connectionMode,\n webhookHost: (section as any).webhookHost,\n webhookPort: (section as any).webhookPort,\n webhookPath: (section as any).webhookPath,\n verificationToken: (section as any).verificationToken,\n encryptKey: (section as any).encryptKey,\n dmPolicy: section.dmPolicy,\n groupPolicy: section.groupPolicy,\n allowFrom: section.allowFrom,\n groupAllowFrom: section.groupAllowFrom,\n requireMention: section.requireMention,\n historyLimit: section.historyLimit,\n textChunkLimit: section.textChunkLimit,\n renderMode: (section as any).renderMode,\n reactionNotifications: section.reactionNotifications,\n streaming: section.streaming,\n blockStreamingCoalesce: section.blockStreamingCoalesce,\n tools: section.tools,\n actions: section.actions,\n dynamicAgentCreation: section.dynamicAgentCreation,\n };\n}\n\nfunction mergeAccount(section: FeishuConfig, account: FeishuAccountConfig | undefined): FeishuAccountConfig {\n const root = resolveRootAccount(section);\n if (!account) return root;\n return {\n ...root,\n ...account,\n // arrays should replace, not concat\n allowFrom: account.allowFrom ?? root.allowFrom,\n groupAllowFrom: account.groupAllowFrom ?? root.groupAllowFrom,\n };\n}\n\nexport function resolveFeishuAccount(cfg: Config, accountId?: string | null): ResolvedFeishuAccount {\n const section = asFeishuSection(cfg) ?? ({ enabled: false } as FeishuConfig);\n const requested = (accountId ?? '').trim();\n\n const accounts = section.accounts ?? {};\n const hasNamedAccounts = Object.keys(accounts).length > 0;\n const effectiveAccountId = requested || section.defaultAccount || (hasNamedAccounts ? Object.keys(accounts)[0] : 'default');\n\n const raw = hasNamedAccounts ? accounts[effectiveAccountId] : resolveRootAccount(section);\n const merged = mergeAccount(section, raw);\n\n const enabled = merged.enabled !== false && section.enabled !== false;\n const appId = merged.appId?.trim() || undefined;\n const appSecret = merged.appSecret?.trim() || undefined;\n const configured = Boolean(appId && appSecret);\n\n return {\n accountId: effectiveAccountId,\n name: merged.name,\n enabled,\n configured,\n appId,\n appSecret,\n domain: (merged.domain ?? 'feishu') as any,\n connectionMode: (merged.connectionMode ?? 'websocket') as any,\n webhookHost: (merged as any).webhookHost,\n webhookPort: (merged as any).webhookPort,\n webhookPath: (merged as any).webhookPath,\n verificationToken: (merged as any).verificationToken,\n encryptKey: (merged as any).encryptKey,\n dmPolicy: (merged.dmPolicy ?? 'pairing') as any,\n groupPolicy: (merged.groupPolicy ?? 'allowlist') as any,\n allowFrom: merged.allowFrom,\n groupAllowFrom: merged.groupAllowFrom,\n requireMention: merged.requireMention,\n historyLimit: typeof merged.historyLimit === 'number' ? merged.historyLimit : 50,\n textChunkLimit: typeof merged.textChunkLimit === 'number' ? merged.textChunkLimit : 4000,\n renderMode: (merged as any).renderMode,\n reactionNotifications: merged.reactionNotifications,\n streaming: merged.streaming === true,\n blockStreamingCoalesce: merged.blockStreamingCoalesce as any,\n tools: merged.tools,\n actions: merged.actions,\n dynamicAgentCreation: merged.dynamicAgentCreation,\n };\n}\n\n"],"mappings":";AA0CA,SAAS,gBAAgB,KAAuC;AAC9D,QAAO,IAAI,UAAU;;AAGvB,SAAgB,qBAAqB,KAAuB;CAC1D,MAAM,UAAU,gBAAgB,IAAI;AACpC,KAAI,CAAC,QAAS,QAAO,EAAE;CACvB,MAAM,WAAW,QAAQ,YAAY,EAAE;CACvC,MAAM,OAAO,OAAO,KAAK,SAAS;AAClC,KAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,QAAO,CAAC,UAAU;;AAGpB,SAAS,mBAAmB,SAA4C;AACtE,QAAO;EACL,SAAS,QAAQ;EACjB,MAAM;EACN,OAAO,QAAQ;EACf,WAAW,QAAQ;EACnB,QAAQ,QAAQ;EAChB,gBAAgB,QAAQ;EACxB,aAAc,QAAgB;EAC9B,aAAc,QAAgB;EAC9B,aAAc,QAAgB;EAC9B,mBAAoB,QAAgB;EACpC,YAAa,QAAgB;EAC7B,UAAU,QAAQ;EAClB,aAAa,QAAQ;EACrB,WAAW,QAAQ;EACnB,gBAAgB,QAAQ;EACxB,gBAAgB,QAAQ;EACxB,cAAc,QAAQ;EACtB,gBAAgB,QAAQ;EACxB,YAAa,QAAgB;EAC7B,uBAAuB,QAAQ;EAC/B,WAAW,QAAQ;EACnB,wBAAwB,QAAQ;EAChC,OAAO,QAAQ;EACf,SAAS,QAAQ;EACjB,sBAAsB,QAAQ;EAC/B;;AAGH,SAAS,aAAa,SAAuB,SAA+D;CAC1G,MAAM,OAAO,mBAAmB,QAAQ;AACxC,KAAI,CAAC,QAAS,QAAO;AACrB,QAAO;EACL,GAAG;EACH,GAAG;EAEH,WAAW,QAAQ,aAAa,KAAK;EACrC,gBAAgB,QAAQ,kBAAkB,KAAK;EAChD;;AAGH,SAAgB,qBAAqB,KAAa,WAAkD;CAClG,MAAM,UAAU,gBAAgB,IAAI,IAAK,EAAE,SAAS,OAAO;CAC3D,MAAM,aAAa,aAAa,IAAI,MAAM;CAE1C,MAAM,WAAW,QAAQ,YAAY,EAAE;CACvC,MAAM,mBAAmB,OAAO,KAAK,SAAS,CAAC,SAAS;CACxD,MAAM,qBAAqB,aAAa,QAAQ,mBAAmB,mBAAmB,OAAO,KAAK,SAAS,CAAC,KAAK;CAGjH,MAAM,SAAS,aAAa,SADhB,mBAAmB,SAAS,sBAAsB,mBAAmB,QAAQ,CAChD;CAEzC,MAAM,UAAU,OAAO,YAAY,SAAS,QAAQ,YAAY;CAChE,MAAM,QAAQ,OAAO,OAAO,MAAM,IAAI,KAAA;CACtC,MAAM,YAAY,OAAO,WAAW,MAAM,IAAI,KAAA;CAC9C,MAAM,aAAa,QAAQ,SAAS,UAAU;AAE9C,QAAO;EACL,WAAW;EACX,MAAM,OAAO;EACb;EACA;EACA;EACA;EACA,QAAS,OAAO,UAAU;EAC1B,gBAAiB,OAAO,kBAAkB;EAC1C,aAAc,OAAe;EAC7B,aAAc,OAAe;EAC7B,aAAc,OAAe;EAC7B,mBAAoB,OAAe;EACnC,YAAa,OAAe;EAC5B,UAAW,OAAO,YAAY;EAC9B,aAAc,OAAO,eAAe;EACpC,WAAW,OAAO;EAClB,gBAAgB,OAAO;EACvB,gBAAgB,OAAO;EACvB,cAAc,OAAO,OAAO,iBAAiB,WAAW,OAAO,eAAe;EAC9E,gBAAgB,OAAO,OAAO,mBAAmB,WAAW,OAAO,iBAAiB;EACpF,YAAa,OAAe;EAC5B,uBAAuB,OAAO;EAC9B,WAAW,OAAO,cAAc;EAChC,wBAAwB,OAAO;EAC/B,OAAO,OAAO;EACd,SAAS,OAAO;EAChB,sBAAsB,OAAO;EAC9B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type FeishuMessageBinding = {
|
|
2
|
+
messageId: string;
|
|
3
|
+
sessionKey: string;
|
|
4
|
+
accountId: string;
|
|
5
|
+
chatId: string;
|
|
6
|
+
senderId: string;
|
|
7
|
+
isGroup: boolean;
|
|
8
|
+
threadId?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function recordFeishuMessageBinding(binding: FeishuMessageBinding): void;
|
|
11
|
+
export declare function getFeishuBindingByMessageId(messageId: string): FeishuMessageBinding | null;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region extensions/feishu/src/state/message-bindings.ts
|
|
2
|
+
const MAX = 5e4;
|
|
3
|
+
const TTL_MS = 1440 * 6e4;
|
|
4
|
+
const byMessageId = /* @__PURE__ */ new Map();
|
|
5
|
+
function prune(now) {
|
|
6
|
+
for (const [k, v] of byMessageId) if (now - v.at > TTL_MS) byMessageId.delete(k);
|
|
7
|
+
if (byMessageId.size <= MAX) return;
|
|
8
|
+
const extra = byMessageId.size - MAX;
|
|
9
|
+
let i = 0;
|
|
10
|
+
for (const k of byMessageId.keys()) {
|
|
11
|
+
byMessageId.delete(k);
|
|
12
|
+
i++;
|
|
13
|
+
if (i >= extra) break;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function recordFeishuMessageBinding(binding) {
|
|
17
|
+
const messageId = binding.messageId.trim();
|
|
18
|
+
if (!messageId) return;
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
prune(now);
|
|
21
|
+
byMessageId.set(messageId, {
|
|
22
|
+
binding,
|
|
23
|
+
at: now
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function getFeishuBindingByMessageId(messageId) {
|
|
27
|
+
const key = messageId.trim();
|
|
28
|
+
if (!key) return null;
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
const hit = byMessageId.get(key);
|
|
31
|
+
if (!hit) return null;
|
|
32
|
+
if (now - hit.at > TTL_MS) {
|
|
33
|
+
byMessageId.delete(key);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return hit.binding;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { getFeishuBindingByMessageId, recordFeishuMessageBinding };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=message-bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-bindings.js","names":[],"sources":["../../../../../extensions/feishu/src/state/message-bindings.ts"],"sourcesContent":["export type FeishuMessageBinding = {\n messageId: string;\n sessionKey: string;\n accountId: string;\n chatId: string;\n senderId: string;\n isGroup: boolean;\n threadId?: string;\n};\n\nconst MAX = 50_000;\nconst TTL_MS = 24 * 60 * 60_000;\n\nconst byMessageId = new Map<string, { binding: FeishuMessageBinding; at: number }>();\n\nfunction prune(now: number) {\n for (const [k, v] of byMessageId) {\n if (now - v.at > TTL_MS) {\n byMessageId.delete(k);\n }\n }\n if (byMessageId.size <= MAX) return;\n const extra = byMessageId.size - MAX;\n let i = 0;\n for (const k of byMessageId.keys()) {\n byMessageId.delete(k);\n i++;\n if (i >= extra) break;\n }\n}\n\nexport function recordFeishuMessageBinding(binding: FeishuMessageBinding): void {\n const messageId = binding.messageId.trim();\n if (!messageId) return;\n const now = Date.now();\n prune(now);\n byMessageId.set(messageId, { binding, at: now });\n}\n\nexport function getFeishuBindingByMessageId(messageId: string): FeishuMessageBinding | null {\n const key = messageId.trim();\n if (!key) return null;\n const now = Date.now();\n const hit = byMessageId.get(key);\n if (!hit) return null;\n if (now - hit.at > TTL_MS) {\n byMessageId.delete(key);\n return null;\n }\n return hit.binding;\n}\n\n"],"mappings":";AAUA,MAAM,MAAM;AACZ,MAAM,SAAS,OAAU;AAEzB,MAAM,8BAAc,IAAI,KAA4D;AAEpF,SAAS,MAAM,KAAa;AAC1B,MAAK,MAAM,CAAC,GAAG,MAAM,YACnB,KAAI,MAAM,EAAE,KAAK,OACf,aAAY,OAAO,EAAE;AAGzB,KAAI,YAAY,QAAQ,IAAK;CAC7B,MAAM,QAAQ,YAAY,OAAO;CACjC,IAAI,IAAI;AACR,MAAK,MAAM,KAAK,YAAY,MAAM,EAAE;AAClC,cAAY,OAAO,EAAE;AACrB;AACA,MAAI,KAAK,MAAO;;;AAIpB,SAAgB,2BAA2B,SAAqC;CAC9E,MAAM,YAAY,QAAQ,UAAU,MAAM;AAC1C,KAAI,CAAC,UAAW;CAChB,MAAM,MAAM,KAAK,KAAK;AACtB,OAAM,IAAI;AACV,aAAY,IAAI,WAAW;EAAE;EAAS,IAAI;EAAK,CAAC;;AAGlD,SAAgB,4BAA4B,WAAgD;CAC1F,MAAM,MAAM,UAAU,MAAM;AAC5B,KAAI,CAAC,IAAK,QAAO;CACjB,MAAM,MAAM,KAAK,KAAK;CACtB,MAAM,MAAM,YAAY,IAAI,IAAI;AAChC,KAAI,CAAC,IAAK,QAAO;AACjB,KAAI,MAAM,IAAI,KAAK,QAAQ;AACzB,cAAY,OAAO,IAAI;AACvB,SAAO;;AAET,QAAO,IAAI"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region extensions/feishu/src/state/thread-bindings.ts
|
|
2
|
+
const STATE_KEY = Symbol.for("xopc.feishuThreadBindingsState");
|
|
3
|
+
function getState() {
|
|
4
|
+
const store = globalThis;
|
|
5
|
+
let st = store[STATE_KEY];
|
|
6
|
+
if (!st) {
|
|
7
|
+
st = { byAccountConversation: /* @__PURE__ */ new Map() };
|
|
8
|
+
store[STATE_KEY] = st;
|
|
9
|
+
}
|
|
10
|
+
return st;
|
|
11
|
+
}
|
|
12
|
+
function key(accountId, conversationId) {
|
|
13
|
+
return `${accountId}:${conversationId}`;
|
|
14
|
+
}
|
|
15
|
+
function bindFeishuConversation(params) {
|
|
16
|
+
const now = Date.now();
|
|
17
|
+
const rec = {
|
|
18
|
+
accountId: params.accountId,
|
|
19
|
+
conversationId: params.conversationId,
|
|
20
|
+
parentConversationId: params.parentConversationId,
|
|
21
|
+
targetSessionKey: params.targetSessionKey,
|
|
22
|
+
boundAt: now,
|
|
23
|
+
lastActivityAt: now,
|
|
24
|
+
metadata: params.metadata
|
|
25
|
+
};
|
|
26
|
+
getState().byAccountConversation.set(key(rec.accountId, rec.conversationId), rec);
|
|
27
|
+
return rec;
|
|
28
|
+
}
|
|
29
|
+
function listBindingsBySessionKey(accountId, targetSessionKey) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const rec of getState().byAccountConversation.values()) if (rec.accountId === accountId && rec.targetSessionKey === targetSessionKey) out.push(rec);
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
function unbindBySessionKey(accountId, targetSessionKey) {
|
|
35
|
+
const removed = [];
|
|
36
|
+
for (const rec of getState().byAccountConversation.values()) {
|
|
37
|
+
if (rec.accountId !== accountId || rec.targetSessionKey !== targetSessionKey) continue;
|
|
38
|
+
getState().byAccountConversation.delete(key(rec.accountId, rec.conversationId));
|
|
39
|
+
removed.push(rec);
|
|
40
|
+
}
|
|
41
|
+
return removed;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { bindFeishuConversation, listBindingsBySessionKey, unbindBySessionKey };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=thread-bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-bindings.js","names":[],"sources":["../../../../../extensions/feishu/src/state/thread-bindings.ts"],"sourcesContent":["type BindingRecord = {\n accountId: string;\n conversationId: string;\n parentConversationId?: string;\n targetSessionKey: string;\n boundAt: number;\n lastActivityAt: number;\n metadata?: Record<string, unknown>;\n};\n\ntype State = {\n byAccountConversation: Map<string, BindingRecord>;\n};\n\nconst STATE_KEY = Symbol.for('xopc.feishuThreadBindingsState');\n\nfunction getState(): State {\n const store = globalThis as Record<PropertyKey, unknown>;\n let st = store[STATE_KEY] as State | undefined;\n if (!st) {\n st = { byAccountConversation: new Map() };\n store[STATE_KEY] = st;\n }\n return st;\n}\n\nfunction key(accountId: string, conversationId: string): string {\n return `${accountId}:${conversationId}`;\n}\n\nexport function bindFeishuConversation(params: {\n accountId: string;\n conversationId: string;\n parentConversationId?: string;\n targetSessionKey: string;\n metadata?: Record<string, unknown>;\n}): BindingRecord {\n const now = Date.now();\n const rec: BindingRecord = {\n accountId: params.accountId,\n conversationId: params.conversationId,\n parentConversationId: params.parentConversationId,\n targetSessionKey: params.targetSessionKey,\n boundAt: now,\n lastActivityAt: now,\n metadata: params.metadata,\n };\n getState().byAccountConversation.set(key(rec.accountId, rec.conversationId), rec);\n return rec;\n}\n\nexport function listBindingsBySessionKey(accountId: string, targetSessionKey: string): BindingRecord[] {\n const out: BindingRecord[] = [];\n for (const rec of getState().byAccountConversation.values()) {\n if (rec.accountId === accountId && rec.targetSessionKey === targetSessionKey) out.push(rec);\n }\n return out;\n}\n\nexport function unbindBySessionKey(accountId: string, targetSessionKey: string): BindingRecord[] {\n const removed: BindingRecord[] = [];\n for (const rec of getState().byAccountConversation.values()) {\n if (rec.accountId !== accountId || rec.targetSessionKey !== targetSessionKey) continue;\n getState().byAccountConversation.delete(key(rec.accountId, rec.conversationId));\n removed.push(rec);\n }\n return removed;\n}\n"],"mappings":";AAcA,MAAM,YAAY,OAAO,IAAI,iCAAiC;AAE9D,SAAS,WAAkB;CACzB,MAAM,QAAQ;CACd,IAAI,KAAK,MAAM;AACf,KAAI,CAAC,IAAI;AACP,OAAK,EAAE,uCAAuB,IAAI,KAAK,EAAE;AACzC,QAAM,aAAa;;AAErB,QAAO;;AAGT,SAAS,IAAI,WAAmB,gBAAgC;AAC9D,QAAO,GAAG,UAAU,GAAG;;AAGzB,SAAgB,uBAAuB,QAMrB;CAChB,MAAM,MAAM,KAAK,KAAK;CACtB,MAAM,MAAqB;EACzB,WAAW,OAAO;EAClB,gBAAgB,OAAO;EACvB,sBAAsB,OAAO;EAC7B,kBAAkB,OAAO;EACzB,SAAS;EACT,gBAAgB;EAChB,UAAU,OAAO;EAClB;AACD,WAAU,CAAC,sBAAsB,IAAI,IAAI,IAAI,WAAW,IAAI,eAAe,EAAE,IAAI;AACjF,QAAO;;AAGT,SAAgB,yBAAyB,WAAmB,kBAA2C;CACrG,MAAM,MAAuB,EAAE;AAC/B,MAAK,MAAM,OAAO,UAAU,CAAC,sBAAsB,QAAQ,CACzD,KAAI,IAAI,cAAc,aAAa,IAAI,qBAAqB,iBAAkB,KAAI,KAAK,IAAI;AAE7F,QAAO;;AAGT,SAAgB,mBAAmB,WAAmB,kBAA2C;CAC/F,MAAM,UAA2B,EAAE;AACnC,MAAK,MAAM,OAAO,UAAU,CAAC,sBAAsB,QAAQ,EAAE;AAC3D,MAAI,IAAI,cAAc,aAAa,IAAI,qBAAqB,iBAAkB;AAC9E,YAAU,CAAC,sBAAsB,OAAO,IAAI,IAAI,WAAW,IAAI,eAAe,CAAC;AAC/E,UAAQ,KAAK,IAAI;;AAEnB,QAAO"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { listFeishuAccountIds, resolveFeishuAccount } from "../state/accounts.js";
|
|
2
|
+
//#region extensions/feishu/src/status/doctor.ts
|
|
3
|
+
function checkAccount(cfg, accountId) {
|
|
4
|
+
const a = resolveFeishuAccount(cfg, accountId);
|
|
5
|
+
const results = [];
|
|
6
|
+
results.push({
|
|
7
|
+
id: `feishu.${accountId}.configured`,
|
|
8
|
+
label: `Feishu[${accountId}] credentials`,
|
|
9
|
+
status: a.configured ? "pass" : "fail",
|
|
10
|
+
message: a.configured ? "Configured" : "Missing appId/appSecret",
|
|
11
|
+
hints: a.configured ? [] : ["Set `channels.feishu.appId` and `channels.feishu.appSecret` (or per-account under `channels.feishu.accounts`)."]
|
|
12
|
+
});
|
|
13
|
+
results.push({
|
|
14
|
+
id: `feishu.${accountId}.mode`,
|
|
15
|
+
label: `Feishu[${accountId}] connection mode`,
|
|
16
|
+
status: "pass",
|
|
17
|
+
message: `Mode: ${a.connectionMode}`,
|
|
18
|
+
hints: []
|
|
19
|
+
});
|
|
20
|
+
return results;
|
|
21
|
+
}
|
|
22
|
+
function createFeishuDoctorAdapter() {
|
|
23
|
+
return { async check(params) {
|
|
24
|
+
const ids = listFeishuAccountIds(params.cfg);
|
|
25
|
+
if (ids.length === 0) return [{
|
|
26
|
+
id: "feishu.missing",
|
|
27
|
+
label: "Feishu config",
|
|
28
|
+
status: "skip",
|
|
29
|
+
message: "No channels.feishu config present",
|
|
30
|
+
hints: ["Add `channels.feishu.enabled=true` to start the channel."]
|
|
31
|
+
}];
|
|
32
|
+
return ids.flatMap((id) => checkAccount(params.cfg, id));
|
|
33
|
+
} };
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createFeishuDoctorAdapter };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","names":[],"sources":["../../../../../extensions/feishu/src/status/doctor.ts"],"sourcesContent":["import type { ChannelDoctorAdapter, ChannelDoctorCheckResult } from '@xopcai/xopc/channels/plugin-types.js';\nimport type { Config } from '@xopcai/xopc/config/schema.js';\n\nimport { listFeishuAccountIds, resolveFeishuAccount } from '../state/accounts.js';\n\nfunction checkAccount(cfg: Config, accountId: string): ChannelDoctorCheckResult[] {\n const a = resolveFeishuAccount(cfg, accountId);\n const results: ChannelDoctorCheckResult[] = [];\n results.push({\n id: `feishu.${accountId}.configured`,\n label: `Feishu[${accountId}] credentials`,\n status: a.configured ? 'pass' : 'fail',\n message: a.configured ? 'Configured' : 'Missing appId/appSecret',\n hints: a.configured\n ? []\n : ['Set `channels.feishu.appId` and `channels.feishu.appSecret` (or per-account under `channels.feishu.accounts`).'],\n });\n results.push({\n id: `feishu.${accountId}.mode`,\n label: `Feishu[${accountId}] connection mode`,\n status: 'pass',\n message: `Mode: ${a.connectionMode}`,\n hints: [],\n });\n return results;\n}\n\nexport function createFeishuDoctorAdapter(): ChannelDoctorAdapter {\n return {\n async check(params: { cfg: Config }) {\n const ids = listFeishuAccountIds(params.cfg);\n if (ids.length === 0) {\n return [\n {\n id: 'feishu.missing',\n label: 'Feishu config',\n status: 'skip',\n message: 'No channels.feishu config present',\n hints: ['Add `channels.feishu.enabled=true` to start the channel.'],\n },\n ];\n }\n return ids.flatMap((id) => checkAccount(params.cfg, id));\n },\n };\n}\n\n"],"mappings":";;AAKA,SAAS,aAAa,KAAa,WAA+C;CAChF,MAAM,IAAI,qBAAqB,KAAK,UAAU;CAC9C,MAAM,UAAsC,EAAE;AAC9C,SAAQ,KAAK;EACX,IAAI,UAAU,UAAU;EACxB,OAAO,UAAU,UAAU;EAC3B,QAAQ,EAAE,aAAa,SAAS;EAChC,SAAS,EAAE,aAAa,eAAe;EACvC,OAAO,EAAE,aACL,EAAE,GACF,CAAC,iHAAiH;EACvH,CAAC;AACF,SAAQ,KAAK;EACX,IAAI,UAAU,UAAU;EACxB,OAAO,UAAU,UAAU;EAC3B,QAAQ;EACR,SAAS,SAAS,EAAE;EACpB,OAAO,EAAE;EACV,CAAC;AACF,QAAO;;AAGT,SAAgB,4BAAkD;AAChE,QAAO,EACL,MAAM,MAAM,QAAyB;EACnC,MAAM,MAAM,qBAAqB,OAAO,IAAI;AAC5C,MAAI,IAAI,WAAW,EACjB,QAAO,CACL;GACE,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,CAAC,2DAA2D;GACpE,CACF;AAEH,SAAO,IAAI,SAAS,OAAO,aAAa,OAAO,KAAK,GAAG,CAAC;IAE3D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region extensions/feishu/src/status/status-adapter.ts
|
|
2
|
+
function createFeishuStatusAdapter() {
|
|
3
|
+
return {
|
|
4
|
+
defaultRuntime: {
|
|
5
|
+
accountId: "default",
|
|
6
|
+
channelId: "feishu",
|
|
7
|
+
enabled: true,
|
|
8
|
+
configured: false
|
|
9
|
+
},
|
|
10
|
+
buildAccountSnapshot: async ({ account }) => ({
|
|
11
|
+
accountId: account.accountId,
|
|
12
|
+
channelId: "feishu",
|
|
13
|
+
enabled: account.enabled,
|
|
14
|
+
configured: account.configured,
|
|
15
|
+
status: account.configured ? "online" : "unconfigured"
|
|
16
|
+
}),
|
|
17
|
+
resolveAccountState: ({ configured, enabled }) => {
|
|
18
|
+
if (!enabled) return "disabled";
|
|
19
|
+
if (!configured) return "error";
|
|
20
|
+
return "online";
|
|
21
|
+
},
|
|
22
|
+
probeAccount: async ({ account, timeoutMs, cfg }) => {
|
|
23
|
+
return {
|
|
24
|
+
ok: account.configured,
|
|
25
|
+
timeoutMs,
|
|
26
|
+
domain: account.domain,
|
|
27
|
+
mode: account.connectionMode,
|
|
28
|
+
enabled: account.enabled,
|
|
29
|
+
configured: account.configured,
|
|
30
|
+
hasConfig: Boolean((cfg.channels?.feishu)?.enabled)
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
buildChannelSummary: async ({ snapshot }) => ({
|
|
34
|
+
ok: snapshot.configured && snapshot.enabled,
|
|
35
|
+
accountId: snapshot.accountId,
|
|
36
|
+
enabled: snapshot.enabled,
|
|
37
|
+
configured: snapshot.configured,
|
|
38
|
+
status: snapshot.status
|
|
39
|
+
})
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createFeishuStatusAdapter };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=status-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-adapter.js","names":[],"sources":["../../../../../extensions/feishu/src/status/status-adapter.ts"],"sourcesContent":["import type { ChannelStatusAdapter } from '@xopcai/xopc/channels/plugin-types.js';\nimport type { Config } from '@xopcai/xopc/config/schema.js';\n\nimport type { ResolvedFeishuAccount } from '../state/accounts.js';\n\nexport function createFeishuStatusAdapter(): ChannelStatusAdapter<ResolvedFeishuAccount> {\n return {\n defaultRuntime: {\n accountId: 'default',\n channelId: 'feishu',\n enabled: true,\n configured: false,\n },\n buildAccountSnapshot: async ({ account }) => ({\n accountId: account.accountId,\n channelId: 'feishu',\n enabled: account.enabled,\n configured: account.configured,\n status: account.configured ? 'online' : 'unconfigured',\n }),\n resolveAccountState: ({ configured, enabled }) => {\n if (!enabled) return 'disabled';\n if (!configured) return 'error';\n return 'online';\n },\n probeAccount: async ({ account, timeoutMs, cfg }) => {\n // Best-effort: ensure credentials present. Real probe will call Feishu API later.\n return {\n ok: account.configured,\n timeoutMs,\n domain: account.domain,\n mode: account.connectionMode,\n enabled: account.enabled,\n configured: account.configured,\n hasConfig: Boolean((cfg.channels?.feishu as any)?.enabled),\n };\n },\n buildChannelSummary: async ({ snapshot }) => ({\n ok: snapshot.configured && snapshot.enabled,\n accountId: snapshot.accountId,\n enabled: snapshot.enabled,\n configured: snapshot.configured,\n status: snapshot.status,\n }),\n };\n}\n\n"],"mappings":";AAKA,SAAgB,4BAAyE;AACvF,QAAO;EACL,gBAAgB;GACd,WAAW;GACX,WAAW;GACX,SAAS;GACT,YAAY;GACb;EACD,sBAAsB,OAAO,EAAE,eAAe;GAC5C,WAAW,QAAQ;GACnB,WAAW;GACX,SAAS,QAAQ;GACjB,YAAY,QAAQ;GACpB,QAAQ,QAAQ,aAAa,WAAW;GACzC;EACD,sBAAsB,EAAE,YAAY,cAAc;AAChD,OAAI,CAAC,QAAS,QAAO;AACrB,OAAI,CAAC,WAAY,QAAO;AACxB,UAAO;;EAET,cAAc,OAAO,EAAE,SAAS,WAAW,UAAU;AAEnD,UAAO;IACL,IAAI,QAAQ;IACZ;IACA,QAAQ,QAAQ;IAChB,MAAM,QAAQ;IACd,SAAS,QAAQ;IACjB,YAAY,QAAQ;IACpB,WAAW,SAAS,IAAI,UAAU,SAAgB,QAAQ;IAC3D;;EAEH,qBAAqB,OAAO,EAAE,gBAAgB;GAC5C,IAAI,SAAS,cAAc,SAAS;GACpC,WAAW,SAAS;GACpB,SAAS,SAAS;GAClB,YAAY,SAAS;GACrB,QAAQ,SAAS;GAClB;EACF"}
|