From da63f1d5ebe48cd1275c4eb4567294ddd221b46b Mon Sep 17 00:00:00 2001 From: Mykhailo Chalyi Date: Mon, 26 Oct 2026 01:41:58 +0000 Subject: [PATCH 1/2] chore(release): prepare v0.20.1 Fix Windows CPython COFF compilation with the existing cached 64 KiB-aligned allocation path. Cover embedding object generation and native Windows, Apple and ELF module loading/execution. Part of EVE-1311. --- .github/workflows/ci.yml | 39 +++++++++++++- CHANGELOG.md | 12 +++++ Cargo.lock | 22 ++++---- Cargo.toml | 2 +- README.md | 2 +- crates/bashkit-cli/Cargo.toml | 2 +- crates/bashkit-cpython-wasm/src/lib.rs | 15 +++--- crates/bashkit-js/package.json | 2 +- crates/bashkit-scripted-tool/Cargo.toml | 2 +- crates/bashkit-wasm/package.json | 2 +- crates/bashkit/Cargo.toml | 2 +- crates/bashkit/docs/cpython.md | 4 +- crates/bashkit/docs/logging.md | 2 +- crates/bashkit/docs/sqlite.md | 2 +- crates/bashkit/fuzz/Cargo.lock | 4 +- crates/bashkit/src/lib.rs | 4 +- docs/builtin_typescript.md | 2 +- docs/migrating-scripted-tool.md | 4 +- examples/hyperlight/Cargo.lock | 2 +- knowledge/runtimes/cpython-wasm.md | 11 +++- scripts/tests/test_cpython_embedding.py | 68 +++++++++++++++++++++++++ 21 files changed, 165 insertions(+), 40 deletions(-) create mode 100644 scripts/tests/test_cpython_embedding.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d144507e4..d1394d42a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -386,6 +386,42 @@ jobs: env: PROPTEST_CASES: 50 + cpython-platforms: + # COFF rejects 64 KiB-aligned statics; Mach-O can lose their alignment at + # load time. Keep the actual embedding, module load and execution covered. + name: CPython (${{ matrix.os }}, Rust ${{ matrix.rust }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + rust: "1.95.0" + - os: macos-latest + rust: "1.95.0" + - os: windows-2025 + rust: "1.96.0" + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0 + with: + toolchain: ${{ matrix.rust }} + + - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2 + + - name: Probe embedding object generation and aligned storage + run: python -m unittest discover -s scripts/tests -p test_cpython_embedding.py -v + + - name: Test CPython module loading and alignment + run: cargo test --locked -p bashkit-cpython-wasm --lib + + - name: Execute CPython through the shell + run: cargo test --locked -p bashkit --features cpython --test integration -- cpython_integration_tests + windows-containment: # THREAT[TM-ESC-033]: Windows path parsing has drive, UNC, device, and # reparse-point semantics that cannot be exercised on a Unix runner. @@ -624,7 +660,7 @@ jobs: check: name: Check if: always() - needs: [lint, audit, test, windows-containment, test-windows, examples, fuzz-check, wasm, wasm-component, wasm-web] + needs: [lint, audit, test, cpython-platforms, windows-containment, test-windows, examples, fuzz-check, wasm, wasm-component, wasm-web] runs-on: ubuntu-latest steps: - name: Verify all jobs passed @@ -632,6 +668,7 @@ jobs: if [[ "${{ needs.lint.result }}" != "success" ]] || \ [[ "${{ needs.audit.result }}" != "success" ]] || \ [[ "${{ needs.test.result }}" != "success" ]] || \ + [[ "${{ needs.cpython-platforms.result }}" != "success" ]] || \ [[ "${{ needs.windows-containment.result }}" != "success" ]] || \ [[ "${{ needs.test-windows.result }}" != "success" ]] || \ [[ "${{ needs.examples.result }}" != "success" ]] || \ diff --git a/CHANGELOG.md b/CHANGELOG.md index 13adb8fac..5cdcf2010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.20.1] - 2026-10-25 + +### Highlights + +- **Windows CPython builds.** The embedded CPython module uses a plain static slice on Windows and caches a 64 KiB-aligned copy at runtime, avoiding the Rust compiler trap when generating Windows COFF objects. Python and the hosted integration catalog remain available. +- **Complete npm runtime files.** The npm publish artifact includes `runtime-functions.js` and its declarations so importing the package succeeds. + +### What's Changed + +- fix(cpython): avoid unsupported over-aligned statics on Windows (EVE-1311). +- fix(release): ship runtime-functions.js in the npm publish artifact ([#2776](https://github.com/everruns/bashkit/pull/2776)). + ## [0.20.0] - 2026-10-25 ### Highlights diff --git a/Cargo.lock b/Cargo.lock index b734e217d..cb0fe5770 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,7 +357,7 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bashkit" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "async-trait", @@ -438,7 +438,7 @@ dependencies = [ [[package]] name = "bashkit-bench" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "bashkit", @@ -453,7 +453,7 @@ dependencies = [ [[package]] name = "bashkit-capi" -version = "0.20.0" +version = "0.20.1" dependencies = [ "bashkit", "serde", @@ -463,7 +463,7 @@ dependencies = [ [[package]] name = "bashkit-cli" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "bashkit", @@ -477,7 +477,7 @@ dependencies = [ [[package]] name = "bashkit-coreutils-port" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "prettyplease", @@ -491,7 +491,7 @@ dependencies = [ [[package]] name = "bashkit-cpython-wasm" -version = "0.20.0" +version = "0.20.1" dependencies = [ "lzma-rs", "wasmtime", @@ -499,7 +499,7 @@ dependencies = [ [[package]] name = "bashkit-eval" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "async-trait", @@ -517,7 +517,7 @@ dependencies = [ [[package]] name = "bashkit-js" -version = "0.20.0" +version = "0.20.1" dependencies = [ "bashkit", "bashkit-scripted-tool", @@ -531,7 +531,7 @@ dependencies = [ [[package]] name = "bashkit-python" -version = "0.20.0" +version = "0.20.1" dependencies = [ "bashkit", "bashkit-scripted-tool", @@ -544,7 +544,7 @@ dependencies = [ [[package]] name = "bashkit-scripted-tool" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "async-trait", @@ -560,7 +560,7 @@ dependencies = [ [[package]] name = "bashkit-wasm" -version = "0.20.0" +version = "0.20.1" dependencies = [ "bashkit", "console_error_panic_hook", diff --git a/Cargo.toml b/Cargo.toml index f95017697..9dc4101e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ resolver = "2" members = ["crates/*"] [workspace.package] -version = "0.20.0" +version = "0.20.1" edition = "2024" license = "MIT" authors = ["Mykhailo Chalyi ", "Everruns"] diff --git a/README.md b/README.md index 1e088ba7f..bd3f9fde6 100644 --- a/README.md +++ b/README.md @@ -442,7 +442,7 @@ Enable the `sqlite` feature to embed [Turso](https://github.com/tursodatabase/tu ```toml [dependencies] -bashkit = { version = "0.20.0", features = ["sqlite"] } +bashkit = { version = "0.20.1", features = ["sqlite"] } ``` ```rust diff --git a/crates/bashkit-cli/Cargo.toml b/crates/bashkit-cli/Cargo.toml index b71a55e70..39bd69f18 100644 --- a/crates/bashkit-cli/Cargo.toml +++ b/crates/bashkit-cli/Cargo.toml @@ -39,7 +39,7 @@ interactive = ["dep:rustyline", "dep:terminal_size", "dep:signal-hook"] # `tzdata` is listed explicitly: an interactive shell must keep honouring # named `TZ=` zones in `date`, which stopped being implied when chrono-tz # moved behind a feature. -bashkit = { path = "../bashkit", version = "0.20.0", default-features = false, features = ["http_client", "ring", "git", "jq", "tzdata"] } +bashkit = { path = "../bashkit", version = "0.20.1", default-features = false, features = ["http_client", "ring", "git", "jq", "tzdata"] } tokio = { workspace = true, features = ["macros", "net", "rt", "rt-multi-thread", "time", "io-std"] } clap.workspace = true anyhow.workspace = true diff --git a/crates/bashkit-cpython-wasm/src/lib.rs b/crates/bashkit-cpython-wasm/src/lib.rs index 7f3c51b75..8247590cf 100644 --- a/crates/bashkit-cpython-wasm/src/lib.rs +++ b/crates/bashkit-cpython-wasm/src/lib.rs @@ -32,17 +32,18 @@ pub static STDLIB_ZIP: &[u8] = include_bytes!("../artifacts/python314.zip"); // Wasmtime maps data segments from immutable host-page-aligned bytes. Keep // 64 KiB alignment for every supported host. Mach-O only preserves host-page -// alignment through linking/ASLR; do not form an over-aligned Rust reference -// there. Cache a padded, aligned copy once when the embedded slice needs one. +// alignment through linking/ASLR, and Windows COFF cannot encode a 64 KiB +// aligned static. Do not form an over-aligned Rust reference on those hosts. +// Cache a padded, aligned copy once when the embedded slice needs one. const MODULE_ALIGNMENT: usize = 65536; -#[cfg(not(target_vendor = "apple"))] +#[cfg(not(any(target_vendor = "apple", windows)))] #[repr(C, align(65536))] struct Aligned(T); -#[cfg(not(target_vendor = "apple"))] +#[cfg(not(any(target_vendor = "apple", windows)))] static CWASM: &Aligned<[u8]> = &Aligned(*include_bytes!(concat!(env!("OUT_DIR"), "/python.cwasm"))); -#[cfg(target_vendor = "apple")] +#[cfg(any(target_vendor = "apple", windows))] static CWASM: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/python.cwasm")); struct PaddedModule { @@ -73,9 +74,9 @@ impl PaddedModule { /// Precompiled module bytes (Pulley, or native with the `native` feature) (for diagnostics and size reporting). /// The returned slice is immutable and 64 KiB aligned for the process lifetime. pub fn cwasm_bytes() -> &'static [u8] { - #[cfg(not(target_vendor = "apple"))] + #[cfg(not(any(target_vendor = "apple", windows)))] let bytes: &[u8] = &CWASM.0; - #[cfg(target_vendor = "apple")] + #[cfg(any(target_vendor = "apple", windows))] let bytes = CWASM; if bytes.as_ptr().align_offset(MODULE_ALIGNMENT) == 0 { return bytes; diff --git a/crates/bashkit-js/package.json b/crates/bashkit-js/package.json index c7855951f..584e162e5 100644 --- a/crates/bashkit-js/package.json +++ b/crates/bashkit-js/package.json @@ -1,6 +1,6 @@ { "name": "@everruns/bashkit", - "version": "0.20.0", + "version": "0.20.1", "description": "Sandboxed bash interpreter for JavaScript/TypeScript", "packageManager": "pnpm@10.33.0", "main": "wrapper.js", diff --git a/crates/bashkit-scripted-tool/Cargo.toml b/crates/bashkit-scripted-tool/Cargo.toml index 887c1a7a8..5c7fff317 100644 --- a/crates/bashkit-scripted-tool/Cargo.toml +++ b/crates/bashkit-scripted-tool/Cargo.toml @@ -30,7 +30,7 @@ jq = ["bashkit/jq"] tracing = ["dep:tracing"] [dependencies] -bashkit = { path = "../bashkit", version = "0.20.0", default-features = false, features = ["bash_tool"] } +bashkit = { path = "../bashkit", version = "0.20.1", default-features = false, features = ["bash_tool"] } tokio = { workspace = true } async-trait = { workspace = true } tower = { workspace = true } diff --git a/crates/bashkit-wasm/package.json b/crates/bashkit-wasm/package.json index 6a19cf377..03cfd66c2 100644 --- a/crates/bashkit-wasm/package.json +++ b/crates/bashkit-wasm/package.json @@ -1,6 +1,6 @@ { "name": "@everruns/bashkit-wasm", - "version": "0.20.0", + "version": "0.20.1", "description": "Sandboxed bash interpreter for the browser (WebAssembly). Single-threaded \u2014 no SharedArrayBuffer, no COOP/COEP headers.", "type": "module", "main": "index.js", diff --git a/crates/bashkit/Cargo.toml b/crates/bashkit/Cargo.toml index 5634b2218..0725ee2e9 100644 --- a/crates/bashkit/Cargo.toml +++ b/crates/bashkit/Cargo.toml @@ -143,7 +143,7 @@ monty = { version = "=0.0.19", optional = true } # Real CPython 3.14 as a WASI guest, precompiled to Pulley (cpython feature). # See knowledge/runtimes/cpython-wasm.md. -bashkit-cpython-wasm = { path = "../bashkit-cpython-wasm", version = "0.20.0", optional = true } +bashkit-cpython-wasm = { path = "../bashkit-cpython-wasm", version = "0.20.1", optional = true } wasmtime = { workspace = true, optional = true, features = ["pooling-allocator"] } monty-types = { version = "=0.0.19", optional = true } # Monty's ruff AST uses compact_str 0.9; get-size2 >=0.10.2 only implements diff --git a/crates/bashkit/docs/cpython.md b/crates/bashkit/docs/cpython.md index f13931f07..f533b576f 100644 --- a/crates/bashkit/docs/cpython.md +++ b/crates/bashkit/docs/cpython.md @@ -19,7 +19,7 @@ Enable the `cpython` cargo feature and register the builtins: ```toml [dependencies] -bashkit = { version = "0.20.0", features = ["cpython"] } +bashkit = { version = "0.20.1", features = ["cpython"] } ``` ```rust @@ -242,7 +242,7 @@ executable memory. Enable `cpython-native` instead of `cpython` to compile it to machine code for your target at build time: ```toml -bashkit = { version = "0.20.0", features = ["cpython-native"] } +bashkit = { version = "0.20.1", features = ["cpython-native"] } ``` Calls get 4-10x faster (`print(1)` ~1 ms instead of ~4 ms; CPU-bound code diff --git a/crates/bashkit/docs/logging.md b/crates/bashkit/docs/logging.md index 51923b94c..1fb9a8c33 100644 --- a/crates/bashkit/docs/logging.md +++ b/crates/bashkit/docs/logging.md @@ -14,7 +14,7 @@ Add the `logging` feature to your `Cargo.toml`: ```toml [dependencies] -bashkit = { version = "0.20.0", features = ["logging"] } +bashkit = { version = "0.20.1", features = ["logging"] } tracing-subscriber = "0.3" # or your preferred subscriber ``` diff --git a/crates/bashkit/docs/sqlite.md b/crates/bashkit/docs/sqlite.md index e3c0a3be8..846daf88e 100644 --- a/crates/bashkit/docs/sqlite.md +++ b/crates/bashkit/docs/sqlite.md @@ -13,7 +13,7 @@ the `sqlite` feature. The engine is [Turso](https://github.com/tursodatabase/tur ```toml # Cargo.toml -bashkit = { version = "0.20.0", features = ["sqlite"] } +bashkit = { version = "0.20.1", features = ["sqlite"] } ``` ```rust,ignore diff --git a/crates/bashkit/fuzz/Cargo.lock b/crates/bashkit/fuzz/Cargo.lock index 2a77566da..aa17572c4 100644 --- a/crates/bashkit/fuzz/Cargo.lock +++ b/crates/bashkit/fuzz/Cargo.lock @@ -90,7 +90,7 @@ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" [[package]] name = "bashkit" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "async-trait", @@ -140,7 +140,7 @@ dependencies = [ [[package]] name = "bashkit-cpython-wasm" -version = "0.20.0" +version = "0.20.1" dependencies = [ "lzma-rs", "wasmtime", diff --git a/crates/bashkit/src/lib.rs b/crates/bashkit/src/lib.rs index d669a8a6b..279d0f279 100644 --- a/crates/bashkit/src/lib.rs +++ b/crates/bashkit/src/lib.rs @@ -323,7 +323,7 @@ //! //! ```toml //! [dependencies] -//! bashkit = { version = "0.20.0", features = ["git"] } +//! bashkit = { version = "0.20.1", features = ["git"] } //! ``` //! //! ```rust,ignore @@ -354,7 +354,7 @@ //! //! ```toml //! [dependencies] -//! bashkit = { version = "0.20.0", features = ["python"] } +//! bashkit = { version = "0.20.1", features = ["python"] } //! ``` //! //! ```rust,ignore diff --git a/docs/builtin_typescript.md b/docs/builtin_typescript.md index 77c9304a0..1aa9bf90b 100644 --- a/docs/builtin_typescript.md +++ b/docs/builtin_typescript.md @@ -12,7 +12,7 @@ Add the `typescript` feature to your `Cargo.toml`: ```toml [dependencies] -bashkit = { version = "0.20.0", features = ["typescript"] } +bashkit = { version = "0.20.1", features = ["typescript"] } ``` Enable TypeScript in the builder: diff --git a/docs/migrating-scripted-tool.md b/docs/migrating-scripted-tool.md index 13f20ccfd..8b34e7e0d 100644 --- a/docs/migrating-scripted-tool.md +++ b/docs/migrating-scripted-tool.md @@ -23,8 +23,8 @@ features = ["scripted_tool", "python", "typescript", "jq"] After: ```toml -bashkit = { version = "0.20.0", features = ["python", "typescript", "jq"] } -bashkit-scripted-tool = { version = "0.20.0", features = ["python", "typescript", "jq"] } +bashkit = { version = "0.20.1", features = ["python", "typescript", "jq"] } +bashkit-scripted-tool = { version = "0.20.1", features = ["python", "typescript", "jq"] } ``` Keep `bashkit` only if you use it directly (`Bash`, `BashTool`, the `Tool` diff --git a/examples/hyperlight/Cargo.lock b/examples/hyperlight/Cargo.lock index 3875d6804..f4a11897f 100644 --- a/examples/hyperlight/Cargo.lock +++ b/examples/hyperlight/Cargo.lock @@ -69,7 +69,7 @@ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" [[package]] name = "bashkit" -version = "0.20.0" +version = "0.20.1" dependencies = [ "anyhow", "async-trait", diff --git a/knowledge/runtimes/cpython-wasm.md b/knowledge/runtimes/cpython-wasm.md index b97eb127f..d5a2e3350 100644 --- a/knowledge/runtimes/cpython-wasm.md +++ b/knowledge/runtimes/cpython-wasm.md @@ -66,8 +66,15 @@ call: embed a byte slice rather than an over-aligned Rust reference. If its runtime address is not 64 KiB aligned, one immutable padded `Vec` copy is cached for the process lifetime; retaining the allocation preserves the chosen aligned - offset. Other hosts retain the aligned static fast path. The original - 64 KiB pointer assertion plus byte-preservation tests cover this contract. + offset. Windows uses the same plain-slice path: COFF cannot encode 64 KiB + static alignment (Rust 1.96.0 traps during object generation). Reducing + the runtime alignment to COFF's 8 KiB limit would violate Wasmtime's + requirements. ELF hosts retain the aligned static fast path. The original + 64 KiB pointer assertion plus byte-preservation tests cover this contract; + `scripts/tests/test_cpython_embedding.py` compiles the real embedding with + a tiny payload and checks object generation, byte preservation, alignment + and process-lifetime caching, including concurrent access. CI runs it and + actual module loading/Python execution on Windows, Apple and ELF hosts. 4. **Copy-on-write instances**: `memory_init_cow` + `memory_guaranteed_dense_image_size(128 MB)` map the ~40 MB snapshot heap instead of copying it (without the dense image every instantiation copied diff --git a/scripts/tests/test_cpython_embedding.py b/scripts/tests/test_cpython_embedding.py new file mode 100644 index 000000000..2e2d6a516 --- /dev/null +++ b/scripts/tests/test_cpython_embedding.py @@ -0,0 +1,68 @@ +"""Compile the real CPython embedding without Wasmtime or the large artifact. + +COFF cannot encode a 64 KiB-aligned static. Probe the production embedding +with a tiny payload so Windows object generation stays a cheap regression test. +On ELF, also select the Windows cfg to exercise the plain-slice allocation path. +""" + +from __future__ import annotations + +import os +import pathlib +import shutil +import subprocess +import sys +import tempfile +import unittest + +ROOT = pathlib.Path(__file__).resolve().parents[2] +SOURCE = ROOT / "crates/bashkit-cpython-wasm/src/lib.rs" + +PROBE = """ +fn main() { + #[cfg(any(windows, target_vendor = "apple"))] + let embedded: &[u8] = CWASM; + #[cfg(not(any(windows, target_vendor = "apple")))] + let embedded: &[u8] = &CWASM.0; + let bytes = cwasm_bytes(); + assert_eq!(bytes, embedded); + assert_eq!(bytes.as_ptr() as usize % 65536, 0); + assert_eq!(bytes.as_ptr(), cwasm_bytes().as_ptr()); + for thread in (0..4).map(|_| std::thread::spawn(cwasm_bytes)).collect::>() { + assert_eq!(bytes.as_ptr(), thread.join().unwrap().as_ptr()); + } +} +""" + + +@unittest.skipUnless(shutil.which("rustc"), "rustc required for embedding probe") +class CPythonEmbeddingTests(unittest.TestCase): + def probe(self, cfg: list[str]) -> None: + source = SOURCE.read_text() + # Use the actual statics, padded allocation and accessor, without the + # Wasmtime API/build script. Changes to their cfg must reach this probe. + embedding = source[source.index("const MODULE_ALIGNMENT"):source.index("/// Create an engine")] + with tempfile.TemporaryDirectory() as directory: + root = pathlib.Path(directory) + (root / "python.cwasm").write_bytes(bytes(range(64))) + probe = root / "probe.rs" + probe.write_text(embedding + PROBE) + env = dict(os.environ, OUT_DIR=str(root)) + command = ["rustc", "--edition=2024", str(probe), *cfg] + # Object generation is the original compiler-crash reproducer. + for args in (["--emit=obj", "-o", str(root / "probe.obj")], + ["-o", str(root / "probe.exe")]): + result = subprocess.run(command + args, env=env, capture_output=True, text=True) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + subprocess.run([str(root / "probe.exe")], check=True) + + def test_host_embedding(self) -> None: + self.probe([]) + + @unittest.skipIf(sys.platform in ("win32", "darwin"), "host already uses the plain slice") + def test_windows_plain_slice_on_elf(self) -> None: + self.probe(["--cfg", "windows", "-Aexplicit_builtin_cfgs_in_flags"]) + + +if __name__ == "__main__": + unittest.main() From ab2f445ad656f0f4235f4519904e4f8d37635b3c Mon Sep 17 00:00:00 2001 From: Mykhailo Chalyi Date: Mon, 26 Oct 2026 01:42:49 +0000 Subject: [PATCH 2/2] chore(release): link patch release evidence --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cdcf2010..713af9ded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,8 @@ ### Highlights -- **Windows CPython builds.** The embedded CPython module uses a plain static slice on Windows and caches a 64 KiB-aligned copy at runtime, avoiding the Rust compiler trap when generating Windows COFF objects. Python and the hosted integration catalog remain available. -- **Complete npm runtime files.** The npm publish artifact includes `runtime-functions.js` and its declarations so importing the package succeeds. +- **Windows CPython builds.** The embedded CPython module uses a plain static slice on Windows and caches a 64 KiB-aligned copy at runtime, avoiding the Rust compiler trap when generating Windows COFF objects. Python and the hosted integration catalog remain available ([#2777](https://github.com/everruns/bashkit/pull/2777)). +- **Complete npm runtime files.** The npm publish artifact includes `runtime-functions.js` and its declarations so importing the package succeeds ([#2776](https://github.com/everruns/bashkit/pull/2776)). ### What's Changed