claude-threads 1.27.0 → 1.29.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 +32 -2
- package/README.md +3 -0
- package/dist/index.js +2046 -1015
- package/dist/mcp/mcp-server.js +589 -329
- package/docs/CONFIGURATION.md +109 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,16 +5,46 @@ 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.
|
|
8
|
+
## [1.29.0] - 2026-08-24
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Watches — event triggers, the proactive counterpart to routines.** `!watch when someone reports a production incident, triage it and post a checklist` creates a watch in natural language: one haiku pass extracts the matching condition, the task, and a set of prefilter keywords (synonyms and both languages for non-English requests), the bot shows all three, and **nothing is saved until someone reacts 👍**. When a matching message appears in the channel, the bot starts a full Claude session **in the triggering message's own thread**, running as the watch's creator with the thread's recent messages auto-included as context.
|
|
12
|
+
- **Two-stage matching keeps chatty channels free:** a zero-cost local keyword prefilter screens every message; only prefilter hits get one haiku call that semantically confirms the match. A keyword hit alone never fires, and a failed confirmation never fires (fail-closed).
|
|
13
|
+
- **Managing:** `!watches` lists numbered with condition/creator/last-fire; `!watches pause|resume|delete <n>` (owner-gated). No manual run — watches are event-driven.
|
|
14
|
+
- **Guardrails:** per-watch cooldown (`limits.watchCooldownMinutes`, default 5) and daily fire cap (`limits.watchDailyCap`, default 20); per-platform cap (`limits.maxWatches`, default 10); at most one watch fires per message; 3 consecutive failed fires auto-disable with a notice; a deauthorized creator disables the watch; session threads and bot posts can never re-trigger (loop prevention); fires count against `MAX_SESSIONS`. Per-platform `watches: false` disables the feature; storage at `~/.config/claude-threads/watches.yaml` (0600, per-platform scoped like memory; override `CLAUDE_THREADS_WATCHES_PATH`).
|
|
15
|
+
- **Platform note:** on Mattermost, other bots' messages (CI alerts, webhooks) can trigger watches; Slack's event filtering means only human messages trigger there.
|
|
16
|
+
- Shared-infrastructure cleanup along the way: the per-platform YAML list store machinery behind routines and watches is now one `PlatformListStore` base (with a shared add/fire-outcome/manage-command core), the strict-JSON extraction all haiku one-shots use lives in one shared helper, and the channel-memory store now uses the shared mutex/atomic-write primitives.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **DM auto-discovery instances now honor the parent platform's `memory`, `routines`, and `watches` settings.** Derived DM instances previously fell back to the fully-enabled defaults — a parent with `memory: false` (privacy) still got end-of-session distillation persisted from private DM conversations.
|
|
20
|
+
- **Routines and watches refuse creation in direct-channel-mode channels.** A fired session there would be keyed on a thread that no typed message can reach (`!stop` and follow-ups route to the channel session). Existing DCM routines stay listable/pausable/deletable and their write-only runs keep working.
|
|
21
|
+
- **Slack thread history now follows cursor pagination.** Threads longer than one API page (1000 messages) previously returned the oldest page's tail as "recent context" for context prompts, work summaries, and memory distillation.
|
|
22
|
+
- **Reconfiguring a platform via the wizard no longer drops settings the prompts don't ask about** (`memory`, `routines`, `watches`, `skipPermissions`, `auditLog`, `ackReaction`, and any future field) — the edit now merges over the existing entry instead of replacing it.
|
|
23
|
+
- **Store hardening:** a failed write can no longer leave a phantom item in the in-memory cache; writes refuse to proceed over an existing-but-unreadable store file instead of destroying it; store reads hand out copies, never live cache references; hand-edited watch keywords are normalized to lowercase (uppercase keywords could never match).
|
|
24
|
+
- **Watch confirm hardening:** the haiku confirm quotes every message line so a spoofed end-delimiter cannot smuggle instructions out of the data block; the confirm budget covers slow hosts (20s) and failures log at warn instead of debug.
|
|
25
|
+
|
|
26
|
+
## [1.28.0] - 2026-08-21
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- **Audit trail (`auditLog`)** - Opt-in per platform: an append-only JSONL stream per platform (`~/.claude-threads/audit/`, files `0600` enforced even on pre-existing artifacts, symlink-refusing writer, never deleted by the bot) recording what the bot did — every tool call Claude issued incl. `server_tool_use` and subagent sidechains (with Bash command line / file path / pattern as detail), session lifecycle incl. failure paths with the triggering user, security-relevant `!commands` (`!kill` and paused-session `!stop` included), routine creation, worktree/plugin mutations, and plan approvals with decider. Built for SIEM file ingestion; rotation/retention is the operator's call. Tool-permission allow/deny decisions stay out of scope (they resolve inside the MCP permission server subprocess; the issued request is still recorded).
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- **`ackReaction` accepts a literal Unicode emoji on both platforms.** `ackReaction: "👀"` used to work on Slack but silently no-op on Mattermost (its reaction API needs the shortcode name). Literal emoji are now normalized to their shortcode at config time; anything that is not a plain shortcode name after mapping (unmapped emoji, flags, keycaps, ZWJ sequences) warns and disables the feature instead of never reacting. Follow-up to #487.
|
|
9
33
|
|
|
10
34
|
### Changed
|
|
11
|
-
-
|
|
35
|
+
- Documented that messages accepted through the message-approval flow (an authorized user approving a non-participant's message) intentionally get no read receipt — the approval reaction is already the visible signal. Also adds the missing red-verified no-ack test for the follow-up path's session-membership gate.
|
|
36
|
+
|
|
37
|
+
## [1.27.0] - 2026-08-20
|
|
12
38
|
|
|
13
39
|
### Added
|
|
40
|
+
- **Read-receipt reaction (`ackReaction`)** - Opt-in per platform: the bot reacts to every message it accepts for processing (session start, follow-up, resume) the moment it is accepted — before any Claude output. `true` uses 👀, a string names a custom emoji. Unlike the transient typing indicator the reaction is persistent and survives reconnects, so users in busy channels (and messages queued behind an in-flight session start) get an immediate, lasting "your message landed" signal.
|
|
14
41
|
- **Direct channel mode (DCM)** - Opt-in per platform via `directChannelMode: true`: the whole configured channel behaves as one session. Messages reach the bot without an `@mention`, and the bot replies with top-level channel posts instead of thread replies, so the channel reads like a plain conversation (#315). Internally the session is keyed by a synthetic thread id (`dcm:<platform id>`) that the platform clients resolve to a channel-root post, which keeps persistence, resume, reaction-based permission prompts, and `!commands` working unchanged. Messages posted inside any thread of the channel route to the same session; the thread-context prompt is skipped (there is no thread history behind the synthetic id). Default off — thread-per-session behavior is unchanged. The long form configures shared-channel behavior: `respondTo: all_messages | mention` (does the bot react to everything or only to @mentions; backed by the per-session quiet-mode flag so `!mentions` toggles it live). On Mattermost, a DM is just a private channel, so pointing a DCM platform entry at a DM channel id covers bot direct messages with no extra feature (#315); Slack is excluded — Socket Mode distributes envelopes across an app's connections, so a second entry on the same credentials could swallow the first one's events.
|
|
15
42
|
- **Platform-level `approvals` option** - `owner | all_users` controls who may answer tool-permission prompts and the other reaction gates (plan approvals, question answers, resume): the session participants (starter + `!invite`d), or everyone on the platform's `allowedUsers` list. Unset keeps the historical default per mode — `all_users` for thread sessions (unchanged upstream behavior), `owner` for direct channel mode — so the option is purely opt-in for existing setups; `approvals: owner` on a thread channel is an opt-in hardening.
|
|
16
43
|
- **DM auto-discovery (Mattermost)** - `directMessages: true` on a platform entry lets anyone on its `allowedUsers` start a bot DM "out of the cold": the first message spawns a derived direct-channel-mode instance for that DM channel (sticky hidden, scoped to the DM partner incl. tool-permission approvals), and persisted DM sessions are reconstructed after a restart. Mattermost only — Slack's Socket Mode envelope distribution makes per-DM connections unsafe there.
|
|
17
44
|
|
|
45
|
+
### Changed
|
|
46
|
+
- **Unit-test infrastructure hardening.** `handler.test.ts` no longer probes the real environment (git child processes, battery readouts are mocked, with a correct pre-mock value-snapshot restore — Bun module namespaces are live bindings, so restoring the namespace would restore the mocks; the same hazard is fixed in the plugin suite's `crossSpawn` restore). The per-test budget on all unit-test entry points is raised to 15s: the 5s default was routinely blown by event-loop contention when several processes compete for the machine, killing millisecond-fast tests at exactly the budget.
|
|
47
|
+
|
|
18
48
|
### Fixed
|
|
19
49
|
- **Permission prompts show the full Bash command.** The approval prompt used to hard-truncate commands at 100 characters, so anything past the first pipe or `&&` was invisible at the exact moment the user was asked to approve it — the gate could only be rubber-stamped. The prompt now shows the command up to a generous 1500-character cap (a pathological command is still cut so it cannot blow up the prompt post). The 50-character display truncation in the streaming view is unchanged; only the permission prompt is affected.
|
|
20
50
|
- **Resuming a legacy persisted session no longer drops the owner from `sessionAllowedUsers`.** (#483) A session persisted before the collaboration list existed restored as an empty set, silently removing the owner from their own session — the one restore site without the defensive `[startedBy]` fallback its siblings already had.
|
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
- **Git worktrees** - `!worktree feature/foo` isolates Claude's changes on a branch
|
|
56
56
|
- **Memory** - Channels learn over time: `!remember` saves shared team notes every session sees, sessions distill durable facts when they end, and Claude's native auto-memory keeps per-repo project knowledge — all scoped per channel ([docs](https://github.com/anneschuth/claude-threads/blob/main/docs/CONFIGURATION.md#memory-memory-default-fully-enabled))
|
|
57
57
|
- **Routines** - `!routine every weekday at 9am, summarize open threads` schedules recurring work; runs post as new threads in the channel, confirmed before saving and managed with `!routines` ([docs](https://github.com/anneschuth/claude-threads/blob/main/docs/CONFIGURATION.md#routines-routines-default-enabled))
|
|
58
|
+
- **Watches** - `!watch when someone reports an incident, triage it` reacts to matching channel messages: a free keyword prefilter plus a semantic check fire a session right in the triggering thread ([docs](https://github.com/anneschuth/claude-threads/blob/main/docs/CONFIGURATION.md#watches-watches-default-enabled))
|
|
58
59
|
- **Files both ways** - Drop any file into the chat for Claude to read, with full multimodal for images and PDFs; Claude posts screenshots, plots, or PDFs back with `send_file` (100 MB cap)
|
|
59
60
|
- **Quiet mode and verbosity dials** - `!mentions on` makes a session respond only when mentioned; session headers and the channel sticky each have `full`/`minimal`/`hidden` modes
|
|
60
61
|
- **Runs on macOS, Linux, and Windows** - Windows via Git Bash or WSL
|
|
@@ -126,6 +127,8 @@ Type `!help` in any session thread:
|
|
|
126
127
|
| `!memory` | Show channel memory (`forget <n\|text>` removes entries) |
|
|
127
128
|
| `!routine <schedule, task>` | Schedule a recurring routine in natural language (confirmed with 👍) |
|
|
128
129
|
| `!routines` | List routines (`pause\|resume\|delete\|run <n>` to manage) |
|
|
130
|
+
| `!watch <when ..., task>` | Create an event trigger in natural language (confirmed with 👍) |
|
|
131
|
+
| `!watches` | List event triggers (`pause\|resume\|delete <n>` to manage) |
|
|
129
132
|
| `!update` | Show auto-update status (`!update now` / `!update defer`) |
|
|
130
133
|
| `!bug <desc>` | Report a bug with context (creates a GitHub issue) |
|
|
131
134
|
| `!approve` | Approve pending plan (alternative to 👍; also `!yes`) |
|