claude-threads 1.23.0 → 1.24.1
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 +109 -26
- package/dist/mcp/mcp-server.js +73 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ 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.24.1] - 2026-08-08
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Task lists no longer degrade to "Task #N" placeholders after a bot restart.** Modern CLIs stream tasks incrementally (`TaskCreate`/`TaskUpdate` with ids), and the bot accumulates them in a per-session `TaskTracker` — but that tracker lived only in memory. After a restart + resume, the first `TaskUpdate` of the next turn hit an empty tracker and rendered a placeholder ("Task #1") instead of the real subject, losing every task name for the rest of the session. The tracker's resolved tasks (id → subject/status) are now persisted to `sessions.json` at each turn end and restored on resume. In-flight creates (id not yet resolved from result text) are deliberately dropped at serialize time; pre-1.24.1 persisted sessions simply start with an empty tracker as before. Covered by a red-green integration test that restarts the bot mid-task-list and asserts the post-resume re-render still shows real subjects on both platform paths.
|
|
12
|
+
|
|
13
|
+
## [1.24.0] - 2026-08-08
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **`!model` and `!effort` — switch model or reasoning effort mid-session.** Verified against the real CLI (2.1.226): `/model` and `/effort` work over stream-json (`/model` with no args lists the options; `/model sonnet` switches "for this session only"; `/effort low|medium|high|xhigh|max|auto`), and both are listed in the CLI's `init.slash_commands` — so the bot's dynamic slash-command passthrough forwards `!model sonnet` / `!effort high` as-is and the CLI's confirmation posts to the thread. Both are now first-class registered commands with unconditional forwarding handlers (like `!context`/`!cost`/`!compact` — they work even before the CLI's init event arrives, and forward their argument: `!model sonnet` → `/model sonnet`), and `!help` gained a line pointing out that Claude Code slash commands work with `!`.
|
|
17
|
+
- **The session header now shows the model the session actually runs on.** Previously the header picked the "primary model" by highest cumulative cost — after a `!model` switch the old model keeps the larger spend, so the header kept naming the old model indefinitely. The per-turn `init.model` (re-emitted every turn, per the reference captures) is now authoritative. Model display names also cover the Claude 5 family via generic id parsing (`claude-sonnet-5` → "Sonnet 5", `claude-fable-5` → "Fable 5", dated ids still render as before).
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **Latest verified Claude CLI: 2.1.226** (from 2.1.223). The full verification battery ran against it this cycle: the decision-bridge e2e (4/4), all 17 reference captures re-recorded on 2.1.225/2.1.226, and both integration matrices. Install hints updated. Also verified while probing: `/cd` and `/add-dir` report "isn't available in this environment" over stream-json on 2.1.226 — a native in-session directory switch isn't possible, so `!cd` keeps its restart-based implementation.
|
|
21
|
+
|
|
8
22
|
## [1.23.0] - 2026-08-08
|
|
9
23
|
|
|
10
24
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -51319,7 +51319,7 @@ var COMMON_CLAUDE_PATHS = process.platform === "win32" ? [
|
|
|
51319
51319
|
var CLAUDE_CLI_MIN_VERSION = "2.0.74";
|
|
51320
51320
|
var CLAUDE_CLI_VERIFIED_RANGE = ">=2.0.74 <2.2.0";
|
|
51321
51321
|
var CLAUDE_CLI_SUPPORTED_MAJOR = 2;
|
|
51322
|
-
var CLAUDE_CLI_LATEST_VERIFIED = "2.1.
|
|
51322
|
+
var CLAUDE_CLI_LATEST_VERIFIED = "2.1.226";
|
|
51323
51323
|
function tryClaudeVersion(claudePath) {
|
|
51324
51324
|
try {
|
|
51325
51325
|
const output = execSync(`"${claudePath}" --version`, {
|
|
@@ -56301,16 +56301,23 @@ class ClaudeCli extends EventEmitter2 {
|
|
|
56301
56301
|
const trimmed = line.trim();
|
|
56302
56302
|
if (!trimmed)
|
|
56303
56303
|
continue;
|
|
56304
|
+
let event;
|
|
56305
|
+
try {
|
|
56306
|
+
event = JSON.parse(trimmed);
|
|
56307
|
+
} catch {
|
|
56308
|
+
continue;
|
|
56309
|
+
}
|
|
56304
56310
|
try {
|
|
56305
|
-
const event = JSON.parse(trimmed);
|
|
56306
56311
|
this.emit("event", event);
|
|
56307
|
-
|
|
56308
|
-
|
|
56309
|
-
|
|
56310
|
-
|
|
56311
|
-
|
|
56312
|
-
|
|
56313
|
-
|
|
56312
|
+
} catch (err) {
|
|
56313
|
+
this.log.error(`'event' listener threw while handling a ${event.type} event: ${err}`);
|
|
56314
|
+
}
|
|
56315
|
+
if (event.type === "result" && isErrorResultEvent(event)) {
|
|
56316
|
+
this.maybeEmitRateLimit(trimmed);
|
|
56317
|
+
}
|
|
56318
|
+
if (event.type === "rate_limit_event") {
|
|
56319
|
+
this.maybeEmitRateLimitHit(parseRateLimitEvent(event));
|
|
56320
|
+
}
|
|
56314
56321
|
}
|
|
56315
56322
|
}
|
|
56316
56323
|
maybeEmitRateLimit(text) {
|
|
@@ -57560,6 +57567,18 @@ var COMMAND_REGISTRY = [
|
|
|
57560
57567
|
description: "Compact conversation",
|
|
57561
57568
|
category: "passthrough",
|
|
57562
57569
|
audience: "both"
|
|
57570
|
+
},
|
|
57571
|
+
{
|
|
57572
|
+
command: "model",
|
|
57573
|
+
description: "Show or switch the model for this session (e.g. !model sonnet)",
|
|
57574
|
+
category: "passthrough",
|
|
57575
|
+
audience: "both"
|
|
57576
|
+
},
|
|
57577
|
+
{
|
|
57578
|
+
command: "effort",
|
|
57579
|
+
description: "Set reasoning effort: low|medium|high|xhigh|max|auto (e.g. !effort high)",
|
|
57580
|
+
category: "passthrough",
|
|
57581
|
+
audience: "both"
|
|
57563
57582
|
}
|
|
57564
57583
|
];
|
|
57565
57584
|
var REACTION_REGISTRY = [
|
|
@@ -57617,6 +57636,8 @@ var COMMAND_PATTERNS = [
|
|
|
57617
57636
|
["context", /^!context\s*$/i],
|
|
57618
57637
|
["cost", /^!cost\s*$/i],
|
|
57619
57638
|
["compact", /^!compact\s*$/i],
|
|
57639
|
+
["model", /^!model(?:\s+(\S+))?\s*$/i],
|
|
57640
|
+
["effort", /^!effort(?:\s+(\S+))?\s*$/i],
|
|
57620
57641
|
["plugin", /^!plugin(?:\s+(.+))?$/i],
|
|
57621
57642
|
["kill", /^!kill\s*$/i],
|
|
57622
57643
|
["bug", /^!bug(?:\s+(.+))?$/i],
|
|
@@ -57741,6 +57762,8 @@ ${formatter.formatBold("Reactions:")}
|
|
|
57741
57762
|
` + `${formatter.formatListItem(approvalReactions)}
|
|
57742
57763
|
` + `${formatter.formatListItem(sessionReactions)}
|
|
57743
57764
|
|
|
57765
|
+
` + `Claude Code slash commands work with ${code("!")} too — e.g. ${code("!model sonnet")}, ${code("!effort high")}, ${code("!compact")}, ${code("!context")}.
|
|
57766
|
+
|
|
57744
57767
|
` + formatSponsorFooter(formatter);
|
|
57745
57768
|
}
|
|
57746
57769
|
|
|
@@ -58122,12 +58145,13 @@ var handlePlugin = async (ctx, args) => {
|
|
|
58122
58145
|
return { handled: true };
|
|
58123
58146
|
};
|
|
58124
58147
|
function createPassthroughHandler(slashCommand) {
|
|
58125
|
-
return async (ctx) => {
|
|
58148
|
+
return async (ctx, args) => {
|
|
58126
58149
|
if (ctx.commandContext === "first-message") {
|
|
58127
58150
|
return { handled: false };
|
|
58128
58151
|
}
|
|
58129
58152
|
if (ctx.isAllowed) {
|
|
58130
|
-
|
|
58153
|
+
const full = args ? `/${slashCommand} ${args}` : `/${slashCommand}`;
|
|
58154
|
+
await ctx.sessionManager.sendFollowUp(ctx.threadId, full, undefined, undefined, undefined, { system: true });
|
|
58131
58155
|
}
|
|
58132
58156
|
return { handled: true };
|
|
58133
58157
|
};
|
|
@@ -58150,6 +58174,8 @@ handlers.set("plugin", handlePlugin);
|
|
|
58150
58174
|
handlers.set("context", createPassthroughHandler("context"));
|
|
58151
58175
|
handlers.set("cost", createPassthroughHandler("cost"));
|
|
58152
58176
|
handlers.set("compact", createPassthroughHandler("compact"));
|
|
58177
|
+
handlers.set("model", createPassthroughHandler("model"));
|
|
58178
|
+
handlers.set("effort", createPassthroughHandler("effort"));
|
|
58153
58179
|
async function executeCommand(command, args, ctx) {
|
|
58154
58180
|
const cmdDef = getCommandDef(command);
|
|
58155
58181
|
if (!cmdDef) {
|
|
@@ -65021,6 +65047,7 @@ function truncateAtWord2(text, maxLength) {
|
|
|
65021
65047
|
return truncated + "...";
|
|
65022
65048
|
}
|
|
65023
65049
|
// src/operations/task-tracker.ts
|
|
65050
|
+
var VALID_STATUSES = new Set(["pending", "in_progress", "completed"]);
|
|
65024
65051
|
var CREATED_RESULT_RE = /Task #(\S+) created/;
|
|
65025
65052
|
|
|
65026
65053
|
class TaskTracker {
|
|
@@ -65114,6 +65141,38 @@ class TaskTracker {
|
|
|
65114
65141
|
this.pendingCreates.clear();
|
|
65115
65142
|
this.unmatchedCreateResults = 0;
|
|
65116
65143
|
}
|
|
65144
|
+
serialize() {
|
|
65145
|
+
const restorable = this.tasks.filter((t) => Boolean(t.taskId));
|
|
65146
|
+
if (restorable.length === 0)
|
|
65147
|
+
return;
|
|
65148
|
+
return restorable.map((t) => {
|
|
65149
|
+
const out = {
|
|
65150
|
+
taskId: t.taskId,
|
|
65151
|
+
subject: t.subject,
|
|
65152
|
+
status: t.status
|
|
65153
|
+
};
|
|
65154
|
+
if (t.activeForm)
|
|
65155
|
+
out.activeForm = t.activeForm;
|
|
65156
|
+
if (t.isPlaceholder)
|
|
65157
|
+
out.isPlaceholder = true;
|
|
65158
|
+
return out;
|
|
65159
|
+
});
|
|
65160
|
+
}
|
|
65161
|
+
restore(state) {
|
|
65162
|
+
if (!Array.isArray(state)) {
|
|
65163
|
+
this.tasks = [];
|
|
65164
|
+
this.pendingCreates.clear();
|
|
65165
|
+
return;
|
|
65166
|
+
}
|
|
65167
|
+
this.tasks = state.filter((t) => t !== null && typeof t === "object" && typeof t.taskId === "string" && t.taskId.length > 0 && typeof t.subject === "string").map((t) => ({
|
|
65168
|
+
taskId: t.taskId,
|
|
65169
|
+
subject: t.subject || `Task #${t.taskId}`,
|
|
65170
|
+
activeForm: typeof t.activeForm === "string" ? t.activeForm : undefined,
|
|
65171
|
+
status: VALID_STATUSES.has(t.status) ? t.status : "pending",
|
|
65172
|
+
isPlaceholder: t.isPlaceholder === true ? true : undefined
|
|
65173
|
+
}));
|
|
65174
|
+
this.pendingCreates.clear();
|
|
65175
|
+
}
|
|
65117
65176
|
}
|
|
65118
65177
|
|
|
65119
65178
|
// src/operations/executors/base.ts
|
|
@@ -67208,9 +67267,15 @@ class MessageManager {
|
|
|
67208
67267
|
serialize() {
|
|
67209
67268
|
return {
|
|
67210
67269
|
taskList: this.taskListExecutor.serialize(),
|
|
67270
|
+
taskTracker: this.taskTracker.serialize(),
|
|
67211
67271
|
contextPrompt: this.promptExecutor.serialize()
|
|
67212
67272
|
};
|
|
67213
67273
|
}
|
|
67274
|
+
restoreTaskTracker(state) {
|
|
67275
|
+
if (state && state.length > 0) {
|
|
67276
|
+
this.taskTracker.restore(state);
|
|
67277
|
+
}
|
|
67278
|
+
}
|
|
67214
67279
|
hydrateTaskListState(persisted) {
|
|
67215
67280
|
this.taskListExecutor.hydrateState(persisted);
|
|
67216
67281
|
}
|
|
@@ -68841,6 +68906,9 @@ function handleEventPreProcessing(session, event, ctx) {
|
|
|
68841
68906
|
}
|
|
68842
68907
|
if (event.type === "system") {
|
|
68843
68908
|
const e = event;
|
|
68909
|
+
if (e.subtype === "init" && typeof e.model === "string") {
|
|
68910
|
+
session.currentModel = e.model;
|
|
68911
|
+
}
|
|
68844
68912
|
if (e.subtype === "init" && e.slash_commands && Array.isArray(e.slash_commands)) {
|
|
68845
68913
|
session.availableSlashCommands = new Set(e.slash_commands.map((cmd) => cmd.startsWith("/") ? cmd.slice(1) : cmd));
|
|
68846
68914
|
sessionLog3(session).info(`Captured ${session.availableSlashCommands.size} slash commands from init: ${[...session.availableSlashCommands].join(", ")}`);
|
|
@@ -68882,7 +68950,7 @@ function handleEventPreProcessing(session, event, ctx) {
|
|
|
68882
68950
|
trackEvent(session, "tool_use", tool.name);
|
|
68883
68951
|
}
|
|
68884
68952
|
}
|
|
68885
|
-
function handleEventPostProcessing(session, event, ctx) {
|
|
68953
|
+
function handleEventPostProcessing(session, event, ctx, mainHandling) {
|
|
68886
68954
|
if (event.type === "assistant") {
|
|
68887
68955
|
const msg = event.message;
|
|
68888
68956
|
for (const block of msg?.content || []) {
|
|
@@ -68899,6 +68967,11 @@ function handleEventPostProcessing(session, event, ctx) {
|
|
|
68899
68967
|
session.isProcessing = false;
|
|
68900
68968
|
ctx.ops.emitSessionUpdate(session.sessionId, { status: getSessionStatus(session) });
|
|
68901
68969
|
updateUsageStats(session, event, ctx);
|
|
68970
|
+
if (mainHandling) {
|
|
68971
|
+
mainHandling.catch(() => {}).then(() => ctx.ops.persistSession(session));
|
|
68972
|
+
} else {
|
|
68973
|
+
ctx.ops.persistSession(session);
|
|
68974
|
+
}
|
|
68902
68975
|
}
|
|
68903
68976
|
if (event.type === "user" && !isSidechainEvent(event)) {
|
|
68904
68977
|
const msg = event.message;
|
|
@@ -68975,20 +69048,15 @@ async function handleCompactionComplete(session, compactMetadata, _ctx) {
|
|
|
68975
69048
|
}
|
|
68976
69049
|
}
|
|
68977
69050
|
function getModelDisplayName(modelId) {
|
|
68978
|
-
|
|
68979
|
-
|
|
68980
|
-
|
|
68981
|
-
return
|
|
68982
|
-
|
|
68983
|
-
return "Opus";
|
|
68984
|
-
if (modelId.includes("sonnet-4"))
|
|
68985
|
-
return "Sonnet 4";
|
|
68986
|
-
if (modelId.includes("sonnet-3-5") || modelId.includes("sonnet-3.5"))
|
|
68987
|
-
return "Sonnet 3.5";
|
|
69051
|
+
const modern = modelId.match(/^claude-([a-z]+)-(\d+)(?:-(\d{1,2}))?(?:-\d{8})?$/);
|
|
69052
|
+
if (modern) {
|
|
69053
|
+
const family = modern[1].charAt(0).toUpperCase() + modern[1].slice(1);
|
|
69054
|
+
return modern[3] ? `${family} ${modern[2]}.${modern[3]}` : `${family} ${modern[2]}`;
|
|
69055
|
+
}
|
|
68988
69056
|
if (modelId.includes("sonnet"))
|
|
68989
69057
|
return "Sonnet";
|
|
68990
|
-
if (modelId.includes("
|
|
68991
|
-
return "
|
|
69058
|
+
if (modelId.includes("opus"))
|
|
69059
|
+
return "Opus";
|
|
68992
69060
|
if (modelId.includes("haiku"))
|
|
68993
69061
|
return "Haiku";
|
|
68994
69062
|
const match = modelId.match(/claude-(\w+)/);
|
|
@@ -69019,6 +69087,10 @@ function updateUsageStats(session, event, ctx) {
|
|
|
69019
69087
|
contextWindowSize = usage.contextWindow;
|
|
69020
69088
|
}
|
|
69021
69089
|
}
|
|
69090
|
+
if (session.currentModel && result.modelUsage[session.currentModel]) {
|
|
69091
|
+
primaryModel = session.currentModel;
|
|
69092
|
+
contextWindowSize = result.modelUsage[session.currentModel].contextWindow;
|
|
69093
|
+
}
|
|
69022
69094
|
let contextTokens = 0;
|
|
69023
69095
|
if (result.usage) {
|
|
69024
69096
|
contextTokens = result.usage.input_tokens + result.usage.cache_creation_input_tokens + result.usage.cache_read_input_tokens;
|
|
@@ -70856,6 +70928,7 @@ Please start a new session.`), { action: "Post resume failure notification" });
|
|
|
70856
70928
|
tasksCompleted: state.tasksCompleted,
|
|
70857
70929
|
tasksMinimized: state.tasksMinimized
|
|
70858
70930
|
});
|
|
70931
|
+
session.messageManager.restoreTaskTracker(state.taskTrackerState);
|
|
70859
70932
|
const persistedWithInteractive = state;
|
|
70860
70933
|
if (persistedWithInteractive.pendingQuestionSet || persistedWithInteractive.pendingApproval) {
|
|
70861
70934
|
session.messageManager.hydrateInteractiveState({
|
|
@@ -71806,8 +71879,8 @@ class SessionManager extends EventEmitter4 {
|
|
|
71806
71879
|
if (!session || !session.messageManager)
|
|
71807
71880
|
return;
|
|
71808
71881
|
handleEventPreProcessing(session, event, this.getContext());
|
|
71809
|
-
session.messageManager.handleEvent(event);
|
|
71810
|
-
handleEventPostProcessing(session, event, this.getContext());
|
|
71882
|
+
const mainHandling = session.messageManager.handleEvent(event);
|
|
71883
|
+
handleEventPostProcessing(session, event, this.getContext(), mainHandling);
|
|
71811
71884
|
}
|
|
71812
71885
|
async handleExit(sessionId, code, source) {
|
|
71813
71886
|
await handleExit(sessionId, code, this.getContext(), source);
|
|
@@ -71845,11 +71918,20 @@ class SessionManager extends EventEmitter4 {
|
|
|
71845
71918
|
this.stopTyping(session);
|
|
71846
71919
|
}
|
|
71847
71920
|
persistSession(session) {
|
|
71921
|
+
try {
|
|
71922
|
+
this.persistSessionUnsafe(session);
|
|
71923
|
+
} catch (err) {
|
|
71924
|
+
log35.error(`Failed to persist session ${session.sessionId}: ${err}`);
|
|
71925
|
+
}
|
|
71926
|
+
}
|
|
71927
|
+
persistSessionUnsafe(session) {
|
|
71848
71928
|
let taskListSnapshot;
|
|
71849
71929
|
let contextPromptSnapshot;
|
|
71930
|
+
let taskTrackerSnapshot;
|
|
71850
71931
|
if (session.messageManager) {
|
|
71851
71932
|
const serialized = session.messageManager.serialize();
|
|
71852
71933
|
taskListSnapshot = serialized.taskList;
|
|
71934
|
+
taskTrackerSnapshot = serialized.taskTracker;
|
|
71853
71935
|
if (serialized.contextPrompt) {
|
|
71854
71936
|
contextPromptSnapshot = serialized.contextPrompt;
|
|
71855
71937
|
}
|
|
@@ -71874,6 +71956,7 @@ class SessionManager extends EventEmitter4 {
|
|
|
71874
71956
|
lastTasksContent: taskListSnapshot?.content ?? null,
|
|
71875
71957
|
tasksCompleted: taskListSnapshot?.isCompleted ?? false,
|
|
71876
71958
|
tasksMinimized: taskListSnapshot?.isMinimized ?? false,
|
|
71959
|
+
taskTrackerState: taskTrackerSnapshot,
|
|
71877
71960
|
worktreeInfo: session.worktreeInfo,
|
|
71878
71961
|
isWorktreeOwner: session.isWorktreeOwner,
|
|
71879
71962
|
pendingWorktreePrompt: session.pendingWorktreePrompt,
|
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -49412,6 +49412,7 @@ function truncateAtWord(text, maxLength) {
|
|
|
49412
49412
|
return truncated + "...";
|
|
49413
49413
|
}
|
|
49414
49414
|
// src/operations/task-tracker.ts
|
|
49415
|
+
var VALID_STATUSES = new Set(["pending", "in_progress", "completed"]);
|
|
49415
49416
|
var CREATED_RESULT_RE = /Task #(\S+) created/;
|
|
49416
49417
|
|
|
49417
49418
|
class TaskTracker {
|
|
@@ -49505,6 +49506,38 @@ class TaskTracker {
|
|
|
49505
49506
|
this.pendingCreates.clear();
|
|
49506
49507
|
this.unmatchedCreateResults = 0;
|
|
49507
49508
|
}
|
|
49509
|
+
serialize() {
|
|
49510
|
+
const restorable = this.tasks.filter((t) => Boolean(t.taskId));
|
|
49511
|
+
if (restorable.length === 0)
|
|
49512
|
+
return;
|
|
49513
|
+
return restorable.map((t) => {
|
|
49514
|
+
const out = {
|
|
49515
|
+
taskId: t.taskId,
|
|
49516
|
+
subject: t.subject,
|
|
49517
|
+
status: t.status
|
|
49518
|
+
};
|
|
49519
|
+
if (t.activeForm)
|
|
49520
|
+
out.activeForm = t.activeForm;
|
|
49521
|
+
if (t.isPlaceholder)
|
|
49522
|
+
out.isPlaceholder = true;
|
|
49523
|
+
return out;
|
|
49524
|
+
});
|
|
49525
|
+
}
|
|
49526
|
+
restore(state) {
|
|
49527
|
+
if (!Array.isArray(state)) {
|
|
49528
|
+
this.tasks = [];
|
|
49529
|
+
this.pendingCreates.clear();
|
|
49530
|
+
return;
|
|
49531
|
+
}
|
|
49532
|
+
this.tasks = state.filter((t) => t !== null && typeof t === "object" && typeof t.taskId === "string" && t.taskId.length > 0 && typeof t.subject === "string").map((t) => ({
|
|
49533
|
+
taskId: t.taskId,
|
|
49534
|
+
subject: t.subject || `Task #${t.taskId}`,
|
|
49535
|
+
activeForm: typeof t.activeForm === "string" ? t.activeForm : undefined,
|
|
49536
|
+
status: VALID_STATUSES.has(t.status) ? t.status : "pending",
|
|
49537
|
+
isPlaceholder: t.isPlaceholder === true ? true : undefined
|
|
49538
|
+
}));
|
|
49539
|
+
this.pendingCreates.clear();
|
|
49540
|
+
}
|
|
49508
49541
|
}
|
|
49509
49542
|
|
|
49510
49543
|
// src/operations/executors/base.ts
|
|
@@ -51908,9 +51941,15 @@ class MessageManager {
|
|
|
51908
51941
|
serialize() {
|
|
51909
51942
|
return {
|
|
51910
51943
|
taskList: this.taskListExecutor.serialize(),
|
|
51944
|
+
taskTracker: this.taskTracker.serialize(),
|
|
51911
51945
|
contextPrompt: this.promptExecutor.serialize()
|
|
51912
51946
|
};
|
|
51913
51947
|
}
|
|
51948
|
+
restoreTaskTracker(state) {
|
|
51949
|
+
if (state && state.length > 0) {
|
|
51950
|
+
this.taskTracker.restore(state);
|
|
51951
|
+
}
|
|
51952
|
+
}
|
|
51914
51953
|
hydrateTaskListState(persisted) {
|
|
51915
51954
|
this.taskListExecutor.hydrateState(persisted);
|
|
51916
51955
|
}
|
|
@@ -56409,16 +56448,23 @@ class ClaudeCli extends EventEmitter2 {
|
|
|
56409
56448
|
const trimmed = line.trim();
|
|
56410
56449
|
if (!trimmed)
|
|
56411
56450
|
continue;
|
|
56451
|
+
let event;
|
|
56452
|
+
try {
|
|
56453
|
+
event = JSON.parse(trimmed);
|
|
56454
|
+
} catch {
|
|
56455
|
+
continue;
|
|
56456
|
+
}
|
|
56412
56457
|
try {
|
|
56413
|
-
const event = JSON.parse(trimmed);
|
|
56414
56458
|
this.emit("event", event);
|
|
56415
|
-
|
|
56416
|
-
|
|
56417
|
-
|
|
56418
|
-
|
|
56419
|
-
|
|
56420
|
-
|
|
56421
|
-
|
|
56459
|
+
} catch (err) {
|
|
56460
|
+
this.log.error(`'event' listener threw while handling a ${event.type} event: ${err}`);
|
|
56461
|
+
}
|
|
56462
|
+
if (event.type === "result" && isErrorResultEvent(event)) {
|
|
56463
|
+
this.maybeEmitRateLimit(trimmed);
|
|
56464
|
+
}
|
|
56465
|
+
if (event.type === "rate_limit_event") {
|
|
56466
|
+
this.maybeEmitRateLimitHit(parseRateLimitEvent(event));
|
|
56467
|
+
}
|
|
56422
56468
|
}
|
|
56423
56469
|
}
|
|
56424
56470
|
maybeEmitRateLimit(text) {
|
|
@@ -56734,6 +56780,18 @@ var COMMAND_REGISTRY = [
|
|
|
56734
56780
|
description: "Compact conversation",
|
|
56735
56781
|
category: "passthrough",
|
|
56736
56782
|
audience: "both"
|
|
56783
|
+
},
|
|
56784
|
+
{
|
|
56785
|
+
command: "model",
|
|
56786
|
+
description: "Show or switch the model for this session (e.g. !model sonnet)",
|
|
56787
|
+
category: "passthrough",
|
|
56788
|
+
audience: "both"
|
|
56789
|
+
},
|
|
56790
|
+
{
|
|
56791
|
+
command: "effort",
|
|
56792
|
+
description: "Set reasoning effort: low|medium|high|xhigh|max|auto (e.g. !effort high)",
|
|
56793
|
+
category: "passthrough",
|
|
56794
|
+
audience: "both"
|
|
56737
56795
|
}
|
|
56738
56796
|
];
|
|
56739
56797
|
var REACTION_REGISTRY = [
|
|
@@ -56806,6 +56864,8 @@ ${formatter.formatBold("Reactions:")}
|
|
|
56806
56864
|
` + `${formatter.formatListItem(approvalReactions)}
|
|
56807
56865
|
` + `${formatter.formatListItem(sessionReactions)}
|
|
56808
56866
|
|
|
56867
|
+
` + `Claude Code slash commands work with ${code("!")} too — e.g. ${code("!model sonnet")}, ${code("!effort high")}, ${code("!compact")}, ${code("!context")}.
|
|
56868
|
+
|
|
56809
56869
|
` + formatSponsorFooter(formatter);
|
|
56810
56870
|
}
|
|
56811
56871
|
|
|
@@ -57072,12 +57132,13 @@ var handlePlugin = async (ctx, args) => {
|
|
|
57072
57132
|
return { handled: true };
|
|
57073
57133
|
};
|
|
57074
57134
|
function createPassthroughHandler(slashCommand) {
|
|
57075
|
-
return async (ctx) => {
|
|
57135
|
+
return async (ctx, args) => {
|
|
57076
57136
|
if (ctx.commandContext === "first-message") {
|
|
57077
57137
|
return { handled: false };
|
|
57078
57138
|
}
|
|
57079
57139
|
if (ctx.isAllowed) {
|
|
57080
|
-
|
|
57140
|
+
const full = args ? `/${slashCommand} ${args}` : `/${slashCommand}`;
|
|
57141
|
+
await ctx.sessionManager.sendFollowUp(ctx.threadId, full, undefined, undefined, undefined, { system: true });
|
|
57081
57142
|
}
|
|
57082
57143
|
return { handled: true };
|
|
57083
57144
|
};
|
|
@@ -57100,6 +57161,8 @@ handlers.set("plugin", handlePlugin);
|
|
|
57100
57161
|
handlers.set("context", createPassthroughHandler("context"));
|
|
57101
57162
|
handlers.set("cost", createPassthroughHandler("cost"));
|
|
57102
57163
|
handlers.set("compact", createPassthroughHandler("compact"));
|
|
57164
|
+
handlers.set("model", createPassthroughHandler("model"));
|
|
57165
|
+
handlers.set("effort", createPassthroughHandler("effort"));
|
|
57103
57166
|
// src/commands/system-prompt-generator.ts
|
|
57104
57167
|
var log9 = createLogger("system-prompt");
|
|
57105
57168
|
function formatUserCommand(cmd) {
|
package/package.json
CHANGED