claude-code-rust 0.13.4 → 0.14.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/README.md +20 -9
- package/agent-sdk/dist/bridge/command_dispatch.js +19 -1
- package/agent-sdk/dist/bridge/commands.js +4 -0
- package/agent-sdk/dist/bridge/message_handlers.js +15 -1
- package/agent-sdk/dist/bridge/session_lifecycle.js +2 -0
- package/agent-sdk/dist/bridge/tasks.js +40 -0
- package/agent-sdk/dist/bridge/tool_calls.js +6 -0
- package/agent-sdk/dist/bridge/tooling.js +0 -1
- package/agent-sdk/dist/bridge.js +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -16,28 +16,39 @@ A native Rust terminal interface for Claude Code. Drop-in replacement for Anthro
|
|
|
16
16
|
|
|
17
17
|
Claude Code Rust replaces the stock Claude Code terminal interface with a native Rust binary built on [Ratatui](https://ratatui.rs/). It connects to the same Claude API through a local Agent SDK bridge. Core Claude Code functionality - tool calls, file editing, terminal commands, and permissions - works unchanged.
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Prerequisite
|
|
20
20
|
|
|
21
|
-
-
|
|
21
|
+
- Install the Claude Code CLI. You do not need to authenticate before installing or starting `claude-rs`; sign in later with `/login` or `claude auth login` when needed.
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
|
-
###
|
|
25
|
+
### Install script (recommended, v0.14.0+)
|
|
26
|
+
|
|
27
|
+
The install script downloads a complete GitHub Release archive. It does not require Rust, Node.js, npm, or Bun on the user's machine.
|
|
28
|
+
|
|
29
|
+
**macOS/Linux:**
|
|
26
30
|
|
|
27
31
|
```bash
|
|
28
|
-
|
|
32
|
+
curl -fsSL https://raw.githubusercontent.com/srothgan/claude-code-rust/main/scripts/install/install.sh | sh
|
|
29
33
|
```
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
**Windows PowerShell:**
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
```powershell
|
|
38
|
+
powershell -NoProfile -ExecutionPolicy Bypass -Command "irm 'https://raw.githubusercontent.com/srothgan/claude-code-rust/main/scripts/install/install.ps1' | iex"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### npm (global)
|
|
42
|
+
|
|
43
|
+
npm remains supported for users who prefer package-manager ownership of the global command:
|
|
34
44
|
|
|
35
45
|
```bash
|
|
36
|
-
npm config get omit
|
|
37
46
|
npm install -g claude-code-rust
|
|
38
47
|
```
|
|
39
48
|
|
|
40
|
-
|
|
49
|
+
This option requires Node.js 24 and npm. The npm package installs a small launcher plus a platform-specific optional dependency containing the prebuilt Rust binary, Agent SDK bridge, and bundled private Bun runtime for your OS and architecture. A separate Rust toolchain or Bun installation is not required.
|
|
50
|
+
|
|
51
|
+
See the [installation guide](https://srothgan.github.io/claude-code-rust/installation.html) for release pinning, custom locations, switching install methods, and troubleshooting.
|
|
41
52
|
|
|
42
53
|
## Usage
|
|
43
54
|
|
|
@@ -66,7 +77,7 @@ Claude Code Rust addresses these with a native terminal UI that uses diffed, dir
|
|
|
66
77
|
|
|
67
78
|
## Documentation
|
|
68
79
|
|
|
69
|
-
The manual covers installation
|
|
80
|
+
The manual covers installation with scripts, npm, and source builds, plus help, slash commands, keyboard shortcuts, settings, diagnostics, architecture, and the changelog:
|
|
70
81
|
|
|
71
82
|
- [Installation](https://srothgan.github.io/claude-code-rust/installation.html)
|
|
72
83
|
- [Usage](https://srothgan.github.io/claude-code-rust/usage.html)
|
|
@@ -1,8 +1,26 @@
|
|
|
1
|
+
import { bridgeLogger, LOG_TARGETS } from "./logger.js";
|
|
1
2
|
export async function dispatchCancelTurnCommand(command, deps) {
|
|
2
3
|
const session = deps.sessionById(command.session_id);
|
|
3
4
|
if (!session) {
|
|
4
5
|
deps.slashError(command.session_id, `unknown session: ${command.session_id}`, deps.requestId);
|
|
5
6
|
return;
|
|
6
7
|
}
|
|
7
|
-
await session.query.interrupt();
|
|
8
|
+
const receipt = await session.query.interrupt();
|
|
9
|
+
const stillQueued = Array.isArray(receipt?.still_queued)
|
|
10
|
+
? receipt.still_queued.filter((entry) => typeof entry === "string")
|
|
11
|
+
: [];
|
|
12
|
+
if (stillQueued.length > 0) {
|
|
13
|
+
bridgeLogger.info({
|
|
14
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
15
|
+
eventName: "interrupt_receipt_still_queued",
|
|
16
|
+
message: "interrupt receipt reported queued async messages",
|
|
17
|
+
outcome: "success",
|
|
18
|
+
sessionId: command.session_id,
|
|
19
|
+
...(deps.requestId ? { requestId: deps.requestId } : {}),
|
|
20
|
+
fields: {
|
|
21
|
+
still_queued_count: stillQueued.length,
|
|
22
|
+
still_queued: stillQueued,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
}
|
|
8
26
|
}
|
|
@@ -307,6 +307,7 @@ export function parseCommandEnvelope(line) {
|
|
|
307
307
|
session_id: expectString(raw, "session_id", "reload_plugins"),
|
|
308
308
|
};
|
|
309
309
|
case "mcp_status":
|
|
310
|
+
// Rust historically sends `get_mcp_snapshot`; normalize it to the bridge-internal command.
|
|
310
311
|
case "get_mcp_snapshot":
|
|
311
312
|
return {
|
|
312
313
|
command: "mcp_status",
|
|
@@ -450,6 +451,9 @@ function parseQuestionAnnotation(value) {
|
|
|
450
451
|
};
|
|
451
452
|
}
|
|
452
453
|
export function toPermissionMode(mode) {
|
|
454
|
+
if (mode === "manual") {
|
|
455
|
+
return "default";
|
|
456
|
+
}
|
|
453
457
|
if (mode === "default" ||
|
|
454
458
|
mode === "auto" ||
|
|
455
459
|
mode === "acceptEdits" ||
|
|
@@ -3,7 +3,7 @@ import { toPermissionMode, buildModeState, refreshSupportedModesForSession } fro
|
|
|
3
3
|
import { writeEvent, emitSessionUpdate, emitConnectEvent, emitSessionReplacedEvent, } from "./events.js";
|
|
4
4
|
import { TOOL_RESULT_TYPES, isToolSearchToolName, isToolSearchToolResultType, unwrapToolUseResult, } from "./tooling.js";
|
|
5
5
|
import { emitToolCall, emitToolCallUpdate, emitToolResultUpdate, finalizeOpenToolCalls, emitToolProgressUpdate, emitToolSummaryUpdate, ensureToolCallVisible, resolveTaskToolUseId, defersTaskNotificationCompletion, toolAcceptsTaskLifecycle, taskProgressText, taskUpdatedFields, } from "./tool_calls.js";
|
|
6
|
-
import { applyTaskLifecycleState } from "./tasks.js";
|
|
6
|
+
import { applyBackgroundTasksChanged, applyTaskLifecycleState } from "./tasks.js";
|
|
7
7
|
import { linkTaskToolUse, unlinkTaskToolUse } from "./task_links.js";
|
|
8
8
|
import { emitAuthRequired, classifyTurnErrorKind, emitFastModeUpdateIfChanged } from "./error_classification.js";
|
|
9
9
|
import { mapAvailableAgentsFromNames, emitAvailableAgentsIfChanged, refreshAvailableAgents } from "./agents.js";
|
|
@@ -39,6 +39,7 @@ function sdkCorrelationMetadata(msg) {
|
|
|
39
39
|
requestId: typeof msg.request_id === "string" ? msg.request_id : undefined,
|
|
40
40
|
subagentType: typeof msg.subagent_type === "string" ? msg.subagent_type : undefined,
|
|
41
41
|
taskDescription: typeof msg.task_description === "string" ? msg.task_description : undefined,
|
|
42
|
+
parentAgentId: typeof msg.parent_agent_id === "string" ? msg.parent_agent_id : undefined,
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
function sdkTaskMetadata(msg) {
|
|
@@ -53,12 +54,14 @@ function sdkTaskMetadata(msg) {
|
|
|
53
54
|
...(metadata.requestId ? { request_id: metadata.requestId } : {}),
|
|
54
55
|
...(metadata.subagentType ? { subagent_type: metadata.subagentType } : {}),
|
|
55
56
|
...(metadata.taskDescription ? { task_description: metadata.taskDescription } : {}),
|
|
57
|
+
...(metadata.parentAgentId ? { parent_agent_id: metadata.parentAgentId } : {}),
|
|
56
58
|
...(taskType ? { task_type: taskType } : {}),
|
|
57
59
|
...(workflowName ? { workflow_name: workflowName } : {}),
|
|
58
60
|
...(prompt ? { prompt } : {}),
|
|
59
61
|
...(outputFile ? { output_file: outputFile } : {}),
|
|
60
62
|
...(summary ? { summary } : {}),
|
|
61
63
|
...(status ? { terminal_status: status } : {}),
|
|
64
|
+
...(typeof msg.blocked === "boolean" ? { blocked: msg.blocked } : {}),
|
|
62
65
|
};
|
|
63
66
|
return Object.keys(taskMetadata).length > 0 ? taskMetadata : undefined;
|
|
64
67
|
}
|
|
@@ -822,6 +825,13 @@ function terminalReasonFromValue(value) {
|
|
|
822
825
|
case "hook_stopped":
|
|
823
826
|
case "tool_deferred":
|
|
824
827
|
case "max_turns":
|
|
828
|
+
case "background_requested":
|
|
829
|
+
case "api_error":
|
|
830
|
+
case "malformed_tool_use_exhausted":
|
|
831
|
+
case "budget_exhausted":
|
|
832
|
+
case "structured_output_retry_exhausted":
|
|
833
|
+
case "tool_deferred_unavailable":
|
|
834
|
+
case "turn_setup_failed":
|
|
825
835
|
case "completed":
|
|
826
836
|
return value;
|
|
827
837
|
default:
|
|
@@ -848,6 +858,10 @@ export function handleSdkMessage(session, message) {
|
|
|
848
858
|
updateAvailableCommands(session, "commands_changed", mapSdkSlashCommands(msg.commands));
|
|
849
859
|
return;
|
|
850
860
|
}
|
|
861
|
+
if (subtype === "background_tasks_changed") {
|
|
862
|
+
applyBackgroundTasksChanged(session, msg);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
851
865
|
if (subtype === "notification") {
|
|
852
866
|
const text = typeof msg.text === "string" ? msg.text : "";
|
|
853
867
|
emitSystemNoticeUpdate(session, notificationSeverity(msg.priority), text);
|
|
@@ -9,6 +9,7 @@ const TASK_TOOL_NAMES = new Set([
|
|
|
9
9
|
"TaskOutput",
|
|
10
10
|
"TaskStop",
|
|
11
11
|
]);
|
|
12
|
+
const BACKGROUND_TASK_METADATA_KEY = "sdk_background_task";
|
|
12
13
|
export function isTaskToolName(name) {
|
|
13
14
|
return TASK_TOOL_NAMES.has(name);
|
|
14
15
|
}
|
|
@@ -806,6 +807,8 @@ function lifecycleMetadata(msg) {
|
|
|
806
807
|
"summary",
|
|
807
808
|
"end_time",
|
|
808
809
|
"total_paused_ms",
|
|
810
|
+
"blocked",
|
|
811
|
+
"parent_agent_id",
|
|
809
812
|
]) {
|
|
810
813
|
copyValue(msg, key);
|
|
811
814
|
copyValue(patch, key);
|
|
@@ -857,6 +860,43 @@ export function applyTaskLifecycleState(session, subtype, msg) {
|
|
|
857
860
|
}),
|
|
858
861
|
]);
|
|
859
862
|
}
|
|
863
|
+
export function applyBackgroundTasksChanged(session, msg) {
|
|
864
|
+
const rawTasks = Array.isArray(msg.tasks) ? msg.tasks : [];
|
|
865
|
+
const nextTasks = rawTasks
|
|
866
|
+
.map((entry) => {
|
|
867
|
+
const task = asRecordOrNull(entry);
|
|
868
|
+
const taskId = nonEmptyString(task?.task_id);
|
|
869
|
+
if (!task || !taskId) {
|
|
870
|
+
return undefined;
|
|
871
|
+
}
|
|
872
|
+
const taskType = nonEmptyString(task.task_type);
|
|
873
|
+
const description = nonEmptyString(task.description);
|
|
874
|
+
return {
|
|
875
|
+
task_id: taskId,
|
|
876
|
+
subject: description ?? taskType ?? taskId,
|
|
877
|
+
description,
|
|
878
|
+
status: "in_progress",
|
|
879
|
+
blocks: [],
|
|
880
|
+
blocked_by: [],
|
|
881
|
+
metadata: {
|
|
882
|
+
[BACKGROUND_TASK_METADATA_KEY]: true,
|
|
883
|
+
...(taskType ? { task_type: taskType } : {}),
|
|
884
|
+
},
|
|
885
|
+
};
|
|
886
|
+
})
|
|
887
|
+
.filter((task) => Boolean(task));
|
|
888
|
+
const nextIds = new Set(nextTasks.map((task) => task.task_id));
|
|
889
|
+
const removedTaskIds = session.taskOrder.filter((taskId) => {
|
|
890
|
+
if (nextIds.has(taskId)) {
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
const metadata = asRecordOrNull(session.tasksById.get(taskId)?.metadata);
|
|
894
|
+
return metadata?.[BACKGROUND_TASK_METADATA_KEY] === true;
|
|
895
|
+
});
|
|
896
|
+
const tasks = nextTasks.map((task) => upsertTask(session, task));
|
|
897
|
+
const removed = removeTasks(session, removedTaskIds);
|
|
898
|
+
emitTaskStateUpdate(session, "background_tasks", tasks, removed, true);
|
|
899
|
+
}
|
|
860
900
|
export function currentTaskSnapshot(session) {
|
|
861
901
|
return orderedTasks(session);
|
|
862
902
|
}
|
|
@@ -423,6 +423,12 @@ function buildTaskMetadata(patch) {
|
|
|
423
423
|
if (typeof patch.status === "string" && ["completed", "failed", "killed"].includes(patch.status)) {
|
|
424
424
|
taskMetadata.terminal_status = patch.status;
|
|
425
425
|
}
|
|
426
|
+
if (typeof patch.blocked === "boolean") {
|
|
427
|
+
taskMetadata.blocked = patch.blocked;
|
|
428
|
+
}
|
|
429
|
+
if (typeof patch.parent_agent_id === "string" && patch.parent_agent_id.length > 0) {
|
|
430
|
+
taskMetadata.parent_agent_id = patch.parent_agent_id;
|
|
431
|
+
}
|
|
426
432
|
return Object.keys(taskMetadata).length > 0 ? taskMetadata : undefined;
|
|
427
433
|
}
|
|
428
434
|
export function taskUpdatedFields(msg) {
|
|
@@ -261,7 +261,6 @@ export function toolTitle(name, input, context = {}) {
|
|
|
261
261
|
return label ? `${ARTIFACT_TOOL_NAME}: ${label}` : ARTIFACT_TOOL_NAME;
|
|
262
262
|
}
|
|
263
263
|
if (name === SHOW_ONBOARDING_ROLE_PICKER_TOOL_NAME) {
|
|
264
|
-
// TODO: The TUI accepts this SDK tool call but does not implement an onboarding role flow yet.
|
|
265
264
|
return SHOW_ONBOARDING_ROLE_PICKER_TOOL_NAME;
|
|
266
265
|
}
|
|
267
266
|
if (name === "EnterWorktree") {
|
package/agent-sdk/dist/bridge.js
CHANGED
|
@@ -130,7 +130,7 @@ export function emitAgentConfigOptionUpdate(sessionId, agent) {
|
|
|
130
130
|
value: agent,
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
|
-
const EXPECTED_AGENT_SDK_VERSION = "0.3.
|
|
133
|
+
const EXPECTED_AGENT_SDK_VERSION = "0.3.207";
|
|
134
134
|
const require = createRequire(import.meta.url);
|
|
135
135
|
export function resolveInstalledAgentSdkVersion() {
|
|
136
136
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-rust",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Claude Code Rust - native Rust terminal interface for Claude Code",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -33,15 +33,15 @@
|
|
|
33
33
|
"LICENSE"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
36
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.207"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@srothgan/claude-code-rust-darwin-arm64": "0.
|
|
40
|
-
"@srothgan/claude-code-rust-darwin-x64": "0.
|
|
41
|
-
"@srothgan/claude-code-rust-linux-x64-gnu": "0.
|
|
42
|
-
"@srothgan/claude-code-rust-linux-arm64-gnu": "0.
|
|
43
|
-
"@srothgan/claude-code-rust-win32-x64-msvc": "0.
|
|
44
|
-
"@srothgan/claude-code-rust-win32-arm64-msvc": "0.
|
|
39
|
+
"@srothgan/claude-code-rust-darwin-arm64": "0.14.0",
|
|
40
|
+
"@srothgan/claude-code-rust-darwin-x64": "0.14.0",
|
|
41
|
+
"@srothgan/claude-code-rust-linux-x64-gnu": "0.14.0",
|
|
42
|
+
"@srothgan/claude-code-rust-linux-arm64-gnu": "0.14.0",
|
|
43
|
+
"@srothgan/claude-code-rust-win32-x64-msvc": "0.14.0",
|
|
44
|
+
"@srothgan/claude-code-rust-win32-arm64-msvc": "0.14.0"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24"
|