@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.
Files changed (161) hide show
  1. package/dist/extensions/feishu/src/adapters/onboard-cli.d.ts +7 -0
  2. package/dist/extensions/feishu/src/adapters/onboard-cli.js +432 -0
  3. package/dist/extensions/feishu/src/adapters/onboard-cli.js.map +1 -0
  4. package/dist/extensions/feishu/src/auth/pairing.d.ts +7 -0
  5. package/dist/extensions/feishu/src/auth/pairing.js +45 -0
  6. package/dist/extensions/feishu/src/auth/pairing.js.map +1 -0
  7. package/dist/extensions/feishu/src/auth/paths.d.ts +2 -0
  8. package/dist/extensions/feishu/src/auth/paths.js +18 -0
  9. package/dist/extensions/feishu/src/auth/paths.js.map +1 -0
  10. package/dist/extensions/feishu/src/directory/directory-adapter.d.ts +2 -0
  11. package/dist/extensions/feishu/src/directory/directory-adapter.js +27 -0
  12. package/dist/extensions/feishu/src/directory/directory-adapter.js.map +1 -0
  13. package/dist/extensions/feishu/src/format.d.ts +21 -0
  14. package/dist/extensions/feishu/src/format.js +99 -0
  15. package/dist/extensions/feishu/src/format.js.map +1 -0
  16. package/dist/extensions/feishu/src/index.d.ts +5 -0
  17. package/dist/extensions/feishu/src/index.js +3 -0
  18. package/dist/extensions/feishu/src/outbound/actions.d.ts +51 -0
  19. package/dist/extensions/feishu/src/outbound/actions.js +62 -0
  20. package/dist/extensions/feishu/src/outbound/actions.js.map +1 -0
  21. package/dist/extensions/feishu/src/outbound/media-load.d.ts +12 -0
  22. package/dist/extensions/feishu/src/outbound/media-load.js +125 -0
  23. package/dist/extensions/feishu/src/outbound/media-load.js.map +1 -0
  24. package/dist/extensions/feishu/src/outbound/outbound-adapter.d.ts +2 -0
  25. package/dist/extensions/feishu/src/outbound/outbound-adapter.js +201 -0
  26. package/dist/extensions/feishu/src/outbound/outbound-adapter.js.map +1 -0
  27. package/dist/extensions/feishu/src/plugin.d.ts +70 -0
  28. package/dist/extensions/feishu/src/plugin.js +313 -0
  29. package/dist/extensions/feishu/src/plugin.js.map +1 -0
  30. package/dist/extensions/feishu/src/schema/config-schema.d.ts +215 -0
  31. package/dist/extensions/feishu/src/schema/config-schema.js +198 -0
  32. package/dist/extensions/feishu/src/schema/config-schema.js.map +1 -0
  33. package/dist/extensions/feishu/src/state/accounts.d.ts +38 -0
  34. package/dist/extensions/feishu/src/state/accounts.js +96 -0
  35. package/dist/extensions/feishu/src/state/accounts.js.map +1 -0
  36. package/dist/extensions/feishu/src/state/message-bindings.d.ts +11 -0
  37. package/dist/extensions/feishu/src/state/message-bindings.js +41 -0
  38. package/dist/extensions/feishu/src/state/message-bindings.js.map +1 -0
  39. package/dist/extensions/feishu/src/state/thread-bindings.js +46 -0
  40. package/dist/extensions/feishu/src/state/thread-bindings.js.map +1 -0
  41. package/dist/extensions/feishu/src/status/doctor.d.ts +2 -0
  42. package/dist/extensions/feishu/src/status/doctor.js +38 -0
  43. package/dist/extensions/feishu/src/status/doctor.js.map +1 -0
  44. package/dist/extensions/feishu/src/status/status-adapter.d.ts +3 -0
  45. package/dist/extensions/feishu/src/status/status-adapter.js +45 -0
  46. package/dist/extensions/feishu/src/status/status-adapter.js.map +1 -0
  47. package/dist/extensions/feishu/src/streaming/streaming-adapter.d.ts +3 -0
  48. package/dist/extensions/feishu/src/streaming/streaming-adapter.js +242 -0
  49. package/dist/extensions/feishu/src/streaming/streaming-adapter.js.map +1 -0
  50. package/dist/extensions/feishu/src/subagent-hooks.js +52 -0
  51. package/dist/extensions/feishu/src/subagent-hooks.js.map +1 -0
  52. package/dist/extensions/feishu/src/tools/docx/docx-batch-insert.js +95 -0
  53. package/dist/extensions/feishu/src/tools/docx/docx-batch-insert.js.map +1 -0
  54. package/dist/extensions/feishu/src/tools/docx/docx-color-text.js +75 -0
  55. package/dist/extensions/feishu/src/tools/docx/docx-color-text.js.map +1 -0
  56. package/dist/extensions/feishu/src/tools/docx/docx-table-ops.js +173 -0
  57. package/dist/extensions/feishu/src/tools/docx/docx-table-ops.js.map +1 -0
  58. package/dist/extensions/feishu/src/tools/docx/docx-types.js +1 -0
  59. package/dist/extensions/feishu/src/tools/tools.d.ts +5 -0
  60. package/dist/extensions/feishu/src/tools/tools.js +46 -0
  61. package/dist/extensions/feishu/src/tools/tools.js.map +1 -0
  62. package/dist/extensions/feishu/src/transport/client/client.d.ts +6 -0
  63. package/dist/extensions/feishu/src/transport/client/client.js +41 -0
  64. package/dist/extensions/feishu/src/transport/client/client.js.map +1 -0
  65. package/dist/extensions/feishu/src/transport/client/lark-sdk-logger.d.ts +13 -0
  66. package/dist/extensions/feishu/src/transport/client/lark-sdk-logger.js +104 -0
  67. package/dist/extensions/feishu/src/transport/client/lark-sdk-logger.js.map +1 -0
  68. package/dist/extensions/feishu/src/transport/reliability/dedupe.d.ts +7 -0
  69. package/dist/extensions/feishu/src/transport/reliability/dedupe.js +30 -0
  70. package/dist/extensions/feishu/src/transport/reliability/dedupe.js.map +1 -0
  71. package/dist/extensions/feishu/src/transport/socket-mode/monitor.d.ts +19 -0
  72. package/dist/extensions/feishu/src/transport/socket-mode/monitor.js +326 -0
  73. package/dist/extensions/feishu/src/transport/socket-mode/monitor.js.map +1 -0
  74. package/dist/extensions/feishu/src/transport/socket-mode/retry.d.ts +1 -0
  75. package/dist/extensions/feishu/src/transport/socket-mode/retry.js +10 -0
  76. package/dist/extensions/feishu/src/transport/socket-mode/retry.js.map +1 -0
  77. package/dist/extensions/feishu/src/transport/text/mentions.d.ts +1 -0
  78. package/dist/extensions/feishu/src/transport/text/mentions.js +9 -0
  79. package/dist/extensions/feishu/src/transport/text/mentions.js.map +1 -0
  80. package/dist/extensions/feishu/src/transport/webhook/monitor.d.ts +19 -0
  81. package/dist/extensions/feishu/src/transport/webhook/monitor.js +271 -0
  82. package/dist/extensions/feishu/src/transport/webhook/monitor.js.map +1 -0
  83. package/dist/extensions/feishu/src/ui/config-surface.d.ts +2 -0
  84. package/dist/extensions/feishu/src/ui/config-surface.js +6 -0
  85. package/dist/extensions/feishu/src/ui/config-surface.js.map +1 -0
  86. package/dist/extensions/feishu/xopc.extension.json +18 -0
  87. package/dist/extensions/telegram/xopc.extension.json +20 -0
  88. package/dist/extensions/weixin/xopc.extension.json +17 -0
  89. package/dist/gateway/static/root/assets/{agents-C2blSFQk.js → agents-Dy5cGVVQ.js} +2 -2
  90. package/dist/gateway/static/root/assets/{agents-C2blSFQk.js.map → agents-Dy5cGVVQ.js.map} +1 -1
  91. package/dist/gateway/static/root/assets/{apps-page-Dg7InQ41.js → apps-page-BOpDR0Lz.js} +2 -2
  92. package/dist/gateway/static/root/assets/{apps-page-Dg7InQ41.js.map → apps-page-BOpDR0Lz.js.map} +1 -1
  93. package/dist/gateway/static/root/assets/channels-settings-CrCesccB.js +9 -0
  94. package/dist/gateway/static/root/assets/channels-settings-CrCesccB.js.map +1 -0
  95. package/dist/gateway/static/root/assets/{cron-page-B-7O4_QQ.js → cron-page-B_XY0gPt.js} +2 -2
  96. package/dist/gateway/static/root/assets/{cron-page-B-7O4_QQ.js.map → cron-page-B_XY0gPt.js.map} +1 -1
  97. package/dist/gateway/static/root/assets/{cron-utils-DvRPM814.js → cron-utils-BYdnLwhl.js} +2 -2
  98. package/dist/gateway/static/root/assets/{cron-utils-DvRPM814.js.map → cron-utils-BYdnLwhl.js.map} +1 -1
  99. package/dist/gateway/static/root/assets/{dist-DYzyRkRh.js → dist-DvaA5uNp.js} +2 -2
  100. package/dist/gateway/static/root/assets/{dist-DYzyRkRh.js.map → dist-DvaA5uNp.js.map} +1 -1
  101. package/dist/gateway/static/root/assets/{extension-debug-page-DV-NwlaY.js → extension-debug-page-CPSk7gFW.js} +2 -2
  102. package/dist/gateway/static/root/assets/{extension-debug-page-DV-NwlaY.js.map → extension-debug-page-CPSk7gFW.js.map} +1 -1
  103. package/dist/gateway/static/root/assets/{extension-page-UUKLJwpo.js → extension-page-COdbk9I6.js} +2 -2
  104. package/dist/gateway/static/root/assets/{extension-page-UUKLJwpo.js.map → extension-page-COdbk9I6.js.map} +1 -1
  105. package/dist/gateway/static/root/assets/{extension-settings-page-R4VlbZOj.js → extension-settings-page-BlEz2Ily.js} +2 -2
  106. package/dist/gateway/static/root/assets/{extension-settings-page-R4VlbZOj.js.map → extension-settings-page-BlEz2Ily.js.map} +1 -1
  107. package/dist/gateway/static/root/assets/index-BQNdJlkw.css +1 -0
  108. package/dist/gateway/static/root/assets/index-tm9ZY35l.js +144 -0
  109. package/dist/gateway/static/root/assets/{index-BCVqNi5T.js.map → index-tm9ZY35l.js.map} +1 -1
  110. package/dist/gateway/static/root/assets/{logs-page-BgUDjMge.js → logs-page-LSa0jmLO.js} +2 -2
  111. package/dist/gateway/static/root/assets/{logs-page-BgUDjMge.js.map → logs-page-LSa0jmLO.js.map} +1 -1
  112. package/dist/gateway/static/root/assets/sessions-page-cn2fi_V3.js +2 -0
  113. package/dist/gateway/static/root/assets/sessions-page-cn2fi_V3.js.map +1 -0
  114. package/dist/gateway/static/root/assets/{settings-page-Doa_lzdW.js → settings-page-CyHd5szQ.js} +2 -2
  115. package/dist/gateway/static/root/assets/{settings-page-Doa_lzdW.js.map → settings-page-CyHd5szQ.js.map} +1 -1
  116. package/dist/gateway/static/root/assets/{skills-page-BdNqg2NG.js → skills-page-irjxwW9u.js} +2 -2
  117. package/dist/gateway/static/root/assets/{skills-page-BdNqg2NG.js.map → skills-page-irjxwW9u.js.map} +1 -1
  118. package/dist/gateway/static/root/channel-icons/feishu.svg +12 -0
  119. package/dist/gateway/static/root/channel-icons/lark.svg +12 -0
  120. package/dist/gateway/static/root/channel-icons/telegram.svg +1 -0
  121. package/dist/gateway/static/root/channel-icons/wechat.svg +1 -0
  122. package/dist/gateway/static/root/channel-icons/weixin.svg +1 -0
  123. package/dist/gateway/static/root/index.html +2 -2
  124. package/dist/package.js +1 -1
  125. package/dist/src/agent/agent-manager.d.ts +1 -0
  126. package/dist/src/agent/agent-manager.js +1 -0
  127. package/dist/src/agent/agent-manager.js.map +1 -1
  128. package/dist/src/agent/service.js +3 -0
  129. package/dist/src/agent/service.js.map +1 -1
  130. package/dist/src/agent/tools/delegate-tool.d.ts +8 -0
  131. package/dist/src/agent/tools/delegate-tool.js +60 -2
  132. package/dist/src/agent/tools/delegate-tool.js.map +1 -1
  133. package/dist/src/agent/tools/factory.d.ts +1 -0
  134. package/dist/src/agent/tools/factory.js +2 -0
  135. package/dist/src/agent/tools/factory.js.map +1 -1
  136. package/dist/src/channels/envelope-timestamp.d.ts +5 -0
  137. package/dist/src/channels/envelope-timestamp.js +10 -1
  138. package/dist/src/channels/envelope-timestamp.js.map +1 -1
  139. package/dist/src/channels/feishu/index.d.ts +5 -0
  140. package/dist/src/channels/feishu/index.js +4 -0
  141. package/dist/src/chat-commands/types.d.ts +1 -1
  142. package/dist/src/extensions/types/hooks.d.ts +46 -1
  143. package/dist/src/extensions/types/hooks.js +3 -0
  144. package/dist/src/extensions/types/hooks.js.map +1 -1
  145. package/dist/src/gateway/service.js +1 -1
  146. package/dist/src/generated/bundled-channel-plugins.d.ts +2 -1
  147. package/dist/src/generated/bundled-channel-plugins.js +8 -2
  148. package/dist/src/generated/bundled-channel-plugins.js.map +1 -1
  149. package/dist/src/providers/env-keys.js +1 -0
  150. package/dist/src/providers/env-keys.js.map +1 -1
  151. package/dist/src/providers/index.js +5 -0
  152. package/dist/src/providers/index.js.map +1 -1
  153. package/dist/src/session/session-title.js +2 -1
  154. package/dist/src/session/session-title.js.map +1 -1
  155. package/package.json +2 -2
  156. package/dist/gateway/static/root/assets/channels-settings-CHOL7G_P.js +0 -9
  157. package/dist/gateway/static/root/assets/channels-settings-CHOL7G_P.js.map +0 -1
  158. package/dist/gateway/static/root/assets/index-BCVqNi5T.js +0 -144
  159. package/dist/gateway/static/root/assets/index-XbYityMf.css +0 -1
  160. package/dist/gateway/static/root/assets/sessions-page-L2VUocA4.js +0 -2
  161. 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,2 @@
1
+ import type { ChannelDoctorAdapter } from '@xopcai/xopc/channels/plugin-types.js';
2
+ export declare function createFeishuDoctorAdapter(): ChannelDoctorAdapter;
@@ -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,3 @@
1
+ import type { ChannelStatusAdapter } from '@xopcai/xopc/channels/plugin-types.js';
2
+ import type { ResolvedFeishuAccount } from '../state/accounts.js';
3
+ export declare function createFeishuStatusAdapter(): ChannelStatusAdapter<ResolvedFeishuAccount>;
@@ -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"}
@@ -0,0 +1,3 @@
1
+ import type { ChannelStreamingAdapter } from '@xopcai/xopc/channels/plugin-types.js';
2
+ import type { Config } from '@xopcai/xopc/config/schema.js';
3
+ export declare function createFeishuStreamingAdapter(getConfig: () => Config): ChannelStreamingAdapter;