@poe-platform/safe-bash 0.1.662 → 0.1.664

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.
@@ -0,0 +1,16 @@
1
+ import type { PythonAsyncExecutor } from './index.js';
2
+ export interface PythonExecutorPoolOptions {
3
+ readonly createExecutor: () => PythonAsyncExecutor;
4
+ readonly maxConcurrentExecutors: number;
5
+ }
6
+ export interface PythonExecutorPool {
7
+ createExecutor(): PythonAsyncExecutor;
8
+ inspect(): {
9
+ readonly active: number;
10
+ readonly capacity: number;
11
+ readonly closed: boolean;
12
+ };
13
+ dispose(): Promise<void>;
14
+ }
15
+ export declare function createPythonExecutorPool(options: PythonExecutorPoolOptions): PythonExecutorPool;
16
+ //# sourceMappingURL=executor-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor-pool.d.ts","sourceRoot":"","sources":["../../../src/commands/python/executor-pool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,YAAY,CAAC;AAG3E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,cAAc,EAAE,MAAM,mBAAmB,CAAC;IACnD,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,IAAI,mBAAmB,CAAC;IACtC,OAAO,IAAI;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5F,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAsE/F"}
@@ -0,0 +1,90 @@
1
+ import { PythonFailure } from './diagnostics.js';
2
+ export function createPythonExecutorPool(options) {
3
+ if (typeof options?.createExecutor !== 'function')
4
+ throw new TypeError('Python executor pool requires a factory');
5
+ const factory = options.createExecutor;
6
+ const capacity = options.maxConcurrentExecutors;
7
+ if (!Number.isSafeInteger(capacity) || capacity < 1)
8
+ throw new RangeError('Invalid Python executor pool capacity');
9
+ const entries = new Set();
10
+ let closed = false;
11
+ let disposal;
12
+ return {
13
+ createExecutor() {
14
+ if (closed)
15
+ throw new PythonFailure('executor-unavailable');
16
+ if (entries.size >= capacity)
17
+ throw new PythonFailure('capacity');
18
+ let acquired;
19
+ const acquisition = new Promise(resolve => { acquired = resolve; });
20
+ let retirement;
21
+ let execution;
22
+ let started = false;
23
+ const entry = {
24
+ retire() {
25
+ retirement ??= Promise.resolve().then(async () => {
26
+ const executor = await acquisition;
27
+ if (executor !== undefined) {
28
+ const results = await Promise.allSettled([Promise.resolve().then(() => {
29
+ const terminate = executor?.terminate;
30
+ if (typeof terminate !== 'function')
31
+ throw new PythonFailure('cleanup');
32
+ return terminate.call(executor);
33
+ }), execution]);
34
+ const failed = results.find(result => result.status === 'rejected');
35
+ if (failed?.status === 'rejected')
36
+ throw failed.reason;
37
+ }
38
+ entries.delete(entry);
39
+ });
40
+ return retirement;
41
+ },
42
+ };
43
+ entries.add(entry);
44
+ let executor;
45
+ try {
46
+ executor = factory();
47
+ }
48
+ catch (error) {
49
+ acquired(undefined);
50
+ entries.delete(entry);
51
+ throw error;
52
+ }
53
+ acquired(executor);
54
+ try {
55
+ if (closed || !executor || typeof executor.run !== 'function' || typeof executor.terminate !== 'function')
56
+ throw new PythonFailure('executor-unavailable');
57
+ }
58
+ catch (error) {
59
+ void entry.retire().catch(() => { });
60
+ throw error;
61
+ }
62
+ return {
63
+ async run(start) {
64
+ if (started || closed || retirement)
65
+ throw new PythonFailure('executor-unavailable');
66
+ started = true;
67
+ const running = Promise.resolve().then(() => {
68
+ if (closed || retirement)
69
+ throw new PythonFailure('executor-unavailable');
70
+ return executor.run(start);
71
+ });
72
+ execution = running.then(() => { }, () => { });
73
+ return running;
74
+ },
75
+ terminate: entry.retire,
76
+ };
77
+ },
78
+ inspect() { return { active: entries.size, capacity, closed }; },
79
+ dispose() {
80
+ closed = true;
81
+ disposal ??= Promise.allSettled([...entries].map(entry => entry.retire())).then(results => {
82
+ const failed = results.find(result => result.status === 'rejected');
83
+ if (failed?.status === 'rejected')
84
+ throw failed.reason;
85
+ });
86
+ return disposal;
87
+ },
88
+ };
89
+ }
90
+ //# sourceMappingURL=executor-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor-pool.js","sourceRoot":"","sources":["../../../src/commands/python/executor-pool.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,18 @@
1
1
  import {
2
2
  PythonPackageConflictError,
3
3
  createPythonCommands,
4
+ createPythonExecutorPool,
4
5
  createPythonPackageCache,
5
6
  createPythonPackageEnvironment,
6
7
  createPythonPackageManifestStore,
7
8
  pythonCommands,
8
9
  pythonDocumentPackages
9
- } from "../../chunks/chunk-Z4UKD5FF.js";
10
+ } from "../../chunks/chunk-6VT3VSBX.js";
10
11
  import "../../chunks/chunk-2E4KBFO6.js";
