claude-threads 1.23.0 → 1.24.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
@@ -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.24.1] - 2026-08-08
9
+
10
+ ### Fixed
11
+ - **Task lists no longer degrade to "Task #N" placeholders after a bot restart.** Modern CLIs stream tasks incrementally (`TaskCreate`/`TaskUpdate` with ids), and the bot accumulates them in a per-session `TaskTracker` — but that tracker lived only in memory. After a restart + resume, the first `TaskUpdate` of the next turn hit an empty tracker and rendered a placeholder ("Task #1") instead of the real subject, losing every task name for the rest of the session. The tracker's resolved tasks (id → subject/status) are now persisted to `sessions.json` at each turn end and restored on resume. In-flight creates (id not yet resolved from result text) are deliberately dropped at serialize time; pre-1.24.1 persisted sessions simply start with an empty tracker as before. Covered by a red-green integration test that restarts the bot mid-task-list and asserts the post-resume re-render still shows real subjects on both platform paths.
12
+
13
+ ## [1.24.0] - 2026-08-08
14
+
15
+ ### Added
16
+ - **`!model` and `!effort` — switch model or reasoning effort mid-session.** Verified against the real CLI (2.1.226): `/model` and `/effort` work over stream-json (`/model` with no args lists the options; `/model sonnet` switches "for this session only"; `/effort low|medium|high|xhigh|max|auto`), and both are listed in the CLI's `init.slash_commands` — so the bot's dynamic slash-command passthrough forwards `!model sonnet` / `!effort high` as-is and the CLI's confirmation posts to the thread. Both are now first-class registered commands with unconditional forwarding handlers (like `!context`/`!cost`/`!compact` — they work even before the CLI's init event arrives, and forward their argument: `!model sonnet` → `/model sonnet`), and `!help` gained a line pointing out that Claude Code slash commands work with `!`.
17
+ - **The session header now shows the model the session actually runs on.** Previously the header picked the "primary model" by highest cumulative cost — after a `!model` switch the old model keeps the larger spend, so the header kept naming the old model indefinitely. The per-turn `init.model` (re-emitted every turn, per the reference captures) is now authoritative. Model display names also cover the Claude 5 family via generic id parsing (`claude-sonnet-5` → "Sonnet 5", `claude-fable-5` → "Fable 5", dated ids still render as before).
18
+
19
+ ### Changed
20
+ - **Latest verified Claude CLI: 2.1.226** (from 2.1.223). The full verification battery ran against it this cycle: the decision-bridge e2e (4/4), all 17 reference captures re-recorded on 2.1.225/2.1.226, and both integration matrices. Install hints updated. Also verified while probing: `/cd` and `/add-dir` report "isn't available in this environment" over stream-json on 2.1.226 — a native in-session directory switch isn't possible, so `!cd` keeps its restart-based implementation.
21
+
8
22
  ## [1.23.0] - 2026-08-08
9
23
 
10
24
  ### Fixed
