claude-threads 0.32.0 β 0.33.1
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 +19 -0
- package/dist/index.js +165 -44
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.33.1] - 2026-01-04
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Recent threads timestamp** - Fixed "just now" showing incorrectly for recent threads. Now displays when the user last worked on the session (`lastActivityAt`) instead of the internal cleanup timestamp (`cleanedAt`).
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **Consolidated time formatting** - Unified duplicate `formatRelativeTime` functions into `utils/format.ts`. Added compact `formatRelativeTimeShort()` for sticky message display (e.g., "5m ago", "2h ago").
|
|
17
|
+
|
|
18
|
+
## [0.33.0] - 2026-01-03
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **Compaction status display** - Shows when Claude CLI is compacting context (ποΈ **Compacting context...**) and when it completes (β
**Context compacted**). Handles `compact_boundary` events with metadata including trigger type and pre-compaction token count.
|
|
22
|
+
- **Message recovery after reconnection** - Recovers missed messages after WebSocket disconnections (e.g., machine sleep, network issues). Tracks last processed post ID and fetches missed posts via REST API on reconnect.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **Timed-out sessions in Recent section** - Fixed bug where timed-out sessions weren't appearing in the "Recent" section of the sticky channel message. Timed-out sessions now show with βΈοΈ indicator and a hint to resume via π reaction.
|
|
26
|
+
- **Task toggle emoji behavior** - Changed from flip behavior to state-based: emoji present = expanded, emoji absent = minimized. Added `reaction_removed` event to platform layer.
|
|
27
|
+
- **Accurate context token calculation** - Fixed incorrect context token calculation by using `total_input_tokens` from the status line instead of per-request tokens.
|
|
28
|
+
|
|
10
29
|
## [0.32.0] - 2026-01-03
|
|
11
30
|
|
|
12
31
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -13310,6 +13310,8 @@ class MattermostClient extends EventEmitter {
|
|
|
13310
13310
|
lastMessageAt = Date.now();
|
|
13311
13311
|
HEARTBEAT_INTERVAL_MS = 30000;
|
|
13312
13312
|
HEARTBEAT_TIMEOUT_MS = 60000;
|
|
13313
|
+
lastProcessedPostId = null;
|
|
13314
|
+
isReconnecting = false;
|
|
13313
13315
|
constructor(platformConfig) {
|
|
13314
13316
|
super();
|
|
13315
13317
|
this.platformId = platformConfig.id;
|
|
@@ -13512,6 +13514,25 @@ class MattermostClient extends EventEmitter {
|
|
|
13512
13514
|
return [];
|
|
13513
13515
|
}
|
|
13514
13516
|
}
|
|
13517
|
+
async getChannelPostsAfter(afterPostId) {
|
|
13518
|
+
try {
|
|
13519
|
+
const response = await this.api("GET", `/channels/${this.channelId}/posts?after=${afterPostId}&per_page=100`);
|
|
13520
|
+
const posts = [];
|
|
13521
|
+
for (const postId of response.order) {
|
|
13522
|
+
const post = response.posts[postId];
|
|
13523
|
+
if (!post)
|
|
13524
|
+
continue;
|
|
13525
|
+
if (post.user_id === this.botUserId)
|
|
13526
|
+
continue;
|
|
13527
|
+
posts.push(this.normalizePlatformPost(post));
|
|
13528
|
+
}
|
|
13529
|
+
posts.sort((a, b) => (a.createAt ?? 0) - (b.createAt ?? 0));
|
|
13530
|
+
return posts;
|
|
13531
|
+
} catch (err) {
|
|
13532
|
+
log2.warn(`Failed to get channel posts after ${afterPostId}: ${err}`);
|
|
13533
|
+
return [];
|
|
13534
|
+
}
|
|
13535
|
+
}
|
|
13515
13536
|
async connect() {
|
|
13516
13537
|
await this.getBotUser();
|
|
13517
13538
|
wsLogger.debug(`Bot user ID: ${this.botUserId}`);
|
|
@@ -13538,6 +13559,12 @@ class MattermostClient extends EventEmitter {
|
|
|
13538
13559
|
this.reconnectAttempts = 0;
|
|
13539
13560
|
this.startHeartbeat();
|
|
13540
13561
|
this.emit("connected");
|
|
13562
|
+
if (this.isReconnecting && this.lastProcessedPostId) {
|
|
13563
|
+
this.recoverMissedMessages().catch((err) => {
|
|
13564
|
+
log2.warn(`Failed to recover missed messages: ${err}`);
|
|
13565
|
+
});
|
|
13566
|
+
}
|
|
13567
|
+
this.isReconnecting = false;
|
|
13541
13568
|
resolve2();
|
|
13542
13569
|
}
|
|
13543
13570
|
} catch (err) {
|
|
@@ -13568,6 +13595,7 @@ class MattermostClient extends EventEmitter {
|
|
|
13568
13595
|
return;
|
|
13569
13596
|
if (post.channel_id !== this.channelId)
|
|
13570
13597
|
return;
|
|
13598
|
+
this.lastProcessedPostId = post.id;
|
|
13571
13599
|
this.getUser(post.user_id).then((user) => {
|
|
13572
13600
|
const normalizedPost = this.normalizePlatformPost(post);
|
|
13573
13601
|
this.emit("message", normalizedPost, user);
|
|
@@ -13595,12 +13623,28 @@ class MattermostClient extends EventEmitter {
|
|
|
13595
13623
|
wsLogger.debug(`Failed to parse reaction: ${err}`);
|
|
13596
13624
|
}
|
|
13597
13625
|
}
|
|
13626
|
+
if (event.event === "reaction_removed") {
|
|
13627
|
+
const data = event.data;
|
|
13628
|
+
if (!data.reaction)
|
|
13629
|
+
return;
|
|
13630
|
+
try {
|
|
13631
|
+
const reaction = JSON.parse(data.reaction);
|
|
13632
|
+
if (reaction.user_id === this.botUserId)
|
|
13633
|
+
return;
|
|
13634
|
+
this.getUser(reaction.user_id).then((user) => {
|
|
13635
|
+
this.emit("reaction_removed", this.normalizePlatformReaction(reaction), user);
|
|
13636
|
+
});
|
|
13637
|
+
} catch (err) {
|
|
13638
|
+
wsLogger.debug(`Failed to parse reaction: ${err}`);
|
|
13639
|
+
}
|
|
13640
|
+
}
|
|
13598
13641
|
}
|
|
13599
13642
|
scheduleReconnect() {
|
|
13600
13643
|
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
13601
13644
|
log2.error("Max reconnection attempts reached");
|
|
13602
13645
|
return;
|
|
13603
13646
|
}
|
|
13647
|
+
this.isReconnecting = true;
|
|
13604
13648
|
this.reconnectAttempts++;
|
|
13605
13649
|
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
|
|
13606
13650
|
log2.info(`Reconnecting... (attempt ${this.reconnectAttempts})`);
|
|
@@ -13632,6 +13676,26 @@ class MattermostClient extends EventEmitter {
|
|
|
13632
13676
|
this.heartbeatInterval = null;
|
|
13633
13677
|
}
|
|
13634
13678
|
}
|
|
13679
|
+
async recoverMissedMessages() {
|
|
13680
|
+
if (!this.lastProcessedPostId) {
|
|
13681
|
+
return;
|
|
13682
|
+
}
|
|
13683
|
+
log2.info(`Recovering missed messages after post ${this.lastProcessedPostId}...`);
|
|
13684
|
+
const missedPosts = await this.getChannelPostsAfter(this.lastProcessedPostId);
|
|
13685
|
+
if (missedPosts.length === 0) {
|
|
13686
|
+
log2.info("No missed messages to recover");
|
|
13687
|
+
return;
|
|
13688
|
+
}
|
|
13689
|
+
log2.info(`Recovered ${missedPosts.length} missed message(s)`);
|
|
13690
|
+
for (const post of missedPosts) {
|
|
13691
|
+
this.lastProcessedPostId = post.id;
|
|
13692
|
+
const user = await this.getUser(post.userId);
|
|
13693
|
+
this.emit("message", post, user);
|
|
13694
|
+
if (!post.rootId) {
|
|
13695
|
+
this.emit("channel_post", post, user);
|
|
13696
|
+
}
|
|
13697
|
+
}
|
|
13698
|
+
}
|
|
13635
13699
|
isUserAllowed(username) {
|
|
13636
13700
|
if (this.allowedUsers.length === 0) {
|
|
13637
13701
|
return true;
|
|
@@ -13798,17 +13862,23 @@ class SessionStore {
|
|
|
13798
13862
|
}
|
|
13799
13863
|
return removedCount;
|
|
13800
13864
|
}
|
|
13801
|
-
getHistory(platformId) {
|
|
13865
|
+
getHistory(platformId, activeSessions) {
|
|
13802
13866
|
const data = this.loadRaw();
|
|
13803
13867
|
const historySessions = [];
|
|
13804
|
-
for (const session of Object.
|
|
13805
|
-
if (session.platformId
|
|
13868
|
+
for (const [sessionId, session] of Object.entries(data.sessions)) {
|
|
13869
|
+
if (session.platformId !== platformId)
|
|
13870
|
+
continue;
|
|
13871
|
+
if (session.cleanedAt) {
|
|
13872
|
+
historySessions.push(session);
|
|
13873
|
+
continue;
|
|
13874
|
+
}
|
|
13875
|
+
if (session.timeoutPostId && activeSessions && !activeSessions.has(sessionId)) {
|
|
13806
13876
|
historySessions.push(session);
|
|
13807
13877
|
}
|
|
13808
13878
|
}
|
|
13809
13879
|
return historySessions.sort((a, b) => {
|
|
13810
|
-
const aTime = new Date(a.cleanedAt).getTime();
|
|
13811
|
-
const bTime = new Date(b.cleanedAt).getTime();
|
|
13880
|
+
const aTime = new Date(a.cleanedAt || a.lastActivityAt).getTime();
|
|
13881
|
+
const bTime = new Date(b.cleanedAt || b.lastActivityAt).getTime();
|
|
13812
13882
|
return bTime - aTime;
|
|
13813
13883
|
});
|
|
13814
13884
|
}
|
|
@@ -13916,6 +13986,27 @@ function getNumberEmojiIndex(emoji) {
|
|
|
13916
13986
|
|
|
13917
13987
|
// src/session/streaming.ts
|
|
13918
13988
|
var log4 = createLogger("streaming");
|
|
13989
|
+
function getMinimizedTaskContent(fullContent) {
|
|
13990
|
+
const progressMatch = fullContent.match(/\((\d+)\/(\d+) \u00B7 (\d+)%\)/);
|
|
13991
|
+
const completed = progressMatch ? parseInt(progressMatch[1], 10) : 0;
|
|
13992
|
+
const total = progressMatch ? parseInt(progressMatch[2], 10) : 0;
|
|
13993
|
+
const pct = progressMatch ? parseInt(progressMatch[3], 10) : 0;
|
|
13994
|
+
const inProgressMatch = fullContent.match(/\uD83D\uDD04 \*\*([^*]+)\*\*(?:\s*\((\d+)s\))?/);
|
|
13995
|
+
let currentTaskText = "";
|
|
13996
|
+
if (inProgressMatch) {
|
|
13997
|
+
const taskName = inProgressMatch[1];
|
|
13998
|
+
const elapsed = inProgressMatch[2] ? ` (${inProgressMatch[2]}s)` : "";
|
|
13999
|
+
currentTaskText = ` \xB7 \uD83D\uDD04 ${taskName}${elapsed}`;
|
|
14000
|
+
}
|
|
14001
|
+
return `---
|
|
14002
|
+
\uD83D\uDCCB **Tasks** (${completed}/${total} \xB7 ${pct}%)${currentTaskText} \uD83D\uDD3D`;
|
|
14003
|
+
}
|
|
14004
|
+
function getTaskDisplayContent(session) {
|
|
14005
|
+
if (!session.lastTasksContent) {
|
|
14006
|
+
return "";
|
|
14007
|
+
}
|
|
14008
|
+
return session.tasksMinimized ? getMinimizedTaskContent(session.lastTasksContent) : session.lastTasksContent;
|
|
14009
|
+
}
|
|
13919
14010
|
var SOFT_BREAK_THRESHOLD = 2000;
|
|
13920
14011
|
var MIN_BREAK_THRESHOLD = 500;
|
|
13921
14012
|
var MAX_LINES_BEFORE_BREAK = 15;
|
|
@@ -14070,7 +14161,8 @@ async function bumpTasksToBottomWithContent(session, newContent, registerPost) {
|
|
|
14070
14161
|
await session.platform.updatePost(oldTasksPostId, newContent);
|
|
14071
14162
|
registerPost(oldTasksPostId, session.threadId);
|
|
14072
14163
|
if (oldTasksContent) {
|
|
14073
|
-
const
|
|
14164
|
+
const displayContent = getTaskDisplayContent(session);
|
|
14165
|
+
const newTasksPost = await session.platform.createInteractivePost(displayContent, [TASK_TOGGLE_EMOJIS[0]], session.threadId);
|
|
14074
14166
|
session.tasksPostId = newTasksPost.id;
|
|
14075
14167
|
registerPost(newTasksPost.id, session.threadId);
|
|
14076
14168
|
} else {
|
|
@@ -14087,7 +14179,8 @@ async function bumpTasksToBottom(session, registerPost) {
|
|
|
14087
14179
|
}
|
|
14088
14180
|
try {
|
|
14089
14181
|
await session.platform.deletePost(session.tasksPostId);
|
|
14090
|
-
const
|
|
14182
|
+
const displayContent = getTaskDisplayContent(session);
|
|
14183
|
+
const newPost = await session.platform.createInteractivePost(displayContent, [TASK_TOGGLE_EMOJIS[0]], session.threadId);
|
|
14091
14184
|
session.tasksPostId = newPost.id;
|
|
14092
14185
|
if (registerPost) {
|
|
14093
14186
|
registerPost(newPost.id, session.threadId);
|
|
@@ -15006,6 +15099,20 @@ function formatShortId(id) {
|
|
|
15006
15099
|
return id;
|
|
15007
15100
|
return `${id.substring(0, 8)}\u2026`;
|
|
15008
15101
|
}
|
|
15102
|
+
function formatRelativeTimeShort(date) {
|
|
15103
|
+
const now = Date.now();
|
|
15104
|
+
const diff = now - date.getTime();
|
|
15105
|
+
const minutes = Math.floor(diff / 60000);
|
|
15106
|
+
const hours = Math.floor(minutes / 60);
|
|
15107
|
+
const days = Math.floor(hours / 24);
|
|
15108
|
+
if (days > 0)
|
|
15109
|
+
return `${days}d ago`;
|
|
15110
|
+
if (hours > 0)
|
|
15111
|
+
return `${hours}h ago`;
|
|
15112
|
+
if (minutes > 0)
|
|
15113
|
+
return `${minutes}m ago`;
|
|
15114
|
+
return "<1m ago";
|
|
15115
|
+
}
|
|
15009
15116
|
|
|
15010
15117
|
// src/session/error-handler.ts
|
|
15011
15118
|
var log5 = createLogger("error");
|
|
@@ -15286,10 +15393,24 @@ function formatEvent(session, e, ctx) {
|
|
|
15286
15393
|
updateUsageStats(session, e, ctx);
|
|
15287
15394
|
return null;
|
|
15288
15395
|
}
|
|
15289
|
-
case "system":
|
|
15396
|
+
case "system": {
|
|
15290
15397
|
if (e.subtype === "error")
|
|
15291
15398
|
return `\u274C ${e.error}`;
|
|
15399
|
+
if (e.subtype === "status" && e.status === "compacting") {
|
|
15400
|
+
return `\uD83D\uDDDC\uFE0F **Compacting context...** *(freeing up memory)*`;
|
|
15401
|
+
}
|
|
15402
|
+
if (e.subtype === "compact_boundary") {
|
|
15403
|
+
const metadata = e.compact_metadata;
|
|
15404
|
+
const trigger = metadata?.trigger || "auto";
|
|
15405
|
+
const preTokens = metadata?.pre_tokens;
|
|
15406
|
+
let info = trigger === "manual" ? "manual" : "auto";
|
|
15407
|
+
if (preTokens && preTokens > 0) {
|
|
15408
|
+
info += `, ${Math.round(preTokens / 1000)}k tokens`;
|
|
15409
|
+
}
|
|
15410
|
+
return `\u2705 **Context compacted** *(${info})*`;
|
|
15411
|
+
}
|
|
15292
15412
|
return null;
|
|
15413
|
+
}
|
|
15293
15414
|
case "user": {
|
|
15294
15415
|
const msg = e.message;
|
|
15295
15416
|
if (typeof msg?.content === "string") {
|
|
@@ -15560,11 +15681,11 @@ function updateUsageStats(session, event, ctx) {
|
|
|
15560
15681
|
}
|
|
15561
15682
|
function updateUsageFromStatusLine(session) {
|
|
15562
15683
|
const statusData = session.claude.getStatusData();
|
|
15563
|
-
if (!statusData
|
|
15684
|
+
if (!statusData)
|
|
15564
15685
|
return;
|
|
15565
15686
|
if (!session.usageStats)
|
|
15566
15687
|
return;
|
|
15567
|
-
const contextTokens = statusData.
|
|
15688
|
+
const contextTokens = statusData.total_input_tokens || 0;
|
|
15568
15689
|
if (statusData.timestamp > session.usageStats.lastUpdated.getTime()) {
|
|
15569
15690
|
session.usageStats.contextTokens = contextTokens;
|
|
15570
15691
|
session.usageStats.contextWindowSize = statusData.context_window_size;
|
|
@@ -15671,13 +15792,17 @@ async function handleMessageApprovalReaction(session, emoji, approver, ctx) {
|
|
|
15671
15792
|
}
|
|
15672
15793
|
session.pendingMessageApproval = null;
|
|
15673
15794
|
}
|
|
15674
|
-
async function handleTaskToggleReaction(session, ctx) {
|
|
15795
|
+
async function handleTaskToggleReaction(session, action, ctx) {
|
|
15675
15796
|
if (!session.tasksPostId || !session.lastTasksContent) {
|
|
15676
15797
|
return false;
|
|
15677
15798
|
}
|
|
15678
|
-
|
|
15799
|
+
const shouldMinimize = action === "added";
|
|
15800
|
+
if (session.tasksMinimized === shouldMinimize) {
|
|
15801
|
+
return true;
|
|
15802
|
+
}
|
|
15803
|
+
session.tasksMinimized = shouldMinimize;
|
|
15679
15804
|
if (ctx.config.debug) {
|
|
15680
|
-
log7.debug(`\uD83D\uDD3D Tasks ${session.tasksMinimized ? "minimized" : "expanded"}`);
|
|
15805
|
+
log7.debug(`\uD83D\uDD3D Tasks ${session.tasksMinimized ? "minimized" : "expanded"} (user ${action} reaction)`);
|
|
15681
15806
|
}
|
|
15682
15807
|
const progressMatch = session.lastTasksContent.match(/\((\d+)\/(\d+) \u00B7 (\d+)%\)/);
|
|
15683
15808
|
const completed = progressMatch ? parseInt(progressMatch[1], 10) : 0;
|
|
@@ -21326,19 +21451,6 @@ function initialize(store) {
|
|
|
21326
21451
|
log13.info(`\uD83D\uDCCC Restored ${persistedIds.size} sticky post ID(s) from persistence`);
|
|
21327
21452
|
}
|
|
21328
21453
|
}
|
|
21329
|
-
function formatRelativeTime(date) {
|
|
21330
|
-
const now = Date.now();
|
|
21331
|
-
const diff = now - date.getTime();
|
|
21332
|
-
const minutes = Math.floor(diff / 60000);
|
|
21333
|
-
const hours = Math.floor(minutes / 60);
|
|
21334
|
-
if (minutes < 1)
|
|
21335
|
-
return "just now";
|
|
21336
|
-
if (minutes < 60)
|
|
21337
|
-
return `${minutes}m ago`;
|
|
21338
|
-
if (hours < 24)
|
|
21339
|
-
return `${hours}h ago`;
|
|
21340
|
-
return `${Math.floor(hours / 24)}d ago`;
|
|
21341
|
-
}
|
|
21342
21454
|
function getTaskProgress(session) {
|
|
21343
21455
|
if (!session.lastTasksContent)
|
|
21344
21456
|
return null;
|
|
@@ -21373,11 +21485,14 @@ function formatHistoryEntry(session) {
|
|
|
21373
21485
|
const topic = getHistorySessionTopic(session);
|
|
21374
21486
|
const threadLink = `[${topic}](/_redirect/pl/${session.threadId})`;
|
|
21375
21487
|
const displayName = session.startedByDisplayName || session.startedBy;
|
|
21376
|
-
const
|
|
21377
|
-
const
|
|
21488
|
+
const isTimedOut = !session.cleanedAt && session.timeoutPostId;
|
|
21489
|
+
const lastActivity = new Date(session.lastActivityAt);
|
|
21490
|
+
const time = formatRelativeTimeShort(lastActivity);
|
|
21378
21491
|
const prStr = session.pullRequestUrl ? ` \xB7 ${formatPullRequestLink(session.pullRequestUrl)}` : "";
|
|
21492
|
+
const indicator = isTimedOut ? "\u23F8\uFE0F" : "\u2713";
|
|
21493
|
+
const resumeHint = isTimedOut ? " \xB7 _react \uD83D\uDD04 to resume_" : "";
|
|
21379
21494
|
const lines = [];
|
|
21380
|
-
lines.push(`
|
|
21495
|
+
lines.push(` ${indicator} ${threadLink} \xB7 **${displayName}**${prStr} \xB7 ${time}${resumeHint}`);
|
|
21381
21496
|
if (session.sessionDescription) {
|
|
21382
21497
|
lines.push(` _${session.sessionDescription}_`);
|
|
21383
21498
|
}
|
|
@@ -21428,7 +21543,8 @@ function formatTopicFromPrompt(prompt) {
|
|
|
21428
21543
|
async function buildStickyMessage(sessions, platformId, config) {
|
|
21429
21544
|
const platformSessions = [...sessions.values()].filter((s) => s.platformId === platformId);
|
|
21430
21545
|
const statusBar = await buildStatusBar(platformSessions.length, config);
|
|
21431
|
-
const
|
|
21546
|
+
const activeSessionIds = new Set(sessions.keys());
|
|
21547
|
+
const historySessions = sessionStore ? sessionStore.getHistory(platformId, activeSessionIds).slice(0, 5) : [];
|
|
21432
21548
|
if (platformSessions.length === 0) {
|
|
21433
21549
|
const lines2 = [
|
|
21434
21550
|
"---",
|
|
@@ -21464,7 +21580,7 @@ async function buildStickyMessage(sessions, platformId, config) {
|
|
|
21464
21580
|
const topic = getSessionTopic(session);
|
|
21465
21581
|
const threadLink = `[${topic}](/_redirect/pl/${session.threadId})`;
|
|
21466
21582
|
const displayName = session.startedByDisplayName || session.startedBy;
|
|
21467
|
-
const time =
|
|
21583
|
+
const time = formatRelativeTimeShort(session.startedAt);
|
|
21468
21584
|
const taskProgress = getTaskProgress(session);
|
|
21469
21585
|
const progressStr = taskProgress ? ` \xB7 ${taskProgress}` : "";
|
|
21470
21586
|
const prStr = session.pullRequestUrl ? ` \xB7 ${formatPullRequestLink(session.pullRequestUrl)}` : "";
|
|
@@ -21659,7 +21775,12 @@ class SessionManager {
|
|
|
21659
21775
|
client.on("message", (post, user) => this.handleMessage(platformId, post, user));
|
|
21660
21776
|
client.on("reaction", (reaction, user) => {
|
|
21661
21777
|
if (user) {
|
|
21662
|
-
this.handleReaction(platformId, reaction.postId, reaction.emojiName, user.username);
|
|
21778
|
+
this.handleReaction(platformId, reaction.postId, reaction.emojiName, user.username, "added");
|
|
21779
|
+
}
|
|
21780
|
+
});
|
|
21781
|
+
client.on("reaction_removed", (reaction, user) => {
|
|
21782
|
+
if (user) {
|
|
21783
|
+
this.handleReaction(platformId, reaction.postId, reaction.emojiName, user.username, "removed");
|
|
21663
21784
|
}
|
|
21664
21785
|
});
|
|
21665
21786
|
client.on("channel_post", () => {
|
|
@@ -21722,8 +21843,8 @@ class SessionManager {
|
|
|
21722
21843
|
return this.findSessionByThreadId(threadId);
|
|
21723
21844
|
}
|
|
21724
21845
|
async handleMessage(_platformId, _post, _user) {}
|
|
21725
|
-
async handleReaction(platformId, postId, emojiName, username) {
|
|
21726
|
-
if (isResumeEmoji(emojiName)) {
|
|
21846
|
+
async handleReaction(platformId, postId, emojiName, username, action) {
|
|
21847
|
+
if (action === "added" && isResumeEmoji(emojiName)) {
|
|
21727
21848
|
const resumed = await this.tryResumeFromReaction(platformId, postId, username);
|
|
21728
21849
|
if (resumed)
|
|
21729
21850
|
return;
|
|
@@ -21736,7 +21857,7 @@ class SessionManager {
|
|
|
21736
21857
|
if (!session.sessionAllowedUsers.has(username) && !session.platform.isUserAllowed(username)) {
|
|
21737
21858
|
return;
|
|
21738
21859
|
}
|
|
21739
|
-
await this.handleSessionReaction(session, postId, emojiName, username);
|
|
21860
|
+
await this.handleSessionReaction(session, postId, emojiName, username, action);
|
|
21740
21861
|
}
|
|
21741
21862
|
async tryResumeFromReaction(platformId, postId, username) {
|
|
21742
21863
|
const persistedSession = this.sessionStore.findByPostId(platformId, postId);
|
|
@@ -21768,21 +21889,21 @@ class SessionManager {
|
|
|
21768
21889
|
await resumeSession(persistedSession, this.getContext());
|
|
21769
21890
|
return true;
|
|
21770
21891
|
}
|
|
21771
|
-
async handleSessionReaction(session, postId, emojiName, username) {
|
|
21772
|
-
if (session.worktreePromptPostId === postId && emojiName === "x") {
|
|
21892
|
+
async handleSessionReaction(session, postId, emojiName, username, action) {
|
|
21893
|
+
if (action === "added" && session.worktreePromptPostId === postId && emojiName === "x") {
|
|
21773
21894
|
await handleWorktreeSkip(session, username, (s) => this.persistSession(s), (s, q) => this.offerContextPrompt(s, q));
|
|
21774
21895
|
return;
|
|
21775
21896
|
}
|
|
21776
|
-
if (session.pendingExistingWorktreePrompt?.postId === postId) {
|
|
21897
|
+
if (action === "added" && session.pendingExistingWorktreePrompt?.postId === postId) {
|
|
21777
21898
|
const handled = await handleExistingWorktreeReaction(session, postId, emojiName, username, this.getContext(), (tid, branchOrPath, user) => this.switchToWorktree(tid, branchOrPath, user));
|
|
21778
21899
|
if (handled)
|
|
21779
21900
|
return;
|
|
21780
21901
|
}
|
|
21781
|
-
if (session.pendingContextPrompt?.postId === postId) {
|
|
21902
|
+
if (action === "added" && session.pendingContextPrompt?.postId === postId) {
|
|
21782
21903
|
await this.handleContextPromptReaction(session, emojiName, username);
|
|
21783
21904
|
return;
|
|
21784
21905
|
}
|
|
21785
|
-
if (session.sessionStartPostId === postId) {
|
|
21906
|
+
if (action === "added" && session.sessionStartPostId === postId) {
|
|
21786
21907
|
if (isCancelEmoji(emojiName)) {
|
|
21787
21908
|
await cancelSession(session, username, this.getContext());
|
|
21788
21909
|
return;
|
|
@@ -21792,20 +21913,20 @@ class SessionManager {
|
|
|
21792
21913
|
return;
|
|
21793
21914
|
}
|
|
21794
21915
|
}
|
|
21795
|
-
if (session.pendingQuestionSet?.currentPostId === postId) {
|
|
21916
|
+
if (action === "added" && session.pendingQuestionSet?.currentPostId === postId) {
|
|
21796
21917
|
await handleQuestionReaction(session, postId, emojiName, username, this.getContext());
|
|
21797
21918
|
return;
|
|
21798
21919
|
}
|
|
21799
|
-
if (session.pendingApproval?.postId === postId) {
|
|
21920
|
+
if (action === "added" && session.pendingApproval?.postId === postId) {
|
|
21800
21921
|
await handleApprovalReaction(session, emojiName, username, this.getContext());
|
|
21801
21922
|
return;
|
|
21802
21923
|
}
|
|
21803
|
-
if (session.pendingMessageApproval?.postId === postId) {
|
|
21924
|
+
if (action === "added" && session.pendingMessageApproval?.postId === postId) {
|
|
21804
21925
|
await handleMessageApprovalReaction(session, emojiName, username, this.getContext());
|
|
21805
21926
|
return;
|
|
21806
21927
|
}
|
|
21807
21928
|
if (session.tasksPostId === postId && isTaskToggleEmoji(emojiName)) {
|
|
21808
|
-
await handleTaskToggleReaction(session, this.getContext());
|
|
21929
|
+
await handleTaskToggleReaction(session, action, this.getContext());
|
|
21809
21930
|
return;
|
|
21810
21931
|
}
|
|
21811
21932
|
}
|