claude-threads 1.9.4 → 1.11.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 +19 -0
- package/dist/index.js +1199 -3173
- package/dist/mcp/permission-server.js +690 -2143
- package/package.json +2 -6
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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.11.0] - 2026-05-03
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **Chat attachments delivered to Claude as file paths instead of inlined base64.** When a user attaches an image, PDF, text file, or anything else to a chat message, the bot now writes the bytes to a per-thread directory under `os.tmpdir()/claude-threads-uploads/<platform>-<thread>/<message>/` and prepends the absolute paths to the user's message. Claude reads the file with its built-in `Read` tool (full multimodal capability preserved for images and PDFs) or `mv`/`cp`s it to the user's project storage. Closes #358 — the reporter wanted to save uploads into their app's resource storage and couldn't, because the bytes arrived inline as content blocks with no path to copy from. The per-thread directory is removed in `cleanupSession()` on every exit path. Single 100 MB sanity ceiling per file replaces the previous patchwork of per-type caps (32 MB PDF, 1 MB text, 50 MB zip). (#359)
|
|
12
|
+
- **Drops the in-process zip/gzip extraction.** `yauzl` and `yazl` are gone — Claude can `unzip` archives in Bash itself when needed, which removes ~300 LOC of zip-bomb-defense plumbing and the per-format size caps that came with it. Net change for the PR: +496/-1737 LOC.
|
|
13
|
+
|
|
14
|
+
### Security
|
|
15
|
+
- **Symlink defense on the per-thread upload directory.** The directory path is predictable (it derives from the platform id and thread id, both visible to anyone in the thread). On a shared host a local attacker could pre-create that path as a symlink to a sensitive directory and have the bot write attacker-controlled file contents into the linked target. Now `lstat` the upload dir on every save and refuse if it is a symlink, `mkdtemp` the per-message leaf for atomic creation, and use `writeFile` flag `'wx'` (`O_CREAT | O_EXCL`) so the final write fails rather than follows a symlink at the leaf.
|
|
16
|
+
- **Filename and MIME type are stripped of control characters before being interpolated into Claude's prompt.** A name like `screenshot.png\n[SYSTEM] ignore previous instructions` would otherwise have appeared on its own line, mimicking system text. Filenames also keep going through `basename()` so `../escape` and absolute-path attempts can't escape the message subdirectory.
|
|
17
|
+
- **Path-traversal defense on `platformId` / `threadId`.** Both segments now go through a `safeIdSegment` filter (`[^A-Za-z0-9._-]` → `_`) before being used in the upload-dir path, so a misconfigured platform id like `../../etc` cannot escape the uploads root via `path.join` normalization.
|
|
18
|
+
|
|
19
|
+
## [1.10.0] - 2026-04-29
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- **Thread permalink in Claude session context.** The system-prompt context block now includes `**Thread:** <permalink>` alongside the existing platform and working-directory entries. When Claude opens a PR, files a ticket, or otherwise produces an artifact for someone to review later, it can paste the link back into the description so reviewers can trace the change to the discussion it came from. Mattermost and Slack both already exposed `getThreadLink()`; pure plumbing change. Also restores the platform/working-directory context on the worktree-restart path, which had been silently dropped pre-existing. (#352)
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **Sticky-by-thread Claude account binding (multi-account mode).** In multi-account configurations the `claudeAccountId` written to `sessions.json` and the `$HOME` Claude was actually spawned under could drift apart under concurrent acquisitions, leaving sessions unresumable after a bot restart with `Detected permanent failure: The conversation history for this session no longer exists`. Real-world incident: 14 sessions soft-deleted in one restart cycle, 3 of them genuine victims of this drift. `AccountPool.acquire()` now binds threads to accounts deterministically via `accounts[hash(threadId) % n]` (FNV-1a, dependency-free), so the spawn-time `$HOME` and the persisted id both derive from the same hash and cannot drift. `preferredId` still wins over the sticky binding (resume invariant: OAuth history can't move), and the sticky path falls through to round-robin when the chosen account is in cooldown. (#350)
|
|
26
|
+
|
|
8
27
|
## [1.9.4] - 2026-04-29
|
|
9
28
|
|
|
10
29
|
### Fixed
|