claude-threads 1.22.1 → 1.23.0

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,16 @@ 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.23.0] - 2026-08-08
9
+
10
+ ### Fixed
11
+ - **A failed compaction no longer leaves a stale "🗜️ Compacting context..." post forever.** Captured against the real CLI (2.1.226, `real-cli-captures/compact-failed.jsonl`): a failed compact emits **no** `compact_boundary` — only a `status` event with `compact_result: "failed"` and a `compact_error` — so the in-progress post was never resolved. It now updates to "⚠️ Compaction failed (reason)". Long-lived bot threads auto-compact in production, so this state was reachable by simply keeping a session busy.
12
+
13
+ ### Added
14
+ - **Compaction completion shows real token counts.** The completion post now renders `pre → post` ("Context compacted (manual, 31k → 3k tokens)") using the `post_tokens` field verified in a new reference capture (`real-cli-captures/compact.jsonl`, recorded via a manual `/compact` driven through stream-json).
15
+ - **`auth_status` events are handled.** An auth error from the CLI mid-session (expired OAuth, revoked key) now posts a warning to the thread instead of vanishing; progress-only auth updates are logged. Shape taken from the Agent SDK's published types (`SDKAuthStatusMessage`, `@anthropic-ai/claude-agent-sdk` 0.3.226) — deliberately not capture-backed, since provoking a real auth failure requires a broken environment.
16
+ - **The mock's `persistent-session` scenario now carries the telemetry noise real streams have** (`thinking_tokens`, `post_turn_summary`, `active_goal`), pinning deliberately that the bot tolerates unconsumed event types — previously that tolerance was only proven incidentally. New `compaction`/`compaction-failed` scenarios and an integration suite cover the compaction lifecycle end to end on both platforms.
17
+
8
18
  ## [1.22.1] - 2026-08-08
9
19
 
10
20
  ### Fixed
package/dist/index.js CHANGED
@@ -68848,10 +68848,25 @@ function handleEventPreProcessing(session, event, ctx) {
68848
68848
  if (e.subtype === "status" && e.status === "compacting") {
68849
68849
  handleCompactionStart(session, ctx);
68850
68850
  }
68851
+ if (e.subtype === "status" && e.compact_result === "failed") {
68852
+ handleCompactionFailed(session, e.compact_error, ctx);
68853
+ }
68851
68854
  if (e.subtype === "compact_boundary") {
68852
68855
  handleCompactionComplete(session, e.compact_metadata, ctx);
68853
68856
  }
68854
68857
  }
68858
+ if (event.type === "auth_status") {
68859
+ const e = event;
68860
+ if (e.error) {
68861
+ sessionLog3(session).warn(`\uD83D\uDD10 Claude CLI auth error: ${e.error}`);
68862
+ if (session.lastAuthErrorPosted !== e.error) {
68863
+ session.lastAuthErrorPosted = e.error;
68864
+ withErrorHandling(() => post(session, "warning", `\uD83D\uDD10 Claude CLI authentication problem: ${e.error}`), { action: "Post auth status warning", session });
68865
+ }
68866
+ } else {
68867
+ sessionLog3(session).info(`\uD83D\uDD10 Claude CLI auth status: authenticating=${e.isAuthenticating ?? false}${e.output?.length ? ` (${e.output[e.output.length - 1]})` : ""}`);
68868
+ }
68869
+ }
68855
68870
  if (event.type === "assistant" && !isSidechainEvent(event)) {
68856
68871
  const msg = event.message;
68857
68872
  if (Array.isArray(msg?.content)) {
@@ -68908,21 +68923,46 @@ function handleEventPostProcessing(session, event, ctx) {
68908
68923
  }
68909
68924
  }
68910
68925
  }
68911
- async function handleCompactionStart(session, _ctx) {
68912
- await session.messageManager?.closeCurrentPost();
68926
+ function handleCompactionStart(session, _ctx) {
68927
+ session.compactionPostPromise = (async () => {
68928
+ await session.messageManager?.closeCurrentPost();
68929
+ const formatter = session.platform.getFormatter();
68930
+ const message = `\uD83D\uDDDC️ ${formatter.formatBold("Compacting context...")} ${formatter.formatItalic("(freeing up memory)")}`;
68931
+ const compactionPost = await withErrorHandling(() => post(session, "info", message), { action: "Post compaction start", session });
68932
+ if (compactionPost) {
68933
+ session.compactionPostId = compactionPost.id;
68934
+ }
68935
+ })();
68936
+ }
68937
+ async function awaitCompactionStartPost(session) {
68938
+ if (session.compactionPostPromise) {
68939
+ await session.compactionPostPromise.catch(() => {});
68940
+ session.compactionPostPromise = undefined;
68941
+ }
68942
+ }
68943
+ async function handleCompactionFailed(session, compactError, _ctx) {
68944
+ await awaitCompactionStartPost(session);
68913
68945
  const formatter = session.platform.getFormatter();
68914
- const message = `\uD83D\uDDDC️ ${formatter.formatBold("Compacting context...")} ${formatter.formatItalic("(freeing up memory)")}`;
68915
- const compactionPost = await withErrorHandling(() => post(session, "info", message), { action: "Post compaction start", session });
68916
- if (compactionPost) {
68917
- session.compactionPostId = compactionPost.id;
68946
+ const reason = compactError || "unknown error";
68947
+ const message = `⚠️ ${formatter.formatBold("Compaction failed")} ${formatter.formatItalic(`(${reason})`)}`;
68948
+ const startPostId = session.compactionPostId;
68949
+ if (startPostId) {
68950
+ await withErrorHandling(() => updatePost(session, startPostId, message), { action: "Update compaction post (failed)", session });
68951
+ session.compactionPostId = undefined;
68952
+ } else {
68953
+ await withErrorHandling(() => post(session, "info", message), { action: "Post compaction failure", session });
68918
68954
  }
68919
68955
  }
68920
68956
  async function handleCompactionComplete(session, compactMetadata, _ctx) {
68957
+ await awaitCompactionStartPost(session);
68921
68958
  const metadata = compactMetadata;
68922
68959
  const trigger = metadata?.trigger || "auto";
68923
68960
  const preTokens = metadata?.pre_tokens;
68961
+ const postTokens = metadata?.post_tokens;
68924
68962
  let info = trigger === "manual" ? "manual" : "auto";
68925
- if (preTokens && preTokens > 0) {
68963
+ if (preTokens && preTokens > 0 && postTokens && postTokens > 0) {
68964
+ info += `, ${Math.round(preTokens / 1000)}k → ${Math.max(1, Math.round(postTokens / 1000))}k tokens`;
68965
+ } else if (preTokens && preTokens > 0) {
68926
68966
  info += `, ${Math.round(preTokens / 1000)}k tokens`;
68927
68967
  }
68928
68968
  const formatter = session.platform.getFormatter();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.22.1",
3
+ "version": "1.23.0",
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",