@nimbus-sh/worker 0.9.0 → 0.11.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 (286) hide show
  1. package/NOTICE.md +5 -0
  2. package/README.md +10 -0
  3. package/dist/_shared/session-router.d.ts +7 -0
  4. package/dist/_shared/session-router.d.ts.map +1 -1
  5. package/dist/_shared/session-router.js +7 -0
  6. package/dist/bindings/body.d.ts +6 -0
  7. package/dist/bindings/body.d.ts.map +1 -0
  8. package/dist/bindings/body.js +37 -0
  9. package/dist/bindings/kv.d.ts +0 -2
  10. package/dist/bindings/kv.d.ts.map +1 -1
  11. package/dist/bindings/kv.js +3 -42
  12. package/dist/bindings/r2.d.ts +0 -2
  13. package/dist/bindings/r2.d.ts.map +1 -1
  14. package/dist/bindings/r2.js +4 -44
  15. package/dist/esbuild-cli-artifact.generated.d.ts +18 -0
  16. package/dist/esbuild-cli-artifact.generated.d.ts.map +1 -0
  17. package/dist/esbuild-cli-artifact.generated.js +17 -0
  18. package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
  19. package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
  20. package/dist/esbuild-wasm-bundle.generated.js +24 -24
  21. package/dist/facets/cirrus-real.d.ts.map +1 -1
  22. package/dist/facets/cirrus-real.js +11 -6
  23. package/dist/facets/compose.d.ts +11 -7
  24. package/dist/facets/compose.d.ts.map +1 -1
  25. package/dist/facets/compose.js +8 -31
  26. package/dist/facets/data-plan.d.ts +79 -0
  27. package/dist/facets/data-plan.d.ts.map +1 -0
  28. package/dist/facets/data-plan.js +477 -0
  29. package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
  30. package/dist/facets/esbuild-bundle-pool.js +3 -3
  31. package/dist/facets/esbuild-transform.d.ts +38 -8
  32. package/dist/facets/esbuild-transform.d.ts.map +1 -1
  33. package/dist/facets/esbuild-transform.js +219 -19
  34. package/dist/facets/exec-telemetry.d.ts +7 -3
  35. package/dist/facets/exec-telemetry.d.ts.map +1 -1
  36. package/dist/facets/manager.d.ts +198 -69
  37. package/dist/facets/manager.d.ts.map +1 -1
  38. package/dist/facets/manager.js +1276 -652
  39. package/dist/facets/opencode-staging.d.ts +0 -2
  40. package/dist/facets/opencode-staging.d.ts.map +1 -1
  41. package/dist/facets/opencode-staging.js +5 -11
  42. package/dist/facets/process.d.ts +4 -0
  43. package/dist/facets/process.d.ts.map +1 -1
  44. package/dist/facets/process.js +3 -0
  45. package/dist/facets/read-profile.d.ts +149 -0
  46. package/dist/facets/read-profile.d.ts.map +1 -0
  47. package/dist/facets/read-profile.js +483 -0
  48. package/dist/facets/real-vite-hmr.d.ts +2 -0
  49. package/dist/facets/real-vite-hmr.d.ts.map +1 -1
  50. package/dist/facets/real-vite-hmr.js +3 -2
  51. package/dist/facets/resident-identity.d.ts +0 -1
  52. package/dist/facets/resident-identity.d.ts.map +1 -1
  53. package/dist/facets/resident-identity.js +0 -3
  54. package/dist/facets/wasm-swap-registry.d.ts +34 -25
  55. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  56. package/dist/facets/wasm-swap-registry.js +62 -56
  57. package/dist/facets/ws-terminal.d.ts +4 -4
  58. package/dist/facets/ws-terminal.d.ts.map +1 -1
  59. package/dist/facets/ws-terminal.js +4 -5
  60. package/dist/git/commands.d.ts +33 -10
  61. package/dist/git/commands.d.ts.map +1 -1
  62. package/dist/git/commands.js +1891 -197
  63. package/dist/git/network-facet.d.ts +12 -2
  64. package/dist/git/network-facet.d.ts.map +1 -1
  65. package/dist/git/network-facet.js +69 -18
  66. package/dist/git/unified-diff.d.ts +74 -0
  67. package/dist/git/unified-diff.d.ts.map +1 -0
  68. package/dist/git/unified-diff.js +676 -0
  69. package/dist/git-bundle.generated.d.ts +7 -11
  70. package/dist/git-bundle.generated.d.ts.map +1 -1
  71. package/dist/git-bundle.generated.js +7 -11
  72. package/dist/hosted/commands.d.ts.map +1 -1
  73. package/dist/hosted/commands.js +64 -245
  74. package/dist/hosted/runtime.d.ts +22 -15
  75. package/dist/hosted/runtime.d.ts.map +1 -1
  76. package/dist/hosted/runtime.js +72 -14
  77. package/dist/hosted/services.d.ts +8 -1
  78. package/dist/hosted/services.d.ts.map +1 -1
  79. package/dist/hosted/services.js +12 -13
  80. package/dist/hosted/session.d.ts +165 -0
  81. package/dist/hosted/session.d.ts.map +1 -0
  82. package/dist/hosted/session.js +132 -0
  83. package/dist/loaders/generated-workers.d.ts +6 -3
  84. package/dist/loaders/generated-workers.d.ts.map +1 -1
  85. package/dist/loaders/generated-workers.js +8 -5
  86. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  87. package/dist/loaders/npm-resolve-preamble.js +0 -27
  88. package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
  89. package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
  90. package/dist/loaders/pre-bundle-preamble.js +13 -8
  91. package/dist/node-shims-artifact.generated.d.ts +13 -4
  92. package/dist/node-shims-artifact.generated.d.ts.map +1 -1
  93. package/dist/node-shims-artifact.generated.js +16 -7
  94. package/dist/npm/bin-links.d.ts +3 -1
  95. package/dist/npm/bin-links.d.ts.map +1 -1
  96. package/dist/npm/bin-links.js +32 -8
  97. package/dist/npm/cache.d.ts +11 -1
  98. package/dist/npm/cache.d.ts.map +1 -1
  99. package/dist/npm/cache.js +21 -7
  100. package/dist/npm/install-batch-facet.d.ts +4 -2
  101. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  102. package/dist/npm/install-batch-facet.js +32 -18
  103. package/dist/npm/installer.d.ts +23 -3
  104. package/dist/npm/installer.d.ts.map +1 -1
  105. package/dist/npm/installer.js +330 -131
  106. package/dist/npm/npx-install.d.ts +3 -1
  107. package/dist/npm/npx-install.d.ts.map +1 -1
  108. package/dist/npm/npx-install.js +4 -1
  109. package/dist/npm/package-lock.d.ts +32 -0
  110. package/dist/npm/package-lock.d.ts.map +1 -0
  111. package/dist/npm/package-lock.js +65 -0
  112. package/dist/npm/placement.d.ts +16 -0
  113. package/dist/npm/placement.d.ts.map +1 -0
  114. package/dist/npm/placement.js +33 -0
  115. package/dist/npm/pre-bundle-facet.d.ts +1 -30
  116. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  117. package/dist/npm/pre-bundle-facet.js +3 -5
  118. package/dist/npm/r2-cache.d.ts +12 -6
  119. package/dist/npm/r2-cache.d.ts.map +1 -1
  120. package/dist/npm/r2-cache.js +34 -16
  121. package/dist/npm/resolve-one-facet.d.ts +3 -0
  122. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  123. package/dist/npm/resolve-one-facet.js +15 -3
  124. package/dist/npm/resolver.d.ts +11 -13
  125. package/dist/npm/resolver.d.ts.map +1 -1
  126. package/dist/npm/resolver.js +12 -25
  127. package/dist/opencode-artifact.generated.js +2 -2
  128. package/dist/replica/routing.d.ts +2 -38
  129. package/dist/replica/routing.d.ts.map +1 -1
  130. package/dist/replica/routing.js +3 -55
  131. package/dist/router/index.d.ts.map +1 -1
  132. package/dist/router/index.js +15 -2
  133. package/dist/router/public-directory.d.ts +18 -0
  134. package/dist/router/public-directory.d.ts.map +1 -1
  135. package/dist/router/public-directory.js +1 -1
  136. package/dist/router/remote-api.d.ts +3 -1
  137. package/dist/router/remote-api.d.ts.map +1 -1
  138. package/dist/router/remote-api.js +42 -79
  139. package/dist/runtime/bash-repl.js +2 -2
  140. package/dist/runtime/bun-repl.d.ts.map +1 -1
  141. package/dist/runtime/bun-repl.js +2 -13
  142. package/dist/runtime/cpython-resident.d.ts.map +1 -1
  143. package/dist/runtime/cpython-resident.js +2 -10
  144. package/dist/runtime/esbuild-wasm-bytes.d.ts +37 -18
  145. package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
  146. package/dist/runtime/esbuild-wasm-bytes.js +66 -92
  147. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  148. package/dist/runtime/facet-loader-host.js +0 -7
  149. package/dist/runtime/git-bundle-artifact.d.ts +17 -0
  150. package/dist/runtime/git-bundle-artifact.d.ts.map +1 -0
  151. package/dist/runtime/git-bundle-artifact.js +25 -0
  152. package/dist/runtime/node-repl.d.ts.map +1 -1
  153. package/dist/runtime/node-repl.js +2 -13
  154. package/dist/runtime/node-shims-artifact.d.ts +22 -23
  155. package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
  156. package/dist/runtime/node-shims-artifact.js +48 -78
  157. package/dist/runtime/node-shims.d.ts.map +1 -1
  158. package/dist/runtime/node-shims.js +2358 -996
  159. package/dist/runtime/opencode-artifact.d.ts.map +1 -1
  160. package/dist/runtime/opencode-artifact.js +17 -53
  161. package/dist/runtime/opencode-facet-runner.d.ts +3 -6
  162. package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
  163. package/dist/runtime/opencode-facet-runner.js +45 -10
  164. package/dist/runtime/opentui-wasm-bytes.d.ts.map +1 -1
  165. package/dist/runtime/opentui-wasm-bytes.js +16 -49
  166. package/dist/runtime/package-manager.d.ts +0 -2
  167. package/dist/runtime/package-manager.d.ts.map +1 -1
  168. package/dist/runtime/package-manager.js +0 -3
  169. package/dist/runtime/python-repl.d.ts.map +1 -1
  170. package/dist/runtime/python-repl.js +4 -35
  171. package/dist/runtime/repl-session.d.ts +10 -0
  172. package/dist/runtime/repl-session.d.ts.map +1 -1
  173. package/dist/runtime/repl-session.js +7 -0
  174. package/dist/runtime/ruby-repl.d.ts.map +1 -1
  175. package/dist/runtime/ruby-repl.js +2 -2
  176. package/dist/runtime/ruby-resident.d.ts.map +1 -1
  177. package/dist/runtime/ruby-resident.js +41 -51
  178. package/dist/runtime/runtime-catalog.d.ts +10 -3
  179. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  180. package/dist/runtime/runtime-catalog.js +125 -15
  181. package/dist/runtime/sqlite-wasm-bytes.d.ts +4 -4
  182. package/dist/runtime/sqlite-wasm-bytes.d.ts.map +1 -1
  183. package/dist/runtime/sqlite-wasm-bytes.js +21 -57
  184. package/dist/runtime/staged-source.d.ts +67 -0
  185. package/dist/runtime/staged-source.d.ts.map +1 -0
  186. package/dist/runtime/staged-source.js +113 -0
  187. package/dist/runtime/wasi/preamble.d.ts +0 -22
  188. package/dist/runtime/wasi/preamble.d.ts.map +1 -1
  189. package/dist/runtime/wasi/preamble.js +98 -1425
  190. package/dist/runtime-catalog.generated.js +1 -1
  191. package/dist/session/agent.d.ts +14 -2
  192. package/dist/session/agent.d.ts.map +1 -1
  193. package/dist/session/agent.js +57 -19
  194. package/dist/session/ai.d.ts +0 -11
  195. package/dist/session/ai.d.ts.map +1 -1
  196. package/dist/session/ai.js +0 -4
  197. package/dist/session/fs-watch.d.ts +0 -11
  198. package/dist/session/fs-watch.d.ts.map +1 -1
  199. package/dist/session/fs-watch.js +0 -21
  200. package/dist/session/hibernation.d.ts +68 -2
  201. package/dist/session/hibernation.d.ts.map +1 -1
  202. package/dist/session/hibernation.js +95 -1
  203. package/dist/session/init-phases.d.ts +1 -2
  204. package/dist/session/init-phases.d.ts.map +1 -1
  205. package/dist/session/init-phases.js +1 -2
  206. package/dist/session/init.d.ts.map +1 -1
  207. package/dist/session/init.js +7 -20
  208. package/dist/session/keys.d.ts +0 -3
  209. package/dist/session/keys.d.ts.map +1 -1
  210. package/dist/session/keys.js +0 -3
  211. package/dist/session/legacy-reset.d.ts +11 -0
  212. package/dist/session/legacy-reset.d.ts.map +1 -0
  213. package/dist/session/legacy-reset.js +16 -0
  214. package/dist/session/nimbus-session.d.ts +50 -16
  215. package/dist/session/nimbus-session.d.ts.map +1 -1
  216. package/dist/session/nimbus-session.js +77 -71
  217. package/dist/session/npm-install-port.d.ts.map +1 -1
  218. package/dist/session/npm-install-port.js +2 -0
  219. package/dist/session/programmatic.d.ts +13 -18
  220. package/dist/session/programmatic.d.ts.map +1 -1
  221. package/dist/session/programmatic.js +53 -39
  222. package/dist/session/replica-routes.d.ts +2 -3
  223. package/dist/session/replica-routes.d.ts.map +1 -1
  224. package/dist/session/replica-routes.js +3 -10
  225. package/dist/session/routes.d.ts.map +1 -1
  226. package/dist/session/routes.js +11 -12
  227. package/dist/session/rpc.d.ts +108 -21
  228. package/dist/session/rpc.d.ts.map +1 -1
  229. package/dist/session/rpc.js +194 -39
  230. package/dist/session/start-real-vite.js +2 -2
  231. package/dist/session/state-store.d.ts +1 -17
  232. package/dist/session/state-store.d.ts.map +1 -1
  233. package/dist/session/state-store.js +3 -53
  234. package/dist/session/supervisor-op.d.ts +7 -0
  235. package/dist/session/supervisor-op.d.ts.map +1 -1
  236. package/dist/session/supervisor-op.js +6 -1
  237. package/dist/session/supervisor-rpc.d.ts +116 -19
  238. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  239. package/dist/session/supervisor-rpc.js +194 -84
  240. package/dist/session/vite-command.d.ts.map +1 -1
  241. package/dist/session/vite-command.js +17 -14
  242. package/dist/session/ws.d.ts.map +1 -1
  243. package/dist/session/ws.js +20 -8
  244. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  245. package/dist/shell/npm-bin-entrypoints.js +30 -5
  246. package/dist/vfs/facet-resident-limits.d.ts +33 -0
  247. package/dist/vfs/facet-resident-limits.d.ts.map +1 -0
  248. package/dist/vfs/facet-resident-limits.js +33 -0
  249. package/dist/vfs/facet-resident-store.d.ts +2 -10
  250. package/dist/vfs/facet-resident-store.d.ts.map +1 -1
  251. package/dist/vfs/facet-resident-store.js +1594 -219
  252. package/dist/workspace-host.d.ts +3 -1
  253. package/dist/workspace-host.d.ts.map +1 -1
  254. package/dist/workspace-host.js +2 -0
  255. package/dist/wrangler/nimbus-wrangler.d.ts +0 -2
  256. package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
  257. package/dist/wrangler/nimbus-wrangler.js +8 -22
  258. package/package.json +34 -7
  259. package/public/_assets/esbuild-0.24.2.js +2380 -0
  260. package/public/_assets/opencode/1.16.2/index-attach.js +2 -2
  261. package/public/_assets/runtime/esbuild-cli-c4fda380d52befc1.js +6892 -0
  262. package/public/_assets/runtime/git-de3e60c9f3ff006a.js +103 -0
  263. package/public/_assets/runtime/{node-shims-acaa037e6d26ec0d.js → node-shims-06565b121555c194.js} +2879 -992
  264. package/public/_assets/runtime/resident-store-6ffb1939c53d982f.js +2264 -0
  265. package/public/_assets/runtime/vfs-write-ledger-e501e8fc793bc2c1.js +889 -0
  266. package/scripts/build-opencode-attach-entry.mjs +51 -1
  267. package/scripts/bundle-esbuild-wasm.mjs +55 -39
  268. package/scripts/bundle-facet-workers.mjs +159 -10
  269. package/scripts/bundle-git.mjs +88 -27
  270. package/scripts/bundle-node-shims.mjs +72 -46
  271. package/scripts/bundle-runtime.mjs +18 -421
  272. package/scripts/cf-git-patch.mjs +137 -0
  273. package/scripts/patch-install-deps.mjs +49 -96
  274. package/scripts/runtime-specs.mjs +435 -0
  275. package/vendor/git-http.generated.d.ts +82 -0
  276. package/vendor/git-upstream.generated.d.ts +4378 -0
  277. package/vendor/git.LICENSE +7 -0
  278. package/vendor/git.generated.d.mts +21 -0
  279. package/vendor/git.generated.mjs +103 -0
  280. package/dist/replica/suspension.d.ts +0 -36
  281. package/dist/replica/suspension.d.ts.map +0 -1
  282. package/dist/replica/suspension.js +0 -49
  283. package/dist/runtime/static-server.d.ts +0 -3
  284. package/dist/runtime/static-server.d.ts.map +0 -1
  285. package/dist/runtime/static-server.js +0 -133
  286. package/scripts/clean-dist.mjs +0 -7
