claude-threads 1.39.2 → 1.39.4
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 +14 -0
- package/dist/index.js +138 -81
- package/dist/mcp/mcp-server.js +316 -100
- package/package.json +22 -18
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ 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.4] - 2026-10-30
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
- `proxy-addr` 2.0.7 → 2.0.8 (critical, IP spoofing), `@modelcontextprotocol/sdk` 1.30.1 → 1.32.2 (three high advisories), `body-parser` 2.3.0 → 2.4.0, `fast-uri` 4.2.1 → 4.2.3, `shell-quote` 1.10.0 → 1.12.0 and `hono` 4.13.9 → 4.13.13, all bundled into what users run (#650). Supersedes the separate Dependabot PRs, none of which could go green on its own.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- `@hono/node-server` 2.1.5, `express-rate-limit` 8.7.1, `@redactpii/node` 1.0.19, `react` 19.3.1, `zod` 4.6.7, plus dev tooling (`eslint`, `knip`, `prettier`, `typescript-eslint`, `@types/*`). `ink` stays on 6.x; the 8.0 major is left for a separate change.
|
|
15
|
+
|
|
16
|
+
## [1.39.3] - 2026-10-01
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **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.
|
|
20
|
+
- **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.
|
|
21
|
+
|
|
8
22
|
## [1.39.2] - 2026-10-01
|
|
9
23
|
|
|
10
24
|
### 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));
|
|
@@ -19189,7 +19189,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
19189
19189
|
exports.useTransition = function() {
|
|
19190
19190
|
return resolveDispatcher().useTransition();
|
|
19191
19191
|
};
|
|
19192
|
-
exports.version = "19.3.
|
|
19192
|
+
exports.version = "19.3.1";
|
|
19193
19193
|
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
|
|
19194
19194
|
})();
|
|
19195
19195
|
});
|
|
@@ -57094,15 +57094,15 @@ class Redactor {
|
|
|
57094
57094
|
name: "CREDIT_CARD"
|
|
57095
57095
|
},
|
|
57096
57096
|
EMAIL: {
|
|
57097
|
-
pattern:
|
|
57097
|
+
pattern: /(?<![\p{L}\p{N}._%+-]|[\p{L}\p{N}]')[\p{L}\p{N}][\p{L}\p{N}._%+'-]*@[\p{L}\p{N}][\p{L}\p{N}_.-]*\.\p{L}{2,}/giu,
|
|
57098
57098
|
name: "EMAIL"
|
|
57099
57099
|
},
|
|
57100
57100
|
NAME: {
|
|
57101
|
-
pattern: /(
|
|
57101
|
+
pattern: /(?=[DdHhGg])(?<=(?:^|[.!?\n])\s*)(?:[Dd]ear|[Hh]i|[Hh]ello|[Gg]reetings|[Hh]ey(?:\s+[Tt]here)?)\s+\p{Lu}[\p{L}'’-]*\p{Ll}(?:[ \t]+\p{Lu}[\p{L}'’-]*\p{Ll})+/gu,
|
|
57102
57102
|
name: "PERSON_NAME"
|
|
57103
57103
|
},
|
|
57104
57104
|
PHONE: {
|
|
57105
|
-
pattern:
|
|
57105
|
+
pattern: /(?<!\w)(?:\+?1[-.\s]?)?(?:\(?\d{3}\)?[-.\s]?)?\d{3}[-.\s]?\d{4}\b/g,
|
|
57106
57106
|
name: "PHONE_NUMBER"
|
|
57107
57107
|
},
|
|
57108
57108
|
SSN: {
|
|
@@ -57116,15 +57116,15 @@ class Redactor {
|
|
|
57116
57116
|
name: "CREDIT_CARD"
|
|
57117
57117
|
},
|
|
57118
57118
|
EMAIL: {
|
|
57119
|
-
pattern:
|
|
57119
|
+
pattern: /(?<![\p{L}\p{N}._%+-]|[\p{L}\p{N}]')[\p{L}\p{N}][\p{L}\p{N}._%+'-]*\s*(?:@|\[at\]|\(at\))\s*[\p{L}\p{N}][\p{L}\p{N}_.-]*\s*(?:\.|\[dot\]|\(dot\))\s*\p{L}{2,}(?![\p{L}\p{N}_])/giu,
|
|
57120
57120
|
name: "EMAIL"
|
|
57121
57121
|
},
|
|
57122
57122
|
NAME: {
|
|
57123
|
-
pattern: /(
|
|
57123
|
+
pattern: /(?=[DdHhGgMmPp])(?<=(?:^|[.!?\n,])\s*)(?:[Dd]ear|[Hh]i|[Hh]ello|[Gg]reetings|[Hh]ey(?:\s+[Tt]here)?|[Mm][Rr][Ss]?\.?|[Mm][Ss]\.?|[Dd][Rr]\.?|[Pp]rof\.?)\s+\p{Lu}[\p{L}'’-]*\p{Ll}(?:[ \t]+\p{Lu}[\p{L}'’-]*\p{Ll})*/gu,
|
|
57124
57124
|
name: "PERSON_NAME"
|
|
57125
57125
|
},
|
|
57126
57126
|
PHONE: {
|
|
57127
|
-
pattern:
|
|
57127
|
+
pattern: /(?<!\w)(?:\+?1[-.\s]?)?(?:\(?\d{3}\)?[-.\s]?)?\d{3}[-.\s]?\d{4}\b|\b\d{3}[-.\s]\d{4}\b/g,
|
|
57128
57128
|
name: "PHONE_NUMBER"
|
|
57129
57129
|
},
|
|
57130
57130
|
SSN: {
|
|
@@ -57145,7 +57145,8 @@ class Redactor {
|
|
|
57145
57145
|
return activeRules;
|
|
57146
57146
|
}
|
|
57147
57147
|
_clonePattern(pattern) {
|
|
57148
|
-
|
|
57148
|
+
const flags = pattern.flags.replace("y", "");
|
|
57149
|
+
return new RegExp(pattern.source, flags.includes("g") ? flags : `${flags}g`);
|
|
57149
57150
|
}
|
|
57150
57151
|
hasPII(text) {
|
|
57151
57152
|
for (const { pattern } of this.activeRules) {
|
|
@@ -57185,48 +57186,42 @@ class Redactor {
|
|
|
57185
57186
|
}
|
|
57186
57187
|
_redactString(text, resetState) {
|
|
57187
57188
|
const events = [];
|
|
57188
|
-
let redactedText = text;
|
|
57189
57189
|
if (resetState && this.anonymize) {
|
|
57190
57190
|
this.anonymizationMap.clear();
|
|
57191
57191
|
this.anonymizationCounters.clear();
|
|
57192
57192
|
}
|
|
57193
|
+
const spans = [];
|
|
57193
57194
|
for (const { pattern, name } of this.activeRules) {
|
|
57194
|
-
const
|
|
57195
|
-
|
|
57196
|
-
|
|
57197
|
-
events.push({ pii_type: piiType, action: "REDACTED" });
|
|
57198
|
-
if (this.anonymize) {
|
|
57199
|
-
const normalizedMatch = match.toLowerCase();
|
|
57200
|
-
const key = `${piiType}:${normalizedMatch}`;
|
|
57201
|
-
if (this.anonymizationMap.has(key)) {
|
|
57202
|
-
return this.anonymizationMap.get(key) ?? match;
|
|
57203
|
-
}
|
|
57204
|
-
const counter = (this.anonymizationCounters.get(piiType) ?? 0) + 1;
|
|
57205
|
-
this.anonymizationCounters.set(piiType, counter);
|
|
57206
|
-
const tokenPrefix = this._getTokenPrefix(piiType);
|
|
57207
|
-
const token = `${tokenPrefix}_${counter}`;
|
|
57208
|
-
this.anonymizationMap.set(key, token);
|
|
57209
|
-
return token;
|
|
57210
|
-
}
|
|
57211
|
-
if (this.globalReplaceWith !== undefined) {
|
|
57212
|
-
return this.globalReplaceWith;
|
|
57213
|
-
}
|
|
57214
|
-
switch (piiType) {
|
|
57215
|
-
case "CREDIT_CARD":
|
|
57216
|
-
return "CREDIT_CARD_NUMBER";
|
|
57217
|
-
case "EMAIL":
|
|
57218
|
-
return "EMAIL_ADDRESS";
|
|
57219
|
-
case "PERSON_NAME":
|
|
57220
|
-
return "PERSON_NAME";
|
|
57221
|
-
case "PHONE_NUMBER":
|
|
57222
|
-
return "PHONE_NUMBER";
|
|
57223
|
-
case "US_SOCIAL_SECURITY_NUMBER":
|
|
57224
|
-
return "US_SOCIAL_SECURITY_NUMBER";
|
|
57225
|
-
default:
|
|
57226
|
-
return "DIGITS";
|
|
57195
|
+
for (const match of text.matchAll(this._clonePattern(pattern))) {
|
|
57196
|
+
if (match[0] === "") {
|
|
57197
|
+
continue;
|
|
57227
57198
|
}
|
|
57228
|
-
|
|
57199
|
+
const start = match.index;
|
|
57200
|
+
spans.push({ start, end: start + match[0].length, name, length: match[0].length });
|
|
57201
|
+
}
|
|
57202
|
+
}
|
|
57203
|
+
spans.sort((a, b) => a.start === b.start ? b.end - a.end : a.start - b.start);
|
|
57204
|
+
const merged = [];
|
|
57205
|
+
for (const span of spans) {
|
|
57206
|
+
const last = merged[merged.length - 1];
|
|
57207
|
+
if (last !== undefined && span.start < last.end) {
|
|
57208
|
+
last.end = Math.max(last.end, span.end);
|
|
57209
|
+
if (span.length > last.length) {
|
|
57210
|
+
last.name = span.name;
|
|
57211
|
+
last.length = span.length;
|
|
57212
|
+
}
|
|
57213
|
+
} else {
|
|
57214
|
+
merged.push({ ...span });
|
|
57215
|
+
}
|
|
57229
57216
|
}
|
|
57217
|
+
let redactedText = "";
|
|
57218
|
+
let cursor = 0;
|
|
57219
|
+
for (const { start, end, name } of merged) {
|
|
57220
|
+
events.push({ pii_type: name, action: "REDACTED" });
|
|
57221
|
+
redactedText += text.slice(cursor, start) + this._replacementFor(name, text.slice(start, end));
|
|
57222
|
+
cursor = end;
|
|
57223
|
+
}
|
|
57224
|
+
redactedText += text.slice(cursor);
|
|
57230
57225
|
if (resetState) {
|
|
57231
57226
|
const hasValidApiKey = this.apiKey !== null && this.apiKey !== "";
|
|
57232
57227
|
if (hasValidApiKey && events.length > 0) {
|
|
@@ -57239,6 +57234,38 @@ class Redactor {
|
|
|
57239
57234
|
}
|
|
57240
57235
|
return redactedText;
|
|
57241
57236
|
}
|
|
57237
|
+
_replacementFor(piiType, match) {
|
|
57238
|
+
if (this.anonymize) {
|
|
57239
|
+
const normalizedMatch = match.toLowerCase();
|
|
57240
|
+
const key = `${piiType}:${normalizedMatch}`;
|
|
57241
|
+
if (this.anonymizationMap.has(key)) {
|
|
57242
|
+
return this.anonymizationMap.get(key) ?? match;
|
|
57243
|
+
}
|
|
57244
|
+
const counter = (this.anonymizationCounters.get(piiType) ?? 0) + 1;
|
|
57245
|
+
this.anonymizationCounters.set(piiType, counter);
|
|
57246
|
+
const tokenPrefix = this._getTokenPrefix(piiType);
|
|
57247
|
+
const token = `${tokenPrefix}_${counter}`;
|
|
57248
|
+
this.anonymizationMap.set(key, token);
|
|
57249
|
+
return token;
|
|
57250
|
+
}
|
|
57251
|
+
if (this.globalReplaceWith !== undefined) {
|
|
57252
|
+
return this.globalReplaceWith;
|
|
57253
|
+
}
|
|
57254
|
+
switch (piiType) {
|
|
57255
|
+
case "CREDIT_CARD":
|
|
57256
|
+
return "CREDIT_CARD_NUMBER";
|
|
57257
|
+
case "EMAIL":
|
|
57258
|
+
return "EMAIL_ADDRESS";
|
|
57259
|
+
case "PERSON_NAME":
|
|
57260
|
+
return "PERSON_NAME";
|
|
57261
|
+
case "PHONE_NUMBER":
|
|
57262
|
+
return "PHONE_NUMBER";
|
|
57263
|
+
case "US_SOCIAL_SECURITY_NUMBER":
|
|
57264
|
+
return "US_SOCIAL_SECURITY_NUMBER";
|
|
57265
|
+
default:
|
|
57266
|
+
return "DIGITS";
|
|
57267
|
+
}
|
|
57268
|
+
}
|
|
57242
57269
|
redact(text) {
|
|
57243
57270
|
return this._redactString(text, true);
|
|
57244
57271
|
}
|
|
@@ -60297,7 +60324,8 @@ class ContentExecutor extends BaseExecutor {
|
|
|
60297
60324
|
headerPostId: null,
|
|
60298
60325
|
headerBody: "",
|
|
60299
60326
|
turnOpen: false,
|
|
60300
|
-
paragraphBreak: false
|
|
60327
|
+
paragraphBreak: false,
|
|
60328
|
+
updateFailures: 0
|
|
60301
60329
|
};
|
|
60302
60330
|
}
|
|
60303
60331
|
setHeader(line) {
|
|
@@ -60318,6 +60346,7 @@ class ContentExecutor extends BaseExecutor {
|
|
|
60318
60346
|
this.state.headerPostId = null;
|
|
60319
60347
|
this.state.headerBody = "";
|
|
60320
60348
|
this.state.turnOpen = false;
|
|
60349
|
+
this.state.updateFailures = 0;
|
|
60321
60350
|
}
|
|
60322
60351
|
getRenderedCurrentPost() {
|
|
60323
60352
|
const postId = this.state.currentPostId;
|
|
@@ -60344,7 +60373,9 @@ ${body}` : this.state.header;
|
|
|
60344
60373
|
this.state.headerDirty = false;
|
|
60345
60374
|
if (this.state.headerPostId) {
|
|
60346
60375
|
const postId = this.state.headerPostId;
|
|
60376
|
+
const failures = this.state.updateFailures;
|
|
60347
60377
|
await this.tryUpdatePost(ctx, postId, this.state.headerBody, "header", { reason: "header_update", headerLength: this.state.header?.length ?? 0 }, { reason: "header_update_failed" }, () => {}, () => {});
|
|
60378
|
+
this.state.updateFailures = failures;
|
|
60348
60379
|
return;
|
|
60349
60380
|
}
|
|
60350
60381
|
if (this.state.header && this.state.turnOpen) {
|
|
@@ -60367,6 +60398,7 @@ ${body}` : this.state.header;
|
|
|
60367
60398
|
this.state.headerBody = content;
|
|
60368
60399
|
this.state.headerDirty = false;
|
|
60369
60400
|
}
|
|
60401
|
+
this.state.updateFailures = 0;
|
|
60370
60402
|
onSuccess();
|
|
60371
60403
|
ctx.threadLogger?.logExecutor("content", "update", postId, successDetails, logTag);
|
|
60372
60404
|
} catch (err) {
|
|
@@ -60379,8 +60411,11 @@ ${body}` : this.state.header;
|
|
|
60379
60411
|
closeCurrentPost(ctx) {
|
|
60380
60412
|
const oldPostId = this.state.currentPostId;
|
|
60381
60413
|
const contentLength = this.state.currentPostContent.length;
|
|
60414
|
+
if (this.state.updateFailures > 0 && this.state.pendingContent.trim())
|
|
60415
|
+
this.giveUpCurrentPost();
|
|
60382
60416
|
this.state.currentPostId = null;
|
|
60383
60417
|
this.state.currentPostContent = "";
|
|
60418
|
+
this.state.updateFailures = 0;
|
|
60384
60419
|
if (ctx?.threadLogger && oldPostId) {
|
|
60385
60420
|
ctx.threadLogger.logExecutor("content", "close", oldPostId, {
|
|
60386
60421
|
contentLength,
|
|
@@ -60436,13 +60471,22 @@ ${body}` : this.state.header;
|
|
|
60436
60471
|
this.state.turnOpen = false;
|
|
60437
60472
|
return;
|
|
60438
60473
|
}
|
|
60439
|
-
|
|
60440
|
-
|
|
60474
|
+
const postBefore = this.state.currentPostId;
|
|
60475
|
+
await this.flushPending(ctx, reason);
|
|
60476
|
+
if (reason === "result") {
|
|
60477
|
+
if (this.state.updateFailures > 0 && this.state.currentPostId !== null && this.state.pendingContent.trim()) {
|
|
60478
|
+
await this.flushPending(ctx, reason);
|
|
60479
|
+
}
|
|
60480
|
+
if (postBefore !== null && this.state.currentPostId === null && this.state.pendingContent.trim()) {
|
|
60481
|
+
await this.flushPending(ctx, reason);
|
|
60482
|
+
}
|
|
60483
|
+
}
|
|
60484
|
+
if (this.state.headerDirty && this.state.updateFailures === 0)
|
|
60441
60485
|
await this.renderHeaderOnly(ctx);
|
|
60442
60486
|
if (reason === "result")
|
|
60443
60487
|
this.state.turnOpen = false;
|
|
60444
60488
|
}
|
|
60445
|
-
async flushPending(ctx) {
|
|
60489
|
+
async flushPending(ctx, reason) {
|
|
60446
60490
|
const pendingAtFlushStart = this.state.pendingContent;
|
|
60447
60491
|
let content = ctx.formatter.formatMarkdown(pendingAtFlushStart).trim();
|
|
60448
60492
|
const { maxLength: MAX_POST_LENGTH, hardThreshold: HARD_CONTINUATION_THRESHOLD } = ctx.platform.getMessageLimits();
|
|
@@ -60460,7 +60504,7 @@ ${body}` : this.state.header;
|
|
|
60460
60504
|
const shouldBreakEarly = this.state.currentPostId && combinedContent.length > MIN_BREAK_THRESHOLD && ctx.contentBreaker.shouldFlushEarly(combinedContent);
|
|
60461
60505
|
const reserve = this.headerReserve(this.state.currentPostId);
|
|
60462
60506
|
if (this.state.currentPostId && (combinedContent.length + reserve > HARD_CONTINUATION_THRESHOLD || shouldBreakEarly)) {
|
|
60463
|
-
await this.handleSplit(ctx, combinedContent, pendingAtFlushStart, HARD_CONTINUATION_THRESHOLD);
|
|
60507
|
+
await this.handleSplit(ctx, combinedContent, pendingAtFlushStart, HARD_CONTINUATION_THRESHOLD, reason);
|
|
60464
60508
|
return;
|
|
60465
60509
|
}
|
|
60466
60510
|
if (this.state.currentPostId && content.length + reserve > MAX_POST_LENGTH) {
|
|
@@ -60495,10 +60539,7 @@ ${body}` : this.state.header;
|
|
|
60495
60539
|
await this.tryUpdatePost(ctx, postId, combinedContent, "flush", { newContentLength: content.length, combinedLength: combinedContent.length }, (err) => ({ failedOp: "updatePost", error: String(err) }), () => {
|
|
60496
60540
|
this.state.currentPostContent = combinedContent;
|
|
60497
60541
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60498
|
-
}, () =>
|
|
60499
|
-
this.state.currentPostId = null;
|
|
60500
|
-
this.state.currentPostContent = "";
|
|
60501
|
-
});
|
|
60542
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60502
60543
|
} else {
|
|
60503
60544
|
const chunks = splitContentForHeight(content, ctx.contentBreaker).flatMap((chunk) => chunk.length + reserve > MAX_POST_LENGTH ? splitByLength(chunk, HARD_CONTINUATION_THRESHOLD - reserve) : [chunk]);
|
|
60504
60545
|
ctx.threadLogger?.logExecutor("content", "create_start", "none", {
|
|
@@ -60509,7 +60550,7 @@ ${body}` : this.state.header;
|
|
|
60509
60550
|
await this.postChunks(ctx, chunks, pendingAtFlushStart, false);
|
|
60510
60551
|
}
|
|
60511
60552
|
}
|
|
60512
|
-
async splitOversized(ctx, content, pendingAtFlushStart, hardThreshold) {
|
|
60553
|
+
async splitOversized(ctx, content, pendingAtFlushStart, hardThreshold, reason) {
|
|
60513
60554
|
const postId = this.state.currentPostId;
|
|
60514
60555
|
if (!postId)
|
|
60515
60556
|
return false;
|
|
@@ -60520,17 +60561,35 @@ ${body}` : this.state.header;
|
|
|
60520
60561
|
let landed = false;
|
|
60521
60562
|
await this.tryUpdatePost(ctx, postId, firstPiece, "handleSplit", { reason: "oversized_code_block", contentLength: content.length, pieces: rest.length + 1 }, { reason: "oversized_code_block_failed" }, () => {
|
|
60522
60563
|
landed = true;
|
|
60523
|
-
}, () => {
|
|
60524
|
-
|
|
60525
|
-
|
|
60526
|
-
|
|
60564
|
+
}, () => {});
|
|
60565
|
+
if (!landed) {
|
|
60566
|
+
this.onInPlaceUpdateFailed(reason);
|
|
60567
|
+
return true;
|
|
60568
|
+
}
|
|
60527
60569
|
this.state.currentPostId = null;
|
|
60528
60570
|
this.state.currentPostContent = "";
|
|
60529
|
-
|
|
60530
|
-
|
|
60531
|
-
await this.postChunks(ctx, rest, pendingAtFlushStart, landed);
|
|
60571
|
+
this.clearFlushedContent(pendingAtFlushStart);
|
|
60572
|
+
await this.postChunks(ctx, rest, pendingAtFlushStart, true);
|
|
60532
60573
|
return true;
|
|
60533
60574
|
}
|
|
60575
|
+
onInPlaceUpdateFailed(reason) {
|
|
60576
|
+
this.state.updateFailures++;
|
|
60577
|
+
const limit = reason === "result" ? 2 : MAX_IN_PLACE_UPDATE_FAILURES;
|
|
60578
|
+
if (this.state.updateFailures < limit)
|
|
60579
|
+
return;
|
|
60580
|
+
this.giveUpCurrentPost();
|
|
60581
|
+
}
|
|
60582
|
+
giveUpCurrentPost() {
|
|
60583
|
+
const opener = openFenceOf(this.state.currentPostContent);
|
|
60584
|
+
this.state.currentPostId = null;
|
|
60585
|
+
this.state.currentPostContent = "";
|
|
60586
|
+
this.state.updateFailures = 0;
|
|
60587
|
+
if (!opener)
|
|
60588
|
+
return;
|
|
60589
|
+
const rest = this.state.pendingContent.replace(/^\n+/, "");
|
|
60590
|
+
this.state.pendingContent = /^```[ \t]*(\n|$)/.test(rest) ? rest.replace(/^```[ \t]*\n?/, "") : `${opener}
|
|
60591
|
+
${rest}`;
|
|
60592
|
+
}
|
|
60534
60593
|
async postChunks(ctx, chunks, pendingAtFlushStart, flushCleared) {
|
|
60535
60594
|
let cleared = flushCleared;
|
|
60536
60595
|
for (let i = 0;i < chunks.length; i++) {
|
|
@@ -60554,7 +60613,7 @@ ${this.state.pendingContent}` : "");
|
|
|
60554
60613
|
}
|
|
60555
60614
|
}
|
|
60556
60615
|
}
|
|
60557
|
-
async handleSplit(ctx, content, pendingAtFlushStart, hardThreshold) {
|
|
60616
|
+
async handleSplit(ctx, content, pendingAtFlushStart, hardThreshold, reason) {
|
|
60558
60617
|
let breakPoint;
|
|
60559
60618
|
let codeBlockOpenPosition;
|
|
60560
60619
|
if (content.length > hardThreshold) {
|
|
@@ -60602,26 +60661,21 @@ ${this.state.pendingContent}` : "");
|
|
|
60602
60661
|
await this.tryUpdatePost(ctx, postId, content, "handleSplit", { reason: "soft_break_no_breakpoint", contentLength: content.length }, { reason: "soft_break_no_breakpoint_failed" }, () => {
|
|
60603
60662
|
this.state.currentPostContent = content;
|
|
60604
60663
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60605
|
-
}, () =>
|
|
60606
|
-
this.state.currentPostId = null;
|
|
60607
|
-
});
|
|
60664
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60608
60665
|
}
|
|
60609
60666
|
return;
|
|
60610
60667
|
}
|
|
60611
60668
|
}
|
|
60612
60669
|
if (codeBlockOpenPosition !== undefined) {
|
|
60613
60670
|
if (codeBlockOpenPosition === 0) {
|
|
60614
|
-
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold))
|
|
60671
|
+
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold, reason))
|
|
60615
60672
|
return;
|
|
60616
60673
|
if (this.state.currentPostId) {
|
|
60617
60674
|
const postId = this.state.currentPostId;
|
|
60618
60675
|
await this.tryUpdatePost(ctx, postId, content, "handleSplit", { reason: "code_block_at_start", contentLength: content.length }, { reason: "code_block_at_start_failed" }, () => {
|
|
60619
60676
|
this.state.currentPostContent = content;
|
|
60620
60677
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60621
|
-
}, () =>
|
|
60622
|
-
this.state.currentPostId = null;
|
|
60623
|
-
this.state.currentPostContent = "";
|
|
60624
|
-
});
|
|
60678
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60625
60679
|
}
|
|
60626
60680
|
return;
|
|
60627
60681
|
}
|
|
@@ -60630,17 +60684,14 @@ ${this.state.pendingContent}` : "");
|
|
|
60630
60684
|
if (breakBeforeCodeBlock > 0) {
|
|
60631
60685
|
breakPoint = breakBeforeCodeBlock;
|
|
60632
60686
|
} else {
|
|
60633
|
-
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold))
|
|
60687
|
+
if (await this.splitOversized(ctx, content, pendingAtFlushStart, hardThreshold, reason))
|
|
60634
60688
|
return;
|
|
60635
60689
|
if (this.state.currentPostId) {
|
|
60636
60690
|
const postId = this.state.currentPostId;
|
|
60637
60691
|
await this.tryUpdatePost(ctx, postId, content, "handleSplit", { reason: "no_break_before_code_block", contentLength: content.length }, { reason: "no_break_before_code_block_failed" }, () => {
|
|
60638
60692
|
this.state.currentPostContent = content;
|
|
60639
60693
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60640
|
-
}, () =>
|
|
60641
|
-
this.state.currentPostId = null;
|
|
60642
|
-
this.state.currentPostContent = "";
|
|
60643
|
-
});
|
|
60694
|
+
}, () => this.onInPlaceUpdateFailed(reason));
|
|
60644
60695
|
}
|
|
60645
60696
|
return;
|
|
60646
60697
|
}
|
|
@@ -60652,11 +60703,11 @@ ${this.state.pendingContent}` : "");
|
|
|
60652
60703
|
const postId = this.state.currentPostId;
|
|
60653
60704
|
await this.tryUpdatePost(ctx, postId, firstPart, "handleSplit", { reason: "split_first_part", firstPartLength: firstPart.length, remainderLength: remainder.length }, { reason: "split_first_part_failed" }, () => {
|
|
60654
60705
|
firstPartLanded = true;
|
|
60655
|
-
}, () => {
|
|
60656
|
-
|
|
60657
|
-
|
|
60658
|
-
|
|
60659
|
-
}
|
|
60706
|
+
}, () => {});
|
|
60707
|
+
if (!firstPartLanded) {
|
|
60708
|
+
this.onInPlaceUpdateFailed(reason);
|
|
60709
|
+
return;
|
|
60710
|
+
}
|
|
60660
60711
|
}
|
|
60661
60712
|
this.state.currentPostId = null;
|
|
60662
60713
|
this.state.currentPostContent = "";
|
|
@@ -60689,6 +60740,7 @@ ${content}` : header : content;
|
|
|
60689
60740
|
if (bumpedPostId) {
|
|
60690
60741
|
adoptAsHeaderPost(bumpedPostId);
|
|
60691
60742
|
this.state.currentPostId = bumpedPostId;
|
|
60743
|
+
this.state.updateFailures = 0;
|
|
60692
60744
|
this.state.currentPostContent = content;
|
|
60693
60745
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60694
60746
|
ctx.threadLogger?.logExecutor("content", "create", bumpedPostId, {
|
|
@@ -60705,6 +60757,7 @@ ${content}` : header : content;
|
|
|
60705
60757
|
const post = await ctx.createPost(rendered, { type: "content" });
|
|
60706
60758
|
adoptAsHeaderPost(post.id);
|
|
60707
60759
|
this.state.currentPostId = post.id;
|
|
60760
|
+
this.state.updateFailures = 0;
|
|
60708
60761
|
this.state.currentPostContent = content;
|
|
60709
60762
|
this.clearFlushedContent(pendingAtFlushStart);
|
|
60710
60763
|
ctx.logger.debug(`Created post ${formatShortId(post.id)}`);
|
|
@@ -60730,6 +60783,11 @@ ${content}` : header : content;
|
|
|
60730
60783
|
}
|
|
60731
60784
|
}
|
|
60732
60785
|
var FENCE_LINE = /^```.*$/gm;
|
|
60786
|
+
var MAX_IN_PLACE_UPDATE_FAILURES = 3;
|
|
60787
|
+
function openFenceOf(text) {
|
|
60788
|
+
const fences = text.match(FENCE_LINE) ?? [];
|
|
60789
|
+
return fences.length % 2 === 1 ? fences[fences.length - 1] : null;
|
|
60790
|
+
}
|
|
60733
60791
|
var FENCE_CLOSE = "\n```";
|
|
60734
60792
|
function splitByLength(text, max) {
|
|
60735
60793
|
const room = max - FENCE_CLOSE.length;
|
|
@@ -71905,7 +71963,6 @@ class SlackClient extends BasePlatformClient {
|
|
|
71905
71963
|
token: this.botToken,
|
|
71906
71964
|
channelId: this.channelId,
|
|
71907
71965
|
allowedUsers: this.allowedUsers,
|
|
71908
|
-
appToken: this.appToken,
|
|
71909
71966
|
apiUrl: this.apiUrl,
|
|
71910
71967
|
outboundFiles: this.outboundFiles,
|
|
71911
71968
|
mcpServers: this.mcpServers,
|