twinny 0.0.0-dev.260525150705

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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +264 -0
  3. package/README.zh-CN.md +252 -0
  4. package/configs/banner.png +0 -0
  5. package/configs/logo.png +0 -0
  6. package/dist/app/caffeinate.d.ts +28 -0
  7. package/dist/app/caffeinate.js +96 -0
  8. package/dist/app/caffeinate.js.map +1 -0
  9. package/dist/app/daemon.d.ts +1 -0
  10. package/dist/app/daemon.js +44 -0
  11. package/dist/app/daemon.js.map +1 -0
  12. package/dist/app/lark-assets.d.ts +25 -0
  13. package/dist/app/lark-assets.js +108 -0
  14. package/dist/app/lark-assets.js.map +1 -0
  15. package/dist/app/startup-probe.d.ts +17 -0
  16. package/dist/app/startup-probe.js +90 -0
  17. package/dist/app/startup-probe.js.map +1 -0
  18. package/dist/app/wiring.d.ts +122 -0
  19. package/dist/app/wiring.js +694 -0
  20. package/dist/app/wiring.js.map +1 -0
  21. package/dist/cli/commands.d.ts +1 -0
  22. package/dist/cli/commands.js +47 -0
  23. package/dist/cli/commands.js.map +1 -0
  24. package/dist/cli/install-wizard.d.ts +41 -0
  25. package/dist/cli/install-wizard.js +629 -0
  26. package/dist/cli/install-wizard.js.map +1 -0
  27. package/dist/codex/appserver.d.ts +109 -0
  28. package/dist/codex/appserver.js +308 -0
  29. package/dist/codex/appserver.js.map +1 -0
  30. package/dist/codex/goal.d.ts +64 -0
  31. package/dist/codex/goal.js +433 -0
  32. package/dist/codex/goal.js.map +1 -0
  33. package/dist/codex/index.d.ts +6 -0
  34. package/dist/codex/index.js +7 -0
  35. package/dist/codex/index.js.map +1 -0
  36. package/dist/codex/protocol.d.ts +95 -0
  37. package/dist/codex/protocol.js +205 -0
  38. package/dist/codex/protocol.js.map +1 -0
  39. package/dist/codex/thread-name.d.ts +3 -0
  40. package/dist/codex/thread-name.js +27 -0
  41. package/dist/codex/thread-name.js.map +1 -0
  42. package/dist/codex/thread.d.ts +76 -0
  43. package/dist/codex/thread.js +80 -0
  44. package/dist/codex/thread.js.map +1 -0
  45. package/dist/codex/turn.d.ts +166 -0
  46. package/dist/codex/turn.js +746 -0
  47. package/dist/codex/turn.js.map +1 -0
  48. package/dist/config/bootstrap.d.ts +14 -0
  49. package/dist/config/bootstrap.js +56 -0
  50. package/dist/config/bootstrap.js.map +1 -0
  51. package/dist/config/index.d.ts +4 -0
  52. package/dist/config/index.js +5 -0
  53. package/dist/config/index.js.map +1 -0
  54. package/dist/config/loader.d.ts +49 -0
  55. package/dist/config/loader.js +467 -0
  56. package/dist/config/loader.js.map +1 -0
  57. package/dist/config/paths.d.ts +11 -0
  58. package/dist/config/paths.js +43 -0
  59. package/dist/config/paths.js.map +1 -0
  60. package/dist/config/secrets.d.ts +33 -0
  61. package/dist/config/secrets.js +85 -0
  62. package/dist/config/secrets.js.map +1 -0
  63. package/dist/conversation/manager.d.ts +701 -0
  64. package/dist/conversation/manager.js +7673 -0
  65. package/dist/conversation/manager.js.map +1 -0
  66. package/dist/conversation/queue.d.ts +8 -0
  67. package/dist/conversation/queue.js +28 -0
  68. package/dist/conversation/queue.js.map +1 -0
  69. package/dist/conversation/routing.d.ts +11 -0
  70. package/dist/conversation/routing.js +55 -0
  71. package/dist/conversation/routing.js.map +1 -0
  72. package/dist/errors.d.ts +6 -0
  73. package/dist/errors.js +17 -0
  74. package/dist/errors.js.map +1 -0
  75. package/dist/index.d.ts +3 -0
  76. package/dist/index.js +4 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/lark/auth.d.ts +41 -0
  79. package/dist/lark/auth.js +132 -0
  80. package/dist/lark/auth.js.map +1 -0
  81. package/dist/lark/browser-auth.d.ts +68 -0
  82. package/dist/lark/browser-auth.js +258 -0
  83. package/dist/lark/browser-auth.js.map +1 -0
  84. package/dist/lark/cards.d.ts +140 -0
  85. package/dist/lark/cards.js +1150 -0
  86. package/dist/lark/cards.js.map +1 -0
  87. package/dist/lark/contact.d.ts +41 -0
  88. package/dist/lark/contact.js +122 -0
  89. package/dist/lark/contact.js.map +1 -0
  90. package/dist/lark/events.d.ts +65 -0
  91. package/dist/lark/events.js +218 -0
  92. package/dist/lark/events.js.map +1 -0
  93. package/dist/lark/files.d.ts +36 -0
  94. package/dist/lark/files.js +191 -0
  95. package/dist/lark/files.js.map +1 -0
  96. package/dist/lark/filters.d.ts +73 -0
  97. package/dist/lark/filters.js +678 -0
  98. package/dist/lark/filters.js.map +1 -0
  99. package/dist/lark/index.d.ts +10 -0
  100. package/dist/lark/index.js +11 -0
  101. package/dist/lark/index.js.map +1 -0
  102. package/dist/lark/messages.d.ts +87 -0
  103. package/dist/lark/messages.js +428 -0
  104. package/dist/lark/messages.js.map +1 -0
  105. package/dist/lark/openapi.d.ts +58 -0
  106. package/dist/lark/openapi.js +206 -0
  107. package/dist/lark/openapi.js.map +1 -0
  108. package/dist/lark/redactor.d.ts +5 -0
  109. package/dist/lark/redactor.js +68 -0
  110. package/dist/lark/redactor.js.map +1 -0
  111. package/dist/lark/types.d.ts +49 -0
  112. package/dist/lark/types.js +18 -0
  113. package/dist/lark/types.js.map +1 -0
  114. package/dist/launchd/install.d.ts +22 -0
  115. package/dist/launchd/install.js +114 -0
  116. package/dist/launchd/install.js.map +1 -0
  117. package/dist/launchd/plist.d.ts +10 -0
  118. package/dist/launchd/plist.js +61 -0
  119. package/dist/launchd/plist.js.map +1 -0
  120. package/dist/lock/index.d.ts +20 -0
  121. package/dist/lock/index.js +74 -0
  122. package/dist/lock/index.js.map +1 -0
  123. package/dist/main.d.ts +2 -0
  124. package/dist/main.js +11 -0
  125. package/dist/main.js.map +1 -0
  126. package/dist/markdown.d.ts +12 -0
  127. package/dist/markdown.js +149 -0
  128. package/dist/markdown.js.map +1 -0
  129. package/dist/observability/health.d.ts +25 -0
  130. package/dist/observability/health.js +187 -0
  131. package/dist/observability/health.js.map +1 -0
  132. package/dist/observability/logs.d.ts +10 -0
  133. package/dist/observability/logs.js +34 -0
  134. package/dist/observability/logs.js.map +1 -0
  135. package/dist/observability/system-notifications.d.ts +25 -0
  136. package/dist/observability/system-notifications.js +33 -0
  137. package/dist/observability/system-notifications.js.map +1 -0
  138. package/dist/profiles/guest.d.ts +19 -0
  139. package/dist/profiles/guest.js +241 -0
  140. package/dist/profiles/guest.js.map +1 -0
  141. package/dist/profiles/index.d.ts +5 -0
  142. package/dist/profiles/index.js +14 -0
  143. package/dist/profiles/index.js.map +1 -0
  144. package/dist/profiles/owner.d.ts +1 -0
  145. package/dist/profiles/owner.js +6 -0
  146. package/dist/profiles/owner.js.map +1 -0
  147. package/dist/store/db.d.ts +10 -0
  148. package/dist/store/db.js +29 -0
  149. package/dist/store/db.js.map +1 -0
  150. package/dist/store/index.d.ts +3 -0
  151. package/dist/store/index.js +4 -0
  152. package/dist/store/index.js.map +1 -0
  153. package/dist/store/migrations.d.ts +13 -0
  154. package/dist/store/migrations.js +79 -0
  155. package/dist/store/migrations.js.map +1 -0
  156. package/dist/store/repositories.d.ts +227 -0
  157. package/dist/store/repositories.js +1384 -0
  158. package/dist/store/repositories.js.map +1 -0
  159. package/dist/telemetry/client.d.ts +60 -0
  160. package/dist/telemetry/client.js +204 -0
  161. package/dist/telemetry/client.js.map +1 -0
  162. package/dist/telemetry/hash.d.ts +1 -0
  163. package/dist/telemetry/hash.js +8 -0
  164. package/dist/telemetry/hash.js.map +1 -0
  165. package/dist/telemetry/index.d.ts +4 -0
  166. package/dist/telemetry/index.js +5 -0
  167. package/dist/telemetry/index.js.map +1 -0
  168. package/dist/telemetry/posthog.d.ts +27 -0
  169. package/dist/telemetry/posthog.js +45 -0
  170. package/dist/telemetry/posthog.js.map +1 -0
  171. package/dist/telemetry/reporter.d.ts +13 -0
  172. package/dist/telemetry/reporter.js +29 -0
  173. package/dist/telemetry/reporter.js.map +1 -0
  174. package/dist/types.d.ts +330 -0
  175. package/dist/types.js +9 -0
  176. package/dist/types.js.map +1 -0
  177. package/dist/version.d.ts +1 -0
  178. package/dist/version.js +1 -0
  179. package/dist/version.js.map +1 -0
  180. package/dist/version.json +3 -0
  181. package/dist/workspace/index.d.ts +2 -0
  182. package/dist/workspace/index.js +3 -0
  183. package/dist/workspace/index.js.map +1 -0
  184. package/dist/workspace/manager.d.ts +14 -0
  185. package/dist/workspace/manager.js +69 -0
  186. package/dist/workspace/manager.js.map +1 -0
  187. package/dist/workspace/slug.d.ts +8 -0
  188. package/dist/workspace/slug.js +59 -0
  189. package/dist/workspace/slug.js.map +1 -0
  190. package/migrations/0001_initial.sql +102 -0
  191. package/package.json +85 -0
