claude-threads 1.14.0 → 1.15.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
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.15.0] - 2026-05-05
11
+
12
+ ### Added
13
+ - **Claude can DM channel members directly via the new `send_dm` MCP tool.** When the user asks for a private ping ("DM me when this finishes," "send the report to alice as a DM"), Claude can now call `send_dm(recipient, message)` instead of asking the user to forward the result themselves. The recipient is a Mattermost username (`@anne` or `anne`) or a Slack user id (`U…`/`<@U…>`) — the asymmetry exists because Slack bot tokens can't reverse-look usernames cheaply, and paginating `users.list` per call is wasteful. Six gates run in order: shape (recipient and message non-empty, message under 4000-char cap), recipient resolution (platform API turns the input into a user id + canonical username), self-DM guard, channel membership (recipient must be a current member of the bot channel, fetched once and cached for 60s), rate limit (3 DMs per recipient per session, optimistic counter increment with rollback on deny / timeout / send-error), and a per-recipient interactive permission prompt the first time the session DMs each user. ✅ promotes that recipient — and only that recipient — to no-prompt for the rest of the session; the rate limit still applies. An in-flight set blocks parallel `send_dm` calls to the same recipient from posting duplicate prompts when Claude fans out tool_use blocks in a single turn. Every DM is prefixed with an attribution line — `_(automated message via claude-threads, on behalf of @anne from #channel)_` — so recipients can trace it back to the session that sent it; the channel name is fetched lazily via the platform's channel-info endpoint, the session-owner username is plumbed in from `session.startedBy` through a new `SESSION_OWNER_USERNAME` env var that threads `lifecycle.ts` → `restart-options.ts` → `ClaudeCliOptions` → `buildPermissionArgs` → MCP child (covers all five `new ClaudeCli` sites). New optional `McpPlatformApi` methods `getChannelMembers`, `resolveRecipient`, `sendDirectMessage`; `getChannelInfo` gained a `name?` field. RED-GREEN tests on every load-bearing guard — self-DM check, membership, rate limit, attribution prefix, allow-all-is-per-recipient, counter rollback on deny / timeout, in-flight-prompt deduplication. (#374)
14
+
15
+ ## [1.14.1] - 2026-05-05
16
+
17
+ ### Fixed
18
+ - **`!update` no longer leaves an interactive bot dead.** The auto-restart path silently broke for users running in a terminal. PR #333 (April) skipped the bash daemon when stdout was a TTY, because the daemon's bash background-job pattern strips the TTY and forces headless mode, but the bot's `!update` flow assumed the daemon was always there to catch exit code 42 and re-exec. Without the daemon, `process.exit(42)` just exited. Install succeeded, sessions persisted, then nothing came back. The fix introduces a `decideRespawn()` step before the exit. When a known supervisor is present (`CLAUDE_THREADS_BIN` from the bash daemon, `pm_id` + `PM2_HOME` from pm2, `INVOCATION_ID` from systemd, `CLAUDE_THREADS_INTERACTIVE` from a TTY-managing wrapper) the bot still exits 42 and lets the supervisor handle the restart so its restart-counters and rate-limits keep working. Otherwise, when there is a TTY, the bot self-respawns. It synchronously resolves `claude-threads` on PATH (with a fallback to `~/.bun/bin` because cron / systemd / launchd `PATH=` is often missing it), then `spawn(binPath, argv, { detached: true, stdio: 'inherit', shell: process.platform === 'win32' })` followed by `unref()` and `exit(0)`. The Node docs cover this combination explicitly: when stdio is inherited, the detached child stays attached to the parent's controlling terminal, so the new process inherits the TUI cleanly. Several footguns are handled. `spawn()` does not throw on ENOENT, it returns a child with `pid === undefined` and fires the `error` event asynchronously, so we check `pid` synchronously instead of trusting a try/catch that never triggers. Bun passes `env: { X: undefined }` as the literal string `"undefined"` (Node correctly omits it), so the auto-restart hand-off vars are removed via `delete` rather than overwrite. Windows `.cmd` shims need `shell: true` since Node 20.12.2 (CVE-2024-27980). Ink's raw mode is reset before the spawn so the new child starts with a clean stdin. If self-respawn cannot launch (no `claude-threads` on PATH at all), the bot broadcasts a clear "could not auto-restart, please run `claude-threads`" message before exiting, so the user is not left wondering what happened. Four prior PRs (#287, #300, #317, #333) chased this in the daemon path. This one fixes the bot side instead. (#372)
19
+
10
20
  ## [1.14.0] - 2026-05-05
11
21
 
12
22
  ### Changed
package/README.md CHANGED
@@ -20,20 +20,21 @@
20
20
 
21
21
  **Bring Claude Code to your team.** Run Claude Code on your machine, share it live in Mattermost or Slack. Colleagues can watch, collaborate, and run their own sessions—all from chat.
22
22
 
23
- > *Think of it as screen-sharing for AI pair programming, but everyone can type.*
23
+ > _Think of it as screen-sharing for AI pair programming, but everyone can type._
24
24
 
25
25
  ## Features
26
26
 
27
27
  - **Real-time streaming** - Claude's responses stream live to chat
28
- - **Multi-platform** - Connect to multiple Mattermost and Slack workspaces
29
- - **Concurrent sessions** - Each thread gets its own Claude session
30
- - **Session persistence** - Sessions survive bot restarts
31
- - **Collaboration** - Invite others to participate in your session
28
+ - **Multi-platform** - Connect to multiple Mattermost and Slack workspaces simultaneously
29
+ - **Concurrent sessions** - Each thread gets its own Claude session, persisted across bot restarts
30
+ - **Collaboration** - `!invite` teammates to participate; they get added as `Co-Authored-By:` trailers on Claude's commits
32
31
  - **Permission modes** - Three-way control over Claude's tool-use: `default` (every action prompts for 👍/✅/👎 approval via emoji), `auto` (Claude's classifier auto-approves low-risk; high-risk still prompts — recommended), or `bypass` (no prompts, all tools allowed). Set via config, `--permission-mode` CLI flag, or in-session with `!permissions default|auto|bypass`.
