claude-threads 1.0.10 → 1.0.12

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 CHANGED
@@ -5,6 +5,22 @@ 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.0.12] - 2026-01-15
9
+
10
+ ### Fixed
11
+ - **Skipped file feedback posting** - Fixed swapped arguments in createPost call that caused "Invalid RootId parameter" errors when posting feedback for skipped files (#221)
12
+
13
+ ## [1.0.11] - 2026-01-15
14
+
15
+ ### Added
16
+ - **Improved gzip error handling** - Uses streaming decompression for better error messages when gzip files are corrupt or truncated (#219)
17
+
18
+ ### Changed
19
+ - **Shorter initial session message** - Session start message is now more concise for popup-friendly display (#218)
20
+
21
+ ### Dependencies
22
+ - **Bump diff from 8.0.2 to 8.0.3** (#220)
23
+
8
24
  ## [1.0.10] - 2026-01-14
9
25
 
10
26
  ### Added
package/dist/index.js CHANGED
@@ -51257,15 +51257,6 @@ class ClaudeCli extends EventEmitter2 {
51257
51257
  }
51258
51258
  }
51259
51259
 
51260
- // src/logo.ts
51261
- function getLogo(version) {
51262
- return `\`\`\`
51263
- \u2734 \u2584\u2588\u2580 \u2588\u2588\u2588 \u2734 claude-threads v${version}
51264
- \u2734 \u2588\u2580 \u2588 \u2734 Chat \xD7 Claude Code
51265
- \u2734 \u2580\u2588\u2584 \u2588 \u2734
51266
- \`\`\``;
51267
- }
51268
-
51269
51260
  // src/version.ts
51270
51261
  import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
51271
51262
  import { dirname as dirname6, resolve as resolve3 } from "path";
@@ -55471,12 +55462,15 @@ function createMessageManagerEvents() {
55471
55462
 
55472
55463
  // src/operations/streaming/handler.ts
55473
55464
  var import_yauzl = __toESM(require_yauzl(), 1);
55474
- import { gunzipSync } from "zlib";
55465
+ import { createGunzip } from "zlib";
55466
+ import { pipeline } from "stream/promises";
55467
+ import { Readable, Writable } from "stream";
55475
55468
  var log17 = createLogger("streaming");
55476
55469
  var MAX_PDF_SIZE = 32 * 1024 * 1024;
55477
55470
  var MAX_TEXT_FILE_SIZE = 1 * 1024 * 1024;
55478
55471
  var MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024;
55479
55472
  var MAX_ZIP_SIZE = 50 * 1024 * 1024;
55473
+ var MAX_GZIP_SIZE = 50 * 1024 * 1024;
55480
55474
  var MAX_ZIP_FILES = 20;
55481
55475
  var SUPPORTED_IMAGE_TYPES = [
55482
55476
  "image/jpeg",
@@ -55709,6 +55703,25 @@ function formatTextFileContent(filename, content) {
55709
55703
  ${content}
55710
55704
  \`\`\``;
55711
55705
  }
55706
+ async function decompressGzipStream(compressedBuffer) {
55707
+ const chunks = [];
55708
+ let totalSize = 0;
55709
+ const gunzip = createGunzip();
55710
+ const source = Readable.from(compressedBuffer);
55711
+ const collector = new Writable({
55712
+ write(chunk, _encoding, callback) {
55713
+ totalSize += chunk.length;
55714
+ if (totalSize > MAX_DECOMPRESSED_SIZE) {
55715
+ callback(new Error(`Decompressed size exceeds ${Math.round(MAX_DECOMPRESSED_SIZE / 1024 / 1024)}MB limit`));
55716
+ return;
55717
+ }
55718
+ chunks.push(chunk);
55719
+ callback();
55720
+ }
55721
+ });
55722
+ await pipeline(source, gunzip, collector);
55723
+ return Buffer.concat(chunks);
55724
+ }
55712
55725
  async function processGzipFile(file, platform, debug = false) {
55713
55726
  try {
55714
55727
  if (!platform.downloadFile) {
@@ -55719,24 +55732,60 @@ async function processGzipFile(file, platform, debug = false) {
55719
55732
  }
55720
55733
  };
55721
55734
  }
55722
- const compressedBuffer = await platform.downloadFile(file.id);
55723
- let decompressedBuffer;
55735
+ if (file.size && file.size > MAX_GZIP_SIZE) {
55736
+ return {
55737
+ skipped: {
55738
+ name: file.name,
55739
+ reason: `Gzip file exceeds ${Math.round(MAX_GZIP_SIZE / 1024 / 1024)}MB limit (${Math.round(file.size / 1024 / 1024)}MB)`,
55740
+ suggestion: "Try compressing a smaller file or splitting the content"
55741
+ }
55742
+ };
55743
+ }
55744
+ let compressedBuffer;
55724
55745
  try {
55725
- decompressedBuffer = gunzipSync(compressedBuffer);
55746
+ compressedBuffer = await platform.downloadFile(file.id);
55726
55747
  } catch (err) {
55748
+ const errorMessage = err instanceof Error ? err.message : String(err);
55749
+ log17.error(`Failed to download gzip file ${file.name}: ${errorMessage}`);
55727
55750
  return {
55728
55751
  skipped: {
55729
55752
  name: file.name,
55730
- reason: `Decompression failed: ${err instanceof Error ? err.message : String(err)}`
55753
+ reason: `Download failed: ${errorMessage}`,
55754
+ suggestion: "Check if the file is still available and try again"
55731
55755
  }
55732
55756
  };
55733
55757
  }
55734
- if (decompressedBuffer.length > MAX_DECOMPRESSED_SIZE) {
55758
+ if (file.size && compressedBuffer.length !== file.size) {
55759
+ log17.warn(`Downloaded size mismatch for ${file.name}: expected ${file.size}, got ${compressedBuffer.length}`);
55760
+ }
55761
+ let decompressedBuffer;
55762
+ try {
55763
+ decompressedBuffer = await decompressGzipStream(compressedBuffer);
55764
+ } catch (err) {
55765
+ const errorMessage = err instanceof Error ? err.message : String(err);
55766
+ let reason;
55767
+ let suggestion;
55768
+ if (errorMessage.includes("incorrect header check")) {
55769
+ reason = "Invalid gzip file: the file header is corrupted or this is not a gzip file";
55770
+ suggestion = "Verify the file is a valid gzip archive";
55771
+ } else if (errorMessage.includes("unexpected end of file")) {
55772
+ reason = "Incomplete gzip file: the file appears to be truncated";
55773
+ suggestion = "Re-download the file or check if the upload completed";
55774
+ } else if (errorMessage.includes("invalid stored block lengths")) {
55775
+ reason = "Corrupted gzip file: the compressed data is damaged";
55776
+ suggestion = "Try re-compressing the original file";
55777
+ } else if (errorMessage.includes("exceeds") && errorMessage.includes("limit")) {
55778
+ reason = errorMessage;
55779
+ suggestion = "Try extracting only the relevant portions of the file";
55780
+ } else {
55781
+ reason = `Decompression failed: ${errorMessage}`;
55782
+ suggestion = "Verify the file is a valid gzip archive";
55783
+ }
55735
55784
  return {
55736
55785
  skipped: {
55737
55786
  name: file.name,
55738
- reason: `Decompressed size exceeds ${Math.round(MAX_DECOMPRESSED_SIZE / 1024 / 1024)}MB limit (${Math.round(decompressedBuffer.length / 1024 / 1024)}MB)`,
55739
- suggestion: "Try extracting only the relevant portions"
55787
+ reason,
55788
+ suggestion
55740
55789
  }
55741
55790
  };
55742
55791
  }
@@ -55777,11 +55826,13 @@ async function processGzipFile(file, platform, debug = false) {
55777
55826
  };
55778
55827
  }
55779
55828
  } catch (err) {
55780
- log17.error(`Failed to process gzip file ${file.name}: ${err}`);
55829
+ const errorMessage = err instanceof Error ? err.message : String(err);
55830
+ log17.error(`Failed to process gzip file ${file.name}: ${errorMessage}`);
55781
55831
  return {
55782
55832
  skipped: {
55783
55833
  name: file.name,
55784
- reason: `Processing failed: ${err instanceof Error ? err.message : String(err)}`
55834
+ reason: `Processing failed: ${errorMessage}`,
55835
+ suggestion: "An unexpected error occurred. Please try again or contact support if the issue persists"
55785
55836
  }
55786
55837
  };
55787
55838
  }
@@ -56538,7 +56589,7 @@ class MessageManager {
56538
56589
  this.session.claude.sendMessage(content);
56539
56590
  if (skippedFiles.length > 0) {
56540
56591
  const feedback = this.formatSkippedFilesFeedback(skippedFiles);
56541
- await this.platform.createPost(this.threadId, feedback);
56592
+ await this.platform.createPost(feedback, this.threadId);
56542
56593
  }
56543
56594
  this.session.lastActivityAt = new Date;
56544
56595
  this.session.isProcessing = true;
@@ -63294,9 +63345,7 @@ async function startSession(options2, username, displayName, replyToPostId, plat
63294
63345
  return;
63295
63346
  }
63296
63347
  const startFormatter = platform.getFormatter();
63297
- const startPost = await withErrorHandling(() => platform.createPost(`${getLogo(VERSION)}
63298
-
63299
- ${startFormatter.formatItalic("Starting session...")}`, replyToPostId), { action: "Create session post" });
63348
+ const startPost = await withErrorHandling(() => platform.createPost(startFormatter.formatItalic("Claude Threads session starting..."), replyToPostId), { action: "Create session post" });
63300
63349
  if (!startPost)
63301
63350
  return;
63302
63351
  const actualThreadId = replyToPostId || startPost.id;
@@ -40344,12 +40344,15 @@ function createMessageManagerEvents() {
40344
40344
 
40345
40345
  // src/operations/streaming/handler.ts
40346
40346
  var import_yauzl = __toESM(require_yauzl(), 1);
40347
- import { gunzipSync } from "zlib";
40347
+ import { createGunzip } from "zlib";
40348
+ import { pipeline as pipeline2 } from "stream/promises";
40349
+ import { Readable, Writable } from "stream";
40348
40350
  var log2 = createLogger("streaming");
40349
40351
  var MAX_PDF_SIZE = 32 * 1024 * 1024;
40350
40352
  var MAX_TEXT_FILE_SIZE = 1 * 1024 * 1024;
40351
40353
  var MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024;
40352
40354
  var MAX_ZIP_SIZE = 50 * 1024 * 1024;
40355
+ var MAX_GZIP_SIZE = 50 * 1024 * 1024;
40353
40356
  var MAX_ZIP_FILES = 20;
40354
40357
  var SUPPORTED_IMAGE_TYPES = [
40355
40358
  "image/jpeg",
@@ -40582,6 +40585,25 @@ function formatTextFileContent(filename, content) {
40582
40585
  ${content}
40583
40586
  \`\`\``;
40584
40587
  }
40588
+ async function decompressGzipStream(compressedBuffer) {
40589
+ const chunks = [];
40590
+ let totalSize = 0;
40591
+ const gunzip = createGunzip();
40592
+ const source = Readable.from(compressedBuffer);
40593
+ const collector = new Writable({
40594
+ write(chunk, _encoding, callback) {
40595
+ totalSize += chunk.length;
40596
+ if (totalSize > MAX_DECOMPRESSED_SIZE) {
40597
+ callback(new Error(`Decompressed size exceeds ${Math.round(MAX_DECOMPRESSED_SIZE / 1024 / 1024)}MB limit`));
40598
+ return;
40599
+ }
40600
+ chunks.push(chunk);
40601
+ callback();
40602
+ }
40603
+ });
40604
+ await pipeline2(source, gunzip, collector);
40605
+ return Buffer.concat(chunks);
40606
+ }
40585
40607
  async function processGzipFile(file2, platform, debug = false) {
40586
40608
  try {
40587
40609
  if (!platform.downloadFile) {
@@ -40592,24 +40614,60 @@ async function processGzipFile(file2, platform, debug = false) {
40592
40614
  }
40593
40615
  };
40594
40616
  }
40595
- const compressedBuffer = await platform.downloadFile(file2.id);
40596
- let decompressedBuffer;
40617
+ if (file2.size && file2.size > MAX_GZIP_SIZE) {
40618
+ return {
40619
+ skipped: {
40620
+ name: file2.name,
40621
+ reason: `Gzip file exceeds ${Math.round(MAX_GZIP_SIZE / 1024 / 1024)}MB limit (${Math.round(file2.size / 1024 / 1024)}MB)`,
40622
+ suggestion: "Try compressing a smaller file or splitting the content"
40623
+ }
40624
+ };
40625
+ }
40626
+ let compressedBuffer;
40597
40627
  try {
40598
- decompressedBuffer = gunzipSync(compressedBuffer);
40628
+ compressedBuffer = await platform.downloadFile(file2.id);
40599
40629
  } catch (err) {
40630
+ const errorMessage = err instanceof Error ? err.message : String(err);
40631
+ log2.error(`Failed to download gzip file ${file2.name}: ${errorMessage}`);
40600
40632
  return {
40601
40633
  skipped: {
40602
40634
  name: file2.name,
40603
- reason: `Decompression failed: ${err instanceof Error ? err.message : String(err)}`
40635
+ reason: `Download failed: ${errorMessage}`,
40636
+ suggestion: "Check if the file is still available and try again"
40604
40637
  }
40605
40638
  };
40606
40639
  }
40607
- if (decompressedBuffer.length > MAX_DECOMPRESSED_SIZE) {
40640
+ if (file2.size && compressedBuffer.length !== file2.size) {
40641
+ log2.warn(`Downloaded size mismatch for ${file2.name}: expected ${file2.size}, got ${compressedBuffer.length}`);
40642
+ }
40643
+ let decompressedBuffer;
40644
+ try {
40645
+ decompressedBuffer = await decompressGzipStream(compressedBuffer);
40646
+ } catch (err) {
40647
+ const errorMessage = err instanceof Error ? err.message : String(err);
40648
+ let reason;
40649
+ let suggestion;
40650
+ if (errorMessage.includes("incorrect header check")) {
40651
+ reason = "Invalid gzip file: the file header is corrupted or this is not a gzip file";
40652
+ suggestion = "Verify the file is a valid gzip archive";
40653
+ } else if (errorMessage.includes("unexpected end of file")) {
40654
+ reason = "Incomplete gzip file: the file appears to be truncated";
40655
+ suggestion = "Re-download the file or check if the upload completed";
40656
+ } else if (errorMessage.includes("invalid stored block lengths")) {
40657
+ reason = "Corrupted gzip file: the compressed data is damaged";
40658
+ suggestion = "Try re-compressing the original file";
40659
+ } else if (errorMessage.includes("exceeds") && errorMessage.includes("limit")) {
40660
+ reason = errorMessage;
40661
+ suggestion = "Try extracting only the relevant portions of the file";
40662
+ } else {
40663
+ reason = `Decompression failed: ${errorMessage}`;
40664
+ suggestion = "Verify the file is a valid gzip archive";
40665
+ }
40608
40666
  return {
40609
40667
  skipped: {
40610
40668
  name: file2.name,
40611
- reason: `Decompressed size exceeds ${Math.round(MAX_DECOMPRESSED_SIZE / 1024 / 1024)}MB limit (${Math.round(decompressedBuffer.length / 1024 / 1024)}MB)`,
40612
- suggestion: "Try extracting only the relevant portions"
40669
+ reason,
40670
+ suggestion
40613
40671
  }
40614
40672
  };
40615
40673
  }
@@ -40650,11 +40708,13 @@ async function processGzipFile(file2, platform, debug = false) {
40650
40708
  };
40651
40709
  }
40652
40710
  } catch (err) {
40653
- log2.error(`Failed to process gzip file ${file2.name}: ${err}`);
40711
+ const errorMessage = err instanceof Error ? err.message : String(err);
40712
+ log2.error(`Failed to process gzip file ${file2.name}: ${errorMessage}`);
40654
40713
  return {
40655
40714
  skipped: {
40656
40715
  name: file2.name,
40657
- reason: `Processing failed: ${err instanceof Error ? err.message : String(err)}`
40716
+ reason: `Processing failed: ${errorMessage}`,
40717
+ suggestion: "An unexpected error occurred. Please try again or contact support if the issue persists"
40658
40718
  }
40659
40719
  };
40660
40720
  }
@@ -41384,7 +41444,7 @@ class MessageManager {
41384
41444
  this.session.claude.sendMessage(content);
41385
41445
  if (skippedFiles.length > 0) {
41386
41446
  const feedback = this.formatSkippedFilesFeedback(skippedFiles);
41387
- await this.platform.createPost(this.threadId, feedback);
41447
+ await this.platform.createPost(feedback, this.threadId);
41388
41448
  }
41389
41449
  this.session.lastActivityAt = new Date;
41390
41450
  this.session.isProcessing = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Share Claude Code sessions live in a Mattermost channel with interactive features",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",