@@ -0,0 +1,678 @@
1
+ export function normalizeIncomingLarkMessage(raw, options = {}) {
2
+ const result = normalizeIncomingLarkMessageWithReason(raw, options);
3
+ return result.kind === "message" ? result.message : null;
4
+ }
5
+ export function normalizeIncomingLarkMessageWithReason(raw, options = {}) {
6
+ const event = unwrapReceiveEvent(raw);
7
+ if (!isRecord(event) || !isRecord(event.sender) || !isRecord(event.message)) {
8
+ return ignored("malformed_event", raw);
9
+ }
10
+ const sender = event.sender;
11
+ const senderId = isRecord(sender.sender_id) ? sender.sender_id : {};
12
+ const senderOpenId = stringValue(senderId.open_id);
13
+ if (!senderOpenId) {
14
+ return ignored("missing_sender_open_id", raw);
15
+ }
16
+ const senderType = stringValue(sender.sender_type)?.toLowerCase();
17
+ if (senderType === "app" || senderType === "bot" || senderOpenId === options.botOpenId) {
18
+ return ignored("bot_self_message", raw);
19
+ }
20
+ const senderName = firstStringValue(sender.name, sender.sender_name, sender.display_name, sender.sender_display_name);
21
+ const message = event.message;
22
+ const chatType = normalizeChatType(stringValue(message.chat_type));
23
+ if (!chatType) {
24
+ return ignored("unsupported_chat_type", raw);
25
+ }
26
+ const messageType = stringValue(message.message_type) ?? "unknown";
27
+ const messageId = stringValue(message.message_id);
28
+ if (!messageId) {
29
+ return ignored("missing_message_id", raw);
30
+ }
31
+ const chatId = chatType === "p2p" ? senderOpenId : stringValue(message.chat_id);
32
+ if (!chatId) {
33
+ return ignored("malformed_event", raw);
34
+ }
35
+ const content = normalizeLarkMessageContent(messageType, message.content);
36
+ const resources = content.resources;
37
+ const shouldUseRaw = content.text === null || (content.text.length === 0 && resources.length === 0);
38
+ const text = shouldUseRaw ? stringifyRawLarkMessageForCodex(message) : (content.text ?? "");
39
+ const rawForCodex = content.rawForCodex || shouldUseRaw;
40
+ return {
41
+ kind: "message",
42
+ message: {
43
+ eventId: stringValue(event.event_id) ??
44
+ stringValue(event.uuid) ??
45
+ stringValue(isRecord(raw) && isRecord(raw.header) ? raw.header.event_id : undefined) ??
46
+ messageId,
47
+ messageId,
48
+ chatId,
49
+ chatType,
50
+ messageType,
51
+ senderOpenId,
52
+ senderName,
53
+ larkGroupId: chatType === "p2p" ? undefined : chatId,
54
+ larkThreadId: larkThreadIdForMessage(message, messageId, chatType),
55
+ larkRootMessageId: firstStringValue(message.root_id),
56
+ larkParentMessageId: firstStringValue(message.parent_id),
57
+ mentions: normalizeMentions(message.mentions),
58
+ resources: resources.length > 0 ? resources : undefined,
59
+ rawForCodex: rawForCodex ? true : undefined,
60
+ text,
61
+ createTime: parseEpochMs(message.create_time ?? event.create_time),
62
+ raw
63
+ }
64
+ };
65
+ }
66
+ export function normalizeLarkBotMenuWithReason(raw) {
67
+ if (!isRecord(raw)) {
68
+ return ignoredBotMenu("malformed_event", raw);
69
+ }
70
+ const header = eventHeader(raw);
71
+ const event = eventPayload(raw);
72
+ const eventKey = stringValue(event.event_key);
73
+ if (!eventKey) {
74
+ return ignoredBotMenu("missing_event_key", raw);
75
+ }
76
+ const action = botMenuActionForEventKey(eventKey);
77
+ if (!action) {
78
+ return ignoredBotMenu("unsupported_event_key", raw);
79
+ }
80
+ const operator = isRecord(event.operator) ? event.operator : {};
81
+ const operatorId = isRecord(operator.operator_id) ? operator.operator_id : {};
82
+ const operatorOpenId = stringValue(operatorId.open_id);
83
+ if (!operatorOpenId) {
84
+ return ignoredBotMenu("missing_operator_open_id", raw);
85
+ }
86
+ return {
87
+ kind: "bot_menu",
88
+ action: {
89
+ eventId: firstStringValue(header.event_id, raw.event_id, raw.uuid, `${eventKey}:${operatorOpenId}`) ?? `${eventKey}:${operatorOpenId}`,
90
+ eventKey,
91
+ action,
92
+ operatorOpenId,
93
+ operatorName: stringValue(operator.operator_name),
94
+ chatId: chatIdFromBotMenuEvent(event),
95
+ timestamp: parseEpochMs(event.timestamp ?? header.create_time ?? raw.create_time),
96
+ raw
97
+ }
98
+ };
99
+ }
100
+ export function normalizeLarkMessageRecallWithReason(raw) {
101
+ if (!isRecord(raw)) {
102
+ return ignoredMessageChange("malformed_event", raw);
103
+ }
104
+ const header = eventHeader(raw);
105
+ const event = eventPayload(raw);
106
+ const messageId = stringValue(event.message_id);
107
+ if (!messageId) {
108
+ return ignoredMessageChange("missing_message_id", raw);
109
+ }
110
+ return {
111
+ kind: "recall",
112
+ recall: {
113
+ eventId: firstStringValue(header.event_id, raw.event_id, raw.uuid, messageId) ?? messageId,
114
+ messageId,
115
+ chatId: stringValue(event.chat_id) ?? chatIdFromChatInfo(event.chat_info),
116
+ recallTime: parseEpochMs(event.recall_time),
117
+ raw
118
+ }
119
+ };
120
+ }
121
+ export function normalizeLarkMessageContent(messageType, content) {
122
+ if (messageType === "text") {
123
+ return {
124
+ text: normalizeTextContent(content),
125
+ resources: [],
126
+ rawForCodex: false
127
+ };
128
+ }
129
+ if (messageType === "post") {
130
+ const post = normalizePostContent(content);
131
+ if (post) {
132
+ return {
133
+ ...post,
134
+ rawForCodex: false
135
+ };
136
+ }
137
+ }
138
+ if (messageType === "interactive") {
139
+ const card = normalizeInteractiveCardContent(content);
140
+ if (card) {
141
+ return {
142
+ ...card,
143
+ rawForCodex: false
144
+ };
145
+ }
146
+ }
147
+ const resources = extractMessageResources(messageType, content);
148
+ return {
149
+ text: resources.length === 0 ? null : fallbackResourceText(resources),
150
+ resources,
151
+ rawForCodex: resources.length === 0
152
+ };
153
+ }
154
+ export function stringifyRawLarkMessageForCodex(message) {
155
+ const body = isRecord(message.body) ? message.body : {};
156
+ const compact = {
157
+ message_type: stringValue(message.message_type) ?? stringValue(message.msg_type) ?? "unknown",
158
+ content: message.content ?? body.content ?? null
159
+ };
160
+ try {
161
+ return JSON.stringify(compact) ?? "";
162
+ }
163
+ catch {
164
+ return String(message);
165
+ }
166
+ }
167
+ function fallbackResourceText(resources) {
168
+ if (resources.length === 0) {
169
+ return null;
170
+ }
171
+ return resources
172
+ .map((resource) => `收到一个文件,资源 key:${resource.fileKey}`)
173
+ .join("\n");
174
+ }
175
+ function normalizePostContent(content) {
176
+ const parsed = parseContentObject(content);
177
+ const post = parsed ? getPostContent(parsed) : null;
178
+ if (!post) {
179
+ return null;
180
+ }
181
+ const resources = [];
182
+ const parts = [];
183
+ const title = stringValue(post.title)?.trim();
184
+ if (title) {
185
+ parts.push(`# ${escapeMarkdownText(title)}`);
186
+ }
187
+ const paragraphs = Array.isArray(post.content) ? post.content : [];
188
+ for (const paragraph of paragraphs) {
189
+ if (!Array.isArray(paragraph)) {
190
+ continue;
191
+ }
192
+ const rendered = renderPostParagraph(paragraph, resources).trim();
193
+ if (rendered) {
194
+ parts.push(rendered);
195
+ }
196
+ }
197
+ return {
198
+ text: parts.join("\n\n"),
199
+ resources
200
+ };
201
+ }
202
+ function getPostContent(content) {
203
+ if (Array.isArray(content.content)) {
204
+ return content;
205
+ }
206
+ for (const locale of ["zh_cn", "en_us", "ja_jp"]) {
207
+ const value = content[locale];
208
+ if (isRecord(value) && Array.isArray(value.content)) {
209
+ return value;
210
+ }
211
+ }
212
+ for (const value of Object.values(content)) {
213
+ if (isRecord(value) && Array.isArray(value.content)) {
214
+ return value;
215
+ }
216
+ }
217
+ return null;
218
+ }
219
+ function normalizeInteractiveCardContent(content) {
220
+ const resolved = resolveInteractiveCardContent(content);
221
+ if (!resolved) {
222
+ return null;
223
+ }
224
+ const resources = [];
225
+ const attributes = [];
226
+ const header = isRecord(resolved.header) ? resolved.header : {};
227
+ const title = cardHeaderTextContent(header, "title");
228
+ const subtitle = cardHeaderTextContent(header, "subtitle");
229
+ if (title) {
230
+ attributes.push(["title", title]);
231
+ }
232
+ if (subtitle) {
233
+ attributes.push(["subtitle", subtitle]);
234
+ }
235
+ const bodyParts = [];
236
+ const body = isRecord(resolved.body) ? resolved.body : {};
237
+ renderCardElements(cardChildElements(body), resources, bodyParts);
238
+ const openTag = attributes.length > 0
239
+ ? `<card ${attributes.map(([name, value]) => `${name}="${escapeXmlAttribute(value)}"`).join(" ")}>`
240
+ : "<card>";
241
+ return {
242
+ text: [openTag, ...bodyParts, "</card>"].join("\n"),
243
+ resources
244
+ };
245
+ }
246
+ function resolveInteractiveCardContent(content) {
247
+ const card = parseContentObject(content);
248
+ if (!card) {
249
+ return null;
250
+ }
251
+ if (isJson2InteractiveCard(card)) {
252
+ return card;
253
+ }
254
+ const userDsl = parseContentObject(card.user_dsl);
255
+ if (userDsl && isJson2InteractiveCard(userDsl)) {
256
+ return userDsl;
257
+ }
258
+ return null;
259
+ }
260
+ function isJson2InteractiveCard(card) {
261
+ return stringValue(card.schema) === "2.0";
262
+ }
263
+ function renderCardElements(elements, resources, parts) {
264
+ if (!Array.isArray(elements)) {
265
+ return;
266
+ }
267
+ for (const element of elements) {
268
+ renderCardElement(element, resources, parts);
269
+ }
270
+ }
271
+ function renderCardElement(element, resources, parts) {
272
+ if (!isRecord(element)) {
273
+ return;
274
+ }
275
+ const tag = stringValue(element.tag);
276
+ if (tag === "markdown") {
277
+ pushNonEmpty(parts, cardMarkdownContent(element));
278
+ return;
279
+ }
280
+ if (tag === "div") {
281
+ pushNonEmpty(parts, cardTextContent(element.text));
282
+ return;
283
+ }
284
+ if (tag === "plain_text") {
285
+ pushNonEmpty(parts, cardTextContent(element));
286
+ return;
287
+ }
288
+ if (tag === "img") {
289
+ const imageKey = cardImageKey(element);
290
+ if (imageKey) {
291
+ const placeholder = resourcePlaceholder(resources.length);
292
+ resources.push({
293
+ resourceType: "image",
294
+ fileKey: imageKey,
295
+ codexTag: "file",
296
+ textPlaceholder: placeholder
297
+ });
298
+ parts.push(placeholder);
299
+ }
300
+ return;
301
+ }
302
+ if (tag === "media") {
303
+ const fileKey = stringValue(element.file_key);
304
+ if (fileKey) {
305
+ const placeholder = resourcePlaceholder(resources.length);
306
+ resources.push({
307
+ resourceType: "file",
308
+ fileKey,
309
+ codexTag: "file",
310
+ textPlaceholder: placeholder
311
+ });
312
+ parts.push(placeholder);
313
+ }
314
+ return;
315
+ }
316
+ if (isDiscardedCardElementTag(tag)) {
317
+ return;
318
+ }
319
+ if (tag === "collapsible_panel") {
320
+ if (isRecord(element.header)) {
321
+ pushNonEmpty(parts, cardHeaderTextContent(element.header, "title"));
322
+ }
323
+ renderCardElements(cardChildElements(element), resources, parts);
324
+ return;
325
+ }
326
+ if (tag === "column_set") {
327
+ renderCardColumns(element.columns, resources, parts);
328
+ return;
329
+ }
330
+ if (isCardContainerTag(tag)) {
331
+ renderCardElements(cardChildElements(element), resources, parts);
332
+ }
333
+ }
334
+ function renderCardColumns(columns, resources, parts) {
335
+ if (!Array.isArray(columns)) {
336
+ return;
337
+ }
338
+ for (const column of columns) {
339
+ if (isRecord(column)) {
340
+ renderCardElements(cardChildElements(column), resources, parts);
341
+ }
342
+ }
343
+ }
344
+ function cardMarkdownContent(element) {
345
+ return stringValue(element.content);
346
+ }
347
+ function cardHeaderTextContent(header, key) {
348
+ return cardTextContent(header[key]);
349
+ }
350
+ function cardChildElements(element) {
351
+ return element.elements;
352
+ }
353
+ function cardTextContent(value) {
354
+ if (!isRecord(value)) {
355
+ return undefined;
356
+ }
357
+ return stringValue(value.content);
358
+ }
359
+ function cardImageKey(element) {
360
+ return stringValue(element.img_key) ?? stringValue(element.image_key);
361
+ }
362
+ function pushNonEmpty(parts, value) {
363
+ if (value !== undefined && value.trim() !== "") {
364
+ parts.push(value);
365
+ }
366
+ }
367
+ function isCardContainerTag(tag) {
368
+ return tag === "column" || tag === "form" || tag === "interactive_container";
369
+ }
370
+ function isDiscardedCardElementTag(tag) {
371
+ return tag === "button" ||
372
+ tag === "select_static" ||
373
+ tag === "multi_select_static" ||
374
+ tag === "select_person" ||
375
+ tag === "multi_select_person" ||
376
+ tag === "input" ||
377
+ tag === "chart" ||
378
+ tag === "date_picker" ||
379
+ tag === "picker_time" ||
380
+ tag === "picker_datetime" ||
381
+ tag === "checker" ||
382
+ tag === "overflow" ||
383
+ tag === "table";
384
+ }
385
+ function renderPostParagraph(paragraph, resources) {
386
+ return paragraph.map((node) => renderPostNode(node, resources)).join("");
387
+ }
388
+ function renderPostNode(node, resources) {
389
+ if (!isRecord(node)) {
390
+ return "";
391
+ }
392
+ const tag = stringValue(node.tag);
393
+ if (tag === "text") {
394
+ return renderStyledMarkdownText(stringValue(node.text) ?? "", node.style);
395
+ }
396
+ if (tag === "a") {
397
+ const text = renderStyledMarkdownText(stringValue(node.text) ?? stringValue(node.href) ?? "", node.style);
398
+ const href = stringValue(node.href);
399
+ return href ? `[${text}](${escapeMarkdownUrl(href)})` : text;
400
+ }
401
+ if (tag === "at") {
402
+ const displayName = stringValue(node.user_name) ?? stringValue(node.user_id) ?? "unknown";
403
+ return renderStyledMarkdownText(`@${displayName}`, node.style);
404
+ }
405
+ if (tag === "img") {
406
+ const imageKey = stringValue(node.image_key);
407
+ if (!imageKey) {
408
+ return renderUnsupportedPostNode(node);
409
+ }
410
+ const placeholder = resourcePlaceholder(resources.length);
411
+ resources.push({
412
+ resourceType: "image",
413
+ fileKey: imageKey,
414
+ codexTag: "img",
415
+ textPlaceholder: placeholder
416
+ });
417
+ return placeholder;
418
+ }
419
+ if (tag === "media") {
420
+ const fileKey = stringValue(node.file_key);
421
+ if (!fileKey) {
422
+ return renderUnsupportedPostNode(node);
423
+ }
424
+ const placeholder = resourcePlaceholder(resources.length);
425
+ resources.push({
426
+ resourceType: "file",
427
+ fileKey,
428
+ codexTag: "video",
429
+ textPlaceholder: placeholder
430
+ });
431
+ return placeholder;
432
+ }
433
+ if (tag === "emotion") {
434
+ const emojiType = stringValue(node.emoji_type);
435
+ return emojiType ? `:${escapeMarkdownText(emojiType)}:` : "";
436
+ }
437
+ if (tag === "hr") {
438
+ return "---";
439
+ }
440
+ if (tag === "code_block") {
441
+ const language = (stringValue(node.language) ?? "").toLowerCase();
442
+ return `\`\`\`${language}\n${stringValue(node.text) ?? ""}\n\`\`\``;
443
+ }
444
+ if (tag === "md") {
445
+ return stringValue(node.text) ?? "";
446
+ }
447
+ return renderUnsupportedPostNode(node);
448
+ }
449
+ function renderStyledMarkdownText(text, style) {
450
+ let rendered = escapeMarkdownText(text);
451
+ const styles = Array.isArray(style) ? style.filter((value) => typeof value === "string") : [];
452
+ if (styles.includes("underline")) {
453
+ rendered = `<u>${rendered}</u>`;
454
+ }
455
+ if (styles.includes("lineThrough")) {
456
+ rendered = `~~${rendered}~~`;
457
+ }
458
+ if (styles.includes("bold") && styles.includes("italic")) {
459
+ return `***${rendered}***`;
460
+ }
461
+ if (styles.includes("bold")) {
462
+ rendered = `**${rendered}**`;
463
+ }
464
+ if (styles.includes("italic")) {
465
+ rendered = `*${rendered}*`;
466
+ }
467
+ return rendered;
468
+ }
469
+ function renderUnsupportedPostNode(node) {
470
+ try {
471
+ return `\`${JSON.stringify(node).replaceAll("`", "\\`")}\``;
472
+ }
473
+ catch {
474
+ return "";
475
+ }
476
+ }
477
+ function resourcePlaceholder(index) {
478
+ return `{{TWINNY_LARK_RESOURCE_${index}}}`;
479
+ }
480
+ function escapeMarkdownText(value) {
481
+ return value.replace(/([\\`*_{}\[\]()#+.!|>~-])/g, "\\$1");
482
+ }
483
+ function escapeMarkdownUrl(value) {
484
+ return value.replace(/\)/g, "%29");
485
+ }
486
+ function escapeXmlAttribute(value) {
487
+ return value
488
+ .replace(/&/g, "&amp;")
489
+ .replace(/"/g, "&quot;")
490
+ .replace(/</g, "&lt;")
491
+ .replace(/>/g, "&gt;");
492
+ }
493
+ function extractMessageResources(messageType, content) {
494
+ const parsed = parseContentObject(content);
495
+ if (!parsed) {
496
+ return [];
497
+ }
498
+ if (messageType === "image") {
499
+ const imageKey = stringValue(parsed.image_key);
500
+ return imageKey ? [{ resourceType: "image", fileKey: imageKey }] : [];
501
+ }
502
+ if (messageType === "file" || messageType === "audio" || messageType === "media" || messageType === "video") {
503
+ const fileKey = stringValue(parsed.file_key);
504
+ return fileKey
505
+ ? [
506
+ {
507
+ resourceType: "file",
508
+ fileKey,
509
+ fileName: stringValue(parsed.file_name)
510
+ }
511
+ ]
512
+ : [];
513
+ }
514
+ return [];
515
+ }
516
+ function parseContentObject(content) {
517
+ if (isRecord(content)) {
518
+ return content;
519
+ }
520
+ if (typeof content !== "string") {
521
+ return null;
522
+ }
523
+ try {
524
+ const parsed = JSON.parse(content);
525
+ return isRecord(parsed) ? parsed : null;
526
+ }
527
+ catch {
528
+ return null;
529
+ }
530
+ }
531
+ export function normalizeTextContent(content) {
532
+ if (typeof content !== "string") {
533
+ if (isRecord(content) && typeof content.text === "string") {
534
+ return content.text;
535
+ }
536
+ return null;
537
+ }
538
+ try {
539
+ const parsed = JSON.parse(content);
540
+ if (isRecord(parsed) && typeof parsed.text === "string") {
541
+ return parsed.text;
542
+ }
543
+ }
544
+ catch {
545
+ // Some event sources emit already-decoded text; raw SDK events emit JSON strings.
546
+ }
547
+ return content;
548
+ }
549
+ function unwrapReceiveEvent(raw) {
550
+ if (isRecord(raw) && isRecord(raw.event)) {
551
+ return raw.event;
552
+ }
553
+ return raw;
554
+ }
555
+ function normalizeChatType(chatType) {
556
+ if (!chatType) {
557
+ return undefined;
558
+ }
559
+ switch (chatType.toLowerCase()) {
560
+ case "p2p":
561
+ case "p2p_chat":
562
+ case "private":
563
+ case "private_chat":
564
+ return "p2p";
565
+ case "group":
566
+ case "group_chat":
567
+ return "group";
568
+ case "topic_group":
569
+ case "topic":
570
+ return "topic_group";
571
+ default:
572
+ return undefined;
573
+ }
574
+ }
575
+ function larkThreadIdForMessage(message, messageId, chatType) {
576
+ const explicitThreadId = firstStringValue(message.thread_id);
577
+ if (explicitThreadId) {
578
+ return explicitThreadId;
579
+ }
580
+ if (chatType !== "topic_group") {
581
+ return undefined;
582
+ }
583
+ return firstStringValue(message.root_id, message.parent_id, messageId) ?? messageId;
584
+ }
585
+ function normalizeMentions(value) {
586
+ if (!Array.isArray(value)) {
587
+ return undefined;
588
+ }
589
+ const mentions = [];
590
+ for (const item of value) {
591
+ if (!isRecord(item)) {
592
+ continue;
593
+ }
594
+ const key = stringValue(item.key);
595
+ const id = isRecord(item.id) ? item.id : {};
596
+ const openId = stringValue(id.open_id) ?? stringValue(item.open_id);
597
+ const userId = stringValue(id.user_id) ?? stringValue(item.user_id);
598
+ const unionId = stringValue(id.union_id) ?? stringValue(item.union_id);
599
+ const name = stringValue(item.name);
600
+ if (!key && !openId && !userId && !unionId) {
601
+ continue;
602
+ }
603
+ mentions.push({
604
+ key: key ?? "",
605
+ openId,
606
+ userId,
607
+ unionId,
608
+ name
609
+ });
610
+ }
611
+ return mentions.length > 0 ? mentions : undefined;
612
+ }
613
+ function parseEpochMs(value) {
614
+ if (typeof value !== "string" && typeof value !== "number") {
615
+ return undefined;
616
+ }
617
+ const parsed = Number(value);
618
+ return Number.isFinite(parsed) ? parsed : undefined;
619
+ }
620
+ function ignored(reason, raw) {
621
+ return { kind: "ignored", reason, raw };
622
+ }
623
+ function ignoredMessageChange(reason, raw) {
624
+ return { kind: "ignored", reason, raw };
625
+ }
626
+ function ignoredBotMenu(reason, raw) {
627
+ return { kind: "ignored", reason, raw };
628
+ }
629
+ function botMenuActionForEventKey(eventKey) {
630
+ const normalized = eventKey.trim().toLowerCase();
631
+ switch (normalized) {
632
+ case "stop":
633
+ case "new":
634
+ case "queue":
635
+ case "status":
636
+ case "help":
637
+ return normalized;
638
+ case "new_session":
639
+ case "new-session":
640
+ case "new session":
641
+ case "new_conversation":
642
+ case "new-conversation":
643
+ return "new_session";
644
+ default:
645
+ return undefined;
646
+ }
647
+ }
648
+ function eventPayload(raw) {
649
+ return isRecord(raw.event) ? raw.event : raw;
650
+ }
651
+ function eventHeader(raw) {
652
+ return isRecord(raw.header) ? raw.header : {};
653
+ }
654
+ function chatIdFromChatInfo(value) {
655
+ if (!isRecord(value)) {
656
+ return undefined;
657
+ }
658
+ return stringValue(value.chat_id);
659
+ }
660
+ function chatIdFromBotMenuEvent(event) {
661
+ return firstStringValue(event.chat_id, event.open_chat_id, isRecord(event.chat) ? event.chat.chat_id : undefined, isRecord(event.chat) ? event.chat.open_chat_id : undefined, chatIdFromChatInfo(event.chat_info), isRecord(event.operator) ? event.operator.chat_id : undefined, isRecord(event.operator) ? event.operator.open_chat_id : undefined);
662
+ }
663
+ function stringValue(value) {
664
+ return typeof value === "string" && value.length > 0 ? value : undefined;
665
+ }
666
+ function firstStringValue(...values) {
667
+ for (const value of values) {
668
+ const string = stringValue(value);
669
+ if (string) {
670
+ return string;
671
+ }
672
+ }
673
+ return undefined;
674
+ }
675
+ function isRecord(value) {
676
+ return value !== null && typeof value === "object" && !Array.isArray(value);
677
+ }
678
+ //# sourceMappingURL=filters.js.map