@jerryan/just-bash 3.6.0 → 3.6.1

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 (76) hide show
  1. package/CHANGELOG.md +334 -316
  2. package/LICENSE +201 -201
  3. package/README.md +827 -827
  4. package/dist/agent-sandbox.d.ts +5 -0
  5. package/dist/bin/{shell/chunks/chunk-7WBCA2BB.js → chunks/chunk-3DWQCLNP.js} +1 -1
  6. package/dist/bin/{shell/chunks/chunk-QFTZKD5O.js → chunks/chunk-6TUILMPB.js} +1 -1
  7. package/dist/bin/chunks/chunk-JHEAT7AR.js +12 -0
  8. package/dist/bin/{shell/chunks/chunk-MF3GVFLC.js → chunks/chunk-L345YZ6R.js} +1 -1
  9. package/dist/bin/chunks/chunk-QKJAAJ7J.js +3 -0
  10. package/dist/bin/chunks/{chunk-6LDOIBU7.js → chunk-SE7JHGP3.js} +6 -6
  11. package/dist/bin/chunks/{chunk-NLU5LALY.js → chunk-YCOJCFGU.js} +1 -1
  12. package/dist/bin/{shell/chunks/flag-coverage-C7PB2MO7.js → chunks/flag-coverage-FYJ2V7J4.js} +1 -1
  13. package/dist/bin/{shell/chunks/js-exec-DJQLXWCS.js → chunks/js-exec-5QZZCOR7.js} +7 -7
  14. package/dist/bin/chunks/js-exec-worker.js +155 -33
  15. package/dist/bin/{shell/chunks/python3-JCJHSX4Z.js → chunks/python3-TMFYDQAP.js} +1 -1
  16. package/dist/bin/chunks/{rm-TF2NJQIA.js → rm-NLG5344W.js} +1 -1
  17. package/dist/bin/chunks/{sleep-DVFE2GSF.js → sleep-MOJQBZMY.js} +1 -1
  18. package/dist/bin/{shell/chunks/sqlite3-KP42NNIY.js → chunks/sqlite3-3EUPHVEZ.js} +1 -1
  19. package/dist/bin/chunks/{timeout-YGFHQJKX.js → timeout-RQOWSWYG.js} +1 -1
  20. package/dist/bin/chunks/worker.js +162 -48
  21. package/dist/bin/just-bash.js +241 -241
  22. package/dist/bin/{chunks/chunk-7WBCA2BB.js → shell/chunks/chunk-3DWQCLNP.js} +1 -1
  23. package/dist/bin/{chunks/chunk-QFTZKD5O.js → shell/chunks/chunk-6TUILMPB.js} +1 -1
  24. package/dist/bin/shell/chunks/chunk-JHEAT7AR.js +12 -0
  25. package/dist/bin/{chunks/chunk-MF3GVFLC.js → shell/chunks/chunk-L345YZ6R.js} +1 -1
  26. package/dist/bin/shell/chunks/chunk-QKJAAJ7J.js +3 -0
  27. package/dist/bin/shell/chunks/{chunk-6LDOIBU7.js → chunk-SE7JHGP3.js} +6 -6
  28. package/dist/bin/shell/chunks/{chunk-NLU5LALY.js → chunk-YCOJCFGU.js} +1 -1
  29. package/dist/bin/{chunks/flag-coverage-C7PB2MO7.js → shell/chunks/flag-coverage-FYJ2V7J4.js} +1 -1
  30. package/dist/bin/{chunks/js-exec-DJQLXWCS.js → shell/chunks/js-exec-5QZZCOR7.js} +7 -7
  31. package/dist/bin/{chunks/python3-JCJHSX4Z.js → shell/chunks/python3-TMFYDQAP.js} +1 -1
  32. package/dist/bin/shell/chunks/{rm-TF2NJQIA.js → rm-NLG5344W.js} +1 -1
  33. package/dist/bin/shell/chunks/{sleep-DVFE2GSF.js → sleep-MOJQBZMY.js} +1 -1
  34. package/dist/bin/{chunks/sqlite3-KP42NNIY.js → shell/chunks/sqlite3-3EUPHVEZ.js} +1 -1
  35. package/dist/bin/shell/chunks/{timeout-YGFHQJKX.js → timeout-RQOWSWYG.js} +1 -1
  36. package/dist/bin/shell/shell.js +3 -3
  37. package/dist/bundle/browser.js +2 -2
  38. package/dist/bundle/chunks/{chunk-N3A4JVFJ.js → chunk-6IA4DXG2.js} +1 -1
  39. package/dist/bundle/chunks/{chunk-PIRTX3D3.js → chunk-G3IRZ4FN.js} +6 -6
  40. package/dist/bundle/chunks/{chunk-24NLAR7R.js → chunk-KEMO3CBM.js} +1 -1
  41. package/dist/bundle/chunks/chunk-PS2RJNZZ.js +2 -0
  42. package/dist/bundle/chunks/{chunk-DMWNBCXJ.js → chunk-TLPMB3FO.js} +1 -1
  43. package/dist/bundle/chunks/chunk-ULXGGWAD.js +11 -0
  44. package/dist/bundle/chunks/{chunk-XV2V56NQ.js → chunk-YFFU74KY.js} +1 -1
  45. package/dist/bundle/chunks/{flag-coverage-XTIQGK65.js → flag-coverage-XSPWRCVG.js} +1 -1
  46. package/dist/bundle/chunks/{js-exec-XKF2B7C3.js → js-exec-57QMXJG5.js} +7 -7
  47. package/dist/bundle/chunks/js-exec-worker.js +155 -33
  48. package/dist/bundle/chunks/{python3-F5S5TYGS.js → python3-NNONJINM.js} +1 -1
  49. package/dist/bundle/chunks/{rm-OAZOF7XI.js → rm-R2ZENNSN.js} +1 -1
  50. package/dist/bundle/chunks/{sleep-PPRBTSVR.js → sleep-25QUPVDK.js} +1 -1
  51. package/dist/bundle/chunks/{sqlite3-4EZ4GXVD.js → sqlite3-M4UZPXDO.js} +1 -1
  52. package/dist/bundle/chunks/{timeout-C6WDYPLV.js → timeout-37GM7IIL.js} +1 -1
  53. package/dist/bundle/chunks/worker.js +162 -48
  54. package/dist/bundle/index.cjs +751 -751
  55. package/dist/bundle/index.js +298 -298
  56. package/dist/commands/js-exec/js-exec.d.ts +4 -0
  57. package/dist/commands/worker-bridge/bridge-handler.d.ts +9 -0
  58. package/dist/commands/worker-bridge/protocol.d.ts +17 -0
  59. package/dist/commands/worker-bridge/sync-backend.d.ts +3 -0
  60. package/dist/fs/overlay-fs/apply.d.ts +13 -0
  61. package/dist/fs/overlay-fs/index.d.ts +2 -0
  62. package/dist/fs/overlay-fs/merge.d.ts +24 -0
  63. package/dist/fs/overlay-fs/overlay-fs.d.ts +17 -0
  64. package/dist/fs/overlay-fs/overlay-tree.d.ts +39 -0
  65. package/dist/fs/vfs-template.d.ts +51 -0
  66. package/dist/index.d.cts +2 -1
  67. package/dist/index.d.ts +2 -1
  68. package/dist/timers.d.ts +9 -0
  69. package/package.json +135 -136
  70. package/vendor/cpython-emscripten/python.cjs +2 -2
  71. package/dist/bin/chunks/chunk-JQM3DKCH.js +0 -12
  72. package/dist/bin/chunks/chunk-PPVF2N6C.js +0 -3
  73. package/dist/bin/shell/chunks/chunk-JQM3DKCH.js +0 -12
  74. package/dist/bin/shell/chunks/chunk-PPVF2N6C.js +0 -3
  75. package/dist/bundle/chunks/chunk-WXPNKIIH.js +0 -2
  76. package/dist/bundle/chunks/chunk-YJKHREBZ.js +0 -11
