claude-threads 1.36.1 → 1.37.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 +13 -0
- package/bin/claude-threads-daemon +8 -0
- package/dist/index.js +302 -73
- package/dist/mcp/mcp-server.js +93 -86
- package/docs/CONFIGURATION.md +27 -0
- package/docs/systemd/claude-threads.service +3 -0
- package/docs/turn-marker-spec.md +149 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.37.0] - 2026-09-11
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Per-platform `lifecycle` visibility** (#505, thanks @kaza). Session status posts — the idle warning, the timeout notice, the pause notice, the resume notice and the shutdown notice a deploy leaves in every open thread — are the bulk of what a quiet channel contains when the bot is used as an assistant rather than a task runner. `lifecycle: minimal` drops the idle warning, which predicts a timeout the next message would undo anyway; `hidden` drops the status posts entirely. Defaults to `full`, so nothing changes unless you set it. Editing a post the thread already has is never suppressed: it adds no post and no notification, and leaving a stale "session idle" up across a restart would read worse than the edit. An abnormal exit survives every level, because a session that died must not look like one that finished. At `hidden` there is no post for a 🔄 reaction to resume from, so the channel sticky tells the reader to send a message instead.
|
|
14
|
+
- **Per-platform `turnMarker`: the daemon says when a turn is over** (#528, thanks @kaza). An end-of-turn signal an integration can wait for, instead of guessing from "it has been quiet for eight seconds". On Slack it rides as invisible message metadata on the turn's last reply; on Mattermost, which has no metadata channel, as a 🏁 reaction. Default `off`, so nothing appears unless you ask for it. The payload carries a version (`v`), and `docs/CONFIGURATION.md` states what is frozen: `event_type` does not change within a 1.x line and `event_payload` only ever gains fields, `session` is stable across restarts and respawns, and `turn` restarts at 1 after a bot restart, so it is an ordering hint within one run rather than a unique key. Each marked turn costs one extra API call.
|
|
15
|
+
- **`CLAUDE_THREADS_HOME` moves the state root** (#557, thanks @Jadefalkner). Everything the bot persists — config, sessions, thread logs, worktree metadata, memory, uploads — resolves from one root instead of `homedir()` directly, so a second bot can run as the same user by pointing at a different directory. Unset, every path resolves exactly as before: this is a refactor at the default, and an existing install upgrades with its sessions intact.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **⚠️ Two bots sharing one `$HOME` will no longer both start** (#557). A one-process-per-root lock now refuses the second, naming the pid that holds it and the fix. This is a deliberate break of a setup that appeared to work: the two instances were writing the same `sessions.json` and quietly losing each other's sessions. If you run more than one bot as the same user, give each its own `CLAUDE_THREADS_HOME` before upgrading. A lock left behind by a killed process is taken over automatically.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **Verifying the `bugReports` gate no longer files a public issue** (#586). `createGitHubIssue` called `execSync` directly, so the one test that proves the gate is load-bearing reached the real `gh` CLI the moment the gate was removed. Anyone following the repo's own red-green rule therefore filed a public issue titled "T" from their test suite, three times in one afternoon (#581, #582, #583). The command is now injectable, the same way `checkGitHubCli` already was, and the test passes a stub and asserts directly that no subprocess runs. A second case covers the other direction, so a stub that was never wired up cannot make the first one pass for the wrong reason.
|
|
22
|
+
|
|
10
23
|
## [1.36.1] - 2026-09-10
|
|
11
24
|
|
|
12
25
|
### Fixed
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#
|
|
8
8
|
# For other exit codes:
|
|
9
9
|
# - 0: Clean exit, don't restart
|
|
10
|
+
# - 3: Refused to start (another instance holds the state directory), don't restart
|
|
10
11
|
# - 1+: Error, optional restart based on flags
|
|
11
12
|
#
|
|
12
13
|
# PLATFORM SUPPORT:
|
|
@@ -32,6 +33,9 @@ set -e
|
|
|
32
33
|
|
|
33
34
|
# Exit code that signals "restart for update"
|
|
34
35
|
RESTART_EXIT_CODE=42
|
|
36
|
+
# Exit code that signals "refused to start" (another instance holds the state
|
|
37
|
+
# directory): never restart, a retry would only collide again.
|
|
38
|
+
LOCKED_EXIT_CODE=3
|
|
35
39
|
|
|
36
40
|
# Configuration
|
|
37
41
|
MAX_RESTARTS=${CLAUDE_THREADS_MAX_RESTARTS:-0} # 0 = unlimited
|
|
@@ -92,6 +96,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
92
96
|
echo ""
|
|
93
97
|
echo "Exit codes:"
|
|
94
98
|
echo " 0 Clean exit, no restart"
|
|
99
|
+
echo " 3 Refused to start (another instance holds the state directory), no restart"
|
|
95
100
|
echo " 42 Update restart signal (always restarts)"
|
|
96
101
|
echo " other Error (restarts only with --restart-on-error)"
|
|
97
102
|
exit 0
|
|
@@ -162,6 +167,9 @@ while true; do
|
|
|
162
167
|
# Clean exit
|
|
163
168
|
log "Clean exit, not restarting"
|
|
164
169
|
should_restart=false
|
|
170
|
+
elif [ $exit_code -eq $LOCKED_EXIT_CODE ]; then
|
|
171
|
+
log "Another instance holds the state directory, not restarting"
|
|
172
|
+
should_restart=false
|
|
165
173
|
elif [ "$RESTART_ON_ERROR" = true ]; then
|
|
166
174
|
# Error exit with restart-on-error enabled
|
|
167
175
|
log "Error exit, restarting due to --restart-on-error"
|