claude-threads 1.18.0 → 1.18.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,11 @@ 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.18.1] - 2026-07-17
9
+
10
+ ### Changed
11
+ - **`react_to_post` resolves the triggering message server-side instead of via a per-message permalink.** v1.18.0 fixed `react_to_post` always landing on the thread root by prepending a `[message permalink: ...]` line to every follow-up message's content — correct, but paid for on every single message in every thread even though reactions are occasional. `url` is now optional: when omitted, the MCP server resolves it to the most recent message in the session's own thread via the same `readThread` call `list_thread` already uses, so no per-message metadata needs to ride along in message content at all. (Mattermost and Slack `readThread` apply `limit` differently — Mattermost takes the newest N, Slack's `conversations.replies` paginates from the thread root forward — so the resolver fetches the default page and takes the last element on both platforms rather than relying on `limit: 1`.)
12
+
8
13
  ## [1.18.0] - 2026-07-17
9
14
 
10
15
  ### Added
package/dist/index.js CHANGED
@@ -80908,10 +80908,6 @@ async function startUI(options) {
80908
80908
  init_logger();
80909
80909
 
80910
80910
  // src/message-handler.ts
80911
- function withMessagePermalink(client, post2, content) {
80912
- return `[message permalink: ${client.getPostPermalink(post2)}]
80913
- ${content}`;
80914
- }
80915
80911
  async function handleMessage(client, session, post2, user, options) {
80916
80912
  const { platformId, logger, onKill } = options;
80917
80913
  const username = user?.username || "unknown";
@@ -81008,10 +81004,8 @@ async function handleMessage(client, session, post2, user, options) {
81008
81004
  return;
81009
81005
  }
81010
81006
  const files2 = post2.metadata?.files;
81011
- if (content || files2?.length) {
81012
- const contentForAgent = content && post2.id !== threadRoot ? withMessagePermalink(client, post2, content) : content;
81013
- await session.sendFollowUp(threadRoot, contentForAgent, files2, username, user?.displayName);
81014
- }
81007
+ if (content || files2?.length)
81008
+ await session.sendFollowUp(threadRoot, content, files2, username, user?.displayName);
81015
81009
  return;
81016
81010
  }
81017
81011
  const hasPausedSession = session.registry.getPersistedByThreadId(threadRoot) !== undefined;
@@ -57637,7 +57637,7 @@ var readPostInputSchema = {
57637
57637
  max_messages: exports_external.coerce.number().int().optional().describe(`Maximum thread messages to return when include_thread is true. Defaults to ${DEFAULT_THREAD_LIMIT}, capped at ${MAX_THREAD_LIMIT}.`)
57638
57638
  };
57639
57639
  var reactToPostInputSchema = {
57640
- url: exports_external.string().describe("Permalink URL to a post the bot can already see (its own channel, or a public channel on the same instance). " + "To react to a specific user message (e.g. to acknowledge the one that triggered the current task), use the " + "per-message permalink provided in that message's context — do NOT default to the thread-root permalink."),
57640
+ url: exports_external.string().optional().describe("Permalink URL to a post the bot can already see (its own channel, or a public channel on the same instance). " + "Omit to react to the most recent message in the current session thread (e.g. to acknowledge the message " + "that triggered the current task) this is the common case and does NOT default to the thread root."),
57641
57641
  emoji: exports_external.string().describe("Emoji name without colons, e.g. 'white_check_mark', '+1', 'eyes'. Platform-specific vocabulary applies.")
57642
57642
  };
57643
57643
  var updateOwnPostInputSchema = {
@@ -57785,6 +57785,27 @@ async function handleReadPost(args) {
57785
57785
  });
57786
57786
  }
57787
57787
  var EMOJI_NAME_RE = /^[a-z0-9_+-]{1,64}$/i;
57788
+ async function resolveLatestThreadPost(cfg) {
57789
+ if (!cfg.api.readThread) {
57790
+ return { ok: false, reason: "this platform does not support reading threads" };
57791
+ }
57792
+ if (!cfg.sessionThreadId) {
57793
+ return { ok: false, reason: "no session thread to react in — pass a permalink URL instead" };
57794
+ }
57795
+ let thread;
57796
+ try {
57797
+ thread = await cfg.api.readThread(cfg.sessionThreadId);
57798
+ } catch (err) {
57799
+ const reason = err instanceof Error ? err.message : String(err);
57800
+ mcpLogger.warn(`react_to_post: failed to resolve latest thread message: ${reason}`);
57801
+ return { ok: false, reason };
57802
+ }
57803
+ const latest = thread.at(-1);
57804
+ if (!latest) {
57805
+ return { ok: false, reason: "session thread is empty — pass a permalink URL instead" };
57806
+ }
57807
+ return { ok: true, post: latest };
57808
+ }
57788
57809
  async function handleReactToPostWith(args, cfg) {
57789
57810
  if (!cfg.api.addReaction) {
57790
57811
  return { ok: false, reason: "this platform does not support adding reactions" };
@@ -57795,7 +57816,7 @@ async function handleReactToPostWith(args, cfg) {
57795
57816
  reason: `invalid emoji name '${args.emoji}' — use names like 'white_check_mark' or '+1'`
57796
57817
  };
57797
57818
  }
57798
- const resolved = await resolvePostFromUrl(args.url, cfg);
57819
+ const resolved = args.url ? await resolvePostFromUrl(args.url, cfg) : await resolveLatestThreadPost(cfg);
57799
57820
  if (!resolved.ok)
57800
57821
  return { ok: false, reason: resolved.reason };
57801
57822
  try {
@@ -57812,7 +57833,8 @@ async function handleReactToPost(args) {
57812
57833
  api: getApi(),
57813
57834
  platformUrl: PLATFORM_URL,
57814
57835
  platformType: PLATFORM_TYPE,
57815
- channelId: PLATFORM_CHANNEL_ID
57836
+ channelId: PLATFORM_CHANNEL_ID,
57837
+ sessionThreadId: PLATFORM_THREAD_ID
57816
57838
  });
57817
57839
  }
57818
57840
  async function handleUpdateOwnPostWith(args, cfg) {
@@ -58364,7 +58386,7 @@ async function main() {
58364
58386
  content: [{ type: "text", text: JSON.stringify(result) }]
58365
58387
  };
58366
58388
  });
58367
- server.tool("react_to_post", "Add an emoji reaction to a post on the chat platform. Use this to acknowledge a request " + "(✅), flag something ambiguous (\uD83D\uDC40), mark a triggering message done, etc. The post must be in " + "the bot's own channel or in a public channel on the same instance. Returns { ok: true } on " + "success or { ok: false, reason } on failure.", reactToPostInputSchema, async ({ url: url2, emoji: emoji4 }) => {
58389
+ server.tool("react_to_post", "Add an emoji reaction to a post on the chat platform. Use this to acknowledge a request " + "(✅), flag something ambiguous (\uD83D\uDC40), mark a triggering message done, etc. Omit `url` to react " + "to the most recent message in the current session thread — the common case. The post must be " + "in the bot's own channel or in a public channel on the same instance. Returns { ok: true } on " + "success or { ok: false, reason } on failure.", reactToPostInputSchema, async ({ url: url2, emoji: emoji4 }) => {
58368
58390
  const result = await handleReactToPost({ url: url2, emoji: emoji4 });
58369
58391
  return {
58370
58392
  content: [{ type: "text", text: JSON.stringify(result) }]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.18.0",
3
+ "version": "1.18.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",