@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.
@@ -7,7 +7,7 @@ import {
7
7
  isPythonFailureCategory,
8
8
  parsePythonInvocation,
9
9
  reportPythonFailure
10
- } from "./chunk-Y7MAMRAF.js";
10
+ } from "./chunk-AJ355TRJ.js";
11
11
  import {
12
12
  createOutputOperation
13
13
  } from "./chunk-CDBQXRWL.js";
@@ -1338,11 +1338,97 @@ function createPythonPackageEnvironment(options = {}) {
1338
1338
  };
1339
1339
  }
1340
1340
 
1341
+ // packages/safe-bash/src/commands/python/executor-pool.ts
1342
+ init_platform();
1343
+ function createPythonExecutorPool(options) {
1344
+ if (typeof options?.createExecutor !== "function") throw new TypeError("Python executor pool requires a factory");
1345
+ const factory = options.createExecutor;
1346
+ const capacity = options.maxConcurrentExecutors;
1347
+ if (!Number.isSafeInteger(capacity) || capacity < 1) throw new RangeError("Invalid Python executor pool capacity");
1348
+ const entries = /* @__PURE__ */ new Set();
1349
+ let closed = false;
1350
+ let disposal;
1351
+ return {
1352
+ createExecutor() {
1353
+ if (closed) throw new PythonFailure("executor-unavailable");
1354
+ if (entries.size >= capacity) throw new PythonFailure("capacity");
1355
+ let acquired;
1356
+ const acquisition = new Promise((resolve) => {
1357
+ acquired = resolve;
1358
+ });
1359
+ let retirement;
1360
+ let execution;
1361
+ let started = false;
1362
+ const entry = {
1363
+ retire() {
1364
+ retirement ??= Promise.resolve().then(async () => {
1365
+ const executor2 = await acquisition;
1366
+ if (executor2 !== void 0) {
1367
+ const results = await Promise.allSettled([Promise.resolve().then(() => {
1368
+ const terminate = executor2?.terminate;
1369
+ if (typeof terminate !== "function") throw new PythonFailure("cleanup");
1370
+ return terminate.call(executor2);
1371
+ }), execution]);
1372
+ const failed = results.find((result) => result.status === "rejected");
1373
+ if (failed?.status === "rejected") throw failed.reason;
1374
+ }
1375
+ entries.delete(entry);
1376
+ });
1377
+ return retirement;
1378
+ }
1379
+ };
1380
+ entries.add(entry);
1381
+ let executor;
1382
+ try {
1383
+ executor = factory();
1384
+ } catch (error) {
1385
+ acquired(void 0);
1386
+ entries.delete(entry);
1387
+ throw error;
1388
+ }
1389
+ acquired(executor);
1390
+ try {
1391
+ if (closed || !executor || typeof executor.run !== "function" || typeof executor.terminate !== "function") throw new PythonFailure("executor-unavailable");
1392
+ } catch (error) {
1393
+ void entry.retire().catch(() => {
1394
+ });
1395
+ throw error;
1396
+ }
1397
+ return {
1398
+ async run(start) {
1399
+ if (started || closed || retirement) throw new PythonFailure("executor-unavailable");
1400
+ started = true;
1401
+ const running = Promise.resolve().then(() => {
1402
+ if (closed || retirement) throw new PythonFailure("executor-unavailable");
1403
+ return executor.run(start);
1404
+ });
1405
+ execution = running.then(() => {
1406
+ }, () => {
1407
+ });
1408
+ return running;
1409
+ },
1410
+ terminate: entry.retire
1411
+ };
1412
+ },
1413
+ inspect() {
1414
+ return { active: entries.size, capacity, closed };
1415
+ },
1416
+ dispose() {
1417
+ closed = true;
1418
+ disposal ??= Promise.allSettled([...entries].map((entry) => entry.retire())).then((results) => {
1419
+ const failed = results.find((result) => result.status === "rejected");
1420
+ if (failed?.status === "rejected") throw failed.reason;
1421
+ });
1422
+ return disposal;
1423
+ }
1424
+ };
1425
+ }
1426
+
1341
1427
  // packages/safe-bash/src/commands/python/index.ts
