claude-threads 0.17.0 → 0.17.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 CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.17.1] - 2025-12-31
11
+
12
+ ### Fixed
13
+ - **Sticky task list optimization**: Completed task lists no longer move to the bottom
14
+ - Once all tasks are done, the "~~Tasks~~ *(completed)*" message stays in place
15
+ - Reduces unnecessary message deletions and recreations
16
+ - Added `tasksCompleted` flag to session state for explicit tracking
17
+
18
+ ### Changed
19
+ - **Task list visual separator**: Added horizontal rule (`---`) above task list for better visibility
20
+
10
21
  ## [0.17.0] - 2025-12-31
11
22
 
12
23
  ### Added
package/dist/index.js CHANGED
@@ -13823,6 +13823,9 @@ async function bumpTasksToBottom(session) {
13823
13823
  if (!session.tasksPostId || !session.lastTasksContent) {
13824
13824
  return;
13825
13825
  }
13826
+ if (session.tasksCompleted) {
13827
+ return;
13828
+ }
13826
13829
  try {
13827
13830
  await session.platform.deletePost(session.tasksPostId);
13828
13831
  const newPost = await session.platform.createPost(session.lastTasksContent, session.threadId);
@@ -13853,7 +13856,8 @@ async function flush(session, registerPost) {
13853
13856
  session.currentPostId = null;
13854
13857
  session.pendingContent = remainder;
13855
13858
  if (remainder) {
13856
- if (session.tasksPostId && session.lastTasksContent) {
13859
+ const hasActiveTasks = session.tasksPostId && session.lastTasksContent && !session.tasksCompleted;
13860
+ if (hasActiveTasks) {
13857
13861
  const postId = await bumpTasksToBottomWithContent(session, `*(continued)*
13858
13862
 
13859
13863
  ` + remainder, registerPost);
@@ -13876,7 +13880,8 @@ async function flush(session, registerPost) {
13876
13880
  if (session.currentPostId) {
13877
13881
  await session.platform.updatePost(session.currentPostId, content);
13878
13882
  } else {
13879
- if (session.tasksPostId && session.lastTasksContent) {
13883
+ const hasActiveTasks = session.tasksPostId && session.lastTasksContent && !session.tasksCompleted;
13884
+ if (hasActiveTasks) {
13880
13885
  const postId = await bumpTasksToBottomWithContent(session, content, registerPost);
13881
13886
  session.currentPostId = postId;
13882
13887
  } else {
@@ -14843,9 +14848,11 @@ async function handleExitPlanMode(session, toolUseId, ctx) {
14843
14848
  async function handleTodoWrite(session, input) {
14844
14849
  const todos = input.todos;
14845
14850
  if (!todos || todos.length === 0) {
14851
+ session.tasksCompleted = true;
14846
14852
  if (session.tasksPostId) {
14847
14853
  try {
14848
- const completedMsg = "\uD83D\uDCCB ~~Tasks~~ *(completed)*";
14854
+ const completedMsg = `---
14855
+ \uD83D\uDCCB ~~Tasks~~ *(completed)*`;
14849
14856
  await session.platform.updatePost(session.tasksPostId, completedMsg);
14850
14857
  session.lastTasksContent = completedMsg;
14851
14858
  } catch (err) {
@@ -14854,6 +14861,7 @@ async function handleTodoWrite(session, input) {
14854
14861
  }
14855
14862
  return;
14856
14863
  }
14864
+ session.tasksCompleted = false;
14857
14865
  const completed = todos.filter((t) => t.status === "completed").length;
14858
14866
  const total = todos.length;
14859
14867
  const pct = Math.round(completed / total * 100);
@@ -14863,7 +14871,8 @@ async function handleTodoWrite(session, input) {
14863
14871
  } else if (!hasInProgress) {
14864
14872
  session.inProgressTaskStart = null;
14865
14873
  }
14866
- let message = `\uD83D\uDCCB **Tasks** (${completed}/${total} \xB7 ${pct}%)
14874
+ let message = `---
14875
+ \uD83D\uDCCB **Tasks** (${completed}/${total} \xB7 ${pct}%)
14867
14876
 
14868
14877
  `;
14869
14878
  for (const todo of todos) {
@@ -19041,6 +19050,7 @@ async function startSession(options, username, replyToPostId, platformId, ctx) {
19041
19050
  sessionStartPostId: post.id,
19042
19051
  tasksPostId: null,
19043
19052
  lastTasksContent: null,
19053
+ tasksCompleted: false,
19044
19054
  activeSubagents: new Map,
19045
19055
  updateTimer: null,
19046
19056
  typingTimer: null,
@@ -19153,6 +19163,7 @@ Please start a new session.`, state.threadId);
19153
19163
  sessionStartPostId: state.sessionStartPostId,
19154
19164
  tasksPostId: state.tasksPostId,
19155
19165
  lastTasksContent: state.lastTasksContent ?? null,
19166
+ tasksCompleted: state.tasksCompleted ?? false,
19156
19167
  activeSubagents: new Map,
19157
19168
  updateTimer: null,
19158
19169
  typingTimer: null,
@@ -20178,6 +20189,7 @@ class SessionManager {
20178
20189
  sessionStartPostId: session.sessionStartPostId,
20179
20190
  tasksPostId: session.tasksPostId,
20180
20191
  lastTasksContent: session.lastTasksContent,
20192
+ tasksCompleted: session.tasksCompleted,
20181
20193
  worktreeInfo: session.worktreeInfo,
20182
20194
  pendingWorktreePrompt: session.pendingWorktreePrompt,
20183
20195
  worktreePromptDisabled: session.worktreePromptDisabled,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "0.17.0",
3
+ "version": "0.17.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",