@oh-my-pi/pi-coding-agent 16.1.12 → 16.1.14

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.
Files changed (130) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/cli.js +5650 -2860
  3. package/dist/types/config/settings-schema.d.ts +44 -14
  4. package/dist/types/cursor.d.ts +9 -9
  5. package/dist/types/eval/__tests__/julia-prelude.test.d.ts +1 -0
  6. package/dist/types/eval/backend-helpers.d.ts +23 -0
  7. package/dist/types/eval/executor-base.d.ts +118 -0
  8. package/dist/types/eval/index.d.ts +2 -0
  9. package/dist/types/eval/jl/executor.d.ts +44 -0
  10. package/dist/types/eval/jl/index.d.ts +11 -0
  11. package/dist/types/eval/jl/kernel.d.ts +28 -0
  12. package/dist/types/eval/jl/prelude.d.ts +1 -0
  13. package/dist/types/eval/jl/runtime.d.ts +22 -0
  14. package/dist/types/eval/kernel-base.d.ts +105 -0
  15. package/dist/types/eval/py/kernel.d.ts +3 -61
  16. package/dist/types/eval/rb/executor.d.ts +77 -0
  17. package/dist/types/eval/rb/index.d.ts +11 -0
  18. package/dist/types/eval/rb/kernel.d.ts +31 -0
  19. package/dist/types/eval/rb/prelude.d.ts +1 -0
  20. package/dist/types/eval/rb/runtime.d.ts +23 -0
  21. package/dist/types/eval/runtime-env.d.ts +24 -0
  22. package/dist/types/eval/types.d.ts +3 -3
  23. package/dist/types/extensibility/extensions/runner.d.ts +2 -15
  24. package/dist/types/extensibility/hooks/loader.d.ts +1 -25
  25. package/dist/types/extensibility/session-handler-types.d.ts +23 -0
  26. package/dist/types/jsonrpc/message-framing.d.ts +35 -0
  27. package/dist/types/mnemopi/embed-client.d.ts +7 -24
  28. package/dist/types/modes/components/chat-transcript-builder.d.ts +1 -1
  29. package/dist/types/modes/components/custom-editor.d.ts +11 -0
  30. package/dist/types/modes/components/selector-helpers.d.ts +53 -0
  31. package/dist/types/modes/interactive-mode.d.ts +0 -2
  32. package/dist/types/modes/theme/theme.d.ts +8 -1
  33. package/dist/types/modes/types.d.ts +0 -2
  34. package/dist/types/modes/utils/copy-targets.d.ts +1 -1
  35. package/dist/types/modes/utils/interactive-context-helpers.d.ts +14 -0
  36. package/dist/types/modes/utils/transcript-render-helpers.d.ts +54 -0
  37. package/dist/types/sdk.d.ts +1 -1
  38. package/dist/types/session/agent-session.d.ts +2 -2
  39. package/dist/types/stt/asr-client.d.ts +3 -29
  40. package/dist/types/subprocess/worker-client.d.ts +149 -0
  41. package/dist/types/subprocess/worker-runtime.d.ts +107 -0
  42. package/dist/types/tiny/title-client.d.ts +14 -34
  43. package/dist/types/tools/eval-backends.d.ts +6 -3
  44. package/dist/types/tools/eval-render.d.ts +6 -5
  45. package/dist/types/tools/eval.d.ts +13 -15
  46. package/dist/types/tools/index.d.ts +3 -3
  47. package/dist/types/tts/tts-client.d.ts +3 -28
  48. package/dist/types/tui/code-cell.d.ts +7 -0
  49. package/dist/types/utils/file-display-mode.d.ts +1 -1
  50. package/dist/types/web/parallel.d.ts +6 -0
  51. package/package.json +12 -12
  52. package/src/config/settings-schema.ts +50 -18
  53. package/src/config/settings.ts +5 -0
  54. package/src/dap/client.ts +13 -107
  55. package/src/eval/__tests__/julia-prelude.test.ts +77 -0
  56. package/src/eval/backend-helpers.ts +48 -0
  57. package/src/eval/executor-base.ts +425 -0
  58. package/src/eval/index.ts +2 -0
  59. package/src/eval/jl/executor.ts +540 -0
  60. package/src/eval/jl/index.ts +54 -0
  61. package/src/eval/jl/kernel.ts +235 -0
  62. package/src/eval/jl/prelude.jl +930 -0
  63. package/src/eval/jl/prelude.ts +3 -0
  64. package/src/eval/jl/runner.jl +634 -0
  65. package/src/eval/jl/runtime.ts +118 -0
  66. package/src/eval/js/index.ts +3 -14
  67. package/src/eval/kernel-base.ts +569 -0
  68. package/src/eval/py/executor.ts +43 -252
  69. package/src/eval/py/index.ts +9 -20
  70. package/src/eval/py/kernel.ts +29 -544
  71. package/src/eval/rb/executor.ts +504 -0
  72. package/src/eval/rb/index.ts +54 -0
  73. package/src/eval/rb/kernel.ts +230 -0
  74. package/src/eval/rb/prelude.rb +721 -0
  75. package/src/eval/rb/prelude.ts +3 -0
  76. package/src/eval/rb/runner.rb +474 -0
  77. package/src/eval/rb/runtime.ts +132 -0
  78. package/src/eval/runtime-env.ts +104 -0
  79. package/src/eval/types.ts +3 -3
  80. package/src/extensibility/extensions/runner.ts +4 -11
  81. package/src/extensibility/hooks/loader.ts +3 -21
  82. package/src/extensibility/session-handler-types.ts +21 -0
  83. package/src/internal-urls/docs-index.generated.txt +1 -1
  84. package/src/jsonrpc/message-framing.ts +142 -0
  85. package/src/lsp/client.ts +13 -109
  86. package/src/mnemopi/embed-client.ts +43 -198
  87. package/src/modes/components/agent-dashboard.ts +17 -40
  88. package/src/modes/components/chat-transcript-builder.ts +18 -102
  89. package/src/modes/components/custom-editor.ts +19 -0
  90. package/src/modes/components/extensions/extension-dashboard.ts +4 -13
  91. package/src/modes/components/extensions/extension-list.ts +16 -44
  92. package/src/modes/components/history-search.ts +4 -16
  93. package/src/modes/components/selector-helpers.ts +129 -0
  94. package/src/modes/components/settings-selector.ts +7 -5
  95. package/src/modes/components/tree-selector.ts +13 -18
  96. package/src/modes/controllers/event-controller.ts +3 -9
  97. package/src/modes/controllers/input-controller.ts +32 -54
  98. package/src/modes/interactive-mode.ts +5 -7
  99. package/src/modes/theme/theme.ts +35 -0
  100. package/src/modes/types.ts +0 -2
  101. package/src/modes/utils/copy-targets.ts +3 -2
  102. package/src/modes/utils/interactive-context-helpers.ts +27 -0
  103. package/src/modes/utils/transcript-render-helpers.ts +157 -0
  104. package/src/modes/utils/ui-helpers.ts +21 -126
  105. package/src/prompts/system/system-prompt.md +10 -10
  106. package/src/prompts/tools/bash.md +0 -1
  107. package/src/prompts/tools/eval.md +6 -4
  108. package/src/prompts/tools/find.md +0 -4
  109. package/src/prompts/tools/read.md +1 -2
  110. package/src/prompts/tools/replace.md +1 -1
  111. package/src/prompts/tools/search.md +0 -1
  112. package/src/sdk.ts +13 -7
  113. package/src/session/agent-session.ts +9 -7
  114. package/src/stt/asr-client.ts +35 -215
  115. package/src/stt/asr-worker.ts +29 -181
  116. package/src/subprocess/worker-client.ts +297 -0
  117. package/src/subprocess/worker-runtime.ts +277 -0
  118. package/src/task/executor.ts +4 -4
  119. package/src/tiny/title-client.ts +53 -219
  120. package/src/tiny/worker.ts +29 -180
  121. package/src/tools/eval-backends.ts +10 -3
  122. package/src/tools/eval-render.ts +17 -8
  123. package/src/tools/eval.ts +187 -22
  124. package/src/tools/index.ts +51 -28
  125. package/src/tts/tts-client.ts +38 -206
  126. package/src/tts/tts-worker.ts +23 -97
  127. package/src/tui/code-cell.ts +12 -1
  128. package/src/utils/file-display-mode.ts +2 -3
  129. package/src/web/parallel.ts +43 -42
  130. package/src/web/search/providers/parallel.ts +10 -99
