claude-code-rust 0.14.0 → 0.14.2
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 +5 -9
- package/agent-sdk/dist/bridge/account_metadata.js +1 -0
- package/agent-sdk/dist/bridge/available_commands.js +1 -1
- package/agent-sdk/dist/bridge/command_interactions.js +16 -0
- package/agent-sdk/dist/bridge/command_lifecycle.js +184 -0
- package/agent-sdk/dist/bridge/command_mcp.js +32 -0
- package/agent-sdk/dist/bridge/command_scheduler.js +136 -0
- package/agent-sdk/dist/bridge/command_session_control.js +269 -0
- package/agent-sdk/dist/bridge/command_session_data.js +203 -0
- package/agent-sdk/dist/bridge/commands.js +6 -0
- package/agent-sdk/dist/bridge/error_classification.js +24 -7
- package/agent-sdk/dist/bridge/events.js +42 -9
- package/agent-sdk/dist/bridge/history.js +7 -3
- package/agent-sdk/dist/bridge/logger.js +2 -0
- package/agent-sdk/dist/bridge/mcp.js +90 -80
- package/agent-sdk/dist/bridge/mcp_auth_adapter.js +67 -0
- package/agent-sdk/dist/bridge/mcp_monitor.js +59 -0
- package/agent-sdk/dist/bridge/message_handlers.js +35 -9
- package/agent-sdk/dist/bridge/session_lifecycle.js +70 -11
- package/agent-sdk/dist/bridge/state_parsing.js +35 -0
- package/agent-sdk/dist/bridge/tool_calls.js +45 -10
- package/agent-sdk/dist/bridge/tooling.js +106 -8
- package/agent-sdk/dist/bridge.js +135 -629
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -18,14 +18,12 @@ Claude Code Rust replaces the stock Claude Code terminal interface with a native
|
|
|
18
18
|
|
|
19
19
|
## Prerequisite
|
|
20
20
|
|
|
21
|
-
-
|
|
21
|
+
- The Claude Code CLI must be installed as fallback for some SDK-unsupported features.
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
25
|
### Install script (recommended, v0.14.0+)
|
|
26
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
27
|
**macOS/Linux:**
|
|
30
28
|
|
|
31
29
|
```bash
|
|
@@ -40,15 +38,11 @@ powershell -NoProfile -ExecutionPolicy Bypass -Command "irm 'https://raw.githubu
|
|
|
40
38
|
|
|
41
39
|
### npm (global)
|
|
42
40
|
|
|
43
|
-
npm remains supported for users who prefer package-manager ownership of the global command:
|
|
44
|
-
|
|
45
41
|
```bash
|
|
46
42
|
npm install -g claude-code-rust
|
|
47
43
|
```
|
|
48
44
|
|
|
49
|
-
|
|
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.
|
|
45
|
+
See the [installation guide](https://srothgan.github.io/claude-code-rust/installation.html) for release pinning, custom install locations, switching install methods, uninstall, and troubleshooting.
|
|
52
46
|
|
|
53
47
|
## Usage
|
|
54
48
|
|
|
@@ -77,13 +71,15 @@ Claude Code Rust addresses these with a native terminal UI that uses diffed, dir
|
|
|
77
71
|
|
|
78
72
|
## Documentation
|
|
79
73
|
|
|
80
|
-
The manual covers installation with scripts
|
|
74
|
+
The manual covers installation with scripts and npm, plus help, slash commands, keyboard shortcuts, settings, diagnostics, troubleshooting, building from source, architecture, and the changelog:
|
|
81
75
|
|
|
82
76
|
- [Installation](https://srothgan.github.io/claude-code-rust/installation.html)
|
|
83
77
|
- [Usage](https://srothgan.github.io/claude-code-rust/usage.html)
|
|
84
78
|
- [Help](https://srothgan.github.io/claude-code-rust/help.html)
|
|
85
79
|
- [Slash commands](https://srothgan.github.io/claude-code-rust/commands.html)
|
|
86
80
|
- [Settings](https://srothgan.github.io/claude-code-rust/settings.html)
|
|
81
|
+
- [Troubleshooting](https://srothgan.github.io/claude-code-rust/troubleshooting.html)
|
|
82
|
+
- [Development](https://srothgan.github.io/claude-code-rust/development.html)
|
|
87
83
|
|
|
88
84
|
## Status
|
|
89
85
|
|
|
@@ -48,7 +48,7 @@ function shouldAcceptAvailableCommandsSnapshot(session, source, commands) {
|
|
|
48
48
|
if (source === "supportedCommands" && current.commands.length > 0) {
|
|
49
49
|
return {
|
|
50
50
|
accept: false,
|
|
51
|
-
reason: "supportedCommands
|
|
51
|
+
reason: "supportedCommands bootstrap cannot replace an existing snapshot",
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
if (commands.length === 0) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { handleElicitationResponse, handlePermissionResponse, handleQuestionResponse, handleUserDialogResponse, } from "./session_lifecycle.js";
|
|
2
|
+
export function handleInteractionCommand(command) {
|
|
3
|
+
switch (command.command) {
|
|
4
|
+
case "permission_response":
|
|
5
|
+
handlePermissionResponse(command);
|
|
6
|
+
return;
|
|
7
|
+
case "question_response":
|
|
8
|
+
handleQuestionResponse(command);
|
|
9
|
+
return;
|
|
10
|
+
case "user_dialog_response":
|
|
11
|
+
handleUserDialogResponse(command);
|
|
12
|
+
return;
|
|
13
|
+
case "elicitation_response":
|
|
14
|
+
handleElicitationResponse(command);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { getSessionMessages, listSessions, } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
+
import { currentSessionListOptions, emitSessionsList, failConnection, setSessionListingDir, slashError, writeEvent, } from "./events.js";
|
|
3
|
+
import { mapSessionMessagesToUpdates } from "./history.js";
|
|
4
|
+
import { bridgeLogger, LOG_TARGETS } from "./logger.js";
|
|
5
|
+
import { closeAllSessions, createSession, sessions, } from "./session_lifecycle.js";
|
|
6
|
+
export async function handleLifecycleCommand(command, requestId, sdkVersionError) {
|
|
7
|
+
switch (command.command) {
|
|
8
|
+
case "initialize":
|
|
9
|
+
await initialize(command, requestId, sdkVersionError);
|
|
10
|
+
return;
|
|
11
|
+
case "create_session":
|
|
12
|
+
await create(command, requestId);
|
|
13
|
+
return;
|
|
14
|
+
case "resume_session":
|
|
15
|
+
await resume(command, requestId);
|
|
16
|
+
return;
|
|
17
|
+
case "new_session":
|
|
18
|
+
await replace(command, requestId);
|
|
19
|
+
return;
|
|
20
|
+
case "shutdown":
|
|
21
|
+
await shutdown(requestId);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function initialize(command, requestId, sdkVersionError) {
|
|
25
|
+
if (sdkVersionError) {
|
|
26
|
+
bridgeLogger.error({
|
|
27
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
28
|
+
eventName: "bridge_initialize_failed",
|
|
29
|
+
message: "bridge initialization failed due to unsupported SDK version",
|
|
30
|
+
outcome: "failure",
|
|
31
|
+
...(requestId ? { requestId } : {}),
|
|
32
|
+
fields: { error_message: sdkVersionError },
|
|
33
|
+
});
|
|
34
|
+
failConnection(sdkVersionError, requestId);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
setSessionListingDir(command.cwd);
|
|
38
|
+
writeEvent({
|
|
39
|
+
event: "initialized",
|
|
40
|
+
result: {
|
|
41
|
+
agent_name: "claude-rs-agent-bridge",
|
|
42
|
+
agent_version: "0.1.0",
|
|
43
|
+
auth_methods: [
|
|
44
|
+
{
|
|
45
|
+
id: "claude-login",
|
|
46
|
+
name: "Log in with Claude",
|
|
47
|
+
description: "Run `claude /login` in a terminal",
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
capabilities: {
|
|
51
|
+
prompt_image: true,
|
|
52
|
+
prompt_embedded_context: true,
|
|
53
|
+
supports_session_listing: true,
|
|
54
|
+
supports_resume_session: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
}, requestId);
|
|
58
|
+
await emitSessionsList(requestId);
|
|
59
|
+
}
|
|
60
|
+
async function create(command, requestId) {
|
|
61
|
+
bridgeLogger.info({
|
|
62
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
63
|
+
eventName: "session_create_requested",
|
|
64
|
+
message: "session creation requested",
|
|
65
|
+
outcome: "start",
|
|
66
|
+
...(requestId ? { requestId } : {}),
|
|
67
|
+
fields: {
|
|
68
|
+
cwd: command.cwd,
|
|
69
|
+
resume_requested: command.resume !== undefined,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
setSessionListingDir(command.cwd);
|
|
73
|
+
await createSession({
|
|
74
|
+
cwd: command.cwd,
|
|
75
|
+
resume: command.resume,
|
|
76
|
+
launchSettings: command.launch_settings,
|
|
77
|
+
connectEvent: "connected",
|
|
78
|
+
requestId,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async function resume(command, requestId) {
|
|
82
|
+
bridgeLogger.info({
|
|
83
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
84
|
+
eventName: "session_resume_requested",
|
|
85
|
+
message: "session resume requested",
|
|
86
|
+
outcome: "start",
|
|
87
|
+
...(requestId ? { requestId } : {}),
|
|
88
|
+
sessionId: command.session_id,
|
|
89
|
+
});
|
|
90
|
+
try {
|
|
91
|
+
const sdkSessions = await listSessions(currentSessionListOptions());
|
|
92
|
+
const matched = sdkSessions.find((entry) => entry.sessionId === command.session_id);
|
|
93
|
+
if (!matched) {
|
|
94
|
+
bridgeLogger.warn({
|
|
95
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
96
|
+
eventName: "session_resume_lookup_failed",
|
|
97
|
+
message: "session resume requested for an unknown session",
|
|
98
|
+
outcome: "failure",
|
|
99
|
+
...(requestId ? { requestId } : {}),
|
|
100
|
+
sessionId: command.session_id,
|
|
101
|
+
fields: { reason: "unknown_session" },
|
|
102
|
+
});
|
|
103
|
+
slashError(command.session_id, `unknown session: ${command.session_id}`, requestId);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
setSessionListingDir(matched.cwd ?? process.cwd());
|
|
107
|
+
const historyMessages = await getSessionMessages(command.session_id, matched.cwd
|
|
108
|
+
? { dir: matched.cwd, includeSystemMessages: true }
|
|
109
|
+
: { includeSystemMessages: true });
|
|
110
|
+
const resumeUpdates = mapSessionMessagesToUpdates(historyMessages);
|
|
111
|
+
const staleSessions = Array.from(sessions.values());
|
|
112
|
+
const hadActiveSession = staleSessions.length > 0;
|
|
113
|
+
bridgeLogger.info({
|
|
114
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
115
|
+
eventName: "session_resume_history_loaded",
|
|
116
|
+
message: "session resume history loaded",
|
|
117
|
+
outcome: "success",
|
|
118
|
+
...(requestId ? { requestId } : {}),
|
|
119
|
+
sessionId: command.session_id,
|
|
120
|
+
fields: {
|
|
121
|
+
history_update_count: resumeUpdates.length,
|
|
122
|
+
stale_session_count: staleSessions.length,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
await createSession({
|
|
126
|
+
cwd: matched.cwd ?? process.cwd(),
|
|
127
|
+
resume: command.session_id,
|
|
128
|
+
launchSettings: command.launch_settings,
|
|
129
|
+
...(resumeUpdates.length > 0 ? { resumeUpdates } : {}),
|
|
130
|
+
connectEvent: hadActiveSession ? "session_replaced" : "connected",
|
|
131
|
+
requestId,
|
|
132
|
+
...(hadActiveSession ? { sessionsToCloseAfterConnect: staleSessions } : {}),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
137
|
+
bridgeLogger.error({
|
|
138
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
139
|
+
eventName: "session_resume_failed",
|
|
140
|
+
message: "session resume failed",
|
|
141
|
+
outcome: "failure",
|
|
142
|
+
...(requestId ? { requestId } : {}),
|
|
143
|
+
sessionId: command.session_id,
|
|
144
|
+
fields: { error_message: message },
|
|
145
|
+
});
|
|
146
|
+
slashError(command.session_id, `failed to resume session: ${message}`, requestId);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function replace(command, requestId) {
|
|
150
|
+
bridgeLogger.info({
|
|
151
|
+
target: LOG_TARGETS.APP_SESSION,
|
|
152
|
+
eventName: "session_new_requested",
|
|
153
|
+
message: "replacement session requested",
|
|
154
|
+
outcome: "start",
|
|
155
|
+
...(requestId ? { requestId } : {}),
|
|
156
|
+
fields: { cwd: command.cwd },
|
|
157
|
+
});
|
|
158
|
+
await closeAllSessions({ reason: "new_session_requested", requestId });
|
|
159
|
+
setSessionListingDir(command.cwd);
|
|
160
|
+
await createSession({
|
|
161
|
+
cwd: command.cwd,
|
|
162
|
+
launchSettings: command.launch_settings,
|
|
163
|
+
connectEvent: "session_replaced",
|
|
164
|
+
requestId,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async function shutdown(requestId) {
|
|
168
|
+
bridgeLogger.info({
|
|
169
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
170
|
+
eventName: "bridge_shutdown_requested",
|
|
171
|
+
message: "bridge shutdown requested",
|
|
172
|
+
outcome: "start",
|
|
173
|
+
...(requestId ? { requestId } : {}),
|
|
174
|
+
});
|
|
175
|
+
await closeAllSessions({ reason: "bridge_shutdown_requested", requestId });
|
|
176
|
+
bridgeLogger.info({
|
|
177
|
+
target: LOG_TARGETS.BRIDGE_LIFECYCLE,
|
|
178
|
+
eventName: "bridge_shutdown_completed",
|
|
179
|
+
message: "bridge shutdown completed",
|
|
180
|
+
outcome: "success",
|
|
181
|
+
...(requestId ? { requestId } : {}),
|
|
182
|
+
});
|
|
183
|
+
process.exit(0);
|
|
184
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { slashError } from "./events.js";
|
|
2
|
+
import { handleMcpAuthenticateCommand, handleMcpClearAuthCommand, handleMcpOauthCallbackUrlCommand, handleMcpReconnectCommand, handleMcpSetServersCommand, handleMcpStatusCommand, handleMcpToggleCommand, } from "./mcp.js";
|
|
3
|
+
import { sessionById } from "./session_lifecycle.js";
|
|
4
|
+
export async function handleMcpCommand(command, requestId) {
|
|
5
|
+
const session = sessionById(command.session_id);
|
|
6
|
+
if (!session) {
|
|
7
|
+
slashError(command.session_id, `unknown session: ${command.session_id}`, requestId);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
switch (command.command) {
|
|
11
|
+
case "mcp_status":
|
|
12
|
+
await handleMcpStatusCommand(session, requestId);
|
|
13
|
+
return;
|
|
14
|
+
case "mcp_reconnect":
|
|
15
|
+
await handleMcpReconnectCommand(session, command, requestId);
|
|
16
|
+
return;
|
|
17
|
+
case "mcp_toggle":
|
|
18
|
+
await handleMcpToggleCommand(session, command, requestId);
|
|
19
|
+
return;
|
|
20
|
+
case "mcp_set_servers":
|
|
21
|
+
await handleMcpSetServersCommand(session, command, requestId);
|
|
22
|
+
return;
|
|
23
|
+
case "mcp_authenticate":
|
|
24
|
+
await handleMcpAuthenticateCommand(session, command, requestId);
|
|
25
|
+
return;
|
|
26
|
+
case "mcp_clear_auth":
|
|
27
|
+
await handleMcpClearAuthCommand(session, command, requestId);
|
|
28
|
+
return;
|
|
29
|
+
case "mcp_oauth_callback_url":
|
|
30
|
+
await handleMcpOauthCallbackUrlCommand(session, command, requestId);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const LIFECYCLE_COMMANDS = new Set([
|
|
2
|
+
"initialize",
|
|
3
|
+
"create_session",
|
|
4
|
+
"resume_session",
|
|
5
|
+
"new_session",
|
|
6
|
+
"rewind",
|
|
7
|
+
"shutdown",
|
|
8
|
+
]);
|
|
9
|
+
const UNBLOCKING_COMMANDS = new Set([
|
|
10
|
+
"cancel_turn",
|
|
11
|
+
"permission_response",
|
|
12
|
+
"question_response",
|
|
13
|
+
"user_dialog_response",
|
|
14
|
+
"elicitation_response",
|
|
15
|
+
"mcp_oauth_callback_url",
|
|
16
|
+
]);
|
|
17
|
+
function commandLane(command) {
|
|
18
|
+
if (UNBLOCKING_COMMANDS.has(command.command)) {
|
|
19
|
+
return { kind: "unblocking" };
|
|
20
|
+
}
|
|
21
|
+
if (LIFECYCLE_COMMANDS.has(command.command)) {
|
|
22
|
+
return { kind: "lifecycle" };
|
|
23
|
+
}
|
|
24
|
+
if ("session_id" in command) {
|
|
25
|
+
return { kind: "session", sessionId: command.session_id };
|
|
26
|
+
}
|
|
27
|
+
return { kind: "lifecycle" };
|
|
28
|
+
}
|
|
29
|
+
function settle(task) {
|
|
30
|
+
return task.then(() => undefined, () => undefined);
|
|
31
|
+
}
|
|
32
|
+
export class BridgeCommandScheduler {
|
|
33
|
+
lifecycleTail;
|
|
34
|
+
sessionTails = new Map();
|
|
35
|
+
activeTasks = new Set();
|
|
36
|
+
shutdownState = "accepting";
|
|
37
|
+
schedule(command, task) {
|
|
38
|
+
const lane = commandLane(command);
|
|
39
|
+
if (!this.accepts(command, lane)) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
let scheduledTask = task;
|
|
43
|
+
if (command.command === "shutdown") {
|
|
44
|
+
this.shutdownState = "queued";
|
|
45
|
+
scheduledTask = async () => {
|
|
46
|
+
this.shutdownState = "running";
|
|
47
|
+
try {
|
|
48
|
+
await task();
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
this.shutdownState = "complete";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const operation = this.scheduleInLane(lane, scheduledTask);
|
|
56
|
+
this.track(operation);
|
|
57
|
+
return operation;
|
|
58
|
+
}
|
|
59
|
+
stopAccepting() {
|
|
60
|
+
if (this.shutdownState === "accepting") {
|
|
61
|
+
this.shutdownState = "complete";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async whenIdle() {
|
|
65
|
+
while (this.activeTasks.size > 0) {
|
|
66
|
+
await Promise.all(this.activeTasks);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
accepts(command, lane) {
|
|
70
|
+
if (this.shutdownState === "accepting") {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return (this.shutdownState === "queued" &&
|
|
74
|
+
command.command !== "shutdown" &&
|
|
75
|
+
lane.kind === "unblocking");
|
|
76
|
+
}
|
|
77
|
+
scheduleInLane(lane, task) {
|
|
78
|
+
switch (lane.kind) {
|
|
79
|
+
case "unblocking":
|
|
80
|
+
return this.start(task);
|
|
81
|
+
case "lifecycle":
|
|
82
|
+
return this.scheduleLifecycle(task);
|
|
83
|
+
case "session":
|
|
84
|
+
return this.scheduleSession(lane.sessionId, task);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
scheduleLifecycle(task) {
|
|
88
|
+
const dependencies = new Set(this.sessionTails.values());
|
|
89
|
+
if (this.lifecycleTail) {
|
|
90
|
+
dependencies.add(this.lifecycleTail);
|
|
91
|
+
}
|
|
92
|
+
const operation = dependencies.size === 0 ? this.start(task) : Promise.all(dependencies).then(task);
|
|
93
|
+
const tail = settle(operation);
|
|
94
|
+
this.lifecycleTail = tail;
|
|
95
|
+
void tail.then(() => {
|
|
96
|
+
if (this.lifecycleTail === tail) {
|
|
97
|
+
this.lifecycleTail = undefined;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return operation;
|
|
101
|
+
}
|
|
102
|
+
scheduleSession(sessionId, task) {
|
|
103
|
+
const dependencies = [];
|
|
104
|
+
if (this.lifecycleTail) {
|
|
105
|
+
dependencies.push(this.lifecycleTail);
|
|
106
|
+
}
|
|
107
|
+
const previousSessionTask = this.sessionTails.get(sessionId);
|
|
108
|
+
if (previousSessionTask) {
|
|
109
|
+
dependencies.push(previousSessionTask);
|
|
110
|
+
}
|
|
111
|
+
const operation = dependencies.length === 0 ? this.start(task) : Promise.all(dependencies).then(task);
|
|
112
|
+
const tail = settle(operation);
|
|
113
|
+
this.sessionTails.set(sessionId, tail);
|
|
114
|
+
void tail.then(() => {
|
|
115
|
+
if (this.sessionTails.get(sessionId) === tail) {
|
|
116
|
+
this.sessionTails.delete(sessionId);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return operation;
|
|
120
|
+
}
|
|
121
|
+
track(operation) {
|
|
122
|
+
const tracked = settle(operation);
|
|
123
|
+
this.activeTasks.add(tracked);
|
|
124
|
+
void tracked.then(() => {
|
|
125
|
+
this.activeTasks.delete(tracked);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
start(task) {
|
|
129
|
+
try {
|
|
130
|
+
return task();
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
return Promise.reject(error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|