onkol 0.5.1 → 0.5.2
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/plugin/discord-client.js +37 -10
- package/package.json +1 -1
- package/src/plugin/discord-client.ts +40 -12
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { Client, GatewayIntentBits } from 'discord.js';
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.svg']);
|
|
6
|
+
const ATTACHMENT_DIR = join(tmpdir(), 'onkol-attachments');
|
|
7
|
+
mkdirSync(ATTACHMENT_DIR, { recursive: true });
|
|
2
8
|
export function shouldForwardMessage(messageChannelId, authorId, isBot, targetChannelId, allowedUsers) {
|
|
3
9
|
if (isBot)
|
|
4
10
|
return false;
|
|
@@ -8,17 +14,38 @@ export function shouldForwardMessage(messageChannelId, authorId, isBot, targetCh
|
|
|
8
14
|
return false;
|
|
9
15
|
return true;
|
|
10
16
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
function isTextAttachment(a) {
|
|
18
|
+
return a.contentType?.startsWith('text/') === true || a.name?.endsWith('.txt') === true;
|
|
19
|
+
}
|
|
20
|
+
function isImageAttachment(a) {
|
|
21
|
+
if (a.contentType?.startsWith('image/'))
|
|
22
|
+
return true;
|
|
23
|
+
const name = (a.name || '').toLowerCase();
|
|
24
|
+
return IMAGE_EXTENSIONS.has(name.slice(name.lastIndexOf('.')));
|
|
25
|
+
}
|
|
26
|
+
// Resolve all attachments: text gets inlined, images get downloaded to temp files
|
|
27
|
+
async function resolveAttachments(message) {
|
|
14
28
|
let content = message.content;
|
|
15
|
-
const
|
|
16
|
-
for (const attachment of textAttachments.values()) {
|
|
29
|
+
for (const attachment of message.attachments.values()) {
|
|
17
30
|
try {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
if (isTextAttachment(attachment)) {
|
|
32
|
+
const res = await fetch(attachment.url);
|
|
33
|
+
if (res.ok) {
|
|
34
|
+
const text = await res.text();
|
|
35
|
+
content = content ? `${content}\n\n${text}` : text;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (isImageAttachment(attachment)) {
|
|
39
|
+
const res = await fetch(attachment.url);
|
|
40
|
+
if (res.ok) {
|
|
41
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
42
|
+
const filename = `${message.id}-${attachment.name || 'image.png'}`;
|
|
43
|
+
const filepath = join(ATTACHMENT_DIR, filename);
|
|
44
|
+
writeFileSync(filepath, buffer);
|
|
45
|
+
const note = `[User sent an image: ${attachment.name || 'image'}. Saved to ${filepath} — use the Read tool to view it.]`;
|
|
46
|
+
content = content ? `${content}\n\n${note}` : note;
|
|
47
|
+
console.error(`[discord-filtered] Downloaded image: ${filepath} (${buffer.length} bytes)`);
|
|
48
|
+
}
|
|
22
49
|
}
|
|
23
50
|
}
|
|
24
51
|
catch (err) {
|
|
@@ -37,7 +64,7 @@ export function createDiscordClient(config, onMessage) {
|
|
|
37
64
|
});
|
|
38
65
|
client.on('messageCreate', async (message) => {
|
|
39
66
|
if (shouldForwardMessage(message.channel.id, message.author.id, message.author.bot, config.channelId, config.allowedUsers)) {
|
|
40
|
-
const content = await
|
|
67
|
+
const content = await resolveAttachments(message);
|
|
41
68
|
if (content) {
|
|
42
69
|
onMessage(content, message);
|
|
43
70
|
}
|
package/package.json
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { Client, GatewayIntentBits, type Message, type Attachment } from 'discord.js'
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'fs'
|
|
3
|
+
import { join } from 'path'
|
|
4
|
+
import { tmpdir } from 'os'
|
|
5
|
+
|
|
6
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.svg'])
|
|
7
|
+
const ATTACHMENT_DIR = join(tmpdir(), 'onkol-attachments')
|
|
8
|
+
mkdirSync(ATTACHMENT_DIR, { recursive: true })
|
|
2
9
|
|
|
3
10
|
export interface DiscordClientConfig {
|
|
4
11
|
botToken: string
|
|
@@ -19,24 +26,45 @@ export function shouldForwardMessage(
|
|
|
19
26
|
return true
|
|
20
27
|
}
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
function isTextAttachment(a: Attachment): boolean {
|
|
30
|
+
return a.contentType?.startsWith('text/') === true || a.name?.endsWith('.txt') === true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isImageAttachment(a: Attachment): boolean {
|
|
34
|
+
if (a.contentType?.startsWith('image/')) return true
|
|
35
|
+
const name = (a.name || '').toLowerCase()
|
|
36
|
+
return IMAGE_EXTENSIONS.has(name.slice(name.lastIndexOf('.')))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Resolve all attachments: text gets inlined, images get downloaded to temp files
|
|
40
|
+
async function resolveAttachments(message: Message): Promise<string> {
|
|
25
41
|
let content = message.content
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
for (const attachment of textAttachments.values()) {
|
|
42
|
+
|
|
43
|
+
for (const attachment of message.attachments.values()) {
|
|
30
44
|
try {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
if (isTextAttachment(attachment)) {
|
|
46
|
+
const res = await fetch(attachment.url)
|
|
47
|
+
if (res.ok) {
|
|
48
|
+
const text = await res.text()
|
|
49
|
+
content = content ? `${content}\n\n${text}` : text
|
|
50
|
+
}
|
|
51
|
+
} else if (isImageAttachment(attachment)) {
|
|
52
|
+
const res = await fetch(attachment.url)
|
|
53
|
+
if (res.ok) {
|
|
54
|
+
const buffer = Buffer.from(await res.arrayBuffer())
|
|
55
|
+
const filename = `${message.id}-${attachment.name || 'image.png'}`
|
|
56
|
+
const filepath = join(ATTACHMENT_DIR, filename)
|
|
57
|
+
writeFileSync(filepath, buffer)
|
|
58
|
+
const note = `[User sent an image: ${attachment.name || 'image'}. Saved to ${filepath} — use the Read tool to view it.]`
|
|
59
|
+
content = content ? `${content}\n\n${note}` : note
|
|
60
|
+
console.error(`[discord-filtered] Downloaded image: ${filepath} (${buffer.length} bytes)`)
|
|
61
|
+
}
|
|
35
62
|
}
|
|
36
63
|
} catch (err) {
|
|
37
64
|
console.error(`[discord-filtered] Failed to fetch attachment ${attachment.name}: ${err}`)
|
|
38
65
|
}
|
|
39
66
|
}
|
|
67
|
+
|
|
40
68
|
return content
|
|
41
69
|
}
|
|
42
70
|
|
|
@@ -62,7 +90,7 @@ export function createDiscordClient(
|
|
|
62
90
|
config.allowedUsers
|
|
63
91
|
)
|
|
64
92
|
) {
|
|
65
|
-
const content = await
|
|
93
|
+
const content = await resolveAttachments(message)
|
|
66
94
|
if (content) {
|
|
67
95
|
onMessage(content, message)
|
|
68
96
|
}
|