claude-threads 1.39.2 → 1.39.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 +68 -38
- package/dist/mcp/mcp-server.js +1 -1
- 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.39.3] - 2026-10-01
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Mattermost: a skin-toned 👍 no longer denies** (#629). Mattermost names an emoji picked with a skin tone `+1_medium_skin_tone` (verified against Mattermost v11), and the permission prompt treats any emoji it does not recognize as a denial. 1.39.2 fixed Slack's `+1::skin-tone-3` form; the Mattermost form is now matched on its base name too, for permission prompts, plan approvals and the other reaction controls.
|
|
12
|
+
- **One failed update no longer turns a code block into a post per flush** (#620). When the platform refused an update of the post Claude was writing a code block into, the bot gave up on that post at once. The continuation started in the middle of the block without its opening fence, so the rest rendered as prose, the height check split it every few lines (a new post per flush, close to 200 posts for a 2000-line file), and the closing fence opened a new block. A failed update is now retried on the next flush, which recovers the post completely for a passing error; only after three failures in a row is the post given up, with its code block reopened at the start of the next one.
|
|
13
|
+
|
|
8
14
|
## [1.39.2] - 2026-10-01
|
|
9
15
|
|
|
10
16
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -6033,7 +6033,7 @@ var init_usage = __esm(() => {
|
|
|
6033
6033
|
|
|
6034
6034
|
// src/utils/emoji.ts
|
|
6035
6035
|
function withoutSkinTone(emoji) {
|
|
6036
|
-
return emoji.replace(/::skin-tone-\d$/, "");
|
|
6036
|
+
return emoji.replace(/::skin-tone-\d$/, "").replace(/(?<=.)_(?:light|medium_light|medium|medium_dark|dark)_skin_tone$/, "");
|
|
6037
6037
|
}
|
|
6038
6038
|
function isApprovalEmoji(emoji) {
|
|
6039
6039
|
return APPROVAL_EMOJIS.includes(withoutSkinTone(emoji));
|
|
@@ -60297,7 +60297,8 @@ class ContentExecutor extends BaseExecutor {
|
|
|
60297
60297
|
headerPostId: null,
|
|
60298
60298
|
headerBody: "",
|
|
60299
60299
|
turnOpen: false,
|
|
60300
|
-
paragraphBreak: false
|
|
60300
|
+
paragraphBreak: false,
|
|
60301
|
+
updateFailures: 0
|
|
60301
60302
|
};
|
|
60302
60303
|
}
|
|
60303
60304
|
setHeader(line) {
|
|
@@ -60318,6 +60319,7 @@ class ContentExecutor extends BaseExecutor {
|
|
|
60318
60319
|
this.state.headerPostId = null;
|
|
60319
60320
|
this.state.headerBody = "";
|
|
60320
60321
|
this.state.turnOpen = false;
|
|
60322
|
+
this.state.updateFailures = 0;
|
|
60321
60323
|
}
|
|
60322
60324
|
getRenderedCurrentPost() {
|
|
60323
60325
|
const postId = this.state.currentPostId;
|
|
@@ -60344,7 +60346,9 @@ ${body}` : this.state.header;
|
|
|
60344
60346
|
this.state.headerDirty = false;
|
|
60345
60347
|
if (this.state.headerPostId) {
|
|
60346
60348
|
const postId = this.state.headerPostId;
|
|
60349
|
+
const failures = this.state.updateFailures;
|
|
60347
60350
|
await this.tryUpdatePost(ctx, postId, this.state.headerBody, "header", { reason: "header_update", headerLength: this.state.header?.length ?? 0 }, { reason: "header_update_failed" }, () => {}, () => {});
|
|
60351
|
+
this.state.updateFailures = failures;
|
|
60348
60352
|
return;
|
|
60349
60353
|
}
|
|
60350
60354
|
if (this.state.header && this.state.turnOpen) {
|
|
@@ -60367,6 +60371,7 @@ ${body}` : this.state.header;
|
|
|
60367
60371
|
this.state.headerBody = content;
|
|
60368
60372
|
this.state.headerDirty = false;
|
|
60369
60373
|
}
|
|
60374
|
+
this.state.updateFailures = 0;
|
|
60370
60375
|
onSuccess();
|
|
60371
60376
|
ctx.threadLogger?.logExecutor("content", "update", postId, successDetails, logTag);
|
|
60372
60377
|
} catch (err) {
|
|
@@ -60379,8 +60384,11 @@ ${body}` : this.state.header;
|
|
|
60379
60384
|
closeCurrentPost(ctx) {
|
|
60380
60385
|
const oldPostId = this.state.currentPostId;
|
|
60381
60386
|
const contentLength = this.state.currentPostContent.length;
|
|
60387
|
+
if (this.state.updateFailures > 0 && this.state.pendingContent.trim())
|
|
60388
|
+
this.giveUpCurrentPost();
|
|
60382
60389
|
this.state.currentPostId = null;
|
|
60383
60390
|
this.state.currentPostContent = "";
|
|
60391
|
+
this.state.updateFailures = 0;
|
|
60384
60392
|
if (ctx?.threadLogger && oldPostId) {
|
|
60385
60393
|
ctx.threadLogger.logExecutor("content", "close", oldPostId, {
|
|
60386
60394
|
contentLength,
|
|
@@ -60436,13 +60444,22 @@ ${body}` : this.state.header;
|
|
|
60436
60444
|
this.state.turnOpen = false;
|
|
60437
60445
|
return;
|
|
60438
60446
|
}
|
|
60439
|
-
|
|
60440
|
-
|
|
60447
|
+
const postBefore = this.state.currentPostId;
|
|
60448
|
+
await this.flushPending(ctx, reason);
|
|
60449
|
+
if (reason === "result") {
|
|
60450
|
+
if (this.state.updateFailures > 0 && this.state.currentPostId !== null && this.state.pendingContent.trim()) {
|
|
60451
|
+
await this.flushPending(ctx, reason);
|
|
60452
|
+
}
|
|
60453
|
+
if (postBefore !== null && this.state.currentPostId === null && this.state.pendingContent.trim()) {
|
|
60454
|
+
await this.flushPending(ctx, reason);
|
|
60455
|
+
}
|
|
60456
|
+
}
|
|
60457
|
+
if (this.state.headerDirty && this.state.updateFailures === 0)
|
|
60441
60458
|
await this.renderHeaderOnly(ctx);
|
|
60442
60459
|
if (reason === "result")
|
|
60443
60460
|
this.state.turnOpen = false;
|
|
60444
60461
|
}
|
|
60445
|
-
async flushPending(ctx) {
|
|
60462
|
+
async flushPending(ctx, reason) {
|
|
60446
60463
|
const pendingAtFlushStart = this.state.pendingContent;
|
|
60447
60464
|
let content = ctx.formatter.formatMarkdown(pendingAtFlushStart).trim();
|
|
60448
60465
|
const { maxLength: MAX_POST_LENGTH, hardThreshold: HARD_CONTINUATION_THRESHOLD } = ctx.platform.getMessageLimits();
|
|
@@ -60460,7 +60477,7 @@ ${body}` : this.state.header;
|
|
|
60460
60477
|
const shouldBreakEarly = this.state.currentPostId && combinedContent.length > MIN_BREAK_THRESHOLD && ctx.contentBreaker.shouldFlushEarly(combinedContent);
|
|
60461
60478
|
const reserve = this.headerReserve(this.state.currentPostId);
|
|
60462
60479
|
if (this.state.currentPostId && (combinedContent.length + reserve > HARD_CONTINUATION_THRESHOLD || shouldBreakEarly)) {
|
|
60463
|
-
await this.handleSplit(ctx, combinedContent, pendingAtFlushStart, HARD_CONTINUATION_THRESHOLD);
|
|
60480
|
+
await this.handleSplit(ctx, combinedContent, pendingAtFlushStart, HARD_CONTINUATION_THRESHOLD, reason);
|
|
60464
60481
|
return;
|
|
60465
60482
|
}
|
|
60466
60483
|
if (this.state.currentPostId && content.length + reserve > MAX_POST_LENGTH) {
|
|
@@ -60495,10 +60512,7 @@ ${body}` : this.state.header;
|
|
|
60495
60512
|
await this.tryUpdatePost(ctx, postId, combinedContent, "flush", { newContentLength: content.length, combinedLength: combinedContent.length }, (err) => ({ failedOp: "updatePost", error: String(err) }), () => {
|
|
60496
60513
|
this.state.currentPostContent = combinedContent;
|
|
60497
60514
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60498
|
-
}, () =>
|
|
60499
|
-
this.state.currentPostId = null;
|
|
60500
|
-
this.state.currentPostContent = "";
|
|
60501
|
-
});
|
|
60515
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60502
60516
|
} else {
|
|
60503
60517
|
const chunks = splitContentForHeight(content, ctx.contentBreaker).flatMap((chunk) => chunk.length + reserve > MAX_POST_LENGTH ? splitByLength(chunk, HARD_CONTINUATION_THRESHOLD - reserve) : [chunk]);
|
|
60504
60518
|
ctx.threadLogger?.logExecutor("content", "create_start", "none", {
|
|
@@ -60509,7 +60523,7 @@ ${body}` : this.state.header;
|
|
|
60509
60523
|
await this.postChunks(ctx, chunks, pendingAtFlushStart, false);
|
|
60510
60524
|
}
|
|
60511
60525
|
}
|
|
60512
|
-
async splitOversized(ctx, content, pendingAtFlushStart, hardThreshold) {
|
|
60526
|
+
async splitOversized(ctx, content, pendingAtFlushStart, hardThreshold, reason) {
|
|
60513
60527
|
const postId = this.state.currentPostId;
|
|
60514
60528
|
if (!postId)
|
|
60515
60529
|
return false;
|
|
@@ -60520,17 +60534,35 @@ ${body}` : this.state.header;
|
|
|
60520
60534
|
let landed = false;
|
|
60521
60535
|
await this.tryUpdatePost(ctx, postId, firstPiece, "handleSplit", { reason: "oversized_code_block", contentLength: content.length, pieces: rest.length + 1 }, { reason: "oversized_code_block_failed" }, () => {
|
|
60522
60536
|
landed = true;
|
|
60523
|
-
}, () => {
|
|
60524
|
-
|
|
60525
|
-
|
|
60526
|
-
|
|
60537
|
+
}, () => {});
|
|
60538
|
+
if (!landed) {
|
|
60539
|
+
this.onInPlaceUpdateFailed(reason);
|
|
60540
|
+
return true;
|
|
60541
|
+
}
|
|
60527
60542
|
this.state.currentPostId = null;
|
|
60528
60543
|
this.state.currentPostContent = "";
|
|
60529
|
-
|
|
60530
|
-
|
|
60531
|
-
await this.postChunks(ctx, rest, pendingAtFlushStart, landed);
|
|
60544
|
+
this.clearFlushedContent(pendingAtFlushStart);
|
|
60545
|
+
await this.postChunks(ctx, rest, pendingAtFlushStart, true);
|
|
60532
60546
|
return true;
|
|
60533
60547
|
}
|
|
60548
|
+
onInPlaceUpdateFailed(reason) {
|
|
60549
|
+
this.state.updateFailures++;
|
|
60550
|
+
const limit = reason === "result" ? 2 : MAX_IN_PLACE_UPDATE_FAILURES;
|
|
60551
|
+
if (this.state.updateFailures < limit)
|
|
60552
|
+
return;
|
|
60553
|
+
this.giveUpCurrentPost();
|
|
60554
|
+
}
|
|
60555
|
+
giveUpCurrentPost() {
|
|
60556
|
+
const opener = openFenceOf(this.state.currentPostContent);
|
|
60557
|
+
this.state.currentPostId = null;
|
|
60558
|
+
this.state.currentPostContent = "";
|
|
60559
|
+
this.state.updateFailures = 0;
|
|
60560
|
+
if (!opener)
|
|
60561
|
+
return;
|
|
60562
|
+
const rest = this.state.pendingContent.replace(/^\n+/, "");
|
|
60563
|
+
this.state.pendingContent = /^```[ \t]*(\n|$)/.test(rest) ? rest.replace(/^```[ \t]*\n?/, "") : `${opener}
|
|
60564
|
+
${rest}`;
|
|
60565
|
+
}
|
|
60534
60566
|
async postChunks(ctx, chunks, pendingAtFlushStart, flushCleared) {
|
|
60535
60567
|
let cleared = flushCleared;
|
|
60536
60568
|
for (let i = 0;i < chunks.length; i++) {
|
|
@@ -60554,7 +60586,7 @@ ${this.state.pendingContent}` : "");
|
|
|
60554
60586
|
}
|
|
60555
60587
|
}
|
|
60556
60588
|
}
|
|
60557
|
-
async handleSplit(ctx, content, pendingAtFlushStart, hardThreshold) {
|
|
60589
|
+
async handleSplit(ctx, content, pendingAtFlushStart, hardThreshold, reason) {
|
|
60558
60590
|
let breakPoint;
|
|
60559
60591
|
let codeBlockOpenPosition;
|
|
60560
60592
|
if (content.length > hardThreshold) {
|
|
@@ -60602,26 +60634,21 @@ ${this.state.pendingContent}` : "");
|
|
|
60602
60634
|
await this.tryUpdatePost(ctx, postId, content, "handleSplit", { reason: "soft_break_no_breakpoint", contentLength: content.length }, { reason: "soft_break_no_breakpoint_failed" }, () => {
|
|
60603
60635
|
this.state.currentPostContent = content;
|
|
60604
60636
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60605
|
-
}, () =>
|
|
60606
|
-
this.state.currentPostId = null;
|
|
60607
|
-
});
|
|
60637
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60608
60638
|
}
|
|
60609
60639
|
return;
|
|
60610
60640
|
}
|
|
60611
60641
|
}
|
|
60612
60642
|
if (codeBlockOpenPosition !== undefined) {
|
|
60613
60643
|
if (codeBlockOpenPosition === 0) {
|
|
60614
|
-
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold))
|
|
60644
|
+
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold, reason))
|
|
60615
60645
|
return;
|
|
60616
60646
|
if (this.state.currentPostId) {
|
|
60617
60647
|
const postId = this.state.currentPostId;
|
|
60618
60648
|
await this.tryUpdatePost(ctx, postId, content, "handleSplit", { reason: "code_block_at_start", contentLength: content.length }, { reason: "code_block_at_start_failed" }, () => {
|
|
60619
60649
|
this.state.currentPostContent = content;
|
|
60620
60650
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60621
|
-
}, () =>
|
|
60622
|
-
this.state.currentPostId = null;
|
|
60623
|
-
this.state.currentPostContent = "";
|
|
60624
|
-
});
|
|
60651
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60625
60652
|
}
|
|
60626
60653
|
return;
|
|
60627
60654
|
}
|
|
@@ -60630,17 +60657,14 @@ ${this.state.pendingContent}` : "");
|
|
|
60630
60657
|
if (breakBeforeCodeBlock > 0) {
|
|
60631
60658
|
breakPoint = breakBeforeCodeBlock;
|
|
60632
60659
|
} else {
|
|
60633
|
-
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold))
|
|
60660
|
+
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold, reason))
|
|
60634
60661
|
return;
|
|
60635
60662
|
if (this.state.currentPostId) {
|
|
60636
60663
|
const postId = this.state.currentPostId;
|
|
60637
60664
|
await this.tryUpdatePost(ctx, postId, content, "handleSplit", { reason: "no_break_before_code_block", contentLength: content.length }, { reason: "no_break_before_code_block_failed" }, () => {
|
|
60638
60665
|
this.state.currentPostContent = content;
|
|
60639
60666
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60640
|
-
}, () =>
|
|
60641
|
-
this.state.currentPostId = null;
|
|
60642
|
-
this.state.currentPostContent = "";
|
|
60643
|
-
});
|
|
60667
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60644
60668
|
}
|
|
60645
60669
|
return;
|
|
60646
60670
|
}
|
|
@@ -60652,11 +60676,11 @@ ${this.state.pendingContent}` : "");
|
|
|
60652
60676
|
const postId = this.state.currentPostId;
|
|
60653
60677
|
await this.tryUpdatePost(ctx, postId, firstPart, "handleSplit", { reason: "split_first_part", firstPartLength: firstPart.length, remainderLength: remainder.length }, { reason: "split_first_part_failed" }, () => {
|
|
60654
60678
|
firstPartLanded = true;
|
|
60655
|
-
}, () => {
|
|
60656
|
-
|
|
60657
|
-
|
|
60658
|
-
|
|
60659
|
-
}
|
|
60679
|
+
}, () => {});
|
|
60680
|
+
if (!firstPartLanded) {
|
|
60681
|
+
this.onInPlaceUpdateFailed(reason);
|
|
60682
|
+
return;
|
|
60683
|
+
}
|
|
60660
60684
|
}
|
|
60661
60685
|
this.state.currentPostId = null;
|
|
60662
60686
|
this.state.currentPostContent = "";
|
|
@@ -60689,6 +60713,7 @@ ${content}` : header : content;
|
|
|
60689
60713
|
if (bumpedPostId) {
|
|
60690
60714
|
adoptAsHeaderPost(bumpedPostId);
|
|
60691
60715
|
this.state.currentPostId = bumpedPostId;
|
|
60716
|
+
this.state.updateFailures = 0;
|
|
60692
60717
|
this.state.currentPostContent = content;
|
|
60693
60718
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60694
60719
|
ctx.threadLogger?.logExecutor("content", "create", bumpedPostId, {
|
|
@@ -60705,6 +60730,7 @@ ${content}` : header : content;
|
|
|
60705
60730
|
const post = await ctx.createPost(rendered, { type: "content" });
|
|
60706
60731
|
adoptAsHeaderPost(post.id);
|
|
60707
60732
|
this.state.currentPostId = post.id;
|
|
60733
|
+
this.state.updateFailures = 0;
|
|
60708
60734
|
this.state.currentPostContent = content;
|
|
60709
60735
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60710
60736
|
ctx.logger.debug(`Created post ${formatShortId(post.id)}`);
|
|
@@ -60730,6 +60756,11 @@ ${content}` : header : content;
|
|
|
60730
60756
|
}
|
|
60731
60757
|
}
|
|
60732
60758
|
var FENCE_LINE = /^```.*$/gm;
|
|
60759
|
+
var MAX_IN_PLACE_UPDATE_FAILURES = 3;
|
|
60760
|
+
function openFenceOf(text) {
|
|
60761
|
+
const fences = text.match(FENCE_LINE) ?? [];
|
|
60762
|
+
return fences.length % 2 === 1 ? fences[fences.length - 1] : null;
|
|
60763
|
+
}
|
|
60733
60764
|
var FENCE_CLOSE = "\n```";
|
|
60734
60765
|
function splitByLength(text, max) {
|
|
60735
60766
|
const room = max - FENCE_CLOSE.length;
|
|
@@ -71905,7 +71936,6 @@ class SlackClient extends BasePlatformClient {
|
|
|
71905
71936
|
token: this.botToken,
|
|
71906
71937
|
channelId: this.channelId,
|
|
71907
71938
|
allowedUsers: this.allowedUsers,
|
|
71908
|
-
appToken: this.appToken,
|
|
71909
71939
|
apiUrl: this.apiUrl,
|
|
71910
71940
|
outboundFiles: this.outboundFiles,
|
|
71911
71941
|
mcpServers: this.mcpServers,
|
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -12723,7 +12723,7 @@ var require_dist = __commonJS(function(exports, module) {
|
|
|
12723
12723
|
|
|
12724
12724
|
// src/utils/emoji.ts
|
|
12725
12725
|
function withoutSkinTone(emoji) {
|
|
12726
|
-
return emoji.replace(/::skin-tone-\d$/, "");
|
|
12726
|
+
return emoji.replace(/::skin-tone-\d$/, "").replace(/(?<=.)_(?:light|medium_light|medium|medium_dark|dark)_skin_tone$/, "");
|
|
12727
12727
|
}
|
|
12728
12728
|
function isApprovalEmoji(emoji) {
|
|
12729
12729
|
return APPROVAL_EMOJIS.includes(withoutSkinTone(emoji));
|
package/package.json
CHANGED