claude-threads 1.16.3 → 1.17.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 +9 -0
- package/README.md +1 -0
- package/dist/index.js +86 -3
- package/dist/mcp/mcp-server.js +18 -0
- package/docs/CONFIGURATION.md +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.17.0] - 2026-06-05
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`!mentions` quiet mode: respond only when @mentioned.** New per-session toggle for holding side conversations inside a bot thread without the bot replying to every message. `!mentions on` makes the bot ignore thread replies that don't explicitly @mention it; `!mentions off` (or a bare `!mentions` to flip the current value) turns it back off. Commands and pending worktree-branch-name prompts always bypass the gate, so `!mentions off` (and answering a worktree prompt) works even while quiet mode is on. When quiet mode is on, the session header shows a row noting it, so a returning user can see why the bot is staying quiet. The setting is owned by the session owner or a globally allowed user and persists across a bot restart. A global `respondOnlyWhenMentioned: true` in `config.yaml` (also offered in the onboarding wizard) seeds quiet mode on every new thread, so users who mostly want quiet threads don't have to run `!mentions on` each time; each session still keeps its own value and can override per-thread. The default everywhere is unchanged (the bot treats every approved-user reply as input), so existing threads and configs are unaffected. (#402)
|
|
14
|
+
|
|
15
|
+
### Dependencies
|
|
16
|
+
- **Production:** `js-yaml` 4.1.1 → 4.2.0, `react` 19.2.6 → 19.2.7. (#404)
|
|
17
|
+
- **Dev:** `typescript-eslint` 8.60.0 → 8.60.1. (#403)
|
|
18
|
+
|
|
10
19
|
## [1.16.3] - 2026-05-31
|
|
11
20
|
|
|
12
21
|
### Changed
|
package/README.md
CHANGED
|
@@ -85,6 +85,7 @@ Type `!help` in any session thread:
|
|
|
85
85
|
| `!compact` | Compress context to free up space |
|
|
86
86
|
| `!cd <path>` | Change working directory (restarts Claude) |
|
|
87
87
|
| `!permissions <mode>` | Set permission mode: `default` / `auto` / `bypass` |
|
|
88
|
+
| `!mentions [on\|off]` | Quiet mode: only respond when @mentioned (bare `!mentions` toggles) |
|
|
88
89
|
| `!worktree <branch>` | Create and switch to a git worktree (also: `list`, `switch`, `remove`, `cleanup`, `off`) |
|
|
89
90
|
| `!plugin <list\|install\|uninstall> [name]` | Manage Claude Code plugins (restarts Claude) |
|
|
90
91
|
| `!invite @user` | Invite a user to this session (added as `Co-Authored-By:` on commits) |
|
package/dist/index.js
CHANGED
|
@@ -54157,6 +54157,13 @@ async function runOnboarding(reconfigure = false) {
|
|
|
54157
54157
|
{ title: "Require", value: "require", description: "Always require branch name before starting" }
|
|
54158
54158
|
],
|
|
54159
54159
|
initial: existingConfig?.worktreeMode === "off" ? 1 : existingConfig?.worktreeMode === "require" ? 2 : 0
|
|
54160
|
+
},
|
|
54161
|
+
{
|
|
54162
|
+
type: "confirm",
|
|
54163
|
+
name: "respondOnlyWhenMentioned",
|
|
54164
|
+
message: "Respond only when @mentioned?",
|
|
54165
|
+
initial: existingConfig?.respondOnlyWhenMentioned || false,
|
|
54166
|
+
hint: "New threads start in quiet mode; users can still toggle per-thread with !mentions"
|
|
54160
54167
|
}
|
|
54161
54168
|
], { onCancel });
|
|
54162
54169
|
const config = {
|
|
@@ -54164,6 +54171,9 @@ async function runOnboarding(reconfigure = false) {
|
|
|
54164
54171
|
...globalSettings,
|
|
54165
54172
|
platforms: []
|
|
54166
54173
|
};
|
|
54174
|
+
if (!config.respondOnlyWhenMentioned) {
|
|
54175
|
+
delete config.respondOnlyWhenMentioned;
|
|
54176
|
+
}
|
|
54167
54177
|
console.log("");
|
|
54168
54178
|
console.log(bold(" Platform Setup"));
|
|
54169
54179
|
console.log("");
|
|
@@ -54274,7 +54284,7 @@ async function runReconfigureFlow(existingConfig) {
|
|
|
54274
54284
|
{
|
|
54275
54285
|
title: "Global settings",
|
|
54276
54286
|
value: "global",
|
|
54277
|
-
description: `workingDir, chrome, worktreeMode`
|
|
54287
|
+
description: `workingDir, chrome, worktreeMode, mentions`
|
|
54278
54288
|
}
|
|
54279
54289
|
];
|
|
54280
54290
|
for (let i2 = 0;i2 < config.platforms.length; i2++) {
|
|
@@ -54321,9 +54331,19 @@ async function runReconfigureFlow(existingConfig) {
|
|
|
54321
54331
|
{ title: "Require", value: "require", description: "Always require branch name before starting" }
|
|
54322
54332
|
],
|
|
54323
54333
|
initial: config.worktreeMode === "off" ? 1 : config.worktreeMode === "require" ? 2 : 0
|
|
54334
|
+
},
|
|
54335
|
+
{
|
|
54336
|
+
type: "confirm",
|
|
54337
|
+
name: "respondOnlyWhenMentioned",
|
|
54338
|
+
message: "Respond only when @mentioned?",
|
|
54339
|
+
initial: config.respondOnlyWhenMentioned || false,
|
|
54340
|
+
hint: "New threads start in quiet mode; users can still toggle per-thread with !mentions"
|
|
54324
54341
|
}
|
|
54325
54342
|
], { onCancel });
|
|
54326
54343
|
config = { ...config, ...globalSettings };
|
|
54344
|
+
if (!config.respondOnlyWhenMentioned) {
|
|
54345
|
+
delete config.respondOnlyWhenMentioned;
|
|
54346
|
+
}
|
|
54327
54347
|
console.log(green(" ✓ Global settings updated"));
|
|
54328
54348
|
} else if (action === "add-new") {
|
|
54329
54349
|
console.log("");
|
|
@@ -54452,6 +54472,7 @@ async function showConfigSummary(config) {
|
|
|
54452
54472
|
console.log(dim(` Working Directory: ${config.workingDir}`));
|
|
54453
54473
|
console.log(dim(` Chrome Integration: ${config.chrome ? "Enabled" : "Disabled"}`));
|
|
54454
54474
|
console.log(dim(` Worktree Mode: ${config.worktreeMode}`));
|
|
54475
|
+
console.log(dim(` Respond Only When Mentioned: ${config.respondOnlyWhenMentioned ? "Enabled" : "Disabled"}`));
|
|
54455
54476
|
console.log("");
|
|
54456
54477
|
console.log(dim(` Platforms (${config.platforms.length}):`));
|
|
54457
54478
|
for (const platform of config.platforms) {
|
|
@@ -59463,6 +59484,14 @@ var COMMAND_REGISTRY = [
|
|
|
59463
59484
|
worksInFirstMessage: true,
|
|
59464
59485
|
isStackable: true
|
|
59465
59486
|
},
|
|
59487
|
+
{
|
|
59488
|
+
command: "mentions",
|
|
59489
|
+
description: "Toggle quiet mode: only respond when @mentioned by name",
|
|
59490
|
+
args: "on / off",
|
|
59491
|
+
category: "settings",
|
|
59492
|
+
audience: "user",
|
|
59493
|
+
claudeNotes: "User decisions, not yours"
|
|
59494
|
+
},
|
|
59466
59495
|
{
|
|
59467
59496
|
command: "update",
|
|
59468
59497
|
description: "Show auto-update status",
|
|
@@ -59572,6 +59601,7 @@ var COMMAND_PATTERNS = [
|
|
|
59572
59601
|
["invite", /^!invite\s+@?([\w.-]+)\s*$/i],
|
|
59573
59602
|
["kick", /^!kick\s+@?([\w.-]+)\s*$/i],
|
|
59574
59603
|
["permissions", /^!permissions?\s+(default|auto|bypass|interactive|skip)\s*$/i],
|
|
59604
|
+
["mentions", /^!mentions(?:\s+(on|off))?\s*$/i],
|
|
59575
59605
|
["update", /^!update(?:\s+(now|defer))?\s*$/i],
|
|
59576
59606
|
["context", /^!context\s*$/i],
|
|
59577
59607
|
["cost", /^!cost\s*$/i],
|
|
@@ -59956,6 +59986,15 @@ var handlePermissions = async (ctx, args) => {
|
|
|
59956
59986
|
await ctx.sessionManager.setSessionPermissionMode(ctx.threadId, ctx.username, mode);
|
|
59957
59987
|
return { handled: true };
|
|
59958
59988
|
};
|
|
59989
|
+
var handleMentions = async (ctx, args) => {
|
|
59990
|
+
if (ctx.commandContext === "first-message") {
|
|
59991
|
+
return { handled: false };
|
|
59992
|
+
}
|
|
59993
|
+
if (ctx.isAllowed) {
|
|
59994
|
+
await ctx.sessionManager.setRespondOnlyWhenMentioned(ctx.threadId, ctx.username, args);
|
|
59995
|
+
}
|
|
59996
|
+
return { handled: true };
|
|
59997
|
+
};
|
|
59959
59998
|
var handleWorktree = async (ctx, args) => {
|
|
59960
59999
|
const parts = args?.split(/\s+/) || [];
|
|
59961
60000
|
const subcommandOrBranch = parts[0]?.toLowerCase();
|
|
@@ -60089,6 +60128,7 @@ handlers.set("kick", handleKick);
|
|
|
60089
60128
|
handlers.set("github-email", handleGitHubEmail);
|
|
60090
60129
|
handlers.set("cd", handleCd);
|
|
60091
60130
|
handlers.set("permissions", handlePermissions);
|
|
60131
|
+
handlers.set("mentions", handleMentions);
|
|
60092
60132
|
handlers.set("worktree", handleWorktree);
|
|
60093
60133
|
handlers.set("bug", handleBug);
|
|
60094
60134
|
handlers.set("plugin", handlePlugin);
|
|
@@ -71262,6 +71302,31 @@ async function kickUser(session, kickedUser, kickedBy, ctx) {
|
|
|
71262
71302
|
sessionLog5(session).warn(`\uD83D\uDEAB @${kickedUser} was not in session`);
|
|
71263
71303
|
}
|
|
71264
71304
|
}
|
|
71305
|
+
async function setRespondOnlyWhenMentioned(session, username, arg, ctx) {
|
|
71306
|
+
if (!await requireSessionOwner(session, username, "change session settings")) {
|
|
71307
|
+
return;
|
|
71308
|
+
}
|
|
71309
|
+
const normalized = arg?.toLowerCase();
|
|
71310
|
+
let enabled;
|
|
71311
|
+
if (normalized === "on") {
|
|
71312
|
+
enabled = true;
|
|
71313
|
+
} else if (normalized === "off") {
|
|
71314
|
+
enabled = false;
|
|
71315
|
+
} else {
|
|
71316
|
+
enabled = !session.respondOnlyWhenMentioned;
|
|
71317
|
+
}
|
|
71318
|
+
session.respondOnlyWhenMentioned = enabled;
|
|
71319
|
+
ctx.ops.persistSession(session);
|
|
71320
|
+
const botName = session.platform.getBotName();
|
|
71321
|
+
if (enabled) {
|
|
71322
|
+
await post(session, "success", `Quiet mode on — I'll only respond when you @mention me (\`@${botName}\`). Use \`!mentions off\` to turn this off.`);
|
|
71323
|
+
} else {
|
|
71324
|
+
await post(session, "success", `Quiet mode off — I'll respond to every message in this thread again.`);
|
|
71325
|
+
}
|
|
71326
|
+
sessionLog5(session).info(`\uD83D\uDD15 respondOnlyWhenMentioned=${enabled} by @${username}`);
|
|
71327
|
+
session.threadLogger?.logCommand("mentions", enabled ? "on" : "off", username);
|
|
71328
|
+
await updateSessionHeader(session, ctx);
|
|
71329
|
+
}
|
|
71265
71330
|
async function setGitHubEmail(session, username, arg, ctx) {
|
|
71266
71331
|
const formatter = session.platform.getFormatter();
|
|
71267
71332
|
const trimmed = arg?.trim();
|
|
@@ -71436,6 +71501,9 @@ async function updateSessionHeader(session, ctx) {
|
|
|
71436
71501
|
if (otherParticipants) {
|
|
71437
71502
|
items.push(["\uD83D\uDC65", "Participants", otherParticipants]);
|
|
71438
71503
|
}
|
|
71504
|
+
if (session.respondOnlyWhenMentioned) {
|
|
71505
|
+
items.push(["\uD83D\uDD15", "Replies", `only when ${formatter.formatBold("@mentioned")} (${formatter.formatCode("!mentions off")} to disable)`]);
|
|
71506
|
+
}
|
|
71439
71507
|
if (session.claudeAccountId) {
|
|
71440
71508
|
const account = ctx.ops.getClaudeAccount(session.claudeAccountId);
|
|
71441
71509
|
const label = account?.displayName ?? session.claudeAccountId;
|
|
@@ -72090,6 +72158,7 @@ async function startSession(options, username, displayName, replyToPostId, platf
|
|
|
72090
72158
|
planApproved: false,
|
|
72091
72159
|
sessionAllowedUsers: new Set([username]),
|
|
72092
72160
|
forceInteractivePermissions,
|
|
72161
|
+
respondOnlyWhenMentioned: ctx.config.respondOnlyWhenMentioned ?? false,
|
|
72093
72162
|
permissionModeOverride: sessionPermissionModeOverride,
|
|
72094
72163
|
sessionStartPostId: startPost ? startPost.id : null,
|
|
72095
72164
|
sessionHeaderMode,
|
|
@@ -72245,6 +72314,7 @@ Please start a new session.`), { action: "Post resume failure notification" });
|
|
|
72245
72314
|
planApproved: state.planApproved ?? false,
|
|
72246
72315
|
sessionAllowedUsers: new Set(state.sessionAllowedUsers),
|
|
72247
72316
|
forceInteractivePermissions: state.forceInteractivePermissions ?? false,
|
|
72317
|
+
respondOnlyWhenMentioned: state.respondOnlyWhenMentioned ?? false,
|
|
72248
72318
|
sessionStartPostId: state.sessionStartPostId ?? null,
|
|
72249
72319
|
sessionHeaderMode: resumeSessionHeaderMode(state.sessionHeaderMode, ctx.ops.getPlatformOverhead(platformId).sessionHeader),
|
|
72250
72320
|
timers: createSessionTimers(),
|
|
@@ -72982,6 +73052,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
72982
73052
|
permissionMode;
|
|
72983
73053
|
chromeEnabled;
|
|
72984
73054
|
worktreeMode;
|
|
73055
|
+
respondOnlyWhenMentioned;
|
|
72985
73056
|
threadLogsEnabled;
|
|
72986
73057
|
threadLogsRetentionDays;
|
|
72987
73058
|
limits;
|
|
@@ -73000,12 +73071,13 @@ class SessionManager extends EventEmitter4 {
|
|
|
73000
73071
|
platformOverhead = new Map;
|
|
73001
73072
|
autoUpdateManager = null;
|
|
73002
73073
|
accountPool;
|
|
73003
|
-
constructor(workingDir, permissionModeOrSkipFlag = "default", chromeEnabled = false, worktreeMode = "prompt", sessionsPath, threadLogsEnabled = true, threadLogsRetentionDays = 30, limits, claudeAccounts) {
|
|
73074
|
+
constructor(workingDir, permissionModeOrSkipFlag = "default", chromeEnabled = false, worktreeMode = "prompt", sessionsPath, threadLogsEnabled = true, threadLogsRetentionDays = 30, limits, claudeAccounts, respondOnlyWhenMentioned = false) {
|
|
73004
73075
|
super();
|
|
73005
73076
|
this.workingDir = workingDir;
|
|
73006
73077
|
this.permissionMode = typeof permissionModeOrSkipFlag === "boolean" ? permissionModeOrSkipFlag ? "bypass" : "default" : permissionModeOrSkipFlag;
|
|
73007
73078
|
this.chromeEnabled = chromeEnabled;
|
|
73008
73079
|
this.worktreeMode = worktreeMode;
|
|
73080
|
+
this.respondOnlyWhenMentioned = respondOnlyWhenMentioned;
|
|
73009
73081
|
this.threadLogsEnabled = threadLogsEnabled;
|
|
73010
73082
|
this.threadLogsRetentionDays = threadLogsRetentionDays;
|
|
73011
73083
|
this.limits = resolveLimits(limits);
|
|
@@ -73093,6 +73165,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
73093
73165
|
workingDir: this.workingDir,
|
|
73094
73166
|
permissionMode: this.permissionMode,
|
|
73095
73167
|
chromeEnabled: this.chromeEnabled,
|
|
73168
|
+
respondOnlyWhenMentioned: this.respondOnlyWhenMentioned,
|
|
73096
73169
|
debug: this.debug,
|
|
73097
73170
|
maxSessions: this.limits.maxSessions,
|
|
73098
73171
|
threadLogsEnabled: this.threadLogsEnabled,
|
|
@@ -73286,6 +73359,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
73286
73359
|
planApproved: session.planApproved,
|
|
73287
73360
|
sessionAllowedUsers: [...session.sessionAllowedUsers],
|
|
73288
73361
|
forceInteractivePermissions: session.forceInteractivePermissions,
|
|
73362
|
+
respondOnlyWhenMentioned: session.respondOnlyWhenMentioned,
|
|
73289
73363
|
sessionStartPostId: session.sessionStartPostId,
|
|
73290
73364
|
tasksPostId: taskListSnapshot?.postId ?? null,
|
|
73291
73365
|
lastTasksContent: taskListSnapshot?.content ?? null,
|
|
@@ -73583,6 +73657,12 @@ class SessionManager extends EventEmitter4 {
|
|
|
73583
73657
|
return;
|
|
73584
73658
|
await setGitHubEmail(session, username, arg, this.getContext());
|
|
73585
73659
|
}
|
|
73660
|
+
async setRespondOnlyWhenMentioned(threadId, username, arg) {
|
|
73661
|
+
const session = this.findSessionByThreadId(threadId);
|
|
73662
|
+
if (!session)
|
|
73663
|
+
return;
|
|
73664
|
+
await setRespondOnlyWhenMentioned(session, username, arg, this.getContext());
|
|
73665
|
+
}
|
|
73586
73666
|
async setSessionPermissionMode(threadId, username, mode) {
|
|
73587
73667
|
const session = this.findSessionByThreadId(threadId);
|
|
73588
73668
|
if (!session)
|
|
@@ -83543,6 +83623,9 @@ async function handleMessage(client, session, post2, user, options) {
|
|
|
83543
83623
|
return;
|
|
83544
83624
|
}
|
|
83545
83625
|
}
|
|
83626
|
+
if (activeSession.respondOnlyWhenMentioned && !client.isBotMentioned(message)) {
|
|
83627
|
+
return;
|
|
83628
|
+
}
|
|
83546
83629
|
if (!session.isUserAllowedInSession(threadRoot, username)) {
|
|
83547
83630
|
if (content)
|
|
83548
83631
|
await session.requestMessageApproval(threadRoot, username, content);
|
|
@@ -84878,7 +84961,7 @@ async function startWithoutDaemon() {
|
|
|
84878
84961
|
keepAlive.setEnabled(keepAliveEnabled);
|
|
84879
84962
|
const threadLogsEnabled = config.threadLogs?.enabled ?? true;
|
|
84880
84963
|
const threadLogsRetentionDays = config.threadLogs?.retentionDays ?? 30;
|
|
84881
|
-
const session = new SessionManager(workingDir, initialPermissionMode, config.chrome, config.worktreeMode, undefined, threadLogsEnabled, threadLogsRetentionDays, config.limits, config.claudeAccounts);
|
|
84964
|
+
const session = new SessionManager(workingDir, initialPermissionMode, config.chrome, config.worktreeMode, undefined, threadLogsEnabled, threadLogsRetentionDays, config.limits, config.claudeAccounts, config.respondOnlyWhenMentioned);
|
|
84882
84965
|
if (config.stickyMessage) {
|
|
84883
84966
|
session.setStickyMessageCustomization(config.stickyMessage.description, config.stickyMessage.footer);
|
|
84884
84967
|
}
|
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -55520,6 +55520,14 @@ var COMMAND_REGISTRY = [
|
|
|
55520
55520
|
worksInFirstMessage: true,
|
|
55521
55521
|
isStackable: true
|
|
55522
55522
|
},
|
|
55523
|
+
{
|
|
55524
|
+
command: "mentions",
|
|
55525
|
+
description: "Toggle quiet mode: only respond when @mentioned by name",
|
|
55526
|
+
args: "on / off",
|
|
55527
|
+
category: "settings",
|
|
55528
|
+
audience: "user",
|
|
55529
|
+
claudeNotes: "User decisions, not yours"
|
|
55530
|
+
},
|
|
55523
55531
|
{
|
|
55524
55532
|
command: "update",
|
|
55525
55533
|
description: "Show auto-update status",
|
|
@@ -55790,6 +55798,15 @@ var handlePermissions = async (ctx, args) => {
|
|
|
55790
55798
|
await ctx.sessionManager.setSessionPermissionMode(ctx.threadId, ctx.username, mode);
|
|
55791
55799
|
return { handled: true };
|
|
55792
55800
|
};
|
|
55801
|
+
var handleMentions = async (ctx, args) => {
|
|
55802
|
+
if (ctx.commandContext === "first-message") {
|
|
55803
|
+
return { handled: false };
|
|
55804
|
+
}
|
|
55805
|
+
if (ctx.isAllowed) {
|
|
55806
|
+
await ctx.sessionManager.setRespondOnlyWhenMentioned(ctx.threadId, ctx.username, args);
|
|
55807
|
+
}
|
|
55808
|
+
return { handled: true };
|
|
55809
|
+
};
|
|
55793
55810
|
var handleWorktree = async (ctx, args) => {
|
|
55794
55811
|
const parts = args?.split(/\s+/) || [];
|
|
55795
55812
|
const subcommandOrBranch = parts[0]?.toLowerCase();
|
|
@@ -55923,6 +55940,7 @@ handlers.set("kick", handleKick);
|
|
|
55923
55940
|
handlers.set("github-email", handleGitHubEmail);
|
|
55924
55941
|
handlers.set("cd", handleCd);
|
|
55925
55942
|
handlers.set("permissions", handlePermissions);
|
|
55943
|
+
handlers.set("mentions", handleMentions);
|
|
55926
55944
|
handlers.set("worktree", handleWorktree);
|
|
55927
55945
|
handlers.set("bug", handleBug);
|
|
55928
55946
|
handlers.set("plugin", handlePlugin);
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -9,6 +9,7 @@ version: 1
|
|
|
9
9
|
workingDir: /home/user/repos/myproject
|
|
10
10
|
chrome: false
|
|
11
11
|
worktreeMode: prompt
|
|
12
|
+
respondOnlyWhenMentioned: false
|
|
12
13
|
|
|
13
14
|
platforms:
|
|
14
15
|
# Mattermost
|
|
@@ -41,6 +42,7 @@ platforms:
|
|
|
41
42
|
| `workingDir` | Default working directory for Claude | Current directory |
|
|
42
43
|
| `chrome` | Enable Chrome integration | `false` |
|
|
43
44
|
| `worktreeMode` | Git worktree mode: `off`, `prompt`, or `require` | `prompt` |
|
|
45
|
+
| `respondOnlyWhenMentioned` | Start new threads in quiet mode, where the bot only replies to messages that @mention it. Users can still toggle per-thread with `!mentions`. | `false` |
|
|
44
46
|
|
|
45
47
|
## Platform Settings
|
|
46
48
|
|