@yaoyuanchao/dingtalk 1.4.15 → 1.4.17

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/channel.ts +84 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaoyuanchao/dingtalk",
3
- "version": "1.4.15",
3
+ "version": "1.4.17",
4
4
  "type": "module",
5
5
  "description": "DingTalk channel plugin for Clawdbot with Stream Mode support",
6
6
  "license": "MIT",
package/src/channel.ts CHANGED
@@ -347,6 +347,90 @@ export const dingtalkPlugin = {
347
347
  },
348
348
  },
349
349
 
350
+ // Handle message actions (sendAttachment, etc.)
351
+ actions: {
352
+ // List supported actions for this channel - SDK uses this to tell agent what's available
353
+ listActions({ cfg }: { cfg: any }) {
354
+ return ['send', 'sendAttachment'];
355
+ },
356
+
357
+ supportsAction({ action }: { action: string }) {
358
+ return action === 'sendAttachment' || action === 'send';
359
+ },
360
+
361
+ async handleAction(ctx: any) {
362
+ const { action, params, cfg, accountId } = ctx;
363
+
364
+ // Only handle sendAttachment action
365
+ if (action !== 'sendAttachment') {
366
+ return null; // Let SDK handle other actions
367
+ }
368
+
369
+ const buffer = params?.buffer;
370
+ const filename = params?.filename || 'attachment.bin';
371
+ const target = params?.target;
372
+
373
+ if (!buffer || !target) {
374
+ return null; // Let SDK handle if missing required params
375
+ }
376
+
377
+ const account = resolveDingTalkAccount({ cfg, accountId });
378
+ const { type, id } = parseOutboundTo(target);
379
+
380
+ // Decode base64 buffer
381
+ let fileBuffer: Buffer;
382
+ try {
383
+ fileBuffer = Buffer.from(buffer, 'base64');
384
+ } catch {
385
+ return { ok: false, error: 'Invalid base64 buffer' };
386
+ }
387
+
388
+ // Add UTF-8 BOM for text files
389
+ const isTextFile = /\.(txt|md|json|csv|xml|html?)$/i.test(filename);
390
+ if (isTextFile) {
391
+ const bom = Buffer.from([0xEF, 0xBB, 0xBF]);
392
+ // Check if BOM already exists
393
+ if (fileBuffer[0] !== 0xEF || fileBuffer[1] !== 0xBB || fileBuffer[2] !== 0xBF) {
394
+ fileBuffer = Buffer.concat([bom, fileBuffer]);
395
+ }
396
+ }
397
+
398
+ // Upload file
399
+ const uploadResult = await uploadMediaFile({
400
+ clientId: account.clientId,
401
+ clientSecret: account.clientSecret,
402
+ robotCode: account.robotCode || account.clientId,
403
+ fileBuffer,
404
+ fileName: filename,
405
+ fileType: 'file',
406
+ });
407
+
408
+ if (!uploadResult.mediaId) {
409
+ console.warn(`[dingtalk] sendAttachment upload failed: ${uploadResult.error}`);
410
+ return { ok: false, error: uploadResult.error };
411
+ }
412
+
413
+ // Send file
414
+ const sendResult = await sendFileMessage({
415
+ clientId: account.clientId,
416
+ clientSecret: account.clientSecret,
417
+ robotCode: account.robotCode || account.clientId,
418
+ userId: type === 'dm' ? id : undefined,
419
+ conversationId: type === 'group' ? id : undefined,
420
+ mediaId: uploadResult.mediaId,
421
+ fileName: filename,
422
+ });
423
+
424
+ if (!sendResult.ok) {
425
+ console.warn(`[dingtalk] sendAttachment send failed: ${sendResult.error}`);
426
+ return { ok: false, error: sendResult.error };
427
+ }
428
+
429
+ console.log(`[dingtalk] sendAttachment success: ${filename}`);
430
+ return { ok: true, channel: 'dingtalk', filename };
431
+ },
432
+ },
433
+
350
434
  gateway: {
351
435
  async startAccount({ account, signal, setStatus }) {
352
436
  const runtime = getDingTalkRuntime();