claude-threads 1.40.2 → 1.41.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 +14 -0
- package/dist/index.js +2647 -2470
- package/dist/mcp/mcp-server.js +55 -18
- package/docs/CONFIGURATION.md +2 -0
- package/package.json +3 -3
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -15692,6 +15692,7 @@ var require_constants2 = __commonJS(function(exports, module) {
|
|
|
15692
15692
|
|
|
15693
15693
|
// node_modules/ws/lib/buffer-util.js
|
|
15694
15694
|
var require_buffer_util = __commonJS(function(exports, module) {
|
|
15695
|
+
var { websocketMask, websocketUnmask } = __require("http");
|
|
15695
15696
|
var { EMPTY_BUFFER } = require_constants2();
|
|
15696
15697
|
var FastBuffer = Buffer[Symbol.species];
|
|
15697
15698
|
function concat(list, totalLength) {
|
|
@@ -15749,7 +15750,20 @@ var require_buffer_util = __commonJS(function(exports, module) {
|
|
|
15749
15750
|
toBuffer,
|
|
15750
15751
|
unmask: _unmask
|
|
15751
15752
|
};
|
|
15752
|
-
if (
|
|
15753
|
+
if (websocketMask) {
|
|
15754
|
+
module.exports.mask = function(source, mask, output, offset, length) {
|
|
15755
|
+
if (length < 24)
|
|
15756
|
+
_mask(source, mask, output, offset, length);
|
|
15757
|
+
else
|
|
15758
|
+
websocketMask(source, mask, output, offset, length);
|
|
15759
|
+
};
|
|
15760
|
+
module.exports.unmask = function(buffer, mask) {
|
|
15761
|
+
if (buffer.length < 24)
|
|
15762
|
+
_unmask(buffer, mask);
|
|
15763
|
+
else
|
|
15764
|
+
websocketUnmask(buffer, mask);
|
|
15765
|
+
};
|
|
15766
|
+
} else if (!process.env.WS_NO_BUFFER_UTIL) {
|
|
15753
15767
|
try {
|
|
15754
15768
|
const bufferUtil = (()=>{throw new Error("Cannot require module "+"bufferutil");})();
|
|
15755
15769
|
module.exports.mask = function(source, mask2, output, offset, length) {
|
|
@@ -16737,13 +16751,16 @@ var require_sender = __commonJS(function(exports, module) {
|
|
|
16737
16751
|
target[2] = target[3] = 0;
|
|
16738
16752
|
target.writeUIntBE(dataLength, 4, 6);
|
|
16739
16753
|
}
|
|
16740
|
-
if (!options.mask)
|
|
16741
|
-
return [target, data];
|
|
16754
|
+
if (!options.mask) {
|
|
16755
|
+
return dataLength ? [target, data] : [target];
|
|
16756
|
+
}
|
|
16742
16757
|
target[1] |= 128;
|
|
16743
16758
|
target[offset - 4] = mask[0];
|
|
16744
16759
|
target[offset - 3] = mask[1];
|
|
16745
16760
|
target[offset - 2] = mask[2];
|
|
16746
16761
|
target[offset - 1] = mask[3];
|
|
16762
|
+
if (!dataLength)
|
|
16763
|
+
return [target];
|
|
16747
16764
|
if (skipMasking)
|
|
16748
16765
|
return [target, data];
|
|
16749
16766
|
if (merge) {
|
|
@@ -17803,9 +17820,14 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
17803
17820
|
opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
|
|
17804
17821
|
}
|
|
17805
17822
|
if (isIpcUrl) {
|
|
17806
|
-
const
|
|
17807
|
-
|
|
17808
|
-
|
|
17823
|
+
const i = opts.path.indexOf(":");
|
|
17824
|
+
if (i === -1) {
|
|
17825
|
+
opts.socketPath = opts.path;
|
|
17826
|
+
opts.path = "";
|
|
17827
|
+
} else {
|
|
17828
|
+
opts.socketPath = opts.path.slice(0, i);
|
|
17829
|
+
opts.path = opts.path.slice(i + 1);
|
|
17830
|
+
}
|
|
17809
17831
|
}
|
|
17810
17832
|
let req;
|
|
17811
17833
|
if (opts.followRedirects) {
|
|
@@ -34277,12 +34299,13 @@ function truncateAtCodePoint(text, max) {
|
|
|
34277
34299
|
return { text, truncated: false };
|
|
34278
34300
|
return { text: points.slice(0, max).join(""), truncated: true };
|
|
34279
34301
|
}
|
|
34302
|
+
var COMMAND_BLOCK_MIN_LENGTH = 120;
|
|
34280
34303
|
var bashToolFormatter = {
|
|
34281
34304
|
toolNames: ["Bash"],
|
|
34282
34305
|
format(toolName, input, options) {
|
|
34283
34306
|
if (toolName !== "Bash")
|
|
34284
34307
|
return null;
|
|
34285
|
-
const { formatter, maxCommandLength = 50, worktreeInfo } = options;
|
|
34308
|
+
const { formatter, detailed = false, maxCommandLength = 50, worktreeInfo } = options;
|
|
34286
34309
|
let cmd = input.command || "";
|
|
34287
34310
|
if (worktreeInfo?.path) {
|
|
34288
34311
|
cmd = cmd.replace(new RegExp(escapeRegExp(worktreeInfo.path), "g"), `[${worktreeInfo.branch}]`);
|
|
@@ -34292,8 +34315,14 @@ var bashToolFormatter = {
|
|
|
34292
34315
|
const permission = truncateAtCodePoint(cmd, PERMISSION_COMMAND_MAX);
|
|
34293
34316
|
const permissionCmd = escapeCodeBlockContent(permission.text) + (permission.truncated ? `
|
|
34294
34317
|
[... truncated]` : "");
|
|
34318
|
+
let display = `\uD83D\uDCBB ${formatter.formatBold("Bash")} ${formatter.formatCode(displayCmd + (truncated ? "..." : ""))}`;
|
|
34319
|
+
if (detailed && truncated && (cmd.length > COMMAND_BLOCK_MIN_LENGTH || cmd.includes(`
|
|
34320
|
+
`))) {
|
|
34321
|
+
display += `
|
|
34322
|
+
${formatter.formatCodeBlock(permissionCmd, "bash")}`;
|
|
34323
|
+
}
|
|
34295
34324
|
return {
|
|
34296
|
-
display
|
|
34325
|
+
display,
|
|
34297
34326
|
permissionText: `\uD83D\uDCBB ${formatter.formatBold("Bash")}
|
|
34298
34327
|
${formatter.formatCodeBlock(permissionCmd, "bash")}`,
|
|
34299
34328
|
isDestructive: true
|
|
@@ -35087,8 +35116,12 @@ function formatBytes(bytes) {
|
|
|
35087
35116
|
|
|
35088
35117
|
// src/operations/streaming/handler.ts
|
|
35089
35118
|
var log9 = createLogger("streaming");
|
|
35119
|
+
|
|
35120
|
+
// src/operations/user-attribution/formatter.ts
|
|
35121
|
+
var speakersBySession = new WeakMap;
|
|
35090
35122
|
// src/operations/message-manager.ts
|
|
35091
35123
|
var log10 = createLogger("msg-mgr");
|
|
35124
|
+
var REACTION_ANCHOR_TYPES = new Set(["content", "task_list", "subagent"]);
|
|
35092
35125
|
// src/persistence/session-store.ts
|
|
35093
35126
|
init_logger();
|
|
35094
35127
|
import { join as join3 } from "path";
|
|
@@ -38847,6 +38880,10 @@ var LOGS_BASE_DIR = join4(stateHome(), ".claude-threads", "logs");
|
|
|
38847
38880
|
// src/operations/bug-report/handler.ts
|
|
38848
38881
|
var piiRedactor = new Redactor({ aggressive: true });
|
|
38849
38882
|
var MAX_SCREENSHOT_BYTES = 10 * 1024 * 1024;
|
|
38883
|
+
// src/session/lifecycle-delivery.ts
|
|
38884
|
+
init_logger();
|
|
38885
|
+
var sessionLog2 = createSessionLog(createLogger("lifecycle"));
|
|
38886
|
+
|
|
38850
38887
|
// src/mcp/decision-bridge.ts
|
|
38851
38888
|
import { createServer, createConnection } from "node:net";
|
|
38852
38889
|
var MAX_BRIDGE_REQUEST_BYTES = 1024 * 1024;
|
|
@@ -39740,13 +39777,13 @@ var log19 = createLogger("tags");
|
|
|
39740
39777
|
// src/session/metadata-suggestions.ts
|
|
39741
39778
|
init_logger();
|
|
39742
39779
|
var log20 = createLogger("session");
|
|
39743
|
-
var
|
|
39780
|
+
var sessionLog3 = createSessionLog(log20);
|
|
39744
39781
|
|
|
39745
39782
|
// src/operations/context-prompt/handler.ts
|
|
39746
39783
|
init_emoji();
|
|
39747
39784
|
init_logger();
|
|
39748
39785
|
var log21 = createLogger("context");
|
|
39749
|
-
var
|
|
39786
|
+
var sessionLog4 = createSessionLog(log21);
|
|
39750
39787
|
var contextPromptTimeouts = new Map;
|
|
39751
39788
|
var contextPromptFiles = new Map;
|
|
39752
39789
|
// src/memory/store.ts
|
|
@@ -39792,21 +39829,21 @@ var log27 = createLogger("watches");
|
|
|
39792
39829
|
// src/operations/commands/guards.ts
|
|
39793
39830
|
init_logger();
|
|
39794
39831
|
var log28 = createLogger("commands");
|
|
39795
|
-
var
|
|
39832
|
+
var sessionLog5 = createSessionLog(log28);
|
|
39796
39833
|
|
|
39797
39834
|
// src/operations/commands/automation.ts
|
|
39798
39835
|
init_logger();
|
|
39799
39836
|
var log29 = createLogger("commands");
|
|
39800
|
-
var
|
|
39837
|
+
var sessionLog6 = createSessionLog(log29);
|
|
39801
39838
|
|
|
39802
39839
|
// src/operations/agent-actions/handler.ts
|
|
39803
39840
|
init_logger();
|
|
39804
39841
|
var log30 = createLogger("agent-actions");
|
|
39805
|
-
var
|
|
39842
|
+
var sessionLog7 = createSessionLog(log30);
|
|
39806
39843
|
|
|
39807
39844
|
// src/session/lifecycle.ts
|
|
39808
39845
|
var log31 = createLogger("lifecycle");
|
|
39809
|
-
var
|
|
39846
|
+
var sessionLog8 = createSessionLog(log31);
|
|
39810
39847
|
var _inFlightSessionStarts = new Map;
|
|
39811
39848
|
var CHAT_PLATFORM_PROMPT = generateChatPlatformPrompt();
|
|
39812
39849
|
|
|
@@ -39830,11 +39867,11 @@ var DEFAULT_FILE3 = join9(DEFAULT_CONFIG_DIR2, "github-emails.yaml");
|
|
|
39830
39867
|
|
|
39831
39868
|
// src/operations/commands/handler.ts
|
|
39832
39869
|
var log33 = createLogger("commands");
|
|
39833
|
-
var
|
|
39870
|
+
var sessionLog9 = createSessionLog(log33);
|
|
39834
39871
|
// src/operations/commands/memory.ts
|
|
39835
39872
|
init_logger();
|
|
39836
39873
|
var log34 = createLogger("commands");
|
|
39837
|
-
var
|
|
39874
|
+
var sessionLog10 = createSessionLog(log34);
|
|
39838
39875
|
// src/operations/suggestions/branch.ts
|
|
39839
39876
|
init_quick_query();
|
|
39840
39877
|
init_logger();
|
|
@@ -39847,11 +39884,11 @@ var log35 = createLogger("branch");
|
|
|
39847
39884
|
init_cli();
|
|
39848
39885
|
init_logger();
|
|
39849
39886
|
var log36 = createLogger("worktree");
|
|
39850
|
-
var
|
|
39887
|
+
var sessionLog11 = createSessionLog(log36);
|
|
39851
39888
|
// src/operations/events/handler.ts
|
|
39852
39889
|
init_logger();
|
|
39853
39890
|
var log37 = createLogger("events");
|
|
39854
|
-
var
|
|
39891
|
+
var sessionLog12 = createSessionLog(log37);
|
|
39855
39892
|
// src/operations/monitor/handler.ts
|
|
39856
39893
|
init_logger();
|
|
39857
39894
|
var log38 = createLogger("monitor");
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -173,6 +173,7 @@ What happens: every `audio/*` attachment (or a file with an audio extension when
|
|
|
173
173
|
| `sessionHeader` | No | Per-thread header visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no header post) |
|
|
174
174
|
| `stickyMessage` | No | Channel sticky visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no sticky, no bumping) |
|
|
175
175
|
| `lifecycle` | No | Session status posts — idle warning, timeout, pause, resume, and the shutdown notice a deploy leaves in each open thread: `full` (default, all of them) / `minimal` (drops the idle warning, which predicts a timeout the next message would undo anyway) / `hidden` (none). Editing a status post the thread already has is not suppressed at any level: it adds no post and no notification, and leaving a stale "session idle" up across a restart would be worse. ⚠️ An **abnormal exit** (`[Exited: <code>]`, non-zero only) posts at every level including `hidden`: it is a failure report, and silencing it would make a session that died look exactly like one that finished. Note that `hidden` also removes the post a 🔄 reaction resumes from — sending a message in the thread still resumes it, and the channel sticky says so. |
|
|
176
|
+
| `lifecycleDelivery` | No | How a **new** lifecycle notice reaches the thread: `post` (default, a new post as before) / `dedup` (no new post when the bot's last post in the thread already shows the same notice: that post is updated to the new text in place instead, which notifies nobody; a "Session resumed" notice counts as the shutdown notice the next restart would post, so back-to-back restarts leave one post) / `reaction` (an emoji on the bot's last post instead of a new post, which notifies nobody: ⏳ idle, ⏰ timed out, 💤 paused, 🔌 shutting down, 🌅 resumed; when that last post is a notice the bot had to post itself, it is updated in place instead, so its text and emoji never disagree). `lifecycle` still decides whether a notice is wanted at all, so `hidden` delivers nothing. Editing an existing status post is unchanged, except that a post carrying the notice as a reaction is never rewritten (its emoji is swapped instead). The deduped or reacted-to post is what a 🔄 reaction resumes the session from. With nothing to react to yet (right after a restart, before the bot has posted), the notice is posted. Any newer post in the thread, by anyone, ends a notice's turn as the last post, so a later notice is never refreshed above it. Under `reaction` the emoji only goes on Claude's reply or a task-list post; on a question, a plan or a prompt the reactions are the answers, so the notice is posted instead, as it is when an emoji swap fails. Posts made while the bot is down are not seen. `reaction` also drops the notice's text, such as "react 🔄 to resume" and the minutes left. ⚠️ An **abnormal exit** always posts, whatever this is set to. |
|
|
176
177
|
| `directChannelMode` | No | Direct channel mode: the whole channel is one session, and the bot replies with top-level channel posts instead of thread replies. `true` for defaults, or an options object (`respondTo`). See [Direct Channel Mode](#direct-channel-mode). |
|
|
177
178
|
| `approvals` | No | Who may answer tool-permission prompts and other reaction gates: `owner` (session participants) or `all_users` (everyone on `allowedUsers`). Unset keeps the historical default per mode — `all_users` for thread sessions, `owner` for direct channel mode. See [Approvals](#approvals). |
|
|
178
179
|
| `ackReaction` | No | Read receipt: react to every accepted message (session start, follow-up, resume) the instant it is accepted, before Claude produces output. `true` uses 👀 (`eyes`), a string names a custom emoji. Persistent, unlike the typing indicator — useful in busy channels and for messages queued behind an in-flight session start. The receipt means *accepted*, not *delivered*: a later failure (capacity limit, Claude not coming up) is still reported by its own post. `!commands` are not acked — they have their own immediate feedback, and neither are messages accepted through the message-approval flow (an authorized user approving a non-participant's message) — there the approval reaction is already the visible signal. Note: in direct channel mode this is one reaction API call per accepted message. Default off. |
|
|
@@ -199,6 +200,7 @@ What happens: every `audio/*` attachment (or a file with an audio extension when
|
|
|
199
200
|
| `sessionHeader` | No | Per-thread header visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no header post) |
|
|
200
201
|
| `stickyMessage` | No | Channel sticky visibility: `full` (default) / `minimal` (status bar only) / `hidden` (no sticky, no bumping) |
|
|
201
202
|
| `lifecycle` | No | Session status posts — idle warning, timeout, pause, resume, and the shutdown notice a deploy leaves in each open thread: `full` (default, all of them) / `minimal` (drops the idle warning, which predicts a timeout the next message would undo anyway) / `hidden` (none). Editing a status post the thread already has is not suppressed at any level: it adds no post and no notification, and leaving a stale "session idle" up across a restart would be worse. ⚠️ An **abnormal exit** (`[Exited: <code>]`, non-zero only) posts at every level including `hidden`: it is a failure report, and silencing it would make a session that died look exactly like one that finished. Note that `hidden` also removes the post a 🔄 reaction resumes from — sending a message in the thread still resumes it, and the channel sticky says so. |
|
|
203
|
+
| `lifecycleDelivery` | No | How a **new** lifecycle notice reaches the thread: `post` (default, a new post as before) / `dedup` (no new post when the bot's last post in the thread already shows the same notice: that post is updated to the new text in place instead, which notifies nobody; a "Session resumed" notice counts as the shutdown notice the next restart would post, so back-to-back restarts leave one post) / `reaction` (an emoji on the bot's last post instead of a new post, which notifies nobody: ⏳ idle, ⏰ timed out, 💤 paused, 🔌 shutting down, 🌅 resumed; when that last post is a notice the bot had to post itself, it is updated in place instead, so its text and emoji never disagree). `lifecycle` still decides whether a notice is wanted at all, so `hidden` delivers nothing. Editing an existing status post is unchanged, except that a post carrying the notice as a reaction is never rewritten (its emoji is swapped instead). The deduped or reacted-to post is what a 🔄 reaction resumes the session from. With nothing to react to yet (right after a restart, before the bot has posted), the notice is posted. Any newer post in the thread, by anyone, ends a notice's turn as the last post, so a later notice is never refreshed above it. Under `reaction` the emoji only goes on Claude's reply or a task-list post; on a question, a plan or a prompt the reactions are the answers, so the notice is posted instead, as it is when an emoji swap fails. Posts made while the bot is down are not seen. `reaction` also drops the notice's text, such as "react 🔄 to resume" and the minutes left. ⚠️ An **abnormal exit** always posts, whatever this is set to. |
|
|
202
204
|
| `directChannelMode` | No | Direct channel mode: the whole channel is one session, and the bot replies with top-level channel posts instead of thread replies. `true` for defaults, or an options object (`respondTo`). See [Direct Channel Mode](#direct-channel-mode). |
|
|
203
205
|
| `approvals` | No | Who may answer tool-permission prompts and other reaction gates: `owner` (session participants) or `all_users` (everyone on `allowedUsers`). Unset keeps the historical default per mode — `all_users` for thread sessions, `owner` for direct channel mode. See [Approvals](#approvals). |
|
|
204
206
|
| `ackReaction` | No | Read receipt: react to every accepted message (session start, follow-up, resume) the instant it is accepted, before Claude produces output. `true` uses 👀 (`eyes`), a string names a custom emoji. Persistent, unlike the typing indicator — useful in busy channels and for messages queued behind an in-flight session start. The receipt means *accepted*, not *delivered*: a later failure (capacity limit, Claude not coming up) is still reported by its own post. `!commands` are not acked — they have their own immediate feedback, and neither are messages accepted through the message-approval flow (an authorized user approving a non-participant's message) — there the approval reaction is already the visible signal. Note: in direct channel mode this is one reaction API call per accepted message. Default off. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-threads",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.41.0",
|
|
4
4
|
"description": "Run Claude Code from Slack or Mattermost. Sessions stream live into threads where your whole team can watch and steer.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"react": "^19.3.1",
|
|
86
86
|
"semver": "7.8.5",
|
|
87
87
|
"update-notifier": "^7.3.1",
|
|
88
|
-
"ws": "8.22.
|
|
88
|
+
"ws": "8.22.1",
|
|
89
89
|
"zod": "^4.6.7"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"@types/ws": "^8.18.2",
|
|
102
102
|
"eslint": "^10.13.0",
|
|
103
103
|
"husky": "^9.1.7",
|
|
104
|
-
"knip": "6.
|
|
104
|
+
"knip": "6.44.1",
|
|
105
105
|
"lint-staged": "^17.0.4",
|
|
106
106
|
"prettier": "^3.9.10",
|
|
107
107
|
"react-devtools-core": "^8.0.0",
|