plan: keep default crate wasm-clean; split tokio features for local
The default crate (no features) must compile to wasm32-unknown-unknown so the downstream TS/Python adapter story works — a wasm-compiled alktty is the protocol layer for a sandboxed adapter. The local feature is inherently non-wasm (portable-pty + tokio::process need a real OS) and enabling it on wasm is a build error by design. Cargo.toml: - tokio: drop features = ["full"], use the wasm-clean subset alkcall uses (rt, sync, io-util, macros) with default-features = false - local feature adds tokio/process + tokio/rt-multi-thread - document the wasm constraint in the [features] comment Plan: - Decision 1: add WASM target subsection recording the constraint - Phase 0: mark the tokio feature split as done - Risks: add WASM-target-regression risk with a cargo-check CI mitigation
This commit is contained in:
@@ -150,6 +150,29 @@ doesn't exist in a single crate. A docker or SSH backend would still
|
||||
be a separate crate — those have real external deps (`bollard`,
|
||||
`russh`) and their own resource models.
|
||||
|
||||
**WASM target.** The default crate (no `local` feature) MUST compile
|
||||
to `wasm32-unknown-unknown`. alkcall and alktype both target wasm;
|
||||
keeping alktty wasm-clean is what makes the downstream TS/Python
|
||||
adapter story work — a wasm-compiled alktty is the protocol layer for
|
||||
a sandboxed adapter (browser terminal over WebTransport, a Python
|
||||
wheel that shells out to a wasm module, etc.). The `local` feature is
|
||||
inherently non-wasm (`portable-pty` needs a real OS, `tokio::process`
|
||||
needs `spawn`), so enabling `local` on wasm is a build error by
|
||||
design — the local-process backend runs on a real OS (Linux, macOS,
|
||||
Windows), never in a sandbox.
|
||||
|
||||
Concretely, `Cargo.toml` uses `tokio = { default-features = false,
|
||||
features = ["rt", "sync", "io-util", "macros"] }` (the wasm-clean
|
||||
subset alkcall uses) and `local` adds `tokio/process` +
|
||||
`tokio/rt-multi-thread`. Do NOT use `features = ["full"]` — it pulls
|
||||
in `signal`/`fs`/`net` which break `wasm32-unknown-unknown`. The
|
||||
adapter's `tokio::spawn` for per-session pumps is fine on wasm (the
|
||||
wasm tokio runtime supports `spawn`); the `local` module's std
|
||||
threads and `tokio::process::Command` are the non-wasm parts, and
|
||||
they're feature-gated. `libc` stays under `cfg(unix)` (it's already
|
||||
there for `signal_from_name` and the pipe-mode `kill` path — neither
|
||||
runs on wasm because the only callers are in `local`).
|
||||
|
||||
### 2. Dependency: `alknet-core` → `alkcall::core`
|
||||
|
||||
All types previously from `alknet-core` now come from `alkcall::core`:
|
||||
@@ -292,12 +315,20 @@ operation spec — the registry runs the ACL before the wrapper, so the
|
||||
### Phase 0: Scaffold hygiene (small fixes before porting)
|
||||
|
||||
1. Bump `alkcall` in `Cargo.toml` from `"0.1.0"` → `"0.1.1"` (ALPN
|
||||
rename release).
|
||||
rename release). *(Done in this revision.)*
|
||||
2. Add `futures = "0.3"` to `[dependencies]` (the `BoxFuture` alias
|
||||
uses `futures::future::BoxFuture`; alkcall pulls it transitively
|
||||
but alktty should declare it directly to not rely on a transitive
|
||||
dep for a public type alias).
|
||||
3. Confirm the `local` feature already wires `portable-pty` +
|
||||
dep for a public type alias). *(Done.)*
|
||||
3. **Split tokio features for the WASM target.** *(Done.* `Cargo.toml`
|
||||
*now uses `tokio = { default-features = false, features = ["rt",
|
||||
"sync", "io-util", "macros"] }` for the default wasm-clean build,
|
||||
and `local` adds `tokio/process` + `tokio/rt-multi-thread`.)* The
|
||||
scaffold's `features = ["full"]` pulled in `signal`/`fs`/`net`
|
||||
which break `wasm32-unknown-unknown`. The dev-deps that need
|
||||
`tokio/process` (the pipe/pty integration tests) get it via the
|
||||
`local` feature on the crate itself, not by re-declaring `full`.
|
||||
4. Confirm the `local` feature already wires `portable-pty` +
|
||||
`tokio-util` as optional deps (it does in the scaffold). The
|
||||
`local` module's `pty.rs` additionally needs `libc` under
|
||||
`cfg(unix)` — already in `[target.'cfg(unix)'.dependencies]`.
|
||||
@@ -518,7 +549,23 @@ well-understood pattern (wezterm uses it) but is inherently platform-
|
||||
specific (Unix only for PTY, pipe mode works cross-platform).
|
||||
|
||||
**Mitigation**: Gate PTY behind `#[cfg(unix)]` as the existing code does.
|
||||
Pipe mode works on all platforms.
|
||||
Pipe mode works on all platforms. The whole `local` module is behind
|
||||
the `local` feature, which is non-wasm by design.
|
||||
|
||||
### Risk: WASM target regression
|
||||
|
||||
The default crate MUST stay `wasm32-unknown-unknown`-clean. A future
|
||||
change that pulls in `tokio::process`, `std::thread`, `libc`, or any
|
||||
OS-specific dep into a non-`local` module silently breaks the
|
||||
downstream TS/Python adapter story (the wasm-compiled protocol layer
|
||||
is what makes those adapters cheap to build).
|
||||
|
||||
**Mitigation**: Add a CI job that runs `cargo check --target
|
||||
wasm32-unknown-unknown` (no features) on every PR. Cheap, catches the
|
||||
regression at the boundary. The tokio feature split in `Cargo.toml`
|
||||
(the wasm-clean `["rt", "sync", "io-util", "macros"]` subset, with
|
||||
`local` adding `process`/`rt-multi-thread`) is the structural guard;
|
||||
the CI job is the enforcement.
|
||||
|
||||
### Risk: BAST schema drift
|
||||
|
||||
|
||||
Reference in New Issue
Block a user