Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ jobs:

- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2

- name: Check browser VM source drift
run: python3 scripts/check_zapcode_browser.py

- name: Check bashkit for wasm32-unknown-unknown
run: cargo check -p bashkit -p bashkit-scripted-tool --target wasm32-unknown-unknown --features bashkit/jq,bashkit/wasm_js,bashkit/terminal
env:
Expand Down Expand Up @@ -175,6 +178,18 @@ jobs:
export CHROME_EXECUTABLE=$(node --input-type=module -e 'const {chromium} = await import(process.env.PLAYWRIGHT_MODULE); console.log(chromium.executablePath())')
node crates/bashkit-wasm/scripts/test-streaming-browser.mjs

- name: Build optional runtime bundle
run: BASHKIT_WASM_VARIANT=runtimes BASHKIT_WASM_FEATURES=terminal,python,typescript bash crates/bashkit-wasm/scripts/build.sh release

- name: Embedded runtime callback tests
run: BASHKIT_WASM_VARIANT=runtimes node --test crates/bashkit-wasm/__test__/runtime-functions.test.mjs

- name: Browser runtime callbacks (Chromium and module workers)
run: |
export PLAYWRIGHT_MODULE="$RUNNER_TEMP/bashkit-browser-test/node_modules/playwright/index.mjs"
export CHROME_EXECUTABLE=$(node --input-type=module -e 'const {chromium} = await import(process.env.PLAYWRIGHT_MODULE); console.log(chromium.executablePath())')
node crates/bashkit-wasm/scripts/test-runtime-browser.mjs

- name: Browser compatibility and transfer-size gates
run: |
node crates/bashkit-wasm/bench/compat.mjs
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/publish-wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ jobs:
- name: Integration tests (headless Node)
run: node --test "crates/bashkit-wasm/__test__/*.test.mjs"

- name: Browser streaming (main thread and worker)
run: |
npm install --prefix "$RUNNER_TEMP/bashkit-browser-test" --no-save playwright@1.62.1
export PLAYWRIGHT_MODULE="$RUNNER_TEMP/bashkit-browser-test/node_modules/playwright/index.mjs"
node "$RUNNER_TEMP/bashkit-browser-test/node_modules/playwright/cli.js" install --with-deps chromium
export CHROME_EXECUTABLE=$(node --input-type=module -e 'const {chromium} = await import(process.env.PLAYWRIGHT_MODULE); console.log(chromium.executablePath())')
node crates/bashkit-wasm/scripts/test-streaming-browser.mjs

- name: Build optional runtime bundle
run: BASHKIT_WASM_VARIANT=runtimes BASHKIT_WASM_FEATURES=terminal,python,typescript bash crates/bashkit-wasm/scripts/build.sh release

- name: Embedded runtime callback tests
run: BASHKIT_WASM_VARIANT=runtimes node --test crates/bashkit-wasm/__test__/runtime-functions.test.mjs

- name: Browser runtime callbacks (Chromium and module workers)
run: |
export PLAYWRIGHT_MODULE="$RUNNER_TEMP/bashkit-browser-test/node_modules/playwright/index.mjs"
export CHROME_EXECUTABLE=$(node --input-type=module -e 'const {chromium} = await import(process.env.PLAYWRIGHT_MODULE); console.log(chromium.executablePath())')
node crates/bashkit-wasm/scripts/test-runtime-browser.mjs