package/dist/index.js CHANGED
@@ -51319,7 +51319,7 @@ var COMMON_CLAUDE_PATHS = process.platform === "win32" ? [
51319
51319
  var CLAUDE_CLI_MIN_VERSION = "2.0.74";
51320
51320
  var CLAUDE_CLI_VERIFIED_RANGE = ">=2.0.74 <2.2.0";
51321
51321
  var CLAUDE_CLI_SUPPORTED_MAJOR = 2;
51322
- var CLAUDE_CLI_LATEST_VERIFIED = "2.1.223";
51322
+ var CLAUDE_CLI_LATEST_VERIFIED = "2.1.226";
51323
51323
  function tryClaudeVersion(claudePath) {
51324
51324
  try {
51325
51325
  const output = execSync(`"${claudePath}" --version`, {
@@ -56301,16 +56301,23 @@ class ClaudeCli extends EventEmitter2 {
56301
56301
  const trimmed = line.trim();
56302
56302
  if (!trimmed)
56303
56303
  continue;
56304
+ let event;
56305
+ try {
56306
+ event = JSON.parse(trimmed);
56307
+ } catch {
56308
+ continue;
56309
+ }
56304
56310
  try {
56305
- const event = JSON.parse(trimmed);
56306
56311
  this.emit("event", event);
56307
- if (event.type === "result" && isErrorResultEvent(event)) {
56308
- this.maybeEmitRateLimit(trimmed);
56309
- }
56310
- if (event.type === "rate_limit_event") {
56311
- this.maybeEmitRateLimitHit(parseRateLimitEvent(event));
56312
- }
56313
- } catch {}
56312
+ } catch (err) {
56313
+ this.log.error(`'event' listener threw while handling a ${event.type} event: ${err}`);
56314
+ }
56315
+ if (event.type === "result" && isErrorResultEvent(event)) {
56316
+ this.maybeEmitRateLimit(trimmed);
56317
+ }
56318
+ if (event.type === "rate_limit_event") {
56319
+ this.maybeEmitRateLimitHit(parseRateLimitEvent(event));
56320
+ }
56314
56321
  }
56315
56322
  }
56316
56323
  maybeEmitRateLimit(text) {
@@ -57560,6 +57567,18 @@ var COMMAND_REGISTRY = [
57560
57567
  description: "Compact conversation",
57561
57568
  category: "passthrough",
57562
57569
  audience: "both"
57570
+ },
57571
+ {
57572
+ command: "model",
57573
+ description: "Show or switch the model for this session (e.g. !model sonnet)",
57574
+ category: "passthrough",
57575
+ audience: "both"
57576
+ },
57577
+ {
57578
+ command: "effort",
57579
+ description: "Set reasoning effort: low|medium|high|xhigh|max|auto (e.g. !effort high)",
57580
+ category: "passthrough",
57581
+ audience: "both"
57563
57582
  }
57564
57583
  ];
57565
57584
  var REACTION_REGISTRY = [
@@ -57617,6 +57636,8 @@ var COMMAND_PATTERNS = [
57617
57636
  ["context", /^!context\s*$/i],
57618
57637
  ["cost", /^!cost\s*$/i],
57619
57638
  ["compact", /^!compact\s*$/i],
57639
+ ["model", /^!model(?:\s+(\S+))?\s*$/i],
57640
+ ["effort", /^!effort(?:\s+(\S+))?\s*$/i],
57620
57641
  ["plugin", /^!plugin(?:\s+(.+))?$/i],
57621
57642
  ["kill", /^!kill\s*$/i],
57622
57643
  ["bug", /^!bug(?:\s+(.+))?$/i],
@@ -57741,6 +57762,8 @@ ${formatter.formatBold("Reactions:")}
57741
57762
  ` + `${formatter.formatListItem(approvalReactions)}
57742
57763
  ` + `${formatter.formatListItem(sessionReactions)}
57743
57764
 
57765
+ ` + `Claude Code slash commands work with ${code("!")} too — e.g. ${code("!model sonnet")}, ${code("!effort high")}, ${code("!compact")}, ${code("!context")}.
57766
+
57744
57767
  ` + formatSponsorFooter(formatter);
57745
57768
  }
57746
57769
 
@@ -58122,12 +58145,13 @@ var handlePlugin = async (ctx, args) => {
58122
58145
  return { handled: true };
58123
58146
  };
58124
58147
  function createPassthroughHandler(slashCommand) {
58125
- return async (ctx) => {
58148
+ return async (ctx, args) => {
58126
58149
  if (ctx.commandContext === "first-message") {
58127
58150
  return { handled: false };
58128
58151
  }
58129
58152
  if (ctx.isAllowed) {
58130
- await ctx.sessionManager.sendFollowUp(ctx.threadId, `/${slashCommand}`, undefined, undefined, undefined, { system: true });
58153
+ const full = args ? `/${slashCommand} ${args}` : `/${slashCommand}`;
58154
+ await ctx.sessionManager.sendFollowUp(ctx.threadId, full, undefined, undefined, undefined, { system: true });
58131
58155
  }
58132
58156
  return { handled: true };
58133
58157
  };
@@ -58150,6 +58174,8 @@ handlers.set("plugin", handlePlugin);
58150
58174
  handlers.set("context", createPassthroughHandler("context"));
58151
58175
  handlers.set("cost", createPassthroughHandler("cost"));
58152
58176
  handlers.set("compact", createPassthroughHandler("compact"));
58177
+ handlers.set("model", createPassthroughHandler("model"));
58178
+ handlers.set("effort", createPassthroughHandler("effort"));
58153
58179
  async function executeCommand(command, args, ctx) {
58154
58180
  const cmdDef = getCommandDef(command);
58155
58181
  if (!cmdDef) {
@@ -65021,6 +65047,7 @@ function truncateAtWord2(text, maxLength) {
65021
65047
  return truncated + "...";
65022
65048
  }
65023
65049
  // src/operations/task-tracker.ts
65050
+ var VALID_STATUSES = new Set(["pending", "in_progress", "completed"]);
65024
65051
  var CREATED_RESULT_RE = /Task #(\S+) created/;
65025
65052
 
65026
65053
  class TaskTracker {
@@ -65114,6 +65141,38 @@ class TaskTracker {
65114
65141
  this.pendingCreates.clear();
65115
65142
  this.unmatchedCreateResults = 0;
65116
65143
  }
65144
+ serialize() {
65145
+ const restorable = this.tasks.filter((t) => Boolean(t.taskId));
65146
+ if (restorable.length === 0)
65147
+ return;
65148
+ return restorable.map((t) => {
65149
+ const out = {
65150
+ taskId: t.taskId,
65151
+ subject: t.subject,
65152
+ status: t.status
65153
+ };
65154
+ if (t.activeForm)
65155
+ out.activeForm = t.activeForm;
65156
+ if (t.isPlaceholder)
65157
+ out.isPlaceholder = true;
65158
+ return out;
65159
+ });
65160
+ }
65161
+ restore(state) {
65162
+ if (!Array.isArray(state)) {
65163
+ this.tasks = [];
65164
+ this.pendingCreates.clear();
65165
+ return;
65166
+ }
65167
+ this.tasks = state.filter((t) => t !== null && typeof t === "object" && typeof t.taskId === "string" && t.taskId.length > 0 && typeof t.subject === "string").map((t) => ({
65168
+ taskId: t.taskId,
65169
+ subject: t.subject || `Task #${t.taskId}`,
65170
+ activeForm: typeof t.activeForm === "string" ? t.activeForm : undefined,
65171
+ status: VALID_STATUSES.has(t.status) ? t.status : "pending",
65172
+ isPlaceholder: t.isPlaceholder === true ? true : undefined
65173
+ }));
65174
+ this.pendingCreates.clear();
65175
+ }
65117
65176
  }
