@oh-my-pi/pi-coding-agent 6.8.2 → 6.8.4
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 +30 -0
- package/package.json +6 -6
- package/src/core/agent-session.ts +7 -18
- package/src/core/bash-executor.ts +7 -64
- package/src/core/custom-commands/loader.ts +0 -8
- package/src/core/extensions/types.ts +0 -3
- package/src/core/index.ts +1 -1
- package/src/core/keybindings.ts +10 -2
- package/src/core/python-executor.ts +15 -25
- package/src/core/ssh/ssh-executor.ts +8 -13
- package/src/core/streaming-output.ts +64 -150
- package/src/core/tools/bash.ts +10 -44
- package/src/core/tools/index.ts +1 -1
- package/src/core/tools/output.ts +7 -8
- package/src/core/tools/python.ts +6 -15
- package/src/core/tools/ssh.ts +6 -14
- package/src/core/tools/task/executor.ts +7 -16
- package/src/core/tools/task/index.ts +11 -12
- package/src/core/tools/task/types.ts +2 -1
- package/src/core/tools/todo-write.ts +2 -18
- package/src/core/tools/truncate.ts +92 -0
- package/src/core/tools/web-fetch.ts +6 -4
- package/src/core/tools/web-scrapers/utils.ts +7 -30
- package/src/core/tools/web-search/providers/anthropic.ts +0 -1
- package/src/index.ts +0 -1
- package/src/modes/interactive/components/todo-display.ts +1 -8
- package/src/modes/interactive/components/tree-selector.ts +2 -2
- package/src/modes/interactive/interactive-mode.ts +1 -15
- package/src/utils/clipboard.ts +27 -20
- package/src/core/tools/task/artifacts.ts +0 -112
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [6.8.4] - 2026-01-21
|
|
6
|
+
### Changed
|
|
7
|
+
|
|
8
|
+
- Updated output sink to properly handle large outputs
|
|
9
|
+
- Improved error message formatting in SSH executor
|
|
10
|
+
- Updated web fetch timeout bounds and conversion
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Fixed output truncation handling in streaming output
|
|
15
|
+
- Fixed timeout handling in web fetch tool
|
|
16
|
+
- Fixed async stream dumping in executors
|
|
17
|
+
|
|
18
|
+
## [6.8.3] - 2026-01-21
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Updated keybinding system to normalize key IDs to lowercase
|
|
23
|
+
- Changed label edit shortcut from 'l' to 'Shift+L' in tree selector
|
|
24
|
+
- Changed output file extension from `.out.md` to `.md` for artifacts
|
|
25
|
+
|
|
26
|
+
### Removed
|
|
27
|
+
|
|
28
|
+
- Removed bundled worktree command from custom commands loader
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Fixed keybinding case sensitivity issues by normalizing all key IDs
|
|
33
|
+
- Fixed task artifact path handling and simplified file structure
|
|
34
|
+
|
|
5
35
|
## [6.8.2] - 2026-01-21
|
|
6
36
|
|
|
7
37
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "6.8.
|
|
3
|
+
"version": "6.8.4",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"prepublishOnly": "bun run generate-template && bun run clean && bun run build"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@oh-my-pi/pi-agent-core": "6.8.
|
|
44
|
-
"@oh-my-pi/pi-ai": "6.8.
|
|
45
|
-
"@oh-my-pi/pi-git-tool": "6.8.
|
|
46
|
-
"@oh-my-pi/pi-tui": "6.8.
|
|
47
|
-
"@oh-my-pi/pi-utils": "6.8.
|
|
43
|
+
"@oh-my-pi/pi-agent-core": "6.8.4",
|
|
44
|
+
"@oh-my-pi/pi-ai": "6.8.4",
|
|
45
|
+
"@oh-my-pi/pi-git-tool": "6.8.4",
|
|
46
|
+
"@oh-my-pi/pi-tui": "6.8.4",
|
|
47
|
+
"@oh-my-pi/pi-utils": "6.8.4",
|
|
48
48
|
"@openai/agents": "^0.3.7",
|
|
49
49
|
"@sinclair/typebox": "^0.34.46",
|
|
50
50
|
"ajv": "^8.17.1",
|
|
@@ -22,7 +22,7 @@ import type { Rule } from "../capability/rule";
|
|
|
22
22
|
import { getAgentDbPath } from "../config";
|
|
23
23
|
import { theme } from "../modes/interactive/theme/theme";
|
|
24
24
|
import ttsrInterruptTemplate from "../prompts/system/ttsr-interrupt.md" with { type: "text" };
|
|
25
|
-
import { type BashResult, executeBash as executeBashCommand
|
|
25
|
+
import { type BashResult, executeBash as executeBashCommand } from "./bash-executor";
|
|
26
26
|
import {
|
|
27
27
|
type CompactionResult,
|
|
28
28
|
calculateContextTokens,
|
|
@@ -60,10 +60,8 @@ import type { Skill, SkillWarning } from "./skills";
|
|
|
60
60
|
import { expandSlashCommand, type FileSlashCommand } from "./slash-commands";
|
|
61
61
|
import { closeAllConnections } from "./ssh/connection-manager";
|
|
62
62
|
import { unmountAll } from "./ssh/sshfs-mount";
|
|
63
|
-
import type { BashOperations } from "./tools/bash";
|
|
64
63
|
import { normalizeDiff, normalizeToLF, ParseError, previewPatch, stripBom } from "./tools/patch";
|
|
65
64
|
import { resolveToCwd } from "./tools/path-utils";
|
|
66
|
-
import { getArtifactsDir } from "./tools/task/artifacts";
|
|
67
65
|
import type { TodoItem } from "./tools/todo-write";
|
|
68
66
|
import type { TtsrManager } from "./ttsr";
|
|
69
67
|
|
|
@@ -1991,10 +1989,7 @@ export class AgentSession {
|
|
|
1991
1989
|
const sessionFile = this.sessionManager.getSessionFile();
|
|
1992
1990
|
if (!sessionFile) return;
|
|
1993
1991
|
|
|
1994
|
-
const
|
|
1995
|
-
if (!artifactsDir) return;
|
|
1996
|
-
|
|
1997
|
-
const todoPath = `${artifactsDir}/todos.json`;
|
|
1992
|
+
const todoPath = `${sessionFile.slice(0, -6)}/todos.json`;
|
|
1998
1993
|
const file = Bun.file(todoPath);
|
|
1999
1994
|
if (!(await file.exists())) {
|
|
2000
1995
|
this._todoReminderCount = 0;
|
|
@@ -2550,25 +2545,19 @@ export class AgentSession {
|
|
|
2550
2545
|
* @param command The bash command to execute
|
|
2551
2546
|
* @param onChunk Optional streaming callback for output
|
|
2552
2547
|
* @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)
|
|
2553
|
-
* @param options.operations Custom BashOperations for remote execution
|
|
2554
2548
|
*/
|
|
2555
2549
|
async executeBash(
|
|
2556
2550
|
command: string,
|
|
2557
2551
|
onChunk?: (chunk: string) => void,
|
|
2558
|
-
options?: { excludeFromContext?: boolean
|
|
2552
|
+
options?: { excludeFromContext?: boolean },
|
|
2559
2553
|
): Promise<BashResult> {
|
|
2560
2554
|
this._bashAbortController = new AbortController();
|
|
2561
2555
|
|
|
2562
2556
|
try {
|
|
2563
|
-
const result =
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
})
|
|
2568
|
-
: await executeBashCommand(command, {
|
|
2569
|
-
onChunk,
|
|
2570
|
-
signal: this._bashAbortController.signal,
|
|
2571
|
-
});
|
|
2557
|
+
const result = await executeBashCommand(command, {
|
|
2558
|
+
onChunk,
|
|
2559
|
+
signal: this._bashAbortController.signal,
|
|
2560
|
+
});
|
|
2572
2561
|
|
|
2573
2562
|
this.recordBashResult(command, result, options);
|
|
2574
2563
|
return result;
|
|
@@ -8,7 +8,6 @@ import { cspawn, Exception, ptree } from "@oh-my-pi/pi-utils";
|
|
|
8
8
|
import { getShellConfig } from "../utils/shell";
|
|
9
9
|
import { getOrCreateSnapshot, getSnapshotSourceCommand } from "../utils/shell-snapshot";
|
|
10
10
|
import { OutputSink } from "./streaming-output";
|
|
11
|
-
import type { BashOperations } from "./tools/bash";
|
|
12
11
|
|
|
13
12
|
export interface BashExecutorOptions {
|
|
14
13
|
cwd?: string;
|
|
@@ -34,7 +33,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
34
33
|
const prefixedCommand = prefix ? `${prefix} ${command}` : command;
|
|
35
34
|
const finalCommand = `${snapshotPrefix}${prefixedCommand}`;
|
|
36
35
|
|
|
37
|
-
const
|
|
36
|
+
const sink = new OutputSink({ onChunk: options?.onChunk });
|
|
38
37
|
|
|
39
38
|
const child = cspawn([shell, ...args, finalCommand], {
|
|
40
39
|
cwd: options?.cwd,
|
|
@@ -45,12 +44,9 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
45
44
|
|
|
46
45
|
// Pump streams - errors during abort/timeout are expected
|
|
47
46
|
// Use preventClose to avoid closing the shared sink when either stream finishes
|
|
48
|
-
await Promise.allSettled([
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
])
|
|
52
|
-
.then(() => stream.close())
|
|
53
|
-
.catch(() => {});
|
|
47
|
+
await Promise.allSettled([child.stdout.pipeTo(sink.createInput()), child.stderr.pipeTo(sink.createInput())]).catch(
|
|
48
|
+
() => {},
|
|
49
|
+
);
|
|
54
50
|
|
|
55
51
|
// Wait for process exit
|
|
56
52
|
try {
|
|
@@ -58,7 +54,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
58
54
|
return {
|
|
59
55
|
exitCode: child.exitCode ?? 0,
|
|
60
56
|
cancelled: false,
|
|
61
|
-
...
|
|
57
|
+
...(await sink.dump()),
|
|
62
58
|
};
|
|
63
59
|
} catch (err) {
|
|
64
60
|
// Exception covers NonZeroExitError, AbortError, TimeoutError
|
|
@@ -71,7 +67,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
71
67
|
return {
|
|
72
68
|
exitCode: undefined,
|
|
73
69
|
cancelled: true,
|
|
74
|
-
...
|
|
70
|
+
...(await sink.dump(annotation)),
|
|
75
71
|
};
|
|
76
72
|
}
|
|
77
73
|
|
|
@@ -79,60 +75,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
79
75
|
return {
|
|
80
76
|
exitCode: err.exitCode,
|
|
81
77
|
cancelled: false,
|
|
82
|
-
...
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
throw err;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export async function executeBashWithOperations(
|
|
91
|
-
command: string,
|
|
92
|
-
cwd: string,
|
|
93
|
-
operations: BashOperations,
|
|
94
|
-
options?: BashExecutorOptions,
|
|
95
|
-
): Promise<BashResult> {
|
|
96
|
-
const stream = new OutputSink({ onChunk: options?.onChunk });
|
|
97
|
-
const writable = stream.createWritable();
|
|
98
|
-
const writer = writable.getWriter();
|
|
99
|
-
|
|
100
|
-
const closeStreams = async () => {
|
|
101
|
-
try {
|
|
102
|
-
await writer.close();
|
|
103
|
-
} catch {}
|
|
104
|
-
try {
|
|
105
|
-
await writable.close();
|
|
106
|
-
} catch {}
|
|
107
|
-
try {
|
|
108
|
-
await stream.close();
|
|
109
|
-
} catch {}
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
const result = await operations.exec(command, cwd, {
|
|
114
|
-
onData: (data) => writer.write(data),
|
|
115
|
-
signal: options?.signal,
|
|
116
|
-
timeout: options?.timeout,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
await closeStreams();
|
|
120
|
-
|
|
121
|
-
const cancelled = options?.signal?.aborted ?? false;
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
exitCode: cancelled ? undefined : (result.exitCode ?? undefined),
|
|
125
|
-
cancelled,
|
|
126
|
-
...stream.dump(),
|
|
127
|
-
};
|
|
128
|
-
} catch (err) {
|
|
129
|
-
await closeStreams();
|
|
130
|
-
|
|
131
|
-
if (options?.signal?.aborted) {
|
|
132
|
-
return {
|
|
133
|
-
exitCode: undefined,
|
|
134
|
-
cancelled: true,
|
|
135
|
-
...stream.dump(),
|
|
78
|
+
...(await sink.dump()),
|
|
136
79
|
};
|
|
137
80
|
}
|
|
138
81
|
|
|
@@ -13,7 +13,6 @@ import { getAgentDir, getConfigDirs } from "../../config";
|
|
|
13
13
|
import * as piCodingAgent from "../../index";
|
|
14
14
|
import { execCommand } from "../exec";
|
|
15
15
|
import { ReviewCommand } from "./bundled/review";
|
|
16
|
-
import { WorktreeCommand } from "./bundled/wt";
|
|
17
16
|
import type {
|
|
18
17
|
CustomCommand,
|
|
19
18
|
CustomCommandAPI,
|
|
@@ -153,13 +152,6 @@ function loadBundledCommands(sharedApi: CustomCommandAPI): LoadedCustomCommand[]
|
|
|
153
152
|
source: "bundled",
|
|
154
153
|
});
|
|
155
154
|
|
|
156
|
-
bundled.push({
|
|
157
|
-
path: "bundled:wt",
|
|
158
|
-
resolvedPath: "bundled:wt",
|
|
159
|
-
command: new WorktreeCommand(sharedApi),
|
|
160
|
-
source: "bundled",
|
|
161
|
-
});
|
|
162
|
-
|
|
163
155
|
return bundled;
|
|
164
156
|
}
|
|
165
157
|
|
|
@@ -29,7 +29,6 @@ import type {
|
|
|
29
29
|
SessionManager,
|
|
30
30
|
} from "../session-manager";
|
|
31
31
|
import type { BashToolDetails, FindToolDetails, GrepToolDetails, LsToolDetails, ReadToolDetails } from "../tools";
|
|
32
|
-
import type { BashOperations } from "../tools/bash";
|
|
33
32
|
import type { EditToolDetails } from "../tools/patch";
|
|
34
33
|
|
|
35
34
|
export type { ExecOptions, ExecResult } from "../exec";
|
|
@@ -551,8 +550,6 @@ export interface InputEventResult {
|
|
|
551
550
|
|
|
552
551
|
/** Result from user_bash event handler */
|
|
553
552
|
export interface UserBashEventResult {
|
|
554
|
-
/** Custom operations to use for execution */
|
|
555
|
-
operations?: BashOperations;
|
|
556
553
|
/** Full replacement: extension handled execution, use this result */
|
|
557
554
|
result?: BashResult;
|
|
558
555
|
}
|
package/src/core/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ export {
|
|
|
11
11
|
type PromptOptions,
|
|
12
12
|
type SessionStats,
|
|
13
13
|
} from "./agent-session";
|
|
14
|
-
export { type BashExecutorOptions, type BashResult, executeBash
|
|
14
|
+
export { type BashExecutorOptions, type BashResult, executeBash } from "./bash-executor";
|
|
15
15
|
export type { CompactionResult } from "./compaction/index";
|
|
16
16
|
export {
|
|
17
17
|
discoverAndLoadExtensions,
|
package/src/core/keybindings.ts
CHANGED
|
@@ -124,6 +124,8 @@ const KEY_LABELS: Record<string, string> = {
|
|
|
124
124
|
right: "Right",
|
|
125
125
|
};
|
|
126
126
|
|
|
127
|
+
const normalizeKeyId = (key: KeyId): KeyId => key.toLowerCase() as KeyId;
|
|
128
|
+
|
|
127
129
|
function formatKeyPart(part: string): string {
|
|
128
130
|
const lower = part.toLowerCase();
|
|
129
131
|
const modifier = MODIFIER_LABELS[lower];
|
|
@@ -199,14 +201,20 @@ export class KeybindingsManager {
|
|
|
199
201
|
// Set defaults for app actions
|
|
200
202
|
for (const [action, keys] of Object.entries(DEFAULT_APP_KEYBINDINGS)) {
|
|
201
203
|
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
202
|
-
this.appActionToKeys.set(
|
|
204
|
+
this.appActionToKeys.set(
|
|
205
|
+
action as AppAction,
|
|
206
|
+
keyArray.map((key) => normalizeKeyId(key as KeyId)),
|
|
207
|
+
);
|
|
203
208
|
}
|
|
204
209
|
|
|
205
210
|
// Override with user config (app actions only)
|
|
206
211
|
for (const [action, keys] of Object.entries(this.config)) {
|
|
207
212
|
if (keys === undefined || !isAppAction(action)) continue;
|
|
208
213
|
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
209
|
-
this.appActionToKeys.set(
|
|
214
|
+
this.appActionToKeys.set(
|
|
215
|
+
action,
|
|
216
|
+
keyArray.map((key) => normalizeKeyId(key as KeyId)),
|
|
217
|
+
);
|
|
210
218
|
}
|
|
211
219
|
}
|
|
212
220
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logger
|
|
1
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import {
|
|
3
3
|
checkPythonKernelAvailability,
|
|
4
4
|
type KernelDisplayOutput,
|
|
@@ -210,30 +210,20 @@ async function executeWithKernel(
|
|
|
210
210
|
code: string,
|
|
211
211
|
options: PythonExecutorOptions | undefined,
|
|
212
212
|
): Promise<PythonResult> {
|
|
213
|
-
const sink = new OutputSink({
|
|
213
|
+
const sink = new OutputSink({ onChunk: options?.onChunk });
|
|
214
214
|
const displayOutputs: KernelDisplayOutput[] = [];
|
|
215
215
|
|
|
216
216
|
try {
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
onDisplay: (output) => {
|
|
228
|
-
displayOutputs.push(output);
|
|
229
|
-
},
|
|
230
|
-
});
|
|
231
|
-
} catch (err) {
|
|
232
|
-
await writer.abort(err);
|
|
233
|
-
throw err;
|
|
234
|
-
} finally {
|
|
235
|
-
await writer.close().catch(() => {});
|
|
236
|
-
}
|
|
217
|
+
const result = await kernel.execute(code, {
|
|
218
|
+
signal: options?.signal,
|
|
219
|
+
timeoutMs: options?.timeout,
|
|
220
|
+
onChunk: (text) => {
|
|
221
|
+
sink.push(text);
|
|
222
|
+
},
|
|
223
|
+
onDisplay: (output) => {
|
|
224
|
+
displayOutputs.push(output);
|
|
225
|
+
},
|
|
226
|
+
});
|
|
237
227
|
|
|
238
228
|
if (result.cancelled) {
|
|
239
229
|
const secs = options?.timeout ? Math.round(options.timeout / 1000) : undefined;
|
|
@@ -244,7 +234,7 @@ async function executeWithKernel(
|
|
|
244
234
|
cancelled: true,
|
|
245
235
|
displayOutputs,
|
|
246
236
|
stdinRequested: result.stdinRequested,
|
|
247
|
-
...sink.dump(annotation),
|
|
237
|
+
...(await sink.dump(annotation)),
|
|
248
238
|
};
|
|
249
239
|
}
|
|
250
240
|
|
|
@@ -254,7 +244,7 @@ async function executeWithKernel(
|
|
|
254
244
|
cancelled: false,
|
|
255
245
|
displayOutputs,
|
|
256
246
|
stdinRequested: true,
|
|
257
|
-
...sink.dump("Kernel requested stdin; interactive input is not supported."),
|
|
247
|
+
...(await sink.dump("Kernel requested stdin; interactive input is not supported.")),
|
|
258
248
|
};
|
|
259
249
|
}
|
|
260
250
|
|
|
@@ -264,7 +254,7 @@ async function executeWithKernel(
|
|
|
264
254
|
cancelled: false,
|
|
265
255
|
displayOutputs,
|
|
266
256
|
stdinRequested: false,
|
|
267
|
-
...sink.dump(),
|
|
257
|
+
...(await sink.dump()),
|
|
268
258
|
};
|
|
269
259
|
} catch (err) {
|
|
270
260
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
@@ -70,16 +70,11 @@ export async function executeSSH(
|
|
|
70
70
|
timeout: options?.timeout,
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
const sink = new OutputSink({
|
|
73
|
+
const sink = new OutputSink({ onChunk: options?.onChunk });
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
child.stderr.pipeTo(sink.createWritable()),
|
|
79
|
-
]);
|
|
80
|
-
} finally {
|
|
81
|
-
await sink.close();
|
|
82
|
-
}
|
|
75
|
+
await Promise.allSettled([child.stdout.pipeTo(sink.createInput()), child.stderr.pipeTo(sink.createInput())]).catch(
|
|
76
|
+
() => {},
|
|
77
|
+
);
|
|
83
78
|
|
|
84
79
|
try {
|
|
85
80
|
await child.exited;
|
|
@@ -87,7 +82,7 @@ export async function executeSSH(
|
|
|
87
82
|
return {
|
|
88
83
|
exitCode,
|
|
89
84
|
cancelled: false,
|
|
90
|
-
...sink.dump(),
|
|
85
|
+
...(await sink.dump()),
|
|
91
86
|
};
|
|
92
87
|
} catch (err) {
|
|
93
88
|
if (err instanceof ptree.Exception) {
|
|
@@ -95,20 +90,20 @@ export async function executeSSH(
|
|
|
95
90
|
return {
|
|
96
91
|
exitCode: undefined,
|
|
97
92
|
cancelled: true,
|
|
98
|
-
...sink.dump(`SSH: ${err.message}`),
|
|
93
|
+
...(await sink.dump(`SSH: ${err.message}`)),
|
|
99
94
|
};
|
|
100
95
|
}
|
|
101
96
|
if (err.aborted) {
|
|
102
97
|
return {
|
|
103
98
|
exitCode: undefined,
|
|
104
99
|
cancelled: true,
|
|
105
|
-
...sink.dump(`
|
|
100
|
+
...(await sink.dump(`Command aborted: ${err.message}`)),
|
|
106
101
|
};
|
|
107
102
|
}
|
|
108
103
|
return {
|
|
109
104
|
exitCode: err.exitCode,
|
|
110
105
|
cancelled: false,
|
|
111
|
-
...sink.dump(`Unexpected error: ${err.message}`),
|
|
106
|
+
...(await sink.dump(`Unexpected error: ${err.message}`)),
|
|
112
107
|
};
|
|
113
108
|
}
|
|
114
109
|
throw err;
|