claude-threads 0.48.3 → 0.48.5
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 +15 -0
- package/dist/index.js +220 -118
- package/dist/mcp/permission-server.js +96 -44
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.48.5] - 2026-01-08
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Slack msg_too_long errors fixed** - Messages are now safely truncated before sending to Slack API, preventing 4000+ character errors (#136)
|
|
14
|
+
- **Emoji conversion for Slack reactions** - Emoji names like `thumbsup` are now correctly converted to unicode for Slack reactions and Mattermost messages (#135)
|
|
15
|
+
|
|
16
|
+
## [0.48.4] - 2026-01-08
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **Code blocks no longer split incorrectly** - Messages are now split at line boundaries and never inside code blocks, removing ugly continuation markers (#134)
|
|
20
|
+
- **Disabled platforms show dim indicator** - Changed disabled platform status from red (error) to dim (inactive) for clearer visual feedback (#132)
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **CI smoke test** - Added startup verification to CI pipeline to catch binary launch issues early (#133)
|
|
24
|
+
|
|
10
25
|
## [0.48.3] - 2026-01-08
|
|
11
26
|
|
|
12
27
|
### Changed
|
package/dist/index.js
CHANGED
|
@@ -42542,6 +42542,155 @@ ${code}
|
|
|
42542
42542
|
}
|
|
42543
42543
|
}
|
|
42544
42544
|
|
|
42545
|
+
// src/platform/utils.ts
|
|
42546
|
+
function getPlatformIcon(platformType) {
|
|
42547
|
+
switch (platformType) {
|
|
42548
|
+
case "slack":
|
|
42549
|
+
return "\uD83D\uDCAC";
|
|
42550
|
+
case "mattermost":
|
|
42551
|
+
return "\uD83D\uDCE2";
|
|
42552
|
+
default:
|
|
42553
|
+
return "\uD83D\uDCAC";
|
|
42554
|
+
}
|
|
42555
|
+
}
|
|
42556
|
+
function truncateMessageSafely(message, maxLength, truncationIndicator = "... (truncated)") {
|
|
42557
|
+
if (message.length <= maxLength)
|
|
42558
|
+
return message;
|
|
42559
|
+
const reservedSpace = 4 + 2 + truncationIndicator.length;
|
|
42560
|
+
let truncated = message.substring(0, maxLength - reservedSpace);
|
|
42561
|
+
const codeBlockMarkers = (truncated.match(/```/g) || []).length;
|
|
42562
|
+
const isInsideCodeBlock = codeBlockMarkers % 2 === 1;
|
|
42563
|
+
if (isInsideCodeBlock) {
|
|
42564
|
+
truncated += "\n```";
|
|
42565
|
+
}
|
|
42566
|
+
return truncated + `
|
|
42567
|
+
|
|
42568
|
+
` + truncationIndicator;
|
|
42569
|
+
}
|
|
42570
|
+
function normalizeEmojiName(emojiName) {
|
|
42571
|
+
const name = emojiName.replace(/^:|:$/g, "");
|
|
42572
|
+
const aliases = {
|
|
42573
|
+
thumbsup: "+1",
|
|
42574
|
+
thumbs_up: "+1",
|
|
42575
|
+
thumbsdown: "-1",
|
|
42576
|
+
thumbs_down: "-1",
|
|
42577
|
+
heavy_check_mark: "white_check_mark",
|
|
42578
|
+
x: "x",
|
|
42579
|
+
cross_mark: "x",
|
|
42580
|
+
heavy_multiplication_x: "x",
|
|
42581
|
+
pause_button: "pause",
|
|
42582
|
+
double_vertical_bar: "pause",
|
|
42583
|
+
play_button: "arrow_forward",
|
|
42584
|
+
stop_button: "stop",
|
|
42585
|
+
octagonal_sign: "stop",
|
|
42586
|
+
"1": "one",
|
|
42587
|
+
"2": "two",
|
|
42588
|
+
"3": "three",
|
|
42589
|
+
"4": "four",
|
|
42590
|
+
"5": "five"
|
|
42591
|
+
};
|
|
42592
|
+
return aliases[name.toLowerCase()] ?? name;
|
|
42593
|
+
}
|
|
42594
|
+
var EMOJI_NAME_TO_UNICODE = {
|
|
42595
|
+
"+1": "\uD83D\uDC4D",
|
|
42596
|
+
"-1": "\uD83D\uDC4E",
|
|
42597
|
+
white_check_mark: "\u2705",
|
|
42598
|
+
x: "\u274C",
|
|
42599
|
+
warning: "\u26A0\uFE0F",
|
|
42600
|
+
stop: "\uD83D\uDED1",
|
|
42601
|
+
pause: "\u23F8\uFE0F",
|
|
42602
|
+
arrow_forward: "\u25B6\uFE0F",
|
|
42603
|
+
one: "1\uFE0F\u20E3",
|
|
42604
|
+
two: "2\uFE0F\u20E3",
|
|
42605
|
+
three: "3\uFE0F\u20E3",
|
|
42606
|
+
four: "4\uFE0F\u20E3",
|
|
42607
|
+
five: "5\uFE0F\u20E3",
|
|
42608
|
+
six: "6\uFE0F\u20E3",
|
|
42609
|
+
seven: "7\uFE0F\u20E3",
|
|
42610
|
+
eight: "8\uFE0F\u20E3",
|
|
42611
|
+
nine: "9\uFE0F\u20E3",
|
|
42612
|
+
keycap_ten: "\uD83D\uDD1F",
|
|
42613
|
+
zero: "0\uFE0F\u20E3",
|
|
42614
|
+
robot: "\uD83E\uDD16",
|
|
42615
|
+
gear: "\u2699\uFE0F",
|
|
42616
|
+
lock: "\uD83D\uDD10",
|
|
42617
|
+
unlock: "\uD83D\uDD13",
|
|
42618
|
+
file_folder: "\uD83D\uDCC1",
|
|
42619
|
+
page_facing_up: "\uD83D\uDCC4",
|
|
42620
|
+
memo: "\uD83D\uDCDD",
|
|
42621
|
+
clock: "\u23F1\uFE0F",
|
|
42622
|
+
hourglass: "\u23F3",
|
|
42623
|
+
seedling: "\uD83C\uDF31",
|
|
42624
|
+
evergreen_tree: "\uD83C\uDF32",
|
|
42625
|
+
deciduous_tree: "\uD83C\uDF33",
|
|
42626
|
+
thread: "\uD83E\uDDF5",
|
|
42627
|
+
arrows_counterclockwise: "\uD83D\uDD04",
|
|
42628
|
+
package: "\uD83D\uDCE6",
|
|
42629
|
+
partying_face: "\uD83C\uDF89",
|
|
42630
|
+
hourglass_flowing_sand: "\u23F3",
|
|
42631
|
+
herb: "\uD83C\uDF3F",
|
|
42632
|
+
bust_in_silhouette: "\uD83D\uDC64",
|
|
42633
|
+
clipboard: "\uD83D\uDCCB",
|
|
42634
|
+
small_red_triangle_down: "\uD83D\uDD3D",
|
|
42635
|
+
arrow_down_small: "\uD83D\uDD3D",
|
|
42636
|
+
new: "\uD83C\uDD95"
|
|
42637
|
+
};
|
|
42638
|
+
var EMOJI_UNICODE_TO_NAME = Object.fromEntries(Object.entries(EMOJI_NAME_TO_UNICODE).map(([name, unicode]) => [unicode, name]));
|
|
42639
|
+
function convertUnicodeEmojiToShortcodes(text) {
|
|
42640
|
+
let result = text;
|
|
42641
|
+
for (const [unicode, name] of Object.entries(EMOJI_UNICODE_TO_NAME)) {
|
|
42642
|
+
result = result.split(unicode).join(`:${name}:`);
|
|
42643
|
+
}
|
|
42644
|
+
return result;
|
|
42645
|
+
}
|
|
42646
|
+
function getEmojiName(emoji) {
|
|
42647
|
+
const mapped = EMOJI_UNICODE_TO_NAME[emoji];
|
|
42648
|
+
if (mapped) {
|
|
42649
|
+
return mapped;
|
|
42650
|
+
}
|
|
42651
|
+
return emoji;
|
|
42652
|
+
}
|
|
42653
|
+
function convertMarkdownToSlack(content) {
|
|
42654
|
+
const codeBlocks = [];
|
|
42655
|
+
const CODE_BLOCK_PLACEHOLDER = "\x00CODE_BLOCK_";
|
|
42656
|
+
let preserved = content.replace(/```[\s\S]*?```/g, (match) => {
|
|
42657
|
+
const index = codeBlocks.length;
|
|
42658
|
+
codeBlocks.push(match);
|
|
42659
|
+
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
42660
|
+
});
|
|
42661
|
+
preserved = preserved.replace(/`[^`\n]+`/g, (match) => {
|
|
42662
|
+
const index = codeBlocks.length;
|
|
42663
|
+
codeBlocks.push(match);
|
|
42664
|
+
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
42665
|
+
});
|
|
42666
|
+
preserved = convertMarkdownTablesToSlack(preserved);
|
|
42667
|
+
preserved = preserved.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
42668
|
+
preserved = preserved.replace(/\*\*([^*]+)\*\*/g, "*$1*");
|
|
42669
|
+
preserved = preserved.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "<$2|$1>");
|
|
42670
|
+
preserved = preserved.replace(/^[-*_]{3,}\s*$/gm, "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
42671
|
+
for (let i = 0;i < codeBlocks.length; i++) {
|
|
42672
|
+
preserved = preserved.replace(`${CODE_BLOCK_PLACEHOLDER}${i}\x00`, codeBlocks[i]);
|
|
42673
|
+
}
|
|
42674
|
+
return preserved;
|
|
42675
|
+
}
|
|
42676
|
+
function convertMarkdownTablesToSlack(content) {
|
|
42677
|
+
const tableRegex = /^\|(.+)\|\s*\n\|[-:\s|]+\|\s*\n((?:\|.+\|\s*\n?)+)/gm;
|
|
42678
|
+
return content.replace(tableRegex, (_match, headerLine, bodyLines) => {
|
|
42679
|
+
const headers = headerLine.split("|").map((h) => h.trim()).filter((h) => h);
|
|
42680
|
+
const rows = bodyLines.trim().split(`
|
|
42681
|
+
`).map((row) => row.split("|").map((c) => c.trim()).filter((c) => c !== ""));
|
|
42682
|
+
const formattedRows = rows.map((row) => {
|
|
42683
|
+
const cells = row.map((cell, i) => {
|
|
42684
|
+
const header = headers[i];
|
|
42685
|
+
return header ? `*${header}:* ${cell}` : cell;
|
|
42686
|
+
});
|
|
42687
|
+
return cells.join(" \xB7 ");
|
|
42688
|
+
});
|
|
42689
|
+
return formattedRows.join(`
|
|
42690
|
+
`);
|
|
42691
|
+
});
|
|
42692
|
+
}
|
|
42693
|
+
|
|
42545
42694
|
// src/platform/mattermost/client.ts
|
|
42546
42695
|
var log = createLogger("mattermost");
|
|
42547
42696
|
function escapeRegExp(string) {
|
|
@@ -42686,7 +42835,7 @@ class MattermostClient extends EventEmitter {
|
|
|
42686
42835
|
async createPost(message, threadId) {
|
|
42687
42836
|
const request = {
|
|
42688
42837
|
channel_id: this.channelId,
|
|
42689
|
-
message,
|
|
42838
|
+
message: convertUnicodeEmojiToShortcodes(message),
|
|
42690
42839
|
root_id: threadId
|
|
42691
42840
|
};
|
|
42692
42841
|
const post = await this.api("POST", "/posts", request);
|
|
@@ -42695,7 +42844,7 @@ class MattermostClient extends EventEmitter {
|
|
|
42695
42844
|
async updatePost(postId, message) {
|
|
42696
42845
|
const request = {
|
|
42697
42846
|
id: postId,
|
|
42698
|
-
message
|
|
42847
|
+
message: convertUnicodeEmojiToShortcodes(message)
|
|
42699
42848
|
};
|
|
42700
42849
|
const post = await this.api("PUT", `/posts/${postId}`, request);
|
|
42701
42850
|
return this.normalizePlatformPost(post);
|
|
@@ -43058,82 +43207,6 @@ class MattermostClient extends EventEmitter {
|
|
|
43058
43207
|
// src/platform/slack/client.ts
|
|
43059
43208
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
43060
43209
|
|
|
43061
|
-
// src/platform/utils.ts
|
|
43062
|
-
function getPlatformIcon(platformType) {
|
|
43063
|
-
switch (platformType) {
|
|
43064
|
-
case "slack":
|
|
43065
|
-
return "\uD83D\uDCAC";
|
|
43066
|
-
case "mattermost":
|
|
43067
|
-
return "\uD83D\uDCE2";
|
|
43068
|
-
default:
|
|
43069
|
-
return "\uD83D\uDCAC";
|
|
43070
|
-
}
|
|
43071
|
-
}
|
|
43072
|
-
function normalizeEmojiName(emojiName) {
|
|
43073
|
-
const name = emojiName.replace(/^:|:$/g, "");
|
|
43074
|
-
const aliases = {
|
|
43075
|
-
thumbsup: "+1",
|
|
43076
|
-
thumbs_up: "+1",
|
|
43077
|
-
thumbsdown: "-1",
|
|
43078
|
-
thumbs_down: "-1",
|
|
43079
|
-
heavy_check_mark: "white_check_mark",
|
|
43080
|
-
x: "x",
|
|
43081
|
-
cross_mark: "x",
|
|
43082
|
-
heavy_multiplication_x: "x",
|
|
43083
|
-
pause_button: "pause",
|
|
43084
|
-
double_vertical_bar: "pause",
|
|
43085
|
-
play_button: "arrow_forward",
|
|
43086
|
-
stop_button: "stop",
|
|
43087
|
-
octagonal_sign: "stop",
|
|
43088
|
-
"1": "one",
|
|
43089
|
-
"2": "two",
|
|
43090
|
-
"3": "three",
|
|
43091
|
-
"4": "four",
|
|
43092
|
-
"5": "five"
|
|
43093
|
-
};
|
|
43094
|
-
return aliases[name.toLowerCase()] ?? name;
|
|
43095
|
-
}
|
|
43096
|
-
function convertMarkdownToSlack(content) {
|
|
43097
|
-
const codeBlocks = [];
|
|
43098
|
-
const CODE_BLOCK_PLACEHOLDER = "\x00CODE_BLOCK_";
|
|
43099
|
-
let preserved = content.replace(/```[\s\S]*?```/g, (match) => {
|
|
43100
|
-
const index = codeBlocks.length;
|
|
43101
|
-
codeBlocks.push(match);
|
|
43102
|
-
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
43103
|
-
});
|
|
43104
|
-
preserved = preserved.replace(/`[^`\n]+`/g, (match) => {
|
|
43105
|
-
const index = codeBlocks.length;
|
|
43106
|
-
codeBlocks.push(match);
|
|
43107
|
-
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
43108
|
-
});
|
|
43109
|
-
preserved = convertMarkdownTablesToSlack(preserved);
|
|
43110
|
-
preserved = preserved.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
43111
|
-
preserved = preserved.replace(/\*\*([^*]+)\*\*/g, "*$1*");
|
|
43112
|
-
preserved = preserved.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "<$2|$1>");
|
|
43113
|
-
preserved = preserved.replace(/^[-*_]{3,}\s*$/gm, "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
43114
|
-
for (let i = 0;i < codeBlocks.length; i++) {
|
|
43115
|
-
preserved = preserved.replace(`${CODE_BLOCK_PLACEHOLDER}${i}\x00`, codeBlocks[i]);
|
|
43116
|
-
}
|
|
43117
|
-
return preserved;
|
|
43118
|
-
}
|
|
43119
|
-
function convertMarkdownTablesToSlack(content) {
|
|
43120
|
-
const tableRegex = /^\|(.+)\|\s*\n\|[-:\s|]+\|\s*\n((?:\|.+\|\s*\n?)+)/gm;
|
|
43121
|
-
return content.replace(tableRegex, (_match, headerLine, bodyLines) => {
|
|
43122
|
-
const headers = headerLine.split("|").map((h) => h.trim()).filter((h) => h);
|
|
43123
|
-
const rows = bodyLines.trim().split(`
|
|
43124
|
-
`).map((row) => row.split("|").map((c) => c.trim()).filter((c) => c !== ""));
|
|
43125
|
-
const formattedRows = rows.map((row) => {
|
|
43126
|
-
const cells = row.map((cell, i) => {
|
|
43127
|
-
const header = headers[i];
|
|
43128
|
-
return header ? `*${header}:* ${cell}` : cell;
|
|
43129
|
-
});
|
|
43130
|
-
return cells.join(" \xB7 ");
|
|
43131
|
-
});
|
|
43132
|
-
return formattedRows.join(`
|
|
43133
|
-
`);
|
|
43134
|
-
});
|
|
43135
|
-
}
|
|
43136
|
-
|
|
43137
43210
|
// src/platform/slack/formatter.ts
|
|
43138
43211
|
class SlackFormatter {
|
|
43139
43212
|
formatBold(text) {
|
|
@@ -43738,9 +43811,10 @@ class SlackClient extends EventEmitter2 {
|
|
|
43738
43811
|
}
|
|
43739
43812
|
async createPost(message, threadId, options) {
|
|
43740
43813
|
const shouldUnfurl = options?.unfurl ?? threadId !== undefined;
|
|
43814
|
+
const truncatedMessage = this.truncateMessageIfNeeded(message);
|
|
43741
43815
|
const body = {
|
|
43742
43816
|
channel: this.channelId,
|
|
43743
|
-
text:
|
|
43817
|
+
text: truncatedMessage,
|
|
43744
43818
|
unfurl_links: shouldUnfurl,
|
|
43745
43819
|
unfurl_media: shouldUnfurl
|
|
43746
43820
|
};
|
|
@@ -43759,10 +43833,11 @@ class SlackClient extends EventEmitter2 {
|
|
|
43759
43833
|
};
|
|
43760
43834
|
}
|
|
43761
43835
|
async updatePost(postId, message) {
|
|
43836
|
+
const truncatedMessage = this.truncateMessageIfNeeded(message);
|
|
43762
43837
|
const response = await this.api("POST", "chat.update", {
|
|
43763
43838
|
channel: this.channelId,
|
|
43764
43839
|
ts: postId,
|
|
43765
|
-
text:
|
|
43840
|
+
text: truncatedMessage
|
|
43766
43841
|
});
|
|
43767
43842
|
return {
|
|
43768
43843
|
id: response.ts,
|
|
@@ -43841,6 +43916,14 @@ class SlackClient extends EventEmitter2 {
|
|
|
43841
43916
|
getMessageLimits() {
|
|
43842
43917
|
return { maxLength: 12000, hardThreshold: 1e4 };
|
|
43843
43918
|
}
|
|
43919
|
+
truncateMessageIfNeeded(message) {
|
|
43920
|
+
const { maxLength } = this.getMessageLimits();
|
|
43921
|
+
if (message.length <= maxLength) {
|
|
43922
|
+
return message;
|
|
43923
|
+
}
|
|
43924
|
+
log2.warn(`Truncating message from ${message.length} to ~${maxLength} chars`);
|
|
43925
|
+
return truncateMessageSafely(message, maxLength, "_... (truncated)_");
|
|
43926
|
+
}
|
|
43844
43927
|
async getThreadHistory(threadId, options) {
|
|
43845
43928
|
try {
|
|
43846
43929
|
const limit = options?.limit || 100;
|
|
@@ -43868,19 +43951,21 @@ class SlackClient extends EventEmitter2 {
|
|
|
43868
43951
|
}
|
|
43869
43952
|
}
|
|
43870
43953
|
async addReaction(postId, emojiName) {
|
|
43871
|
-
|
|
43954
|
+
const name = getEmojiName(emojiName);
|
|
43955
|
+
log2.debug(`Adding reaction :${name}: to post ${postId.substring(0, 12)}`);
|
|
43872
43956
|
await this.api("POST", "reactions.add", {
|
|
43873
43957
|
channel: this.channelId,
|
|
43874
43958
|
timestamp: postId,
|
|
43875
|
-
name
|
|
43959
|
+
name
|
|
43876
43960
|
});
|
|
43877
43961
|
}
|
|
43878
43962
|
async removeReaction(postId, emojiName) {
|
|
43879
|
-
|
|
43963
|
+
const name = getEmojiName(emojiName);
|
|
43964
|
+
log2.debug(`Removing reaction :${name}: from post ${postId.substring(0, 12)}`);
|
|
43880
43965
|
await this.api("POST", "reactions.remove", {
|
|
43881
43966
|
channel: this.channelId,
|
|
43882
43967
|
timestamp: postId,
|
|
43883
|
-
name
|
|
43968
|
+
name
|
|
43884
43969
|
});
|
|
43885
43970
|
}
|
|
43886
43971
|
isBotMentioned(message) {
|
|
@@ -43961,14 +44046,14 @@ async function getUser(config, userId) {
|
|
|
43961
44046
|
async function createPost(config, channelId, message, rootId) {
|
|
43962
44047
|
return mattermostApi(config, "POST", "/posts", {
|
|
43963
44048
|
channel_id: channelId,
|
|
43964
|
-
message,
|
|
44049
|
+
message: convertUnicodeEmojiToShortcodes(message),
|
|
43965
44050
|
root_id: rootId
|
|
43966
44051
|
});
|
|
43967
44052
|
}
|
|
43968
44053
|
async function updatePost(config, postId, message) {
|
|
43969
44054
|
return mattermostApi(config, "PUT", `/posts/${postId}`, {
|
|
43970
44055
|
id: postId,
|
|
43971
|
-
message
|
|
44056
|
+
message: convertUnicodeEmojiToShortcodes(message)
|
|
43972
44057
|
});
|
|
43973
44058
|
}
|
|
43974
44059
|
async function addReaction(config, postId, userId, emojiName) {
|
|
@@ -45211,13 +45296,20 @@ async function bumpTasksToBottomWithContent(session, newContent, registerPost) {
|
|
|
45211
45296
|
const oldTasksPostId = session.tasksPostId;
|
|
45212
45297
|
const oldTasksContent = session.lastTasksContent;
|
|
45213
45298
|
sessionLog(session).debug(`Bumping tasks to bottom, repurposing post ${oldTasksPostId.substring(0, 8)}`);
|
|
45299
|
+
const { maxLength: MAX_POST_LENGTH } = session.platform.getMessageLimits();
|
|
45300
|
+
let contentToPost = newContent;
|
|
45301
|
+
if (contentToPost.length > MAX_POST_LENGTH) {
|
|
45302
|
+
sessionLog(session).warn(`Content too long for repurposed post (${contentToPost.length}), truncating`);
|
|
45303
|
+
const formatter = session.platform.getFormatter();
|
|
45304
|
+
contentToPost = truncateMessageSafely(contentToPost, MAX_POST_LENGTH, formatter.formatItalic("... (truncated)"));
|
|
45305
|
+
}
|
|
45214
45306
|
try {
|
|
45215
45307
|
await session.platform.removeReaction(oldTasksPostId, TASK_TOGGLE_EMOJIS[0]);
|
|
45216
45308
|
} catch (err) {
|
|
45217
45309
|
sessionLog(session).debug(`Could not remove toggle emoji: ${err}`);
|
|
45218
45310
|
}
|
|
45219
45311
|
await session.platform.unpinPost(oldTasksPostId).catch(() => {});
|
|
45220
|
-
await withErrorHandling(() => session.platform.updatePost(oldTasksPostId,
|
|
45312
|
+
await withErrorHandling(() => session.platform.updatePost(oldTasksPostId, contentToPost), { action: "Repurpose task post", session });
|
|
45221
45313
|
registerPost(oldTasksPostId, session.threadId);
|
|
45222
45314
|
if (oldTasksContent) {
|
|
45223
45315
|
const displayContent = getTaskDisplayContent(session);
|
|
@@ -45281,6 +45373,7 @@ async function flush(session, registerPost) {
|
|
|
45281
45373
|
const currentPostId = session.currentPostId;
|
|
45282
45374
|
let breakPoint;
|
|
45283
45375
|
let codeBlockLanguage;
|
|
45376
|
+
let codeBlockOpenPosition;
|
|
45284
45377
|
if (content.length > HARD_CONTINUATION_THRESHOLD) {
|
|
45285
45378
|
const startSearchPos = Math.floor(HARD_CONTINUATION_THRESHOLD * 0.7);
|
|
45286
45379
|
const breakInfo = findLogicalBreakpoint(content, startSearchPos, Math.floor(HARD_CONTINUATION_THRESHOLD * 0.3));
|
|
@@ -45290,13 +45383,8 @@ async function flush(session, registerPost) {
|
|
|
45290
45383
|
const codeBlockState = getCodeBlockState(content, startSearchPos);
|
|
45291
45384
|
if (codeBlockState.isInside) {
|
|
45292
45385
|
codeBlockLanguage = codeBlockState.language;
|
|
45293
|
-
|
|
45294
|
-
|
|
45295
|
-
if (lineBreakMatch && lineBreakMatch.index !== undefined) {
|
|
45296
|
-
breakPoint = startSearchPos + lineBreakMatch.index + 1;
|
|
45297
|
-
} else {
|
|
45298
|
-
breakPoint = HARD_CONTINUATION_THRESHOLD;
|
|
45299
|
-
}
|
|
45386
|
+
codeBlockOpenPosition = codeBlockState.openPosition;
|
|
45387
|
+
breakPoint = HARD_CONTINUATION_THRESHOLD;
|
|
45300
45388
|
} else {
|
|
45301
45389
|
breakPoint = content.lastIndexOf(`
|
|
45302
45390
|
`, HARD_CONTINUATION_THRESHOLD);
|
|
@@ -45319,35 +45407,46 @@ async function flush(session, registerPost) {
|
|
|
45319
45407
|
return;
|
|
45320
45408
|
}
|
|
45321
45409
|
}
|
|
45322
|
-
|
|
45323
|
-
|
|
45324
|
-
|
|
45325
|
-
|
|
45326
|
-
|
|
45327
|
-
|
|
45410
|
+
if (codeBlockLanguage !== undefined && codeBlockOpenPosition !== undefined) {
|
|
45411
|
+
if (codeBlockOpenPosition === 0) {
|
|
45412
|
+
try {
|
|
45413
|
+
await session.platform.updatePost(currentPostId, content);
|
|
45414
|
+
} catch {
|
|
45415
|
+
sessionLog(session).debug("Update failed (code block at start), will create new post on next flush");
|
|
45416
|
+
session.currentPostId = null;
|
|
45417
|
+
}
|
|
45418
|
+
return;
|
|
45419
|
+
}
|
|
45420
|
+
const breakBeforeCodeBlock = content.lastIndexOf(`
|
|
45421
|
+
`, codeBlockOpenPosition);
|
|
45422
|
+
if (breakBeforeCodeBlock > 0) {
|
|
45423
|
+
breakPoint = breakBeforeCodeBlock;
|
|
45424
|
+
} else {
|
|
45425
|
+
try {
|
|
45426
|
+
await session.platform.updatePost(currentPostId, content);
|
|
45427
|
+
} catch {
|
|
45428
|
+
sessionLog(session).debug("Update failed (no break before code block), will create new post on next flush");
|
|
45429
|
+
session.currentPostId = null;
|
|
45430
|
+
}
|
|
45431
|
+
return;
|
|
45432
|
+
}
|
|
45328
45433
|
}
|
|
45329
|
-
const
|
|
45330
|
-
const
|
|
45331
|
-
|
|
45332
|
-
` + formatter2.formatItalic("... (continued below)") : firstPart;
|
|
45434
|
+
const firstPart = content.substring(0, breakPoint).trim();
|
|
45435
|
+
const remainder = content.substring(breakPoint).trim();
|
|
45333
45436
|
try {
|
|
45334
|
-
await session.platform.updatePost(currentPostId,
|
|
45437
|
+
await session.platform.updatePost(currentPostId, firstPart);
|
|
45335
45438
|
} catch {
|
|
45336
45439
|
sessionLog(session).debug("Update failed during split, continuing with new post");
|
|
45337
45440
|
}
|
|
45338
45441
|
session.currentPostId = null;
|
|
45339
45442
|
session.pendingContent = remainder;
|
|
45340
45443
|
if (remainder) {
|
|
45341
|
-
const continuationMarker = formatter2.formatItalic("(continued)");
|
|
45342
|
-
const continuationContent = continuationMarker + `
|
|
45343
|
-
|
|
45344
|
-
` + remainder;
|
|
45345
45444
|
const hasActiveTasks = session.tasksPostId && session.lastTasksContent && !session.tasksCompleted;
|
|
45346
45445
|
if (hasActiveTasks) {
|
|
45347
|
-
const postId = await bumpTasksToBottomWithContent(session,
|
|
45446
|
+
const postId = await bumpTasksToBottomWithContent(session, remainder, registerPost);
|
|
45348
45447
|
session.currentPostId = postId;
|
|
45349
45448
|
} else {
|
|
45350
|
-
const post = await withErrorHandling(() => session.platform.createPost(
|
|
45449
|
+
const post = await withErrorHandling(() => session.platform.createPost(remainder, session.threadId), { action: "Create continuation post", session });
|
|
45351
45450
|
if (post) {
|
|
45352
45451
|
session.currentPostId = post.id;
|
|
45353
45452
|
registerPost(post.id, session.threadId);
|
|
@@ -45358,11 +45457,9 @@ async function flush(session, registerPost) {
|
|
|
45358
45457
|
return;
|
|
45359
45458
|
}
|
|
45360
45459
|
if (content.length > MAX_POST_LENGTH) {
|
|
45361
|
-
sessionLog(session).warn(`Content too long (${content.length}), truncating
|
|
45460
|
+
sessionLog(session).warn(`Content too long (${content.length}), truncating`);
|
|
45362
45461
|
const formatter2 = session.platform.getFormatter();
|
|
45363
|
-
content = content
|
|
45364
|
-
|
|
45365
|
-
` + formatter2.formatItalic("... (truncated)");
|
|
45462
|
+
content = truncateMessageSafely(content, MAX_POST_LENGTH, formatter2.formatItalic("... (truncated)"));
|
|
45366
45463
|
}
|
|
45367
45464
|
if (session.currentPostId) {
|
|
45368
45465
|
const postId = session.currentPostId;
|
|
@@ -62854,7 +62951,10 @@ function Platforms({ platforms }) {
|
|
|
62854
62951
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
62855
62952
|
children: getPlatformIcon(platform2.platformType || "mattermost")
|
|
62856
62953
|
}, undefined, false, undefined, this),
|
|
62857
|
-
platform2.
|
|
62954
|
+
!platform2.enabled ? /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
62955
|
+
dimColor: true,
|
|
62956
|
+
children: "\u25CB"
|
|
62957
|
+
}, undefined, false, undefined, this) : platform2.reconnecting ? /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
62858
62958
|
color: "yellow",
|
|
62859
62959
|
children: "\u25CC"
|
|
62860
62960
|
}, undefined, false, undefined, this) : platform2.connected ? /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
@@ -62865,7 +62965,8 @@ function Platforms({ platforms }) {
|
|
|
62865
62965
|
children: "\u25CB"
|
|
62866
62966
|
}, undefined, false, undefined, this),
|
|
62867
62967
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
62868
|
-
color: "cyan",
|
|
62968
|
+
color: platform2.enabled ? "cyan" : undefined,
|
|
62969
|
+
dimColor: !platform2.enabled,
|
|
62869
62970
|
children: [
|
|
62870
62971
|
"@",
|
|
62871
62972
|
platform2.botName
|
|
@@ -62876,6 +62977,7 @@ function Platforms({ platforms }) {
|
|
|
62876
62977
|
children: "on"
|
|
62877
62978
|
}, undefined, false, undefined, this),
|
|
62878
62979
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
62980
|
+
dimColor: !platform2.enabled,
|
|
62879
62981
|
children: platform2.displayName
|
|
62880
62982
|
}, undefined, false, undefined, this),
|
|
62881
62983
|
platform2.reconnecting && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
@@ -65080,7 +65182,7 @@ async function main() {
|
|
|
65080
65182
|
await sessionManager?.pauseSessionsForPlatform(platformId);
|
|
65081
65183
|
client.disconnect();
|
|
65082
65184
|
sessionStore2.setPlatformEnabled(platformId, false);
|
|
65083
|
-
ui.setPlatformStatus(platformId, { connected: false });
|
|
65185
|
+
ui.setPlatformStatus(platformId, { connected: false, reconnecting: false });
|
|
65084
65186
|
ui.addLog({ level: "info", component: "toggle", message: `\u2713 Platform ${platformId} disabled` });
|
|
65085
65187
|
}
|
|
65086
65188
|
},
|
|
@@ -33837,6 +33837,100 @@ ${code}
|
|
|
33837
33837
|
}
|
|
33838
33838
|
}
|
|
33839
33839
|
|
|
33840
|
+
// src/platform/utils.ts
|
|
33841
|
+
var EMOJI_NAME_TO_UNICODE = {
|
|
33842
|
+
"+1": "\uD83D\uDC4D",
|
|
33843
|
+
"-1": "\uD83D\uDC4E",
|
|
33844
|
+
white_check_mark: "\u2705",
|
|
33845
|
+
x: "\u274C",
|
|
33846
|
+
warning: "\u26A0\uFE0F",
|
|
33847
|
+
stop: "\uD83D\uDED1",
|
|
33848
|
+
pause: "\u23F8\uFE0F",
|
|
33849
|
+
arrow_forward: "\u25B6\uFE0F",
|
|
33850
|
+
one: "1\uFE0F\u20E3",
|
|
33851
|
+
two: "2\uFE0F\u20E3",
|
|
33852
|
+
three: "3\uFE0F\u20E3",
|
|
33853
|
+
four: "4\uFE0F\u20E3",
|
|
33854
|
+
five: "5\uFE0F\u20E3",
|
|
33855
|
+
six: "6\uFE0F\u20E3",
|
|
33856
|
+
seven: "7\uFE0F\u20E3",
|
|
33857
|
+
eight: "8\uFE0F\u20E3",
|
|
33858
|
+
nine: "9\uFE0F\u20E3",
|
|
33859
|
+
keycap_ten: "\uD83D\uDD1F",
|
|
33860
|
+
zero: "0\uFE0F\u20E3",
|
|
33861
|
+
robot: "\uD83E\uDD16",
|
|
33862
|
+
gear: "\u2699\uFE0F",
|
|
33863
|
+
lock: "\uD83D\uDD10",
|
|
33864
|
+
unlock: "\uD83D\uDD13",
|
|
33865
|
+
file_folder: "\uD83D\uDCC1",
|
|
33866
|
+
page_facing_up: "\uD83D\uDCC4",
|
|
33867
|
+
memo: "\uD83D\uDCDD",
|
|
33868
|
+
clock: "\u23F1\uFE0F",
|
|
33869
|
+
hourglass: "\u23F3",
|
|
33870
|
+
seedling: "\uD83C\uDF31",
|
|
33871
|
+
evergreen_tree: "\uD83C\uDF32",
|
|
33872
|
+
deciduous_tree: "\uD83C\uDF33",
|
|
33873
|
+
thread: "\uD83E\uDDF5",
|
|
33874
|
+
arrows_counterclockwise: "\uD83D\uDD04",
|
|
33875
|
+
package: "\uD83D\uDCE6",
|
|
33876
|
+
partying_face: "\uD83C\uDF89",
|
|
33877
|
+
hourglass_flowing_sand: "\u23F3",
|
|
33878
|
+
herb: "\uD83C\uDF3F",
|
|
33879
|
+
bust_in_silhouette: "\uD83D\uDC64",
|
|
33880
|
+
clipboard: "\uD83D\uDCCB",
|
|
33881
|
+
small_red_triangle_down: "\uD83D\uDD3D",
|
|
33882
|
+
arrow_down_small: "\uD83D\uDD3D",
|
|
33883
|
+
new: "\uD83C\uDD95"
|
|
33884
|
+
};
|
|
33885
|
+
var EMOJI_UNICODE_TO_NAME = Object.fromEntries(Object.entries(EMOJI_NAME_TO_UNICODE).map(([name, unicode]) => [unicode, name]));
|
|
33886
|
+
function convertUnicodeEmojiToShortcodes(text) {
|
|
33887
|
+
let result = text;
|
|
33888
|
+
for (const [unicode, name] of Object.entries(EMOJI_UNICODE_TO_NAME)) {
|
|
33889
|
+
result = result.split(unicode).join(`:${name}:`);
|
|
33890
|
+
}
|
|
33891
|
+
return result;
|
|
33892
|
+
}
|
|
33893
|
+
function convertMarkdownToSlack(content) {
|
|
33894
|
+
const codeBlocks = [];
|
|
33895
|
+
const CODE_BLOCK_PLACEHOLDER = "\x00CODE_BLOCK_";
|
|
33896
|
+
let preserved = content.replace(/```[\s\S]*?```/g, (match) => {
|
|
33897
|
+
const index = codeBlocks.length;
|
|
33898
|
+
codeBlocks.push(match);
|
|
33899
|
+
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
33900
|
+
});
|
|
33901
|
+
preserved = preserved.replace(/`[^`\n]+`/g, (match) => {
|
|
33902
|
+
const index = codeBlocks.length;
|
|
33903
|
+
codeBlocks.push(match);
|
|
33904
|
+
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
33905
|
+
});
|
|
33906
|
+
preserved = convertMarkdownTablesToSlack(preserved);
|
|
33907
|
+
preserved = preserved.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
33908
|
+
preserved = preserved.replace(/\*\*([^*]+)\*\*/g, "*$1*");
|
|
33909
|
+
preserved = preserved.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "<$2|$1>");
|
|
33910
|
+
preserved = preserved.replace(/^[-*_]{3,}\s*$/gm, "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
33911
|
+
for (let i = 0;i < codeBlocks.length; i++) {
|
|
33912
|
+
preserved = preserved.replace(`${CODE_BLOCK_PLACEHOLDER}${i}\x00`, codeBlocks[i]);
|
|
33913
|
+
}
|
|
33914
|
+
return preserved;
|
|
33915
|
+
}
|
|
33916
|
+
function convertMarkdownTablesToSlack(content) {
|
|
33917
|
+
const tableRegex = /^\|(.+)\|\s*\n\|[-:\s|]+\|\s*\n((?:\|.+\|\s*\n?)+)/gm;
|
|
33918
|
+
return content.replace(tableRegex, (_match, headerLine, bodyLines) => {
|
|
33919
|
+
const headers = headerLine.split("|").map((h) => h.trim()).filter((h) => h);
|
|
33920
|
+
const rows = bodyLines.trim().split(`
|
|
33921
|
+
`).map((row) => row.split("|").map((c) => c.trim()).filter((c) => c !== ""));
|
|
33922
|
+
const formattedRows = rows.map((row) => {
|
|
33923
|
+
const cells = row.map((cell, i) => {
|
|
33924
|
+
const header = headers[i];
|
|
33925
|
+
return header ? `*${header}:* ${cell}` : cell;
|
|
33926
|
+
});
|
|
33927
|
+
return cells.join(" \xB7 ");
|
|
33928
|
+
});
|
|
33929
|
+
return formattedRows.join(`
|
|
33930
|
+
`);
|
|
33931
|
+
});
|
|
33932
|
+
}
|
|
33933
|
+
|
|
33840
33934
|
// src/mattermost/api.ts
|
|
33841
33935
|
var log = createLogger("mm-api");
|
|
33842
33936
|
async function mattermostApi(config2, method, path, body) {
|
|
@@ -33872,14 +33966,14 @@ async function getUser(config2, userId) {
|
|
|
33872
33966
|
async function createPost(config2, channelId, message, rootId) {
|
|
33873
33967
|
return mattermostApi(config2, "POST", "/posts", {
|
|
33874
33968
|
channel_id: channelId,
|
|
33875
|
-
message,
|
|
33969
|
+
message: convertUnicodeEmojiToShortcodes(message),
|
|
33876
33970
|
root_id: rootId
|
|
33877
33971
|
});
|
|
33878
33972
|
}
|
|
33879
33973
|
async function updatePost(config2, postId, message) {
|
|
33880
33974
|
return mattermostApi(config2, "PUT", `/posts/${postId}`, {
|
|
33881
33975
|
id: postId,
|
|
33882
|
-
message
|
|
33976
|
+
message: convertUnicodeEmojiToShortcodes(message)
|
|
33883
33977
|
});
|
|
33884
33978
|
}
|
|
33885
33979
|
async function addReaction(config2, postId, userId, emojiName) {
|
|
@@ -34037,48 +34131,6 @@ function createMattermostPermissionApi(config2) {
|
|
|
34037
34131
|
return new MattermostPermissionApi(config2);
|
|
34038
34132
|
}
|
|
34039
34133
|
|
|
34040
|
-
// src/platform/utils.ts
|
|
34041
|
-
function convertMarkdownToSlack(content) {
|
|
34042
|
-
const codeBlocks = [];
|
|
34043
|
-
const CODE_BLOCK_PLACEHOLDER = "\x00CODE_BLOCK_";
|
|
34044
|
-
let preserved = content.replace(/```[\s\S]*?```/g, (match) => {
|
|
34045
|
-
const index = codeBlocks.length;
|
|
34046
|
-
codeBlocks.push(match);
|
|
34047
|
-
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
34048
|
-
});
|
|
34049
|
-
preserved = preserved.replace(/`[^`\n]+`/g, (match) => {
|
|
34050
|
-
const index = codeBlocks.length;
|
|
34051
|
-
codeBlocks.push(match);
|
|
34052
|
-
return `${CODE_BLOCK_PLACEHOLDER}${index}\x00`;
|
|
34053
|
-
});
|
|
34054
|
-
preserved = convertMarkdownTablesToSlack(preserved);
|
|
34055
|
-
preserved = preserved.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
34056
|
-
preserved = preserved.replace(/\*\*([^*]+)\*\*/g, "*$1*");
|
|
34057
|
-
preserved = preserved.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "<$2|$1>");
|
|
34058
|
-
preserved = preserved.replace(/^[-*_]{3,}\s*$/gm, "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
34059
|
-
for (let i = 0;i < codeBlocks.length; i++) {
|
|
34060
|
-
preserved = preserved.replace(`${CODE_BLOCK_PLACEHOLDER}${i}\x00`, codeBlocks[i]);
|
|
34061
|
-
}
|
|
34062
|
-
return preserved;
|
|
34063
|
-
}
|
|
34064
|
-
function convertMarkdownTablesToSlack(content) {
|
|
34065
|
-
const tableRegex = /^\|(.+)\|\s*\n\|[-:\s|]+\|\s*\n((?:\|.+\|\s*\n?)+)/gm;
|
|
34066
|
-
return content.replace(tableRegex, (_match, headerLine, bodyLines) => {
|
|
34067
|
-
const headers = headerLine.split("|").map((h) => h.trim()).filter((h) => h);
|
|
34068
|
-
const rows = bodyLines.trim().split(`
|
|
34069
|
-
`).map((row) => row.split("|").map((c) => c.trim()).filter((c) => c !== ""));
|
|
34070
|
-
const formattedRows = rows.map((row) => {
|
|
34071
|
-
const cells = row.map((cell, i) => {
|
|
34072
|
-
const header = headers[i];
|
|
34073
|
-
return header ? `*${header}:* ${cell}` : cell;
|
|
34074
|
-
});
|
|
34075
|
-
return cells.join(" \xB7 ");
|
|
34076
|
-
});
|
|
34077
|
-
return formattedRows.join(`
|
|
34078
|
-
`);
|
|
34079
|
-
});
|
|
34080
|
-
}
|
|
34081
|
-
|
|
34082
34134
|
// src/platform/slack/formatter.ts
|
|
34083
34135
|
class SlackFormatter {
|
|
34084
34136
|
formatBold(text) {
|