claude-threads 1.6.2 → 1.6.3
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 +6 -0
- package/dist/index.js +39 -33
- package/dist/mcp/permission-server.js +21 -671
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.6.3] - 2026-04-21
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Skipped file attachments are now surfaced on session start** - When a user starts a session with an unsupported file (e.g. `.xlsx`), the bot posts the `⚠️ Some files could not be processed` warning instead of silently dropping it. The same warning now fires on the mid-thread context-prompt and worktree paths. (#325, thanks @shaders)
|
|
12
|
+
- **Recognize `.har` and `.log` as text** - Both extensions come through as `application/octet-stream` via Mattermost/Slack and were previously dropped as unsupported. (#325)
|
|
13
|
+
|
|
8
14
|
## [1.6.2] - 2026-04-20
|
|
9
15
|
|
|
10
16
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -59420,6 +59420,8 @@ var TEXT_FILE_EXTENSIONS = [
|
|
|
59420
59420
|
".xml",
|
|
59421
59421
|
".yaml",
|
|
59422
59422
|
".yml",
|
|
59423
|
+
".har",
|
|
59424
|
+
".log",
|
|
59423
59425
|
".js",
|
|
59424
59426
|
".ts",
|
|
59425
59427
|
".jsx",
|
|
@@ -59990,7 +59992,7 @@ function getUnsupportedFileSuggestion(file) {
|
|
|
59990
59992
|
async function buildMessageContent(text, platform, files, debug = false) {
|
|
59991
59993
|
const result = await processFiles(platform, files, debug);
|
|
59992
59994
|
if (result.blocks.length === 0) {
|
|
59993
|
-
return text;
|
|
59995
|
+
return { content: text, skipped: result.skipped };
|
|
59994
59996
|
}
|
|
59995
59997
|
if (text) {
|
|
59996
59998
|
result.blocks.push({
|
|
@@ -59998,7 +60000,12 @@ async function buildMessageContent(text, platform, files, debug = false) {
|
|
|
59998
60000
|
text
|
|
59999
60001
|
});
|
|
60000
60002
|
}
|
|
60001
|
-
return result.blocks;
|
|
60003
|
+
return { content: result.blocks, skipped: result.skipped };
|
|
60004
|
+
}
|
|
60005
|
+
async function postSkippedFilesFeedback(platform, threadId, skipped) {
|
|
60006
|
+
if (skipped.length === 0)
|
|
60007
|
+
return;
|
|
60008
|
+
await platform.createPost(formatSkippedFilesFeedback(skipped), threadId);
|
|
60002
60009
|
}
|
|
60003
60010
|
async function processFiles(platform, files, debug = false) {
|
|
60004
60011
|
const blocks = [];
|
|
@@ -60052,6 +60059,18 @@ async function processFiles(platform, files, debug = false) {
|
|
|
60052
60059
|
}
|
|
60053
60060
|
return { blocks, skipped };
|
|
60054
60061
|
}
|
|
60062
|
+
function formatSkippedFilesFeedback(skippedFiles) {
|
|
60063
|
+
const lines = ["⚠️ **Some files could not be processed:**"];
|
|
60064
|
+
for (const file of skippedFiles) {
|
|
60065
|
+
let line = `- **${file.name}**: ${file.reason}`;
|
|
60066
|
+
if (file.suggestion) {
|
|
60067
|
+
line += ` _(${file.suggestion})_`;
|
|
60068
|
+
}
|
|
60069
|
+
lines.push(line);
|
|
60070
|
+
}
|
|
60071
|
+
return lines.join(`
|
|
60072
|
+
`);
|
|
60073
|
+
}
|
|
60055
60074
|
function startTyping(session) {
|
|
60056
60075
|
if (session.timers.typingTimer)
|
|
60057
60076
|
return;
|
|
@@ -60498,20 +60517,15 @@ class MessageManager {
|
|
|
60498
60517
|
}
|
|
60499
60518
|
this.session.threadLogger?.logUserMessage(username || this.session.startedBy, message, displayName, files && files.length > 0);
|
|
60500
60519
|
await this.prepareForUserMessage();
|
|
60501
|
-
let skippedFiles = [];
|
|
60502
|
-
if (files && files.length > 0) {
|
|
60503
|
-
const fileResult = await processFiles(this.platform, files);
|
|
60504
|
-
skippedFiles = fileResult.skipped;
|
|
60505
|
-
}
|
|
60506
60520
|
let content = message;
|
|
60521
|
+
let skippedFiles = [];
|
|
60507
60522
|
if (this.buildMessageContentCallback) {
|
|
60508
|
-
|
|
60523
|
+
const built = await this.buildMessageContentCallback(message, this.platform, files);
|
|
60524
|
+
content = built.content;
|
|
60525
|
+
skippedFiles = built.skipped;
|
|
60509
60526
|
}
|
|
60510
60527
|
this.session.claude.sendMessage(content);
|
|
60511
|
-
|
|
60512
|
-
const feedback = this.formatSkippedFilesFeedback(skippedFiles);
|
|
60513
|
-
await this.platform.createPost(feedback, this.threadId);
|
|
60514
|
-
}
|
|
60528
|
+
await postSkippedFilesFeedback(this.platform, this.threadId, skippedFiles);
|
|
60515
60529
|
this.session.lastActivityAt = new Date;
|
|
60516
60530
|
this.session.isProcessing = true;
|
|
60517
60531
|
this.emitSessionUpdateCallback?.({ status: "active", isTyping: true });
|
|
@@ -60519,18 +60533,6 @@ class MessageManager {
|
|
|
60519
60533
|
logger.debug("User message sent to Claude");
|
|
60520
60534
|
return true;
|
|
60521
60535
|
}
|
|
60522
|
-
formatSkippedFilesFeedback(skippedFiles) {
|
|
60523
|
-
const lines = ["⚠️ **Some files could not be processed:**"];
|
|
60524
|
-
for (const file of skippedFiles) {
|
|
60525
|
-
let line = `- **${file.name}**: ${file.reason}`;
|
|
60526
|
-
if (file.suggestion) {
|
|
60527
|
-
line += ` _(${file.suggestion})_`;
|
|
60528
|
-
}
|
|
60529
|
-
lines.push(line);
|
|
60530
|
-
}
|
|
60531
|
-
return lines.join(`
|
|
60532
|
-
`);
|
|
60533
|
-
}
|
|
60534
60536
|
getSession() {
|
|
60535
60537
|
return this.session;
|
|
60536
60538
|
}
|
|
@@ -66294,9 +66296,10 @@ ${fmt.formatItalic("Claude Code restarted in the new worktree")}`);
|
|
|
66294
66296
|
const contextPrefix = options2.formatContextForClaude(threadMessages, workSummary);
|
|
66295
66297
|
const messageToSend = contextPrefix + session.firstPrompt;
|
|
66296
66298
|
session.messageCount++;
|
|
66297
|
-
const content = await options2.buildMessageContent(messageToSend, session, undefined);
|
|
66299
|
+
const { content, skipped } = await options2.buildMessageContent(messageToSend, session, undefined);
|
|
66298
66300
|
session.claude.sendMessage(content);
|
|
66299
66301
|
options2.startTyping(session);
|
|
66302
|
+
await postSkippedFilesFeedback(session.platform, session.threadId, skipped);
|
|
66300
66303
|
sessionLog3(session).debug(`\uD83C\uDF3F Auto-included ${threadMessages.length} messages + work summary for mid-session worktree`);
|
|
66301
66304
|
}
|
|
66302
66305
|
session.worktreeResponsePostId = undefined;
|
|
@@ -66899,11 +66902,12 @@ async function handleContextPromptTimeout(session, ctx) {
|
|
|
66899
66902
|
}
|
|
66900
66903
|
session.messageCount++;
|
|
66901
66904
|
const messageToSend = ctx.injectMetadataReminder(queuedPrompt, session);
|
|
66902
|
-
const content = await ctx.buildMessageContent(messageToSend, session, queuedFiles);
|
|
66905
|
+
const { content, skipped } = await ctx.buildMessageContent(messageToSend, session, queuedFiles);
|
|
66903
66906
|
if (session.claude.isRunning()) {
|
|
66904
66907
|
session.claude.sendMessage(content);
|
|
66905
66908
|
ctx.startTyping(session);
|
|
66906
66909
|
}
|
|
66910
|
+
await postSkippedFilesFeedback(session.platform, session.threadId, skipped);
|
|
66907
66911
|
ctx.persistSession(session);
|
|
66908
66912
|
sessionLog5(session).debug(`\uD83E\uDDF5 Context prompt timed out, continuing without thread context`);
|
|
66909
66913
|
}
|
|
@@ -66920,11 +66924,12 @@ async function offerContextPrompt(session, queuedPrompt, queuedFiles, ctx, exclu
|
|
|
66920
66924
|
sessionLog5(session).debug(`\uD83E\uDDF5 Including work summary (no thread messages)`);
|
|
66921
66925
|
}
|
|
66922
66926
|
messageToSend = ctx.injectMetadataReminder(messageToSend, session);
|
|
66923
|
-
const content = await ctx.buildMessageContent(messageToSend, session, queuedFiles);
|
|
66927
|
+
const { content, skipped } = await ctx.buildMessageContent(messageToSend, session, queuedFiles);
|
|
66924
66928
|
if (session.claude.isRunning()) {
|
|
66925
66929
|
session.claude.sendMessage(content);
|
|
66926
66930
|
ctx.startTyping(session);
|
|
66927
66931
|
}
|
|
66932
|
+
await postSkippedFilesFeedback(session.platform, session.threadId, skipped);
|
|
66928
66933
|
return false;
|
|
66929
66934
|
}
|
|
66930
66935
|
if (messageCount === 1) {
|
|
@@ -66938,11 +66943,12 @@ async function offerContextPrompt(session, queuedPrompt, queuedFiles, ctx, exclu
|
|
|
66938
66943
|
}
|
|
66939
66944
|
session.messageCount++;
|
|
66940
66945
|
messageToSend = ctx.injectMetadataReminder(messageToSend, session);
|
|
66941
|
-
const content = await ctx.buildMessageContent(messageToSend, session, queuedFiles);
|
|
66946
|
+
const { content, skipped } = await ctx.buildMessageContent(messageToSend, session, queuedFiles);
|
|
66942
66947
|
if (session.claude.isRunning()) {
|
|
66943
66948
|
session.claude.sendMessage(content);
|
|
66944
66949
|
ctx.startTyping(session);
|
|
66945
66950
|
}
|
|
66951
|
+
await postSkippedFilesFeedback(session.platform, session.threadId, skipped);
|
|
66946
66952
|
sessionLog5(session).debug(`\uD83E\uDDF5 Auto-included 1 message as context (thread starter)${previousWorkSummary ? " + work summary" : ""}`);
|
|
66947
66953
|
return false;
|
|
66948
66954
|
}
|
|
@@ -67119,7 +67125,7 @@ function createMessageManager(session, ctx) {
|
|
|
67119
67125
|
}
|
|
67120
67126
|
session.messageCount++;
|
|
67121
67127
|
messageToSend = maybeInjectMetadataReminder(messageToSend, session, ctx, session);
|
|
67122
|
-
const content = await ctx.ops.buildMessageContent(messageToSend, session.platform, undefined);
|
|
67128
|
+
const { content } = await ctx.ops.buildMessageContent(messageToSend, session.platform, undefined);
|
|
67123
67129
|
if (session.claude.isRunning()) {
|
|
67124
67130
|
session.claude.sendMessage(content);
|
|
67125
67131
|
ctx.ops.startTyping(session);
|
|
@@ -67425,17 +67431,19 @@ ${CHAT_PLATFORM_PROMPT}`;
|
|
|
67425
67431
|
await ctx.ops.updateStickyMessage();
|
|
67426
67432
|
return;
|
|
67427
67433
|
}
|
|
67428
|
-
const content = await ctx.ops.buildMessageContent(options2.prompt, session.platform, options2.files);
|
|
67434
|
+
const { content, skipped } = await ctx.ops.buildMessageContent(options2.prompt, session.platform, options2.files);
|
|
67429
67435
|
const messageText = typeof content === "string" ? content : options2.prompt;
|
|
67430
67436
|
if (replyToPostId) {
|
|
67431
67437
|
const excludePostId = triggeringPostId || replyToPostId;
|
|
67432
67438
|
const contextOffered = await ctx.ops.offerContextPrompt(session, messageText, options2.files, excludePostId);
|
|
67433
67439
|
if (contextOffered) {
|
|
67440
|
+
await postSkippedFilesFeedback(session.platform, actualThreadId, skipped);
|
|
67434
67441
|
return;
|
|
67435
67442
|
}
|
|
67436
67443
|
}
|
|
67437
67444
|
session.messageCount++;
|
|
67438
67445
|
claude.sendMessage(content);
|
|
67446
|
+
await postSkippedFilesFeedback(session.platform, actualThreadId, skipped);
|
|
67439
67447
|
}
|
|
67440
67448
|
async function resumeSession(state, ctx) {
|
|
67441
67449
|
if (!state.threadId || !state.platformId || !state.claudeSessionId || !state.workingDir) {
|
|
@@ -67620,9 +67628,7 @@ async function sendFollowUp(session, message, files, ctx, username, displayName)
|
|
|
67620
67628
|
if (session.needsContextPromptOnNextMessage) {
|
|
67621
67629
|
session.needsContextPromptOnNextMessage = false;
|
|
67622
67630
|
await session.messageManager?.prepareForUserMessage();
|
|
67623
|
-
const
|
|
67624
|
-
const messageText = typeof content === "string" ? content : message;
|
|
67625
|
-
const contextOffered = await ctx.ops.offerContextPrompt(session, messageText, files);
|
|
67631
|
+
const contextOffered = await ctx.ops.offerContextPrompt(session, message, files);
|
|
67626
67632
|
if (contextOffered) {
|
|
67627
67633
|
session.lastActivityAt = new Date;
|
|
67628
67634
|
return;
|
|
@@ -15849,7 +15849,7 @@ var require_validation3 = __commonJS((exports, module) => {
|
|
|
15849
15849
|
|
|
15850
15850
|
// node_modules/ws/lib/receiver.js
|
|
15851
15851
|
var require_receiver = __commonJS((exports, module) => {
|
|
15852
|
-
var { Writable
|
|
15852
|
+
var { Writable } = __require("stream");
|
|
15853
15853
|
var PerMessageDeflate = require_permessage_deflate();
|
|
15854
15854
|
var {
|
|
15855
15855
|
BINARY_TYPES,
|
|
@@ -15868,7 +15868,7 @@ var require_receiver = __commonJS((exports, module) => {
|
|
|
15868
15868
|
var INFLATING = 5;
|
|
15869
15869
|
var DEFER_EVENT = 6;
|
|
15870
15870
|
|
|
15871
|
-
class Receiver extends
|
|
15871
|
+
class Receiver extends Writable {
|
|
15872
15872
|
constructor(options2 = {}) {
|
|
15873
15873
|
super();
|
|
15874
15874
|
this._allowSynchronousEvents = options2.allowSynchronousEvents !== undefined ? options2.allowSynchronousEvents : true;
|
|
@@ -16906,7 +16906,7 @@ var require_websocket = __commonJS((exports, module) => {
|
|
|
16906
16906
|
var net = __require("net");
|
|
16907
16907
|
var tls = __require("tls");
|
|
16908
16908
|
var { randomBytes, createHash } = __require("crypto");
|
|
16909
|
-
var { Duplex, Readable
|
|
16909
|
+
var { Duplex, Readable } = __require("stream");
|
|
16910
16910
|
var { URL: URL2 } = __require("url");
|
|
16911
16911
|
var PerMessageDeflate = require_permessage_deflate();
|
|
16912
16912
|
var Receiver = require_receiver();
|
|
@@ -52407,661 +52407,28 @@ function createMessageManagerEvents() {
|
|
|
52407
52407
|
|
|
52408
52408
|
// src/operations/streaming/handler.ts
|
|
52409
52409
|
var import_yauzl = __toESM(require_yauzl(), 1);
|
|
52410
|
-
import { createGunzip } from "zlib";
|
|
52411
|
-
import { pipeline as pipeline2 } from "stream/promises";
|
|
52412
|
-
import { Readable, Writable } from "stream";
|
|
52413
52410
|
var log2 = createLogger("streaming");
|
|
52414
52411
|
var MAX_PDF_SIZE = 32 * 1024 * 1024;
|
|
52415
52412
|
var MAX_TEXT_FILE_SIZE = 1 * 1024 * 1024;
|
|
52416
52413
|
var MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024;
|
|
52417
52414
|
var MAX_ZIP_SIZE = 50 * 1024 * 1024;
|
|
52418
52415
|
var MAX_GZIP_SIZE = 50 * 1024 * 1024;
|
|
52419
|
-
|
|
52420
|
-
|
|
52421
|
-
|
|
52422
|
-
|
|
52423
|
-
"image/gif",
|
|
52424
|
-
"image/webp"
|
|
52425
|
-
];
|
|
52426
|
-
var SUPPORTED_TEXT_TYPES = [
|
|
52427
|
-
"text/plain",
|
|
52428
|
-
"text/markdown",
|
|
52429
|
-
"text/csv",
|
|
52430
|
-
"text/xml",
|
|
52431
|
-
"text/yaml",
|
|
52432
|
-
"text/x-yaml",
|
|
52433
|
-
"application/json",
|
|
52434
|
-
"application/xml",
|
|
52435
|
-
"application/x-yaml",
|
|
52436
|
-
"application/yaml"
|
|
52437
|
-
];
|
|
52438
|
-
var TEXT_FILE_EXTENSIONS = [
|
|
52439
|
-
".txt",
|
|
52440
|
-
".md",
|
|
52441
|
-
".markdown",
|
|
52442
|
-
".json",
|
|
52443
|
-
".csv",
|
|
52444
|
-
".xml",
|
|
52445
|
-
".yaml",
|
|
52446
|
-
".yml",
|
|
52447
|
-
".js",
|
|
52448
|
-
".ts",
|
|
52449
|
-
".jsx",
|
|
52450
|
-
".tsx",
|
|
52451
|
-
".py",
|
|
52452
|
-
".rb",
|
|
52453
|
-
".go",
|
|
52454
|
-
".rs",
|
|
52455
|
-
".java",
|
|
52456
|
-
".c",
|
|
52457
|
-
".cpp",
|
|
52458
|
-
".h",
|
|
52459
|
-
".hpp",
|
|
52460
|
-
".cs",
|
|
52461
|
-
".php",
|
|
52462
|
-
".swift",
|
|
52463
|
-
".kt",
|
|
52464
|
-
".scala",
|
|
52465
|
-
".sh",
|
|
52466
|
-
".bash",
|
|
52467
|
-
".zsh",
|
|
52468
|
-
".fish",
|
|
52469
|
-
".ps1",
|
|
52470
|
-
".bat",
|
|
52471
|
-
".cmd",
|
|
52472
|
-
".html",
|
|
52473
|
-
".htm",
|
|
52474
|
-
".css",
|
|
52475
|
-
".scss",
|
|
52476
|
-
".sass",
|
|
52477
|
-
".less",
|
|
52478
|
-
".sql",
|
|
52479
|
-
".graphql",
|
|
52480
|
-
".gql",
|
|
52481
|
-
".toml",
|
|
52482
|
-
".ini",
|
|
52483
|
-
".cfg",
|
|
52484
|
-
".conf",
|
|
52485
|
-
".env",
|
|
52486
|
-
".properties",
|
|
52487
|
-
".dockerfile",
|
|
52488
|
-
".gitignore",
|
|
52489
|
-
".gitattributes",
|
|
52490
|
-
".editorconfig"
|
|
52491
|
-
];
|
|
52492
|
-
function isImageFile(file2) {
|
|
52493
|
-
return file2.mimeType.startsWith("image/") && SUPPORTED_IMAGE_TYPES.includes(file2.mimeType);
|
|
52494
|
-
}
|
|
52495
|
-
function isPdfFile(file2) {
|
|
52496
|
-
return file2.mimeType === "application/pdf" || file2.name.toLowerCase().endsWith(".pdf");
|
|
52497
|
-
}
|
|
52498
|
-
function isTextFile(file2) {
|
|
52499
|
-
if (SUPPORTED_TEXT_TYPES.includes(file2.mimeType)) {
|
|
52500
|
-
return true;
|
|
52501
|
-
}
|
|
52502
|
-
const lowerName = file2.name.toLowerCase();
|
|
52503
|
-
return TEXT_FILE_EXTENSIONS.some((ext) => lowerName.endsWith(ext));
|
|
52504
|
-
}
|
|
52505
|
-
function isGzipFile(file2) {
|
|
52506
|
-
return file2.mimeType === "application/gzip" || file2.mimeType === "application/x-gzip" || file2.name.toLowerCase().endsWith(".gz");
|
|
52507
|
-
}
|
|
52508
|
-
function isZipFile(file2) {
|
|
52509
|
-
return file2.mimeType === "application/zip" || file2.mimeType === "application/x-zip-compressed" || file2.name.toLowerCase().endsWith(".zip");
|
|
52510
|
-
}
|
|
52511
|
-
function categorizeFile(file2) {
|
|
52512
|
-
if (isImageFile(file2))
|
|
52513
|
-
return "image";
|
|
52514
|
-
if (isPdfFile(file2))
|
|
52515
|
-
return "pdf";
|
|
52516
|
-
if (isZipFile(file2))
|
|
52517
|
-
return "zip";
|
|
52518
|
-
if (isGzipFile(file2))
|
|
52519
|
-
return "gzip";
|
|
52520
|
-
if (isTextFile(file2))
|
|
52521
|
-
return "text";
|
|
52522
|
-
return "unsupported";
|
|
52523
|
-
}
|
|
52524
|
-
async function processImageFile(file2, platform, debug = false) {
|
|
52525
|
-
try {
|
|
52526
|
-
if (!platform.downloadFile) {
|
|
52527
|
-
return {
|
|
52528
|
-
skipped: {
|
|
52529
|
-
name: file2.name,
|
|
52530
|
-
reason: "Platform does not support file downloads"
|
|
52531
|
-
}
|
|
52532
|
-
};
|
|
52533
|
-
}
|
|
52534
|
-
const buffer = await platform.downloadFile(file2.id);
|
|
52535
|
-
const base644 = buffer.toString("base64");
|
|
52536
|
-
if (debug) {
|
|
52537
|
-
log2.debug(`Attached image: ${file2.name} (${file2.mimeType}, ${Math.round(buffer.length / 1024)}KB)`);
|
|
52538
|
-
}
|
|
52539
|
-
return {
|
|
52540
|
-
block: {
|
|
52541
|
-
type: "image",
|
|
52542
|
-
source: {
|
|
52543
|
-
type: "base64",
|
|
52544
|
-
media_type: file2.mimeType,
|
|
52545
|
-
data: base644
|
|
52546
|
-
}
|
|
52547
|
-
}
|
|
52548
|
-
};
|
|
52549
|
-
} catch (err) {
|
|
52550
|
-
log2.error(`Failed to download image ${file2.name}: ${err}`);
|
|
52551
|
-
return {
|
|
52552
|
-
skipped: {
|
|
52553
|
-
name: file2.name,
|
|
52554
|
-
reason: `Download failed: ${err instanceof Error ? err.message : String(err)}`
|
|
52555
|
-
}
|
|
52556
|
-
};
|
|
52557
|
-
}
|
|
52558
|
-
}
|
|
52559
|
-
async function processPdfFile(file2, platform, debug = false) {
|
|
52560
|
-
try {
|
|
52561
|
-
if (!platform.downloadFile) {
|
|
52562
|
-
return {
|
|
52563
|
-
skipped: {
|
|
52564
|
-
name: file2.name,
|
|
52565
|
-
reason: "Platform does not support file downloads"
|
|
52566
|
-
}
|
|
52567
|
-
};
|
|
52568
|
-
}
|
|
52569
|
-
const buffer = await platform.downloadFile(file2.id);
|
|
52570
|
-
if (buffer.length > MAX_PDF_SIZE) {
|
|
52571
|
-
return {
|
|
52572
|
-
skipped: {
|
|
52573
|
-
name: file2.name,
|
|
52574
|
-
reason: `PDF exceeds ${Math.round(MAX_PDF_SIZE / 1024 / 1024)}MB limit (${Math.round(buffer.length / 1024 / 1024)}MB)`,
|
|
52575
|
-
suggestion: "Try splitting the PDF into smaller parts"
|
|
52576
|
-
}
|
|
52577
|
-
};
|
|
52578
|
-
}
|
|
52579
|
-
const base644 = buffer.toString("base64");
|
|
52580
|
-
if (debug) {
|
|
52581
|
-
log2.debug(`Attached PDF: ${file2.name} (${Math.round(buffer.length / 1024)}KB)`);
|
|
52582
|
-
}
|
|
52583
|
-
return {
|
|
52584
|
-
block: {
|
|
52585
|
-
type: "document",
|
|
52586
|
-
source: {
|
|
52587
|
-
type: "base64",
|
|
52588
|
-
media_type: "application/pdf",
|
|
52589
|
-
data: base644
|
|
52590
|
-
},
|
|
52591
|
-
title: file2.name
|
|
52592
|
-
}
|
|
52593
|
-
};
|
|
52594
|
-
} catch (err) {
|
|
52595
|
-
log2.error(`Failed to process PDF ${file2.name}: ${err}`);
|
|
52596
|
-
return {
|
|
52597
|
-
skipped: {
|
|
52598
|
-
name: file2.name,
|
|
52599
|
-
reason: `Processing failed: ${err instanceof Error ? err.message : String(err)}`
|
|
52600
|
-
}
|
|
52601
|
-
};
|
|
52602
|
-
}
|
|
52603
|
-
}
|
|
52604
|
-
async function processTextFile(file2, platform, debug = false) {
|
|
52605
|
-
try {
|
|
52606
|
-
if (!platform.downloadFile) {
|
|
52607
|
-
return {
|
|
52608
|
-
skipped: {
|
|
52609
|
-
name: file2.name,
|
|
52610
|
-
reason: "Platform does not support file downloads"
|
|
52611
|
-
}
|
|
52612
|
-
};
|
|
52613
|
-
}
|
|
52614
|
-
const buffer = await platform.downloadFile(file2.id);
|
|
52615
|
-
if (buffer.length > MAX_TEXT_FILE_SIZE) {
|
|
52616
|
-
return {
|
|
52617
|
-
skipped: {
|
|
52618
|
-
name: file2.name,
|
|
52619
|
-
reason: `File exceeds ${Math.round(MAX_TEXT_FILE_SIZE / 1024)}KB limit (${Math.round(buffer.length / 1024)}KB)`,
|
|
52620
|
-
suggestion: "Try splitting the file or extracting relevant portions"
|
|
52621
|
-
}
|
|
52622
|
-
};
|
|
52623
|
-
}
|
|
52624
|
-
const content = buffer.toString("utf-8");
|
|
52625
|
-
if (debug) {
|
|
52626
|
-
log2.debug(`Attached text file: ${file2.name} (${Math.round(buffer.length / 1024)}KB)`);
|
|
52627
|
-
}
|
|
52628
|
-
const wrappedContent = formatTextFileContent(file2.name, content);
|
|
52629
|
-
return {
|
|
52630
|
-
block: {
|
|
52631
|
-
type: "text",
|
|
52632
|
-
text: wrappedContent
|
|
52633
|
-
}
|
|
52634
|
-
};
|
|
52635
|
-
} catch (err) {
|
|
52636
|
-
log2.error(`Failed to process text file ${file2.name}: ${err}`);
|
|
52637
|
-
return {
|
|
52638
|
-
skipped: {
|
|
52639
|
-
name: file2.name,
|
|
52640
|
-
reason: `Processing failed: ${err instanceof Error ? err.message : String(err)}`
|
|
52641
|
-
}
|
|
52642
|
-
};
|
|
52643
|
-
}
|
|
52644
|
-
}
|
|
52645
|
-
function formatTextFileContent(filename, content) {
|
|
52646
|
-
return `\uD83D\uDCC4 **${filename}**:
|
|
52647
|
-
\`\`\`
|
|
52648
|
-
${content}
|
|
52649
|
-
\`\`\``;
|
|
52650
|
-
}
|
|
52651
|
-
async function decompressGzipStream(compressedBuffer) {
|
|
52652
|
-
const chunks = [];
|
|
52653
|
-
let totalSize = 0;
|
|
52654
|
-
const gunzip = createGunzip();
|
|
52655
|
-
const source = Readable.from(compressedBuffer);
|
|
52656
|
-
const collector = new Writable({
|
|
52657
|
-
write(chunk, _encoding, callback) {
|
|
52658
|
-
totalSize += chunk.length;
|
|
52659
|
-
if (totalSize > MAX_DECOMPRESSED_SIZE) {
|
|
52660
|
-
callback(new Error(`Decompressed size exceeds ${Math.round(MAX_DECOMPRESSED_SIZE / 1024 / 1024)}MB limit`));
|
|
52661
|
-
return;
|
|
52662
|
-
}
|
|
52663
|
-
chunks.push(chunk);
|
|
52664
|
-
callback();
|
|
52665
|
-
}
|
|
52666
|
-
});
|
|
52667
|
-
await pipeline2(source, gunzip, collector);
|
|
52668
|
-
return Buffer.concat(chunks);
|
|
52669
|
-
}
|
|
52670
|
-
async function processGzipFile(file2, platform, debug = false) {
|
|
52671
|
-
try {
|
|
52672
|
-
if (!platform.downloadFile) {
|
|
52673
|
-
return {
|
|
52674
|
-
skipped: {
|
|
52675
|
-
name: file2.name,
|
|
52676
|
-
reason: "Platform does not support file downloads"
|
|
52677
|
-
}
|
|
52678
|
-
};
|
|
52679
|
-
}
|
|
52680
|
-
if (file2.size && file2.size > MAX_GZIP_SIZE) {
|
|
52681
|
-
return {
|
|
52682
|
-
skipped: {
|
|
52683
|
-
name: file2.name,
|
|
52684
|
-
reason: `Gzip file exceeds ${Math.round(MAX_GZIP_SIZE / 1024 / 1024)}MB limit (${Math.round(file2.size / 1024 / 1024)}MB)`,
|
|
52685
|
-
suggestion: "Try compressing a smaller file or splitting the content"
|
|
52686
|
-
}
|
|
52687
|
-
};
|
|
52688
|
-
}
|
|
52689
|
-
let compressedBuffer;
|
|
52690
|
-
try {
|
|
52691
|
-
compressedBuffer = await platform.downloadFile(file2.id);
|
|
52692
|
-
} catch (err) {
|
|
52693
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
52694
|
-
log2.error(`Failed to download gzip file ${file2.name}: ${errorMessage}`);
|
|
52695
|
-
return {
|
|
52696
|
-
skipped: {
|
|
52697
|
-
name: file2.name,
|
|
52698
|
-
reason: `Download failed: ${errorMessage}`,
|
|
52699
|
-
suggestion: "Check if the file is still available and try again"
|
|
52700
|
-
}
|
|
52701
|
-
};
|
|
52702
|
-
}
|
|
52703
|
-
if (file2.size && compressedBuffer.length !== file2.size) {
|
|
52704
|
-
log2.warn(`Downloaded size mismatch for ${file2.name}: expected ${file2.size}, got ${compressedBuffer.length}`);
|
|
52705
|
-
}
|
|
52706
|
-
let decompressedBuffer;
|
|
52707
|
-
try {
|
|
52708
|
-
decompressedBuffer = await decompressGzipStream(compressedBuffer);
|
|
52709
|
-
} catch (err) {
|
|
52710
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
52711
|
-
let reason;
|
|
52712
|
-
let suggestion;
|
|
52713
|
-
if (errorMessage.includes("incorrect header check")) {
|
|
52714
|
-
reason = "Invalid gzip file: the file header is corrupted or this is not a gzip file";
|
|
52715
|
-
suggestion = "Verify the file is a valid gzip archive";
|
|
52716
|
-
} else if (errorMessage.includes("unexpected end of file")) {
|
|
52717
|
-
reason = "Incomplete gzip file: the file appears to be truncated";
|
|
52718
|
-
suggestion = "Re-download the file or check if the upload completed";
|
|
52719
|
-
} else if (errorMessage.includes("invalid stored block lengths")) {
|
|
52720
|
-
reason = "Corrupted gzip file: the compressed data is damaged";
|
|
52721
|
-
suggestion = "Try re-compressing the original file";
|
|
52722
|
-
} else if (errorMessage.includes("exceeds") && errorMessage.includes("limit")) {
|
|
52723
|
-
reason = errorMessage;
|
|
52724
|
-
suggestion = "Try extracting only the relevant portions of the file";
|
|
52725
|
-
} else {
|
|
52726
|
-
reason = `Decompression failed: ${errorMessage}`;
|
|
52727
|
-
suggestion = "Verify the file is a valid gzip archive";
|
|
52728
|
-
}
|
|
52729
|
-
return {
|
|
52730
|
-
skipped: {
|
|
52731
|
-
name: file2.name,
|
|
52732
|
-
reason,
|
|
52733
|
-
suggestion
|
|
52734
|
-
}
|
|
52735
|
-
};
|
|
52736
|
-
}
|
|
52737
|
-
const innerFilename = file2.name.toLowerCase().endsWith(".gz") ? file2.name.slice(0, -3) : file2.name;
|
|
52738
|
-
const contentType = detectDecompressedContentType(decompressedBuffer, innerFilename);
|
|
52739
|
-
if (debug) {
|
|
52740
|
-
log2.debug(`Decompressed ${file2.name}: ${Math.round(decompressedBuffer.length / 1024)}KB, detected type: ${contentType}`);
|
|
52741
|
-
}
|
|
52742
|
-
if (contentType === "pdf") {
|
|
52743
|
-
const base644 = decompressedBuffer.toString("base64");
|
|
52744
|
-
return {
|
|
52745
|
-
block: {
|
|
52746
|
-
type: "document",
|
|
52747
|
-
source: {
|
|
52748
|
-
type: "base64",
|
|
52749
|
-
media_type: "application/pdf",
|
|
52750
|
-
data: base644
|
|
52751
|
-
},
|
|
52752
|
-
title: innerFilename
|
|
52753
|
-
}
|
|
52754
|
-
};
|
|
52755
|
-
} else if (contentType === "text") {
|
|
52756
|
-
const content = decompressedBuffer.toString("utf-8");
|
|
52757
|
-
const wrappedContent = formatTextFileContent(innerFilename, content);
|
|
52758
|
-
return {
|
|
52759
|
-
block: {
|
|
52760
|
-
type: "text",
|
|
52761
|
-
text: wrappedContent
|
|
52762
|
-
}
|
|
52763
|
-
};
|
|
52764
|
-
} else {
|
|
52765
|
-
return {
|
|
52766
|
-
skipped: {
|
|
52767
|
-
name: file2.name,
|
|
52768
|
-
reason: "Decompressed content type not supported",
|
|
52769
|
-
suggestion: "Only text-based files and PDFs are supported after decompression"
|
|
52770
|
-
}
|
|
52771
|
-
};
|
|
52772
|
-
}
|
|
52773
|
-
} catch (err) {
|
|
52774
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
52775
|
-
log2.error(`Failed to process gzip file ${file2.name}: ${errorMessage}`);
|
|
52776
|
-
return {
|
|
52777
|
-
skipped: {
|
|
52778
|
-
name: file2.name,
|
|
52779
|
-
reason: `Processing failed: ${errorMessage}`,
|
|
52780
|
-
suggestion: "An unexpected error occurred. Please try again or contact support if the issue persists"
|
|
52781
|
-
}
|
|
52782
|
-
};
|
|
52783
|
-
}
|
|
52784
|
-
}
|
|
52785
|
-
async function extractZipEntry(zipfile, entry) {
|
|
52786
|
-
return new Promise((resolve2, reject) => {
|
|
52787
|
-
zipfile.openReadStream(entry, (err, readStream) => {
|
|
52788
|
-
if (err) {
|
|
52789
|
-
reject(err);
|
|
52790
|
-
return;
|
|
52791
|
-
}
|
|
52792
|
-
if (!readStream) {
|
|
52793
|
-
reject(new Error("No read stream"));
|
|
52794
|
-
return;
|
|
52795
|
-
}
|
|
52796
|
-
const chunks = [];
|
|
52797
|
-
readStream.on("data", (chunk) => chunks.push(chunk));
|
|
52798
|
-
readStream.on("end", () => resolve2(Buffer.concat(chunks)));
|
|
52799
|
-
readStream.on("error", reject);
|
|
52800
|
-
});
|
|
52801
|
-
});
|
|
52802
|
-
}
|
|
52803
|
-
async function processZipFile(file2, platform, debug = false) {
|
|
52804
|
-
const blocks = [];
|
|
52805
|
-
const skipped = [];
|
|
52806
|
-
try {
|
|
52807
|
-
if (!platform.downloadFile) {
|
|
52808
|
-
return {
|
|
52809
|
-
blocks: [],
|
|
52810
|
-
skipped: [{
|
|
52811
|
-
name: file2.name,
|
|
52812
|
-
reason: "Platform does not support file downloads"
|
|
52813
|
-
}]
|
|
52814
|
-
};
|
|
52815
|
-
}
|
|
52816
|
-
if (file2.size && file2.size > MAX_ZIP_SIZE) {
|
|
52817
|
-
return {
|
|
52818
|
-
blocks: [],
|
|
52819
|
-
skipped: [{
|
|
52820
|
-
name: file2.name,
|
|
52821
|
-
reason: `Zip file exceeds ${Math.round(MAX_ZIP_SIZE / 1024 / 1024)}MB limit (${Math.round(file2.size / 1024 / 1024)}MB)`
|
|
52822
|
-
}]
|
|
52823
|
-
};
|
|
52824
|
-
}
|
|
52825
|
-
const zipBuffer = await platform.downloadFile(file2.id);
|
|
52826
|
-
if (debug) {
|
|
52827
|
-
log2.debug(`Processing zip file ${file2.name}: ${Math.round(zipBuffer.length / 1024)}KB`);
|
|
52828
|
-
}
|
|
52829
|
-
const zipfile = await new Promise((resolve2, reject) => {
|
|
52830
|
-
import_yauzl.default.fromBuffer(zipBuffer, { lazyEntries: true }, (err, zf) => {
|
|
52831
|
-
if (err)
|
|
52832
|
-
reject(err);
|
|
52833
|
-
else if (!zf)
|
|
52834
|
-
reject(new Error("Failed to open zip file"));
|
|
52835
|
-
else
|
|
52836
|
-
resolve2(zf);
|
|
52837
|
-
});
|
|
52838
|
-
});
|
|
52839
|
-
const entries = [];
|
|
52840
|
-
await new Promise((resolve2, reject) => {
|
|
52841
|
-
zipfile.on("entry", (entry) => {
|
|
52842
|
-
if (!entry.fileName.endsWith("/")) {
|
|
52843
|
-
entries.push(entry);
|
|
52844
|
-
}
|
|
52845
|
-
zipfile.readEntry();
|
|
52846
|
-
});
|
|
52847
|
-
zipfile.on("end", resolve2);
|
|
52848
|
-
zipfile.on("error", reject);
|
|
52849
|
-
zipfile.readEntry();
|
|
52850
|
-
});
|
|
52851
|
-
if (entries.length > MAX_ZIP_FILES) {
|
|
52852
|
-
zipfile.close();
|
|
52853
|
-
return {
|
|
52854
|
-
blocks: [],
|
|
52855
|
-
skipped: [{
|
|
52856
|
-
name: file2.name,
|
|
52857
|
-
reason: `Zip contains too many files (${entries.length}). Maximum is ${MAX_ZIP_FILES} files.`,
|
|
52858
|
-
suggestion: "Extract and upload the most relevant files individually"
|
|
52859
|
-
}]
|
|
52860
|
-
};
|
|
52861
|
-
}
|
|
52862
|
-
if (entries.length === 0) {
|
|
52863
|
-
zipfile.close();
|
|
52864
|
-
return {
|
|
52865
|
-
blocks: [],
|
|
52866
|
-
skipped: [{
|
|
52867
|
-
name: file2.name,
|
|
52868
|
-
reason: "Zip archive is empty"
|
|
52869
|
-
}]
|
|
52870
|
-
};
|
|
52871
|
-
}
|
|
52872
|
-
const zipfile2 = await new Promise((resolve2, reject) => {
|
|
52873
|
-
import_yauzl.default.fromBuffer(zipBuffer, { lazyEntries: true }, (err, zf) => {
|
|
52874
|
-
if (err)
|
|
52875
|
-
reject(err);
|
|
52876
|
-
else if (!zf)
|
|
52877
|
-
reject(new Error("Failed to open zip file"));
|
|
52878
|
-
else
|
|
52879
|
-
resolve2(zf);
|
|
52880
|
-
});
|
|
52881
|
-
});
|
|
52882
|
-
let processedCount = 0;
|
|
52883
|
-
await new Promise((resolve2, reject) => {
|
|
52884
|
-
zipfile2.on("entry", async (entry) => {
|
|
52885
|
-
try {
|
|
52886
|
-
if (entry.fileName.endsWith("/")) {
|
|
52887
|
-
zipfile2.readEntry();
|
|
52888
|
-
return;
|
|
52889
|
-
}
|
|
52890
|
-
if (entry.uncompressedSize > MAX_DECOMPRESSED_SIZE) {
|
|
52891
|
-
skipped.push({
|
|
52892
|
-
name: entry.fileName,
|
|
52893
|
-
reason: `File exceeds ${Math.round(MAX_DECOMPRESSED_SIZE / 1024 / 1024)}MB decompressed size limit`
|
|
52894
|
-
});
|
|
52895
|
-
zipfile2.readEntry();
|
|
52896
|
-
return;
|
|
52897
|
-
}
|
|
52898
|
-
const buffer = await extractZipEntry(zipfile2, entry);
|
|
52899
|
-
const contentType = detectDecompressedContentType(buffer, entry.fileName);
|
|
52900
|
-
if (debug) {
|
|
52901
|
-
log2.debug(`Extracted ${entry.fileName}: ${Math.round(buffer.length / 1024)}KB, type: ${contentType}`);
|
|
52902
|
-
}
|
|
52903
|
-
if (contentType === "pdf") {
|
|
52904
|
-
const base644 = buffer.toString("base64");
|
|
52905
|
-
blocks.push({
|
|
52906
|
-
type: "document",
|
|
52907
|
-
source: {
|
|
52908
|
-
type: "base64",
|
|
52909
|
-
media_type: "application/pdf",
|
|
52910
|
-
data: base644
|
|
52911
|
-
}
|
|
52912
|
-
});
|
|
52913
|
-
processedCount++;
|
|
52914
|
-
} else if (contentType === "text") {
|
|
52915
|
-
const content = buffer.toString("utf-8");
|
|
52916
|
-
const wrappedContent = formatTextFileContent(entry.fileName, content);
|
|
52917
|
-
blocks.push({
|
|
52918
|
-
type: "text",
|
|
52919
|
-
text: wrappedContent
|
|
52920
|
-
});
|
|
52921
|
-
processedCount++;
|
|
52922
|
-
} else {
|
|
52923
|
-
skipped.push({
|
|
52924
|
-
name: entry.fileName,
|
|
52925
|
-
reason: "Unsupported file type inside zip",
|
|
52926
|
-
suggestion: "Only text-based files and PDFs are supported"
|
|
52927
|
-
});
|
|
52928
|
-
}
|
|
52929
|
-
zipfile2.readEntry();
|
|
52930
|
-
} catch (err) {
|
|
52931
|
-
skipped.push({
|
|
52932
|
-
name: entry.fileName,
|
|
52933
|
-
reason: `Failed to extract: ${err instanceof Error ? err.message : String(err)}`
|
|
52934
|
-
});
|
|
52935
|
-
zipfile2.readEntry();
|
|
52936
|
-
}
|
|
52937
|
-
});
|
|
52938
|
-
zipfile2.on("end", resolve2);
|
|
52939
|
-
zipfile2.on("error", reject);
|
|
52940
|
-
zipfile2.readEntry();
|
|
52941
|
-
});
|
|
52942
|
-
zipfile2.close();
|
|
52943
|
-
if (debug) {
|
|
52944
|
-
log2.debug(`Zip ${file2.name}: processed ${processedCount} files, skipped ${skipped.length}`);
|
|
52945
|
-
}
|
|
52946
|
-
return { blocks, skipped };
|
|
52947
|
-
} catch (err) {
|
|
52948
|
-
log2.error(`Failed to process zip file ${file2.name}: ${err}`);
|
|
52949
|
-
return {
|
|
52950
|
-
blocks: [],
|
|
52951
|
-
skipped: [{
|
|
52952
|
-
name: file2.name,
|
|
52953
|
-
reason: `Failed to process zip: ${err instanceof Error ? err.message : String(err)}`
|
|
52954
|
-
}]
|
|
52955
|
-
};
|
|
52956
|
-
}
|
|
52957
|
-
}
|
|
52958
|
-
function detectDecompressedContentType(buffer, filename) {
|
|
52959
|
-
if (buffer.length >= 5 && buffer.toString("ascii", 0, 5) === "%PDF-") {
|
|
52960
|
-
return "pdf";
|
|
52961
|
-
}
|
|
52962
|
-
const lowerFilename = filename.toLowerCase();
|
|
52963
|
-
if (lowerFilename.endsWith(".pdf")) {
|
|
52964
|
-
return "pdf";
|
|
52965
|
-
}
|
|
52966
|
-
if (TEXT_FILE_EXTENSIONS.some((ext) => lowerFilename.endsWith(ext))) {
|
|
52967
|
-
return "text";
|
|
52968
|
-
}
|
|
52969
|
-
if (buffer.length > 0) {
|
|
52970
|
-
const firstChar = String.fromCharCode(buffer[0]);
|
|
52971
|
-
if (firstChar === "{" || firstChar === "[") {
|
|
52972
|
-
return "text";
|
|
52973
|
-
}
|
|
52974
|
-
}
|
|
52975
|
-
try {
|
|
52976
|
-
const text = buffer.toString("utf-8");
|
|
52977
|
-
const printableRatio = countPrintableChars(text) / text.length;
|
|
52978
|
-
if (printableRatio > 0.9) {
|
|
52979
|
-
return "text";
|
|
52980
|
-
}
|
|
52981
|
-
} catch {}
|
|
52982
|
-
return "unknown";
|
|
52983
|
-
}
|
|
52984
|
-
function countPrintableChars(text) {
|
|
52985
|
-
let count = 0;
|
|
52986
|
-
for (let i = 0;i < text.length; i++) {
|
|
52987
|
-
const code = text.charCodeAt(i);
|
|
52988
|
-
if (code >= 32 && code <= 126 || code === 9 || code === 10 || code === 13) {
|
|
52989
|
-
count++;
|
|
52990
|
-
}
|
|
52991
|
-
}
|
|
52992
|
-
return count;
|
|
52993
|
-
}
|
|
52994
|
-
function getUnsupportedFileSuggestion(file2) {
|
|
52995
|
-
const ext = file2.name.toLowerCase().split(".").pop();
|
|
52996
|
-
const mime = file2.mimeType.toLowerCase();
|
|
52997
|
-
if (ext === "doc" || ext === "docx" || mime.includes("msword") || mime.includes("wordprocessingml")) {
|
|
52998
|
-
return "Convert to PDF for best results";
|
|
52999
|
-
}
|
|
53000
|
-
if (ext === "xls" || ext === "xlsx" || mime.includes("spreadsheet")) {
|
|
53001
|
-
return "Export as CSV for text-based analysis";
|
|
53002
|
-
}
|
|
53003
|
-
if (ext === "ppt" || ext === "pptx" || mime.includes("presentation")) {
|
|
53004
|
-
return "Convert to PDF for best results";
|
|
53005
|
-
}
|
|
53006
|
-
if (ext === "tar" || ext === "rar" || ext === "7z") {
|
|
53007
|
-
return "Extract files and upload them individually, or use .zip format";
|
|
53008
|
-
}
|
|
53009
|
-
if (ext === "exe" || ext === "dll" || ext === "so" || ext === "dylib") {
|
|
53010
|
-
return "Binary files are not supported";
|
|
53011
|
-
}
|
|
53012
|
-
return;
|
|
52416
|
+
async function postSkippedFilesFeedback(platform, threadId, skipped) {
|
|
52417
|
+
if (skipped.length === 0)
|
|
52418
|
+
return;
|
|
52419
|
+
await platform.createPost(formatSkippedFilesFeedback(skipped), threadId);
|
|
53013
52420
|
}
|
|
53014
|
-
|
|
53015
|
-
const
|
|
53016
|
-
const
|
|
53017
|
-
|
|
53018
|
-
|
|
53019
|
-
|
|
53020
|
-
for (const file2 of files) {
|
|
53021
|
-
const category = categorizeFile(file2);
|
|
53022
|
-
if (category === "zip") {
|
|
53023
|
-
const zipResult = await processZipFile(file2, platform, debug);
|
|
53024
|
-
blocks.push(...zipResult.blocks);
|
|
53025
|
-
for (const s of zipResult.skipped) {
|
|
53026
|
-
skipped.push(s);
|
|
53027
|
-
log2.warn(`Skipped file ${s.name}: ${s.reason}`);
|
|
53028
|
-
}
|
|
53029
|
-
continue;
|
|
53030
|
-
}
|
|
53031
|
-
let result;
|
|
53032
|
-
switch (category) {
|
|
53033
|
-
case "image":
|
|
53034
|
-
result = await processImageFile(file2, platform, debug);
|
|
53035
|
-
break;
|
|
53036
|
-
case "pdf":
|
|
53037
|
-
result = await processPdfFile(file2, platform, debug);
|
|
53038
|
-
break;
|
|
53039
|
-
case "text":
|
|
53040
|
-
result = await processTextFile(file2, platform, debug);
|
|
53041
|
-
break;
|
|
53042
|
-
case "gzip":
|
|
53043
|
-
result = await processGzipFile(file2, platform, debug);
|
|
53044
|
-
break;
|
|
53045
|
-
case "unsupported":
|
|
53046
|
-
default:
|
|
53047
|
-
result = {
|
|
53048
|
-
skipped: {
|
|
53049
|
-
name: file2.name,
|
|
53050
|
-
reason: `Unsupported file type: ${file2.mimeType}`,
|
|
53051
|
-
suggestion: getUnsupportedFileSuggestion(file2)
|
|
53052
|
-
}
|
|
53053
|
-
};
|
|
53054
|
-
break;
|
|
53055
|
-
}
|
|
53056
|
-
if (result.block) {
|
|
53057
|
-
blocks.push(result.block);
|
|
53058
|
-
}
|
|
53059
|
-
if (result.skipped) {
|
|
53060
|
-
skipped.push(result.skipped);
|
|
53061
|
-
log2.warn(`Skipped file ${result.skipped.name}: ${result.skipped.reason}`);
|
|
52421
|
+
function formatSkippedFilesFeedback(skippedFiles) {
|
|
52422
|
+
const lines = ["⚠️ **Some files could not be processed:**"];
|
|
52423
|
+
for (const file2 of skippedFiles) {
|
|
52424
|
+
let line = `- **${file2.name}**: ${file2.reason}`;
|
|
52425
|
+
if (file2.suggestion) {
|
|
52426
|
+
line += ` _(${file2.suggestion})_`;
|
|
53062
52427
|
}
|
|
52428
|
+
lines.push(line);
|
|
53063
52429
|
}
|
|
53064
|
-
return
|
|
52430
|
+
return lines.join(`
|
|
52431
|
+
`);
|
|
53065
52432
|
}
|
|
53066
52433
|
|
|
53067
52434
|
// src/operations/message-manager.ts
|
|
@@ -53495,20 +52862,15 @@ class MessageManager {
|
|
|
53495
52862
|
}
|
|
53496
52863
|
this.session.threadLogger?.logUserMessage(username || this.session.startedBy, message, displayName, files && files.length > 0);
|
|
53497
52864
|
await this.prepareForUserMessage();
|
|
53498
|
-
let skippedFiles = [];
|
|
53499
|
-
if (files && files.length > 0) {
|
|
53500
|
-
const fileResult = await processFiles(this.platform, files);
|
|
53501
|
-
skippedFiles = fileResult.skipped;
|
|
53502
|
-
}
|
|
53503
52865
|
let content = message;
|
|
52866
|
+
let skippedFiles = [];
|
|
53504
52867
|
if (this.buildMessageContentCallback) {
|
|
53505
|
-
|
|
52868
|
+
const built = await this.buildMessageContentCallback(message, this.platform, files);
|
|
52869
|
+
content = built.content;
|
|
52870
|
+
skippedFiles = built.skipped;
|
|
53506
52871
|
}
|
|
53507
52872
|
this.session.claude.sendMessage(content);
|
|
53508
|
-
|
|
53509
|
-
const feedback = this.formatSkippedFilesFeedback(skippedFiles);
|
|
53510
|
-
await this.platform.createPost(feedback, this.threadId);
|
|
53511
|
-
}
|
|
52873
|
+
await postSkippedFilesFeedback(this.platform, this.threadId, skippedFiles);
|
|
53512
52874
|
this.session.lastActivityAt = new Date;
|
|
53513
52875
|
this.session.isProcessing = true;
|
|
53514
52876
|
this.emitSessionUpdateCallback?.({ status: "active", isTyping: true });
|
|
@@ -53516,18 +52878,6 @@ class MessageManager {
|
|
|
53516
52878
|
logger.debug("User message sent to Claude");
|
|
53517
52879
|
return true;
|
|
53518
52880
|
}
|
|
53519
|
-
formatSkippedFilesFeedback(skippedFiles) {
|
|
53520
|
-
const lines = ["⚠️ **Some files could not be processed:**"];
|
|
53521
|
-
for (const file2 of skippedFiles) {
|
|
53522
|
-
let line = `- **${file2.name}**: ${file2.reason}`;
|
|
53523
|
-
if (file2.suggestion) {
|
|
53524
|
-
line += ` _(${file2.suggestion})_`;
|
|
53525
|
-
}
|
|
53526
|
-
lines.push(line);
|
|
53527
|
-
}
|
|
53528
|
-
return lines.join(`
|
|
53529
|
-
`);
|
|
53530
|
-
}
|
|
53531
52881
|
getSession() {
|
|
53532
52882
|
return this.session;
|
|
53533
52883
|
}
|