@qvac/harness 0.3.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +700 -126
- package/README.md +156 -0
- package/dist/harness.bundle +71 -103
- package/dist/prebuilds-manifest.json +0 -8
- package/dist-lib/index.d.ts +42 -40
- package/dist-lib/index.js +307 -117
- package/dist-lib/lib/audio-transcode-bare.d.ts +2 -2
- package/dist-lib/lib/audio-transcode-bare.js +28 -18
- package/dist-lib/lib/audio-transcode-node.d.ts +2 -2
- package/dist-lib/lib/capabilities/audio-resample.d.ts +7 -6
- package/dist-lib/lib/capabilities/audio-resample.js +30 -18
- package/dist-lib/lib/capabilities/completion.d.ts +20 -19
- package/dist-lib/lib/capabilities/completion.js +194 -135
- package/dist-lib/lib/capabilities/download.d.ts +6 -6
- package/dist-lib/lib/capabilities/download.js +15 -8
- package/dist-lib/lib/capabilities/embed.js +2 -1
- package/dist-lib/lib/capabilities/enhance.d.ts +6 -1
- package/dist-lib/lib/capabilities/enhance.js +7 -4
- package/dist-lib/lib/capabilities/invoke.js +7 -4
- package/dist-lib/lib/capabilities/kv-cache.js +2 -1
- package/dist-lib/lib/capabilities/preview-model-source.d.ts +69 -0
- package/dist-lib/lib/capabilities/preview-model-source.js +439 -0
- package/dist-lib/lib/capabilities/speech-text.js +5 -4
- package/dist-lib/lib/capabilities/tool-selection.js +10 -9
- package/dist-lib/lib/capabilities/tool-turns.js +30 -16
- package/dist-lib/lib/capabilities/usage-breakdown.js +2 -1
- package/dist-lib/lib/capabilities/voice.d.ts +5 -1
- package/dist-lib/lib/capabilities/voice.js +22 -12
- package/dist-lib/lib/connect.d.ts +15 -37
- package/dist-lib/lib/connect.js +161 -112
- package/dist-lib/lib/context-window.js +25 -21
- package/dist-lib/lib/contract-types.d.ts +26 -20
- package/dist-lib/lib/diagram-repair.d.ts +4 -4
- package/dist-lib/lib/diagram-repair.js +6 -3
- package/dist-lib/lib/docx/index.d.ts +3 -2
- package/dist-lib/lib/{error-fields.d.ts → guards.d.ts} +1 -0
- package/dist-lib/lib/{error-fields.js → guards.js} +3 -0
- package/dist-lib/lib/hardware/capability-probe.js +20 -10
- package/dist-lib/lib/hardware/gpu-classify.js +6 -3
- package/dist-lib/lib/hardware/gpu-probe-addon.js +8 -4
- package/dist-lib/lib/hardware/gpu-probe.js +4 -2
- package/dist-lib/lib/hardware/gpu-stats.native.cjs +8 -9
- package/dist-lib/lib/hardware/parsers.js +8 -4
- package/dist-lib/lib/helpers/buffer-burst.js +4 -2
- package/dist-lib/lib/helpers/control-tokens.js +4 -2
- package/dist-lib/lib/helpers/join-guard.d.ts +2 -2
- package/dist-lib/lib/helpers/join-guard.js +4 -2
- package/dist-lib/lib/helpers/load-stall.js +4 -2
- package/dist-lib/lib/helpers/markup-stream-filter.d.ts +2 -2
- package/dist-lib/lib/helpers/markup-stream-filter.js +6 -3
- package/dist-lib/lib/helpers/race-abort.js +2 -1
- package/dist-lib/lib/helpers/race-timeout.d.ts +5 -0
- package/dist-lib/lib/helpers/race-timeout.js +14 -0
- package/dist-lib/lib/helpers/run-outcome.d.ts +6 -8
- package/dist-lib/lib/helpers/run-outcome.js +36 -20
- package/dist-lib/lib/helpers/spawn-path.js +6 -3
- package/dist-lib/lib/helpers/text-coalescer.js +6 -3
- package/dist-lib/lib/helpers/thinking.js +38 -45
- package/dist-lib/lib/helpers/tool-call-markup.d.ts +9 -7
- package/dist-lib/lib/helpers/tool-call-markup.js +36 -20
- package/dist-lib/lib/helpers/tool-intent.d.ts +3 -2
- package/dist-lib/lib/helpers/tool-intent.js +4 -2
- package/dist-lib/lib/helpers/tool-label.js +18 -9
- package/dist-lib/lib/hooks/built-in/arg-repair.js +23 -13
- package/dist-lib/lib/hooks/built-in/egress.js +2 -1
- package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
- package/dist-lib/lib/hooks/pipeline.d.ts +5 -4
- package/dist-lib/lib/hooks/pipeline.js +6 -3
- package/dist-lib/lib/hooks/run.js +12 -8
- package/dist-lib/lib/model-download-progress.js +10 -8
- package/dist-lib/lib/models/context.d.ts +1 -1
- package/dist-lib/lib/models/context.js +5 -1
- package/dist-lib/lib/models/custom-model-cache.d.ts +13 -0
- package/dist-lib/lib/models/custom-model-cache.js +70 -0
- package/dist-lib/lib/models/gguf-header.d.ts +31 -0
- package/dist-lib/lib/models/gguf-header.js +230 -0
- package/dist-lib/lib/models/idle-unload.d.ts +14 -0
- package/dist-lib/lib/models/idle-unload.js +51 -0
- package/dist-lib/lib/models/kv-cache.d.ts +3 -2
- package/dist-lib/lib/models/kv-cache.js +4 -3
- package/dist-lib/lib/models/llm-presets.d.ts +2 -2
- package/dist-lib/lib/models/llm-presets.js +4 -2
- package/dist-lib/lib/models/model-catalog-constants.js +3 -2
- package/dist-lib/lib/models/model-catalog.d.ts +19 -21
- package/dist-lib/lib/models/model-catalog.js +66 -33
- package/dist-lib/lib/models/model-delete.d.ts +4 -1
- package/dist-lib/lib/models/model-delete.js +30 -15
- package/dist-lib/lib/models/model-handle.js +2 -1
- package/dist-lib/lib/models/model-list.d.ts +14 -3
- package/dist-lib/lib/models/model-list.js +33 -6
- package/dist-lib/lib/models/model-pool.d.ts +44 -10
- package/dist-lib/lib/models/model-pool.js +47 -42
- package/dist-lib/lib/models/model-source.js +11 -6
- package/dist-lib/lib/models/music-catalog.d.ts +2 -2
- package/dist-lib/lib/models/nmt-catalog.d.ts +4 -3
- package/dist-lib/lib/models/nmt-catalog.js +10 -5
- package/dist-lib/lib/models/opencl-cache.d.ts +6 -1
- package/dist-lib/lib/models/opencl-cache.js +5 -3
- package/dist-lib/lib/models/sdk-faults.d.ts +11 -8
- package/dist-lib/lib/models/sdk-faults.js +9 -6
- package/dist-lib/lib/models/shards.d.ts +11 -0
- package/dist-lib/lib/models/shards.js +15 -0
- package/dist-lib/lib/models/tool-dialect.js +10 -5
- package/dist-lib/lib/no-redirect-fetch-bare.d.ts +3 -3
- package/dist-lib/lib/no-redirect-fetch-bare.js +1 -1
- package/dist-lib/lib/no-redirect-fetch-impl.js +6 -3
- package/dist-lib/lib/no-redirect-fetch-node.d.ts +1 -1
- package/dist-lib/lib/no-redirect-fetch-node.js +9 -9
- package/dist-lib/lib/office/index.d.ts +3 -2
- package/dist-lib/lib/office/python.d.ts +3 -2
- package/dist-lib/lib/office/python.js +2 -1
- package/dist-lib/lib/prompt.d.ts +5 -4
- package/dist-lib/lib/prompt.js +8 -4
- package/dist-lib/lib/queue.js +10 -5
- package/dist-lib/lib/resolution-detector.js +21 -11
- package/dist-lib/lib/rpc-session.js +2 -1
- package/dist-lib/lib/sdk-loader.js +2 -1
- package/dist-lib/lib/sdk-storage.js +4 -2
- package/dist-lib/lib/serve.js +128 -68
- package/dist-lib/lib/spawn.js +7 -4
- package/dist-lib/lib/tmp-path.d.ts +7 -6
- package/dist-lib/lib/tool-call-display.d.ts +2 -2
- package/dist-lib/lib/tools/create-documents.js +18 -10
- package/dist-lib/lib/tools/edit-documents.js +23 -13
- package/dist-lib/lib/tools/edit-image.d.ts +2 -2
- package/dist-lib/lib/tools/edit-image.js +60 -36
- package/dist-lib/lib/tools/exec/adapters/adapter.d.ts +10 -10
- package/dist-lib/lib/tools/exec/adapters/python/attachments.d.ts +17 -11
- package/dist-lib/lib/tools/exec/adapters/python/attachments.js +53 -40
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +60 -32
- package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.d.ts +33 -22
- package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.js +58 -29
- package/dist-lib/lib/tools/exec/adapters/python/interrupt-timer.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/loader.js +23 -12
- package/dist-lib/lib/tools/exec/adapters/python/memfs.d.ts +13 -11
- package/dist-lib/lib/tools/exec/adapters/python/memfs.js +10 -5
- package/dist-lib/lib/tools/exec/adapters/python/net-shim.js +3 -1
- package/dist-lib/lib/tools/exec/adapters/python/output-policy.d.ts +6 -4
- package/dist-lib/lib/tools/exec/adapters/python/output-policy.js +20 -10
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +14 -7
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +41 -34
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +316 -166
- package/dist-lib/lib/tools/exec/adapters/python/run-session.d.ts +9 -8
- package/dist-lib/lib/tools/exec/adapters/python/run-session.js +56 -28
- package/dist-lib/lib/tools/exec/adapters/python/wheels.d.ts +8 -10
- package/dist-lib/lib/tools/exec/adapters/python/wheels.js +22 -11
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.d.ts +3 -2
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +41 -26
- package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +27 -18
- package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.js +14 -13
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.d.ts +4 -4
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.js +10 -5
- package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.d.ts +4 -4
- package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/cli-process.d.ts +6 -1
- package/dist-lib/lib/tools/exec/obsidian/cli-process.js +8 -5
- package/dist-lib/lib/tools/exec/obsidian/cli.d.ts +6 -6
- package/dist-lib/lib/tools/exec/obsidian/cli.js +4 -4
- package/dist-lib/lib/tools/exec/obsidian/command.d.ts +3 -2
- package/dist-lib/lib/tools/exec/obsidian/command.js +6 -3
- package/dist-lib/lib/tools/exec/obsidian/output.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/route.d.ts +4 -6
- package/dist-lib/lib/tools/exec/obsidian/route.js +17 -11
- package/dist-lib/lib/tools/exec/obsidian/safe-path.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/vault-create.js +15 -7
- package/dist-lib/lib/tools/exec/obsidian/vault-paths.d.ts +2 -2
- package/dist-lib/lib/tools/exec/obsidian/vault-paths.js +20 -10
- package/dist-lib/lib/tools/exec/obsidian/vault-read.js +20 -13
- package/dist-lib/lib/tools/exec/obsidian/vault-write.js +24 -12
- package/dist-lib/lib/tools/exec/runner.d.ts +14 -14
- package/dist-lib/lib/tools/exec/runner.js +5 -3
- package/dist-lib/lib/tools/exec/scope.js +52 -28
- package/dist-lib/lib/tools/exec/shell-argv.js +31 -18
- package/dist-lib/lib/tools/exec/shell-guidance.d.ts +6 -1
- package/dist-lib/lib/tools/exec/shell-guidance.js +35 -20
- package/dist-lib/lib/tools/exec/video-tools.js +2 -2
- package/dist-lib/lib/tools/exec.d.ts +6 -8
- package/dist-lib/lib/tools/exec.js +113 -54
- package/dist-lib/lib/tools/file-glob.d.ts +4 -5
- package/dist-lib/lib/tools/file-glob.js +16 -11
- package/dist-lib/lib/tools/fs/glob.js +13 -18
- package/dist-lib/lib/tools/fs/remote-protocol.d.ts +10 -10
- package/dist-lib/lib/tools/fs/remote.d.ts +3 -2
- package/dist-lib/lib/tools/fs/remote.js +13 -7
- package/dist-lib/lib/tools/fs/scope.d.ts +8 -3
- package/dist-lib/lib/tools/fs/scope.js +20 -12
- package/dist-lib/lib/tools/fs/walk.js +6 -3
- package/dist-lib/lib/tools/fs/write.d.ts +3 -2
- package/dist-lib/lib/tools/generate-image.d.ts +11 -9
- package/dist-lib/lib/tools/generate-image.js +73 -37
- package/dist-lib/lib/tools/generate-music.d.ts +22 -11
- package/dist-lib/lib/tools/generate-music.js +79 -48
- package/dist-lib/lib/tools/grep.js +66 -41
- package/dist-lib/lib/tools/http-request/encode-fields.js +18 -9
- package/dist-lib/lib/tools/http-request/{utils.js → request.js} +20 -11
- package/dist-lib/lib/tools/http-request/truncate-response.js +57 -46
- package/dist-lib/lib/tools/http-request.d.ts +1 -1
- package/dist-lib/lib/tools/http-request.js +33 -18
- package/dist-lib/lib/tools/mcp/protocol.d.ts +53 -0
- package/dist-lib/lib/tools/mcp/{utils.js → protocol.js} +45 -23
- package/dist-lib/lib/tools/mcp-call.d.ts +1 -1
- package/dist-lib/lib/tools/mcp-call.js +37 -16
- package/dist-lib/lib/tools/operations/builders.js +10 -6
- package/dist-lib/lib/tools/operations/compile.js +20 -10
- package/dist-lib/lib/tools/operations/decoders.js +12 -6
- package/dist-lib/lib/tools/operations/gmail-message.js +3 -2
- package/dist-lib/lib/tools/outbound-guard.d.ts +4 -3
- package/dist-lib/lib/tools/outbound-guard.js +14 -8
- package/dist-lib/lib/tools/private-ip.js +8 -7
- package/dist-lib/lib/tools/rag-search.js +14 -7
- package/dist-lib/lib/tools/read-files.js +23 -20
- package/dist-lib/lib/tools/skill.js +19 -10
- package/dist-lib/lib/tools/skills/auth-resolver.d.ts +11 -18
- package/dist-lib/lib/tools/skills/auth-resolver.js +30 -18
- package/dist-lib/lib/tools/skills/bin-check.d.ts +3 -2
- package/dist-lib/lib/tools/skills/bin-check.js +10 -3
- package/dist-lib/lib/tools/skills/bundled-dir.js +20 -10
- package/dist-lib/lib/tools/skills/bundled-hash.d.ts +3 -2
- package/dist-lib/lib/tools/skills/bundled-hash.js +6 -1
- package/dist-lib/lib/tools/skills/catalog.d.ts +3 -2
- package/dist-lib/lib/tools/skills/catalog.js +33 -28
- package/dist-lib/lib/tools/skills/cli-argv.d.ts +3 -2
- package/dist-lib/lib/tools/skills/cli-argv.js +55 -52
- package/dist-lib/lib/tools/skills/cli-schema-check.js +21 -10
- package/dist-lib/lib/tools/skills/cli-schema-load.js +28 -20
- package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +6 -6
- package/dist-lib/lib/tools/skills/cli-schema.js +2 -1
- package/dist-lib/lib/tools/skills/credential-check.d.ts +6 -3
- package/dist-lib/lib/tools/skills/credential-check.js +24 -12
- package/dist-lib/lib/tools/skills/credential-grants.js +1 -6
- package/dist-lib/lib/tools/skills/credential-health.d.ts +5 -1
- package/dist-lib/lib/tools/skills/credential-health.js +5 -3
- package/dist-lib/lib/tools/skills/frontmatter-parser.js +10 -5
- package/dist-lib/lib/tools/skills/manifest-parse.js +84 -64
- package/dist-lib/lib/tools/skills/mention.js +7 -6
- package/dist-lib/lib/tools/skills/obsidian-readiness.d.ts +2 -2
- package/dist-lib/lib/tools/skills/obsidian-readiness.js +11 -3
- package/dist-lib/lib/tools/skills/overlay-crud.d.ts +6 -4
- package/dist-lib/lib/tools/skills/overlay-crud.js +12 -6
- package/dist-lib/lib/tools/skills/overlay-dir.js +4 -2
- package/dist-lib/lib/tools/skills/overlay-watch.d.ts +3 -2
- package/dist-lib/lib/tools/skills/overlay-watch.js +8 -4
- package/dist-lib/lib/tools/skills/setup-routes.js +1 -3
- package/dist-lib/lib/tools/skills/skill-settings.js +4 -1
- package/dist-lib/lib/tools/skills/skill-state.d.ts +6 -11
- package/dist-lib/lib/tools/skills/skill-state.js +48 -29
- package/dist-lib/lib/tools/skills/tool-grants.js +6 -3
- package/dist-lib/lib/tools/toolsets.js +2 -1
- package/dist-lib/lib/tools/translate.d.ts +4 -5
- package/dist-lib/lib/tools/translate.js +31 -14
- package/dist-lib/lib/tools/url-guard.js +2 -1
- package/dist-lib/lib/tools/weather-lookup/place.js +8 -4
- package/dist-lib/lib/tools/weather-lookup/report.d.ts +7 -1
- package/dist-lib/lib/tools/weather-lookup/report.js +46 -9
- package/dist-lib/lib/tools/weather-lookup.js +18 -12
- package/dist-lib/lib/tools/web-fetch.js +47 -24
- package/dist-lib/lib/tools/web-search.js +8 -3
- package/dist-lib/lib/validating-lookup.d.ts +4 -4
- package/dist-lib/lib/wav-encode.d.ts +1 -1
- package/dist-lib/lib/wav-encode.js +11 -10
- package/dist-lib/lib/web-fetch/embedded-state.js +24 -12
- package/dist-lib/lib/web-fetch/extract.js +4 -2
- package/dist-lib/lib/web-fetch/images.js +8 -4
- package/dist-lib/lib/web-fetch/video.d.ts +2 -2
- package/dist-lib/lib/web-fetch/video.js +8 -4
- package/dist-lib/lib/web-search/engine-registry.d.ts +2 -2
- package/dist-lib/lib/web-search/engines/aol.js +1 -1
- package/dist-lib/lib/web-search/engines/bing.js +1 -1
- package/dist-lib/lib/web-search/engines/brave.js +4 -1
- package/dist-lib/lib/web-search/engines/duckduckgo.js +3 -2
- package/dist-lib/lib/web-search/engines/google.js +7 -3
- package/dist-lib/lib/web-search/engines/wikipedia.js +5 -4
- package/dist-lib/lib/web-search/engines/yahoo.js +1 -1
- package/dist-lib/lib/web-search/fetch-html.d.ts +5 -4
- package/dist-lib/lib/web-search/fetch-html.js +13 -7
- package/dist-lib/lib/web-search/orchestrator.d.ts +9 -5
- package/dist-lib/lib/web-search/orchestrator.js +3 -3
- package/dist-lib/lib/wire.d.ts +3 -2
- package/dist-lib/lib/wire.js +23 -15
- package/dist-lib/schema/baseline.js +10 -5
- package/dist-lib/schema/build.js +2 -1
- package/dist-lib/schema/harness.d.ts +15 -2
- package/dist-lib/schema/harness.js +55 -2
- package/dist-lib/schema/release-tags.d.ts +3 -2
- package/dist-lib/schema/release-tags.js +6 -3
- package/dist-lib/spec/bind.js +6 -0
- package/dist-lib/spec/calls.js +2 -0
- package/dist-lib/spec/hrpc/hrpc.json +26 -0
- package/dist-lib/spec/hrpc/index.js +27 -3
- package/dist-lib/spec/hrpc/messages.js +207 -8
- package/dist-lib/spec/hyperschema/index.js +207 -8
- package/dist-lib/spec/hyperschema/schema.json +165 -1
- package/dist-lib/spec/hyperschema/types.d.ts +42 -1
- package/package.json +13 -14
- package/worker/harness-sidecar.mjs +16 -22
- package/worker/stow-entry.mjs +7 -4
- package/dist-lib/lib/tools/mcp/utils.d.ts +0 -47
- /package/dist-lib/lib/tools/http-request/{utils.d.ts → request.d.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IMAGE_INPUT, OFFICE_READ, PDF_READ, isEscaped, parseInputs, parseOutputs, parsePackages, stripCommentsAndDocstrings, unwrapPythonSource } from './python-adapter.js';
|
|
1
|
+
import { IMAGE_INPUT, OFFICE_READ, PDF_READ, isEscaped, parseInputs, parseOutputs, parsePackages, stripCommentsAndDocstrings, tripleQuoteAt, unwrapPythonSource } from './python-adapter.js';
|
|
2
2
|
const ARTIFACT_OUTPUT = /\.(docx|xlsx|pptx|pdf)$/i;
|
|
3
3
|
const CREATE_PACKAGES = new Map([
|
|
4
4
|
['python-docx', '1.2.0'],
|
|
@@ -126,13 +126,14 @@ export function splitPythonSource(source) {
|
|
|
126
126
|
}
|
|
127
127
|
continue;
|
|
128
128
|
}
|
|
129
|
-
const triple =
|
|
129
|
+
const triple = tripleQuoteAt(source, i);
|
|
130
130
|
const quote = triple ?? (ch === '"' || ch === "'" ? ch : null);
|
|
131
131
|
if (quote) {
|
|
132
132
|
const fstring = isFStringPrefix(code);
|
|
133
|
-
const end = scanLiteral(source, i + quote.length, quote, fstring);
|
|
134
|
-
if (!end)
|
|
133
|
+
const end = scanLiteral(source, i + quote.length, { quote, fstring });
|
|
134
|
+
if (!end) {
|
|
135
135
|
return null;
|
|
136
|
+
}
|
|
136
137
|
code += '""';
|
|
137
138
|
text += end.text;
|
|
138
139
|
code += end.code;
|
|
@@ -144,7 +145,7 @@ export function splitPythonSource(source) {
|
|
|
144
145
|
}
|
|
145
146
|
return { code, text };
|
|
146
147
|
}
|
|
147
|
-
function scanLiteral(source, start, quote, fstring) {
|
|
148
|
+
function scanLiteral(source, start, { quote, fstring }) {
|
|
148
149
|
let text = '';
|
|
149
150
|
let code = '';
|
|
150
151
|
let i = start;
|
|
@@ -159,11 +160,13 @@ function scanLiteral(source, start, quote, fstring) {
|
|
|
159
160
|
i += 2;
|
|
160
161
|
continue;
|
|
161
162
|
}
|
|
162
|
-
if (ch === '}')
|
|
163
|
+
if (ch === '}') {
|
|
163
164
|
return null;
|
|
165
|
+
}
|
|
164
166
|
const interior = scanInterpolation(source, i + 1);
|
|
165
|
-
if (!interior)
|
|
167
|
+
if (!interior) {
|
|
166
168
|
return null;
|
|
169
|
+
}
|
|
167
170
|
code += ` ${interior.code} `;
|
|
168
171
|
text += interior.text;
|
|
169
172
|
i = interior.index;
|
|
@@ -183,10 +186,12 @@ function scanInterpolation(source, start) {
|
|
|
183
186
|
while (i < source.length) {
|
|
184
187
|
const ch = source[i];
|
|
185
188
|
if (nested) {
|
|
186
|
-
if (ch === nested && !isEscaped(source, i))
|
|
189
|
+
if (ch === nested && !isEscaped(source, i)) {
|
|
187
190
|
nested = null;
|
|
188
|
-
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
189
193
|
text += ch;
|
|
194
|
+
}
|
|
190
195
|
i++;
|
|
191
196
|
continue;
|
|
192
197
|
}
|
|
@@ -195,12 +200,14 @@ function scanInterpolation(source, start) {
|
|
|
195
200
|
i++;
|
|
196
201
|
continue;
|
|
197
202
|
}
|
|
198
|
-
if (ch === '{')
|
|
203
|
+
if (ch === '{') {
|
|
199
204
|
depth++;
|
|
205
|
+
}
|
|
200
206
|
if (ch === '}') {
|
|
201
207
|
depth--;
|
|
202
|
-
if (depth === 0)
|
|
208
|
+
if (depth === 0) {
|
|
203
209
|
return { index: i + 1, text, code };
|
|
210
|
+
}
|
|
204
211
|
}
|
|
205
212
|
code += ch;
|
|
206
213
|
i++;
|
|
@@ -210,81 +217,102 @@ function scanInterpolation(source, start) {
|
|
|
210
217
|
function isKeywordArgument(code, start, length) {
|
|
211
218
|
const before = code.slice(0, start).trimEnd();
|
|
212
219
|
const last = before[before.length - 1];
|
|
213
|
-
if (last !== '(' && last !== ',')
|
|
220
|
+
if (last !== '(' && last !== ',') {
|
|
214
221
|
return false;
|
|
222
|
+
}
|
|
215
223
|
const after = code.slice(start + length).trimStart();
|
|
216
224
|
return after.startsWith('=') && after[1] !== '=';
|
|
217
225
|
}
|
|
218
226
|
function lintCreateSource(source) {
|
|
219
227
|
const halves = splitPythonSource(source);
|
|
220
|
-
if (!halves)
|
|
228
|
+
if (!halves) {
|
|
221
229
|
return 'write';
|
|
222
|
-
|
|
230
|
+
}
|
|
231
|
+
if (halves.text.includes('__')) {
|
|
223
232
|
return 'write';
|
|
224
|
-
|
|
233
|
+
}
|
|
234
|
+
if (/\\(?:x[0-9A-Fa-f]|u[0-9A-Fa-f]|U[0-9A-Fa-f]|N\{|[0-7])/.test(halves.text)) {
|
|
225
235
|
return 'write';
|
|
226
|
-
|
|
236
|
+
}
|
|
237
|
+
if (/[^\x20-\x7e\t\r\n\f]/.test(halves.code)) {
|
|
227
238
|
return 'write';
|
|
239
|
+
}
|
|
228
240
|
let builder = false;
|
|
229
241
|
for (const line of halves.code.split('\n')) {
|
|
230
242
|
for (const statement of line.split(';')) {
|
|
231
243
|
if (!/\b(?:from|import)\b/.test(statement))
|
|
232
244
|
continue;
|
|
233
245
|
const match = IMPORT_FROM.exec(statement);
|
|
234
|
-
if (!match)
|
|
246
|
+
if (!match) {
|
|
235
247
|
return 'write';
|
|
248
|
+
}
|
|
236
249
|
const root = match[1].split('.')[0];
|
|
237
|
-
if (!IMPORT_ROOTS.has(root))
|
|
250
|
+
if (!IMPORT_ROOTS.has(root)) {
|
|
238
251
|
return 'write';
|
|
239
|
-
|
|
252
|
+
}
|
|
253
|
+
if (BUILDER_ROOTS.has(root)) {
|
|
240
254
|
builder = true;
|
|
255
|
+
}
|
|
241
256
|
}
|
|
242
257
|
}
|
|
243
|
-
if (!builder)
|
|
258
|
+
if (!builder) {
|
|
244
259
|
return 'write';
|
|
260
|
+
}
|
|
245
261
|
for (const match of halves.code.matchAll(/[A-Za-z_]\w*/g)) {
|
|
246
262
|
const token = match[0];
|
|
247
263
|
if (token.includes('__') || DENIED_TOKENS.has(token) || INTROSPECTION_TOKEN.test(token)) {
|
|
248
264
|
return 'write';
|
|
249
265
|
}
|
|
250
|
-
if (isKeywordArgument(halves.code, match.index, token.length))
|
|
266
|
+
if (isKeywordArgument(halves.code, match.index, token.length)) {
|
|
251
267
|
continue;
|
|
252
|
-
|
|
268
|
+
}
|
|
269
|
+
if (PYTHON_BUILTINS.has(token) && !ALLOWED_BUILTINS.has(token)) {
|
|
253
270
|
return 'write';
|
|
271
|
+
}
|
|
254
272
|
}
|
|
255
273
|
const openers = stripCommentsAndDocstrings(source);
|
|
256
274
|
const reads = [new RegExp(OFFICE_READ.source), new RegExp(PDF_READ.source)];
|
|
257
|
-
if (reads.some((pattern) => pattern.test(openers)))
|
|
275
|
+
if (reads.some((pattern) => pattern.test(openers))) {
|
|
258
276
|
return 'write';
|
|
277
|
+
}
|
|
259
278
|
return 'read';
|
|
260
279
|
}
|
|
261
280
|
export function pythonCreateEffect(args) {
|
|
262
281
|
const outputs = parseOutputs(args.outputs);
|
|
263
|
-
if (!Array.isArray(outputs) || outputs.length === 0)
|
|
282
|
+
if (!Array.isArray(outputs) || outputs.length === 0) {
|
|
264
283
|
return 'write';
|
|
265
|
-
|
|
284
|
+
}
|
|
285
|
+
if (!outputs.every((name) => ARTIFACT_OUTPUT.test(name))) {
|
|
266
286
|
return 'write';
|
|
287
|
+
}
|
|
267
288
|
const packages = parsePackages(args.packages);
|
|
268
|
-
if (packages && 'error' in packages)
|
|
289
|
+
if (packages && 'error' in packages) {
|
|
269
290
|
return 'write';
|
|
291
|
+
}
|
|
270
292
|
for (const spec of packages ?? []) {
|
|
271
293
|
const match = PACKAGE_SPEC.exec(spec);
|
|
272
|
-
if (!match)
|
|
294
|
+
if (!match) {
|
|
273
295
|
return 'write';
|
|
296
|
+
}
|
|
274
297
|
const name = match[1].toLowerCase().replace(/[_.]+/g, '-');
|
|
275
|
-
if (!CREATE_PACKAGES.has(name))
|
|
298
|
+
if (!CREATE_PACKAGES.has(name)) {
|
|
276
299
|
return 'write';
|
|
277
|
-
|
|
300
|
+
}
|
|
301
|
+
if (CREATE_PACKAGES.get(name) !== (match[2] ?? null)) {
|
|
278
302
|
return 'write';
|
|
303
|
+
}
|
|
279
304
|
}
|
|
280
305
|
const inputs = parseInputs(args.inputs);
|
|
281
|
-
if (inputs && 'error' in inputs)
|
|
306
|
+
if (inputs && 'error' in inputs) {
|
|
282
307
|
return 'write';
|
|
283
|
-
|
|
308
|
+
}
|
|
309
|
+
if ((inputs ?? []).some((input) => !IMAGE_INPUT.test(input.path))) {
|
|
284
310
|
return 'write';
|
|
311
|
+
}
|
|
285
312
|
const command = String(args.command ?? '');
|
|
286
313
|
const source = unwrapPythonSource(command) ?? command;
|
|
287
|
-
if (!source.trim())
|
|
314
|
+
if (!source.trim()) {
|
|
288
315
|
return 'write';
|
|
316
|
+
}
|
|
289
317
|
return lintCreateSource(source);
|
|
290
318
|
}
|
|
@@ -3,29 +3,32 @@ import type { NoRedirectFetchInit, NoRedirectFetchResponse } from '../../../../n
|
|
|
3
3
|
export declare const MAX_RESPONSE_BYTES: number;
|
|
4
4
|
type NoRedirectFetch = (url: URL, init?: NoRedirectFetchInit) => Promise<NoRedirectFetchResponse>;
|
|
5
5
|
declare const GUARDED: unique symbol;
|
|
6
|
-
export
|
|
6
|
+
export interface ConnectPolicy {
|
|
7
7
|
readonly named: readonly string[];
|
|
8
8
|
readonly ask: (host: string) => Promise<boolean>;
|
|
9
|
-
}
|
|
9
|
+
}
|
|
10
10
|
export declare function setConnectPolicy(next: ConnectPolicy | null): void;
|
|
11
11
|
export declare function isGuardedFetch(fetch: unknown): boolean;
|
|
12
|
-
|
|
12
|
+
interface SignalLike {
|
|
13
13
|
readonly aborted: boolean;
|
|
14
14
|
addEventListener(type: 'abort', listener: () => void): void;
|
|
15
|
-
}
|
|
16
|
-
|
|
15
|
+
}
|
|
16
|
+
interface RequestLike {
|
|
17
|
+
url: string;
|
|
18
|
+
}
|
|
19
|
+
interface FetchInit {
|
|
17
20
|
method?: string;
|
|
18
21
|
headers?: unknown;
|
|
19
22
|
body?: unknown;
|
|
20
23
|
signal?: SignalLike | null;
|
|
21
24
|
redirect?: string;
|
|
22
|
-
}
|
|
23
|
-
export
|
|
25
|
+
}
|
|
26
|
+
export interface GuardedFetchOptions {
|
|
24
27
|
readonly fetch?: NoRedirectFetch;
|
|
25
28
|
readonly resolveHost?: HostResolver;
|
|
26
29
|
readonly maxBytes?: number;
|
|
27
30
|
readonly timeoutMs?: number;
|
|
28
|
-
}
|
|
31
|
+
}
|
|
29
32
|
declare class GuardedHeaders {
|
|
30
33
|
#private;
|
|
31
34
|
constructor(entries: [string, string][]);
|
|
@@ -37,6 +40,24 @@ declare class GuardedHeaders {
|
|
|
37
40
|
forEach(fn: (value: string, key: string) => void): void;
|
|
38
41
|
[Symbol.iterator](): IterableIterator<[string, string]>;
|
|
39
42
|
}
|
|
43
|
+
export interface GuardedResponseInit {
|
|
44
|
+
readonly status: number;
|
|
45
|
+
readonly headers: [string, string][];
|
|
46
|
+
readonly url: string;
|
|
47
|
+
readonly redirected: boolean;
|
|
48
|
+
}
|
|
49
|
+
interface BodyChunk {
|
|
50
|
+
done: boolean;
|
|
51
|
+
value?: Uint8Array;
|
|
52
|
+
}
|
|
53
|
+
interface BodyReader {
|
|
54
|
+
read(): Promise<BodyChunk>;
|
|
55
|
+
cancel(): Promise<void>;
|
|
56
|
+
releaseLock(): void;
|
|
57
|
+
}
|
|
58
|
+
interface ResponseBody {
|
|
59
|
+
getReader(): BodyReader;
|
|
60
|
+
}
|
|
40
61
|
export declare class GuardedResponse {
|
|
41
62
|
#private;
|
|
42
63
|
readonly type = "basic";
|
|
@@ -45,28 +66,18 @@ export declare class GuardedResponse {
|
|
|
45
66
|
readonly headers: GuardedHeaders;
|
|
46
67
|
readonly url: string;
|
|
47
68
|
readonly redirected: boolean;
|
|
48
|
-
constructor(
|
|
69
|
+
constructor(bytes: Uint8Array, { status, headers, url, redirected }: GuardedResponseInit);
|
|
49
70
|
get ok(): boolean;
|
|
50
71
|
get bodyUsed(): boolean;
|
|
51
|
-
get body():
|
|
52
|
-
getReader(): {
|
|
53
|
-
read(): Promise<{
|
|
54
|
-
done: boolean;
|
|
55
|
-
value?: Uint8Array;
|
|
56
|
-
}>;
|
|
57
|
-
cancel(): Promise<void>;
|
|
58
|
-
releaseLock(): void;
|
|
59
|
-
};
|
|
60
|
-
};
|
|
72
|
+
get body(): ResponseBody;
|
|
61
73
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
62
74
|
bytes(): Promise<Uint8Array>;
|
|
63
75
|
text(): Promise<string>;
|
|
64
76
|
json(): Promise<unknown>;
|
|
65
77
|
clone(): GuardedResponse;
|
|
66
78
|
}
|
|
67
|
-
|
|
68
|
-
url: string;
|
|
69
|
-
}, init?: FetchInit) => Promise<GuardedResponse>) & {
|
|
79
|
+
type GuardedFetch = ((input: string | URL | RequestLike, init?: FetchInit) => Promise<GuardedResponse>) & {
|
|
70
80
|
[GUARDED]: true;
|
|
71
81
|
};
|
|
82
|
+
export declare function createGuardedFetch(options?: GuardedFetchOptions): GuardedFetch;
|
|
72
83
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbortController } from 'bare-abort-controller';
|
|
2
2
|
import b4a from 'b4a';
|
|
3
|
-
import
|
|
3
|
+
import { noRedirectFetch } from '#no-redirect-fetch';
|
|
4
4
|
import { lookupHost } from '../../../../dns-lookup.js';
|
|
5
5
|
import { hostIsNamed } from './named-hosts.js';
|
|
6
6
|
import { checkOutboundHost, resolveOutboundUrl } from '../../../url-guard.js';
|
|
@@ -16,28 +16,35 @@ export function setConnectPolicy(next) {
|
|
|
16
16
|
granted.clear();
|
|
17
17
|
}
|
|
18
18
|
async function mayConnect(host) {
|
|
19
|
-
if (!policy || granted.has(host) || hostIsNamed(host, policy.named))
|
|
19
|
+
if (!policy || granted.has(host) || hostIsNamed(host, policy.named)) {
|
|
20
20
|
return true;
|
|
21
|
+
}
|
|
21
22
|
const allowed = await policy.ask(host);
|
|
22
|
-
if (allowed)
|
|
23
|
+
if (allowed) {
|
|
23
24
|
granted.add(host);
|
|
25
|
+
}
|
|
24
26
|
return allowed;
|
|
25
27
|
}
|
|
26
28
|
export function isGuardedFetch(fetch) {
|
|
27
|
-
return typeof fetch === 'function' && fetch[GUARDED] === true;
|
|
29
|
+
return typeof fetch === 'function' && GUARDED in fetch && fetch[GUARDED] === true;
|
|
28
30
|
}
|
|
29
31
|
function isRedirect(status) {
|
|
30
32
|
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
31
33
|
}
|
|
34
|
+
function headerPairs(headers) {
|
|
35
|
+
if (Array.isArray(headers))
|
|
36
|
+
return headers;
|
|
37
|
+
if ('entries' in headers && typeof headers.entries === 'function') {
|
|
38
|
+
return headers.entries();
|
|
39
|
+
}
|
|
40
|
+
return Object.entries(headers);
|
|
41
|
+
}
|
|
32
42
|
function headerRecord(headers) {
|
|
33
43
|
const out = {};
|
|
34
|
-
if (!headers || typeof headers !== 'object')
|
|
44
|
+
if (!headers || typeof headers !== 'object') {
|
|
35
45
|
return out;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
: typeof headers.entries === 'function'
|
|
39
|
-
? headers.entries()
|
|
40
|
-
: Object.entries(headers);
|
|
46
|
+
}
|
|
47
|
+
const pairs = headerPairs(headers);
|
|
41
48
|
for (const pair of pairs) {
|
|
42
49
|
if (!Array.isArray(pair) || pair.length < 2)
|
|
43
50
|
continue;
|
|
@@ -50,10 +57,12 @@ function bodyBytes(body) {
|
|
|
50
57
|
return undefined;
|
|
51
58
|
if (typeof body === 'string')
|
|
52
59
|
return body;
|
|
53
|
-
if (body instanceof ArrayBuffer)
|
|
60
|
+
if (body instanceof ArrayBuffer) {
|
|
54
61
|
return new Uint8Array(body);
|
|
55
|
-
|
|
62
|
+
}
|
|
63
|
+
if (ArrayBuffer.isView(body)) {
|
|
56
64
|
return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
|
|
65
|
+
}
|
|
57
66
|
return String(body);
|
|
58
67
|
}
|
|
59
68
|
function plain(bytes) {
|
|
@@ -95,7 +104,7 @@ export class GuardedResponse {
|
|
|
95
104
|
redirected;
|
|
96
105
|
#bytes;
|
|
97
106
|
#used = false;
|
|
98
|
-
constructor(status, headers,
|
|
107
|
+
constructor(bytes, { status, headers, url, redirected }) {
|
|
99
108
|
this.status = status;
|
|
100
109
|
this.headers = new GuardedHeaders(headers);
|
|
101
110
|
this.#bytes = bytes;
|
|
@@ -116,8 +125,9 @@ export class GuardedResponse {
|
|
|
116
125
|
this.#used = true;
|
|
117
126
|
return {
|
|
118
127
|
read: async () => {
|
|
119
|
-
if (offset >= bytes.byteLength)
|
|
128
|
+
if (offset >= bytes.byteLength) {
|
|
120
129
|
return { done: true };
|
|
130
|
+
}
|
|
121
131
|
const value = plain(bytes.subarray(offset, offset + CHUNK_BYTES));
|
|
122
132
|
offset += value.byteLength;
|
|
123
133
|
return { done: false, value };
|
|
@@ -132,8 +142,7 @@ export class GuardedResponse {
|
|
|
132
142
|
}
|
|
133
143
|
async arrayBuffer() {
|
|
134
144
|
this.#used = true;
|
|
135
|
-
|
|
136
|
-
return buffer.slice(byteOffset, byteOffset + byteLength);
|
|
145
|
+
return new Uint8Array(this.#bytes).buffer;
|
|
137
146
|
}
|
|
138
147
|
async bytes() {
|
|
139
148
|
return new Uint8Array(await this.arrayBuffer());
|
|
@@ -146,11 +155,16 @@ export class GuardedResponse {
|
|
|
146
155
|
return JSON.parse(await this.text());
|
|
147
156
|
}
|
|
148
157
|
clone() {
|
|
149
|
-
return new GuardedResponse(this
|
|
158
|
+
return new GuardedResponse(this.#bytes, {
|
|
159
|
+
status: this.status,
|
|
160
|
+
headers: [...this.headers.entries()],
|
|
161
|
+
url: this.url,
|
|
162
|
+
redirected: this.redirected
|
|
163
|
+
});
|
|
150
164
|
}
|
|
151
165
|
}
|
|
152
166
|
export function createGuardedFetch(options = {}) {
|
|
153
|
-
const send = options.fetch ??
|
|
167
|
+
const send = options.fetch ?? noRedirectFetch;
|
|
154
168
|
const resolveHost = options.resolveHost ?? lookupHost;
|
|
155
169
|
const maxBytes = options.maxBytes ?? MAX_RESPONSE_BYTES;
|
|
156
170
|
const timeoutMs = options.timeoutMs ?? TIMEOUT_MS;
|
|
@@ -161,8 +175,9 @@ export function createGuardedFetch(options = {}) {
|
|
|
161
175
|
const headers = headerRecord(init.headers);
|
|
162
176
|
const controller = new AbortController();
|
|
163
177
|
const timer = setTimeout(() => controller.abort(undefined), timeoutMs);
|
|
164
|
-
if (init.signal?.aborted)
|
|
178
|
+
if (init.signal?.aborted) {
|
|
165
179
|
controller.abort(undefined);
|
|
180
|
+
}
|
|
166
181
|
init.signal?.addEventListener('abort', () => controller.abort(undefined));
|
|
167
182
|
try {
|
|
168
183
|
for (let hops = 0;; hops++) {
|
|
@@ -170,14 +185,16 @@ export function createGuardedFetch(options = {}) {
|
|
|
170
185
|
throw new TypeError(`fetch refused: unsupported protocol ${url.protocol}`);
|
|
171
186
|
}
|
|
172
187
|
const literal = checkOutboundHost(url);
|
|
173
|
-
if (literal)
|
|
188
|
+
if (literal) {
|
|
174
189
|
throw new TypeError(`fetch refused: ${literal}`);
|
|
190
|
+
}
|
|
175
191
|
if (!(await mayConnect(url.hostname))) {
|
|
176
192
|
throw new TypeError(`fetch refused: ${url.hostname} was not approved for this run`);
|
|
177
193
|
}
|
|
178
194
|
const check = await resolveOutboundUrl(url, resolveHost, controller.signal);
|
|
179
|
-
if (check.blocked)
|
|
195
|
+
if (check.blocked) {
|
|
180
196
|
throw new TypeError(`fetch refused: ${check.blocked}`);
|
|
197
|
+
}
|
|
181
198
|
const response = await send(url, {
|
|
182
199
|
method,
|
|
183
200
|
headers,
|
|
@@ -188,18 +205,22 @@ export function createGuardedFetch(options = {}) {
|
|
|
188
205
|
});
|
|
189
206
|
const location = response.headers.get('location');
|
|
190
207
|
if (!isRedirect(response.status) || !location || init.redirect === 'manual') {
|
|
191
|
-
return new GuardedResponse(
|
|
208
|
+
return new GuardedResponse(plain(response.bytes()), {
|
|
209
|
+
status: response.status,
|
|
210
|
+
headers: response.headers.entries(),
|
|
211
|
+
url: url.href,
|
|
212
|
+
redirected: hops > 0
|
|
213
|
+
});
|
|
192
214
|
}
|
|
193
|
-
if (init.redirect === 'error')
|
|
215
|
+
if (init.redirect === 'error') {
|
|
194
216
|
throw new TypeError('fetch refused: redirect not allowed');
|
|
195
|
-
|
|
217
|
+
}
|
|
218
|
+
if (hops >= MAX_REDIRECTS) {
|
|
196
219
|
throw new TypeError('fetch refused: too many redirects');
|
|
220
|
+
}
|
|
197
221
|
const next = new URL(location, url);
|
|
198
222
|
if (next.protocol !== url.protocol || next.host !== url.host) {
|
|
199
|
-
|
|
200
|
-
if (/^(authorization|cookie)$/i.test(name))
|
|
201
|
-
delete headers[name];
|
|
202
|
-
}
|
|
223
|
+
stripCredentials(headers);
|
|
203
224
|
}
|
|
204
225
|
if (response.status === 303 ||
|
|
205
226
|
((response.status === 301 || response.status === 302) && method === 'POST')) {
|
|
@@ -215,8 +236,16 @@ export function createGuardedFetch(options = {}) {
|
|
|
215
236
|
};
|
|
216
237
|
const fetch = (input, init) => {
|
|
217
238
|
const response = guardedFetch(input, init);
|
|
218
|
-
response.catch(
|
|
239
|
+
response.catch(noop);
|
|
219
240
|
return response;
|
|
220
241
|
};
|
|
221
242
|
return Object.assign(fetch, { [GUARDED]: true });
|
|
222
243
|
}
|
|
244
|
+
function stripCredentials(headers) {
|
|
245
|
+
for (const name of Object.keys(headers)) {
|
|
246
|
+
if (/^(authorization|cookie)$/i.test(name)) {
|
|
247
|
+
delete headers[name];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function noop() { }
|
|
@@ -15,12 +15,15 @@ class B4aTextDecoder {
|
|
|
15
15
|
encoding;
|
|
16
16
|
constructor(label = 'utf-8') {
|
|
17
17
|
const normalized = String(label).toLowerCase();
|
|
18
|
-
if (normalized.includes('16'))
|
|
18
|
+
if (normalized.includes('16')) {
|
|
19
19
|
this.encoding = 'utf16le';
|
|
20
|
-
|
|
20
|
+
}
|
|
21
|
+
else if (/latin1|iso-8859|ascii/.test(normalized)) {
|
|
21
22
|
this.encoding = 'latin1';
|
|
22
|
-
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
23
25
|
this.encoding = 'utf8';
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
decode(input) {
|
|
26
29
|
if (input === undefined)
|
|
@@ -39,13 +42,15 @@ class B4aTextEncoder {
|
|
|
39
42
|
export function nodeShapedProcess(base) {
|
|
40
43
|
return new Proxy(base, {
|
|
41
44
|
get(target, prop) {
|
|
42
|
-
if (prop === 'versions')
|
|
45
|
+
if (prop === 'versions') {
|
|
43
46
|
return { ...target.versions, node: '22.0.0' };
|
|
47
|
+
}
|
|
44
48
|
if (prop === 'binding') {
|
|
45
49
|
return (name) => (name === 'constants' ? { fs: fsConstants } : {});
|
|
46
50
|
}
|
|
47
|
-
if (prop === 'getuid')
|
|
51
|
+
if (prop === 'getuid') {
|
|
48
52
|
return () => 0;
|
|
53
|
+
}
|
|
49
54
|
return Reflect.get(target, prop);
|
|
50
55
|
}
|
|
51
56
|
});
|
|
@@ -64,12 +69,15 @@ async function shapeBareGlobals() {
|
|
|
64
69
|
g.AbortController = AbortController;
|
|
65
70
|
g.AbortSignal = AbortSignal;
|
|
66
71
|
}
|
|
67
|
-
if (!g.TextDecoder)
|
|
72
|
+
if (!g.TextDecoder) {
|
|
68
73
|
g.TextDecoder = B4aTextDecoder;
|
|
69
|
-
|
|
74
|
+
}
|
|
75
|
+
if (!g.TextEncoder) {
|
|
70
76
|
g.TextEncoder = B4aTextEncoder;
|
|
71
|
-
|
|
77
|
+
}
|
|
78
|
+
if (!g.process) {
|
|
72
79
|
g.process = nodeShapedProcess(process);
|
|
80
|
+
}
|
|
73
81
|
if (!g.performance) {
|
|
74
82
|
const origin = Date.now();
|
|
75
83
|
g.performance = { now: () => Date.now() - origin, timeOrigin: origin };
|
|
@@ -82,17 +90,20 @@ const silentStdio = {
|
|
|
82
90
|
};
|
|
83
91
|
export function pyodideLoadOptions() {
|
|
84
92
|
const cacheDir = process.env.QVAC_PYODIDE_CACHE_DIR;
|
|
85
|
-
if (!cacheDir)
|
|
93
|
+
if (!cacheDir) {
|
|
86
94
|
return { ...silentStdio };
|
|
95
|
+
}
|
|
87
96
|
return { ...silentStdio, packageCacheDir: cacheDir };
|
|
88
97
|
}
|
|
89
98
|
export const defaultLoad = async () => {
|
|
90
|
-
if (typeof globalThis.Bare !== 'undefined')
|
|
99
|
+
if (typeof globalThis.Bare !== 'undefined') {
|
|
91
100
|
await shapeBareGlobals();
|
|
101
|
+
}
|
|
92
102
|
const moduleName = 'pyodide';
|
|
93
|
-
const { loadPyodide } =
|
|
103
|
+
const { loadPyodide } = await import(__rewriteRelativeImportExtension(moduleName));
|
|
94
104
|
const options = pyodideLoadOptions();
|
|
95
|
-
if (options.packageCacheDir)
|
|
105
|
+
if (options.packageCacheDir) {
|
|
96
106
|
seedPackageCache(options.packageCacheDir);
|
|
107
|
+
}
|
|
97
108
|
return (await loadPyodide(options));
|
|
98
109
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
interface Fs {
|
|
2
2
|
mkdirTree(path: string): void;
|
|
3
3
|
chdir(path: string): void;
|
|
4
4
|
writeFile(path: string, data: Uint8Array): void;
|
|
@@ -20,28 +20,30 @@ type Fs = {
|
|
|
20
20
|
isLink(mode: number): boolean;
|
|
21
21
|
unlink(path: string): void;
|
|
22
22
|
rmdir(path: string): void;
|
|
23
|
-
}
|
|
24
|
-
|
|
23
|
+
}
|
|
24
|
+
interface CwdFs extends Fs {
|
|
25
|
+
cwd(): string;
|
|
26
|
+
}
|
|
27
|
+
export interface Scratch {
|
|
25
28
|
readonly dir: string;
|
|
26
29
|
readonly cwd: string;
|
|
27
30
|
[Symbol.dispose](): void;
|
|
28
|
-
}
|
|
29
|
-
|
|
31
|
+
}
|
|
32
|
+
interface InputFile {
|
|
30
33
|
readonly path: string;
|
|
31
34
|
readonly bytes: Uint8Array;
|
|
32
|
-
}
|
|
35
|
+
}
|
|
33
36
|
export declare function nextScratchDir(fs: Pick<Fs, 'analyzePath'>): string;
|
|
34
37
|
export declare function stageInputFiles(fs: Fs, dir: string, inputs: readonly InputFile[]): void;
|
|
35
|
-
export
|
|
38
|
+
export interface CollectedOutputs {
|
|
36
39
|
files: Map<string, Uint8Array>;
|
|
37
40
|
missing: string[];
|
|
38
41
|
rejected: {
|
|
39
42
|
name: string;
|
|
40
43
|
reason: string;
|
|
41
44
|
}[];
|
|
42
|
-
}
|
|
45
|
+
}
|
|
46
|
+
export declare function collectOutputs(fs: Fs, dir: string, names: readonly string[]): CollectedOutputs;
|
|
43
47
|
export declare function removeScratch(fs: Fs, dir: string, previousCwd: string): void;
|
|
44
|
-
export declare function openScratch(fs:
|
|
45
|
-
cwd(): string;
|
|
46
|
-
}, workdir?: string): Scratch;
|
|
48
|
+
export declare function openScratch(fs: CwdFs, workdir?: string): Scratch;
|
|
47
49
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage } from '../../../../guards.js';
|
|
1
2
|
import { hlog } from '../../../../log.js';
|
|
2
3
|
import { MAX_OUTPUT_FILE_BYTES, MAX_OUTPUT_TOTAL_BYTES } from './output-policy.js';
|
|
3
4
|
let runCounter = 0;
|
|
@@ -6,14 +7,16 @@ function filePath(dir, name) {
|
|
|
6
7
|
}
|
|
7
8
|
export function nextScratchDir(fs) {
|
|
8
9
|
let candidate = `/tmp/qvac-exec-${++runCounter}`;
|
|
9
|
-
while (fs.analyzePath(candidate).exists)
|
|
10
|
+
while (fs.analyzePath(candidate).exists) {
|
|
10
11
|
candidate = `/tmp/qvac-exec-${++runCounter}`;
|
|
12
|
+
}
|
|
11
13
|
return candidate;
|
|
12
14
|
}
|
|
13
15
|
export function stageInputFiles(fs, dir, inputs) {
|
|
14
16
|
fs.mkdirTree(dir);
|
|
15
|
-
for (const input of inputs)
|
|
17
|
+
for (const input of inputs) {
|
|
16
18
|
fs.writeFile(filePath(dir, input.path), input.bytes);
|
|
19
|
+
}
|
|
17
20
|
}
|
|
18
21
|
function isRegularFile(fs, path) {
|
|
19
22
|
const mode = fs.lstat(path).mode;
|
|
@@ -51,10 +54,12 @@ function removeTree(fs, dir) {
|
|
|
51
54
|
continue;
|
|
52
55
|
const path = filePath(dir, name);
|
|
53
56
|
const mode = fs.lstat(path).mode;
|
|
54
|
-
if (fs.isDir(mode) && !fs.isLink(mode))
|
|
57
|
+
if (fs.isDir(mode) && !fs.isLink(mode)) {
|
|
55
58
|
removeTree(fs, path);
|
|
56
|
-
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
57
61
|
fs.unlink(path);
|
|
62
|
+
}
|
|
58
63
|
}
|
|
59
64
|
fs.rmdir(dir);
|
|
60
65
|
}
|
|
@@ -66,7 +71,7 @@ export function removeScratch(fs, dir, previousCwd) {
|
|
|
66
71
|
catch (error) {
|
|
67
72
|
hlog('python: scratch cleanup failed', {
|
|
68
73
|
dir,
|
|
69
|
-
err:
|
|
74
|
+
err: errorMessage(error)
|
|
70
75
|
});
|
|
71
76
|
}
|
|
72
77
|
}
|