@poe-platform/safe-bash 0.1.821 → 0.1.823

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 (93) hide show
  1. package/dist/safe-bash/chunks/{chunk-HNT2MR4W.js → chunk-363QOIDR.js} +2 -1
  2. package/dist/safe-bash/chunks/chunk-AGHV53VF.js +42 -0
  3. package/dist/safe-bash/chunks/{chunk-VF3Q2V3E.js → chunk-RAFD5ZAH.js} +1 -1
  4. package/dist/safe-bash/chunks/{chunk-67QE3JLU.js → chunk-TZRVK3NU.js} +1 -1
  5. package/dist/safe-bash/chunks/{chunk-IRJS54AA.js → chunk-VWLQDZFF.js} +20 -12
  6. package/dist/safe-bash/chunks/{chunk-NAETSXBW.js → chunk-ZJAXMB5M.js} +1 -1
  7. package/dist/safe-bash/command-chunks/{chunk-QX3WKBLI.js → chunk-36FV6BAG.js} +5 -3
  8. package/dist/safe-bash/command-chunks/{chunk-ZSHXZ3XG.js → chunk-3EAZRKI4.js} +7 -7
  9. package/dist/safe-bash/command-chunks/chunk-64HIOP7Q.js +993 -0
  10. package/dist/safe-bash/command-chunks/{chunk-WOT2YXBT.js → chunk-7ZQVMPSB.js} +213 -42
  11. package/dist/safe-bash/command-chunks/{chunk-GRFJKJFN.js → chunk-AVSINNZ6.js} +233 -3
  12. package/dist/safe-bash/command-chunks/{chunk-BZLLQWRK.js → chunk-E5CDHXFA.js} +2 -2
  13. package/dist/safe-bash/command-chunks/{chunk-RHXV2KG5.js → chunk-EO3RYGUZ.js} +1010 -58
  14. package/dist/safe-bash/command-chunks/{chunk-MCUDSE4H.js → chunk-EWECMOQ5.js} +1 -1
  15. package/dist/safe-bash/command-chunks/{chunk-RTUDDAAY.js → chunk-O3KFOFJM.js} +1 -1
  16. package/dist/safe-bash/command-chunks/{chunk-SLD5A7IL.js → chunk-OU5UEUZN.js} +1 -1
  17. package/dist/safe-bash/command-chunks/{chunk-RKAL5VFP.js → chunk-PLVFJ6FF.js} +255 -616
  18. package/dist/safe-bash/command-chunks/{chunk-CJIFJ45R.js → chunk-QBCEAYQT.js} +1 -1
  19. package/dist/safe-bash/command-chunks/{chunk-4Q3HP33O.js → chunk-RGKHTSUY.js} +146 -123
  20. package/dist/safe-bash/command-chunks/{chunk-I7MEH76L.js → chunk-UYNJF5QN.js} +1 -1
  21. package/dist/safe-bash/command-chunks/{chunk-IAHYG67O.js → chunk-V5ZBRM5R.js} +3 -3
  22. package/dist/safe-bash/command-chunks/{chunk-R4NPYXQX.js → chunk-WDTWJFPK.js} +320 -67
  23. package/dist/safe-bash/command-chunks/{chunk-GQV5RWMN.js → chunk-ZFXHSFTU.js} +1 -1
  24. package/dist/safe-bash/command-chunks/{prompt-tool-debug-ERJKK3XZ.js → prompt-tool-debug-3POFNRYP.js} +5 -5
  25. package/dist/safe-bash/commands/bc/index.browser.js +1 -1
  26. package/dist/safe-bash/commands/llm/index.browser.js +3 -1
  27. package/dist/safe-bash/commands/llm/index.js +1 -1
  28. package/dist/safe-bash/commands/python/executor.browser.js +12 -1
  29. package/dist/safe-bash/commands/python/executor.js +1 -1
  30. package/dist/safe-bash/commands/python/index.browser.js +23 -1
  31. package/dist/safe-bash/commands/python/index.js +1 -1
  32. package/dist/safe-bash/core.browser.js +2 -2
  33. package/dist/safe-bash/full-core.browser.js +30 -6
  34. package/dist/safe-bash/plugins/index.browser.js +3 -3
  35. package/dist/safe-bash/registry-entry.browser.js +2 -2
  36. package/dist/safe-bash/search.browser.js +1 -1
  37. package/dist/safe-bash/shell/runtime.d.ts +2 -2
  38. package/dist/safe-bash/shell/runtime.js +11 -2
  39. package/dist/safe-bash/shell/sync-extra-evaluators.js +12 -12
  40. package/dist/safe-bash/shell-entry.browser.js +2 -2
  41. package/dist/safe-bash-command-llm/collections.js +24 -65
  42. package/dist/safe-bash-command-llm/command.js +6 -6
  43. package/dist/safe-bash-command-llm/fragment-loaders.d.ts +3 -2
  44. package/dist/safe-bash-command-llm/index.d.ts +3 -2
  45. package/dist/safe-bash-command-llm/index.js +10 -8
  46. package/dist/safe-bash-command-llm/loader-provider.d.ts +25 -0
  47. package/dist/safe-bash-command-llm/openai-sse.js +2 -2
  48. package/dist/safe-bash-command-llm/openai.js +4 -4
  49. package/dist/safe-bash-command-llm/providers/index.js +4 -4
  50. package/dist/safe-bash-command-llm/providers/openai.js +4 -4
  51. package/dist/safe-bash-command-llm/python-unicode.d.ts +2 -0
  52. package/dist/safe-bash-command-llm/templates.d.ts +7 -2
  53. package/dist/safe-bash-command-llm/types.d.ts +7 -1
  54. package/dist/safe-bash-command-mcp/index.browser.js +3 -0
  55. package/dist/safe-bash-command-mcp/index.js +3 -0
  56. package/dist/safe-bash-command-patch/index.js +2 -2
  57. package/dist/safe-bash-command-patch/patch-publication.js +1 -1
  58. package/dist/safe-bash-command-patch/patch.js +2 -2
  59. package/dist/safe-bash-command-python/build-backend.d.ts +51 -0
  60. package/dist/safe-bash-command-python/build-dependencies.d.ts +12 -0
  61. package/dist/safe-bash-command-python/build-environment.d.ts +3 -0
  62. package/dist/safe-bash-command-python/build-wheel.d.ts +8 -0
  63. package/dist/safe-bash-command-python/executor.d.ts +12 -2
  64. package/dist/safe-bash-command-python/executor.js +26 -4
  65. package/dist/safe-bash-command-python/index.js +26 -4
  66. package/dist/safe-bash-command-python/jspi.js +2 -2
  67. package/dist/safe-bash-command-python/llm-assets-node.js +1 -1
  68. package/dist/safe-bash-command-python/llm-fragment-loader.d.ts +6 -0
  69. package/dist/safe-bash-command-python/llm-functions-loader.d.ts +5 -1
  70. package/dist/safe-bash-command-python/llm-loader-discovery.d.ts +13 -0
  71. package/dist/safe-bash-command-python/llm-package-manager.d.ts +7 -0
  72. package/dist/safe-bash-command-python/llm-template-loader.d.ts +6 -0
  73. package/dist/safe-bash-command-python/manifest.d.ts +13 -0
  74. package/dist/safe-bash-command-python/provisioning.d.ts +33 -5
  75. package/dist/safe-bash-command-python/provisioning.js +1 -1
  76. package/dist/safe-bash-command-python/source-environment.d.ts +9 -0
  77. package/dist/safe-bash-command-python/source-snapshot.d.ts +8 -0
  78. package/dist/safe-bash-command-python/worker.js +3 -185
  79. package/dist/safe-bash-csv-engine/index.js +1 -1
  80. package/dist/safe-bash-csv-engine/python-iso2022.d.ts +21 -0
  81. package/dist/safe-bash-csv-engine/python-utf7.d.ts +18 -0
  82. package/dist/safe-bash-csv-engine/text-decoder.d.ts +2 -0
  83. package/dist/safe-bash-csv-engine/text-decoder.js +7 -3
  84. package/dist/safe-bash-zip-engine/index.js +1 -1
  85. package/dist/safe-bash-zip-engine/zip/repair.js +1 -1
  86. package/dist/safe-bash-zip-engine/zip/sfx.js +1 -1
  87. package/dist/safe-bash-zip-engine/zip-format.d.ts +3 -1
  88. package/dist/safe-bash-zip-engine/zip-format.js +1 -1
  89. package/dist/safe-playwright-cloudflare/shell-browser-resource.d.ts +1 -1
  90. package/dist/safe-playwright-cloudflare/shell-browser-resource.js +35 -20
  91. package/package.json +3 -3
  92. package/dist/safe-bash/chunks/chunk-PSD2RSOS.js +0 -31
  93. package/dist/safe-bash/command-chunks/chunk-5EFNQ6FY.js +0 -458