11
12
  import {
12
13
  PythonFailure,
13
14
  inspectPythonCapabilities
14
- } from "../../chunks/chunk-Y7MAMRAF.js";
15
+ } from "../../chunks/chunk-AJ355TRJ.js";
15
16
  import "../../chunks/chunk-CDBQXRWL.js";
16
17
  import "../../chunks/chunk-THXJ6CLF.js";
17
18
  import "../../chunks/chunk-CHHAB5SS.js";
@@ -22,6 +23,7 @@ export {
22
23
  PythonFailure,
23
24
  PythonPackageConflictError,
24
25
  createPythonCommands,
26
+ createPythonExecutorPool,
25
27
  createPythonPackageCache,
26
28
  createPythonPackageEnvironment,
27
29
  createPythonPackageManifestStore,
@@ -12,7 +12,8 @@ export interface PythonInitializationProgress {
12
12
  readonly command: string;
13
13
  }
14
14
  export interface PythonCommandsOptions {
15
- readonly createWorker: () => PythonWorkerEndpoint;
15
+ readonly createWorker?: () => PythonWorkerEndpoint;
16
+ readonly createExecutor?: () => PythonAsyncExecutor;
16
17
  /** Explicit distribution requirements; no import scanning or implicit package downloads. */
17
18
  readonly packages?: readonly string[];
18
19
  /** Requirements files in the canonical filesystem. */
@@ -46,6 +47,18 @@ export interface PythonWorkerStart {
46
47
  readonly runtimeMount: string;
47
48
  readonly maxTransferBytes: number;
48
49
  }
50
+ export interface PythonExecutorStart extends Omit<PythonWorkerStart, 'type' | 'shared'> {
51
+ readonly signal: AbortSignal;
52
+ dispatch(request: {
53
+ readonly op: string;
54
+ readonly args: unknown[];
55
+ }): Promise<unknown>;
56
+ onReady(): void;
57
+ }
58
+ export interface PythonAsyncExecutor {
59
+ run(start: PythonExecutorStart): Promise<number>;
60
+ terminate(): void | Promise<void>;
61
+ }
49
62
  export declare function createPythonCommands(options: PythonCommandsOptions): readonly CommandDefinition[];
50
63
  export declare function pythonCommands(options: PythonCommandsOptions): VirtualShellPlugin;
51
64
  export { createPythonPackageEnvironment, pythonDocumentPackages } from './provisioning.js';
@@ -53,6 +66,8 @@ export type { PythonPackageOptions, PythonPackageCache, PythonPackageProgress, P
53
66
  export { PythonPackageConflictError, createPythonPackageManifestStore } from './manifest.js';
54
67
  export type { PythonPackageManifest, PythonPackageManifestStore } from './manifest.js';
55
68
  export { createPythonPackageCache } from './cache.js';
69
+ export { createPythonExecutorPool } from './executor-pool.js';
70
+ export type { PythonExecutorPool, PythonExecutorPoolOptions } from './executor-pool.js';
56
71
  export { PythonFailure, inspectPythonCapabilities } from './diagnostics.js';
57
72
  export type { PythonFailureCategory, PythonDiagnostic, PythonDiagnosticObserver, PythonFileSystemRequirement, PythonCapabilityOptions, PythonCapabilityReport } from './diagnostics.js';
58
73
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/python/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/python/index.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,9 @@ import { PythonFailure, isPythonFailureCategory, reportPythonFailure } from './d
12
12
  class PythonInputChunkError extends RangeError {
13
13
  }
14
14
  export function createPythonCommands(options) {
15
- if (typeof options?.createWorker !== 'function')
15
+ if (!options || (typeof options.createWorker === 'function') === (typeof options.createExecutor === 'function')
16
+ || options.createWorker !== undefined && typeof options.createWorker !== 'function'
17
+ || options.createExecutor !== undefined && typeof options.createExecutor !== 'function')
16
18
  throw new PythonFailure('executor-unavailable');
17
19
  if (options.onDiagnostic !== undefined && typeof options.onDiagnostic !== 'function')
18
20
  throw new TypeError('Python onDiagnostic must be a function');
@@ -67,6 +69,7 @@ export function createPythonCommands(options) {
67
69
  let stdoutOperation;
68
70
  let stderrOperation;
69
71
  let endpoint;
72
+ let executor;
70
73
  let packages;
71
74
  let unsubscribe;
72
75
  let admitted = false;
@@ -89,7 +92,7 @@ export function createPythonCommands(options) {
89
92
  void (async () => {
90
93
  signal.removeEventListener('abort', aborted);
91
94
  const subscription = Promise.resolve().then(() => unsubscribe?.());
92
- const termination = Promise.resolve().then(() => endpoint?.terminate());
95
+ const termination = Promise.resolve().then(() => executor ? executor.terminate() : endpoint?.terminate());
93
96
  const results = await Promise.allSettled([subscription, termination, service.close(), stdoutOperation?.close(), stderrOperation?.close(), ...pending]);
94
97
  await input.return?.(undefined);
95
98
  fragment = undefined;
@@ -123,36 +126,17 @@ export function createPythonCommands(options) {
123
126
  const outputContext = { signal, ...(context.registerCleanup ? { registerCleanup: context.registerCleanup } : {}) };
124
127
  stdoutOperation = createOutputOperation(outputContext, context.stdout);
125
128
  stderrOperation = createOutputOperation(outputContext, context.stderr);
126
- let shared;
127
- try {
128
- shared = new SharedArrayBuffer(8 + maxTransferBytes * 6 + 65536);
129
- }
130
- catch (reason) {
131
- throw reportPythonFailure('transport-unavailable', reason, options.onDiagnostic);
132
- }
133
- const control = new Int32Array(shared, 0, 2);
134
- const payload = new Uint8Array(shared, 8);
135
- const reply = (value, status) => {
136
- if (closed)
129
+ const diagnoseFilesystemFailure = async (operation, error) => {
130
+ if (typeof error !== 'object' || error === null || !('code' in error) || error.code !== 'ENOTSUP')
137
131
  return;
138
- let bytes;
139
- try {
140
- bytes = encodePythonReply(value, payload.length);
141
- }
142
- catch (error) {
143
- if (typeof error !== 'object' || error === null || !('code' in error) || error.code !== 'EFBIG')
144
- throw error;
145
- bytes = encodePythonReply({ code: 'EFBIG' }, payload.length);
146
- status = 2;
147
- }
148
- payload.set(bytes);
149
- try {
150
- Atomics.store(control, 1, bytes.length);
151
- Atomics.store(control, 0, status);
152
- Atomics.notify(control, 0);
153
- }
154
- catch (reason) {
155
- throw reportPythonFailure('transport-unavailable', reason, options.onDiagnostic);
132
+ const category = operation === 'open' ? 'filesystem-open'
133
+ : operation === 'read' ? 'filesystem-read'
134
+ : operation === 'write' || operation === 'ftruncate' ? 'filesystem-write'
135
+ : operation === 'readdir' ? 'filesystem-directory' : 'filesystem-operation';
136
+ if (!filesystemDiagnostics.has(category)) {
137
+ filesystemDiagnostics.add(category);
138
+ const failure = reportPythonFailure(category, error, options.onDiagnostic);
139
+ await writeBytes(stderrOperation.output, new TextEncoder().encode('python: ' + failure.message + '\n'), signal);
156
140
  }
157
141
  };
158
142
  const dispatch = async (request) => {
@@ -208,110 +192,216 @@ export function createPythonCommands(options) {
208
192
  pending.delete(preparation);
209
193
  }
210
194
  signal.throwIfAborted();
211
- try {
212
- endpoint = options.createWorker();
213
- }
214
- catch (reason) {
215
- throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : 'startup', reason, options.onDiagnostic);
216
- }
217
- signal.throwIfAborted();
218
- result = await new Promise((resolve, reject) => {
219
- let settled = false;
220
- const fail = (reason) => { settled = true; reject(reason); };
221
- rejectRun = fail;
222
- signal.addEventListener('abort', aborted, { once: true });
223
- const transportFailure = (reason) => { fail(reportPythonFailure('transport-unavailable', reason, options.onDiagnostic)); };
195
+ if (options.createExecutor) {
224
196
  try {
225
- unsubscribe = endpoint.subscribe(value => {
226
- if (closed || settled)
227
- return;
228
- if (typeof value !== 'object' || value === null) {
229
- transportFailure(new TypeError('Invalid Python worker message'));
197
+ executor = options.createExecutor();
198
+ }
199
+ catch (reason) {
200
+ throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : 'startup', reason, options.onDiagnostic);
201
+ }
202
+ if (!executor || typeof executor.run !== 'function' || typeof executor.terminate !== 'function')
203
+ throw reportPythonFailure('executor-unavailable', undefined, options.onDiagnostic);
204
+ let requesting = false;
205
+ let running = true;
206
+ const start = {
207
+ invocation: { command: context.command, args: [...context.args], cwd: context.cwd, env: { ...context.env } },
208
+ runtimeMount, maxTransferBytes, signal, ...(packages ? { packages } : {}), installOnly: !!installation,
209
+ onReady() {
210
+ if (closed || !running || signal.aborted || ready)
230
211
  return;
212
+ ready = true;
213
+ try {
214
+ options.onProgress?.({ phase: 'ready', command: context.command });
231
215
  }
232
- const message = value;
233
- if (message.type === 'ready') {
234
- ready = true;
235
- try {
236
- options.onProgress?.({ phase: 'ready', command: context.command });
237
- }
238
- catch (error) {
239
- fail(error);
240
- }
241
- return;
216
+ catch (reason) {
217
+ running = false;
218
+ rejectRun?.(reason);
219
+ throw reason;
220
+ }
221
+ },
222
+ async dispatch(request) {
223
+ signal.throwIfAborted();
224
+ if (closed || !running || requesting || !request || typeof request.op !== 'string' || !Array.isArray(request.args))
225
+ throw reportPythonFailure('transport-unavailable', undefined, options.onDiagnostic);
226
+ requesting = true;
227
+ const operation = Promise.resolve().then(() => dispatch(request)).catch(async (error) => {
228
+ signal.throwIfAborted();
229
+ if (error instanceof PythonInputChunkError)
230
+ rejectRun?.(error);
231
+ if (request.op.startsWith('package-'))
232
+ throw Object.assign(reportPythonFailure('runtime-assets', error, options.onDiagnostic), { code: 'EPACKAGE' });
233
+ await diagnoseFilesystemFailure(request.op, error);
234
+ throw error;
235
+ });
236
+ const tracked = operation.then(() => { }, () => { });
237
+ pending.add(tracked);
238
+ try {
239
+ return await operation;
240
+ }
241
+ finally {
242
+ requesting = false;
243
+ pending.delete(tracked);
242
244
  }
243
- if (message.type === 'exit') {
244
- if (pending.size) {
245
- transportFailure(new TypeError('Python worker exited with an outstanding request'));
245
+ },
246
+ };
247
+ const execution = Promise.resolve().then(() => {
248
+ signal.throwIfAborted();
249
+ return executor.run(start);
250
+ }).catch(reason => {
251
+ running = false;
252
+ if (signal.aborted)
253
+ throw signal.reason;
254
+ throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : ready ? 'runtime' : 'startup', reason, options.onDiagnostic);
255
+ }).then(status => {
256
+ running = false;
257
+ if (requesting)
258
+ throw reportPythonFailure('transport-unavailable', undefined, options.onDiagnostic);
259
+ try {
260
+ return validateExitCode(status);
261
+ }
262
+ catch (reason) {
263
+ throw reportPythonFailure('transport-unavailable', reason, options.onDiagnostic);
264
+ }
265
+ });
266
+ const tracked = execution.then(() => { }, () => { });
267
+ pending.add(tracked);
268
+ void tracked.then(() => pending.delete(tracked));
269
+ result = await new Promise((resolve, reject) => {
270
+ rejectRun = reject;
271
+ signal.addEventListener('abort', aborted, { once: true });
272
+ if (signal.aborted)
273
+ aborted();
274
+ execution.then(resolve, reject);
275
+ });
276
+ }
277
+ else {
278
+ let shared;
279
+ try {
280
+ shared = new SharedArrayBuffer(8 + maxTransferBytes * 6 + 65536);
281
+ }
282
+ catch (reason) {
283
+ throw reportPythonFailure('transport-unavailable', reason, options.onDiagnostic);
284
+ }
285
+ const control = new Int32Array(shared, 0, 2);
286
+ const payload = new Uint8Array(shared, 8);
287
+ const reply = (value, status) => {
288
+ if (closed)
289
+ return;
290
+ let bytes;
291
+ try {
292
+ bytes = encodePythonReply(value, payload.length);
293
+ }
294
+ catch (error) {
295
+ if (typeof error !== 'object' || error === null || !('code' in error) || error.code !== 'EFBIG')
296
+ throw error;
297
+ bytes = encodePythonReply({ code: 'EFBIG' }, payload.length);
298
+ status = 2;
299
+ }
300
+ payload.set(bytes);
301
+ try {
302
+ Atomics.store(control, 1, bytes.length);
303
+ Atomics.store(control, 0, status);
304
+ Atomics.notify(control, 0);
305
+ }
306
+ catch (reason) {
307
+ throw reportPythonFailure('transport-unavailable', reason, options.onDiagnostic);
308
+ }
309
+ };
310
+ try {
311
+ endpoint = options.createWorker();
312
+ }
313
+ catch (reason) {
314
+ throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : 'startup', reason, options.onDiagnostic);
315
+ }
316
+ signal.throwIfAborted();
317
+ result = await new Promise((resolve, reject) => {
318
+ let settled = false;
319
+ const fail = (reason) => { settled = true; reject(reason); };
320
+ rejectRun = fail;
321
+ signal.addEventListener('abort', aborted, { once: true });
322
+ const transportFailure = (reason) => { fail(reportPythonFailure('transport-unavailable', reason, options.onDiagnostic)); };
323
+ try {
324
+ unsubscribe = endpoint.subscribe(value => {
325
+ if (closed || settled)
326
+ return;
327
+ if (typeof value !== 'object' || value === null) {
328
+ transportFailure(new TypeError('Invalid Python worker message'));
246
329
  return;
247
330
  }
248
- try {
249
- const status = validateExitCode(message.exitCode);
250
- settled = true;
251
- resolve(status);
252
- }
253
- catch (error) {
254
- transportFailure(error);
331
+ const message = value;
332
+ if (message.type === 'ready') {
333
+ ready = true;
334
+ try {
335
+ options.onProgress?.({ phase: 'ready', command: context.command });
336
+ }
337
+ catch (error) {
338
+ fail(error);
339
+ }
340
+ return;
255
341
  }
256
- return;
257
- }
258
- if (message.type === 'error') {
259
- fail(reportPythonFailure(isPythonFailureCategory(message.category) ? message.category : ready ? 'runtime' : 'startup', message.message, options.onDiagnostic));
260
- return;
261
- }
262
- if (typeof message.op !== 'string' || !Array.isArray(message.args) || pending.size) {
263
- transportFailure(new TypeError('Invalid concurrent Python worker request'));
264
- return;
265
- }
266
- const work = dispatch({ op: message.op, args: message.args }).then(value => { pending.delete(work); reply(value, 1); }, async (error) => {
267
- if (signal.aborted) {
268
- pending.delete(work);
269
- fail(signal.reason);
342
+ if (message.type === 'exit') {
343
+ if (pending.size) {
344
+ transportFailure(new TypeError('Python worker exited with an outstanding request'));
345
+ return;
346
+ }
347
+ try {
348
+ const status = validateExitCode(message.exitCode);
349
+ settled = true;
350
+ resolve(status);
351
+ }
352
+ catch (error) {
353
+ transportFailure(error);
354
+ }
270
355
  return;
271
356
  }
272
- if (typeof message.op === 'string' && message.op.startsWith('package-')) {
273
- const failure = reportPythonFailure('runtime-assets', error, options.onDiagnostic);
274
- pending.delete(work);
275
- reply({ code: 'EPACKAGE', message: failure.message }, 2);
357
+ if (message.type === 'error') {
358
+ fail(reportPythonFailure(isPythonFailureCategory(message.category) ? message.category : ready ? 'runtime' : 'startup', message.message, options.onDiagnostic));
276
359
  return;
277
360
  }
278
- if (typeof error !== 'object' || error === null || !('code' in error) || typeof error.code !== 'string') {
279
- pending.delete(work);
280
- fail(error);
361
+ if (typeof message.op !== 'string' || !Array.isArray(message.args) || pending.size) {
362
+ transportFailure(new TypeError('Invalid concurrent Python worker request'));
281
363
  return;
282
364
  }
283
- if (error.code === 'ENOTSUP') {
284
- const category = message.op === 'open' ? 'filesystem-open'
285
- : message.op === 'read' ? 'filesystem-read'
286
- : message.op === 'write' || message.op === 'ftruncate' ? 'filesystem-write'
287
- : message.op === 'readdir' ? 'filesystem-directory' : 'filesystem-operation';
288
- if (!filesystemDiagnostics.has(category)) {
289
- filesystemDiagnostics.add(category);
290
- const failure = reportPythonFailure(category, error, options.onDiagnostic);
291
- await writeBytes(stderrOperation.output, new TextEncoder().encode('python: ' + failure.message + '\n'), signal);
365
+ const work = dispatch({ op: message.op, args: message.args }).then(value => { pending.delete(work); reply(value, 1); }, async (error) => {
366
+ if (signal.aborted) {
367
+ pending.delete(work);
368
+ fail(signal.reason);
369
+ return;
292
370
  }
293
- }
294
- pending.delete(work);
295
- reply({ code: error.code }, 2);
296
- });
297
- pending.add(work);
298
- void work.catch(reason => { pending.delete(work); fail(reason); });
299
- }, transportFailure);
300
- }
301
- catch (reason) {
302
- transportFailure(reason);
303
- }
304
- if (settled)
305
- return;
306
- const start = { type: 'start', shared, invocation: { command: context.command, args: [...context.args], cwd: context.cwd, env: { ...context.env } }, runtimeMount, maxTransferBytes, ...(packages ? { packages } : {}), installOnly: !!installation };
307
- signal.throwIfAborted();
308
- try {
309
- endpoint.postMessage(start);
310
- }
311
- catch (reason) {
312
- transportFailure(reason);
313
- }
314
- });
371
+ if (typeof message.op === 'string' && message.op.startsWith('package-')) {
372
+ const failure = reportPythonFailure('runtime-assets', error, options.onDiagnostic);
373
+ pending.delete(work);
374
+ reply({ code: 'EPACKAGE', message: failure.message }, 2);
375
+ return;
376
+ }
377
+ if (typeof error !== 'object' || error === null || !('code' in error) || typeof error.code !== 'string') {
378
+ pending.delete(work);
379
+ fail(error);
380
+ return;
381
+ }
382
+ await diagnoseFilesystemFailure(message.op, error);
383
+ pending.delete(work);
384
+ reply({ code: error.code }, 2);
385
+ });
386
+ pending.add(work);
387
+ void work.catch(reason => { pending.delete(work); fail(reason); });
388
+ }, transportFailure);
389
+ }
390
+ catch (reason) {
391
+ transportFailure(reason);
392
+ }
393
+ if (settled)
394
+ return;
395
+ const start = { type: 'start', shared, invocation: { command: context.command, args: [...context.args], cwd: context.cwd, env: { ...context.env } }, runtimeMount, maxTransferBytes, ...(packages ? { packages } : {}), installOnly: !!installation };
396
+ signal.throwIfAborted();
397
+ try {
398
+ endpoint.postMessage(start);
399
+ }
400
+ catch (reason) {
401
+ transportFailure(reason);
402
+ }
403
+ });
404
+ }
315
405
  }
316
406
  catch (reason) {
317
407
  if (!signal.aborted && reason instanceof PythonInputChunkError) {
@@ -350,10 +440,10 @@ export function createPythonCommands(options) {
350
440
  }
351
441
  return { exitCode: result };
352
442
  };
353
- return ['python', 'python3'].map(name => ({ name, description: 'Python with an explicit synchronous interpreter worker and canonical filesystem', execute }));
443
+ return ['python', 'python3'].map(name => ({ name, description: 'Python with an explicit interpreter executor and canonical filesystem', execute }));
354
444
  }
355
445
  export function pythonCommands(options) {
356
- if (typeof options?.createWorker !== 'function')
446
+ if (!options || (typeof options.createWorker === 'function') === (typeof options.createExecutor === 'function'))
357
447
  throw new PythonFailure('executor-unavailable');
358
448
  if (options?.environment && options.provisioning)
359
449
  throw new TypeError('A borrowed Python environment cannot be combined with provisioning options');
@@ -372,5 +462,6 @@ export function pythonCommands(options) {
372
462
  export { createPythonPackageEnvironment, pythonDocumentPackages } from './provisioning.js';
373
463
  export { PythonPackageConflictError, createPythonPackageManifestStore } from './manifest.js';
374
464
  export { createPythonPackageCache } from './cache.js';
465
+ export { createPythonExecutorPool } from './executor-pool.js';
375
466
  export { PythonFailure, inspectPythonCapabilities } from './diagnostics.js';
376
467
  //# sourceMappingURL=index.js.map