1342
1428
  var PythonInputChunkError = class extends RangeError {
1343
1429
  };
1344
1430
  function createPythonCommands(options) {
1345
- if (typeof options?.createWorker !== "function") throw new PythonFailure("executor-unavailable");
1431
+ if (!options || typeof options.createWorker === "function" === (typeof options.createExecutor === "function") || options.createWorker !== void 0 && typeof options.createWorker !== "function" || options.createExecutor !== void 0 && typeof options.createExecutor !== "function") throw new PythonFailure("executor-unavailable");
1346
1432
  if (options.onDiagnostic !== void 0 && typeof options.onDiagnostic !== "function") throw new TypeError("Python onDiagnostic must be a function");
1347
1433
  if (options.environment && options.provisioning) throw new TypeError("A borrowed Python environment cannot be combined with provisioning options");
1348
1434
  const maxTransferBytes = options.maxTransferBytes ?? 65536;
@@ -1391,6 +1477,7 @@ function createPythonCommands(options) {
1391
1477
  let stdoutOperation;
1392
1478
  let stderrOperation;
1393
1479
  let endpoint;
1480
+ let executor;
1394
1481
  let packages;
1395
1482
  let unsubscribe;
1396
1483
  let admitted = false;
@@ -1415,7 +1502,7 @@ function createPythonCommands(options) {
1415
1502
  void (async () => {
1416
1503
  signal.removeEventListener("abort", aborted);
1417
1504
  const subscription = Promise.resolve().then(() => unsubscribe?.());
1418
- const termination = Promise.resolve().then(() => endpoint?.terminate());
1505
+ const termination = Promise.resolve().then(() => executor ? executor.terminate() : endpoint?.terminate());
1419
1506
  const results = await Promise.allSettled([subscription, termination, service.close(), stdoutOperation?.close(), stderrOperation?.close(), ...pending]);
1420
1507
  await input.return?.(void 0);
1421
1508
  fragment = void 0;
@@ -1447,31 +1534,13 @@ function createPythonCommands(options) {
1447
1534
  const outputContext = { signal, ...context.registerCleanup ? { registerCleanup: context.registerCleanup } : {} };
1448
1535
  stdoutOperation = createOutputOperation(outputContext, context.stdout);
1449
1536
  stderrOperation = createOutputOperation(outputContext, context.stderr);
1450
- let shared;
1451
- try {
1452
- shared = new SharedArrayBuffer(8 + maxTransferBytes * 6 + 65536);
1453
- } catch (reason) {
1454
- throw reportPythonFailure("transport-unavailable", reason, options.onDiagnostic);
1455
- }
1456
- const control = new Int32Array(shared, 0, 2);
1457
- const payload = new Uint8Array(shared, 8);
1458
- const reply = (value, status) => {
1459
- if (closed) return;
1460
- let bytes;
1461
- try {
1462
- bytes = encodePythonReply(value, payload.length);
1463
- } catch (error) {
1464
- if (typeof error !== "object" || error === null || !("code" in error) || error.code !== "EFBIG") throw error;
1465
- bytes = encodePythonReply({ code: "EFBIG" }, payload.length);
1466
- status = 2;
1467
- }
1468
- payload.set(bytes);
1469
- try {
1470
- Atomics.store(control, 1, bytes.length);
1471
- Atomics.store(control, 0, status);
1472
- Atomics.notify(control, 0);
1473
- } catch (reason) {
1474
- throw reportPythonFailure("transport-unavailable", reason, options.onDiagnostic);
1537
+ const diagnoseFilesystemFailure = async (operation, error) => {
1538
+ if (typeof error !== "object" || error === null || !("code" in error) || error.code !== "ENOTSUP") return;
1539
+ const category = operation === "open" ? "filesystem-open" : operation === "read" ? "filesystem-read" : operation === "write" || operation === "ftruncate" ? "filesystem-write" : operation === "readdir" ? "filesystem-directory" : "filesystem-operation";
1540
+ if (!filesystemDiagnostics.has(category)) {
1541
+ filesystemDiagnostics.add(category);
1542
+ const failure2 = reportPythonFailure(category, error, options.onDiagnostic);
1543
+ await writeBytes(stderrOperation.output, new TextEncoder().encode("python: " + failure2.message + "\n"), signal);
1475
1544
  }
1476
1545
  };
1477
1546
  const dispatch = async (request) => {
@@ -1523,114 +1592,213 @@ function createPythonCommands(options) {
1523
1592
  pending.delete(preparation);
1524
1593
  }
1525
1594
  signal.throwIfAborted();
1526
- try {
1527
- endpoint = options.createWorker();
1528
- } catch (reason) {
1529
- throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : "startup", reason, options.onDiagnostic);
1530
- }
1531
- signal.throwIfAborted();
1532
- result = await new Promise((resolve, reject) => {
1533
- let settled = false;
1534
- const fail = (reason) => {
1535
- settled = true;
1536
- reject(reason);
1537
- };
1538
- rejectRun = fail;
1539
- signal.addEventListener("abort", aborted, { once: true });
1540
- const transportFailure = (reason) => {
1541
- fail(reportPythonFailure("transport-unavailable", reason, options.onDiagnostic));
1542
- };
1595
+ if (options.createExecutor) {
1543
1596
  try {
1544
- unsubscribe = endpoint.subscribe((value) => {
1545
- if (closed || settled) return;
1546
- if (typeof value !== "object" || value === null) {
1547
- transportFailure(new TypeError("Invalid Python worker message"));
1548
- return;
1597
+ executor = options.createExecutor();
1598
+ } catch (reason) {
1599
+ throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : "startup", reason, options.onDiagnostic);
1600
+ }
1601
+ if (!executor || typeof executor.run !== "function" || typeof executor.terminate !== "function") throw reportPythonFailure("executor-unavailable", void 0, options.onDiagnostic);
1602
+ let requesting = false;
1603
+ let running = true;
1604
+ const start = {
1605
+ invocation: { command: context.command, args: [...context.args], cwd: context.cwd, env: { ...context.env } },
1606
+ runtimeMount,
1607
+ maxTransferBytes,
1608
+ signal,
1609
+ ...packages ? { packages } : {},
1610
+ installOnly: !!installation,
1611
+ onReady() {
1612
+ if (closed || !running || signal.aborted || ready) return;
1613
+ ready = true;
1614
+ try {
1615
+ options.onProgress?.({ phase: "ready", command: context.command });
1616
+ } catch (reason) {
1617
+ running = false;
1618
+ rejectRun?.(reason);
1619
+ throw reason;
1549
1620
  }
1550
- const message = value;
1551
- if (message.type === "ready") {
1552
- ready = true;
1553
- try {
1554
- options.onProgress?.({ phase: "ready", command: context.command });
1555
- } catch (error) {
1556
- fail(error);
1557
- }
1558
- return;
1621
+ },
1622
+ async dispatch(request) {
1623
+ signal.throwIfAborted();
1624
+ if (closed || !running || requesting || !request || typeof request.op !== "string" || !Array.isArray(request.args)) throw reportPythonFailure("transport-unavailable", void 0, options.onDiagnostic);
1625
+ requesting = true;
1626
+ const operation = Promise.resolve().then(() => dispatch(request)).catch(async (error) => {
1627
+ signal.throwIfAborted();
1628
+ if (error instanceof PythonInputChunkError) rejectRun?.(error);
1629
+ if (request.op.startsWith("package-")) throw Object.assign(reportPythonFailure("runtime-assets", error, options.onDiagnostic), { code: "EPACKAGE" });
1630
+ await diagnoseFilesystemFailure(request.op, error);
1631
+ throw error;
1632
+ });
1633
+ const tracked2 = operation.then(() => {
1634
+ }, () => {
1635
+ });
1636
+ pending.add(tracked2);
1637
+ try {
1638
+ return await operation;
1639
+ } finally {
1640
+ requesting = false;
1641
+ pending.delete(tracked2);
1559
1642
  }
1560
- if (message.type === "exit") {
1561
- if (pending.size) {
1562
- transportFailure(new TypeError("Python worker exited with an outstanding request"));
1643
+ }
1644
+ };
1645
+ const execution = Promise.resolve().then(() => {
1646
+ signal.throwIfAborted();
1647
+ return executor.run(start);
1648
+ }).catch((reason) => {
1649
+ running = false;
1650
+ if (signal.aborted) throw signal.reason;
1651
+ throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : ready ? "runtime" : "startup", reason, options.onDiagnostic);
1652
+ }).then((status) => {
1653
+ running = false;
1654
+ if (requesting) throw reportPythonFailure("transport-unavailable", void 0, options.onDiagnostic);
1655
+ try {
1656
+ return validateExitCode(status);
1657
+ } catch (reason) {
1658
+ throw reportPythonFailure("transport-unavailable", reason, options.onDiagnostic);
1659
+ }
1660
+ });
1661
+ const tracked = execution.then(() => {
1662
+ }, () => {
1663
+ });
1664
+ pending.add(tracked);
1665
+ void tracked.then(() => pending.delete(tracked));
1666
+ result = await new Promise((resolve, reject) => {
1667
+ rejectRun = reject;
1668
+ signal.addEventListener("abort", aborted, { once: true });
1669
+ if (signal.aborted) aborted();
1670
+ execution.then(resolve, reject);
1671
+ });
1672
+ } else {
1673
+ let shared;
1674
+ try {
1675
+ shared = new SharedArrayBuffer(8 + maxTransferBytes * 6 + 65536);
1676
+ } catch (reason) {
1677
+ throw reportPythonFailure("transport-unavailable", reason, options.onDiagnostic);
1678
+ }
1679
+ const control = new Int32Array(shared, 0, 2);
1680
+ const payload = new Uint8Array(shared, 8);
1681
+ const reply = (value, status) => {
1682
+ if (closed) return;
1683
+ let bytes;
1684
+ try {
1685
+ bytes = encodePythonReply(value, payload.length);
1686
+ } catch (error) {
1687
+ if (typeof error !== "object" || error === null || !("code" in error) || error.code !== "EFBIG") throw error;
1688
+ bytes = encodePythonReply({ code: "EFBIG" }, payload.length);
1689
+ status = 2;
1690
+ }
1691
+ payload.set(bytes);
1692
+ try {
1693
+ Atomics.store(control, 1, bytes.length);
1694
+ Atomics.store(control, 0, status);
1695
+ Atomics.notify(control, 0);
1696
+ } catch (reason) {
1697
+ throw reportPythonFailure("transport-unavailable", reason, options.onDiagnostic);
1698
+ }
1699
+ };
1700
+ try {
1701
+ endpoint = options.createWorker();
1702
+ } catch (reason) {
1703
+ throw reportPythonFailure(reason instanceof PythonFailure ? reason.category : "startup", reason, options.onDiagnostic);
1704
+ }
1705
+ signal.throwIfAborted();
1706
+ result = await new Promise((resolve, reject) => {
1707
+ let settled = false;
1708
+ const fail = (reason) => {
1709
+ settled = true;
1710
+ reject(reason);
1711
+ };
1712
+ rejectRun = fail;
1713
+ signal.addEventListener("abort", aborted, { once: true });
1714
+ const transportFailure = (reason) => {
1715
+ fail(reportPythonFailure("transport-unavailable", reason, options.onDiagnostic));
1716
+ };
1717
+ try {
1718
+ unsubscribe = endpoint.subscribe((value) => {
1719
+ if (closed || settled) return;
1720
+ if (typeof value !== "object" || value === null) {
1721
+ transportFailure(new TypeError("Invalid Python worker message"));
1563
1722
  return;
1564
1723
  }
1565
- try {
1566
- const status = validateExitCode(message.exitCode);
1567
- settled = true;
1568
- resolve(status);
1569
- } catch (error) {
1570
- transportFailure(error);
1724
+ const message = value;
1725
+ if (message.type === "ready") {
1726
+ ready = true;
1727
+ try {
1728
+ options.onProgress?.({ phase: "ready", command: context.command });
1729
+ } catch (error) {
1730
+ fail(error);
1731
+ }
1732
+ return;
1571
1733
  }
1572
- return;
1573
- }
1574
- if (message.type === "error") {
1575
- fail(reportPythonFailure(isPythonFailureCategory(message.category) ? message.category : ready ? "runtime" : "startup", message.message, options.onDiagnostic));
1576
- return;
1577
- }
1578
- if (typeof message.op !== "string" || !Array.isArray(message.args) || pending.size) {
1579
- transportFailure(new TypeError("Invalid concurrent Python worker request"));
1580
- return;
1581
- }
1582
- const work = dispatch({ op: message.op, args: message.args }).then(
1583
- (value2) => {
1584
- pending.delete(work);
1585
- reply(value2, 1);
1586
- },
1587
- async (error) => {
1588
- if (signal.aborted) {
1589
- pending.delete(work);
1590
- fail(signal.reason);
1734
+ if (message.type === "exit") {
1735
+ if (pending.size) {
1736
+ transportFailure(new TypeError("Python worker exited with an outstanding request"));
1591
1737
  return;
1592
1738
  }
1593
- if (typeof message.op === "string" && message.op.startsWith("package-")) {
1594
- const failure2 = reportPythonFailure("runtime-assets", error, options.onDiagnostic);
1595
- pending.delete(work);
1596
- reply({ code: "EPACKAGE", message: failure2.message }, 2);
1597
- return;
1739
+ try {
1740
+ const status = validateExitCode(message.exitCode);
1741
+ settled = true;
1742
+ resolve(status);
1743
+ } catch (error) {
1744
+ transportFailure(error);
1598
1745
  }
1599
- if (typeof error !== "object" || error === null || !("code" in error) || typeof error.code !== "string") {
1746
+ return;
1747
+ }
1748
+ if (message.type === "error") {
1749
+ fail(reportPythonFailure(isPythonFailureCategory(message.category) ? message.category : ready ? "runtime" : "startup", message.message, options.onDiagnostic));
1750
+ return;
1751
+ }
1752
+ if (typeof message.op !== "string" || !Array.isArray(message.args) || pending.size) {
1753
+ transportFailure(new TypeError("Invalid concurrent Python worker request"));
1754
+ return;
1755
+ }
1756
+ const work = dispatch({ op: message.op, args: message.args }).then(
1757
+ (value2) => {
1600
1758
  pending.delete(work);
1601
- fail(error);
1602
- return;
1603
- }
1604
- if (error.code === "ENOTSUP") {
1605
- const category = message.op === "open" ? "filesystem-open" : message.op === "read" ? "filesystem-read" : message.op === "write" || message.op === "ftruncate" ? "filesystem-write" : message.op === "readdir" ? "filesystem-directory" : "filesystem-operation";
1606
- if (!filesystemDiagnostics.has(category)) {
1607
- filesystemDiagnostics.add(category);
1608
- const failure2 = reportPythonFailure(category, error, options.onDiagnostic);
1609
- await writeBytes(stderrOperation.output, new TextEncoder().encode("python: " + failure2.message + "\n"), signal);
1759
+ reply(value2, 1);
1760
+ },
1761
+ async (error) => {
1762
+ if (signal.aborted) {
1763
+ pending.delete(work);
1764
+ fail(signal.reason);
1765
+ return;
1766
+ }
1767
+ if (typeof message.op === "string" && message.op.startsWith("package-")) {
1768
+ const failure2 = reportPythonFailure("runtime-assets", error, options.onDiagnostic);
1769
+ pending.delete(work);
1770
+ reply({ code: "EPACKAGE", message: failure2.message }, 2);
1771
+ return;
1772
+ }
1773
+ if (typeof error !== "object" || error === null || !("code" in error) || typeof error.code !== "string") {
1774
+ pending.delete(work);
1775
+ fail(error);
1776
+ return;
1610
1777
  }
1778
+ await diagnoseFilesystemFailure(message.op, error);
1779
+ pending.delete(work);
1780
+ reply({ code: error.code }, 2);
1611
1781
  }
1782
+ );
1783
+ pending.add(work);
1784
+ void work.catch((reason) => {
1612
1785
  pending.delete(work);
1613
- reply({ code: error.code }, 2);
1614
- }
1615
- );
1616
- pending.add(work);
1617
- void work.catch((reason) => {
1618
- pending.delete(work);
1619
- fail(reason);
1620
- });
1621
- }, transportFailure);
1622
- } catch (reason) {
1623
- transportFailure(reason);
1624
- }
1625
- if (settled) return;
1626
- const start = { type: "start", shared, invocation: { command: context.command, args: [...context.args], cwd: context.cwd, env: { ...context.env } }, runtimeMount, maxTransferBytes, ...packages ? { packages } : {}, installOnly: !!installation };
1627
- signal.throwIfAborted();
1628
- try {
1629
- endpoint.postMessage(start);
1630
- } catch (reason) {
1631
- transportFailure(reason);
1632
- }
1633
- });
1786
+ fail(reason);
1787
+ });
1788
+ }, transportFailure);
1789
+ } catch (reason) {
1790
+ transportFailure(reason);
1791
+ }
1792
+ if (settled) return;
1793
+ const start = { type: "start", shared, invocation: { command: context.command, args: [...context.args], cwd: context.cwd, env: { ...context.env } }, runtimeMount, maxTransferBytes, ...packages ? { packages } : {}, installOnly: !!installation };
1794
+ signal.throwIfAborted();
1795
+ try {
1796
+ endpoint.postMessage(start);
1797
+ } catch (reason) {
1798
+ transportFailure(reason);
1799
+ }
1800
+ });
1801
+ }
1634
1802
  } catch (reason) {
1635
1803
  if (!signal.aborted && reason instanceof PythonInputChunkError) {
1636
1804
  try {
@@ -1661,10 +1829,10 @@ function createPythonCommands(options) {
1661
1829
  }
1662
1830
  return { exitCode: result };
1663
1831
  };
1664
- return ["python", "python3"].map((name) => ({ name, description: "Python with an explicit synchronous interpreter worker and canonical filesystem", execute }));
1832
+ return ["python", "python3"].map((name) => ({ name, description: "Python with an explicit interpreter executor and canonical filesystem", execute }));
1665
1833
  }
1666
1834
  function pythonCommands(options) {
1667
- if (typeof options?.createWorker !== "function") throw new PythonFailure("executor-unavailable");
1835
+ if (!options || typeof options.createWorker === "function" === (typeof options.createExecutor === "function")) throw new PythonFailure("executor-unavailable");
1668
1836
  if (options?.environment && options.provisioning) throw new TypeError("A borrowed Python environment cannot be combined with provisioning options");
1669
1837
  const { provisioning, ...configuration } = options;
1670
1838
  const environment = options.environment ?? createPythonPackageEnvironment(provisioning);
@@ -1694,7 +1862,8 @@ export {
1694
1862
  createPythonPackageCache,
1695
1863
  pythonDocumentPackages,
1696
1864
  createPythonPackageEnvironment,
1865
+ createPythonExecutorPool,
1697
1866
  createPythonCommands,
1698
1867
  pythonCommands
1699
1868
  };
1700
- //# sourceMappingURL=chunk-Z4UKD5FF.js.map
1869
+ //# sourceMappingURL=chunk-6VT3VSBX.js.map