@@ -0,0 +1,993 @@
1
+ // packages/safe-bash-command-python/src/invocation.ts
2
+ var PythonInvocationError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "PythonInvocationError";
6
+ }
7
+ };
8
+ function parsePythonInvocation(args, env) {
9
+ const startupArgs = [];
10
+ let informational = false;
11
+ let module;
12
+ scan: for (let index = 0; index < args.length; index++) {
13
+ const option = args[index];
14
+ if (option === "--" || option === "-" || !option.startsWith("-")) break;
15
+ if (option === "--help") {
16
+ informational = true;
17
+ break;
18
+ }
19
+ if (option === "--version") {
20
+ informational = true;
21
+ continue;
22
+ }
23
+ if (option.startsWith("--")) throw new PythonInvocationError("unsupported option " + option);
24
+ for (let offset = 1; offset < option.length; offset++) {
25
+ const flag = option[offset];
26
+ if (flag === "h" || flag === "?") {
27
+ informational = true;
28
+ break scan;
29
+ }
30
+ if (flag === "V") {
31
+ informational = true;
32
+ continue;
33
+ }
34
+ if ("cmWX".includes(flag)) {
35
+ const operand = option.slice(offset + 1) || args[++index];
36
+ if (operand === void 0) throw new PythonInvocationError("argument expected for -" + flag);
37
+ if (flag === "m" && !informational) module = { name: operand, args: args.slice(index + 1) };
38
+ if (flag === "c" || flag === "m") break scan;
39
+ if (flag === "X") {
40
+ const separator = operand.indexOf("=");
41
+ const name = separator < 0 ? operand : operand.slice(0, separator);
42
+ const value = separator < 0 ? void 0 : operand.slice(separator + 1);
43
+ let decimal = value ?? "";
44
+ while (decimal.length && " \n\r\v\f".includes(decimal[0])) decimal = decimal.slice(1);
45
+ if (decimal[0] === "+" || decimal[0] === "-") decimal = decimal.slice(1);
46
+ const digits = decimal.length > 0 && [...decimal].every((character) => character >= "0" && character <= "9");
47
+ const supported = name === "utf8" && (value === void 0 || value === "0" || value === "1") || (name === "dev" || name === "warn_default_encoding") && value === void 0 || name === "int_max_str_digits" && digits && Number.isSafeInteger(Number(value)) && Number(value) <= 2147483647 && (Number(value) === 0 || Number(value) >= 640);
48
+ if (!supported) throw new PythonInvocationError("unsupported -X option " + operand);
49
+ startupArgs.push("-X", operand);
50
+ }
51
+ break;
52
+ }
53
+ if (!"BEPOusISbdvqR".includes(flag)) throw new PythonInvocationError("unsupported option -" + flag);
54
+ startupArgs.push("-" + flag);
55
+ }
56
+ }
57
+ if (!informational && !startupArgs.includes("-E") && !startupArgs.includes("-I")) {
58
+ if (env.PYTHONINSPECT) throw new PythonInvocationError("PYTHONINSPECT requires an interactive terminal, which the shell does not expose");
59
+ if (env.PYTHONHOME) throw new PythonInvocationError("PYTHONHOME cannot replace the configured Pyodide runtime");
60
+ }
61
+ const runtimeEnv = { ...env };
62
+ delete runtimeEnv.PYTHONPATH;
63
+ delete runtimeEnv.PYTHONHOME;
64
+ delete runtimeEnv.PYTHONWARNINGS;
65
+ runtimeEnv.PYTHONINSPECT = "";
66
+ startupArgs.push("-c", "");
67
+ return { startupArgs, env: runtimeEnv, module };
68
+ }
69
+
70
+ // packages/safe-bash-command-python/src/native-wheel.ts
71
+ var pythonNativeWheel = `
72
+ def _safe_extract_native_wheel(read, serialized):
73
+ import io as _native_io, json as _native_json, shutil as _native_shutil
74
+ from pathlib import Path as _NativePath
75
+ from zipfile import ZipFile as _NativeZip
76
+ from pyodide import _package_loader as _native_loader
77
+ from pyodide.ffi import run_sync as _native_sync
78
+
79
+ class _NativeWheel(_native_io.RawIOBase):
80
+ def __init__(self, size):
81
+ self.size, self.position = size, 0
82
+ def readable(self):
83
+ return True
84
+ def seekable(self):
85
+ return True
86
+ def tell(self):
87
+ return self.position
88
+ def seek(self, offset, whence=0):
89
+ if whence not in (0, 1, 2):
90
+ raise ValueError('invalid whence')
91
+ position = offset + (0, self.position, self.size)[whence]
92
+ if position < 0:
93
+ raise OSError(22, 'Invalid argument')
94
+ self.position = position
95
+ return position
96
+ def read(self, size=-1):
97
+ remaining = max(0, self.size - self.position)
98
+ size = remaining if size is None or size < 0 else min(size, remaining)
99
+ output = bytearray()
100
+ while len(output) < size:
101
+ result = read(self.position, min(size-len(output), 65536))
102
+ if hasattr(result, 'then'):
103
+ result = _native_sync(result)
104
+ chunk = bytes(result)
105
+ if not chunk or len(chunk) > size-len(output):
106
+ raise OSError('Invalid Python package chunk')
107
+ output.extend(chunk)
108
+ self.position += len(chunk)
109
+ return bytes(output)
110
+
111
+ _native_config = _native_json.loads(serialized)
112
+ with _NativeWheel(_native_config['size']) as _native_archive:
113
+ if 'metadata_name' in _native_config:
114
+ from micropip.metadata import wheel_dist_info_dir as _native_metadata_dir
115
+ from zipfile import Path as _NativeZipPath
116
+ with _NativeZip(_native_archive) as _native_zip:
117
+ path = _NativePath(_native_metadata_dir(_native_zip, _native_config['metadata_name'])) / 'METADATA'
118
+ return _native_json.dumps(_NativeZipPath(_native_zip, str(path)).read_text(encoding='utf-8'))
119
+ _native_target = _NativePath(_native_config['extract_dir'] if 'extract_dir' in _native_config else _native_loader.get_install_dir(_native_config['target']))
120
+ _native_target.mkdir(parents=True, exist_ok=True)
121
+ _native_shutil._unpack_zipfile(_native_archive, _native_target)
122
+ with _NativeZip(_native_archive) as _native_zip:
123
+ if _NativePath(_native_config['filename']).suffix == '.whl':
124
+ _native_loader.set_wheel_metadata(_native_config['filename'], _native_zip, _native_target, _native_config['metadata'])
125
+ _native_loader.install_datafiles(_native_config['filename'], _native_zip, _native_target)
126
+ _native_dynlibs = _native_loader.get_dynlibs(_native_archive, _NativePath(_native_config['filename']).suffix, _native_target)
127
+ return _native_json.dumps(_native_dynlibs)
128
+ _safe_extract_native_wheel(_safe_native_wheel_read, _safe_native_wheel_config)
129
+ `;
130
+
131
+ // packages/safe-bash-command-python/src/provisioning-runtime.ts
132
+ async function installPythonPackages(supplied, start, request, maxTransferBytes) {
133
+ if (!start.requirements.length && !start.uninstall && !start.bootstrap) return;
134
+ const runtime = supplied;
135
+ if (runtime.version !== "314.0.6" || !runtime._api?.packageManager || !runtime._api.lockfile_packages || typeof runtime._api.packageManager.installPackage !== "function" || typeof runtime.loadPackage !== "function" || typeof runtime.runPythonAsync !== "function") throw new Error("Python package installer ABI requires Pyodide 314.0.6");
136
+ let transportFailure;
137
+ let accepting = true;
138
+ let pending = Promise.resolve();
139
+ let installing = Promise.resolve();
140
+ const manager = runtime._api.packageManager;
141
+ const transfer = (consume) => {
142
+ if (!accepting) return Promise.reject(new Error("Python package transport is only available during installation"));
143
+ const work = pending.then(async () => {
144
+ if (transportFailure) throw transportFailure.error;
145
+ try {
146
+ return await consume();
147
+ } catch (error) {
148
+ transportFailure ??= { error };
149
+ throw error;
150
+ }
151
+ });
152
+ pending = work.then(() => {
153
+ }, () => {
154
+ });
155
+ return work;
156
+ };
157
+ const readArtifact = (operation, key, offset, length) => {
158
+ const failed = (error) => {
159
+ transportFailure ??= { error };
160
+ throw error;
161
+ };
162
+ try {
163
+ const result = request(operation, start.session, key, offset, Math.min(length, maxTransferBytes, 65536));
164
+ return result instanceof Promise ? result.catch(failed) : result;
165
+ } catch (error) {
166
+ return failed(error);
167
+ }
168
+ };
169
+ const withArtifact = (url, expected, metadata, consume) => transfer(async () => {
170
+ const opened = await request("package-open", start.session, url, expected, ...metadata ? [metadata] : []);
171
+ try {
172
+ return await consume(opened, (offset, length) => readArtifact("package-read", opened.key, offset, length));
173
+ } finally {
174
+ await request("package-close", start.session, opened.key);
175
+ }
176
+ });
177
+ const wheel = async (size, read, configuration) => {
178
+ const globals = ["_safe_native_wheel_read", "_safe_native_wheel_config", "_safe_extract_native_wheel"];
179
+ try {
180
+ runtime.globals.set(globals[0], read);
181
+ runtime.globals.set(globals[1], JSON.stringify({ ...configuration, size }));
182
+ const result = JSON.parse(await runtime.runPythonAsync(pythonNativeWheel));
183
+ if (Array.isArray(result)) for (const path of result) await runtime._api.loadDynlib(path);
184
+ return result;
185
+ } finally {
186
+ for (const name of globals) runtime.globals.delete(name);
187
+ }
188
+ };
189
+ const fetch = (url, expected, metadata) => withArtifact(url, expected, metadata, async (opened, read) => {
190
+ const bytes = new Uint8Array(opened.size);
191
+ for (let offset = 0; offset < bytes.length; ) {
192
+ const chunk = await read(offset, bytes.length - offset);
193
+ if (!Array.isArray(chunk) || chunk.length === 0 || offset + chunk.length > bytes.length) throw new Error("Invalid Python package chunk");
194
+ bytes.set(chunk, offset);
195
+ offset += chunk.length;
196
+ }
197
+ return { bytes, headers: opened.headers };
198
+ });
199
+ manager.downloadPackage = async (metadata) => {
200
+ if (!accepting) throw new Error("Python package transport is only available during installation");
201
+ if (metadata.channel === manager.defaultChannel) {
202
+ const pkg = runtime._api.lockfile_packages[metadata.normalizedName];
203
+ if (!pkg) throw new Error(`Missing matching Pyodide package: ${metadata.normalizedName}`);
204
+ return { url: new URL(pkg.file_name, "https://cdn.jsdelivr.net/pyodide/v314.0.6/full/").href, expected: pkg.sha256 };
205
+ }
206
+ return { url: metadata.channel };
207
+ };
208
+ manager.installPackage = (metadata, source) => {
209
+ if (!accepting) return Promise.reject(new Error("Python package transport is only available during installation"));
210
+ const work = installing.then(async () => {
211
+ if (source instanceof Uint8Array) throw new Error("Expected retained Python package source");
212
+ const pkg = runtime._api.lockfile_packages[metadata.normalizedName] ?? metadata.packageData;
213
+ if (!pkg) throw new Error(`Missing matching Pyodide package: ${metadata.normalizedName}`);
214
+ return withArtifact(source.url, source.expected, void 0, (opened, read) => wheel(opened.size, read, {
215
+ filename: pkg.file_name,
216
+ target: pkg.install_dir ?? null,
217
+ metadata: { INSTALLER: "pyodide.loadPackage", PYODIDE_SOURCE: metadata.channel === manager.defaultChannel ? "pyodide" : metadata.channel }
218
+ }));
219
+ });
220
+ installing = work.then(() => {
221
+ }, () => {
222
+ });
223
+ return work;
224
+ };
225
+ const loadPackages = async (names) => {
226
+ const errors = [];
227
+ await runtime.loadPackage(names, { messageCallback() {
228
+ }, errorCallback(message) {
229
+ errors.push(message);
230
+ } });
231
+ if (errors.length) throw new Error(errors.join("\n"));
232
+ };
233
+ const installedGlobals = [];
234
+ const bind = (name, value) => {
235
+ runtime.globals.set(name, value);
236
+ installedGlobals.push(name);
237
+ };
238
+ try {
239
+ await loadPackages(["micropip"]);
240
+ bind("_safe_package_native", loadPackages);
241
+ bind("_safe_package_bytes", async (url, hash) => (await fetch(url, hash)).bytes);
242
+ bind("_safe_package_metadata", async (url) => {
243
+ const result = await fetch(url, void 0, "metadata");
244
+ return JSON.stringify({ text: new TextDecoder().decode(result.bytes), headers: Object.fromEntries(result.headers.map(([name, value]) => [name.toLowerCase(), value])) });
245
+ });
246
+ bind("_safe_package_wheel_download", async (url, expected) => withArtifact(url, expected, void 0, async (opened) => {
247
+ return JSON.stringify(await request("package-retain", start.session, opened.key));
248
+ }));
249
+ bind("_safe_package_wheel_metadata", async (serialized) => transfer(async () => {
250
+ const { source, name } = JSON.parse(serialized);
251
+ return wheel(source.size, (offset, length) => readArtifact("package-read-retained", source.token, offset, length), { metadata_name: name });
252
+ }));
253
+ bind("_safe_package_wheel_install", async (serialized) => transfer(async () => {
254
+ const { source, ...configuration } = JSON.parse(serialized);
255
+ await wheel(source.size, (offset, length) => readArtifact("package-read-retained", source.token, offset, length), configuration);
256
+ }));
257
+ bind("_safe_package_requirements_json", JSON.stringify(start.requested ?? start.requirements));
258
+ for (const key of ["pre", "upgrade", "forceReinstall", "legacy"]) {
259
+ bind("_safe_package_" + key, !!start[key]);
260
+ }
261
+ bind("_safe_package_restore_json", JSON.stringify(start.restore ?? []));
262
+ bind("_safe_package_records_json", JSON.stringify(start.records ?? null));
263
+ bind("_safe_package_uninstall_json", JSON.stringify(start.uninstall ?? null));
264
+ bind("_safe_package_emit", async (stream, message) => {
265
+ if (stream !== "stdout" && stream !== "stderr") throw new Error("Invalid package output stream");
266
+ const bytes = new TextEncoder().encode(message);
267
+ for (let offset = 0; offset < bytes.length; offset += maxTransferBytes) await request(stream, Array.from(bytes.subarray(offset, offset + maxTransferBytes)));
268
+ });
269
+ bind("_safe_package_line", async () => {
270
+ const bytes = [];
271
+ while (true) {
272
+ const chunk = await request("stdin", 1);
273
+ if (!chunk.length) {
274
+ if (!bytes.length) throw new Error("EOF when reading package confirmation");
275
+ break;
276
+ }
277
+ if (chunk[0] === 10) break;
278
+ bytes.push(chunk[0]);
279
+ }
280
+ return new TextDecoder().decode(Uint8Array.from(bytes));
281
+ });
282
+ await runtime.runPythonAsync(`
283
+ import json as _safe_json
284
+ import importlib.metadata as _safe_metadata
285
+ _safe_preloaded = [d.metadata['Name'] for d in _safe_metadata.distributions() if d.metadata['Name']]
286
+ from micropip._compat import compatibility_layer as _safe_compat
287
+ from micropip.package_manager import PackageManager as _SafePackageManager
288
+ from micropip.wheelinfo import WheelInfo as _SafeWheelInfo
289
+ from micropip._utils import check_compatible as _safe_check_compatible
290
+ from micropip._vendored.packaging.src.packaging.requirements import Requirement as _SafeRequirement, InvalidRequirement as _SafeInvalidRequirement
291
+ from micropip._vendored.packaging.src.packaging.utils import canonicalize_name as _safe_name
292
+
293
+ class _SafePackageCompatibility(_safe_compat):
294
+ @staticmethod
295
+ async def loadPackage(names):
296
+ return await _safe_package_native(names)
297
+ @staticmethod
298
+ async def fetch_bytes(url, kwargs):
299
+ return (await _safe_package_bytes(url)).to_bytes()
300
+ @staticmethod
301
+ async def fetch_string_and_headers(url, kwargs):
302
+ value = _safe_json.loads(await _safe_package_metadata(url))
303
+ return value['text'], value['headers']
304
+
305
+ async def _safe_wheel_fetch(self, url, kwargs, compat):
306
+ expected = self.sha256 if url == self.url else None
307
+ if url == self.metadata_url and isinstance(self.core_metadata, dict):
308
+ expected = self.core_metadata.get('sha256')
309
+ return (await _safe_package_bytes(url, expected)).to_bytes()
310
+ _SafeWheelInfo._fetch_bytes = _safe_wheel_fetch
311
+ from micropip.metadata import Metadata as _SafeWheelMetadata
312
+ async def _safe_wheel_download(self, fetch_kwargs, compat_layer):
313
+ if self._data is not None:
314
+ return
315
+ self._data = _safe_json.loads(await _safe_package_wheel_download(self.url, self.sha256))
316
+ if self._metadata is None:
317
+ metadata = await _safe_package_wheel_metadata(_safe_json.dumps({'source': self._data, 'name': self.name}))
318
+ self._metadata = _SafeWheelMetadata(metadata.encode('utf-8'))
319
+ async def _safe_wheel_install(self, target, compat_layer):
320
+ if not self._data:
321
+ raise RuntimeError('Micropip internal error: attempted to install wheel before downloading it?')
322
+ source = 'pypi' if self.sha256 is not None else self.url
323
+ metadata = {'PYODIDE_SOURCE': source, 'PYODIDE_URL': self.url, 'PYODIDE_SHA256': self._data['key'], 'INSTALLER': 'micropip'}
324
+ if self._requires:
325
+ metadata['PYODIDE_REQUIRES'] = _safe_json.dumps(sorted(x.name for x in self._requires))
326
+ await _safe_package_wheel_install(_safe_json.dumps({'source': self._data, 'filename': self.filename, 'extract_dir': str(target), 'metadata': metadata}))
327
+ setattr(compat_layer.loadedPackages, self._project_name, source)
328
+ _SafeWheelInfo.download = _safe_wheel_download
329
+ _SafeWheelInfo.install = _safe_wheel_install
330
+ _safe_preloaded = {_safe_name(name) for name in _safe_preloaded}
331
+ _safe_manager = _SafePackageManager(_SafePackageCompatibility)
332
+ async def _safe_parse_sources(sources, download=True):
333
+ roots = []
334
+ for source in sources:
335
+ try:
336
+ root = _SafeRequirement(source)
337
+ if root.name.endswith('.whl'):
338
+ raise _SafeInvalidRequirement(source)
339
+ except _SafeInvalidRequirement:
340
+ wheel = _SafeWheelInfo.from_url(source)
341
+ root = _SafeRequirement(wheel.name + ' @ ' + source)
342
+ roots.append(root)
343
+ if (not root.marker or root.marker.evaluate({'extra': ''})) and root.url:
344
+ direct = _SafeWheelInfo.from_url(root.url)
345
+ _safe_check_compatible(direct.filename)
346
+ if download:
347
+ await direct.download({}, _SafePackageCompatibility)
348
+ return roots
349
+
350
+ def _safe_validate(roots):
351
+ for root in roots:
352
+ if root.marker and not root.marker.evaluate({'extra': ''}):
353
+ continue
354
+ version = _safe_metadata.version(root.name)
355
+ if not root.specifier.contains(version, prereleases=True):
356
+ raise ValueError('Python package version conflict: ' + str(root))
357
+ if root.url:
358
+ wheel = _SafeWheelInfo.from_url(root.url)
359
+ pin = _SafeRequirement(wheel.name + '==' + str(wheel.version))
360
+ if _safe_name(wheel.name) != _safe_name(root.name) or not pin.specifier.contains(version, prereleases=True):
361
+ raise ValueError('Python package wheel version conflict: ' + str(root))
362
+ async def _safe_resolve(_safe_roots, upgrade=False, force=False):
363
+ _safe_extras = {}
364
+ for _safe_root in _safe_roots:
365
+ if not _safe_root.marker or _safe_root.marker.evaluate({'extra': ''}):
366
+ _safe_extras.setdefault(_safe_name(_safe_root.name), set()).update(_safe_root.extras)
367
+ for _safe_root in _safe_roots:
368
+ _safe_root.extras.update(_safe_extras.get(_safe_name(_safe_root.name), set()))
369
+ _safe_requested_names = set(_safe_extras)
370
+ import micropip.package_manager as _safe_pm
371
+ _SafeTransaction = _safe_pm.Transaction
372
+ class _SafeReplacementTransaction(_SafeTransaction):
373
+ def check_version_satisfied(self, req, *, allow_reinstall=False):
374
+ if req.url:
375
+ wheel = _SafeWheelInfo.from_url(req.url)
376
+ if _safe_name(wheel.name) != req.name:
377
+ raise ValueError('Python package wheel name conflict: ' + str(req))
378
+ req = _SafeRequirement(req.name + '==' + str(wheel.version))
379
+ if req.name in _safe_preloaded or req.name in self.locked:
380
+ return super().check_version_satisfied(req)
381
+ if force or (upgrade and req.name in _safe_requested_names):
382
+ return False, ''
383
+ return super().check_version_satisfied(req, allow_reinstall=allow_reinstall)
384
+ async def _safe_install(requirements):
385
+ _safe_pm.Transaction = _SafeReplacementTransaction
386
+ try:
387
+ await _safe_manager.install(requirements, deps=True, pre=_safe_package_pre, reinstall=True)
388
+ finally:
389
+ _safe_pm.Transaction = _SafeTransaction
390
+ _safe_validate([root for root in _safe_roots if _safe_name(root.name) in _safe_preloaded])
391
+ await _safe_install([str(root) for root in _safe_roots])
392
+ _safe_managed = set(_safe_requested_names)
393
+ _safe_previous_pending = set()
394
+ while True:
395
+ _safe_distributions = [d for d in _safe_metadata.distributions() if d.metadata['Name']]
396
+ _safe_versions = {_safe_name(d.metadata['Name']): d.version for d in _safe_distributions}
397
+ while True:
398
+ _safe_changed = False
399
+ _safe_dependencies = []
400
+ for _safe_dist in _safe_distributions:
401
+ if _safe_name(_safe_dist.metadata['Name']) not in _safe_managed:
402
+ continue
403
+ _safe_contexts = {''} | _safe_extras.get(_safe_name(_safe_dist.metadata['Name']), set())
404
+ for _safe_dep in _safe_dist.requires or []:
405
+ _safe_requirement = _SafeRequirement(_safe_dep)
406
+ if _safe_requirement.marker and not any(_safe_requirement.marker.evaluate({'extra': extra}) for extra in _safe_contexts):
407
+ continue
408
+ _safe_requirement.marker = None
409
+ _safe_dependencies.append(_safe_requirement)
410
+ _safe_dependency_name = _safe_name(_safe_requirement.name)
411
+ if _safe_dependency_name not in _safe_managed:
412
+ _safe_managed.add(_safe_dependency_name)
413
+ _safe_changed = True
414
+ _safe_selected = _safe_extras.setdefault(_safe_name(_safe_requirement.name), set())
415
+ if not _safe_requirement.extras.issubset(_safe_selected):
416
+ _safe_selected.update(_safe_requirement.extras)
417
+ _safe_changed = True
418
+ if not _safe_changed:
419
+ break
420
+ _safe_pending = set()
421
+ for _safe_requirement in _safe_dependencies:
422
+ _safe_version = _safe_versions.get(_safe_name(_safe_requirement.name))
423
+ if _safe_version is None or not _safe_requirement.specifier.contains(_safe_version, prereleases=True):
424
+ _safe_pending.add(str(_safe_requirement))
425
+ if not _safe_pending:
426
+ break
427
+ if frozenset(_safe_pending) in _safe_previous_pending:
428
+ raise ValueError('Python package dependencies remain missing: ' + ', '.join(sorted(_safe_pending)))
429
+ _safe_previous_pending.add(frozenset(_safe_pending))
430
+ await _safe_install(sorted(_safe_pending))
431
+ _safe_validate(_safe_roots)
432
+ return _safe_managed
433
+ def _safe_removal_listing(_safe_dist):
434
+ from micropip._utils import get_files_in_distribution as _safe_distribution_files
435
+ import os as _safe_os
436
+ def _safe_compact(paths):
437
+ compact = []
438
+ for path in sorted(paths, key=len):
439
+ if not any(path.startswith(parent.rstrip('*').rstrip('/') + '/') for parent in compact):
440
+ compact.append(path)
441
+ return compact
442
+ _safe_files = {str(path) for path in _safe_distribution_files(_safe_dist) if not str(path).endswith('.pyc')}
443
+ _safe_folders = _safe_compact({_safe_os.path.dirname(path) for path in _safe_files if path.endswith('__init__.py') or '.dist-info' in path})
444
+ _safe_skipped = set()
445
+ for _safe_folder in _safe_folders:
446
+ for _safe_dir, _, _safe_names in _safe_os.walk(_safe_folder):
447
+ for _safe_name_ in _safe_names:
448
+ _safe_path = _safe_os.path.join(_safe_dir, _safe_name_)
449
+ if not _safe_name_.endswith('.pyc') and _safe_os.path.isfile(_safe_path) and _safe_path not in _safe_files:
450
+ _safe_skipped.add(_safe_path)
451
+ _safe_listing = set(_safe_files) | {_safe_os.path.join(folder, '*') for folder in _safe_folders}
452
+ return [sorted(_safe_compact(_safe_listing)), sorted(_safe_compact(_safe_skipped))]
453
+ _safe_uninstall = _safe_json.loads(_safe_package_uninstall_json)
454
+ _safe_records = _safe_json.loads(_safe_package_records_json)
455
+ _safe_metadata_only = _safe_uninstall is not None and _safe_records is not None
456
+ _safe_record_by_name = {}
457
+ _safe_snapshot_paths = {}
458
+ if _safe_records is not None:
459
+ for _safe_record in _safe_records:
460
+ _safe_record_name = _safe_record[0]
461
+ if _SafeRequirement(_safe_record_name).name != _safe_record_name or _safe_name(_safe_record_name) != _safe_record_name or _safe_record_name in _safe_record_by_name:
462
+ raise ValueError('Invalid Python package metadata snapshot')
463
+ _safe_record_by_name[_safe_record_name] = _safe_record
464
+ if _safe_metadata_only:
465
+ from pathlib import Path as _SafePath
466
+ import sysconfig as _safe_sysconfig
467
+ for _safe_record_name, _safe_record in _safe_record_by_name.items():
468
+ if _safe_record_name in _safe_preloaded:
469
+ continue
470
+ _safe_path = (_SafePath(_safe_sysconfig.get_path('purelib')) / (_safe_record_name.replace('-', '_') + '-snapshot.dist-info')).resolve()
471
+ _safe_path.mkdir()
472
+ (_safe_path / 'METADATA').write_text(_safe_record[1])
473
+ (_safe_path / 'PYODIDE_URL').write_text(_safe_record[2])
474
+ (_safe_path / 'RECORD').write_text('')
475
+ _safe_dist = _safe_metadata.Distribution.at(_safe_path)
476
+ if _safe_name(_safe_dist.metadata['Name']) != _safe_record_name:
477
+ raise ValueError('Python package metadata name conflict: ' + _safe_record_name)
478
+ _SafeRequirement(_safe_record_name + '==' + _safe_dist.version)
479
+ _safe_snapshot_paths[_safe_record_name] = str(_safe_path)
480
+ _safe_metadata.MetadataPathFinder.invalidate_caches()
481
+ _safe_restore = _safe_json.loads(_safe_package_restore_json)
482
+ _safe_restored_roots = await _safe_parse_sources(_safe_restore, not _safe_metadata_only)
483
+ if _safe_package_legacy:
484
+ _safe_restored_names = await _safe_resolve(_safe_restored_roots)
485
+ else:
486
+ if not _safe_metadata_only:
487
+ await _safe_manager.install(_safe_restore, deps=False)
488
+ _safe_validate(_safe_restored_roots)
489
+ _safe_restored_names = {_safe_name(root.name) for root in _safe_restored_roots if not root.marker or root.marker.evaluate({'extra': ''})}
490
+ if _safe_metadata_only and set(_safe_record_by_name) != _safe_restored_names:
491
+ raise ValueError('Python package metadata snapshot does not match installed requirements')
492
+ _safe_roots = await _safe_parse_sources(_safe_json.loads(_safe_package_requirements_json), not _safe_metadata_only)
493
+ if _safe_metadata_only:
494
+ for _safe_root in _safe_roots:
495
+ if _safe_root.url and _safe_name(_safe_root.name) in _safe_snapshot_paths:
496
+ _safe_wheel = _SafeWheelInfo.from_url(_safe_root.url)
497
+ if _safe_name(_safe_wheel.name) == _safe_name(_safe_root.name) and str(_safe_wheel.version) == _safe_metadata.version(_safe_root.name):
498
+ _safe_root.url = None
499
+ _safe_root.specifier = _SafeRequirement(_safe_root.name + '==' + str(_safe_wheel.version)).specifier
500
+ _safe_managed = await _safe_resolve(_safe_roots, _safe_package_upgrade, _safe_package_forceReinstall)
501
+ _safe_distributions = [d for d in _safe_metadata.distributions() if d.metadata['Name']]
502
+ _safe_versions = {_safe_name(d.metadata['Name']): d.version for d in _safe_distributions}
503
+ _safe_removed = []
504
+ if _safe_uninstall:
505
+ _safe_targets = list(dict.fromkeys(_safe_name(_SafeRequirement(source).name) for source in _safe_uninstall['packages']))
506
+ for _safe_target in _safe_targets:
507
+ if _safe_target in _safe_preloaded or _safe_target in _safe_managed:
508
+ raise ValueError('Cannot uninstall host-required Python package: ' + _safe_target)
509
+ for _safe_target in _safe_targets:
510
+ if _safe_target not in _safe_versions:
511
+ await _safe_package_emit('stderr', 'WARNING: Skipping ' + _safe_target + ' as it is not installed.\\n')
512
+ continue
513
+ _safe_dist = _safe_metadata.distribution(_safe_target)
514
+ _safe_version = _safe_dist.version
515
+ await _safe_package_emit('stdout', 'Found existing installation: ' + _safe_target + ' ' + _safe_version + '\\nUninstalling ' + _safe_target + '-' + _safe_version + ':\\n')
516
+ if not _safe_uninstall['yes']:
517
+ _safe_record = _safe_record_by_name.get(_safe_target)
518
+ _safe_lists = _safe_record[3:] if _safe_snapshot_paths.get(_safe_target) == str(_safe_dist._path) else _safe_removal_listing(_safe_dist)
519
+ for _safe_heading, _safe_paths in zip(['Would remove:', 'Would not remove (might be manually added):'], _safe_lists):
520
+ if _safe_paths:
521
+ await _safe_package_emit('stdout', ' ' + _safe_heading + '\\n')
522
+ for _safe_path in _safe_paths:
523
+ await _safe_package_emit('stdout', ' ' + _safe_path + '\\n')
524
+ while True:
525
+ await _safe_package_emit('stdout', 'Proceed (Y/n)? ')
526
+ _safe_answer = (await _safe_package_line()).strip().lower()
527
+ if _safe_answer in ('y', 'n', ''):
528
+ break
529
+ await _safe_package_emit('stdout', 'Your response (' + repr(_safe_answer) + ') was not one of the expected responses: y, n, \\n')
530
+ if _safe_answer == 'n':
531
+ continue
532
+ import logging as _safe_logging
533
+ _safe_logger = _safe_logging.getLogger('micropip')
534
+ _safe_disabled = _safe_logger.disabled
535
+ try:
536
+ _safe_logger.disabled = True
537
+ _safe_manager.uninstall([_safe_target])
538
+ finally:
539
+ _safe_logger.disabled = _safe_disabled
540
+ _safe_metadata.MetadataPathFinder.invalidate_caches()
541
+ try:
542
+ _safe_metadata.distribution(_safe_target)
543
+ except _safe_metadata.PackageNotFoundError:
544
+ pass
545
+ else:
546
+ raise ValueError('Python package removal did not complete: ' + _safe_target)
547
+ _safe_restored_names.discard(_safe_target)
548
+ _safe_removed.append(_safe_target + '-' + _safe_version)
549
+ _safe_distributions = [d for d in _safe_metadata.distributions() if d.metadata['Name']]
550
+ _safe_versions = {_safe_name(d.metadata['Name']): d.version for d in _safe_distributions}
551
+ _safe_uninstalled_json = _safe_json.dumps(_safe_removed)
552
+ _safe_managed.update(_safe_restored_names)
553
+ _safe_sources = []
554
+ _safe_final_records = []
555
+ for _safe_dist in _safe_distributions:
556
+ _safe_dist_name = _safe_name(_safe_dist.metadata['Name'])
557
+ if _safe_dist_name in _safe_managed:
558
+ _safe_origin = _safe_dist.read_text('PYODIDE_URL')
559
+ if _safe_origin:
560
+ _safe_sources.append(_safe_dist_name + ' @ ' + _safe_origin.strip())
561
+ if _safe_snapshot_paths.get(_safe_dist_name) == str(_safe_dist._path):
562
+ _safe_final_records.append(_safe_record_by_name[_safe_dist_name])
563
+ else:
564
+ _safe_headers = _safe_dist.metadata
565
+ _safe_metadata_text = ''.join(key + ': ' + value + '\\n' for key in ['Metadata-Version', 'Name', 'Version', 'Requires-Python', 'Requires-Dist', 'Provides-Extra'] for value in _safe_headers.get_all(key, []))
566
+ _safe_final_records.append([_safe_dist_name, _safe_metadata_text, (_safe_origin or '').strip(), *_safe_removal_listing(_safe_dist)])
567
+ _safe_installed_json = _safe_json.dumps(_safe_sources + [name + '==' + version for name, version in sorted(_safe_versions.items()) if name in _safe_managed])
568
+ _safe_records_json = _safe_json.dumps(_safe_final_records)
569
+ _safe_metadata.MetadataPathFinder.invalidate_caches()
570
+ import gc as _safe_gc
571
+ _safe_gc.collect()
572
+ `);
573
+ await installing;
574
+ accepting = false;
575
+ await pending;
576
+ if (transportFailure) throw transportFailure.error;
577
+ const pinned = JSON.parse(runtime.runPython("_safe_installed_json"));
578
+ await request("package-commit", start.session, start.restore === void 0 ? pinned : { version: 2, installed: pinned, records: JSON.parse(runtime.runPython("_safe_records_json")) });
579
+ if (start.uninstall) {
580
+ const removed = JSON.parse(runtime.runPython("_safe_uninstalled_json"));
581
+ for (const name of removed) {
582
+ const bytes = new TextEncoder().encode(" Successfully uninstalled " + name + "\n");
583
+ for (let offset = 0; offset < bytes.length; offset += maxTransferBytes) await request("stdout", Array.from(bytes.subarray(offset, offset + maxTransferBytes)));
584
+ }
585
+ }
586
+ } catch (error) {
587
+ await installing;
588
+ accepting = false;
589
+ await pending;
590
+ throw transportFailure ? transportFailure.error : error;
591
+ } finally {
592
+ await installing;
593
+ accepting = false;
594
+ await pending;
595
+ manager.downloadPackage = manager.installPackage = async () => {
596
+ throw new Error("Python package transport is only available during installation");
597
+ };
598
+ for (const name of installedGlobals) runtime.globals.delete(name);
599
+ }
600
+ }
601
+
602
+ // packages/safe-bash-command-python/src/execution.ts
603
+ var pythonExecution = `
604
+ import sys, os, json, runpy, traceback, types, warnings, textwrap, io, struct, linecache
605
+ _safe_invocation = json.loads(_safe_invocation_json)
606
+ os.environ.clear()
607
+ os.environ.update(_safe_invocation['env'])
608
+ _safe_args = list(_safe_invocation['args'])
609
+ sys.orig_argv = [_safe_invocation.get('command', 'python')] + _safe_args
610
+ _safe_exit = 0
611
+
612
+ class _SafeOptionError(ValueError):
613
+ pass
614
+
615
+ def _safe_system_exit(_error):
616
+ if isinstance(_error.code, int):
617
+ _status = int.__index__(_error.code)
618
+ _long_bound = 1 << (8 * struct.calcsize('@l') - 1)
619
+ status = (_status & 255) if -_long_bound <= _status < _long_bound else 255
620
+ else:
621
+ status = 0 if _error.code is None else 1
622
+ if _error.code is not None and not isinstance(_error.code, int):
623
+ print(_error.code, file=sys.stderr)
624
+ return status
625
+
626
+ def _safe_launch():
627
+ args = list(_safe_args)
628
+ unbuffered = False
629
+ ignore_env = bool(sys.flags.ignore_environment)
630
+ safe_path = bool(sys.flags.safe_path)
631
+ native_warning_options = list(sys.warnoptions)
632
+ # Pyodide adds a bootstrap cwd entry even when CPython safe-path mode is set.
633
+ # Each execution mode below supplies its own entry after explicit PYTHONPATH.
634
+ sys.path[:] = [entry for entry in sys.path if entry != '']
635
+ warning_options = []
636
+ version_count = 0
637
+ options_terminated = False
638
+ while args and args[0].startswith('-') and args[0] != '-':
639
+ option = args.pop(0)
640
+ if option == '--':
641
+ options_terminated = True
642
+ break
643
+ if option in ('--help', '-h', '-?'):
644
+ print('usage: python [-uBEPOsSIbdvqR] [-W filter] [-X option] [-c code | -m module | file | -] [args ...]')
645
+ print('Dedicated Pyodide interpreter; stdin is noninteractive.')
646
+ print('-u: unbuffered binary output; -B: disable bytecode writes; -E: ignore PYTHON* settings')
647
+ print('-P: omit automatic unsafe sys.path entry; -W: Python warning filter')
648
+ print('-O/-OO, -S/-s/-I, -b/-bb, -d/-v/-q/-R: CPython startup flags')
649
+ print('-X: utf8, dev, warn_default_encoding, int_max_str_digits; interactive flags are unsupported.')
650
+ return
651
+ if option == '--version':
652
+ version_count += 1
653
+ continue
654
+ if option.startswith('--'):
655
+ raise _SafeOptionError('unsupported option ' + option)
656
+ index = 1
657
+ while index < len(option):
658
+ flag = option[index]
659
+ if flag in ('h', '?'):
660
+ args = ['--help']
661
+ break
662
+ if flag == 'V':
663
+ version_count += 1
664
+ index += 1
665
+ continue
666
+ if flag in ('c', 'm', 'W', 'X'):
667
+ operand = option[index + 1:] if index + 1 < len(option) else args.pop(0) if args else None
668
+ if operand is None:
669
+ raise _SafeOptionError('argument expected for -' + flag)
670
+ if flag in ('W', 'X'):
671
+ if flag == 'W': warning_options.append(operand)
672
+ break
673
+ args = ['-' + flag, operand] + args
674
+ break
675
+ elif flag in ('O', 'S', 's', 'I', 'b', 'd', 'v', 'q', 'R'):
676
+ pass # Applied by CPython startup configuration before bootstrap.
677
+ elif flag == 'u':
678
+ unbuffered = True
679
+ elif flag == 'B':
680
+ sys.dont_write_bytecode = True
681
+ elif flag == 'E':
682
+ ignore_env = True
683
+ elif flag == 'P':
684
+ safe_path = True
685
+ else:
686
+ raise _SafeOptionError('unsupported option -' + flag)
687
+ index += 1
688
+ if args and args[0] in ('-c', '-m'):
689
+ break
690
+ if version_count:
691
+ print('Python ' + (sys.version if version_count > 1 else sys.version.split()[0]))
692
+ return
693
+ if not ignore_env:
694
+ unbuffered = unbuffered or bool(os.environ.get('PYTHONUNBUFFERED'))
695
+ sys.dont_write_bytecode = sys.dont_write_bytecode or bool(os.environ.get('PYTHONDONTWRITEBYTECODE'))
696
+ safe_path = safe_path or bool(os.environ.get('PYTHONSAFEPATH'))
697
+ path = os.environ.get('PYTHONPATH')
698
+ if path:
699
+ sys.path[0:0] = [os.path.abspath(entry) for entry in path.split(os.pathsep)]
700
+ if os.environ.get('PYTHONWARNINGS'):
701
+ warning_options[0:0] = os.environ['PYTHONWARNINGS'].split(',')
702
+ encoding = os.environ.get('PYTHONIOENCODING')
703
+ if encoding:
704
+ name, separator, errors = encoding.partition(':')
705
+ for stream in (sys.stdin, sys.stdout):
706
+ stream.reconfigure(encoding=name or None, errors=(errors or 'strict'))
707
+ sys.stderr.reconfigure(encoding=name or None, errors='backslashreplace')
708
+ # CPython's -b/-bb filter follows environment and command-line -W filters.
709
+ byte_warning = ('error' if sys.flags.bytes_warning > 1 else 'default') + '::BytesWarning'
710
+ native_before = [value for value in native_warning_options if not (sys.flags.bytes_warning and value == byte_warning)]
711
+ warning_options = native_before + warning_options + ([byte_warning] if sys.flags.bytes_warning else [])
712
+ warnings._processoptions(warning_options)
713
+ sys.warnoptions[:] = warning_options
714
+ if unbuffered:
715
+ for name in ('stdout', 'stderr'):
716
+ stream = getattr(sys, name)
717
+ stream.flush()
718
+ encoding, errors = stream.encoding, stream.errors
719
+ binary = stream.detach()
720
+ raw = binary.detach() if hasattr(binary, 'detach') else binary
721
+ replacement = io.TextIOWrapper(raw, encoding=encoding, errors=errors, write_through=True)
722
+ setattr(sys, name, replacement)
723
+ setattr(sys, '__' + name + '__', replacement)
724
+ main = types.ModuleType('__main__')
725
+ main.__dict__.update(__package__=None, __spec__=None, __loader__=__import__('importlib.machinery', fromlist=['BuiltinImporter']).BuiltinImporter, __builtins__=__builtins__)
726
+ sys.modules['__main__'] = main
727
+ if not options_terminated and args and args[0] == '-c':
728
+ sys.argv = ['-c'] + args[2:]
729
+ if not safe_path: sys.path.insert(0, '')
730
+ source = textwrap.dedent(args[1])
731
+ code = compile(source, '<string>', 'exec')
732
+ # CPython 3.14 retains -c source for both top-level and nested tracebacks.
733
+ linecache._register_code(code, source, '<string>')
734
+ exec(code, main.__dict__)
735
+ elif not options_terminated and args and args[0] == '-m':
736
+ sys.argv = args[1:]
737
+ if not safe_path: sys.path.insert(0, os.getcwd())
738
+ runpy._run_module_as_main(args[1], alter_argv=True)
739
+ elif not args or args[0] == '-':
740
+ sys.argv = (['-'] + args[1:]) if args else ['']
741
+ if not safe_path: sys.path.insert(0, '')
742
+ main.__file__ = '<stdin>'
743
+ exec(compile(sys.stdin.buffer.read(), '<stdin>', 'exec'), main.__dict__)
744
+ else:
745
+ sys.argv = args
746
+ # CPython makes __file__ absolute without collapsing ./ or ../ components.
747
+ path = args[0] if os.path.isabs(args[0]) else os.path.join(os.getcwd(), args[0])
748
+ importer = __import__('pkgutil').get_importer(path)
749
+ if importer is not None:
750
+ sys.path.insert(0, path)
751
+ runpy._run_module_as_main('__main__', alter_argv=False)
752
+ else:
753
+ if not safe_path: sys.path.insert(0, os.path.dirname(os.path.realpath(path)))
754
+ try:
755
+ with open(path, 'rb') as source:
756
+ code = source.read()
757
+ except OSError as error:
758
+ print("python: can't open file " + repr(path) + ': [Errno ' + str(error.errno) + '] ' + error.strerror, file=sys.stderr)
759
+ return 2
760
+ main.__file__ = path
761
+ main.__loader__ = __import__('importlib.machinery', fromlist=['SourceFileLoader']).SourceFileLoader('__main__', path)
762
+ exec(compile(code, path, 'exec'), main.__dict__)
763
+ return 0
764
+
765
+ try:
766
+ _safe_exit = _safe_launch() or 0
767
+ except SystemExit as _error:
768
+ _safe_exit = _safe_system_exit(_error)
769
+ except _SafeOptionError as _error:
770
+ print('python: ' + str(_error), file=sys.stderr)
771
+ _safe_exit = 2
772
+ except BaseException as _error:
773
+ # Hide bridge frames while preserving actual Python frames and chained errors.
774
+ _trace = _error.__traceback__
775
+ while _trace is not None and _trace.tb_frame.f_code.co_filename == '<exec>':
776
+ _trace = _trace.tb_next
777
+ _error.__traceback__ = _trace
778
+ sys.last_exc = _error
779
+ _safe_exit = 130 if isinstance(_error, KeyboardInterrupt) else 1
780
+ try:
781
+ sys.excepthook(type(_error), _error, _trace)
782
+ except SystemExit as _hook_error:
783
+ _safe_exit = _safe_system_exit(_hook_error)
784
+ except BaseException as _hook_error:
785
+ print('Error in sys.excepthook:', file=sys.stderr)
786
+ traceback.print_exception(type(_hook_error), _hook_error, _hook_error.__traceback__.tb_next)
787
+ print('\\nOriginal exception was:', file=sys.stderr)
788
+ sys.__excepthook__(type(_error), _error, _trace)
789
+ finally:
790
+ for _stream in (sys.stdout, sys.stderr):
791
+ if _stream is not None and not getattr(_stream, 'closed', False):
792
+ try:
793
+ _stream.flush()
794
+ except BaseException:
795
+ _safe_exit = 120
796
+ _safe_exit
797
+ `;
798
+
799
+ // packages/safe-bash-command-python/src/runtime-scripts.ts
800
+ var pythonRuntimeRelocation = `
801
+ import sys, zipimport, importlib.machinery
802
+
803
+ def _rebase_runtime_path(value):
804
+ return _safe_runtime_mount + value if isinstance(value, str) and (value == '/lib' or value.startswith('/lib/')) else value
805
+
806
+ def _rebase_runtime_loader(loader):
807
+ if isinstance(loader, zipimport.zipimporter):
808
+ archive = _rebase_runtime_path(loader.archive)
809
+ if archive != loader.archive:
810
+ return zipimport.zipimporter(archive + '/' + loader.prefix)
811
+ elif isinstance(loader, (importlib.machinery.SourceFileLoader, importlib.machinery.SourcelessFileLoader, importlib.machinery.ExtensionFileLoader)):
812
+ path = _rebase_runtime_path(loader.path)
813
+ if path != loader.path:
814
+ return type(loader)(loader.name, path)
815
+ return loader
816
+ sys.path[:] = [_rebase_runtime_path(value) for value in sys.path]
817
+ for _module in list(sys.modules.values()):
818
+ if _module is None:
819
+ continue
820
+ for _attribute in ('__file__', '__cached__'):
821
+ if hasattr(_module, _attribute):
822
+ setattr(_module, _attribute, _rebase_runtime_path(getattr(_module, _attribute)))
823
+ if hasattr(_module, '__path__'):
824
+ _module.__path__ = [_rebase_runtime_path(value) for value in _module.__path__]
825
+ if hasattr(_module, '__loader__'):
826
+ _module.__loader__ = _rebase_runtime_loader(_module.__loader__)
827
+ _spec = getattr(_module, '__spec__', None)
828
+ if _spec is not None:
829
+ _spec.origin = _rebase_runtime_path(_spec.origin)
830
+ _spec.loader = _rebase_runtime_loader(_spec.loader)
831
+ if _spec.submodule_search_locations is not None:
832
+ _spec.submodule_search_locations = [_rebase_runtime_path(value) for value in _spec.submodule_search_locations]
833
+ sys.path_importer_cache.clear()
834
+ `;
835
+ var pythonImportMetadata = `
836
+ import importlib._bootstrap_external, types, json
837
+ _safe_import_stat_callback = _safe_import_stat
838
+ _safe_original_import_stat = importlib._bootstrap_external._path_stat
839
+ def _safe_import_path_stat(path):
840
+ if path == _safe_runtime_mount or path.startswith(_safe_runtime_mount + '/'):
841
+ return _safe_original_import_stat(path)
842
+ value = json.loads(_safe_import_stat_callback(path))
843
+ if 'errno' in value:
844
+ raise OSError(value['errno'], 'filesystem import metadata unavailable', path)
845
+ return types.SimpleNamespace(st_mode=value['mode'], st_size=value['size'], st_mtime=value['mtimeMs'] / 1000)
846
+ importlib._bootstrap_external._path_stat = _safe_import_path_stat
847
+ `;
848
+ var pythonDirectoryEntries = `
849
+ import os, json, errno
850
+ _safe_directory_callback = _safe_directory_entries
851
+ def _safe_listdir(path='.'):
852
+ if isinstance(path, int):
853
+ raise OSError(errno.ENOTSUP, 'retained directory descriptors are unsupported')
854
+ original = os.fspath(path) if path is not None else '.'
855
+ value = json.loads(_safe_directory_callback(os.fsdecode(original)))
856
+ if 'errno' in value:
857
+ raise OSError(value['errno'], 'directory enumeration failed', path)
858
+ return [os.fsencode(name) for name in value['entries']] if isinstance(original, bytes) else value['entries']
859
+ os.listdir = _safe_listdir
860
+ # The frozen importer holds the posix module separately from os.
861
+ importlib._bootstrap_external._os.listdir = _safe_listdir
862
+ `;
863
+ var pythonStatProjection = `
864
+ import os, json, errno
865
+ _safe_stat_callback = _safe_stat_projection
866
+ _safe_stat_type = os.stat_result
867
+ _safe_fspath = os.fspath
868
+ _safe_fsdecode = os.fsdecode
869
+
870
+ def _safe_stat(path, *, dir_fd=None, follow_symlinks=True):
871
+ if dir_fd is not None:
872
+ raise OSError(errno.ENOTSUP, 'dir_fd metadata is unsupported')
873
+ if isinstance(path, int):
874
+ if not follow_symlinks:
875
+ raise ValueError('stat: cannot use fd and follow_symlinks together')
876
+ else:
877
+ path = _safe_fsdecode(_safe_fspath(path))
878
+ value = json.loads(_safe_stat_callback(path, follow_symlinks))
879
+ if 'errno' in value:
880
+ raise OSError(value['errno'], 'filesystem metadata unavailable', path)
881
+ keys = ('mode','ino','dev','nlink','uid','gid','size')
882
+ if any(key not in value for key in keys):
883
+ raise OSError(errno.EOVERFLOW, 'canonical identity or required stat metadata unavailable', path)
884
+ times = [value[key] / 1000 for key in ('atimeMs','mtimeMs','ctimeMs')]
885
+ extras = dict(zip(('st_atime','st_mtime','st_ctime'), times))
886
+ for name, milliseconds in zip(('atime','mtime','ctime'), (value['atimeMs'],value['mtimeMs'],value['ctimeMs'])):
887
+ seconds = int(milliseconds // 1000)
888
+ extras['st_' + name + '_ns'] = seconds * 1000000000 + round((milliseconds - seconds * 1000) * 1000000)
889
+ for key in ('blocks','blksize','rdev'):
890
+ if key in value:
891
+ extras['st_' + key] = value[key]
892
+ return _safe_stat_type(tuple(value[key] for key in keys) + tuple(int(time // 1) for time in times), extras)
893
+
894
+ def _safe_lstat(path, *, dir_fd=None):
895
+ return _safe_stat(path, dir_fd=dir_fd, follow_symlinks=False)
896
+
897
+ def _safe_fstat(fd):
898
+ if not isinstance(fd, int):
899
+ raise TypeError('file descriptor must be an integer')
900
+ return _safe_stat(fd)
901
+ os.stat = _safe_stat
902
+ os.lstat = _safe_lstat
903
+ os.fstat = _safe_fstat
904
+ import stat as _safe_stat_module
905
+ class _SafeDirEntry:
906
+ def __init__(self, root, name):
907
+ self.name = name
908
+ self.path = os.path.join(root, name)
909
+ self._cache = {}
910
+ def __fspath__(self):
911
+ return self.path
912
+ def stat(self, *, follow_symlinks=True):
913
+ if follow_symlinks not in self._cache:
914
+ self._cache[follow_symlinks] = os.stat(self.path, follow_symlinks=follow_symlinks)
915
+ return self._cache[follow_symlinks]
916
+ def inode(self):
917
+ return self.stat(follow_symlinks=False).st_ino
918
+ def is_dir(self, *, follow_symlinks=True):
919
+ try:
920
+ return _safe_stat_module.S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode)
921
+ except FileNotFoundError:
922
+ return False
923
+ def is_file(self, *, follow_symlinks=True):
924
+ try:
925
+ return _safe_stat_module.S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode)
926
+ except FileNotFoundError:
927
+ return False
928
+ def is_symlink(self):
929
+ try:
930
+ return _safe_stat_module.S_ISLNK(self.stat(follow_symlinks=False).st_mode)
931
+ except FileNotFoundError:
932
+ return False
933
+ class _SafeScandir:
934
+ def __init__(self, path):
935
+ self._entries = iter([_SafeDirEntry(path, name) for name in os.listdir(path)])
936
+ def __iter__(self):
937
+ return self
938
+ def __next__(self):
939
+ return next(self._entries)
940
+ def close(self):
941
+ self._entries = iter(())
942
+ def __enter__(self):
943
+ return self
944
+ def __exit__(self, *args):
945
+ self.close()
946
+ def _safe_scandir(path='.'):
947
+ if isinstance(path, int):
948
+ raise OSError(errno.ENOTSUP, 'retained directory descriptors are unsupported')
949
+ return _SafeScandir(os.fspath(path) if path is not None else '.')
950
+ os.scandir = _safe_scandir
951
+
952
+ `;
953
+ var pythonHardLinks = `
954
+ import os, json, errno
955
+ _safe_link_callback = _safe_hard_link
956
+ def _safe_link(src, dst, *, src_dir_fd=None, dst_dir_fd=None, follow_symlinks=True):
957
+ if src_dir_fd is not None or dst_dir_fd is not None:
958
+ raise OSError(errno.ENOTSUP, 'dir_fd hard links are unsupported')
959
+ source = os.fsdecode(os.fspath(src))
960
+ destination = os.fsdecode(os.fspath(dst))
961
+ value = json.loads(_safe_link_callback(source, destination, bool(follow_symlinks)))
962
+ if 'errno' in value:
963
+ raise OSError(value['errno'], 'hard link creation failed', src, None, dst)
964
+ os.link = _safe_link
965
+ os.supports_follow_symlinks.add(_safe_link)
966
+ `;
967
+ var pythonTreeCleanup = `
968
+ import shutil, os, json
969
+ _safe_tree_callback = _safe_tree_cleanup
970
+ _safe_original_rmtree_impl = shutil._rmtree_impl
971
+ def _safe_rmtree_impl(path, dir_fd, onexc):
972
+ if dir_fd is not None:
973
+ return _safe_original_rmtree_impl(path, dir_fd, onexc)
974
+ value = json.loads(_safe_tree_callback(os.fsdecode(path)))
975
+ if not value['supported']:
976
+ return _safe_original_rmtree_impl(path, dir_fd, onexc)
977
+ if 'errno' in value:
978
+ onexc(os.rmdir, path, OSError(value['errno'], 'directory cleanup failed', path))
979
+ shutil._rmtree_impl = _safe_rmtree_impl
980
+ `;
981
+
982
+ export {
983
+ PythonInvocationError,
984
+ parsePythonInvocation,
985
+ installPythonPackages,
986
+ pythonExecution,
987
+ pythonRuntimeRelocation,
988
+ pythonImportMetadata,
989
+ pythonDirectoryEntries,
990
+ pythonStatProjection,
991
+ pythonHardLinks,
992
+ pythonTreeCleanup
993
+ };