33
- - **Git worktrees** - Isolate changes in separate branches
34
- - **File attachments** - Attach images, PDFs, and files for Claude to analyze
35
- - **Chrome automation** - Control Chrome browser for web tasks
32
+ - **Claude posts back to chat** - Claude can call `send_file` to drop screenshots, generated PDFs, plots, or audio directly into the thread, and `read_post` to follow a Mattermost or Slack permalink the user shares
33
+ - **Git worktrees** - Isolate Claude's changes in a branch with `!worktree feature/foo`; supports `list`, `switch`, `remove`, `cleanup`, `off`
34
+ - **File attachments** - Drop images, PDFs, archives, or any file into the chat; Claude reads them from disk via its own `Read`/Bash tools (100 MB cap)
35
+ - **Chrome automation** - Optional integration with Claude in Chrome for web tasks
36
36
  - **Multi-account Claude (opt-in)** - Round-robin sessions across multiple Claude subscriptions or API keys with automatic rate-limit cooldown — see [Configuration](docs/CONFIGURATION.md#claude-accounts-optional-multi-account-mode)
37
+ - **Auto-update** - Bot checks npm for new versions and offers to restart; `!update now` / `!update defer` controls the timing
37
38
 
38
39
  ## Quick Start
39
40
 
@@ -50,6 +51,7 @@ claude-threads
50
51
  ```
51
52
 
52
53
  The **interactive setup wizard** will guide you through everything:
54
+
53
55
  - Configure Claude Code CLI (if needed)
54
56
  - Set up your Mattermost or Slack bot
55
57
  - Test credentials and permissions
@@ -74,46 +76,49 @@ Mention the bot in your chat:
74
76
 
75
77
  Type `!help` in any session thread:
76
78
 
77
- | Command | Description |
78
- |:--------|:------------|
79
- | `!help` | Show available commands |
80
- | `!context` | Show context usage |
81
- | `!cost` | Show token usage and cost |
82
- | `!compact` | Compress context to free up space |
83
- | `!cd <path>` | Change working directory |
84
- | `!worktree <branch>` | Create and switch to a git worktree |
85
- | `!invite @user` | Invite a user to this session |
86
- | `!kick @user` | Remove an invited user |
87
- | `!bug <desc>` | Report a bug with context |
88
- | `!escape` | Interrupt current task |
89
- | `!stop` | Stop this session |
79
+ | Command | Description |
80
+ | :------------------------------------------ | :--------------------------------------------------------------------------------------- |
81
+ | `!help` | Show available commands |
82
+ | `!release-notes` | Show what changed in the running version |
83
+ | `!context` | Show context usage |
84
+ | `!cost` | Show token usage and cost |
85
+ | `!compact` | Compress context to free up space |
86
+ | `!cd <path>` | Change working directory (restarts Claude) |
87
+ | `!permissions <mode>` | Set permission mode: `default` / `auto` / `bypass` |
88
+ | `!worktree <branch>` | Create and switch to a git worktree (also: `list`, `switch`, `remove`, `cleanup`, `off`) |
89
+ | `!plugin <list\|install\|uninstall> [name]` | Manage Claude Code plugins (restarts Claude) |
90
+ | `!invite @user` | Invite a user to this session (added as `Co-Authored-By:` on commits) |
91
+ | `!kick @user` | Remove an invited user |
92
+ | `!github-email <email>` | Register your GitHub noreply email so `!invite` can attribute commits to you |
93
+ | `!update` | Show auto-update status (`!update now` / `!update defer`) |
94
+ | `!bug <desc>` | Report a bug with context (creates a GitHub issue) |
95
+ | `!approve` | Approve pending plan (alternative to 👍 reaction) |
96
+ | `!escape` | Interrupt current task (session stays active) |
97
+ | `!stop` | Stop this session |
98
+ | `!kill` | Emergency shutdown (kills ALL sessions and exits the bot) |
90
99
 
91
100
  ## Interactive Controls
92
101
 
93
102
  **Permission approval** - When Claude wants to execute a tool:
103
+
94
104
  - 👍 Allow this action
95
105
  - ✅ Allow all future actions
96
106
  - 👎 Deny
97
107
 
98
108
  **Plan approval** - When Claude creates a plan:
109
+
99
110
  - 👍 Approve and start
100
111
  - 👎 Request changes
101
112
 
102
113
  **Questions** - React with 1️⃣ 2️⃣ 3️⃣ 4️⃣ to answer multiple choice
103
114
 
104
- **Cancel session** - Type `!stop` or react with
115
+ **Session control** - ⏸️ to interrupt, ❌ or 🛑 to stop, ↩️ to resume a timed-out session
105
116
 
106
117
  ## File Attachments
107
118
 
108
- Attach files to your messages for Claude to analyze:
119
+ Drop any file into the chat (image, PDF, archive, source, log, you name it). The bot saves it to a per-thread directory and prepends the path to your message; Claude reads it with its own `Read` tool (full multimodal for images and PDFs) or processes it via Bash. Single 100 MB cap per file. Need to extract a zip? Claude runs `unzip` itself.
109
120
 
110
- | Type | Formats | Max Size |
111
- |:-----|:--------|:---------|
112
- | Images | JPEG, PNG, GIF, WebP | - |
113
- | Documents | PDF | 32 MB |
114
- | Text | .txt, .md, .json, .csv, .xml, .yaml, source code | 1 MB |
115
- | Archives | .zip (auto-extracted, max 20 files) | 50 MB |
116
- | Compressed | .gz (auto-decompressed) | - |
121
+ Going the other way, Claude can post files back into the thread (screenshots, generated PDFs, plots, MP3s) by calling the `send_file` MCP tool. Path is validated against the session working directory; auto-approved so the user doesn't have to 👍 every screenshot.
117
122
 
118
123
  ## Collaboration
119
124
 
@@ -122,7 +127,13 @@ Attach files to your messages for Claude to analyze:
122
127
  !kick @colleague # Remove access
123
128
  ```
124
129
 
125
- Unauthorized users can request message approval from the session owner.
130
+ Unauthorized users can request message approval from the session owner with a 👍 reaction.
131
+
132
+ Invited collaborators are added as `Co-Authored-By:` trailers on any commits Claude makes during the session. Each collaborator runs `!github-email <their-noreply-address>` once (find yours at <https://github.com/settings/emails>) and the bot remembers it across sessions.
133
+
134
+ ## Sharing Links With Claude
135
+
136
+ Paste a Mattermost or Slack permalink in the thread and Claude can resolve it to the post body (and optional thread context) via the `read_post` MCP tool, instead of asking you to copy-paste. Auto-approved; scoped to channels the bot can already see.
126
137
 
127
138
  ## Git Worktrees
128
139