@@ -1690,6 +1690,16 @@ var OpCode = {
1690
1690
  REALPATH: 13,
1691
1691
  RENAME: 14,
1692
1692
  COPY_FILE: 15,
1693
+ // Ranged variant for write payloads larger than the data buffer.
1694
+ // FLAGS carries the file offset (uint32); the chunk length is its
1695
+ // DATA_LENGTH. (Reads use plain READ_FILE plus the generic
1696
+ // READ_RESULT_RANGE assembly; only the write direction needs this.)
1697
+ WRITE_FILE_RANGE: 17,
1698
+ // Fetch the next slice of an oversized result (any op). The host
1699
+ // publishes the first DATA_BUFFER bytes with the FULL length in
1700
+ // RESULT_LENGTH and retains the complete buffer; the worker loops
1701
+ // this op (FLAGS = offset, MODE = length) to assemble the rest.
1702
+ READ_RESULT_RANGE: 18,
1693
1703
  // Special operations for I/O
1694
1704
  WRITE_STDOUT: 100,
1695
1705
  WRITE_STDERR: 101,
@@ -1718,7 +1728,8 @@ var ErrorCode = {
1718
1728
  IO_ERROR: 7,
1719
1729
  TIMEOUT: 8,
1720
1730
  NETWORK_ERROR: 9,
1721
- NETWORK_NOT_CONFIGURED: 10
1731
+ NETWORK_NOT_CONFIGURED: 10,
1732
+ NOT_EMPTY: 11
1722
1733
  };
1723
1734
  var Offset = {
1724
1735
  OP_CODE: 0,
@@ -1736,9 +1747,10 @@ var Offset = {
1736
1747
  var Size = {
1737
1748
  CONTROL_REGION: 32,
1738
1749
  PATH_BUFFER: 4096,
1739
- // 8MB limit for FS read/write, HTTP responses, and tool invocation results.
1740
- // Sized to handle typical OpenAPI/GraphQL responses (paginated lists, batch queries).
1741
- // Still well under the 64MB QuickJS memory limit per execution.
1750
+ // 8MB transfer CHUNK size — not a semantic cap. Results larger than
1751
+ // this are assembled transparently (READ_RESULT_RANGE), and large
1752
+ // writes stream as WRITE_FILE_RANGE chunks. Sized to keep ordinary
1753
+ // ops single-transfer while bounding per-transfer copies.
1742
1754
  DATA_BUFFER: 8388608,
1743
1755
  TOTAL: 8392736
1744
1756
  // 32 + 4096 + 8MB
@@ -1870,6 +1882,20 @@ var ProtocolBuffer = class {
1870
1882
  this.uint8View.set(data, Offset.DATA_BUFFER);
1871
1883
  this.setResultLength(data.length);
1872
1884
  }
1885
+ /**
1886
+ * Publish a result of ANY size: the first DATA_BUFFER bytes land in
1887
+ * the data region and RESULT_LENGTH carries the FULL length. The
1888
+ * worker detects the overflow and fetches the rest with
1889
+ * READ_RESULT_RANGE ops (served from the host's retained buffer).
1890
+ */
1891
+ setResultPrefix(data) {
1892
+ if (data.length > 2147483647) {
1893
+ throw new Error(`Result too large: ${data.length} exceeds int32`);
1894
+ }
1895
+ const n = Math.min(data.length, Size.DATA_BUFFER);
1896
+ this.uint8View.set(data.subarray(0, n), Offset.DATA_BUFFER);
1897
+ this.setResultLength(data.length);
1898
+ }
1873
1899
  getResultAsString() {
1874
1900
  const result = this.getResult();
1875
1901
  return new TextDecoder().decode(result);
@@ -1999,50 +2025,113 @@ var SyncBackend = class {
1999
2025
  }
2000
2026
  this.protocol.setStatus(Status.READY);
2001
2027
  this.protocol.notify();
2002
- const waitResult = this.protocol.waitForResult(this.operationTimeoutMs);
2028
+ const deadline = Date.now() + this.operationTimeoutMs;
2029
+ let waitResult = this.protocol.waitForResult(this.operationTimeoutMs);
2030
+ while (waitResult !== "timed-out" && this.protocol.getStatus() === Status.READY) {
2031
+ const remaining = deadline - Date.now();
2032
+ if (remaining <= 0) {
2033
+ waitResult = "timed-out";
2034
+ break;
2035
+ }
2036
+ waitResult = this.protocol.waitForResult(remaining);
2037
+ }
2003
2038
  if (waitResult === "timed-out") {
2004
2039
  return { success: false, error: "Operation timed out" };
2005
2040
  }
2006
2041
  const status = this.protocol.getStatus();
2007
2042
  if (status === Status.SUCCESS) {
2008
- return { success: true, result: this.protocol.getResult() };
2043
+ const totalLength = this.protocol.getResultLength();
2044
+ if (totalLength <= Size.DATA_BUFFER) {
2045
+ return { success: true, result: this.protocol.getResult() };
2046
+ }
2047
+ const content = new Uint8Array(totalLength);
2048
+ content.set(this.protocol.getResult().subarray(0, Size.DATA_BUFFER), 0);
2049
+ let offset = Size.DATA_BUFFER;
2050
+ while (offset < totalLength) {
2051
+ const length = Math.min(Size.DATA_BUFFER, totalLength - offset);
2052
+ const slice = this.execSync(
2053
+ OpCode.READ_RESULT_RANGE,
2054
+ "",
2055
+ void 0,
2056
+ offset,
2057
+ length
2058
+ );
2059
+ if (!slice.success) {
2060
+ throw this.opError_("Failed to read result range", slice);
2061
+ }
2062
+ const chunk = slice.result ?? new Uint8Array(0);
2063
+ content.set(chunk, offset);
2064
+ offset += chunk.length;
2065
+ if (chunk.length === 0) {
2066
+ throw this.opError_("bridge returned an empty result slice", slice);
2067
+ }
2068
+ }
2069
+ return { success: true, result: content };
2009
2070
  }
2010
2071
  return {
2011
2072
  success: false,
2012
- error: this.protocol.getResultAsString() || `Error code: ${this.protocol.getErrorCode()}`
2073
+ error: this.protocol.getResultAsString() || // Impossible by construction: every host error path publishes a
2074
+ // code and message. If this ever fires, the diagnostic payload
2075
+ // must identify the exact protocol state.
2076
+ `bridge protocol violation: op ${opCode} woke with status ${status} (wait=${waitResult}, errorCode=${this.protocol.getErrorCode()})`,
2077
+ errorCode: this.protocol.getErrorCode()
2013
2078
  };
2014
2079
  }
2080
+ /** Build an op failure that preserves the bridge's numeric error code,
2081
+ * so downstream errno mapping prefers it over substring matching. */
2082
+ opError_(fallback, result) {
2083
+ const err = new Error(result.error || fallback);
2084
+ err.bridgeErrorCode = result.errorCode;
2085
+ return err;
2086
+ }
2015
2087
  readFile(path) {
2016
2088
  const result = this.execSync(OpCode.READ_FILE, path);
2017
2089
  if (!result.success) {
2018
- throw new Error(result.error || "Failed to read file");
2090
+ throw this.opError_("Failed to read file", result);
2019
2091
  }
2020
2092
  return result.result ?? new Uint8Array(0);
2021
2093
  }
2022
2094
  writeFile(path, data) {
2023
- const result = this.execSync(OpCode.WRITE_FILE, path, data);
2024
- if (!result.success) {
2025
- throw new Error(result.error || "Failed to write file");
2095
+ if (data.length <= Size.DATA_BUFFER) {
2096
+ const result = this.execSync(OpCode.WRITE_FILE, path, data);
2097
+ if (!result.success) {
2098
+ throw this.opError_("Failed to write file", result);
2099
+ }
2100
+ return;
2101
+ }
2102
+ let offset = 0;
2103
+ while (offset < data.length) {
2104
+ const chunk = data.subarray(offset, offset + Size.DATA_BUFFER);
2105
+ const result = this.execSync(
2106
+ OpCode.WRITE_FILE_RANGE,
2107
+ path,
2108
+ chunk,
2109
+ offset
2110
+ );
2111
+ if (!result.success) {
2112
+ throw this.opError_("Failed to write file", result);
2113
+ }
2114
+ offset += chunk.length;
2026
2115
  }
2027
2116
  }
2028
2117
  stat(path) {
2029
2118
  const result = this.execSync(OpCode.STAT, path);
2030
2119
  if (!result.success) {
2031
- throw new Error(result.error || "Failed to stat");
2120
+ throw this.opError_("Failed to stat", result);
2032
2121
  }
2033
2122
  return this.protocol.decodeStat();
2034
2123
  }
2035
2124
  lstat(path) {
2036
2125
  const result = this.execSync(OpCode.LSTAT, path);
2037
2126
  if (!result.success) {
2038
- throw new Error(result.error || "Failed to lstat");
2127
+ throw this.opError_("Failed to lstat", result);
2039
2128
  }
2040
2129
  return this.protocol.decodeStat();
2041
2130
  }
2042
2131
  readdir(path) {
2043
2132
  const result = this.execSync(OpCode.READDIR, path);
2044
2133
  if (!result.success) {
2045
- throw new Error(result.error || "Failed to readdir");
2134
+ throw this.opError_("Failed to readdir", result);
2046
2135
  }
2047
2136
  return JSON.parse(this.protocol.getResultAsString());
2048
2137
  }
@@ -2050,7 +2139,7 @@ var SyncBackend = class {
2050
2139
  const flags = recursive ? Flags.MKDIR_RECURSIVE : 0;
2051
2140
  const result = this.execSync(OpCode.MKDIR, path, void 0, flags);
2052
2141
  if (!result.success) {
2053
- throw new Error(result.error || "Failed to mkdir");
2142
+ throw this.opError_("Failed to mkdir", result);
2054
2143
  }
2055
2144
  }
2056
2145
  rm(path, recursive = false, force = false) {
@@ -2059,7 +2148,7 @@ var SyncBackend = class {
2059
2148
  if (force) flags |= Flags.FORCE;
2060
2149
  const result = this.execSync(OpCode.RM, path, void 0, flags);
2061
2150
  if (!result.success) {
2062
- throw new Error(result.error || "Failed to rm");
2151
+ throw this.opError_("Failed to rm", result);
2063
2152
  }
2064
2153
  }
2065
2154
  exists(path) {
@@ -2072,33 +2161,33 @@ var SyncBackend = class {
2072
2161
  appendFile(path, data) {
2073
2162
  const result = this.execSync(OpCode.APPEND_FILE, path, data);
2074
2163
  if (!result.success) {
2075
- throw new Error(result.error || "Failed to append file");
2164
+ throw this.opError_("Failed to append file", result);
2076
2165
  }
2077
2166
  }
2078
2167
  symlink(target, linkPath) {
2079
2168
  const targetData = new TextEncoder().encode(target);
2080
2169
  const result = this.execSync(OpCode.SYMLINK, linkPath, targetData);
2081
2170
  if (!result.success) {
2082
- throw new Error(result.error || "Failed to symlink");
2171
+ throw this.opError_("Failed to symlink", result);
2083
2172
  }
2084
2173
  }
2085
2174
  readlink(path) {
2086
2175
  const result = this.execSync(OpCode.READLINK, path);
2087
2176
  if (!result.success) {
2088
- throw new Error(result.error || "Failed to readlink");
2177
+ throw this.opError_("Failed to readlink", result);
2089
2178
  }
2090
2179
  return this.protocol.getResultAsString();
2091
2180
  }
2092
2181
  chmod(path, mode) {
2093
2182
  const result = this.execSync(OpCode.CHMOD, path, void 0, 0, mode);
2094
2183
  if (!result.success) {
2095
- throw new Error(result.error || "Failed to chmod");
2184
+ throw this.opError_("Failed to chmod", result);
2096
2185
  }
2097
2186
  }
2098
2187
  realpath(path) {
2099
2188
  const result = this.execSync(OpCode.REALPATH, path);
2100
2189
  if (!result.success) {
2101
- throw new Error(result.error || "Failed to realpath");
2190
+ throw this.opError_("Failed to realpath", result);
2102
2191
  }
2103
2192
  return this.protocol.getResultAsString();
2104
2193
  }
@@ -2106,28 +2195,28 @@ var SyncBackend = class {
2106
2195
  const newPathData = new TextEncoder().encode(newPath);
2107
2196
  const result = this.execSync(OpCode.RENAME, oldPath, newPathData);
2108
2197
  if (!result.success) {
2109
- throw new Error(result.error || "Failed to rename");
2198
+ throw this.opError_("Failed to rename", result);
2110
2199
  }
2111
2200
  }
2112
2201
  copyFile(src, dest) {
2113
2202
  const destData = new TextEncoder().encode(dest);
2114
2203
  const result = this.execSync(OpCode.COPY_FILE, src, destData);
2115
2204
  if (!result.success) {
2116
- throw new Error(result.error || "Failed to copyFile");
2205
+ throw this.opError_("Failed to copyFile", result);
2117
2206
  }
2118
2207
  }
2119
2208
  writeStdout(data) {
2120
2209
  const encoded = new TextEncoder().encode(data);
2121
2210
  const result = this.execSync(OpCode.WRITE_STDOUT, "", encoded);
2122
2211
  if (!result.success) {
2123
- throw new Error(result.error || "Failed to write stdout");
2212
+ throw this.opError_("Failed to write stdout", result);
2124
2213
  }
2125
2214
  }
2126
2215
  writeStderr(data) {
2127
2216
  const encoded = new TextEncoder().encode(data);
2128
2217
  const result = this.execSync(OpCode.WRITE_STDERR, "", encoded);
2129
2218
  if (!result.success) {
2130
- throw new Error(result.error || "Failed to write stderr");
2219
+ throw this.opError_("Failed to write stderr", result);
2131
2220
  }
2132
2221
  }
2133
2222
  exit(code) {
@@ -2141,7 +2230,7 @@ var SyncBackend = class {
2141
2230
  const requestData = options ? new TextEncoder().encode(JSON.stringify(options)) : void 0;
2142
2231
  const result = this.execSync(OpCode.HTTP_REQUEST, url, requestData);
2143
2232
  if (!result.success) {
2144
- throw new Error(result.error || "HTTP request failed");
2233
+ throw this.opError_("HTTP request failed", result);
2145
2234
  }
2146
2235
  const responseJson = new TextDecoder().decode(result.result);
2147
2236
  const parsed = JSON.parse(responseJson);
@@ -2164,7 +2253,7 @@ var SyncBackend = class {
2164
2253
  const requestData = stdin ? new TextEncoder().encode(JSON.stringify({ stdin })) : void 0;
2165
2254
  const result = this.execSync(OpCode.EXEC_COMMAND, command, requestData);
2166
2255
  if (!result.success) {
2167
- throw new Error(result.error || "Command execution failed");
2256
+ throw this.opError_("Command execution failed", result);
2168
2257
  }
2169
2258
  const responseJson = new TextDecoder().decode(result.result);
2170
2259
  return JSON.parse(responseJson);
@@ -2177,7 +2266,7 @@ var SyncBackend = class {
2177
2266
  const requestData = new TextEncoder().encode(JSON.stringify({ args }));
2178
2267
  const result = this.execSync(OpCode.EXEC_COMMAND, command, requestData);
2179
2268
  if (!result.success) {
2180
- throw new Error(result.error || "Command execution failed");
2269
+ throw this.opError_("Command execution failed", result);
2181
2270
  }
2182
2271
  const responseJson = new TextDecoder().decode(result.result);
2183
2272
  return JSON.parse(responseJson);
@@ -2190,7 +2279,7 @@ var SyncBackend = class {
2190
2279
  const requestData = argsJson ? new TextEncoder().encode(argsJson) : void 0;
2191
2280
  const result = this.execSync(OpCode.INVOKE_TOOL, path, requestData);
2192
2281
  if (!result.success) {
2193
- throw new Error(result.error || "Tool invocation failed");
2282
+ throw this.opError_("Tool invocation failed", result);
2194
2283
  }
2195
2284
  return new TextDecoder().decode(result.result);
2196
2285
  }
@@ -2321,26 +2410,50 @@ function createHOSTFS(backend, FS, PATH, configuredMaxFileSize) {
2321
2410
  parts.reverse();
2322
2411
  return PATH.join(...parts);
2323
2412
  }
2413
+ function errnoFromError(e) {
2414
+ const bridgeCode = e?.bridgeErrorCode;
2415
+ if (typeof bridgeCode === "number" && bridgeCode !== ErrorCode.NONE) {
2416
+ switch (bridgeCode) {
2417
+ case ErrorCode.NOT_FOUND:
2418
+ return ERRNO_CODES.ENOENT;
2419
+ case ErrorCode.IS_DIRECTORY:
2420
+ return ERRNO_CODES.EISDIR;
2421
+ case ErrorCode.NOT_DIRECTORY:
2422
+ return ERRNO_CODES.ENOTDIR;
2423
+ case ErrorCode.EXISTS:
2424
+ return ERRNO_CODES.EEXIST;
2425
+ case ErrorCode.PERMISSION_DENIED:
2426
+ return ERRNO_CODES.EACCES;
2427
+ case ErrorCode.NOT_EMPTY:
2428
+ return ERRNO_CODES.ENOTEMPTY;
2429
+ case ErrorCode.INVALID_PATH:
2430
+ return ERRNO_CODES.EINVAL;
2431
+ default:
2432
+ return ERRNO_CODES.EIO;
2433
+ }
2434
+ }
2435
+ const msg = e?.message?.toLowerCase() || (typeof e === "string" ? e.toLowerCase() : "");
2436
+ let code = ERRNO_CODES.EIO;
2437
+ if (msg.includes("no such file") || msg.includes("not found")) {
2438
+ code = ERRNO_CODES.ENOENT;
2439
+ } else if (msg.includes("is a directory")) {
2440
+ code = ERRNO_CODES.EISDIR;
2441
+ } else if (msg.includes("not a directory")) {
2442
+ code = ERRNO_CODES.ENOTDIR;
2443
+ } else if (msg.includes("already exists")) {
2444
+ code = ERRNO_CODES.EEXIST;
2445
+ } else if (msg.includes("permission")) {
2446
+ code = ERRNO_CODES.EACCES;
2447
+ } else if (msg.includes("not empty")) {
2448
+ code = ERRNO_CODES.ENOTEMPTY;
2449
+ }
2450
+ return code;
2451
+ }
2324
2452
  function tryFSOperation(f) {
2325
2453
  try {
2326
2454
  return f();
2327
2455
  } catch (e) {
2328
- const msg = e?.message?.toLowerCase() || (typeof e === "string" ? e.toLowerCase() : "");
2329
- let code = ERRNO_CODES.EIO;
2330
- if (msg.includes("no such file") || msg.includes("not found")) {
2331
- code = ERRNO_CODES.ENOENT;
2332
- } else if (msg.includes("is a directory")) {
2333
- code = ERRNO_CODES.EISDIR;
2334
- } else if (msg.includes("not a directory")) {
2335
- code = ERRNO_CODES.ENOTDIR;
2336
- } else if (msg.includes("already exists")) {
2337
- code = ERRNO_CODES.EEXIST;
2338
- } else if (msg.includes("permission")) {
2339
- code = ERRNO_CODES.EACCES;
2340
- } else if (msg.includes("not empty")) {
2341
- code = ERRNO_CODES.ENOTEMPTY;
2342
- }
2343
- throw new FS.ErrnoError(code);
2456
+ throw new FS.ErrnoError(errnoFromError(e));
2344
2457
  }
2345
2458
  }
2346
2459
  function getMode(path) {
@@ -2491,11 +2604,12 @@ function createHOSTFS(backend, FS, PATH, configuredMaxFileSize) {
2491
2604
  } else {
2492
2605
  content = backend.readFile(path);
2493
2606
  }
2494
- } catch (_e) {
2495
- if (isCreate && isWrite) {
2607
+ } catch (e) {
2608
+ const code = errnoFromError(e);
2609
+ if (code === ERRNO_CODES.ENOENT && isCreate && isWrite) {
2496
2610
  content = new Uint8Array(0);
2497
2611
  } else {
2498
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
2612
+ throw new FS.ErrnoError(code);
2499
2613
  }
2500
2614
  }
2501
2615
  if (content.length > maxFileSize) {