- name: Browser compatibility and transfer-size gates
run: |
node crates/bashkit-wasm/bench/compat.mjs
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions contracts/capability-parity.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@
},
"browser_wasm": {
"label": "Browser WASM",
"supported": ["execution_limits", "cancellation", "deadlines", "output_caps", "cwd", "env", "custom_builtins", "virtual_filesystem", "snapshots"],
"supported": ["execution_limits", "cancellation", "deadlines", "output_caps", "cwd", "env", "custom_builtins", "virtual_filesystem", "snapshots", "runtime_python", "runtime_typescript", "host_functions_python", "host_functions_typescript", "interactive_terminal"],
"evidence": {
"execution_limits": ["crates/bashkit-wasm/__test__/bashkit-wasm.test.mjs#options: maxLoopIterations bounds runaway loops"],
"cancellation": ["crates/bashkit-wasm/__test__/bashkit-wasm.test.mjs#cancel aborts in-flight work and remains sticky until clearCancel"],
Expand All @@ -217,7 +217,12 @@
"env": ["crates/bashkit-wasm/__test__/bashkit-wasm.test.mjs#options: env and cwd"],
"custom_builtins": ["crates/bashkit-wasm/__test__/bashkit-wasm.test.mjs#reset preserves registered custom builtins"],
"virtual_filesystem": ["crates/bashkit-wasm/__test__/bashkit-wasm.test.mjs#bash.fs() returns a live handle"],
"snapshots": ["crates/bashkit-wasm/__test__/bashkit-wasm.test.mjs#commit and checkout restore persistent state"]
"snapshots": ["crates/bashkit-wasm/__test__/bashkit-wasm.test.mjs#commit and checkout restore persistent state"],
"runtime_python": ["crates/bashkit-wasm/__test__/runtime-functions.test.mjs#both browser runtimes share VFS"],
"runtime_typescript": ["crates/bashkit-wasm/__test__/runtime-functions.test.mjs#both browser runtimes share VFS"],
"host_functions_python": ["crates/bashkit-wasm/__test__/runtime-functions.test.mjs#browser host functions, reset and VFS"],
"host_functions_typescript": ["crates/bashkit-wasm/__test__/runtime-functions.test.mjs#browser host functions, reset and VFS"],
"interactive_terminal": ["crates/bashkit-wasm/__test__/terminal.test.mjs#terminal: vi edits a VFS file"]
},
"unsupported": {
"runtime_env": "The slim wasm package exposes no post-construction host mutation API; env is construction-only.",
Expand All @@ -227,12 +232,7 @@
"network_policy": "The slim browser build has no network builtin or host socket access.",
"transport_hooks": "The slim browser build has no HTTP transport.",
"mounts": "Browser WASM exposes one in-memory VFS and no host filesystem mounts.",
"runtime_python": "The slim browser build omits embedded language runtimes.",
"runtime_typescript": "The slim browser build omits embedded language runtimes.",
"runtime_sqlite": "The slim browser build omits embedded language runtimes.",
"interactive_terminal": "Not exposed in the slim browser package yet.",
"host_functions_python": "The slim browser build currently omits embedded language runtimes.",
"host_functions_typescript": "The slim browser build currently omits embedded language runtimes."
"runtime_sqlite": "The slim browser build omits embedded language runtimes."
}
},
"c_abi": {
Expand Down
12 changes: 11 additions & 1 deletion crates/bashkit-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
# app, including embedded/iframe contexts. See knowledge/runtimes/browser-package.md.
#
# Feature surface mirrors the `wasm` CI job (jq). http_client,
# ssh, sqlite, python, realfs, and interop are intentionally excluded: they need
# ssh, sqlite, realfs, and interop are intentionally excluded: they need
# sockets, threads, or a host filesystem that the browser sandbox lacks.
# Python/TypeScript are optional features, published through the /runtimes import.
#
# JS callbacks (js_sys::Function / JsFuture) are `!Send`, but bashkit's `Builtin`
# trait is `Send + Sync` (async_trait). wasm32 is single-threaded, so we bridge
Expand All @@ -32,6 +33,8 @@ publish = false
# `bashkit/terminal`; `scripts/build.sh` turns it on for the npm package because
# it costs ~60 KB gzipped and stays inert until a page constructs `Terminal`.
terminal = ["bashkit/terminal"]
python = ["bashkit/python", "dep:getrandom03"]
typescript = ["bashkit/typescript"]

[lib]
crate-type = ["cdylib", "rlib"]
Expand Down Expand Up @@ -67,3 +70,10 @@ getrandom = { workspace = true, features = ["wasm_js"] }
[package.metadata.wasm-pack.profile.release]
# Keep the shipped .wasm small; the interpreter is large.
wasm-opt = ["-Oz"]

# Monty also uses getrandom 0.3; select its browser backend explicitly.
[dependencies.getrandom03]
package = "getrandom"
version = "0.3"
features = ["wasm_js"]
optional = true
15 changes: 14 additions & 1 deletion crates/bashkit-wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ filesystem there is no built-in VFS underneath to supply it.

Plain bash plus the built-in text tooling (`grep`, `sed`, `awk`, `jq`, `find`,
…) and `jq`. Not included in the browser build: outbound HTTP (`curl`/`wget`),
`ssh`, `sqlite`, and embedded `python`, these need sockets, threads, or a host
`ssh` and `sqlite`, these need sockets, threads, or a host
filesystem the browser sandbox doesn't provide. Bridge to the network through a
custom builtin (see above) so requests go through your app's own `fetch`.

Expand Down Expand Up @@ -320,3 +320,16 @@ node crates/bashkit-wasm/bench/artifact.mjs crates/bashkit-wasm/pkg --check

The [browser benchmark methodology](https://github.com/everruns/bashkit/blob/main/crates/bashkit-wasm/bench/README.md) describes reproducible
cold-start and execution experiments and the measured profile tradeoff.

## Optional Python/TypeScript and host functions

Import `@everruns/bashkit-wasm/runtimes` for the runtime-enabled single-threaded
bundle; the default import stays slim. Enable `python`/`typescript` explicitly
and pass `externalFunctions`/`externalHandler` (Python) or
`typescriptExternalFunctions`/`typescriptExternalHandler` (TypeScript).
Callbacks support JSON values and an execution-local AbortSignal. Use async
`Bash.execute`, with one active execution per instance. See the
[host function guide](../../docs/start-browser.md#python-and-typescript-host-functions).

Build both variants with `scripts/build.sh release`, followed by
`BASHKIT_WASM_VARIANT=runtimes BASHKIT_WASM_FEATURES=terminal,python,typescript scripts/build.sh release`.
Loading
Loading