@qvac/harness 0.4.0 → 0.6.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.
Files changed (299) hide show
  1. package/CHANGELOG.md +740 -141
  2. package/README.md +75 -7
  3. package/dist/harness.bundle +72 -50
  4. package/dist-lib/index.d.ts +49 -39
  5. package/dist-lib/index.js +448 -161
  6. package/dist-lib/lib/audio-transcode-bare.d.ts +2 -2
  7. package/dist-lib/lib/audio-transcode-bare.js +28 -18
  8. package/dist-lib/lib/audio-transcode-node.d.ts +2 -2
  9. package/dist-lib/lib/capabilities/audio-resample.d.ts +7 -6
  10. package/dist-lib/lib/capabilities/audio-resample.js +30 -18
  11. package/dist-lib/lib/capabilities/completion.d.ts +20 -19
  12. package/dist-lib/lib/capabilities/completion.js +193 -132
  13. package/dist-lib/lib/capabilities/download.d.ts +6 -6
  14. package/dist-lib/lib/capabilities/download.js +15 -8
  15. package/dist-lib/lib/capabilities/embed.js +2 -1
  16. package/dist-lib/lib/capabilities/enhance.d.ts +6 -1
  17. package/dist-lib/lib/capabilities/enhance.js +7 -4
  18. package/dist-lib/lib/capabilities/invoke.js +7 -4
  19. package/dist-lib/lib/capabilities/kv-cache.js +2 -1
  20. package/dist-lib/lib/capabilities/preview-model-source.d.ts +9 -7
  21. package/dist-lib/lib/capabilities/preview-model-source.js +80 -28
  22. package/dist-lib/lib/capabilities/speech-text.js +5 -4
  23. package/dist-lib/lib/capabilities/tool-selection.js +10 -9
  24. package/dist-lib/lib/capabilities/tool-turns.js +30 -16
  25. package/dist-lib/lib/capabilities/usage-breakdown.js +2 -1
  26. package/dist-lib/lib/capabilities/voice.d.ts +5 -1
  27. package/dist-lib/lib/capabilities/voice.js +22 -12
  28. package/dist-lib/lib/connect.d.ts +13 -32
  29. package/dist-lib/lib/connect.js +170 -112
  30. package/dist-lib/lib/context-window.js +25 -21
  31. package/dist-lib/lib/contract-types.d.ts +35 -15
  32. package/dist-lib/lib/diagram-repair.d.ts +4 -4
  33. package/dist-lib/lib/diagram-repair.js +6 -3
  34. package/dist-lib/lib/docx/index.d.ts +3 -2
  35. package/dist-lib/lib/{error-fields.d.ts → guards.d.ts} +1 -0
  36. package/dist-lib/lib/{error-fields.js → guards.js} +3 -0
  37. package/dist-lib/lib/hardware/capability-probe.js +20 -10
  38. package/dist-lib/lib/hardware/gpu-classify.js +6 -3
  39. package/dist-lib/lib/hardware/gpu-probe-addon.js +8 -4
  40. package/dist-lib/lib/hardware/gpu-probe.js +4 -2
  41. package/dist-lib/lib/hardware/gpu-stats.native.cjs +8 -9
  42. package/dist-lib/lib/hardware/parsers.js +8 -4
  43. package/dist-lib/lib/helpers/buffer-burst.js +4 -2
  44. package/dist-lib/lib/helpers/control-tokens.js +4 -2
  45. package/dist-lib/lib/helpers/join-guard.d.ts +2 -2
  46. package/dist-lib/lib/helpers/join-guard.js +4 -2
  47. package/dist-lib/lib/helpers/load-stall.js +4 -2
  48. package/dist-lib/lib/helpers/markup-stream-filter.d.ts +2 -2
  49. package/dist-lib/lib/helpers/markup-stream-filter.js +6 -3
  50. package/dist-lib/lib/helpers/race-abort.js +2 -1
  51. package/dist-lib/lib/helpers/race-timeout.d.ts +5 -0
  52. package/dist-lib/lib/helpers/race-timeout.js +14 -0
  53. package/dist-lib/lib/helpers/run-outcome.d.ts +6 -8
  54. package/dist-lib/lib/helpers/run-outcome.js +36 -20
  55. package/dist-lib/lib/helpers/spawn-path.js +6 -3
  56. package/dist-lib/lib/helpers/text-coalescer.js +6 -3
  57. package/dist-lib/lib/helpers/thinking.js +38 -45
  58. package/dist-lib/lib/helpers/tool-call-markup.d.ts +9 -7
  59. package/dist-lib/lib/helpers/tool-call-markup.js +36 -20
  60. package/dist-lib/lib/helpers/tool-intent.d.ts +3 -2
  61. package/dist-lib/lib/helpers/tool-intent.js +4 -2
  62. package/dist-lib/lib/helpers/tool-label.js +18 -9
  63. package/dist-lib/lib/hooks/built-in/arg-repair.js +23 -13
  64. package/dist-lib/lib/hooks/built-in/egress.js +2 -1
  65. package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
  66. package/dist-lib/lib/hooks/pipeline.d.ts +5 -4
  67. package/dist-lib/lib/hooks/pipeline.js +6 -3
  68. package/dist-lib/lib/hooks/run.js +12 -8
  69. package/dist-lib/lib/model-download-progress.js +10 -8
  70. package/dist-lib/lib/models/context.d.ts +1 -1
  71. package/dist-lib/lib/models/context.js +5 -1
  72. package/dist-lib/lib/models/custom-model-cache.d.ts +10 -1
  73. package/dist-lib/lib/models/custom-model-cache.js +43 -15
  74. package/dist-lib/lib/models/gguf-header.d.ts +3 -2
  75. package/dist-lib/lib/models/gguf-header.js +44 -22
  76. package/dist-lib/lib/models/idle-unload.d.ts +14 -0
  77. package/dist-lib/lib/models/idle-unload.js +51 -0
  78. package/dist-lib/lib/models/kv-cache.d.ts +3 -2
  79. package/dist-lib/lib/models/kv-cache.js +4 -3
  80. package/dist-lib/lib/models/llm-presets.d.ts +2 -2
  81. package/dist-lib/lib/models/llm-presets.js +4 -2
  82. package/dist-lib/lib/models/model-catalog-constants.js +3 -2
  83. package/dist-lib/lib/models/model-catalog.d.ts +15 -20
  84. package/dist-lib/lib/models/model-catalog.js +66 -31
  85. package/dist-lib/lib/models/model-delete.js +18 -8
  86. package/dist-lib/lib/models/model-handle.js +2 -1
  87. package/dist-lib/lib/models/model-list.d.ts +8 -3
  88. package/dist-lib/lib/models/model-list.js +11 -6
  89. package/dist-lib/lib/models/model-pool.d.ts +48 -10
  90. package/dist-lib/lib/models/model-pool.js +106 -45
  91. package/dist-lib/lib/models/model-source.js +10 -5
  92. package/dist-lib/lib/models/music-catalog.d.ts +2 -2
  93. package/dist-lib/lib/models/nmt-catalog.d.ts +4 -3
  94. package/dist-lib/lib/models/nmt-catalog.js +10 -5
  95. package/dist-lib/lib/models/opencl-cache.d.ts +6 -1
  96. package/dist-lib/lib/models/opencl-cache.js +5 -3
  97. package/dist-lib/lib/models/sdk-faults.d.ts +11 -8
  98. package/dist-lib/lib/models/sdk-faults.js +9 -6
  99. package/dist-lib/lib/models/shards.d.ts +11 -0
  100. package/dist-lib/lib/models/shards.js +15 -0
  101. package/dist-lib/lib/models/tool-dialect.js +10 -5
  102. package/dist-lib/lib/no-redirect-fetch-bare.d.ts +3 -3
  103. package/dist-lib/lib/no-redirect-fetch-bare.js +1 -1
  104. package/dist-lib/lib/no-redirect-fetch-impl.js +6 -3
  105. package/dist-lib/lib/no-redirect-fetch-node.d.ts +1 -1
  106. package/dist-lib/lib/no-redirect-fetch-node.js +9 -9
  107. package/dist-lib/lib/office/index.d.ts +3 -2
  108. package/dist-lib/lib/office/python.d.ts +3 -2
  109. package/dist-lib/lib/office/python.js +2 -1
  110. package/dist-lib/lib/prompt.d.ts +5 -4
  111. package/dist-lib/lib/prompt.js +8 -4
  112. package/dist-lib/lib/queue.js +10 -5
  113. package/dist-lib/lib/resolution-detector.js +21 -11
  114. package/dist-lib/lib/rpc-session.js +2 -1
  115. package/dist-lib/lib/sdk-loader.js +2 -1
  116. package/dist-lib/lib/sdk-storage.js +4 -2
  117. package/dist-lib/lib/serve.js +122 -66
  118. package/dist-lib/lib/spawn.js +7 -4
  119. package/dist-lib/lib/tmp-path.d.ts +7 -6
  120. package/dist-lib/lib/tool-call-display.d.ts +2 -2
  121. package/dist-lib/lib/tools/create-documents.js +18 -10
  122. package/dist-lib/lib/tools/edit-documents.js +23 -13
  123. package/dist-lib/lib/tools/edit-image.d.ts +2 -2
  124. package/dist-lib/lib/tools/edit-image.js +60 -36
  125. package/dist-lib/lib/tools/exec/adapters/adapter.d.ts +10 -10
  126. package/dist-lib/lib/tools/exec/adapters/python/attachments.d.ts +17 -11
  127. package/dist-lib/lib/tools/exec/adapters/python/attachments.js +53 -40
  128. package/dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts +2 -2
  129. package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +60 -32
  130. package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.d.ts +33 -22
  131. package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.js +58 -29
  132. package/dist-lib/lib/tools/exec/adapters/python/interrupt-timer.d.ts +2 -2
  133. package/dist-lib/lib/tools/exec/adapters/python/loader.js +23 -12
  134. package/dist-lib/lib/tools/exec/adapters/python/memfs.d.ts +13 -11
  135. package/dist-lib/lib/tools/exec/adapters/python/memfs.js +10 -5
  136. package/dist-lib/lib/tools/exec/adapters/python/net-shim.js +3 -1
  137. package/dist-lib/lib/tools/exec/adapters/python/output-policy.d.ts +6 -4
  138. package/dist-lib/lib/tools/exec/adapters/python/output-policy.js +20 -10
  139. package/dist-lib/lib/tools/exec/adapters/python/pyodide.d.ts +2 -2
  140. package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +14 -7
  141. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +41 -34
  142. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +316 -166
  143. package/dist-lib/lib/tools/exec/adapters/python/run-session.d.ts +9 -8
  144. package/dist-lib/lib/tools/exec/adapters/python/run-session.js +56 -28
  145. package/dist-lib/lib/tools/exec/adapters/python/wheels.d.ts +8 -10
  146. package/dist-lib/lib/tools/exec/adapters/python/wheels.js +22 -11
  147. package/dist-lib/lib/tools/exec/adapters/python/worker/client.d.ts +3 -2
  148. package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +41 -26
  149. package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +27 -18
  150. package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.d.ts +2 -2
  151. package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.js +14 -13
  152. package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.d.ts +4 -4
  153. package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.js +10 -5
  154. package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.d.ts +4 -4
  155. package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.js +2 -1
  156. package/dist-lib/lib/tools/exec/obsidian/cli-process.d.ts +6 -1
  157. package/dist-lib/lib/tools/exec/obsidian/cli-process.js +8 -5
  158. package/dist-lib/lib/tools/exec/obsidian/cli.d.ts +6 -6
  159. package/dist-lib/lib/tools/exec/obsidian/cli.js +4 -4
  160. package/dist-lib/lib/tools/exec/obsidian/command.d.ts +3 -2
  161. package/dist-lib/lib/tools/exec/obsidian/command.js +6 -3
  162. package/dist-lib/lib/tools/exec/obsidian/output.js +2 -1
  163. package/dist-lib/lib/tools/exec/obsidian/route.d.ts +4 -6
  164. package/dist-lib/lib/tools/exec/obsidian/route.js +17 -11
  165. package/dist-lib/lib/tools/exec/obsidian/safe-path.js +2 -1
  166. package/dist-lib/lib/tools/exec/obsidian/vault-create.js +15 -7
  167. package/dist-lib/lib/tools/exec/obsidian/vault-paths.d.ts +2 -2
  168. package/dist-lib/lib/tools/exec/obsidian/vault-paths.js +20 -10
  169. package/dist-lib/lib/tools/exec/obsidian/vault-read.js +20 -13
  170. package/dist-lib/lib/tools/exec/obsidian/vault-write.js +24 -12
  171. package/dist-lib/lib/tools/exec/runner.d.ts +14 -14
  172. package/dist-lib/lib/tools/exec/runner.js +5 -3
  173. package/dist-lib/lib/tools/exec/scope.js +52 -28
  174. package/dist-lib/lib/tools/exec/shell-argv.js +31 -18
  175. package/dist-lib/lib/tools/exec/shell-guidance.d.ts +6 -1
  176. package/dist-lib/lib/tools/exec/shell-guidance.js +35 -20
  177. package/dist-lib/lib/tools/exec/video-tools.js +2 -2
  178. package/dist-lib/lib/tools/exec.d.ts +6 -8
  179. package/dist-lib/lib/tools/exec.js +113 -54
  180. package/dist-lib/lib/tools/file-glob.d.ts +4 -5
  181. package/dist-lib/lib/tools/file-glob.js +16 -11
  182. package/dist-lib/lib/tools/fs/glob.js +13 -18
  183. package/dist-lib/lib/tools/fs/remote-protocol.d.ts +10 -10
  184. package/dist-lib/lib/tools/fs/remote.d.ts +3 -2
  185. package/dist-lib/lib/tools/fs/remote.js +13 -7
  186. package/dist-lib/lib/tools/fs/scope.d.ts +8 -3
  187. package/dist-lib/lib/tools/fs/scope.js +20 -12
  188. package/dist-lib/lib/tools/fs/walk.js +6 -3
  189. package/dist-lib/lib/tools/fs/write.d.ts +3 -2
  190. package/dist-lib/lib/tools/generate-image.d.ts +11 -9
  191. package/dist-lib/lib/tools/generate-image.js +73 -37
  192. package/dist-lib/lib/tools/generate-music.d.ts +22 -11
  193. package/dist-lib/lib/tools/generate-music.js +79 -48
  194. package/dist-lib/lib/tools/grep.js +66 -41
  195. package/dist-lib/lib/tools/http-request/encode-fields.js +18 -9
  196. package/dist-lib/lib/tools/http-request/{utils.js → request.js} +20 -11
  197. package/dist-lib/lib/tools/http-request/truncate-response.js +57 -46
  198. package/dist-lib/lib/tools/http-request.d.ts +1 -1
  199. package/dist-lib/lib/tools/http-request.js +33 -18
  200. package/dist-lib/lib/tools/mcp/protocol.d.ts +53 -0
  201. package/dist-lib/lib/tools/mcp/{utils.js → protocol.js} +45 -23
  202. package/dist-lib/lib/tools/mcp-call.d.ts +1 -1
  203. package/dist-lib/lib/tools/mcp-call.js +37 -16
  204. package/dist-lib/lib/tools/operations/builders.js +10 -6
  205. package/dist-lib/lib/tools/operations/compile.js +20 -10
  206. package/dist-lib/lib/tools/operations/decoders.js +12 -6
  207. package/dist-lib/lib/tools/operations/gmail-message.js +3 -2
  208. package/dist-lib/lib/tools/outbound-guard.d.ts +4 -3
  209. package/dist-lib/lib/tools/outbound-guard.js +14 -8
  210. package/dist-lib/lib/tools/private-ip.js +8 -7
  211. package/dist-lib/lib/tools/rag-search.js +14 -7
  212. package/dist-lib/lib/tools/read-files.js +23 -20
  213. package/dist-lib/lib/tools/skill.js +19 -10
  214. package/dist-lib/lib/tools/skills/auth-resolver.d.ts +11 -18
  215. package/dist-lib/lib/tools/skills/auth-resolver.js +30 -18
  216. package/dist-lib/lib/tools/skills/bin-check.d.ts +3 -2
  217. package/dist-lib/lib/tools/skills/bin-check.js +10 -3
  218. package/dist-lib/lib/tools/skills/bundled-dir.js +20 -10
  219. package/dist-lib/lib/tools/skills/bundled-hash.d.ts +3 -2
  220. package/dist-lib/lib/tools/skills/bundled-hash.js +6 -1
  221. package/dist-lib/lib/tools/skills/catalog.d.ts +3 -2
  222. package/dist-lib/lib/tools/skills/catalog.js +33 -28
  223. package/dist-lib/lib/tools/skills/cli-argv.d.ts +3 -2
  224. package/dist-lib/lib/tools/skills/cli-argv.js +55 -52
  225. package/dist-lib/lib/tools/skills/cli-schema-check.js +21 -10
  226. package/dist-lib/lib/tools/skills/cli-schema-load.js +28 -20
  227. package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +6 -6
  228. package/dist-lib/lib/tools/skills/cli-schema.js +2 -1
  229. package/dist-lib/lib/tools/skills/credential-check.d.ts +6 -3
  230. package/dist-lib/lib/tools/skills/credential-check.js +24 -12
  231. package/dist-lib/lib/tools/skills/credential-grants.js +1 -6
  232. package/dist-lib/lib/tools/skills/credential-health.d.ts +5 -1
  233. package/dist-lib/lib/tools/skills/credential-health.js +5 -3
  234. package/dist-lib/lib/tools/skills/frontmatter-parser.js +10 -5
  235. package/dist-lib/lib/tools/skills/manifest-parse.js +84 -64
  236. package/dist-lib/lib/tools/skills/mention.js +7 -6
  237. package/dist-lib/lib/tools/skills/obsidian-readiness.d.ts +2 -2
  238. package/dist-lib/lib/tools/skills/obsidian-readiness.js +11 -3
  239. package/dist-lib/lib/tools/skills/overlay-crud.d.ts +6 -4
  240. package/dist-lib/lib/tools/skills/overlay-crud.js +12 -6
  241. package/dist-lib/lib/tools/skills/overlay-dir.js +4 -2
  242. package/dist-lib/lib/tools/skills/overlay-watch.d.ts +3 -2
  243. package/dist-lib/lib/tools/skills/overlay-watch.js +8 -4
  244. package/dist-lib/lib/tools/skills/setup-routes.js +1 -3
  245. package/dist-lib/lib/tools/skills/skill-settings.js +4 -1
  246. package/dist-lib/lib/tools/skills/skill-state.d.ts +6 -11
  247. package/dist-lib/lib/tools/skills/skill-state.js +48 -29
  248. package/dist-lib/lib/tools/skills/tool-grants.js +6 -3
  249. package/dist-lib/lib/tools/toolsets.js +2 -1
  250. package/dist-lib/lib/tools/translate.d.ts +4 -5
  251. package/dist-lib/lib/tools/translate.js +31 -14
  252. package/dist-lib/lib/tools/url-guard.js +2 -1
  253. package/dist-lib/lib/tools/weather-lookup/place.js +8 -4
  254. package/dist-lib/lib/tools/weather-lookup/report.d.ts +7 -1
  255. package/dist-lib/lib/tools/weather-lookup/report.js +46 -9
  256. package/dist-lib/lib/tools/weather-lookup.js +18 -12
  257. package/dist-lib/lib/tools/web-fetch.js +47 -24
  258. package/dist-lib/lib/tools/web-search.js +8 -3
  259. package/dist-lib/lib/validating-lookup.d.ts +4 -4
  260. package/dist-lib/lib/wav-encode.d.ts +1 -1
  261. package/dist-lib/lib/wav-encode.js +11 -10
  262. package/dist-lib/lib/web-fetch/embedded-state.js +24 -12
  263. package/dist-lib/lib/web-fetch/extract.js +4 -2
  264. package/dist-lib/lib/web-fetch/images.js +8 -4
  265. package/dist-lib/lib/web-fetch/video.d.ts +2 -2
  266. package/dist-lib/lib/web-fetch/video.js +8 -4
  267. package/dist-lib/lib/web-search/engine-registry.d.ts +2 -2
  268. package/dist-lib/lib/web-search/engines/aol.js +1 -1
  269. package/dist-lib/lib/web-search/engines/bing.js +1 -1
  270. package/dist-lib/lib/web-search/engines/brave.js +4 -1
  271. package/dist-lib/lib/web-search/engines/duckduckgo.js +3 -2
  272. package/dist-lib/lib/web-search/engines/google.js +7 -3
  273. package/dist-lib/lib/web-search/engines/wikipedia.js +5 -4
  274. package/dist-lib/lib/web-search/engines/yahoo.js +1 -1
  275. package/dist-lib/lib/web-search/fetch-html.d.ts +5 -4
  276. package/dist-lib/lib/web-search/fetch-html.js +13 -7
  277. package/dist-lib/lib/web-search/orchestrator.d.ts +9 -5
  278. package/dist-lib/lib/web-search/orchestrator.js +3 -3
  279. package/dist-lib/lib/wire.d.ts +3 -2
  280. package/dist-lib/lib/wire.js +23 -15
  281. package/dist-lib/schema/baseline.js +10 -5
  282. package/dist-lib/schema/build.js +2 -1
  283. package/dist-lib/schema/harness.d.ts +15 -2
  284. package/dist-lib/schema/harness.js +39 -2
  285. package/dist-lib/schema/release-tags.d.ts +3 -2
  286. package/dist-lib/schema/release-tags.js +6 -3
  287. package/dist-lib/spec/bind.js +9 -0
  288. package/dist-lib/spec/calls.js +3 -0
  289. package/dist-lib/spec/hrpc/hrpc.json +39 -0
  290. package/dist-lib/spec/hrpc/index.js +39 -3
  291. package/dist-lib/spec/hrpc/messages.js +105 -8
  292. package/dist-lib/spec/hyperschema/index.js +105 -8
  293. package/dist-lib/spec/hyperschema/schema.json +77 -1
  294. package/dist-lib/spec/hyperschema/types.d.ts +25 -1
  295. package/package.json +14 -14
  296. package/worker/harness-sidecar.mjs +15 -22
  297. package/worker/stow-entry.mjs +7 -4
  298. package/dist-lib/lib/tools/mcp/utils.d.ts +0 -47
  299. /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 = source.startsWith('"""', i) ? '"""' : source.startsWith("'''", i) ? "'''" : null;
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
- else
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
- if (halves.text.includes('__'))
230
+ }
231
+ if (halves.text.includes('__')) {
223
232
  return 'write';
224
- if (/\\(?:x[0-9A-Fa-f]|u[0-9A-Fa-f]|U[0-9A-Fa-f]|N\{|[0-7])/.test(halves.text))
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
- if (/[^\x20-\x7e\t\r\n\f]/.test(halves.code))
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
- if (BUILDER_ROOTS.has(root))
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
- if (PYTHON_BUILTINS.has(token) && !ALLOWED_BUILTINS.has(token))
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
- if (!outputs.every((name) => ARTIFACT_OUTPUT.test(name)))
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
- if (CREATE_PACKAGES.get(name) !== (match[2] ?? null))
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
- if ((inputs ?? []).some((input) => !IMAGE_INPUT.test(input.path)))
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 type ConnectPolicy = {
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
- type SignalLike = {
12
+ interface SignalLike {
13
13
  readonly aborted: boolean;
14
14
  addEventListener(type: 'abort', listener: () => void): void;
15
- };
16
- type FetchInit = {
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 type GuardedFetchOptions = {
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(status: number, headers: [string, string][], bytes: Uint8Array, url: string, redirected: boolean);
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
- export declare function createGuardedFetch(options?: GuardedFetchOptions): ((input: string | URL | {
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 defaultFetch from '#no-redirect-fetch';
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
- const pairs = Array.isArray(headers)
37
- ? headers
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
- if (ArrayBuffer.isView(body))
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, bytes, url, redirected) {
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
- const { buffer, byteOffset, byteLength } = this.#bytes;
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.status, [...this.headers.entries()], this.#bytes, this.url, this.redirected);
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 ?? defaultFetch;
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(response.status, response.headers.entries(), plain(response.bytes()), url.href, hops > 0);
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
- if (hops >= MAX_REDIRECTS)
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
- for (const name of Object.keys(headers)) {
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() { }
@@ -1,5 +1,5 @@
1
- export type InterruptTimer = {
1
+ export interface InterruptTimer {
2
2
  readonly interrupt: Uint8Array;
3
3
  disarm(): boolean;
4
- };
4
+ }
5
5
  export declare function startInterruptTimer(ms: number): InterruptTimer;
@@ -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
- else if (/latin1|iso-8859|ascii/.test(normalized))
20
+ }
21
+ else if (/latin1|iso-8859|ascii/.test(normalized)) {
21
22
  this.encoding = 'latin1';
22
- else
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
- if (!g.TextEncoder)
74
+ }
75
+ if (!g.TextEncoder) {
70
76
  g.TextEncoder = B4aTextEncoder;
71
- if (!g.process)
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 } = (await import(__rewriteRelativeImportExtension(moduleName)));
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
- type Fs = {
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
- export type Scratch = {
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
- type InputFile = {
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 declare function collectOutputs(fs: Fs, dir: string, names: readonly string[]): {
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: 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
- else
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: error instanceof Error ? error.message : String(error)
74
+ err: errorMessage(error)
70
75
  });
71
76
  }
72
77
  }