@@ -0,0 +1,425 @@
1
+ import { logger } from "@oh-my-pi/pi-utils";
2
+ import { Settings } from "../config/settings";
3
+ import { OutputSink } from "../session/streaming-output";
4
+ import type { ToolSession } from "../tools";
5
+ import { resolveOutputMaxColumns, resolveOutputSinkHeadBytes } from "../tools/output-meta";
6
+ import { isEvalTimeoutControlEvent } from "./bridge-timeout";
7
+ import type { JsStatusEvent } from "./js/shared/types";
8
+ import type { KernelDisplayOutput } from "./py/display";
9
+ import { registerPyToolBridge } from "./py/tool-bridge";
10
+
11
+ /**
12
+ * Constructor for a language executor's cancellation error. Each backend
13
+ * subclasses {@link Error} and carries a `timedOut` flag distinguishing a
14
+ * deadline expiry from a plain abort.
15
+ */
16
+ export type CancelledErrorClass = new (timedOut: boolean) => Error & { timedOut: boolean };
17
+
18
+ /** Managed-env values a kernel patch may carry (`null` clears, `undefined` skips). */
19
+ export type KernelEnvPatch = Record<string, string | null | undefined>;
20
+
21
+ /**
22
+ * Options every kernel-backed language executor shares. Per-language option
23
+ * interfaces structurally extend this; the base executor only reads these.
24
+ */
25
+ export interface KernelExecutorBaseOptions {
26
+ cwd?: string;
27
+ timeoutMs?: number;
28
+ deadlineMs?: number;
29
+ idleTimeoutMs?: number;
30
+ onChunk?: (chunk: string) => Promise<void> | void;
31
+ signal?: AbortSignal;
32
+ onStatus?: (event: JsStatusEvent) => void;
33
+ emitStatus?: (event: JsStatusEvent) => void;
34
+ toolSession?: ToolSession;
35
+ bridgeSessionId?: string;
36
+ artifactId?: string;
37
+ artifactPath?: string;
38
+ }
39
+
40
+ /** Normalised execution result produced by {@link executeWithKernelBase}. */
41
+ export interface KernelExecutionResult {
42
+ output: string;
43
+ exitCode: number | undefined;
44
+ cancelled: boolean;
45
+ truncated: boolean;
46
+ artifactId: string | undefined;
47
+ totalLines: number;
48
+ totalBytes: number;
49
+ outputLines: number;
50
+ outputBytes: number;
51
+ displayOutputs: KernelDisplayOutput[];
52
+ stdinRequested: boolean;
53
+ }
54
+
55
+ /** Minimal kernel surface the base executor drives, satisfied by every backend kernel. */
56
+ export interface GenericKernel<TEnv> {
57
+ execute(
58
+ code: string,
59
+ options: {
60
+ cwd?: string;
61
+ env?: TEnv;
62
+ id: string;
63
+ signal?: AbortSignal;
64
+ timeoutMs?: number;
65
+ onChunk: (text: string) => Promise<void> | void;
66
+ onDisplay: (output: KernelDisplayOutput) => Promise<void> | void;
67
+ },
68
+ ): Promise<{
69
+ status: "ok" | "error";
70
+ cancelled: boolean;
71
+ timedOut: boolean;
72
+ kernelKilled?: boolean;
73
+ stdinRequested?: boolean;
74
+ }>;
75
+ }
76
+
77
+ // ---------------------------------------------------------------------------
78
+ // Cancellation helpers
79
+ // ---------------------------------------------------------------------------
80
+
81
+ export function getExecutionDeadlineMs(options?: { deadlineMs?: number; timeoutMs?: number }): number | undefined {
82
+ if (options?.deadlineMs !== undefined) return options.deadlineMs;
83
+ if (options?.timeoutMs === undefined) return undefined;
84
+ return Date.now() + options.timeoutMs;
85
+ }
86
+
87
+ export function getRemainingTimeoutMs(deadlineMs?: number): number | undefined {
88
+ if (deadlineMs === undefined) return undefined;
89
+ return deadlineMs - Date.now();
90
+ }
91
+
92
+ export function isCancellationError(error: unknown, cancelledErrorClass: CancelledErrorClass): boolean {
93
+ return (
94
+ error instanceof cancelledErrorClass ||
95
+ (typeof DOMException !== "undefined" &&
96
+ error instanceof DOMException &&
97
+ (error.name === "AbortError" || error.name === "TimeoutError")) ||
98
+ (error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError"))
99
+ );
100
+ }
101
+
102
+ export function isTimedOutCancellation(
103
+ error: unknown,
104
+ cancelledErrorClass: CancelledErrorClass,
105
+ signal?: AbortSignal,
106
+ ): boolean {
107
+ if (error instanceof cancelledErrorClass) return error.timedOut;
108
+ if (typeof DOMException !== "undefined" && error instanceof DOMException) return error.name === "TimeoutError";
109
+ if (error instanceof Error && error.name === "TimeoutError") return true;
110
+ const reason = signal?.reason;
111
+ if (typeof DOMException !== "undefined" && reason instanceof DOMException) return reason.name === "TimeoutError";
112
+ return reason instanceof Error ? reason.name === "TimeoutError" : false;
113
+ }
114
+
115
+ export async function waitForPromiseWithCancellation<T>(
116
+ promise: Promise<T>,
117
+ options: { signal?: AbortSignal; deadlineMs?: number },
118
+ cancelledErrorClass: CancelledErrorClass,
119
+ ): Promise<T> {
120
+ if (options.signal?.aborted) {
121
+ throw new cancelledErrorClass(isTimedOutCancellation(options.signal.reason, cancelledErrorClass, options.signal));
122
+ }
123
+ const remainingMs = getRemainingTimeoutMs(options.deadlineMs);
124
+ if (remainingMs !== undefined && remainingMs <= 0) {
125
+ throw new cancelledErrorClass(true);
126
+ }
127
+ if (!options.signal && remainingMs === undefined) {
128
+ return await promise;
129
+ }
130
+
131
+ const { promise: resultPromise, resolve, reject } = Promise.withResolvers<T>();
132
+ const cleanups: Array<() => void> = [];
133
+ const finish = (cb: () => void): void => {
134
+ while (cleanups.length > 0) cleanups.pop()?.();
135
+ cb();
136
+ };
137
+ if (options.signal) {
138
+ const onAbort = (): void =>
139
+ finish(() =>
140
+ reject(
141
+ new cancelledErrorClass(
142
+ isTimedOutCancellation(options.signal?.reason, cancelledErrorClass, options.signal),
143
+ ),
144
+ ),
145
+ );
146
+ options.signal.addEventListener("abort", onAbort, { once: true });
147
+ cleanups.push(() => options.signal?.removeEventListener("abort", onAbort));
148
+ }
149
+ if (remainingMs !== undefined) {
150
+ const timer = setTimeout(() => finish(() => reject(new cancelledErrorClass(true))), remainingMs);
151
+ timer.unref();
152
+ cleanups.push(() => clearTimeout(timer));
153
+ }
154
+ promise.then(
155
+ value => finish(() => resolve(value)),
156
+ err => finish(() => reject(err)),
157
+ );
158
+ return await resultPromise;
159
+ }
160
+
161
+ export function createCancelledKernelResult(output: string): KernelExecutionResult {
162
+ const outputBytes = Buffer.byteLength(output, "utf-8");
163
+ const outputLines = output.length > 0 ? 1 : 0;
164
+ return {
165
+ output,
166
+ exitCode: undefined,
167
+ cancelled: true,
168
+ truncated: false,
169
+ artifactId: undefined,
170
+ totalLines: outputLines,
171
+ totalBytes: outputBytes,
172
+ outputLines,
173
+ outputBytes,
174
+ displayOutputs: [],
175
+ stdinRequested: false,
176
+ };
177
+ }
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // Managed environment helpers
181
+ // ---------------------------------------------------------------------------
182
+
183
+ export const MANAGED_KERNEL_ENV_KEYS = [
184
+ "PI_SESSION_FILE",
185
+ "PI_ARTIFACTS_DIR",
186
+ "PI_TOOL_BRIDGE_URL",
187
+ "PI_TOOL_BRIDGE_TOKEN",
188
+ "PI_TOOL_BRIDGE_SESSION",
189
+ "PI_EVAL_LOCAL_ROOTS",
190
+ ] as const;
191
+
192
+ interface ManagedKernelEnvOptions {
193
+ sessionFile?: string;
194
+ artifactsDir?: string;
195
+ bridgeSessionId?: string;
196
+ bridge?: { url: string; token: string };
197
+ localRoots?: Record<string, string>;
198
+ }
199
+
200
+ export function buildManagedKernelEnvPatch(options: ManagedKernelEnvOptions): Record<string, string | null> {
201
+ const localRoots = options.localRoots;
202
+ return {
203
+ PI_SESSION_FILE: options.sessionFile ?? null,
204
+ PI_ARTIFACTS_DIR: options.artifactsDir ?? null,
205
+ PI_TOOL_BRIDGE_URL: options.bridge?.url ?? null,
206
+ PI_TOOL_BRIDGE_TOKEN: options.bridge?.token ?? null,
207
+ PI_TOOL_BRIDGE_SESSION: options.bridge && options.bridgeSessionId ? options.bridgeSessionId : null,
208
+ PI_EVAL_LOCAL_ROOTS: localRoots && Object.keys(localRoots).length > 0 ? JSON.stringify(localRoots) : null,
209
+ };
210
+ }
211
+
212
+ export function buildManagedKernelEnv(options: ManagedKernelEnvOptions): Record<string, string> | undefined {
213
+ const patch = buildManagedKernelEnvPatch(options);
214
+ const env: Record<string, string> = {};
215
+ let hasKeys = false;
216
+ for (const key of MANAGED_KERNEL_ENV_KEYS) {
217
+ const value = patch[key];
218
+ if (value !== null) {
219
+ env[key] = value;
220
+ hasKeys = true;
221
+ }
222
+ }
223
+ return hasKeys ? env : undefined;
224
+ }
225
+
226
+ export function attachSessionOwner(
227
+ session: { ownerIds: Set<string>; hasFallbackOwner: boolean },
228
+ sessionId: string,
229
+ ownerId: string | undefined,
230
+ ): void {
231
+ if (ownerId !== undefined) {
232
+ if (session.hasFallbackOwner) {
233
+ session.ownerIds.delete(sessionId);
234
+ session.hasFallbackOwner = false;
235
+ }
236
+ session.ownerIds.add(ownerId);
237
+ return;
238
+ }
239
+ if (session.hasFallbackOwner || session.ownerIds.size === 0) {
240
+ session.ownerIds.add(sessionId);
241
+ session.hasFallbackOwner = true;
242
+ }
243
+ }
244
+
245
+ // ---------------------------------------------------------------------------
246
+ // Base executor implementation
247
+ // ---------------------------------------------------------------------------
248
+
249
+ export interface ExecuteWithKernelBaseParams<
250
+ TOptions extends KernelExecutorBaseOptions,
251
+ TEnv extends KernelEnvPatch = Record<string, string | null>,
252
+ > {
253
+ kernel: GenericKernel<TEnv>;
254
+ code: string;
255
+ options: TOptions | undefined;
256
+ /** Prefix for the per-execution run id (e.g. `"py"`, `"rb"`, `"jl"`). */
257
+ runIdPrefix: string;
258
+ /** Human-readable language label used in the failure log line. */
259
+ errorLogLabel: string;
260
+ /**
261
+ * Julia surfaces eval-timeout control events through its normal status path,
262
+ * so they must NOT be filtered out the way the JS-status backends do.
263
+ */
264
+ isJulia?: boolean;
265
+ cancelledErrorClass: CancelledErrorClass;
266
+ buildKernelEnvPatch: (options: TOptions) => TEnv;
267
+ formatKernelTimeoutAnnotation: (executionTimeoutMs: number | undefined, kernelKilled: boolean) => string;
268
+ formatTimeoutAnnotation: (executionTimeoutMs: number | undefined) => string | undefined;
269
+ /**
270
+ * Override how the wall-clock deadline is derived from options. Defaults to
271
+ * {@link getExecutionDeadlineMs}; Julia passes the pre-computed `deadlineMs`
272
+ * straight through instead of re-deriving from `timeoutMs`.
273
+ */
274
+ resolveDeadlineMs?: (options: TOptions | undefined) => number | undefined;
275
+ }
276
+
277
+ export async function executeWithKernelBase<
278
+ TOptions extends KernelExecutorBaseOptions,
279
+ TEnv extends KernelEnvPatch = Record<string, string | null>,
280
+ >(params: ExecuteWithKernelBaseParams<TOptions, TEnv>): Promise<KernelExecutionResult> {
281
+ const {
282
+ kernel,
283
+ code,
284
+ options,
285
+ runIdPrefix,
286
+ errorLogLabel,
287
+ isJulia,
288
+ cancelledErrorClass,
289
+ buildKernelEnvPatch,
290
+ formatKernelTimeoutAnnotation,
291
+ formatTimeoutAnnotation,
292
+ resolveDeadlineMs,
293
+ } = params;
294
+
295
+ const settings = await Settings.init();
296
+ const sink = new OutputSink({
297
+ onChunk: options?.onChunk,
298
+ artifactPath: options?.artifactPath,
299
+ artifactId: options?.artifactId,
300
+ headBytes: resolveOutputSinkHeadBytes(settings),
301
+ maxColumns: resolveOutputMaxColumns(settings),
302
+ });
303
+
304
+ const displayOutputs: KernelDisplayOutput[] = [];
305
+ const deadlineMs = (resolveDeadlineMs ?? getExecutionDeadlineMs)(options);
306
+ let executionTimeoutMs: number | undefined;
307
+
308
+ const collectDisplay = (output: KernelDisplayOutput): void => {
309
+ if (output.type === "status") {
310
+ options?.onStatus?.(output.event);
311
+ if (!isJulia && isEvalTimeoutControlEvent(output.event)) return;
312
+ }
313
+ displayOutputs.push(output);
314
+ };
315
+
316
+ const emitStatus: (event: JsStatusEvent) => void =
317
+ options?.emitStatus ?? (event => collectDisplay({ type: "status", event }));
318
+ const runId = `${runIdPrefix}-${crypto.randomUUID()}`;
319
+ const unregisterBridge =
320
+ options?.toolSession && options?.bridgeSessionId
321
+ ? registerPyToolBridge(options.bridgeSessionId, runId, {
322
+ toolSession: options.toolSession,
323
+ signal: options.signal,
324
+ emitStatus,
325
+ })
326
+ : null;
327
+
328
+ try {
329
+ const remainingMs = getRemainingTimeoutMs(deadlineMs);
330
+ if (remainingMs !== undefined) {
331
+ if (remainingMs <= 0) {
332
+ throw new cancelledErrorClass(true);
333
+ }
334
+ executionTimeoutMs = remainingMs;
335
+ }
336
+
337
+ const result = await kernel.execute(code, {
338
+ cwd: options?.cwd,
339
+ env: buildKernelEnvPatch(options ?? ({} as TOptions)),
340
+ id: runId,
341
+ signal: options?.signal,
342
+ timeoutMs: executionTimeoutMs,
343
+ onChunk: text => sink.push(text),
344
+ onDisplay: output => collectDisplay(output),
345
+ });
346
+
347
+ if (result.cancelled) {
348
+ const annotation = result.timedOut
349
+ ? formatKernelTimeoutAnnotation(executionTimeoutMs ?? options?.idleTimeoutMs, result.kernelKilled ?? false)
350
+ : undefined;
351
+ const dumped = await sink.dump(annotation);
352
+ return {
353
+ exitCode: undefined,
354
+ cancelled: true,
355
+ truncated: dumped.truncated,
356
+ output: dumped.output,
357
+ artifactId: dumped.artifactId ?? undefined,
358
+ totalLines: dumped.totalLines,
359
+ totalBytes: dumped.totalBytes,
360
+ outputLines: dumped.outputLines,
361
+ outputBytes: dumped.outputBytes,
362
+ displayOutputs,
363
+ stdinRequested: !!result.stdinRequested,
364
+ };
365
+ }
366
+
367
+ if (result.stdinRequested) {
368
+ const dumped = await sink.dump("Kernel requested stdin; interactive input is not supported.");
369
+ return {
370
+ exitCode: 1,
371
+ cancelled: false,
372
+ truncated: dumped.truncated,
373
+ output: dumped.output,
374
+ artifactId: dumped.artifactId ?? undefined,
375
+ totalLines: dumped.totalLines,
376
+ totalBytes: dumped.totalBytes,
377
+ outputLines: dumped.outputLines,
378
+ outputBytes: dumped.outputBytes,
379
+ displayOutputs,
380
+ stdinRequested: true,
381
+ };
382
+ }
383
+
384
+ const exitCode = result.status === "ok" ? 0 : 1;
385
+ const dumped = await sink.dump();
386
+ return {
387
+ exitCode,
388
+ cancelled: false,
389
+ truncated: dumped.truncated,
390
+ output: dumped.output,
391
+ artifactId: dumped.artifactId ?? undefined,
392
+ totalLines: dumped.totalLines,
393
+ totalBytes: dumped.totalBytes,
394
+ outputLines: dumped.outputLines,
395
+ outputBytes: dumped.outputBytes,
396
+ displayOutputs,
397
+ stdinRequested: false,
398
+ };
399
+ } catch (err) {
400
+ if (isCancellationError(err, cancelledErrorClass) || options?.signal?.aborted) {
401
+ const timedOut = isTimedOutCancellation(err, cancelledErrorClass, options?.signal);
402
+ const dumped = await sink.dump(
403
+ timedOut ? formatTimeoutAnnotation(executionTimeoutMs ?? options?.idleTimeoutMs) : undefined,
404
+ );
405
+ return {
406
+ exitCode: undefined,
407
+ cancelled: true,
408
+ truncated: dumped.truncated,
409
+ output: dumped.output,
410
+ artifactId: dumped.artifactId ?? undefined,
411
+ totalLines: dumped.totalLines,
412
+ totalBytes: dumped.totalBytes,
413
+ outputLines: dumped.outputLines,
414
+ outputBytes: dumped.outputBytes,
415
+ displayOutputs,
416
+ stdinRequested: false,
417
+ };
418
+ }
419
+ const error = err instanceof Error ? err : new Error(String(err));
420
+ logger.error(`${errorLogLabel} execution failed`, { error: error.message });
421
+ throw error;
422
+ } finally {
423
+ unregisterBridge?.();
424
+ }
425
+ }
package/src/eval/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./backend";
2
+ export { default as juliaBackend } from "./jl";
2
3
  export { default as jsBackend } from "./js";
3
4
  export { default as pythonBackend } from "./py";
5
+ export { default as rubyBackend } from "./rb";
4
6
  export * from "./types";