eniac-slack 0.1.13 → 0.1.15
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/CHANGELOG.md +10 -0
- package/dist/services/claude.d.ts.map +1 -1
- package/dist/services/claude.js +33 -15
- package/dist/services/claude.js.map +1 -1
- package/dist/utils/slack-files.d.ts +4 -2
- package/dist/utils/slack-files.d.ts.map +1 -1
- package/dist/utils/slack-files.js +62 -51
- package/dist/utils/slack-files.js.map +1 -1
- package/package.json +1 -1
- package/src/services/claude.ts +41 -16
- package/src/utils/slack-files.ts +75 -52
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.15] - 2026-03-12
|
|
4
|
+
|
|
5
|
+
- fix(slack): 이미지 로깅 강화 + magic bytes 불일치 허용 (#24)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## [0.1.14] - 2026-03-12
|
|
9
|
+
|
|
10
|
+
- fix(slack): sharp 정규화 + AsyncIterable로 이미지 직접 전달 (#23)
|
|
11
|
+
|
|
12
|
+
|
|
3
13
|
## [0.1.13] - 2026-03-12
|
|
4
14
|
|
|
5
15
|
- fix(slack): sharp로 이미지 정규화하여 Could not process image 해결 (#22)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/services/claude.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/services/claude.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAK9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,UAAU,OAAO;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAuJvC;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CASzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAExE;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAaT;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAEhE;AAkBD;;;;;GAKG;AACH,wBAAuB,IAAI,CACzB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,SAAS,EACtB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,cAAc,EAAE,GACxB,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAoN1C"}
|
package/dist/services/claude.js
CHANGED
|
@@ -233,26 +233,44 @@ export async function* chat(threadTs, userMessage, slackClient, channel, images)
|
|
|
233
233
|
session.lastActivityAt = Date.now();
|
|
234
234
|
saveSessions();
|
|
235
235
|
console.log(`[claude] starting query, cwd=${session.workDir}, hasStarted=${session.hasStarted}`);
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
236
|
+
// Build prompt: string for text-only, AsyncIterable<SDKUserMessage> for images
|
|
237
|
+
const hasImages = images && images.length > 0;
|
|
238
|
+
let promptInput;
|
|
239
|
+
if (hasImages) {
|
|
240
|
+
const contentBlocks = [];
|
|
241
|
+
for (const img of images) {
|
|
242
|
+
contentBlocks.push({
|
|
243
|
+
type: "image",
|
|
244
|
+
source: {
|
|
245
|
+
type: "base64",
|
|
246
|
+
media_type: img.mediaType,
|
|
247
|
+
data: img.base64,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
contentBlocks.push({ type: "text", text: userMessage });
|
|
252
|
+
for (const img of images) {
|
|
253
|
+
console.log(`[claude] image: mediaType=${img.mediaType}, base64Length=${img.base64.length}, first20chars=${img.base64.substring(0, 20)}`);
|
|
247
254
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
console.log(`[claude] sending ${images.length} image(s) as inline content blocks via AsyncIterable<SDKUserMessage>`);
|
|
256
|
+
const userMsg = {
|
|
257
|
+
type: "user",
|
|
258
|
+
message: { role: "user", content: contentBlocks },
|
|
259
|
+
parent_tool_use_id: null,
|
|
260
|
+
session_id: "",
|
|
261
|
+
};
|
|
262
|
+
async function* singleMessage() {
|
|
263
|
+
yield userMsg;
|
|
264
|
+
}
|
|
265
|
+
promptInput = singleMessage();
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
promptInput = userMessage;
|
|
251
269
|
}
|
|
252
270
|
let receivedSuccessResult = false;
|
|
253
271
|
try {
|
|
254
272
|
const q = query({
|
|
255
|
-
prompt,
|
|
273
|
+
prompt: promptInput,
|
|
256
274
|
options: {
|
|
257
275
|
cwd: session.workDir,
|
|
258
276
|
canUseTool,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/services/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/services/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,12 +5,14 @@ export interface SlackImageFile {
|
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Download image files from a Slack message's `files` array.
|
|
8
|
-
*
|
|
9
|
-
* Only images with supported media types are returned; non-image files are skipped.
|
|
10
8
|
*/
|
|
11
9
|
export declare function downloadSlackImages(client: WebClient, files: Array<{
|
|
12
10
|
url_private_download?: string;
|
|
13
11
|
url_private?: string;
|
|
14
12
|
mimetype?: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
filetype?: string;
|
|
15
|
+
size?: number;
|
|
16
|
+
id?: string;
|
|
15
17
|
}>): Promise<SlackImageFile[]>;
|
|
16
18
|
//# sourceMappingURL=slack-files.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-files.d.ts","sourceRoot":"","sources":["../../src/utils/slack-files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;CACpE;
|
|
1
|
+
{"version":3,"file":"slack-files.d.ts","sourceRoot":"","sources":["../../src/utils/slack-files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;CACpE;AAwBD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,KAAK,CAAC;IACX,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC,GACD,OAAO,CAAC,cAAc,EAAE,CAAC,CAyF3B"}
|
|
@@ -5,92 +5,103 @@ const SUPPORTED_TYPES = new Set([
|
|
|
5
5
|
"image/gif",
|
|
6
6
|
"image/webp",
|
|
7
7
|
]);
|
|
8
|
-
/**
|
|
9
|
-
* Validate that a buffer actually contains image data by checking magic bytes.
|
|
10
|
-
*/
|
|
11
|
-
function isValidImage(buf, expectedMime) {
|
|
12
|
-
if (buf.length < 4)
|
|
13
|
-
return false;
|
|
14
|
-
switch (expectedMime) {
|
|
15
|
-
case "image/png":
|
|
16
|
-
return buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47;
|
|
17
|
-
case "image/jpeg":
|
|
18
|
-
return buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff;
|
|
19
|
-
case "image/gif":
|
|
20
|
-
return buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46;
|
|
21
|
-
case "image/webp":
|
|
22
|
-
return buf.length >= 12 && buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46
|
|
23
|
-
&& buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50;
|
|
24
|
-
default:
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
8
|
const MAX_IMAGE_DIMENSION = 1568; // Claude API recommended max
|
|
29
9
|
/**
|
|
30
|
-
*
|
|
31
|
-
* This fixes issues with exotic color spaces, corrupted chunks, and oversized images.
|
|
10
|
+
* Detect actual image format from magic bytes.
|
|
32
11
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
12
|
+
function detectImageFormat(buf) {
|
|
13
|
+
if (buf.length < 12)
|
|
14
|
+
return null;
|
|
15
|
+
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47)
|
|
16
|
+
return "image/png";
|
|
17
|
+
if (buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff)
|
|
18
|
+
return "image/jpeg";
|
|
19
|
+
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46)
|
|
20
|
+
return "image/gif";
|
|
21
|
+
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46
|
|
22
|
+
&& buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50)
|
|
23
|
+
return "image/webp";
|
|
24
|
+
return null;
|
|
42
25
|
}
|
|
43
26
|
/**
|
|
44
27
|
* Download image files from a Slack message's `files` array.
|
|
45
|
-
*
|
|
46
|
-
* Only images with supported media types are returned; non-image files are skipped.
|
|
47
28
|
*/
|
|
48
29
|
export async function downloadSlackImages(client, files) {
|
|
49
30
|
const token = client.token;
|
|
50
|
-
if (!token)
|
|
31
|
+
if (!token) {
|
|
32
|
+
console.warn("[slack-files] no token found on WebClient");
|
|
51
33
|
return [];
|
|
34
|
+
}
|
|
52
35
|
const results = [];
|
|
53
36
|
for (const file of files) {
|
|
54
37
|
const mime = file.mimetype;
|
|
55
|
-
|
|
38
|
+
console.log(`[slack-files] processing file: id=${file.id}, name=${file.name}, filetype=${file.filetype}, mimetype=${mime}, size=${file.size}`);
|
|
39
|
+
if (!mime || !SUPPORTED_TYPES.has(mime)) {
|
|
40
|
+
console.log(`[slack-files] skipping unsupported mime: ${mime}`);
|
|
56
41
|
continue;
|
|
42
|
+
}
|
|
57
43
|
const url = file.url_private_download ?? file.url_private;
|
|
58
|
-
if (!url)
|
|
44
|
+
if (!url) {
|
|
45
|
+
console.warn(`[slack-files] no download URL for file ${file.id}`);
|
|
59
46
|
continue;
|
|
47
|
+
}
|
|
48
|
+
console.log(`[slack-files] downloading from: ${url.substring(0, 80)}...`);
|
|
60
49
|
try {
|
|
61
50
|
const resp = await fetch(url, {
|
|
62
51
|
headers: { Authorization: `Bearer ${token}` },
|
|
63
52
|
});
|
|
53
|
+
console.log(`[slack-files] response: status=${resp.status}, content-type=${resp.headers.get("content-type")}, content-length=${resp.headers.get("content-length")}`);
|
|
64
54
|
if (!resp.ok) {
|
|
65
|
-
console.warn(`[slack-files] failed
|
|
55
|
+
console.warn(`[slack-files] download failed: ${resp.status} ${resp.statusText}`);
|
|
66
56
|
continue;
|
|
67
57
|
}
|
|
68
58
|
const buf = Buffer.from(await resp.arrayBuffer());
|
|
69
|
-
|
|
70
|
-
|
|
59
|
+
const hexDump = buf.subarray(0, 16).toString("hex").match(/../g)?.join(" ") ?? "";
|
|
60
|
+
const detectedFormat = detectImageFormat(buf);
|
|
61
|
+
console.log(`[slack-files] downloaded ${buf.length} bytes, first 16 bytes: ${hexDump}`);
|
|
62
|
+
console.log(`[slack-files] declared mime=${mime}, detected format=${detectedFormat}`);
|
|
63
|
+
// If the data looks like HTML (Slack error page), log and skip
|
|
64
|
+
if (buf.subarray(0, 20).toString("utf8").includes("<") || buf.subarray(0, 20).toString("utf8").includes("<!")) {
|
|
65
|
+
const preview = buf.subarray(0, 200).toString("utf8");
|
|
66
|
+
console.warn(`[slack-files] downloaded data looks like HTML, not an image! Preview: ${preview}`);
|
|
71
67
|
continue;
|
|
72
68
|
}
|
|
73
|
-
//
|
|
69
|
+
// Even if declared mime doesn't match magic bytes, try to normalize with sharp
|
|
70
|
+
// sharp can handle format detection internally
|
|
74
71
|
try {
|
|
75
|
-
const
|
|
76
|
-
console.log(`[slack-files]
|
|
72
|
+
const metadata = await sharp(buf).metadata();
|
|
73
|
+
console.log(`[slack-files] sharp metadata: format=${metadata.format}, width=${metadata.width}, height=${metadata.height}, channels=${metadata.channels}, space=${metadata.space}, size=${metadata.size}`);
|
|
74
|
+
const normalized = await sharp(buf)
|
|
75
|
+
.resize(MAX_IMAGE_DIMENSION, MAX_IMAGE_DIMENSION, {
|
|
76
|
+
fit: "inside",
|
|
77
|
+
withoutEnlargement: true,
|
|
78
|
+
})
|
|
79
|
+
.png()
|
|
80
|
+
.toBuffer();
|
|
81
|
+
const b64 = normalized.toString("base64");
|
|
82
|
+
console.log(`[slack-files] normalized: ${buf.length} → ${normalized.length} bytes, base64=${b64.length} chars`);
|
|
77
83
|
results.push({
|
|
78
|
-
base64:
|
|
79
|
-
mediaType,
|
|
84
|
+
base64: b64,
|
|
85
|
+
mediaType: "image/png",
|
|
80
86
|
});
|
|
81
87
|
}
|
|
82
|
-
catch (
|
|
83
|
-
console.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
catch (sharpErr) {
|
|
89
|
+
console.error(`[slack-files] sharp processing failed:`, sharpErr);
|
|
90
|
+
// Last resort: if magic bytes detected a valid image, try raw base64
|
|
91
|
+
if (detectedFormat && SUPPORTED_TYPES.has(detectedFormat)) {
|
|
92
|
+
console.log(`[slack-files] fallback: using raw buffer with detected format ${detectedFormat}`);
|
|
93
|
+
results.push({
|
|
94
|
+
base64: buf.toString("base64"),
|
|
95
|
+
mediaType: detectedFormat,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
88
98
|
}
|
|
89
99
|
}
|
|
90
100
|
catch (err) {
|
|
91
|
-
console.
|
|
101
|
+
console.error(`[slack-files] error downloading file ${file.id}:`, err);
|
|
92
102
|
}
|
|
93
103
|
}
|
|
104
|
+
console.log(`[slack-files] total images processed: ${results.length}`);
|
|
94
105
|
return results;
|
|
95
106
|
}
|
|
96
107
|
//# sourceMappingURL=slack-files.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-files.js","sourceRoot":"","sources":["../../src/utils/slack-files.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,YAAY;IACZ,WAAW;IACX,WAAW;IACX,YAAY;CACb,CAAC,CAAC;AAEH;;GAEG;AACH,SAAS,
|
|
1
|
+
{"version":3,"file":"slack-files.js","sourceRoot":"","sources":["../../src/utils/slack-files.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/services/claude.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
2
|
import type {
|
|
3
3
|
SDKMessage,
|
|
4
|
+
SDKUserMessage,
|
|
4
5
|
CanUseTool,
|
|
5
6
|
PermissionResult,
|
|
6
7
|
McpServerConfig,
|
|
@@ -324,30 +325,54 @@ export async function* chat(
|
|
|
324
325
|
|
|
325
326
|
console.log(`[claude] starting query, cwd=${session.workDir}, hasStarted=${session.hasStarted}`);
|
|
326
327
|
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
328
|
+
// Build prompt: string for text-only, AsyncIterable<SDKUserMessage> for images
|
|
329
|
+
const hasImages = images && images.length > 0;
|
|
330
|
+
|
|
331
|
+
// Construct the prompt with inline image content blocks for the Claude API
|
|
332
|
+
type ContentBlock =
|
|
333
|
+
| { type: "text"; text: string }
|
|
334
|
+
| { type: "image"; source: { type: "base64"; media_type: string; data: string } };
|
|
335
|
+
|
|
336
|
+
let promptInput: string | AsyncIterable<SDKUserMessage>;
|
|
337
|
+
if (hasImages) {
|
|
338
|
+
const contentBlocks: ContentBlock[] = [];
|
|
339
|
+
for (const img of images!) {
|
|
340
|
+
contentBlocks.push({
|
|
341
|
+
type: "image",
|
|
342
|
+
source: {
|
|
343
|
+
type: "base64",
|
|
344
|
+
media_type: img.mediaType,
|
|
345
|
+
data: img.base64,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
contentBlocks.push({ type: "text", text: userMessage });
|
|
350
|
+
|
|
351
|
+
for (const img of images!) {
|
|
352
|
+
console.log(`[claude] image: mediaType=${img.mediaType}, base64Length=${img.base64.length}, first20chars=${img.base64.substring(0, 20)}`);
|
|
339
353
|
}
|
|
354
|
+
console.log(`[claude] sending ${images!.length} image(s) as inline content blocks via AsyncIterable<SDKUserMessage>`);
|
|
340
355
|
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
356
|
+
const userMsg: SDKUserMessage = {
|
|
357
|
+
type: "user",
|
|
358
|
+
message: { role: "user", content: contentBlocks as never },
|
|
359
|
+
parent_tool_use_id: null,
|
|
360
|
+
session_id: "",
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
async function* singleMessage(): AsyncIterable<SDKUserMessage> {
|
|
364
|
+
yield userMsg;
|
|
365
|
+
}
|
|
366
|
+
promptInput = singleMessage();
|
|
367
|
+
} else {
|
|
368
|
+
promptInput = userMessage;
|
|
344
369
|
}
|
|
345
370
|
|
|
346
371
|
let receivedSuccessResult = false;
|
|
347
372
|
|
|
348
373
|
try {
|
|
349
374
|
const q = query({
|
|
350
|
-
prompt,
|
|
375
|
+
prompt: promptInput,
|
|
351
376
|
options: {
|
|
352
377
|
cwd: session.workDir,
|
|
353
378
|
canUseTool,
|
package/src/utils/slack-files.ts
CHANGED
|
@@ -13,99 +13,122 @@ const SUPPORTED_TYPES = new Set([
|
|
|
13
13
|
"image/webp",
|
|
14
14
|
]);
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* Validate that a buffer actually contains image data by checking magic bytes.
|
|
18
|
-
*/
|
|
19
|
-
function isValidImage(buf: Buffer, expectedMime: string): boolean {
|
|
20
|
-
if (buf.length < 4) return false;
|
|
21
|
-
switch (expectedMime) {
|
|
22
|
-
case "image/png":
|
|
23
|
-
return buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47;
|
|
24
|
-
case "image/jpeg":
|
|
25
|
-
return buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff;
|
|
26
|
-
case "image/gif":
|
|
27
|
-
return buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46;
|
|
28
|
-
case "image/webp":
|
|
29
|
-
return buf.length >= 12 && buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46
|
|
30
|
-
&& buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50;
|
|
31
|
-
default:
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
16
|
const MAX_IMAGE_DIMENSION = 1568; // Claude API recommended max
|
|
37
17
|
|
|
38
18
|
/**
|
|
39
|
-
*
|
|
40
|
-
* This fixes issues with exotic color spaces, corrupted chunks, and oversized images.
|
|
19
|
+
* Detect actual image format from magic bytes.
|
|
41
20
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return { data: normalized, mediaType: "image/png" };
|
|
21
|
+
function detectImageFormat(buf: Buffer): string | null {
|
|
22
|
+
if (buf.length < 12) return null;
|
|
23
|
+
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) return "image/png";
|
|
24
|
+
if (buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) return "image/jpeg";
|
|
25
|
+
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46) return "image/gif";
|
|
26
|
+
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46
|
|
27
|
+
&& buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) return "image/webp";
|
|
28
|
+
return null;
|
|
51
29
|
}
|
|
52
30
|
|
|
53
31
|
/**
|
|
54
32
|
* Download image files from a Slack message's `files` array.
|
|
55
|
-
*
|
|
56
|
-
* Only images with supported media types are returned; non-image files are skipped.
|
|
57
33
|
*/
|
|
58
34
|
export async function downloadSlackImages(
|
|
59
35
|
client: WebClient,
|
|
60
|
-
files: Array<{
|
|
36
|
+
files: Array<{
|
|
37
|
+
url_private_download?: string;
|
|
38
|
+
url_private?: string;
|
|
39
|
+
mimetype?: string;
|
|
40
|
+
name?: string;
|
|
41
|
+
filetype?: string;
|
|
42
|
+
size?: number;
|
|
43
|
+
id?: string;
|
|
44
|
+
}>
|
|
61
45
|
): Promise<SlackImageFile[]> {
|
|
62
46
|
const token = (client as unknown as { token?: string }).token;
|
|
63
|
-
if (!token)
|
|
47
|
+
if (!token) {
|
|
48
|
+
console.warn("[slack-files] no token found on WebClient");
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
64
51
|
|
|
65
52
|
const results: SlackImageFile[] = [];
|
|
66
53
|
|
|
67
54
|
for (const file of files) {
|
|
68
55
|
const mime = file.mimetype;
|
|
69
|
-
|
|
56
|
+
console.log(`[slack-files] processing file: id=${file.id}, name=${file.name}, filetype=${file.filetype}, mimetype=${mime}, size=${file.size}`);
|
|
57
|
+
|
|
58
|
+
if (!mime || !SUPPORTED_TYPES.has(mime)) {
|
|
59
|
+
console.log(`[slack-files] skipping unsupported mime: ${mime}`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
70
62
|
|
|
71
63
|
const url = file.url_private_download ?? file.url_private;
|
|
72
|
-
if (!url)
|
|
64
|
+
if (!url) {
|
|
65
|
+
console.warn(`[slack-files] no download URL for file ${file.id}`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
console.log(`[slack-files] downloading from: ${url.substring(0, 80)}...`);
|
|
73
69
|
|
|
74
70
|
try {
|
|
75
71
|
const resp = await fetch(url, {
|
|
76
72
|
headers: { Authorization: `Bearer ${token}` },
|
|
77
73
|
});
|
|
78
74
|
|
|
75
|
+
console.log(`[slack-files] response: status=${resp.status}, content-type=${resp.headers.get("content-type")}, content-length=${resp.headers.get("content-length")}`);
|
|
76
|
+
|
|
79
77
|
if (!resp.ok) {
|
|
80
|
-
console.warn(`[slack-files] failed
|
|
78
|
+
console.warn(`[slack-files] download failed: ${resp.status} ${resp.statusText}`);
|
|
81
79
|
continue;
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
const buf = Buffer.from(await resp.arrayBuffer());
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
const hexDump = buf.subarray(0, 16).toString("hex").match(/../g)?.join(" ") ?? "";
|
|
84
|
+
const detectedFormat = detectImageFormat(buf);
|
|
85
|
+
console.log(`[slack-files] downloaded ${buf.length} bytes, first 16 bytes: ${hexDump}`);
|
|
86
|
+
console.log(`[slack-files] declared mime=${mime}, detected format=${detectedFormat}`);
|
|
87
|
+
|
|
88
|
+
// If the data looks like HTML (Slack error page), log and skip
|
|
89
|
+
if (buf.subarray(0, 20).toString("utf8").includes("<") || buf.subarray(0, 20).toString("utf8").includes("<!")) {
|
|
90
|
+
const preview = buf.subarray(0, 200).toString("utf8");
|
|
91
|
+
console.warn(`[slack-files] downloaded data looks like HTML, not an image! Preview: ${preview}`);
|
|
87
92
|
continue;
|
|
88
93
|
}
|
|
89
94
|
|
|
90
|
-
//
|
|
95
|
+
// Even if declared mime doesn't match magic bytes, try to normalize with sharp
|
|
96
|
+
// sharp can handle format detection internally
|
|
91
97
|
try {
|
|
92
|
-
const
|
|
93
|
-
console.log(`[slack-files]
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const metadata = await sharp(buf).metadata();
|
|
99
|
+
console.log(`[slack-files] sharp metadata: format=${metadata.format}, width=${metadata.width}, height=${metadata.height}, channels=${metadata.channels}, space=${metadata.space}, size=${metadata.size}`);
|
|
100
|
+
|
|
101
|
+
const normalized = await sharp(buf)
|
|
102
|
+
.resize(MAX_IMAGE_DIMENSION, MAX_IMAGE_DIMENSION, {
|
|
103
|
+
fit: "inside",
|
|
104
|
+
withoutEnlargement: true,
|
|
105
|
+
})
|
|
106
|
+
.png()
|
|
107
|
+
.toBuffer();
|
|
108
|
+
|
|
109
|
+
const b64 = normalized.toString("base64");
|
|
110
|
+
console.log(`[slack-files] normalized: ${buf.length} → ${normalized.length} bytes, base64=${b64.length} chars`);
|
|
111
|
+
|
|
100
112
|
results.push({
|
|
101
|
-
base64:
|
|
102
|
-
mediaType:
|
|
113
|
+
base64: b64,
|
|
114
|
+
mediaType: "image/png",
|
|
103
115
|
});
|
|
116
|
+
} catch (sharpErr) {
|
|
117
|
+
console.error(`[slack-files] sharp processing failed:`, sharpErr);
|
|
118
|
+
// Last resort: if magic bytes detected a valid image, try raw base64
|
|
119
|
+
if (detectedFormat && SUPPORTED_TYPES.has(detectedFormat)) {
|
|
120
|
+
console.log(`[slack-files] fallback: using raw buffer with detected format ${detectedFormat}`);
|
|
121
|
+
results.push({
|
|
122
|
+
base64: buf.toString("base64"),
|
|
123
|
+
mediaType: detectedFormat as SlackImageFile["mediaType"],
|
|
124
|
+
});
|
|
125
|
+
}
|
|
104
126
|
}
|
|
105
127
|
} catch (err) {
|
|
106
|
-
console.
|
|
128
|
+
console.error(`[slack-files] error downloading file ${file.id}:`, err);
|
|
107
129
|
}
|
|
108
130
|
}
|
|
109
131
|
|
|
132
|
+
console.log(`[slack-files] total images processed: ${results.length}`);
|
|
110
133
|
return results;
|
|
111
134
|
}
|