65118
65177
 
65119
65178
  // src/operations/executors/base.ts
@@ -67208,9 +67267,15 @@ class MessageManager {
67208
67267
  serialize() {
67209
67268
  return {
67210
67269
  taskList: this.taskListExecutor.serialize(),
67270
+ taskTracker: this.taskTracker.serialize(),
67211
67271
  contextPrompt: this.promptExecutor.serialize()
67212
67272
  };
67213
67273
  }
67274
+ restoreTaskTracker(state) {
67275
+ if (state && state.length > 0) {
67276
+ this.taskTracker.restore(state);
67277
+ }
67278
+ }
67214
67279
  hydrateTaskListState(persisted) {
67215
67280
  this.taskListExecutor.hydrateState(persisted);
67216
67281
  }
@@ -68841,6 +68906,9 @@ function handleEventPreProcessing(session, event, ctx) {
68841
68906
  }
68842
68907
  if (event.type === "system") {
68843
68908
  const e = event;
68909
+ if (e.subtype === "init" && typeof e.model === "string") {
68910
+ session.currentModel = e.model;
68911
+ }
68844
68912
  if (e.subtype === "init" && e.slash_commands && Array.isArray(e.slash_commands)) {
68845
68913
  session.availableSlashCommands = new Set(e.slash_commands.map((cmd) => cmd.startsWith("/") ? cmd.slice(1) : cmd));
68846
68914
  sessionLog3(session).info(`Captured ${session.availableSlashCommands.size} slash commands from init: ${[...session.availableSlashCommands].join(", ")}`);
@@ -68882,7 +68950,7 @@ function handleEventPreProcessing(session, event, ctx) {
68882
68950
  trackEvent(session, "tool_use", tool.name);
68883
68951
  }
68884
68952
  }
68885
- function handleEventPostProcessing(session, event, ctx) {
68953
+ function handleEventPostProcessing(session, event, ctx, mainHandling) {
68886
68954
  if (event.type === "assistant") {
68887
68955
  const msg = event.message;
68888
68956
  for (const block of msg?.content || []) {
@@ -68899,6 +68967,11 @@ function handleEventPostProcessing(session, event, ctx) {
68899
68967
  session.isProcessing = false;
68900
68968
  ctx.ops.emitSessionUpdate(session.sessionId, { status: getSessionStatus(session) });
68901
68969
  updateUsageStats(session, event, ctx);
68970
+ if (mainHandling) {
68971
+ mainHandling.catch(() => {}).then(() => ctx.ops.persistSession(session));
68972
+ } else {
68973
+ ctx.ops.persistSession(session);
68974
+ }
68902
68975
  }
68903
68976
  if (event.type === "user" && !isSidechainEvent(event)) {
68904
68977
  const msg = event.message;
@@ -68975,20 +69048,15 @@ async function handleCompactionComplete(session, compactMetadata, _ctx) {
68975
69048
  }
68976
69049
  }
68977
69050
  function getModelDisplayName(modelId) {
68978
- if (modelId.includes("opus-4-5") || modelId.includes("opus-4.5"))
68979
- return "Opus 4.5";
68980
- if (modelId.includes("opus-4"))
68981
- return "Opus 4";
68982
- if (modelId.includes("opus"))
68983
- return "Opus";
68984
- if (modelId.includes("sonnet-4"))
68985
- return "Sonnet 4";
68986
- if (modelId.includes("sonnet-3-5") || modelId.includes("sonnet-3.5"))
68987
- return "Sonnet 3.5";
69051
+ const modern = modelId.match(/^claude-([a-z]+)-(\d+)(?:-(\d{1,2}))?(?:-\d{8})?$/);
69052
+ if (modern) {
69053
+ const family = modern[1].charAt(0).toUpperCase() + modern[1].slice(1);
69054
+ return modern[3] ? `${family} ${modern[2]}.${modern[3]}` : `${family} ${modern[2]}`;
69055
+ }
68988
69056
  if (modelId.includes("sonnet"))
68989
69057
  return "Sonnet";
68990
- if (modelId.includes("haiku-4-5") || modelId.includes("haiku-4.5"))
68991
- return "Haiku 4.5";
69058
+ if (modelId.includes("opus"))
69059
+ return "Opus";
68992
69060
  if (modelId.includes("haiku"))
68993
69061
  return "Haiku";
68994
69062
  const match = modelId.match(/claude-(\w+)/);
@@ -69019,6 +69087,10 @@ function updateUsageStats(session, event, ctx) {
69019
69087
  contextWindowSize = usage.contextWindow;
69020
69088
  }
69021
69089
  }
69090
+ if (session.currentModel && result.modelUsage[session.currentModel]) {
69091
+ primaryModel = session.currentModel;
69092
+ contextWindowSize = result.modelUsage[session.currentModel].contextWindow;
69093
+ }
69022
69094
  let contextTokens = 0;
69023
69095
  if (result.usage) {
69024
69096
  contextTokens = result.usage.input_tokens + result.usage.cache_creation_input_tokens + result.usage.cache_read_input_tokens;
@@ -70856,6 +70928,7 @@ Please start a new session.`), { action: "Post resume failure notification" });
70856
70928
  tasksCompleted: state.tasksCompleted,
70857
70929
  tasksMinimized: state.tasksMinimized
70858
70930
  });
70931
+ session.messageManager.restoreTaskTracker(state.taskTrackerState);
70859
70932
  const persistedWithInteractive = state;
70860
70933
  if (persistedWithInteractive.pendingQuestionSet || persistedWithInteractive.pendingApproval) {
70861
70934
  session.messageManager.hydrateInteractiveState({
@@ -71806,8 +71879,8 @@ class SessionManager extends EventEmitter4 {
71806
71879
  if (!session || !session.messageManager)
71807
71880
  return;
71808
71881
  handleEventPreProcessing(session, event, this.getContext());
71809
- session.messageManager.handleEvent(event);
71810
- handleEventPostProcessing(session, event, this.getContext());
71882
+ const mainHandling = session.messageManager.handleEvent(event);
71883
+ handleEventPostProcessing(session, event, this.getContext(), mainHandling);
71811
71884
  }
71812
71885
  async handleExit(sessionId, code, source) {
71813
71886
  await handleExit(sessionId, code, this.getContext(), source);
@@ -71845,11 +71918,20 @@ class SessionManager extends EventEmitter4 {
71845
71918
  this.stopTyping(session);
71846
71919
  }
71847
71920
  persistSession(session) {
71921
+ try {
71922
+ this.persistSessionUnsafe(session);
71923
+ } catch (err) {
71924
+ log35.error(`Failed to persist session ${session.sessionId}: ${err}`);
71925
+ }
71926
+ }
71927
+ persistSessionUnsafe(session) {
71848
71928
  let taskListSnapshot;
71849
71929
  let contextPromptSnapshot;
71930
+ let taskTrackerSnapshot;
71850
71931
  if (session.messageManager) {
71851
71932
  const serialized = session.messageManager.serialize();
71852
71933
  taskListSnapshot = serialized.taskList;
71934
+ taskTrackerSnapshot = serialized.taskTracker;
71853
71935
  if (serialized.contextPrompt) {
71854
71936
  contextPromptSnapshot = serialized.contextPrompt;
71855
71937
  }
@@ -71874,6 +71956,7 @@ class SessionManager extends EventEmitter4 {
71874
71956
  lastTasksContent: taskListSnapshot?.content ?? null,
71875
71957
  tasksCompleted: taskListSnapshot?.isCompleted ?? false,
71876
71958
  tasksMinimized: taskListSnapshot?.isMinimized ?? false,
71959
+ taskTrackerState: taskTrackerSnapshot,
71877
71960
  worktreeInfo: session.worktreeInfo,
71878
71961
  isWorktreeOwner: session.isWorktreeOwner,
71879
71962
  pendingWorktreePrompt: session.pendingWorktreePrompt,
@@ -49412,6 +49412,7 @@ function truncateAtWord(text, maxLength) {
49412
49412
  return truncated + "...";
49413
49413
  }
49414
49414
  // src/operations/task-tracker.ts
49415
+ var VALID_STATUSES = new Set(["pending", "in_progress", "completed"]);
49415
49416
  var CREATED_RESULT_RE = /Task #(\S+) created/;
49416
49417
 
49417
49418
  class TaskTracker {
@@ -49505,6 +49506,38 @@ class TaskTracker {
49505
49506
  this.pendingCreates.clear();
49506
49507
  this.unmatchedCreateResults = 0;
49507
49508
  }
49509
+ serialize() {
49510
+ const restorable = this.tasks.filter((t) => Boolean(t.taskId));
49511
+ if (restorable.length === 0)
49512
+ return;
49513
+ return restorable.map((t) => {
49514
+ const out = {
49515
+ taskId: t.taskId,
49516
+ subject: t.subject,
49517
+ status: t.status
49518
+ };
49519
+ if (t.activeForm)
49520
+ out.activeForm = t.activeForm;
49521
+ if (t.isPlaceholder)
49522
+ out.isPlaceholder = true;
49523
+ return out;
49524
+ });
49525
+ }
49526
+ restore(state) {
49527
+ if (!Array.isArray(state)) {
49528
+ this.tasks = [];
49529
+ this.pendingCreates.clear();
49530
+ return;
49531
+ }
49532
+ this.tasks = state.filter((t) => t !== null && typeof t === "object" && typeof t.taskId === "string" && t.taskId.length > 0 && typeof t.subject === "string").map((t) => ({
49533
+ taskId: t.taskId,
49534
+ subject: t.subject || `Task #${t.taskId}`,
49535
+ activeForm: typeof t.activeForm === "string" ? t.activeForm : undefined,
49536
+ status: VALID_STATUSES.has(t.status) ? t.status : "pending",
49537
+ isPlaceholder: t.isPlaceholder === true ? true : undefined
49538
+ }));
49539
+ this.pendingCreates.clear();
49540
+ }
49508
49541
  }
49509
49542
 
49510
49543
  // src/operations/executors/base.ts
@@ -51908,9 +51941,15 @@ class MessageManager {
51908
51941
  serialize() {
51909
51942
  return {
51910
51943
  taskList: this.taskListExecutor.serialize(),
51944
+ taskTracker: this.taskTracker.serialize(),
51911
51945
  contextPrompt: this.promptExecutor.serialize()
51912
51946
  };
51913
51947
  }
51948
+ restoreTaskTracker(state) {
51949
+ if (state && state.length > 0) {
51950
+ this.taskTracker.restore(state);
51951
+ }
51952
+ }
51914
51953
  hydrateTaskListState(persisted) {
51915
51954
  this.taskListExecutor.hydrateState(persisted);
51916
51955
  }
@@ -56409,16 +56448,23 @@ class ClaudeCli extends EventEmitter2 {
56409
56448
  const trimmed = line.trim();
56410
56449
  if (!trimmed)
56411
56450
  continue;
56451
+ let event;
56452
+ try {
56453
+ event = JSON.parse(trimmed);
56454
+ } catch {
56455
+ continue;
56456
+ }
56412
56457
  try {
56413
- const event = JSON.parse(trimmed);
56414
56458
  this.emit("event", event);
56415
- if (event.type === "result" && isErrorResultEvent(event)) {
56416
- this.maybeEmitRateLimit(trimmed);
56417
- }
56418
- if (event.type === "rate_limit_event") {
56419
- this.maybeEmitRateLimitHit(parseRateLimitEvent(event));
56420
- }
56421
- } catch {}
56459
+ } catch (err) {
56460
+ this.log.error(`'event' listener threw while handling a ${event.type} event: ${err}`);
56461
+ }
56462
+ if (event.type === "result" && isErrorResultEvent(event)) {
56463
+ this.maybeEmitRateLimit(trimmed);
56464
+ }
56465
+ if (event.type === "rate_limit_event") {
56466
+ this.maybeEmitRateLimitHit(parseRateLimitEvent(event));
56467
+ }
56422
56468
  }
56423
56469
  }
56424
56470
  maybeEmitRateLimit(text) {
@@ -56734,6 +56780,18 @@ var COMMAND_REGISTRY = [
56734
56780
  description: "Compact conversation",
56735
56781
  category: "passthrough",
56736
56782
  audience: "both"
56783
+ },
56784
+ {
56785
+ command: "model",
56786
+ description: "Show or switch the model for this session (e.g. !model sonnet)",
56787
+ category: "passthrough",
56788
+ audience: "both"
56789
+ },
56790
+ {
56791
+ command: "effort",
56792
+ description: "Set reasoning effort: low|medium|high|xhigh|max|auto (e.g. !effort high)",
56793
+ category: "passthrough",
56794
+ audience: "both"
56737
56795
  }
56738
56796
  ];
56739
56797
  var REACTION_REGISTRY = [
@@ -56806,6 +56864,8 @@ ${formatter.formatBold("Reactions:")}
56806
56864
  ` + `${formatter.formatListItem(approvalReactions)}
56807
56865
  ` + `${formatter.formatListItem(sessionReactions)}
56808
56866
 
56867
+ ` + `Claude Code slash commands work with ${code("!")} too — e.g. ${code("!model sonnet")}, ${code("!effort high")}, ${code("!compact")}, ${code("!context")}.
56868
+
56809
56869
  ` + formatSponsorFooter(formatter);
56810
56870
  }
56811
56871
 
@@ -57072,12 +57132,13 @@ var handlePlugin = async (ctx, args) => {
57072
57132
  return { handled: true };
57073
57133
  };
57074
57134
  function createPassthroughHandler(slashCommand) {
57075
- return async (ctx) => {
57135
+ return async (ctx, args) => {
57076
57136
  if (ctx.commandContext === "first-message") {
57077
57137
  return { handled: false };
57078
57138
  }
57079
57139
  if (ctx.isAllowed) {
57080
- await ctx.sessionManager.sendFollowUp(ctx.threadId, `/${slashCommand}`, undefined, undefined, undefined, { system: true });
57140
+ const full = args ? `/${slashCommand} ${args}` : `/${slashCommand}`;
57141
+ await ctx.sessionManager.sendFollowUp(ctx.threadId, full, undefined, undefined, undefined, { system: true });
57081
57142
  }
57082
57143
  return { handled: true };
57083
57144
  };
@@ -57100,6 +57161,8 @@ handlers.set("plugin", handlePlugin);
57100
57161
  handlers.set("context", createPassthroughHandler("context"));
57101
57162
  handlers.set("cost", createPassthroughHandler("cost"));
57102
57163
  handlers.set("compact", createPassthroughHandler("compact"));
57164
+ handlers.set("model", createPassthroughHandler("model"));
57165
+ handlers.set("effort", createPassthroughHandler("effort"));
57103
57166
  // src/commands/system-prompt-generator.ts
57104
57167
  var log9 = createLogger("system-prompt");
57105
57168
  function formatUserCommand(cmd) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.23.0",
3
+ "version": "1.24.1",
4
4
  "description": "Run Claude Code from Slack or Mattermost. Sessions stream live into threads where your whole team can watch and steer.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",