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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **Routing capability gains write-path v1 mutation surface (CID-transform API).** Added explicit mutation methods that take a base CID and return a new root CID: `mkdir`, `writeFile`, and `remove`, plus `publish` for IPNS updates with optional compare-and-set (`expectedCurrent`) conflict checks. This keeps reads on WASI paths while making writes explicit, attenuable effects with no hidden mutable daemon root.
- **`ww run` now requires a persistent identity by default.** Identity resolution no longer silently falls back to ephemeral keys when `--identity` is missing or points to a nonexistent file. Default lookup is `~/.ww/identity`; if absent, startup fails with a clear message and remediation. Operators can explicitly bypass with `--insecure-ephemeral` (named insecure on purpose), which restores prior ephemeral behavior for quick trial runs.
- **Admin UDS interface removed; `ww shell` is temporarily unavailable.** Removed the daemon-side Unix-domain admin service and its local socket discovery path. `ww shell` now remains as a forward-stable CLI surface but exits with `NOT IMPLEMENTED` until the replacement remote transport/auth path lands.
- **Filesystem data-plane contract tightened: backend is now root-layer-only and `perform fs` reads are deprecated.** The shell/MCP evaluation wrapper no longer routes data-plane reads through `(perform fs ...)`; filesystem reads now go through WASI path I/O (`load`, `import`, `/ipfs/...`, `/ipns/...`). The legacy `fs` handler remains only to return a migration-grade deprecation error. Backend virtual mount resolution now rejects targeted mounts (`source:/guest/path`) and accepts root layers only; `ww run` enforces this early with a CLI preflight error that lists offending mounts. Docs updated across `doc/shell.md`, `doc/capabilities.md`, and `doc/architecture.md` to reflect the single-path model.
- **Filesystem data-plane contract tightened: backend is now root-layer-only and `perform fs` reads are removed.** The shell/MCP evaluation wrapper no longer routes data-plane reads through `(perform fs ...)`; filesystem reads now go through WASI path I/O (`load`, `import`, `/ipfs/...`, `/ipns/...`). The legacy `fs` handler has been removed. Backend virtual mount resolution now rejects targeted mounts (`source:/guest/path`) and accepts root layers only; `ww run` enforces this early with a CLI preflight error that lists offending mounts. Docs updated across `doc/shell.md`, `doc/capabilities.md`, and `doc/architecture.md` to reflect the single-path model.
- **CompilationService now uses a dedicated worker pool with in-flight dedupe.** The compiler subsystem moved from single-thread compile handling to a fixed worker pool (`WW_COMPILE_WORKERS`, default derived from CPU count), keys cache entries by `(wasm_blake3, engine identity)`, and coalesces concurrent duplicate compile requests so one cold compile serves all waiters.
- **Shell local-discovery policy aligned to per-user run dir.** `ww shell` local discovery now scans only `~/.ww/run/` for `<peer-id>.sock` entries (no `/var/run/ww` fallback), and the client fails deterministically with a disambiguation error when multiple local daemons are present instead of prompting interactively. Updated `src/discovery.rs`, `src/cli/shell.rs`, and shell/CLI docs to match this behavior and keep the local admin auth boundary consistently user-scoped.
- **CLI module boundary cleanup (no behavior change).** Extracted daemon-management helpers, namespace command handlers, and doctor checks from `src/cli/main.rs` into `src/cli/daemon_cmd.rs`, `src/cli/ns_cmd.rs`, and `src/cli/doctor_cmd.rs`, leaving `Commands` as thin delegators. This reduces `main.rs` surface area and improves maintainability while preserving existing command behavior.
- **Runtime load path now supports staged component precompilation via a dedicated compiler service.** Added `ProcBuilder::with_component(...)` so executor spawns can instantiate precompiled components instead of recompiling WASM on worker threads, threaded an optional compile-request channel through runtime construction, and wired daemon startup to spawn `CompilationService` and pass it into kernel/admin runtimes. This keeps behavior compatible while moving CPU-heavy compile work off the executor hot path.