@@ -7,7 +7,7 @@
7
7
  * node scripts/bundle-runtime.mjs clang binji-2020 [--bucket nimbus-runtime-cache]
8
8
  * node scripts/bundle-runtime.mjs python 0.29.4 [--bucket nimbus-runtime-cache]
9
9
  * node scripts/bundle-runtime.mjs --pin-catalog (read-only; publishes nothing)
10
- * node scripts/bundle-runtime.mjs bash 5.2.37-2 --npm-package <dir> (local; no R2)
10
+ * node scripts/bundle-runtime.mjs bash 5.2.37-3 --npm-package <dir> (local; no R2)
11
11
  *
12
12
  * `--npm-package` is the SECOND publisher for the same artifacts: it stages
13
13
  * exactly what the R2 path stages, composes the same manifest bytes, and lays
@@ -50,7 +50,7 @@ import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync, openSync, c
50
50
  import { execFileSync, execSync, spawnSync } from 'node:child_process';
51
51
  import { tmpdir } from 'node:os';
52
52
  import { basename, dirname, join } from 'node:path';
53
- import { BASH_RUNNER } from '@nimbus-sh/core/runtime/os-contracts.js';
53
+ import { SPECS } from './runtime-specs.mjs';
54
54
 
55
55
  const ACCOUNT = process.env.CLOUDFLARE_ACCOUNT_ID;
