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.
Files changed (3) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/index.js +165 -44
  3. 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.values(data.sessions)) {
13805
- if (session.platformId === platformId && session.cleanedAt) {
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 newTasksPost = await session.platform.createInteractivePost(oldTasksContent, [TASK_TOGGLE_EMOJIS[0]], session.threadId);
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 newPost = await session.platform.createInteractivePost(session.lastTasksContent, [TASK_TOGGLE_EMOJIS[0]], session.threadId);
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 || !statusData.current_usage)
15684
+ if (!statusData)
15564
15685
  return;
15565
15686
  if (!session.usageStats)
15566
15687
  return;
15567
- const contextTokens = statusData.current_usage.input_tokens + statusData.current_usage.cache_creation_input_tokens + statusData.current_usage.cache_read_input_tokens;
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
- session.tasksMinimized = !session.tasksMinimized;
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 cleanedAt = session.cleanedAt ? new Date(session.cleanedAt) : new Date(session.lastActivityAt);
21377
- const time = formatRelativeTime(cleanedAt);
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(` \u2713 ${threadLink} \xB7 **${displayName}**${prStr} \xB7 ${time}`);
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 historySessions = sessionStore ? sessionStore.getHistory(platformId).slice(0, 5) : [];
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 = formatRelativeTime(session.startedAt);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "0.32.0",
3
+ "version": "0.33.1",
4
4
  "description": "Share Claude Code sessions live in a Mattermost channel with interactive features",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",