### Removed
- **Legacy `perform fs` compatibility handler removed.** The deprecated `fs-handler` fallback in `std/caps` has been deleted; callers must use WASI path I/O for reads and the routing write-path API for mutations.
- **`std/lib/ww/fs.glia` and `std/lib/ww/routing.glia` — pure-veneer modules.** Both were 1-line pass-throughs over the bound `fs` and `routing` capabilities (`(defn read-str [path] (perform fs :read-str path))` and four analogous `routing/*` shims). Zero internal callers across the repo. The wrappers obscured the canonical `(perform <cap> :<method> args)` cap-dispatch idiom without abstracting anything, and the names sustained the fiction that `ww/fs` was "the filesystem module" when `fs` is the underlying capability and the only thing doing work. Also gone: the pure-Glia `ipfs-path` / `ipns-path` constructors (trivial `(str "/ipfs/" cid)` inlines) and the incomplete `cid?` predicate (missed several valid CIDv1 multicodec prefixes — `bafr`, `bagu`, `bagy`, … — and wasn't fs-related to begin with). `doc/capabilities.md` updated: the "Content access" section now shows `(perform fs :read-str path)` directly instead of advertising `fs/read*` wrappers; the env-bindings table entry switches from "Glia functions" to "capabilities" framing. The `fs` and `routing` capabilities themselves are unchanged — still bound at env startup (`std/shell/src/lib.rs:260-274`); only the redundant module veneer is gone. Both modules were introduced earlier in `[Unreleased]` and never shipped in a release, so zero external migration burden.
- **`ww shell` "AI agents:" startup hint.** The line `AI agents: ipfs cat /ipns/releases.wetware.run/.agents/prompt.md` is gone from `src/cli/shell.rs`. The hint pointed at a host-shell command (`ipfs cat`) that's awkward to surface from inside a Glia REPL (the user can't paste it), and the obvious Glia-form rewrite — `(perform fs :read-str "/ipns/…")` — fails today because the WASI fs interceptor (`crates/cell/src/fs_intercept.rs:481-520`) only recognizes `ipfs/<CID>/…` paths (`parse_ipfs_path` at line 72 strips the `ipfs/` prefix; there's no `ipns/` sibling). `/ipfs/<CID>/…` reads through the cap *do* work — `open_ipfs` lazily materializes content from the pinset cache — so a hint pointing at a stable CID would work today; what's missing is IPNS resolution at the intercept layer (or a sibling cap method that calls Kubo `name/resolve` first, then routes through the existing pinset path). Restoring a pasteable Glia-form hint is the natural reward for that follow-up.

Expand Down
6 changes: 3 additions & 3 deletions doc/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ Use regular guest file I/O against filesystem paths:
- direct guest reads via WASI-aware code under `/ipfs/<cid>/...` and
`/ipns/<name>/...`

`(perform fs ...)` is legacy and returns a migration error. Keeping a separate
`perform` filesystem read surface created dual-path semantics and is being
removed.
There is no `perform fs` read surface. Keeping a separate `perform`
filesystem API created dual-path semantics; reads now go only through
WASI path I/O.

### Content mutation (explicit capability API)

Expand Down
77 changes: 0 additions & 77 deletions std/caps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,30 +640,6 @@ pub fn make_routing_handler(routing: routing_capnp::routing::Client) -> Val {
}
}

/// Legacy `fs` effect handler.
///
/// `perform fs` data-plane reads are removed in favor of direct WASI file I/O
/// (`load`, `import`, and normal guest file reads against `/ipfs` / `/ipns`).
/// The handler remains only to produce a migration-grade error when older code
/// attempts `(perform fs ...)`.
pub fn make_fs_handler() -> Val {
Val::AsyncNativeFn {
name: "fs-handler".into(),
func: Rc::new(move |args: Vec<Val>| {
Box::pin(async move {
let (method, rest) = extract_method(&args[0])?;
let _resume = &args[1];
let _ = rest;
Err(glia::error::cap_call(
"fs",
method,
"deprecated: `(perform fs ...)` is removed; use WASI path I/O (`load`, `import`, or direct file reads under /ipfs|/ipns)".to_string(),
))
})
}),
}
}

// ---------------------------------------------------------------------------
// Effect handler wrapping — nests with-effect-handler forms around an expr
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -1003,57 +979,4 @@ mod tests {
}
}

// -- make_fs_handler (legacy deprecation behavior) --

/// Drive an `AsyncNativeFn` synchronously by polling its future to
/// completion on a fresh single-threaded tokio runtime.
fn drive_handler(handler: &Val, method: &str, path: Option<&str>) -> Result<Val, Val> {
let mut method_list = vec![Val::Keyword(method.into())];
if let Some(p) = path {
method_list.push(Val::Str(p.into()));
}
let resume = Val::NativeFn {
name: "test-resume".into(),
func: std::rc::Rc::new(|args: &[Val]| Ok(args[0].clone())),
};
let args = vec![Val::List(method_list), resume];

match handler {
Val::AsyncNativeFn { func, .. } => {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("runtime");
let local = tokio::task::LocalSet::new();
local.block_on(&rt, func(args))
}
other => panic!("expected AsyncNativeFn, got {other:?}"),
}
}

#[test]
fn fs_read_returns_deprecation_error() {
let handler = make_fs_handler();
let err = drive_handler(&handler, "read", Some("/ipfs/bafy.../foo.txt")).unwrap_err();
assert_eq!(
glia::error::type_tag(&err),
Some(glia::error::tag::CAP_CALL),
"expected cap-call-failed tag, got: {err:?}"
);
let msg = glia::error::message(&err).unwrap_or("");
assert!(
msg.contains("deprecated") && msg.contains("perform fs"),
"expected migration error message, got: {msg}"
);
}

#[test]
fn fs_unknown_method_still_returns_deprecation_error() {
let handler = make_fs_handler();
let err = drive_handler(&handler, "explode", Some("anything")).unwrap_err();
assert_eq!(
glia::error::type_tag(&err),
Some(glia::error::tag::CAP_CALL)
);
}
}
7 changes: 3 additions & 4 deletions std/kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1089,10 +1089,9 @@ fn parse_initd_script(name: &str, data: &[u8]) -> Option<Vec<Val>> {
/// ```glia
/// (with-effect-handler host host-handler
/// (with-effect-handler runtime runtime-handler
/// (with-effect-handler fs fs-handler
/// (with-effect-handler routing routing-handler
/// (with-effect-handler :load (fn [path resume] (resume (load path)))
/// <form>)))))
/// (with-effect-handler routing routing-handler
/// (with-effect-handler :load (fn [path resume] (resume (load path)))
/// <form>))))
/// ```
///
/// Cap handlers are looked up from the environment by name. Keyword effect
Expand Down