@ai-ecoverse/slicc-bios 1.4.2 → 1.5.1
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.
- package/README.md +7 -1
- package/package.json +2 -2
- package/src/packages/optional/catalog.json +1 -1
package/README.md
CHANGED
|
@@ -309,7 +309,7 @@ seven can also join a tailnet, with a patched build of Tailscale's wasm client (
|
|
|
309
309
|
- A device that reconnects replaces only its own process's link, so `slicc <join> prompt` doesn't drop that machine's `follow`. Control-only links (`caps: []`) get no `.slicc.internal` name and no exit.
|
|
310
310
|
- **Folders (`fs`):** a CLI started with `--mount <path>[:<name>][:ro]` lists its folders in HELLO, and later in `OPEN { kind: 'mounts' }` updates; the page offers cap `mounts`. Each is a `hostfs` source named `<device>/<name>`, so `mount -t hostfs lars-mbp/proj /mnt/proj` mounts it, and nothing is mounted unless someone asks. A bare source with no `<device>/`, as slicc-node named its folders (`mount -t hostfs project /mnt/p`, or one remembered from then), is the folder of that name on the CLI linked on this computer, when exactly one local CLI shares one. The device's row in Linked devices lists its folders (`folders`, with a Read-only badge; spectrum ≥ 1.58.0): **Mount** (`mountFolder(source)`) mounts one at `/mnt/<device>/<name>` (a folder named `.` or `..` is never listed), and **Eject** (`ejectFolder(source)`) unmounts it. The Files panel's Mounted strip shows each `hostfs` mount's source (`mountInfo()`), so `/mnt/proj · lars-mbp/proj` reads as another computer's folder. A mounted linked folder stays with the CLI process it was first granted from (`slicc-os.link-sources`), even if that process comes back under another name. If that process isn't linked, the folder goes to whichever process has the name now, but only when no other process with the same host name shares a folder of that name; otherwise it waits. So a remembered `lars-mbp/proj` never lands on another process's `proj`. A remembered linked folder that is mounted again before its CLI is back stays `nomedium`, and fills in when the CLI links. The kernel's `hostfs` hook answers such a source with a `MessagePort` (slicc-kernel ≥ 1.54.9), and the page serves it with `serveHostfsPort` over `OPEN { kind: 'fs', mount, op, … }` streams: `list` collects its NDJSON, a read over 64 KiB and every write get their own channel, and `watch` streams the CLI's change events. A read-only kernel mount, or a read-only export, sends `readonly: true` on every OPEN. A link that drops makes the mount `nomedium` until the CLI is back; files that were open reopen by path and continue if the host didn't change them.
|
|
311
311
|
- **SSH host key:** the CLI's HELLO carries its host key, and the page writes `<host>.slicc.internal,<address> <key>` into the system-wide `/etc/ssh/ssh_known_hosts`, replacing older entries for that name or address, so `ssh` never trusts a key on first sight, whichever user runs it. Seven manages these keys, not the user, and OpenSSH looks up a user's own file under the passwd home, which isn't always `$HOME`.
|
|
312
|
-
- **Tests:** `test/integration/remote.test.mjs` runs the real `slicc watch`, `slicc prompt` and `slicc abort` with `--signal stdio` against seven's real agent and a fake Bedrock. It also leads a fake tray hub and sends a `webhook.event`, which reaches the agent as a webhook lick (without its `authorization` header) and starts a run. `test/integration/tray.test.mjs` leads a fake tray hub and links a follower in the page through it, then rotates and unlinks. `test/integration/link.test.mjs` links a fake node in the page over a real `RTCPeerConnection`, and, with `SLICC_CLI` set, the real `slicc attach --signal stdio`, relaying its NDJSON through the CDP binding: raw TCP and the http kind; kernel `ssh` with strict host-key checking against `--runner sh -c`, after `pnpm add -g @ai-ecoverse/wasix-openssh`; and, with the link as the exit, a name from the CLI's `--hosts` file, then refused under `--deny`; and `<port>.kernel.localhost` through the CLI's listener into a kernel server (`httptest`), with 502 for a closed port and the facade refused; a folder shared with `--mount`, mounted as `ref-node/proj`, read, written, seen changing on the host, and refused for writes when mounted `ro`; a second headless Chromium shared with `--cdp-extra`, listed and driven by `playwright-cli --runtime ref-node/<id>`; and a program WebSocket from kernel `bash` through the proxy to a `ws` echo server on the CLI's loopback: text, binary, the subprotocol, a close from each end, and `EACCES` under `--deny
|
|
312
|
+
- **Tests:** `test/integration/remote.test.mjs` runs the real `slicc watch`, `slicc prompt` and `slicc abort` with `--signal stdio` against seven's real agent and a fake Bedrock. It also leads a fake tray hub and sends a `webhook.event`, which reaches the agent as a webhook lick (without its `authorization` header) and starts a run. `test/integration/tray.test.mjs` leads a fake tray hub and links a follower in the page through it, then rotates and unlinks. `test/integration/link.test.mjs` links a fake node in the page over a real `RTCPeerConnection`, and, with `SLICC_CLI` set, the real `slicc attach --signal stdio`, relaying its NDJSON through the CDP binding: raw TCP and the http kind; kernel `ssh` with strict host-key checking against `--runner sh -c`, after `pnpm add -g @ai-ecoverse/wasix-openssh`; and, with the link as the exit, a name from the CLI's `--hosts` file, then refused under `--deny`; and `<port>.kernel.localhost` through the CLI's listener into a kernel server (`httptest`), with 502 for a closed port and the facade refused; a folder shared with `--mount`, mounted as `ref-node/proj`, read, written, seen changing on the host, and refused for writes when mounted `ro`; a second headless Chromium shared with `--cdp-extra`, listed and driven by `playwright-cli --runtime ref-node/<id>`; and a program WebSocket from kernel `bash` through the proxy to a `ws` echo server on the CLI's loopback: text, binary, the subprotocol, a close from each end, and `EACCES` under `--deny`; and a kernel `python3` UDP socket (after `pnpm add -g @ai-ecoverse/wasix-python`) to a UDP echo server on the CLI's loopback, unconnected and connected, and `EACCES` on a connected socket under `--deny`, as with the fake node's own refusal. CI runs the CLI from npm, the pinned `@ai-ecoverse/slicc` devDependency.
|
|
313
313
|
- **As the exit:** a CLI linked on this computer (`npx sliccy@next`) is the exit by itself until the user chooses one, so the kernel's HTTP and raw TCP get past CORS at once, as slicc-node's proxy did; a Tailscale exit node that is on comes first. A remote device that offers to be a default exit carries other traffic only once it's chosen. The Network panel's **Internet traffic** picker (`setExit`) is one choice across Directly, Tailscale exit nodes and linked devices: choosing a device turns off Tailscale's exit node, and choosing Tailscale clears the device. The choice of a device is kept in `localStorage` (`slicc-os.exit`), and while that device isn't connected, after a reload or while it reconnects, internet traffic **waits**: raw connections get `ENETUNREACH` and HTTP fails, rather than going out directly. Choosing Directly sends it directly again and is kept (`direct`), so a local CLI doesn't take it over, while a Tailscale exit node turned on later still does; unlinking the chosen exit device goes back to the automatic choice.
|
|
314
314
|
- **What the agent sees:** the transport's `traits` name the default exit while there is one, so the agent can say how its fetches go. `traits.exit` is `{ kind, caps }`:
|
|
315
315
|
- **`kind`:** `local` (a CLI on this computer), `remote` (a chosen linked device) or `tailnet` (a Tailscale exit node);
|
|
@@ -326,6 +326,12 @@ seven can also join a tailnet, with a patched build of Tailscale's wasm client (
|
|
|
326
326
|
- **When nothing carries it:** an exit without WebSockets (a CLI without cap `ws`) answers `502`. A held exit waits as HTTP does.
|
|
327
327
|
- **No secrets yet:** a handshake whose URL or headers carry a vault placeholder (`fnox_proxy_…`) is refused (`EACCES`, "secrets in WebSocket handshakes aren't supported yet"), so the placeholder never leaves seven.
|
|
328
328
|
- **Never through the page:** seven never opens a browser WebSocket itself. Unlike `fetch`, a browser WebSocket can't leave out the user's cookies for the site it reaches, so a program could act as the user there. With **Directly**, or no exit, a WebSocket is `501` with a hint to link a slicc CLI or use a Tailscale exit node.
|
|
329
|
+
- **UDP (`udp`):** a WASIX program's datagram socket (`AF_INET`/`AF_INET6` `SOCK_DGRAM`, such as Python's `socket` or a resolver) reaches a routed address through the exits, as `connect()` does. The kernel opens one uplink socket per program socket and family on its first routed send, and the router picks its exit then, by that first destination: a route claim (a linked device's own address, a tailnet address), then the default exit. Every later datagram of that socket goes through the same exit, whatever its destination, until the socket closes or that exit's socket ends. `traits.udp` is always `true`, because the kernel reads the uplink's traits once at start; with no exit that carries UDP (none, Directly, a held exit, a CLI without cap `udp`), a send fails with `ENETUNREACH`.
|
|
330
|
+
- **A linked CLI** with cap `udp` (slicc CLI ≥ 1.42.0) carries it as `OPEN { kind: 'udp', family }` (`os/link-udp.js`). Each datagram is a record, both ways: a type byte (`1` a datagram, `2` unreachable), a big-endian `u16` host length, the host, a `u16` port, a `u32` length, then the payload. Its own `<host>.slicc.internal` address goes to the CLI's `127.0.0.1`, and replies from there come back from that address, so a connected socket accepts them.
|
|
331
|
+
- **What's carried:** datagrams of at most 65 507 bytes (IPv4) or 65 527 (IPv6) to IP addresses; a larger send is `EMSGSIZE`. There's no back-pressure, as with UDP: a datagram that doesn't fit the link's window is dropped, and at most 512 datagrams or 256 KiB wait to be read before more are dropped.
|
|
332
|
+
- **What isn't:** broadcast, multicast and the unspecified address, which the kernel and the CLI both refuse, and anything inbound that the socket didn't ask for: like a NAT, the CLI passes on a datagram only from an address and port the socket sent to. It closes a socket idle for 5 minutes, and the next send opens a new one.
|
|
333
|
+
- **Errors:** a destination the CLI refuses under its policy comes back as an unreachable record with `EACCES`, and a send the OS fails with its code. A connected socket's next send or receive fails with it; an unconnected socket is told nothing, as on Linux. ICMP unreachable comes back only from a CLI on Linux.
|
|
334
|
+
- **The Tailscale exit** carries UDP too, with one wasm-tailscale `dial('udp', …)` per destination (at most 256 per socket, the oldest closed first), so tailnet addresses and, with an exit node, public ones.
|
|
329
335
|
- **Network panel:** `status().links.devices` lists the linked devices (name, `<host>.slicc.internal`, address, mode, what they offer, the CLI's policy summary, whether they can be the exit, and their state), `status().exit` is the current choice, and `unlink(id)` drops a device. On `*.sliccy.ai` the panel also has the join URL, `rotateJoinUrl` and `retryLinks`.
|
|
330
336
|
- **Remote devices (the tray hub):** on `*.sliccy.ai`, `os/tray.js` makes seven a **tray leader** on SLICC's tray hub (`slicc-tray-hub`), through the sliccy-ai worker's same-origin proxy for `POST /tray`, `/controller/<token>` and the leader WebSocket, which drops cookies. The hub mints the join URL on `www.sliccy.ai`, and the panel shows `npx sliccy@next <join-url> follow` (`@next` until `sliccy`'s `latest` is the new CLI; `latest` is still six's). Followers then link the same way as a local CLI: seven offers, and the offer, answer and candidates go over the hub's bootstrap messages. TURN comes from the hub.
|
|
331
337
|
- **Who may link:** only followers with runtime `slicc-link/1` and full trust. A device **is its DTLS certificate**: its id is the SHA-256 fingerprint in its answer. The CLI keeps one certificate per hub and mints a new `controllerId` for every connection, which is only a routing id. A device that reconnects replaces its old link and gets its address back, and a new certificate is a new device. Known devices (name, label, address, what they offer) are kept in `localStorage` (`slicc-os.devices`), keyed by fingerprint, so a device that's away shows as reconnecting. The exit choice is keyed the same way.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-bios",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Slim loader that boots SLICC into OPFS and serves the UI from there",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"format": "biome check --write ."
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@ai-ecoverse/slicc": "1.
|
|
45
|
+
"@ai-ecoverse/slicc": "1.42.0",
|
|
46
46
|
"@ai-ecoverse/slicc-browsers": "1.7.3",
|
|
47
47
|
"@ai-ecoverse/slicc-node": "2.5.1",
|
|
48
48
|
"@ai-ecoverse/slicc-shared-web": "1.20.0",
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"@ai-ecoverse/wasm-sqlite3": {
|
|
126
126
|
"id": "sqlite3",
|
|
127
127
|
"label": "SQLite",
|
|
128
|
-
"description": "The sqlite3 shell 3.54, for SQLite databases.
|
|
128
|
+
"description": "The sqlite3 shell 3.54, for SQLite databases. journal_mode=WAL falls back to delete, and a WAL database made elsewhere opens as \"file is not a database\".",
|
|
129
129
|
"commands": ["sqlite3"],
|
|
130
130
|
"size": 668627
|
|
131
131
|
},
|