56
56
  // Resolve the wrangler bin from either the package-local or the
@@ -135,7 +135,7 @@ if (!NPM_OUT_DIR && !ACCOUNT) {
135
135
  // time, including while another ingest is in flight against a different bucket.
136
136
  if (PIN_ONLY) {
137
137
  pinCatalogFromR2();
138
- process.exit(0);
138
+ process.exit();
139
139
  }
140
140
 
141
141
  if (!positionalArgs[0] || !positionalArgs[1]) {
@@ -146,297 +146,6 @@ if (!positionalArgs[0] || !positionalArgs[1]) {
146
146
  const RUNTIME = positionalArgs[0];
147
147
  const VERSION = positionalArgs[1];
148
148
 
149
- /**
150
- * Static per-runtime spec. Each entry says where to fetch the upstream
151
- * file from and how to map it into the per-user VFS at install time.
152
- *
153
- * For `clang binji-2020`:
154
- * - VFS path `bin/clang` ← upstream `clang` (31.2 MB)
155
- * - VFS path `bin/wasm-ld` ← upstream `lld` (19.5 MB)
156
- * - VFS path `share/clang/sysroot.tar`← upstream `sysroot.tar` (9.3 MB)
157
- * - VFS path `LICENSE` ← bundled APACHE-2.0 text
158
- */
159
- const SPECS = {
160
- 'clang/binji-2020': {
161
- license: 'Apache-2.0-with-LLVM-exception',
162
- wasi_namespace: 'wasi_unstable',
163
- upstream_base: 'https://raw.githubusercontent.com/binji/wasm-clang/master',
164
- npm: {
165
- name: '@nimbus-sh/runtime-clang',
166
- summary: 'clang 8.0.1 and wasm-ld for wasm32-wasi, with a wasi-libc sysroot',
167
- // npm demands semver and this runtime's Nimbus version is a channel
168
- // name, so the compiler's own version is what the package carries. The
169
- // two namespaces stay separate: the manifest still says `binji-2020`,
170
- // and that is what the install root under ~/.nimbus/runtimes is named.
171
- version: '8.0.1',
172
- },
173
- files: [
174
- { src: 'clang', vfs: 'bin/clang', mode: 'exec', runner: 'clang-runner', binName: 'clang' },
175
- { src: 'lld', vfs: 'bin/wasm-ld', mode: 'exec', runner: 'clang-runner', binName: 'wasm-ld', kind: 'linker' },
176
- { src: 'sysroot.tar', vfs: 'share/clang/sysroot.tar' },
177
- ],
178
- // Bundled LICENSE text — Apache 2.0 with LLVM exception (full text below).
179
- // Source: https://github.com/llvm/llvm-project/blob/main/LICENSE.TXT
180
- license_text: APACHE_2_LLVM_LICENSE_TEXT(),
181
- },
182
- // ── Ruby (v1, 2026-05-11) ────────────────────────────────────────
183
- // ruby.wasm 2.9.3-2.9.4 from npm @ruby/3.3-wasm-wasi (Ruby 3.3.x
184
- // built on WASI). We bundle ONLY the `ruby+stdlib.wasm` artifact
185
- // (34.3 MiB) — it's self-contained, stdlib is packed via wasi-vfs
186
- // into the wasm. No separate stdlib zip transport needed (unlike
187
- // Pyodide which ships python_stdlib.zip alongside the asm.js).
188
- //
189
- // Upstream channel: npm tarball — the script downloads the tarball
190
- // (`upstream_base + '/' + src`) and extracts the wasm by file
191
- // name via the `tarball_extract` flag. Each spec.files entry's
192
- // `src` is interpreted as the path INSIDE the extracted tarball.
193
- //
194
- // See /workspace/.seal-internal/2026-05-11-ruby-v1/audit.md for
195
- // the full artifact audit + import/export breakdown.
196
- 'ruby/3.3.4': {
197
- license: 'Ruby+BSD-2-Clause',
198
- wasi_namespace: 'wasi_snapshot_preview1',
199
- upstream_base: 'https://registry.npmjs.org/@ruby/3.3-wasm-wasi/-/3.3-wasm-wasi-2.9.3-2.9.4.tgz',
200
- npm: {
201
- name: '@nimbus-sh/runtime-ruby',
202
- summary: 'Ruby 3.3.4 (ruby.wasm) for wasm32-wasi, with its stdlib packed in',
203
- },
204
- tarball_extract: 'package/dist', // strip this prefix from src paths inside the tarball
205
- files: [
206
- // The Ruby wasm — includes Ruby 3.3.x interpreter + stdlib packed
207
- // via wasi-vfs. ruby-runner instantiates this at child-facet
208
- // module-init time and drives it via the Ruby ABI exports
209
- // (`ruby-init`, `ruby-init-loadpath`, `rb-eval-string-protect`).
210
- { src: 'ruby+stdlib.wasm', vfs: 'share/ruby/ruby+stdlib.wasm' },
211
- // User-facing bin entries. The shell registry dispatches `ruby`
212
- // and `ruby3` to ruby-runner; this file is a marker, not exec.
213
- { src: 'BIN_MARKER', vfs: 'bin/ruby', mode: 'exec', runner: 'ruby-runner', binName: 'ruby' },
214
- { src: 'BIN_MARKER', vfs: 'bin/ruby3', mode: 'exec', runner: 'ruby-runner', binName: 'ruby3' },
215
- ],
216
- synthetic_files: {
217
- 'BIN_MARKER': Buffer.from(
218
- '# Nimbus ruby-runner launcher marker. The actual Ruby wasm\n' +
219
- '# lives in share/ruby/. This file is here only so `which ruby`\n' +
220
- '# and `ls bin/` find a regular file at the expected path. The\n' +
221
- '# shell-registry dispatches `ruby` directly to the ruby-runner\n' +
222
- '# factory; this file is not read or executed by Nimbus.\n',
223
- 'utf8',
224
- ),
225
- },
226
- license_text: RUBY_LICENSE_TEXT(),
227
- },
228
- // ── GNU bash (fork runtime, 2026-07-20) ──────────────────────────
229
- // bash 5.2.37 cross-compiled to wasm32-wasi with the Nimbus process
230
- // overlay (nimbus-proc.{h,c}: fork/exec/wait/pipe over nimbus_proc.*
231
- // imports + asyncify-native setjmp) and asyncify-instrumented.
232
- // There is NO upstream binary channel — the artifacts are built from
233
- // source by packages/worker/wasm/bash/build-bash.sh (bash) and
234
- // coreutils/build-busybox.sh (BusyBox 1.37.0, the plain-WASI multicall
235
- // exec target providing ls/cat/cp/mv/rm/grep/sed/awk/find/... — see
236
- // busybox.applets), then staged from the local build tree via
237
- // `local_base`. The bash-runner aliases every applet name in
238
- // busybox.applets onto the busybox module so bash's PATH lookup finds
239
- // them in /bin and /usr/bin.
240
- //
241
- // The version is `<upstream>-<build>`: the build number advances with
242
- // every rebuild, and the entrypoint names the runner contract the build
243
- // was made for (BASH_RUNNER), so a deployment whose preamble predates it
244
- // never binds it. 5.2.37 is build 1, published under `bash-runner`.
245
- 'bash/5.2.37-2': {
246
- license: 'GPL-3.0-or-later AND GPL-2.0-only',
247
- wasi_namespace: 'wasi_snapshot_preview1',
248
- local_base: '../wasm/bash',
249
- auxiliary_bins: 'coreutils/busybox.applets',
250
- npm: {
251
- name: '@nimbus-sh/runtime-bash',
252
- summary: 'GNU bash 5.2.37 and BusyBox 1.37.0, cross-compiled to wasm32-wasi',
253
- },
254
- files: [
255
- { src: 'bash.async.wasm', vfs: 'share/bash/bash.async.wasm' },
256
- { src: 'coreutils/busybox.wasm', vfs: 'share/bash/coreutils/busybox.wasm' },
257
- { src: 'coreutils/busybox.applets', vfs: 'share/bash/coreutils/busybox.applets' },
258
- { src: 'BIN_MARKER', vfs: 'bin/bash', mode: 'exec', runner: BASH_RUNNER, binName: 'bash' },
259
- ],
260
- synthetic_files: {
261
- 'BIN_MARKER': Buffer.from(
262
- '# Nimbus bash-runner launcher marker. The real GNU bash wasm\n' +
263
- '# lives in share/bash/. The shell registry dispatches `bash`\n' +
264
- '# (and #!/bin/bash shebangs) to the bash-runner factory; this\n' +
265
- '# file exists so `which bash` and `ls bin/` find a regular,\n' +
266
- '# executable file at the expected path.\n',
267
- 'utf8',
268
- ),
269
- },
270
- license_text: GPL_3_LICENSE_NOTICE(),
271
- },
272
- 'python/0.29.4': {
273
- license: 'MPL-2.0',
274
- wasi_namespace: null, // Pyodide is Emscripten, not WASI
275
- upstream_base: 'https://cdn.jsdelivr.net/pyodide/v0.29.4/full',
276
- files: [
277
- // The wasm module Pyodide instantiates. Goes to share/ so the
278
- // user-VFS layout matches binji-clang's convention (bin/ for
279
- // exec entry, share/<name>/ for runtime-private blobs).
280
- { src: 'pyodide.asm.wasm', vfs: 'share/pyodide/pyodide.asm.wasm' },
281
- // The Emscripten JS half. Runtime sync adapts it once for
282
- // workerd and records that contract in manifest metadata; the
283
- // Python runner consumes the resulting artifact without patching
284
- // it during session boot.
285
- { src: 'pyodide.asm.js', vfs: 'share/pyodide/pyodide.asm.js', transform: 'pyodide-workerd-adapter' },
286
- // Python 3.13 stdlib. Pyodide writes this into its Emscripten
287
- // MEMFS at /lib/python313.zip and CPython imports from there
288
- // via the ZipImporter on sys.path.
289
- { src: 'python_stdlib.zip', vfs: 'share/pyodide/python_stdlib.zip' },
290
- // Lockfile — only used by pyodide.loadPackage / micropip (v3
291
- // scope). We ship it so v3 doesn't need to re-bundle from
292
- // scratch; v1 ignores its contents.
293
- { src: 'pyodide-lock.json', vfs: 'share/pyodide/pyodide-lock.json' },
294
- // The user-facing "bin" — a tiny launcher marker. We don't
295
- // actually exec this file; the python-runner factory pulls
296
- // bytes from the share/ entries and ignores bin/python's
297
- // content. The presence of the entry in entrypoints[] is what
298
- // wires `python` into the shell registry.
299
- { src: 'BIN_MARKER', vfs: 'bin/python', mode: 'exec', runner: 'python-runner', binName: 'python' },
300
- // Second entrypoint — `python3` is conventional on Linux.
301
- { src: 'BIN_MARKER', vfs: 'bin/python3', mode: 'exec', runner: 'python-runner', binName: 'python3' },
302
- ],
303
- license_text: MPL_2_LICENSE_TEXT(),
304
- /** Source 'BIN_MARKER' is synthesised, not fetched. */
305
- synthetic_files: {
306
- 'BIN_MARKER': Buffer.from(
307
- '# Nimbus python-runner launcher marker. The actual Pyodide\n' +
308
- '# bootstrap lives in share/pyodide/. This file is here only so\n' +
309
- '# `which python` and `ls bin/` find a regular file at the\n' +
310
- '# expected path. The shell-registry dispatches `python`\n' +
311
- '# directly to the python-runner factory; this file is not\n' +
312
- '# read or executed by Nimbus.\n',
313
- 'utf8',
314
- ),
315
- },
316
- python_packages: ['numpy', 'markupsafe'],
317
- },
318
-
319
- // CPython 3.13 cross-built for wasm32-wasi by packages/worker/wasm/python/
320
- // build-python.sh, with the C libraries the published wasm32-wasi artifacts
321
- // leave out (zlib, bzip2, xz, sqlite, OpenSSL). Unlike the Pyodide entry
322
- // above this is a real WASI module: it talks to runtime/wasi/preamble.ts, so
323
- // it has no filesystem of its own to copy in and diff back out.
324
- //
325
- // Additive alongside python/0.29.4. Nothing reads these keys until
326
- // session/init.ts routes `python` at the cpython-runner factory.
327
- 'cpython/3.13.14': {
328
- license: 'PSF-2.0',
329
- wasi_namespace: 'wasi_snapshot_preview1',
330
- local_base: '../wasm/python',
331
- npm: {
332
- name: '@nimbus-sh/runtime-cpython',
333
- summary: 'CPython 3.13.14, cross-compiled to wasm32-wasi, with its stdlib',
334
- },
335
- files: [
336
- { src: 'python.wasm', vfs: 'share/cpython/python.wasm' },
337
- // The same interpreter with numpy and markupsafe's C speedups linked in,
338
- // and their Python half. wasm32-wasi has no dlopen, so a compiled package
339
- // is either in the binary or unavailable; the runner picks between the two
340
- // from what the session installed. Both ship because the choice is made
341
- // per invocation, inside the session, long after the install.
342
- { src: 'python-sci.wasm', vfs: 'share/cpython/python-sci.wasm' },
343
- // Beside the stdlib zip on purpose: the runner puts it on sys.path and
344
- // zipimport reads it out of the session filesystem, so it needs the same
345
- // treatment as lib/python313.zip and no separate transport.
346
- { src: 'sci-packages.zip', vfs: 'lib/sci-packages.zip' },
347
- // The stdlib, pyc-only. Read straight out of the session filesystem by
348
- // zipimport, which is why it needs no separate transport.
349
- // Laid out as a Python prefix, so nimbus_py_init can be handed the
350
- // install root directly. Aliasing lib/ onto some other path would put
351
- // entries in the guest's filesystem that the supervisor cannot serve,
352
- // and a manifest entry nobody can fetch is an EIO waiting to happen.
353
- { src: 'python313.zip', vfs: 'lib/python313.zip' },
354
- // OpenSSL has no default trust store to fall back on here: there is no
355
- // /etc/ssl in the session, so ssl.create_default_context() would verify
356
- // against nothing and every HTTPS fetch would fail. SSL_CERT_FILE points
357
- // at this. Mozilla's bundle, as published by curl.se.
358
- { src: 'cacert.pem', vfs: 'etc/ssl/cert.pem' },
359
- { src: 'STDLIB_MARKER', vfs: 'lib/python3.13/os.py' },
360
- { src: 'BIN_MARKER', vfs: 'bin/python', mode: 'exec', runner: 'cpython-runner', binName: 'python' },
361
- { src: 'BIN_MARKER', vfs: 'bin/python3', mode: 'exec', runner: 'cpython-runner', binName: 'python3' },
362
- ],
363
- license_text: PSF_LICENSE_NOTICE(),
364
- /** Source 'BIN_MARKER' is synthesised, not fetched. */
365
- synthetic_files: {
366
- 'STDLIB_MARKER': Buffer.from(
367
- '# Nimbus stdlib marker. Every module is read from ../python313.zip;\n' +
368
- '# this file exists so the prefix looks like a Python prefix.\n',
369
- 'utf8',
370
- ),
371
- 'BIN_MARKER': Buffer.from(
372
- '# Nimbus cpython-runner launcher marker. The interpreter itself\n' +
373
- '# lives in share/cpython/. This file exists so `which python` and\n' +
374
- '# `ls bin/` find a regular, executable file at the expected path;\n' +
375
- '# the shell registry dispatches `python` directly to the\n' +
376
- '# cpython-runner factory and never reads this content.\n',
377
- 'utf8',
378
- ),
379
- },
380
- },
381
-
382
- // 2026-05-11 sysroot-prep Phase 0 — R2 ingestion ONLY for the
383
- // clang-sysroot-swap wave. This entry stages the upstream wasi-sdk-19
384
- // sysroot in R2 (binji-shape: rootless `include/lib/share` layout) so
385
- // when the swap wave dispatches, the blob is already present.
386
- //
387
- // `ingest_only: true` SUPPRESSES the manifest write AND the catalog
388
- // auto-flip at the bottom of the script. The swap wave owns those
389
- // operations (it composes a new manifest that inherits bin/clang,
390
- // bin/wasm-ld from binji-2020 and references this
391
- // prep'd sysroot.tar blob, then flips `clang.default`).
392
- //
393
- // `repackage` describes a download+extract+retar pre-step that
394
- // produces a single local `sysroot.tar` file BEFORE the upload loop.
395
- // The file's `src` value is used as both the cached download filename
396
- // and (after repackage) the upload basename.
397
- 'clang/wasi-sdk-19': {
398
- license: 'Apache-2.0-with-LLVM-exception',
399
- ingest_only: true,
400
- files: [
401
- // The upload loop sees one logical "file" with src='sysroot.tar'.
402
- // The repackage step below produces it from the upstream tarball
403
- // and writes it to <workDir>/sysroot.tar before the upload loop
404
- // runs. `vfs` mirrors the binji-2020 path for the swap wave's
405
- // manifest composer (kept for documentation only; ignored in
406
- // ingest_only mode since no manifest is written).
407
- { src: 'sysroot.tar', vfs: 'share/clang/sysroot.tar' },
408
- ],
409
- // Build-time step: fetch the upstream wasi-sdk-19 sysroot tarball,
410
- // extract, and re-tar in binji-2020 layout (rootless: include/, lib/,
411
- // share/ as top-level entries, no `wasi-sysroot/` prefix). Runs
412
- // BEFORE the existing fetch loop sees `sysroot.tar`.
413
- repackage: {
414
- upstream_url:
415
- 'https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sysroot-19.0.tar.gz',
416
- // sha256 of the upstream .tar.gz, captured 2026-05-11.
417
- // Falsification: bundle-runtime.mjs verifies this on every run.
418
- upstream_sha256:
419
- 'd601c901a26d6cdb158e60c8a981caa189e87875abc23bb071c2c533a39fd143',
420
- // Subdir inside the extracted tarball whose children become the
421
- // top-level entries of the produced sysroot.tar.
422
- strip_prefix: 'wasi-sysroot',
423
- // Directories at strip_prefix to include in the produced sysroot.tar.
424
- // Anything else under wasi-sysroot/ is dropped.
425
- include_dirs: ['include', 'lib', 'share'],
426
- // Expected sha256 of the *produced* sysroot.tar. Captured from a
427
- // dry-run inspection at /tmp/sysroot-prep-work/ (see prep audit).
428
- // Verified before upload; abort on mismatch.
429
- output_sha256:
430
- '82f30ed81d39072d54e3ba207305c26bfc29a7726e500230db3cad8abe828be3',
431
- // Expected raw byte size of the produced sysroot.tar.
432
- output_size: 11898880,
433
- },
434
- // license_text intentionally omitted — ingest_only mode skips the
435
- // bundled LICENSE write. The swap wave composes a concat-license
436
- // (binji + wasi-libc) at manifest time.
437
- },
438
- };
439
-
440
149
  const key = `${RUNTIME}/${VERSION}`;
441
150
  const spec = SPECS[key];
442
151
  if (!spec) {
@@ -470,6 +179,8 @@ if (NPM_OUT_DIR) {
470
179
  const workDir = join(tmpdir(), `bundle-runtime-${RUNTIME}-${VERSION}`);
471
180
  rmSync(workDir, { recursive: true, force: true });
472
181
  mkdirSync(workDir, { recursive: true });
182
+ // Scratch for this run only (every run starts it empty): removed however the run ends.
183
+ process.on('exit', () => rmSync(workDir, { recursive: true, force: true }));
473
184
 
474
185
  console.log(`[bundle-runtime] ${RUNTIME} ${VERSION}`);
475
186
  console.log(`[bundle-runtime] work dir: ${workDir}`);
@@ -819,6 +530,7 @@ function pinCatalogFromR2() {
819
530
  const workDir = join(tmpdir(), `nimbus-catalog-pin-${process.pid}`);
820
531
  mkdirSync(workDir, { recursive: true });
821
532
  const local = join(workDir, 'catalog.json');
533
+ // Failures return rather than process.exit, so the finally removes the download either way.
822
534
  try {
823
535
  const result = spawnSync(
824
536
  WRANGLER,
@@ -829,7 +541,8 @@ function pinCatalogFromR2() {
829
541
  console.error(`ERROR: could not read catalog/v1.json from '${BUCKET}'; the pin is unchanged.`);
830
542
  const detail = (result.stderr || '').trim();
831
543
  if (detail) console.error(` ${detail.split('\n').slice(-3).join('\n ')}`);
832
- process.exit(1);
544
+ process.exitCode = 1;
545
+ return;
833
546
  }
834
547
  const bytes = readFileSync(local);
835
548
  // A pin over bytes that are not the catalog would disable the cache on
@@ -839,11 +552,13 @@ function pinCatalogFromR2() {
839
552
  parsed = JSON.parse(bytes.toString('utf8'));
840
553
  } catch (e) {
841
554
  console.error(`ERROR: catalog/v1.json is not valid JSON (${e.message}); refusing to pin it`);
842
- process.exit(1);
555
+ process.exitCode = 1;
556
+ return;
843
557
  }
844
558
  if (!parsed || typeof parsed.runtimes !== 'object' || parsed.runtimes === null) {
845
559
  console.error('ERROR: catalog/v1.json has no runtimes object; refusing to pin it');
846
- process.exit(1);
560
+ process.exitCode = 1;
561
+ return;
847
562
  }
848
563
  console.log(`[bundle-runtime] catalog lists: ${Object.keys(parsed.runtimes).join(', ') || '(none)'}`);
849
564
  writeCatalogPin(bytes);
@@ -955,17 +670,18 @@ function writeNpmPackage(outDir, manifest, downloaded) {
955
670
  files: ['index.js', 'index.d.ts', 'manifest.json', 'blobs', 'LICENSE', 'README.md'],
956
671
  // The runtime is inert without the half that installs and runs it, and
957
672
  // `index.d.ts` types itself against that package's exports. The floor is
958
- // the core release whose FacetHost carries every runner generated from
959
- // this tree — earlier cores would seed the files and then have no
960
- // command to run them.
961
- peerDependencies: { '@nimbus-sh/core': '>=0.4.0' },
673
+ // the first core release that registers every runner this manifest names:
674
+ // an earlier core seeds the files and then has no command to run them.
675
+ peerDependencies: { '@nimbus-sh/core': spec.npm.core ?? '>=0.4.0' },
962
676
  publishConfig: { access: 'public' },
963
677
  }, null, 2)}\n`);
964
678
 
965
679
  console.log(`\n[bundle-runtime] DONE (npm package)`);
966
680
  console.log(`[bundle-runtime] ${spec.npm.name}@${npmVersion} → ${outDir}`);
967
681
  console.log(`[bundle-runtime] ${written.size} blobs, ${(unpackedBytes / 1024 / 1024).toFixed(2)} MiB unpacked`);
968
- console.log(`[bundle-runtime] publish with: npm publish ${outDir}`);
682
+ // `--tag latest` because a rebuild (`5.2.37-2`) sorts below the build it
683
+ // replaces; see packages/core/scripts/check-runtime-packages.mjs.
684
+ console.log(`[bundle-runtime] publish with: cd ${outDir} && npm publish --tag latest --access public --auth-type=web`);
969
685
  console.log(`[bundle-runtime] R2: UNTOUCHED (nothing was read from or written to Cloudflare)`);
970
686
  }
971
687
 
@@ -1304,122 +1020,3 @@ function runRepackage(rep, workDir) {
1304
1020
  process.exit(3);
1305
1021
  }
1306
1022
  }
1307
-
1308
- // ── Bundled LICENSE text generator ────────────────────────────────
1309
- function GPL_3_LICENSE_NOTICE() {
1310
- return `GNU bash 5.2.37 — GPL-3.0-or-later
1311
- Copyright (C) Free Software Foundation, Inc.
1312
-
1313
- This runtime bundles GNU bash cross-compiled to wasm32-wasi. Full
1314
- license text: https://www.gnu.org/licenses/gpl-3.0.txt
1315
- Corresponding source: https://ftp.gnu.org/gnu/bash/bash-5.2.37.tar.gz
1316
- plus the Nimbus build overlay (packages/worker/wasm/bash/ in the
1317
- Nimbus repository: nimbus-proc.{h,c}, build-bash.sh, coreutils/).
1318
-
1319
- BusyBox 1.37.0 — GPL-2.0-only
1320
- Copyright (C) many authors, 1998-2015. See the source distribution.
1321
-
1322
- The coreutils exec targets (ls, cat, grep, sed, awk, find, ...) are
1323
- BusyBox cross-compiled to wasm32-wasi as one multicall binary. Full
1324
- license text: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
1325
- Corresponding source: https://busybox.net/downloads/busybox-1.37.0.tar.bz2
1326
- plus the Nimbus build overlay (packages/worker/wasm/bash/coreutils/ in
1327
- the Nimbus repository: build-busybox.sh, wasi-shim.c, overlay/).
1328
- `;
1329
- }
1330
-
1331
- function PSF_LICENSE_NOTICE() {
1332
- return [
1333
- 'Python is distributed under the Python Software Foundation License',
1334
- 'Version 2. The full text is at https://docs.python.org/3/license.html',
1335
- 'and is included in the interpreter as Lib/LICENSE.txt.',
1336
- '',
1337
- 'Copyright (c) 2001-2026 Python Software Foundation. All Rights Reserved.',
1338
- '',
1339
- 'This build is CPython 3.13.14 cross-compiled for wasm32-wasi and',
1340
- 'statically linked against zlib (zlib licence), bzip2 (BSD-like), xz',
1341
- 'liblzma (0BSD), SQLite (public domain) and OpenSSL 3.5 (Apache-2.0).',
1342
- 'Each of those carries its own licence, reproduced by its upstream.',
1343
- '',
1344
- ].join('\n');
1345
- }
1346
-
1347
- function MPL_2_LICENSE_TEXT() {
1348
- // Mozilla Public License 2.0 — Pyodide is MPL-2.0-licensed. We
1349
- // ship an abbreviated header pointing at the canonical text; the
1350
- // LICENSE file lives next to the runtime install dir as a
1351
- // disclosure to the user.
1352
- return [
1353
- '==============================================================================',
1354
- 'Pyodide is licensed under the Mozilla Public License Version 2.0:',
1355
- '==============================================================================',
1356
- '',
1357
- 'Copyright (c) 2018-present Pyodide contributors.',
1358
- '',
1359
- 'Full license: https://www.mozilla.org/en-US/MPL/2.0/',
1360
- '',
1361
- 'Pyodide source: https://github.com/pyodide/pyodide',
1362
- 'Release tarball: https://cdn.jsdelivr.net/pyodide/v0.29.4/full/',
1363
- '',
1364
- 'Bundled in Nimbus for the `nimbus install python` runtime. Python',
1365
- 'itself is under the PSF License Agreement (https://docs.python.org/3/',
1366
- 'license.html); pyodide.asm.wasm contains CPython 3.13 + selected',
1367
- 'standard-library modules statically linked to wasm32-unknown-emscripten.',
1368
- '',
1369
- ].join('\n');
1370
- }
1371
-
1372
- function APACHE_2_LLVM_LICENSE_TEXT() {
1373
- // Apache 2.0 with LLVM exception — abbreviated header pointing at
1374
- // the canonical upstream LICENSE.TXT. We don't redistribute the
1375
- // entire license verbatim here; the LICENSE file in the runtime
1376
- // install dir tells the user where to find the full text.
1377
- return [
1378
- '==============================================================================',
1379
- 'The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:',
1380
- '==============================================================================',
1381
- '',
1382
- 'Copyright (c) The LLVM Project authors.',
1383
- 'Copyright (c) Ben Smith (binji) and contributors to wasm-clang.',
1384
- '',
1385
- 'Full license: https://github.com/llvm/llvm-project/blob/main/LICENSE.TXT',
1386
- '',
1387
- 'binji/wasm-clang source: https://github.com/binji/wasm-clang',
1388
- 'Original CppCon 2019 talk: https://www.youtube.com/watch?v=5N4b-rU-OAA',
1389
- '',
1390
- 'This artifact is a frozen build of LLVM 8.0 from 2018-2020. It is bundled',
1391
- 'in Nimbus under the original LLVM Apache 2.0 + LLVM Exception license.',
1392
- 'See the canonical LICENSE.TXT for the full text including the WebAssembly',
1393
- 'runtime exception clauses.',
1394
- '',
1395
- ].join('\n');
1396
- }
1397
-
1398
- function RUBY_LICENSE_TEXT() {
1399
- // Ruby is dual-licensed under the Ruby License + BSD-2-Clause.
1400
- // ruby.wasm packaging adds MIT for the JS bindings (which we
1401
- // re-implement, so we don't redistribute their JS — only the wasm).
1402
- // The wasm itself carries: Ruby License + BSD-2-Clause for the
1403
- // interpreter, plus various permissive licenses for bundled gems
1404
- // and the C extensions in stdlib.
1405
- return [
1406
- '==============================================================================',
1407
- 'Ruby is dual-licensed under the Ruby License (2-clause variant) and BSD-2-Clause:',
1408
- '==============================================================================',
1409
- '',
1410
- 'Copyright (c) Yukihiro Matsumoto. All rights reserved.',
1411
- '',
1412
- 'Ruby License full text: https://www.ruby-lang.org/en/about/license.txt',
1413
- 'BSD-2-Clause full text: https://opensource.org/license/bsd-2-clause/',
1414
- '',
1415
- 'Ruby source: https://github.com/ruby/ruby',
1416
- 'ruby.wasm source: https://github.com/ruby/ruby.wasm',
1417
- 'Release tarball: https://registry.npmjs.org/@ruby/3.3-wasm-wasi/-/3.3-wasm-wasi-2.9.3-2.9.4.tgz',
1418
- '',
1419
- 'Bundled in Nimbus for the `nimbus install ruby` runtime. ruby+stdlib.wasm',
1420
- 'contains Ruby 3.3.x + the standard library packed via wasi-vfs, compiled',
1421
- 'to wasm32-unknown-wasi. The full Ruby standard library license list is in',
1422
- 'the upstream LEGAL file: https://github.com/ruby/ruby/blob/master/LEGAL.',
1423
- '',
1424
- ].join('\n');
1425
- }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * The installed cf-git copies and whether each carries the tracked patch.
3
+ *
4
+ * `packages/worker/patches/@ashishkumar472+cf-git+1.0.5.patch` rewrites one
5
+ * file, `index.js`. Its `index <pre>..<post>` header names the git blob ids of
6
+ * that file before and after the patch, so a copy's state is exact: its
7
+ * index.js hashes to <post> (patched), to <pre> (pristine), or to neither
8
+ * (foreign: an older or newer revision of the patch, or a hand edit).
9
+ *
10
+ * patch-install-deps.mjs brings every copy to <post>; bundle-git.mjs refuses to
11
+ * bundle a copy that is not at <post>, so a store patched by an older revision
12
+ * can never regenerate the git bundle without the current fixes.
13
+ */
14
+
15
+ import { createHash } from 'node:crypto';
16
+ import { existsSync, readdirSync, readFileSync, realpathSync } from 'node:fs';
17
+ import { spawnSync } from 'node:child_process';
18
+ import { dirname, join, resolve, sep } from 'node:path';
19
+ import { homedir } from 'node:os';
20
+ import { fileURLToPath } from 'node:url';
21
+
22
+ const __dirname = dirname(fileURLToPath(import.meta.url));
23
+
24
+ export const CF_GIT_PATCH = resolve(__dirname, '..', 'patches', '@ashishkumar472+cf-git+1.0.5.patch');
25
+ /** Where bun's cache keeps the pristine package, below the cache directory. */
26
+ const CACHE_ENTRY = join('@ashishkumar472', 'cf-git@1.0.5@@@1');
27
+
28
+ /** The patch's pre- and post-image blob ids (abbreviated, as git writes them). */
29
+ export function patchImages(patch = CF_GIT_PATCH) {
30
+ if (!existsSync(patch)) throw new Error(`Missing tracked cf-git patch: ${patch}`);
31
+ const text = readFileSync(patch, 'utf8');
32
+ if ((text.match(/^diff --git /gm) ?? []).length !== 1 || !/^diff --git a\/index\.js b\/index\.js$/m.test(text)) {
33
+ throw new Error(`${patch}: expected a patch of index.js alone`);
34
+ }
35
+ const header = /^index ([0-9a-f]{7,40})\.\.([0-9a-f]{7,40})(?: \d+)?$/m.exec(text);
36
+ if (!header) throw new Error(`${patch}: no 'index <pre>..<post>' header to verify an install against`);
37
+ return { pre: header[1], post: header[2] };
38
+ }
39
+
40
+ /** `git hash-object` of a file. */
41
+ export function blobId(file) {
42
+ const bytes = readFileSync(file);
43
+ return createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex');
44
+ }
45
+
46
+ /** 'patched' | 'pristine' | 'foreign' | 'missing', by index.js's blob id. */
47
+ export function cfGitState(dir, images = patchImages()) {
48
+ const file = join(dir, 'index.js');
49
+ if (!existsSync(file)) return 'missing';
50
+ const id = blobId(file);
51
+ if (id.startsWith(images.post)) return 'patched';
52
+ if (id.startsWith(images.pre)) return 'pristine';
53
+ return 'foreign';
54
+ }
55
+
56
+ /** node_modules trees at the repo root and one level into packages/* and apps/*. */
57
+ export function findNodeModules(base, depth = 0) {
58
+ if (depth > 5 || !existsSync(base)) return [];
59
+ const out = [];
60
+ let entries;
61
+ try { entries = readdirSync(base, { withFileTypes: true }); }
62
+ catch { return []; }
63
+ for (const ent of entries) {
64
+ if (!ent.isDirectory()) continue;
65
+ if (ent.name === 'node_modules') {
66
+ out.push(join(base, ent.name));
67
+ } else if (ent.name === 'packages' || ent.name === 'apps') {
68
+ for (const sub of readdirSync(join(base, ent.name), { withFileTypes: true })) {
69
+ if (sub.isDirectory()) out.push(...findNodeModules(join(base, ent.name, sub.name), depth + 1));
70
+ }
71
+ }
72
+ }
73
+ return out;
74
+ }
75
+
76
+ /** Real directories of every installed @ashishkumar472/cf-git@1.0.5, however bun laid it out. */
77
+ export function findCfGitDirs(repoRoot) {
78
+ const dirs = new Set();
79
+ for (const nm of findNodeModules(repoRoot)) {
80
+ for (const packagePath of [
81
+ join(nm, 'isomorphic-git', 'package.json'),
82
+ join(nm, '@ashishkumar472', 'cf-git', 'package.json'),
83
+ join(nm, '.bun', '@ashishkumar472+cf-git@1.0.5', 'node_modules', '@ashishkumar472', 'cf-git', 'package.json'),
84
+ ]) {
85
+ if (!existsSync(packagePath)) continue;
86
+ const pkg = JSON.parse(readFileSync(packagePath, 'utf8'));
87
+ if (pkg.name === '@ashishkumar472/cf-git' && pkg.version === '1.0.5') dirs.add(realpathSync(dirname(packagePath)));
88
+ }
89
+ }
90
+ return dirs;
91
+ }
92
+
93
+ /** What to delete so `bun install` lays the copy out again: its store entry, else the package itself. */
94
+ export function storeEntry(dir) {
95
+ const marker = `${sep}node_modules${sep}.bun${sep}`;
96
+ const at = dir.lastIndexOf(marker);
97
+ if (at < 0) return dir;
98
+ return dir.slice(0, at + marker.length) + dir.slice(at + marker.length).split(sep)[0];
99
+ }
100
+
101
+ /** The command that reinstalls `dir` from bun's cache, for a refusal to name. */
102
+ export function reinstallCommand(dir, repoRoot) {
103
+ return `rm -rf '${storeEntry(dir)}' && (cd '${repoRoot}' && bun install)`;
104
+ }
105
+
106
+ /**
107
+ * Throw unless every installed copy carries exactly the tracked patch. `extra`
108
+ * names a copy found another way (the one a bundler resolves), checked too.
109
+ */
110
+ export function assertCfGitPatched(repoRoot, extra = []) {
111
+ const images = patchImages();
112
+ const dirs = findCfGitDirs(repoRoot);
113
+ for (const dir of extra) dirs.add(realpathSync(dir));
114
+ if (dirs.size === 0) throw new Error('No @ashishkumar472/cf-git@1.0.5 installation found');
115
+ const wrong = [...dirs].map((dir) => [dir, cfGitState(dir, images)]).filter(([, state]) => state !== 'patched');
116
+ if (wrong.length === 0) return dirs;
117
+ throw new Error(
118
+ 'cf-git is not patched with the tracked patch (packages/worker/patches/@ashishkumar472+cf-git+1.0.5.patch, '
119
+ + `index.js ${images.pre}..${images.post}), so a bundle built now would lack its fixes:\n`
120
+ + wrong.map(([dir, state]) => ` ${dir}: ${state}\n fix: ${reinstallCommand(dir, repoRoot)}`).join('\n'),
121
+ );
122
+ }
123
+
124
+ /** bun's cache directory: $BUN_INSTALL_CACHE_DIR, else what `bun pm cache` reports, else bun's default. */
125
+ function bunCacheDir() {
126
+ if (process.env.BUN_INSTALL_CACHE_DIR) return process.env.BUN_INSTALL_CACHE_DIR;
127
+ const reported = spawnSync('bun', ['pm', 'cache'], { encoding: 'utf8' });
128
+ if (reported.status === 0 && reported.stdout.trim()) return reported.stdout.trim();
129
+ return join(process.env.BUN_INSTALL || join(homedir(), '.bun'), 'install', 'cache');
130
+ }
131
+
132
+ /** bun's cached, unpatched index.js for cf-git 1.0.5, or null when the cache holds no pristine copy. */
133
+ export function pristineIndexJs(images = patchImages()) {
134
+ const file = join(bunCacheDir(), CACHE_ENTRY, 'index.js');
135
+ if (!existsSync(file)) return null;
136
+ return blobId(file).startsWith(images.pre) ? file : null;
137
+ }