claude-threads 1.0.6 → 1.0.8

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,16 @@ 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.8] - 2026-01-13
9
+
10
+ ### Fixed
11
+ - **Maximize content per message when height-splitting** - Split algorithm now finds the optimal breakpoint to maximize content per message, instead of splitting at the first available breakpoint. Previously would split after Part 1 when Parts 1-4 could fit together.
12
+
13
+ ## [1.0.7] - 2026-01-13
14
+
15
+ ### Fixed
16
+ - **Check combined content height for streaming split decisions** - Fixed bug where height check only evaluated new content instead of combined content (existing + new), causing "Show More" collapse when total exceeded threshold but new content alone didn't (#212)
17
+
8
18
  ## [1.0.6] - 2026-01-13
9
19
 
10
20
  ### Fixed
package/dist/index.js CHANGED
@@ -50926,6 +50926,10 @@ class DefaultContentBreaker {
50926
50926
  return true;
50927
50927
  return false;
50928
50928
  }
50929
+ exceedsHeightThreshold(content) {
50930
+ const estimatedHeight = estimateRenderedHeight(content);
50931
+ return estimatedHeight >= MAX_HEIGHT_THRESHOLD;
50932
+ }
50929
50933
  endsAtBreakpoint(content) {
50930
50934
  const trimmed = content.trimEnd();
50931
50935
  if (/ {2}\u21B3 [\u2713\u274C][^\n]*$/.test(trimmed)) {
@@ -50947,16 +50951,29 @@ function splitContentForHeight(content, contentBreaker) {
50947
50951
  let remaining = content;
50948
50952
  const goodBreakpointTypes = new Set(["paragraph", "code_block_end", "heading", "tool_marker"]);
50949
50953
  while (remaining && contentBreaker.shouldFlushEarly(remaining)) {
50950
- const breakpoint = contentBreaker.findLogicalBreakpoint(remaining, 0, remaining.length);
50951
- if (!breakpoint || breakpoint.position <= 0 || breakpoint.position >= remaining.length) {
50952
- break;
50954
+ let bestBreakpoint = null;
50955
+ let searchStart = 0;
50956
+ while (searchStart < remaining.length) {
50957
+ const breakpoint = contentBreaker.findLogicalBreakpoint(remaining, searchStart, remaining.length - searchStart);
50958
+ if (!breakpoint || breakpoint.position <= searchStart || breakpoint.position >= remaining.length) {
50959
+ break;
50960
+ }
50961
+ if (!goodBreakpointTypes.has(breakpoint.type)) {
50962
+ searchStart = breakpoint.position + 1;
50963
+ continue;
50964
+ }
50965
+ const firstPart2 = remaining.substring(0, breakpoint.position).trim();
50966
+ if (!contentBreaker.exceedsHeightThreshold(firstPart2)) {
50967
+ bestBreakpoint = breakpoint;
50968
+ }
50969
+ searchStart = breakpoint.position + 1;
50953
50970
  }
50954
- if (!goodBreakpointTypes.has(breakpoint.type)) {
50971
+ if (!bestBreakpoint) {
50955
50972
  break;
50956
50973
  }
50957
- const firstPart = remaining.substring(0, breakpoint.position).trim();
50958
- const secondPart = remaining.substring(breakpoint.position).trim();
50959
- if (!contentBreaker.shouldFlushEarly(firstPart) && secondPart.length > 0) {
50974
+ const firstPart = remaining.substring(0, bestBreakpoint.position).trim();
50975
+ const secondPart = remaining.substring(bestBreakpoint.position).trim();
50976
+ if (secondPart.length > 0) {
50960
50977
  chunks.push(firstPart);
50961
50978
  remaining = secondPart;
50962
50979
  } else {
@@ -52418,7 +52435,7 @@ class ContentExecutor extends BaseExecutor {
52418
52435
  } else {
52419
52436
  combinedContent = content;
52420
52437
  }
52421
- const shouldBreakEarly = this.state.currentPostId && content.length > MIN_BREAK_THRESHOLD && ctx.contentBreaker.shouldFlushEarly(content);
52438
+ const shouldBreakEarly = this.state.currentPostId && combinedContent.length > MIN_BREAK_THRESHOLD && ctx.contentBreaker.shouldFlushEarly(combinedContent);
52422
52439
  if (this.state.currentPostId && (combinedContent.length > HARD_CONTINUATION_THRESHOLD || shouldBreakEarly)) {
52423
52440
  await this.handleSplit(ctx, combinedContent, pendingAtFlushStart, HARD_CONTINUATION_THRESHOLD);
52424
52441
  return;
@@ -52507,9 +52524,26 @@ class ContentExecutor extends BaseExecutor {
52507
52524
  }
52508
52525
  }
52509
52526
  } else {
52510
- const breakInfo = ctx.contentBreaker.findLogicalBreakpoint(content, 2000);
52511
- if (breakInfo && breakInfo.position < content.length) {
52512
- breakPoint = breakInfo.position;
52527
+ const goodBreakpointTypes = new Set(["paragraph", "code_block_end", "heading", "tool_marker"]);
52528
+ let bestBreakPoint = null;
52529
+ let searchStart = 0;
52530
+ while (searchStart < content.length) {
52531
+ const breakInfo = ctx.contentBreaker.findLogicalBreakpoint(content, searchStart, content.length - searchStart);
52532
+ if (!breakInfo || breakInfo.position <= searchStart || breakInfo.position >= content.length) {
52533
+ break;
52534
+ }
52535
+ if (!goodBreakpointTypes.has(breakInfo.type)) {
52536
+ searchStart = breakInfo.position + 1;
52537
+ continue;
52538
+ }
52539
+ const firstPart2 = content.substring(0, breakInfo.position).trim();
52540
+ if (!ctx.contentBreaker.exceedsHeightThreshold(firstPart2)) {
52541
+ bestBreakPoint = breakInfo.position;
52542
+ }
52543
+ searchStart = breakInfo.position + 1;
52544
+ }
52545
+ if (bestBreakPoint !== null && bestBreakPoint > 0) {
52546
+ breakPoint = bestBreakPoint;
52513
52547
  } else {
52514
52548
  if (this.state.currentPostId) {
52515
52549
  try {
@@ -35635,6 +35635,10 @@ class DefaultContentBreaker {
35635
35635
  return true;
35636
35636
  return false;
35637
35637
  }
35638
+ exceedsHeightThreshold(content) {
35639
+ const estimatedHeight = estimateRenderedHeight(content);
35640
+ return estimatedHeight >= MAX_HEIGHT_THRESHOLD;
35641
+ }
35638
35642
  endsAtBreakpoint(content) {
35639
35643
  const trimmed = content.trimEnd();
35640
35644
  if (/ {2}\u21B3 [\u2713\u274C][^\n]*$/.test(trimmed)) {
@@ -35656,16 +35660,29 @@ function splitContentForHeight(content, contentBreaker) {
35656
35660
  let remaining = content;
35657
35661
  const goodBreakpointTypes = new Set(["paragraph", "code_block_end", "heading", "tool_marker"]);
35658
35662
  while (remaining && contentBreaker.shouldFlushEarly(remaining)) {
35659
- const breakpoint = contentBreaker.findLogicalBreakpoint(remaining, 0, remaining.length);
35660
- if (!breakpoint || breakpoint.position <= 0 || breakpoint.position >= remaining.length) {
35661
- break;
35663
+ let bestBreakpoint = null;
35664
+ let searchStart = 0;
35665
+ while (searchStart < remaining.length) {
35666
+ const breakpoint = contentBreaker.findLogicalBreakpoint(remaining, searchStart, remaining.length - searchStart);
35667
+ if (!breakpoint || breakpoint.position <= searchStart || breakpoint.position >= remaining.length) {
35668
+ break;
35669
+ }
35670
+ if (!goodBreakpointTypes.has(breakpoint.type)) {
35671
+ searchStart = breakpoint.position + 1;
35672
+ continue;
35673
+ }
35674
+ const firstPart2 = remaining.substring(0, breakpoint.position).trim();
35675
+ if (!contentBreaker.exceedsHeightThreshold(firstPart2)) {
35676
+ bestBreakpoint = breakpoint;
35677
+ }
35678
+ searchStart = breakpoint.position + 1;
35662
35679
  }
35663
- if (!goodBreakpointTypes.has(breakpoint.type)) {
35680
+ if (!bestBreakpoint) {
35664
35681
  break;
35665
35682
  }
35666
- const firstPart = remaining.substring(0, breakpoint.position).trim();
35667
- const secondPart = remaining.substring(breakpoint.position).trim();
35668
- if (!contentBreaker.shouldFlushEarly(firstPart) && secondPart.length > 0) {
35683
+ const firstPart = remaining.substring(0, bestBreakpoint.position).trim();
35684
+ const secondPart = remaining.substring(bestBreakpoint.position).trim();
35685
+ if (secondPart.length > 0) {
35669
35686
  chunks.push(firstPart);
35670
35687
  remaining = secondPart;
35671
35688
  } else {
@@ -37218,7 +37235,7 @@ class ContentExecutor extends BaseExecutor {
37218
37235
  } else {
37219
37236
  combinedContent = content;
37220
37237
  }
37221
- const shouldBreakEarly = this.state.currentPostId && content.length > MIN_BREAK_THRESHOLD && ctx.contentBreaker.shouldFlushEarly(content);
37238
+ const shouldBreakEarly = this.state.currentPostId && combinedContent.length > MIN_BREAK_THRESHOLD && ctx.contentBreaker.shouldFlushEarly(combinedContent);
37222
37239
  if (this.state.currentPostId && (combinedContent.length > HARD_CONTINUATION_THRESHOLD || shouldBreakEarly)) {
37223
37240
  await this.handleSplit(ctx, combinedContent, pendingAtFlushStart, HARD_CONTINUATION_THRESHOLD);
37224
37241
  return;
@@ -37307,9 +37324,26 @@ class ContentExecutor extends BaseExecutor {
37307
37324
  }
37308
37325
  }
37309
37326
  } else {
37310
- const breakInfo = ctx.contentBreaker.findLogicalBreakpoint(content, 2000);
37311
- if (breakInfo && breakInfo.position < content.length) {
37312
- breakPoint = breakInfo.position;
37327
+ const goodBreakpointTypes = new Set(["paragraph", "code_block_end", "heading", "tool_marker"]);
37328
+ let bestBreakPoint = null;
37329
+ let searchStart = 0;
37330
+ while (searchStart < content.length) {
37331
+ const breakInfo = ctx.contentBreaker.findLogicalBreakpoint(content, searchStart, content.length - searchStart);
37332
+ if (!breakInfo || breakInfo.position <= searchStart || breakInfo.position >= content.length) {
37333
+ break;
37334
+ }
37335
+ if (!goodBreakpointTypes.has(breakInfo.type)) {
37336
+ searchStart = breakInfo.position + 1;
37337
+ continue;
37338
+ }
37339
+ const firstPart2 = content.substring(0, breakInfo.position).trim();
37340
+ if (!ctx.contentBreaker.exceedsHeightThreshold(firstPart2)) {
37341
+ bestBreakPoint = breakInfo.position;
37342
+ }
37343
+ searchStart = breakInfo.position + 1;
37344
+ }
37345
+ if (bestBreakPoint !== null && bestBreakPoint > 0) {
37346
+ breakPoint = bestBreakPoint;
37313
37347
  } else {
37314
37348
  if (this.state.currentPostId) {
37315
37349
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
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",