@ai-ecoverse/slicc-bios 1.5.3 → 1.7.0

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 CHANGED
@@ -81,7 +81,7 @@ The kernel runs with users on (slicc-kernel ≥ 1.81.0): files have owners and m
81
81
  - **Under `'report'`** nothing is protected, since protection has no report mode of its own. Installs already run as tagged writers from `/opt/slicc/base` with the clean config, and bios watches the six trees through the kernel (`fs.watch`, recursive). Each change made through the page's kernel outside bios's own installs goes to `denials.log` as `op: 'protect'`, `errno: 'EROFS'`: a write that `'enforce'` would refuse. The watch doesn't say which process wrote, so these lines have no user and no tag. Changes made outside the page's kernel (bios's install kernels, the page itself) aren't seen.
82
82
  - **Global packages** (`pnpm add -g` into `/usr/local/share/pnpm`) aren't protected and run untagged.
83
83
  - **A remembered mount** (`slicc-os.mounts`) at, under or above a protected path is dropped at boot under `'enforce'`, with a notice, *A remembered folder wasn’t mounted*.
84
- - **Sudo approvals:** the kernel's `approve` hook feeds `model.approvals`, spectrum's sudo dialog. It shows the resolved path and arguments, shell-quoted, the directory, the requester mapped from the tag, the target and *Always allow*. Every tab shows the request (`BroadcastChannel('slicc-approvals')`), and the first decision wins; the other tabs see *Answered in another tab*. *Always allow* is offered only for a command bios trusts to run the same way every time: the kernel's resolved path, whose real path and every directory above it are root's and not group- or other-writable (checked by a root `stat` when the request comes), that isn't a shell, interpreter or wrapper (`bash`, `python*`, `node`, `env`, `xargs`, `sudo`, `timeout`, `find -exec` and the like), doesn't write named files (`tee`, `cp`, `mv`, `chmod`, `dd`, `sed -i`, `tar -x`, `git`, `pnpm` and the like), whose operands are all absolute, inside none of `/tmp`, `/var/tmp`, `/home`, `/mnt`, `/scoops` and `/dev/shm`, and not user-writable (a file that isn't root's or is group- or other-writable, a directory above that is, or a missing path whose parent is), with no shell metacharacter in any argument, and which may not change the secret rules. Everything else gets *Allow once* only. A request that may change the secret rules never offers *Always allow* either. bios decides that at least as broadly as spectrum's dialog: it runs the dialog's own classifier (`os/rules.js`, a port of spectrum 1.62's until spectrum exports it), its own path check (`/etc/fnox`, `/etc/slicc/secrets-policy.toml`, and for a command that isn't read-only `/`, `/etc`, `/etc/slicc`, a name with `fnox` or `secrets-policy`, a glob or `..`), and treats any `$`, backtick, quote or backslash in an argument, and any quoting or `cd` inside a `-c` script, as a possible change. For such a request bios sends `always: false`, and answers an `always` for it, from any tab, as `once`, so no `NOPASSWD` line is written for it.
84
+ - **Sudo approvals:** the kernel's `approve` hook feeds `model.approvals`, spectrum's sudo dialog. It shows the resolved path and arguments, shell-quoted, the directory, the requester mapped from the tag, the target and *Always allow*. Every tab shows the request (`BroadcastChannel('slicc-approvals')`), and the first decision wins; the other tabs see *Answered in another tab*. *Always allow* is offered only for a command bios trusts to run the same way every time: the kernel's resolved path, whose real path and every directory above it are root's and not group- or other-writable (checked by a root `stat` when the request comes), that isn't a shell, interpreter or wrapper (`bash`, `python*`, `node`, `env`, `xargs`, `sudo`, `timeout`, `find -exec` and the like), doesn't write named files (`tee`, `cp`, `mv`, `chmod`, `dd`, `sed -i`, `tar -x`, `git`, `pnpm` and the like), whose operands are all absolute, inside none of `/tmp`, `/var/tmp`, `/home`, `/mnt`, `/scoops` and `/dev/shm`, and not user-writable (a file that isn't root's or is group- or other-writable, a directory above that is, or a missing path whose parent is), with no shell metacharacter in any argument, and which may not change the secret rules. Everything else gets *Allow once* only. A request that may change the secret rules never offers *Always allow* either. bios decides that at least as broadly as spectrum's dialog: it runs the dialog's own classifier (spectrum's exported `secretRules`; without it every command counts as one that may change them), its own path check (`/etc/fnox`, `/etc/slicc/secrets-policy.toml`, and for a command that isn't read-only `/`, `/etc`, `/etc/slicc`, a name with `fnox` or `secrets-policy`, a glob or `..`), and treats any `$`, backtick, quote or backslash in an argument, and any quoting or `cd` inside a `-c` script, as a possible change. For such a request bios sends `always: false`, and answers an `always` for it, from any tab, as `once`, so no `NOPASSWD` line is written for it.
85
85
  - **Denials:** denials under `'report'` and `'enforce'` go to `/var/log/slicc/denials.log`, one JSON line per distinct `(uid, tag, op, path, errno)` with its `count`, `first` and last `time`, plus `user`, `tag` (the process's tag, `null` for an untagged one) and `mode`. They're written within a quarter of a second, at every 100 distinct denials, and when the page is hidden (`visibilitychange`). When the page goes away (`pagehide`), the ones not yet written are kept in `localStorage` (`slicc.denials.spool.*`), and the next page writes them once its kernel is up. The log rotates to `denials.log.1` at 1 MiB. `slicc-denials` (in `/usr/local/bin`) sums up the log and its `.1`: the total and time span, then counts by tag kind (`agent`, `user`, `untagged`), op, errno and path prefix; `--json` prints the same as one object.
86
86
  - **Not a boundary:** the kernel's loopback (`<port>.kernel.localhost`) isn't one between users (N2). A server any user starts is reachable by every process and by seven's pages.
87
87
 
@@ -168,7 +168,7 @@ The Files panel lists `/opt/grammars/node_modules` but doesn't scan it.
168
168
 
169
169
  #### Optional packages
170
170
 
171
- Below the system rows, Install / Update offers **Optional packages** (spectrum ≥ 1.42.0): tools that seven doesn't preinstall, each at the version the homescoop coordinator certified. The catalog is [`src/packages/optional/`](src/packages/optional/): `package.json` pins each package exactly, `package-lock.json` (made with `npm install --package-lock-only --ignore-scripts`, never installed) holds its integrity, and `catalog.json` gives its id, label, description, commands, tarball size and `requires`. A test keeps the three in step. Today it offers git, OpenSSH, Python, uv, Node.js (slicc-jsh's `node` and `jsh`), `sliccy:browser` for `.jsh` scripts, Ruby, Perl, esbuild, TypeScript, Biome, the PDF tools (poppler), qpdf, rsync, buf, screen, SQLite, dig and GnuPG.
171
+ Below the system rows, Install / Update offers **Optional packages** (spectrum ≥ 1.42.0): tools that seven doesn't preinstall, each at the version the homescoop coordinator certified. The catalog is [`src/packages/optional/`](src/packages/optional/): `package.json` pins each package exactly, `package-lock.json` (made with `npm install --package-lock-only --ignore-scripts`, never installed) holds its integrity, and `catalog.json` gives its id, label, description, commands, tarball size and `requires`. A test keeps the three in step. Today it offers git, OpenSSH, Python, uv, Node.js (slicc-jsh's `node` and `jsh`), `sliccy:browser` for `.jsh` scripts, Ruby, Perl, esbuild, TypeScript, Biome, the PDF tools (poppler), qpdf, rsync, buf, screen, SQLite, dig, websocat, GnuPG and fnox.
172
172
 
173
173
  - **Install** runs `pnpm add -g <package>@<version>` in the page's kernel, as a user would, under the Web Lock `slicc-optional`, so the commands work at once in every open shell. pnpm 12 gives each global add its own project under `$PNPM_HOME/global/v11/`; bios reads `PNPM_HOME` from the kernel's environment. Afterwards `os/packages.js` reads that project's `pnpm-lock.yaml`: every package in it, the one added and each dependency, must be a version in the catalog's lockfile or the base set's, with that integrity. homescoop pins `@ai-ecoverse/*` dependencies exactly (uv → Python, git → bash), so the catalog's lockfile names them all. Anything else, a dependency pnpm resolved to another version included, removes the package again and fails the row with *This version doesn't match the tested build*. An entry's `requires` (uv needs Python) are installed first.
174
174
  - **State** comes from pnpm's global projects, not from a list of bios's own, so a package installed by hand shows as installed with its version. One older than the catalog's offers **Update**, which adds the catalog's version; one at or above it offers **Remove**. bios never downgrades.
@@ -219,11 +219,25 @@ Packages are served unbundled, exactly as npm publishes them, so `pnpm upgrade <
219
219
  - `exports` is read with the conditions `browser`, `import`, `module` and `default`, then the `browser` field (including its file mappings), `module` and `main`.
220
220
  - A relative import's `browser` file mapping comes from the nearest `package.json` up to the importer's package root (a package directory in a `node_modules`, or `/os`), never from above it and never from `/`. Any process can write `/package.json`, so it must not remap seven's own imports.
221
221
  - Extensionless relative imports get `.js`, `.mjs`, `.cjs`, `.json` or `/index.js`.
222
- - **Node built-ins** (`node:x` and the bare names) become `/__slicc/node/<x>.js`. That's a generated module exporting exactly the names the importer asks for: `crypto.randomUUID`, `getRandomValues`, `webcrypto` and `subtle` are real, and everything else throws when called (not when imported). `node:worker_threads` is a real module instead: its `Worker` starts a module Web Worker, posts `workerData` to it first, and forwards `message` and `error`; inside that worker, `workerData` and a `parentPort` with `postMessage` and `on('message')` work as in Node.
222
+ - **Node built-ins** (`node:x` and the bare names) become `/__slicc/node/<x>.js`. That's a generated module exporting exactly the names the importer asks for: `url`'s `URL` and `URLSearchParams` are the page's own, and everything else throws when called (not when imported). `node:worker_threads` is a real module instead: its `Worker` starts a module Web Worker, posts `workerData` to it first, and forwards `message` and `error`; inside that worker, `workerData` and a `parentPort` with `postMessage` and `on('message')` work as in Node.
223
223
  - **CommonJS** (`src/sw/transform.js`): a script without module syntax that uses `require` or `exports` is wrapped as an ES module. Its `require()` calls become imports, `module.exports` is the default export, and `exports.x =` assignments become named exports. As in Node, the wrapped code also gets the free variables `process` and `global`. `global` is `globalThis`. `process` is the page's own `process` if there is one, and otherwise one shared minimal object (`platform: 'browser'`, `env: {}`, `argv: []`, `cwd()` returning `/`, and `nextTick`), so packages that read `process.platform` at load time (cross-spawn, which, isexe) load.
224
224
  - **TypeScript** (`src/sw/strip.js`): `.ts`, `.mts` and `.cts` files are served as `text/javascript` with their types blanked out. Annotations, `interface` and `type` declarations, `import type`, `export type` and type-only specifiers, generics, `as` and `satisfies`, non-null `!`, `declare`, access modifiers, `abstract`, optional `?` and `implements` become spaces, so every line and column stays where it was and no source map is needed. This is what Node's `--experimental-strip-types` does, and for every TypeScript file of the three pi extensions in the test matrix the output is the same as Node's. Syntax with no erasable form (`enum`, a `namespace` with values, parameter properties, `import x = require()`, `export =`, `<T>x` and decorators) makes the module throw a `SyntaxError` with the file, line and column. An import of `./x.js` finds `x.ts` when there is no `x.js` (and `.mjs` finds `.mts`, `.cjs` finds `.cts`), as with TypeScript's `nodenext` and `bundler` resolution. Extensionless imports don't look for `.ts`. A `.cts` file is wrapped as CommonJS after stripping.
225
225
  - **Caching:** rewritten scripts are cached per file until the file or `/pnpm-lock.yaml` changes, so an update is picked up without reinstalling the service worker.
226
226
 
227
+ ## Vault
228
+
229
+ Seven keeps its secrets in the vault, a separate origin (`@ai-ecoverse/slicc-vault`, types only in `devDependencies`; its README's "The embedding API" is the spec). `src/seed/vault.js` brokers it:
230
+ - **The origin** comes from `vaultOrigin()`: production seven (`https://seven.sliccy.ai`) always uses `https://vault.sliccy.ai` and refuses an override with a console error; every other seven uses `https://vault-preview.sliccy.ai`, or the origin in `localStorage['slicc-os.vault-origin']`, which the tests point at a fake vault.
231
+ - **The core frame** is a hidden iframe at that origin. After each `load` (so again after the frame reloads) seven posts the page hello `{ type: 'slicc-vault', v: 1, op: 'hello', role: 'page', sudoGid }`, with the kernel's `sudo` gid from `kernel.groups.list()` (left out under users `off`; the owner tab keeps it in `localStorage['slicc-os.vault-sudo-gid']` for the other tabs), and talks to the vault over that page port only.
232
+ - **`model.vault`** (spectrum's `VaultPort`) gives Settings › Secrets, the value requests and the composer's hold synchronous `status()` and `list()` snapshots (re-listed after every `changed`), `audit`, `availability()` (`connecting` until the welcome, `waiting` without one within 5 s or while an answer is 2 s late, then `locked` or `ready`), and the page ops `put` (with spectrum's `PutOptions` passed through), `cancel`, `remove`, `restore`, `import`, `export`, `lock` and `dismissBackupReminder`. Rejections are `Error`s with the vault's errno as `code`. Values go only through `put` (and `seal`), are never logged, stored or put into an error message, and never reach the agent worker.
233
+ - **`button()`** is a plain iframe of `<vault origin>/button.html`, with no `sandbox`, so it can open the vault's popup. Every `button` message carries seven's current colour scheme as `theme`, and is sent again on the frame's `load` and whenever the scheme changes; spectrum (≥ 1.68.3) gives the iframe the same `color-scheme`, so Chrome doesn't paint it opaque.
234
+ - **The agent's port:** for slicc-agent ≥ 4.0.0 only, each agent worker gets its own `agent`-role port, posted raw as `{ vault, scrub }` next to the agent's `{ kernel, admin }`, and again with a fresh port after the frame reloads. The agent port gets no events, so every lock change in the page port's `status` is posted to the worker as `{ locked: true | false }`. `scrub` is the last `{ needed, version, ready }` pair (`localStorage['slicc-os.vault-scrub']`, `null` before any vault connected); each new pair is posted to the worker as `{ scrub }` before seven relays the `put`, `seal` or `import` answer that caused it. Agents before 4.0.0 speak an earlier draft of that wire, so they get no port and stay inert.
235
+ - **`/dev/sealed`:** the kernel's `sealed` hook relays each request with its kernel stamp (`caller`, unchanged) as the vault's `sealed` op, and returns its one reply. While kernel users aren't `enforce`, `materialize` and `materializeConsume` are refused with `EACCES`; under `enforce`, `materialize` is relayed like the rest, and the kernel's `materializeConsume` (`ticket`, `stamp`, `path`, `resolved`, `argv`, `cwd`, `interpreters`, `trusted`, unchanged) goes to the vault's page op of that name, whose `{ values, placeholders }` go back to the kernel only. jerk's requests (`src/seed/jerk.js`) are answered with `answer`: `jop: list` with rows from each linked device that runs jerk (J1 `list`), `jop: status` from the vault's records (exit 3 without one), `jop: create` through J1 `create` with its progress lines (exit 4 without a jerk device), `unseal` by removing the provider's `jerk:` records, and `oauth` and `jerk-seal` with exit 5 until seven signs in itself. A `cancelled` event stops a running J1 `create`.
236
+ - **Forward (seam):** `forward` is passed through with the kernel's full stamp as `owner` (`users` included, since the vault injects only for `enforce`) and the response port transferred; the exit router's use of it is VAULT-1b's follow-up.
237
+ - **fnox** (the optional catalog's `fnox`, wasi-fnox): every kernel process gets `FNOX_CONFIG_DIR=/etc/fnox`, sudo included, and bios writes `/etc/fnox/config.toml` once as root's `0644` (`default_provider = "seven"`, provider `seven` of type `sealed`), so cones read it and only `sudo` changes it. fnox keeps placeholders there and reaches the vault through `/dev/sealed`; while the vault frame never answered, every sealed operation fails at once with `ENOTCONN`. Use `fnox set` to change a secret (`fnox edit` is refused on WASI).
238
+ - **Egress:** the vault's token refreshes arrive as `egress` events; seven sends them without following redirects (through its exits when the transport hands redirects back, else the page's own `fetch` with `redirect: 'manual'`), answers a redirect with an error, zeroes the request body once it's sent, and answers on the event's port within 30 s, never logging the request.
239
+ - **Adobe IMS:** with agent ≥ 4.0.0, `login('adobe', …)` opens its popup before anything else, then seals the token as `{ kind: 'model', provider: 'adobe', name: 'ADOBE_IMS_TOKEN', source: 'oauth:adobe', expiresAt }` and resolves `{ sealed: true }`, so the token never reaches spectrum or the agent. IMS gives no refresh token: an expired token means signing in again, which replaces the record and keeps its placeholder. Agents before 4.0.0 get the token as before.
240
+
227
241
  ## Network
228
242
 
229
243
  Before the kernel starts, `os/transport.js` picks how programs reach the network. The first of these that applies wins:
@@ -309,7 +323,7 @@ seven can also join a tailnet, with a patched build of Tailscale's wasm client (
309
323
  - 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
324
  - **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
325
  - **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`; 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.
326
+ - **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`; kernel `websocat`, installed from the catalog, to a `ws` echo on the CLI's loopback and, without `-k`, to `wss://echo.sliccy.ai/` (SLICC's echo, behind Cloudflare's certificate), so its own TLS checks the chain over raw TCP through the link, then failing at once under Directly and with no exit, and its `cmd:`, `exec:` and `sh-c:` refused at startup; 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
327
  - **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
328
  - **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
329
  - **`kind`:** `local` (a CLI on this computer), `remote` (a chosen linked device) or `tailnet` (a Tailscale exit node);
@@ -326,6 +340,7 @@ seven can also join a tailnet, with a patched build of Tailscale's wasm client (
326
340
  - **When nothing carries it:** an exit without WebSockets (a CLI without cap `ws`) answers `502`. A held exit waits as HTTP does.
327
341
  - **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
342
  - **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.
343
+ - **websocat** (the catalog's, an upstream alpha) doesn't use the proxy: it dials raw TCP and does its own TLS against its embedded roots, so `ws://` and `wss://` hosts outside seven need an exit for raw TCP, a linked slicc CLI or a Tailscale exit node. Without one it fails at once (`Network unreachable`, or `No such file or directory` for a name).
329
344
  - **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
345
  - **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
346
  - **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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-bios",
3
- "version": "1.5.3",
3
+ "version": "1.7.0",
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",
@@ -46,6 +46,8 @@
46
46
  "@ai-ecoverse/slicc-browsers": "1.7.4",
47
47
  "@ai-ecoverse/slicc-node": "2.5.1",
48
48
  "@ai-ecoverse/slicc-shared-web": "1.20.0",
49
+ "@ai-ecoverse/slicc-spectrum": "1.77.0",
50
+ "@ai-ecoverse/slicc-vault": "1.9.1",
49
51
  "@biomejs/biome": "2.5.15",
50
52
  "es-module-lexer": "3.0.3",
51
53
  "fake-indexeddb": "6.2.5",
@@ -3,7 +3,7 @@
3
3
  "private": true,
4
4
  "description": "SLICC's agent, which the UI installs with pnpm in the background into /opt/agent in OPFS",
5
5
  "dependencies": {
6
- "@ai-ecoverse/slicc-agent": "3.50.2",
6
+ "@ai-ecoverse/slicc-agent": "5.0.3",
7
7
  "@ai-ecoverse/slicc-kernel": "1.102.5"
8
8
  }
9
9
  }
@@ -6,39 +6,42 @@ settings:
6
6
 
7
7
  overrides:
8
8
  '@google/genai': '-'
9
- esbuild: '-'
10
9
 
11
10
  importers:
12
11
 
13
12
  .:
14
13
  dependencies:
15
14
  '@ai-ecoverse/slicc-agent':
16
- specifier: 3.50.2
17
- version: 3.50.2(@ai-ecoverse/slicc-kernel@1.102.5)(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
15
+ specifier: 5.0.3
16
+ version: 5.0.3(@ai-ecoverse/slicc-kernel@1.102.5)(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
18
17
  '@ai-ecoverse/slicc-kernel':
19
18
  specifier: 1.102.5
20
19
  version: 1.102.5
21
20
 
22
21
  packages:
23
22
 
24
- '@ai-ecoverse/slicc-agent@3.50.2':
25
- resolution: {integrity: sha512-8WcNCTemX9W7QOTrt3yqUBqieF7eCm04hxdW4J8+PJ6IZpN9vBIeoOZvKS+sdl/Z3qTiITTxXUW53w+kbrX0TQ==}
23
+ '@ai-ecoverse/slicc-agent@5.0.3':
24
+ resolution: {integrity: sha512-5mQ7TbLZCfdRaS4YFJXamjLCyzD9DxsWAImD2EU4sl85VNhgeXe6axRiOBkY45tpeKHBWG/MQUV5Mi75llUJMg==}
26
25
  engines: {node: '>=24'}
27
26
  peerDependencies:
28
- '@ai-ecoverse/slicc-kernel': '>=1.47.1 <2'
29
- '@ai-ecoverse/slicc-spectrum': ^1.39.0
27
+ '@ai-ecoverse/slicc-kernel': '>=1.90.0 <2'
28
+ '@ai-ecoverse/slicc-spectrum': ^1.75.0
30
29
  peerDependenciesMeta:
31
30
  '@ai-ecoverse/slicc-spectrum':
32
31
  optional: true
33
32
 
34
- '@ai-ecoverse/slicc-browsers@1.5.0':
35
- resolution: {integrity: sha512-H+K/cAMqVCPHKycoM68ZW/jDaOBcmqbMR4mVeBKP/L2Tb5U4dX15vcJ/EmFyBvA2XwYDM40KToJSWMUgK/Q/dg==}
33
+ '@ai-ecoverse/slicc-browsers@1.7.1':
34
+ resolution: {integrity: sha512-35vGFMbZrl33ZQ9/VgjwZDBXp0RP87mKY0hnIG31tW5Nt5hh+icdp+3Y/t1kypoENAre+jnVEDa9W/H+yK6zyA==}
36
35
  engines: {node: '>=24'}
37
36
 
38
37
  '@ai-ecoverse/slicc-kernel@1.102.5':
39
38
  resolution: {integrity: sha512-p4ya+WnAUor3eo4hX9ZRDLCfgFn3RYac4Oas1UOO+Efnv2ecGKMCdGfPlGPCoIlrs6ab8FJl8YG1xGtGNem9JQ==}
40
39
  engines: {node: '>=24'}
41
40
 
41
+ '@ai-ecoverse/slicc-vault@1.9.1':
42
+ resolution: {integrity: sha512-Ot5MFg0e+lrs4gH0TSMciKrrs299nQ4Fnr75oc6ZjcDAi7zbUUx/0lMUTthCpHxKI9HllLCGtxV6CTrHKT15mw==}
43
+ engines: {node: '>=24'}
44
+
42
45
  '@anthropic-ai/sdk@0.129.0':
43
46
  resolution: {integrity: sha512-MH7LB20kNpGLUpPTe2OG5XvL/KhX8HUO9XyBaFjgFk6TLS4Xjt0VPIuMKywe7POKKPslX+QxSlVok9e+8kG5Nw==}
44
47
  hasBin: true
@@ -132,42 +135,33 @@ packages:
132
135
  resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==}
133
136
  engines: {node: '>=6.9.0'}
134
137
 
135
- '@earendil-works/chord@1.0.4':
136
- resolution: {integrity: sha512-d2JZw2utoa/reoSmL07O71wsXiMDhIlnnxTb4LCNV+Oq8Evj2rGLvjVuYrlXZGbXUr0IDNfvd1RT/utCY1UhkQ==}
138
+ '@earendil-works/chord@1.2.0':
139
+ resolution: {integrity: sha512-Xh3M5B4D9YotOyBXyVbZ/5WfoUwP6Kt+TheCIDLxLCUx72UExuxZF//hNmIQGD13EkAHf2svKpXr/rCCT1gXTg==}
137
140
  engines: {node: '>=22.19.0'}
138
141
 
139
- '@earendil-works/pi-ai@1.0.4':
140
- resolution: {integrity: sha512-/Eu5R0gfor6wcmRcVyOmulUiZmsHJ0bKu5wXXnpCoSHF3y4FnW4fgnjRlLjNza8NJWXdvW5Uew90Zukx7Sh2rw==}
142
+ '@earendil-works/pi-ai@1.2.0':
143
+ resolution: {integrity: sha512-U5/1zXqfV1on7/9sbez03tT4Ru49Lvfb4+zXSDK3DBKF5cRk6KxvAOTOY3HJ4jimlZth+rs7vbJqN6iBQAoNuQ==}
141
144
  engines: {node: '>=22.19.0'}
142
145
  hasBin: true
143
146
 
144
- '@earendil-works/pi-client@1.0.4':
145
- resolution: {integrity: sha512-c+hB+VE+K+2990do99wk4m+R7RvRt7A/Wb9JOHWM3c+vCFqZqo8VdU65a+P/hUZp2cVhoxFnzFZsDf9yqaGvUA==}
147
+ '@earendil-works/pi-codemode@1.2.0':
148
+ resolution: {integrity: sha512-UZF7IN0IIrf3bop2wTxrwoAakGctH6d3zdPwhPN+QHMECfoI5E6B6l6I17YGFZPj8cmGex6xX7mLCNJXRf7wsw==}
146
149
  engines: {node: '>=22.19.0'}
147
150
 
148
- '@earendil-works/pi-codemode@1.1.0':
149
- resolution: {integrity: sha512-8Asc2AzhoNaXS1snmRFa96OhcWIlFM5k1Kuiz6p2DvIYgi5QHQccRAmDVY9oO92TzWrizpvQpconZGQ7JhlI7Q==}
151
+ '@earendil-works/pi-durable@1.2.0':
152
+ resolution: {integrity: sha512-2kDyK7HVCTcxf3CTHkDR0rRGCUfIpoZr76fC6n/KZDu7hkDWR62anEujIkJ+8sKjtNpEM+zyKW3bi2NIEUyiCw==}
150
153
  engines: {node: '>=22.19.0'}
151
154
 
152
- '@earendil-works/pi-durable@1.0.4':
153
- resolution: {integrity: sha512-i22unyhavxrTF/KS/JcBOKprQRgepufOIztnqBKZXJCWbEHsXDzcINtjmmBSbFB/3S+4FWIl3eJ5FMbRe33Ybg==}
155
+ '@earendil-works/pi-mcp@1.2.0':
156
+ resolution: {integrity: sha512-ertUv40rUBgssTzw2lIPlejjIBdhvdg4uw+whWCDJYKYHU+ldp1ezhbB0BzwpBfnwef6/YN+m6eKLscj+r3p7w==}
154
157
  engines: {node: '>=22.19.0'}
155
158
 
156
- '@earendil-works/pi-mcp@1.1.0':
157
- resolution: {integrity: sha512-xGKwvu3SvVTeoIx8Z7UGoJprB4VK20wKORMhufcWGx61fIauhu3J+UqfB5eeoF1oE/geYBA598K6nh1SdABQkg==}
159
+ '@earendil-works/pi-telemetry@1.3.0':
160
+ resolution: {integrity: sha512-ERGZr+aXjNJzoUbB7ZzHVH3g5otzMHjHLs2Fyizm12By5X+gBEhod9cJXFOk13S7M8a29Am+Mq21zm73mRJFLg==}
158
161
  engines: {node: '>=22.19.0'}
159
162
 
160
- '@earendil-works/pi-protocol@1.0.4':
161
- resolution: {integrity: sha512-GJ1ieSJdguV3VaO5fXD+LEm6w1Rx0HKk7P1g8I6ZelmiGpmQAYOneUZaCUhAz5BeC6FpyUFzBb+AOo0Npfxtvw==}
162
- engines: {node: '>=22.19.0'}
163
-
164
- '@earendil-works/pi-server@1.0.4':
165
- resolution: {integrity: sha512-9kQipVdjVMhprBzw/plrimPPDETNfFD7E2N8n1LBoLS7rcX+5js2hmUBJZPddmFnxNQgFeAgTgFH8bsCiWmlqw==}
166
- engines: {node: '>=22.19.0'}
167
-
168
- '@earendil-works/pi-telemetry@1.0.4':
169
- resolution: {integrity: sha512-DL2eXXtnL5/VQkuQd97fL57GXTG1/zKHtMmDsrv8tGeJ5EgYYTWvzy44dqbYL0lD0Z22v/NOwqU3PHO75HVrqA==}
170
- engines: {node: '>=22.19.0'}
163
+ '@silvia-odwyer/photon@0.3.3':
164
+ resolution: {integrity: sha512-8BhUjEch4slwRe8uXnaA4vcA5uiiOTT90UMsxulOj2gN98X1p0q9Z4Ysk4DkD05uNgbR9XoSqtZ37w+33w4QKQ==}
171
165
 
172
166
  '@smithy/core@3.35.1':
173
167
  resolution: {integrity: sha512-i4YPS4B6ts7bjn7UwLnGjiZdprOvHvgGobFZsYK3GIY3E5hIqtj0rReU69BcTpGp+fvtraSNXeG1l+jtJvF55w==}
@@ -308,6 +302,9 @@ packages:
308
302
  typebox@1.3.27:
309
303
  resolution: {integrity: sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA==}
310
304
 
305
+ typebox@1.3.36:
306
+ resolution: {integrity: sha512-bu2Ec2Ti9B4IFSFj1FcZbtLNB/W7igQwxocMGJLAG2NTv1nI+ImtIA34YgHW4CVyGVlJqNXR1GJyLmdWgV3DuA==}
307
+
311
308
  which@2.0.2:
312
309
  resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
313
310
  engines: {node: '>= 8'}
@@ -327,19 +324,18 @@ packages:
327
324
 
328
325
  snapshots:
329
326
 
330
- '@ai-ecoverse/slicc-agent@3.50.2(@ai-ecoverse/slicc-kernel@1.102.5)(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)':
327
+ '@ai-ecoverse/slicc-agent@5.0.3(@ai-ecoverse/slicc-kernel@1.102.5)(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)':
331
328
  dependencies:
332
- '@ai-ecoverse/slicc-browsers': 1.5.0
329
+ '@ai-ecoverse/slicc-browsers': 1.7.1
333
330
  '@ai-ecoverse/slicc-kernel': 1.102.5
334
- '@earendil-works/chord': 1.0.4
335
- '@earendil-works/pi-ai': 1.0.4(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
336
- '@earendil-works/pi-client': 1.0.4
337
- '@earendil-works/pi-codemode': 1.1.0
338
- '@earendil-works/pi-durable': 1.0.4(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
339
- '@earendil-works/pi-mcp': 1.1.0
340
- '@earendil-works/pi-protocol': 1.0.4
341
- '@earendil-works/pi-server': 1.0.4
331
+ '@ai-ecoverse/slicc-vault': 1.9.1
332
+ '@earendil-works/chord': 1.2.0
333
+ '@earendil-works/pi-ai': 1.2.0(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
334
+ '@earendil-works/pi-codemode': 1.2.0
335
+ '@earendil-works/pi-durable': 1.2.0(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
336
+ '@earendil-works/pi-mcp': 1.2.0
342
337
  '@sqlite.org/sqlite-wasm': 3.53.4-build2
338
+ typebox: 1.3.36
343
339
  transitivePeerDependencies:
344
340
  - '@aws-sdk/credential-provider-node'
345
341
  - '@smithy/hash-node'
@@ -350,10 +346,12 @@ snapshots:
350
346
  - ws
351
347
  - zod
352
348
 
353
- '@ai-ecoverse/slicc-browsers@1.5.0': {}
349
+ '@ai-ecoverse/slicc-browsers@1.7.1': {}
354
350
 
355
351
  '@ai-ecoverse/slicc-kernel@1.102.5': {}
356
352
 
353
+ '@ai-ecoverse/slicc-vault@1.9.1': {}
354
+
357
355
  '@anthropic-ai/sdk@0.129.0':
358
356
  dependencies:
359
357
  json-schema-to-ts: 3.1.1
@@ -543,13 +541,15 @@ snapshots:
543
541
 
544
542
  '@babel/runtime@7.29.7': {}
545
543
 
546
- '@earendil-works/chord@1.0.4': {}
544
+ '@earendil-works/chord@1.2.0':
545
+ dependencies:
546
+ typebox: 1.3.27
547
547
 
548
- '@earendil-works/pi-ai@1.0.4(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)':
548
+ '@earendil-works/pi-ai@1.2.0(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)':
549
549
  dependencies:
550
550
  '@anthropic-ai/sdk': 0.129.0
551
551
  '@aws-sdk/client-bedrock-runtime': 3.1127.0
552
- '@earendil-works/pi-telemetry': 1.0.4
552
+ '@earendil-works/pi-telemetry': 1.3.0
553
553
  '@smithy/node-http-handler': 4.12.1
554
554
  http-proxy-agent: 9.1.0
555
555
  https-proxy-agent: 9.1.0
@@ -566,19 +566,16 @@ snapshots:
566
566
  - ws
567
567
  - zod
568
568
 
569
- '@earendil-works/pi-client@1.0.4':
570
- dependencies:
571
- '@earendil-works/chord': 1.0.4
572
- '@earendil-works/pi-protocol': 1.0.4
573
-
574
- '@earendil-works/pi-codemode@1.1.0':
569
+ '@earendil-works/pi-codemode@1.2.0':
575
570
  dependencies:
576
571
  quickjs-wasi: 3.6.2
577
572
 
578
- '@earendil-works/pi-durable@1.0.4(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)':
573
+ '@earendil-works/pi-durable@1.2.0(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)':
579
574
  dependencies:
580
- '@earendil-works/chord': 1.0.4
581
- '@earendil-works/pi-ai': 1.0.4(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
575
+ '@earendil-works/chord': 1.2.0
576
+ '@earendil-works/pi-ai': 1.2.0(@aws-sdk/credential-provider-node@3.972.84)(@smithy/signature-v4@5.7.4)(ws@8.22.0)
577
+ '@earendil-works/pi-codemode': 1.2.0
578
+ '@silvia-odwyer/photon': 0.3.3
582
579
  diff: 8.0.4
583
580
  typebox: 1.3.27
584
581
  transitivePeerDependencies:
@@ -591,21 +588,13 @@ snapshots:
591
588
  - ws
592
589
  - zod
593
590
 
594
- '@earendil-works/pi-mcp@1.1.0':
591
+ '@earendil-works/pi-mcp@1.2.0':
595
592
  dependencies:
596
593
  cross-spawn: 7.0.6
597
594
 
598
- '@earendil-works/pi-protocol@1.0.4':
599
- dependencies:
600
- '@earendil-works/chord': 1.0.4
601
- typebox: 1.3.27
602
-
603
- '@earendil-works/pi-server@1.0.4':
604
- dependencies:
605
- '@earendil-works/chord': 1.0.4
606
- '@earendil-works/pi-protocol': 1.0.4
595
+ '@earendil-works/pi-telemetry@1.3.0': {}
607
596
 
608
- '@earendil-works/pi-telemetry@1.0.4': {}
597
+ '@silvia-odwyer/photon@0.3.3': {}
609
598
 
610
599
  '@smithy/core@3.35.1':
611
600
  dependencies:
@@ -720,6 +709,8 @@ snapshots:
720
709
 
721
710
  typebox@1.3.27: {}
722
711
 
712
+ typebox@1.3.36: {}
713
+
723
714
  which@2.0.2:
724
715
  dependencies:
725
716
  isexe: 2.0.0
@@ -291,6 +291,10 @@
291
291
  "integrity": "sha512-xpi0li0G2wD3ezIlHGcfDJ8Pd1/pT9w+dNU5U3vrx8XlkIAEnpjJRpPU/+sIDeBy81EauPd9H0M3ke33wZD53g==",
292
292
  "sha256": "ea735648aff0c8620b62462bcbe9023d10c7306bbb41930e140977a2aa530964"
293
293
  },
294
+ "@ai-ecoverse/wasi-fnox@1.39.0-2": {
295
+ "integrity": "sha512-puU9FN7kXKnlxaClZyqGd/m/229HHmVOA50+YExQBxzb1IrwPz/yS0Q1KDw0GnzC/glVLqu6jkSyc05LK1Fzyg==",
296
+ "sha256": "3b6607de060ea30756807aa936774842b3bded9f463025c4d10732a8b474b175"
297
+ },
294
298
  "@ai-ecoverse/wasi-esbuild@0.28.2-2": {
295
299
  "integrity": "sha512-Z6LXuBY2G9Po4cbEUFhbASSQ0ab5tdSHqtt1qDxNCgJFquAk525swjbTRVsj/j0v2iJVlq3Um1r2eYiYkGyLrQ==",
296
300
  "sha256": "9d9ed5820c8b5e8cb1924d4f2756e8a9a59f82ed344508ff1704b213bc1199ca"
@@ -371,6 +375,10 @@
371
375
  "integrity": "sha512-fEmBJVZ6DDWwogpP7mmgQGnOHqQ0VPCeuhJh/IkHsril59T5InBczSEZ2y8KY+Vl71lVQRKt5IJ5Au7JP4YpAQ==",
372
376
  "sha256": "b3ecab2258cd2e07fc71d38358eeaff3818d366559b41d37eb5d9af3fc10f5b8"
373
377
  },
378
+ "@ai-ecoverse/wasix-websocat@4.0.0-alpha3-3": {
379
+ "integrity": "sha512-D3iGDb+tx30SUwuONfyMfRDY9ZIJnEnF8A4X5r4P8uPXYUge9ZTL8wVTMW9x060kq0VN1w9mifNzDF6Lb1/fFA==",
380
+ "sha256": "50062e7d8f0d05eb04735aa3f5fd71b561bd831d7426f5a4baa0621980c20a61"
381
+ },
374
382
  "@ai-ecoverse/wasm-bash@5.3.0-13": {
375
383
  "integrity": "sha512-pusddMmR2Y7k1fSDtF8vCNzPcpe4LCPEvwPhsxhnx9V7NmMcdudBvPE1nKLzetnqNQtXLjVaMNvKPxzrLO9KGw==",
376
384
  "sha256": "10fea4a64c1622155b24127dcdecb4c843ce608b42725806d6ca944d5035d3b9"
@@ -150,6 +150,20 @@
150
150
  "commands": ["dig"],
151
151
  "size": 207317
152
152
  },
153
+ "@ai-ecoverse/wasix-websocat": {
154
+ "id": "websocat",
155
+ "label": "websocat",
156
+ "description": "Connects to WebSocket servers (ws:// and wss://) from the terminal. An upstream alpha (websocat 4). It speaks raw TCP, so hosts outside seven need an exit: a linked slicc CLI or a Tailscale exit node. A listener that can't bind still exits 0.",
157
+ "commands": ["websocat"],
158
+ "size": 1266828
159
+ },
160
+ "@ai-ecoverse/wasi-fnox": {
161
+ "id": "fnox",
162
+ "label": "fnox",
163
+ "description": "Secrets by name: fnox keeps placeholders and seven's vault keeps the values. Pipe a value into fnox set NAME to add or change one; fnox exec hands a program the values the secret rules allow.",
164
+ "commands": ["fnox"],
165
+ "size": 2154238
166
+ },
153
167
  "@ai-ecoverse/wasix-gnupg": {
154
168
  "id": "gpg",
155
169
  "label": "GnuPG",
@@ -12,6 +12,7 @@
12
12
  "@ai-ecoverse/wasi-buf": "1.73.0-2",
13
13
  "@ai-ecoverse/wasi-dig": "0.1.0-2",
14
14
  "@ai-ecoverse/wasi-esbuild": "0.28.2-2",
15
+ "@ai-ecoverse/wasi-fnox": "1.39.0-2",
15
16
  "@ai-ecoverse/wasi-gh": "2.102.0-1",
16
17
  "@ai-ecoverse/wasi-typescript": "7.0.2-1",
17
18
  "@ai-ecoverse/wasix-gnupg": "2.4.9-5",
@@ -20,6 +21,7 @@
20
21
  "@ai-ecoverse/wasix-python": "3.14.2-20",
21
22
  "@ai-ecoverse/wasix-ruby": "3.4.11-12",
22
23
  "@ai-ecoverse/wasix-uv-shim": "0.1.0-6",
24
+ "@ai-ecoverse/wasix-websocat": "4.0.0-alpha3-3",
23
25
  "@ai-ecoverse/wasm-git": "2.55.0-15",
24
26
  "@ai-ecoverse/wasm-libheif": "1.23.6-1",
25
27
  "@ai-ecoverse/wasm-poppler": "26.10.0-2",
@@ -96,6 +98,15 @@
96
98
  "slicc-kernel": ">=1.30.0"
97
99
  }
98
100
  },
101
+ "node_modules/@ai-ecoverse/wasi-fnox": {
102
+ "version": "1.39.0-2",
103
+ "resolved": "https://registry.npmjs.org/@ai-ecoverse/wasi-fnox/-/wasi-fnox-1.39.0-2.tgz",
104
+ "integrity": "sha512-puU9FN7kXKnlxaClZyqGd/m/229HHmVOA50+YExQBxzb1IrwPz/yS0Q1KDw0GnzC/glVLqu6jkSyc05LK1Fzyg==",
105
+ "license": "MIT",
106
+ "engines": {
107
+ "slicc-kernel": ">=1.83.0"
108
+ }
109
+ },
99
110
  "node_modules/@ai-ecoverse/wasi-gh": {
100
111
  "version": "2.102.0-1",
101
112
  "resolved": "https://registry.npmjs.org/@ai-ecoverse/wasi-gh/-/wasi-gh-2.102.0-1.tgz",
@@ -174,6 +185,15 @@
174
185
  "slicc-kernel": ">=1.51.0"
175
186
  }
176
187
  },
188
+ "node_modules/@ai-ecoverse/wasix-websocat": {
189
+ "version": "4.0.0-alpha3-3",
190
+ "resolved": "https://registry.npmjs.org/@ai-ecoverse/wasix-websocat/-/wasix-websocat-4.0.0-alpha3-3.tgz",
191
+ "integrity": "sha512-D3iGDb+tx30SUwuONfyMfRDY9ZIJnEnF8A4X5r4P8uPXYUge9ZTL8wVTMW9x060kq0VN1w9mifNzDF6Lb1/fFA==",
192
+ "license": "MIT OR Apache-2.0",
193
+ "engines": {
194
+ "slicc-kernel": ">=1.95.0"
195
+ }
196
+ },
177
197
  "node_modules/@ai-ecoverse/wasm-bash": {
178
198
  "version": "5.3.0-13",
179
199
  "resolved": "https://registry.npmjs.org/@ai-ecoverse/wasm-bash/-/wasm-bash-5.3.0-13.tgz",
@@ -9,6 +9,7 @@
9
9
  "@ai-ecoverse/wasi-buf": "1.73.0-2",
10
10
  "@ai-ecoverse/wasi-dig": "0.1.0-2",
11
11
  "@ai-ecoverse/wasi-esbuild": "0.28.2-2",
12
+ "@ai-ecoverse/wasi-fnox": "1.39.0-2",
12
13
  "@ai-ecoverse/wasi-gh": "2.102.0-1",
13
14
  "@ai-ecoverse/wasi-typescript": "7.0.2-1",
14
15
  "@ai-ecoverse/wasix-gnupg": "2.4.9-5",
@@ -17,6 +18,7 @@
17
18
  "@ai-ecoverse/wasix-python": "3.14.2-20",
18
19
  "@ai-ecoverse/wasix-ruby": "3.4.11-12",
19
20
  "@ai-ecoverse/wasix-uv-shim": "0.1.0-6",
21
+ "@ai-ecoverse/wasix-websocat": "4.0.0-alpha3-3",
20
22
  "@ai-ecoverse/wasm-git": "2.55.0-15",
21
23
  "@ai-ecoverse/wasm-libheif": "1.23.6-1",
22
24
  "@ai-ecoverse/wasm-poppler": "26.10.0-2",
@@ -10,7 +10,7 @@
10
10
  "@ai-ecoverse/slicc-cdp": "1.25.1",
11
11
  "@ai-ecoverse/slicc-clipboard": "1.0.2",
12
12
  "@ai-ecoverse/slicc-kernel": "1.102.5",
13
- "@ai-ecoverse/slicc-spectrum": "1.68.0",
13
+ "@ai-ecoverse/slicc-spectrum": "1.77.0",
14
14
  "@ai-ecoverse/wasi-pnpm": "12.9.1-8",
15
15
  "@ai-ecoverse/wasi-ripgrep": "15.2.0-3",
16
16
  "@ai-ecoverse/wasm-bash": "5.3.0-18",
@@ -77,9 +77,9 @@
77
77
  }
78
78
  },
79
79
  "node_modules/@ai-ecoverse/slicc-spectrum": {
80
- "version": "1.68.0",
81
- "resolved": "https://registry.npmjs.org/@ai-ecoverse/slicc-spectrum/-/slicc-spectrum-1.68.0.tgz",
82
- "integrity": "sha512-X4YdicEzvSvoaFC1zcVNXkQroENlXxqXe9ipF6YxW3G1F1L4+q5oDUfX7zUx4kD1ecpvtacH/k3szc6DS9HKdg==",
80
+ "version": "1.77.0",
81
+ "resolved": "https://registry.npmjs.org/@ai-ecoverse/slicc-spectrum/-/slicc-spectrum-1.77.0.tgz",
82
+ "integrity": "sha512-2IDp53NpmNoqKqdIgtv3H+wEAEYCp3Z4GeNp0DFnzqx/PUiC9crEdKt9ce3a3NHNJKtcPeDGwr1lu7GLRfEWPg==",
83
83
  "license": "Apache-2.0",
84
84
  "engines": {
85
85
  "node": ">=24"
@@ -7,7 +7,7 @@
7
7
  "@ai-ecoverse/slicc-cdp": "1.25.1",
8
8
  "@ai-ecoverse/slicc-clipboard": "1.0.2",
9
9
  "@ai-ecoverse/slicc-kernel": "1.102.5",
10
- "@ai-ecoverse/slicc-spectrum": "1.68.0",
10
+ "@ai-ecoverse/slicc-spectrum": "1.77.0",
11
11
  "@ai-ecoverse/wasi-pnpm": "12.9.1-8",
12
12
  "@ai-ecoverse/wasi-ripgrep": "15.2.0-3",
13
13
  "@ai-ecoverse/wasm-bash": "5.3.0-18",
@@ -21,8 +21,8 @@ importers:
21
21
  specifier: 1.102.5
22
22
  version: 1.102.5
23
23
  '@ai-ecoverse/slicc-spectrum':
24
- specifier: 1.68.0
25
- version: 1.68.0
24
+ specifier: 1.77.0
25
+ version: 1.77.0
26
26
  '@ai-ecoverse/wasi-pnpm':
27
27
  specifier: 12.9.1-8
28
28
  version: 12.9.1-8
@@ -111,8 +111,8 @@ packages:
111
111
  resolution: {integrity: sha512-p4ya+WnAUor3eo4hX9ZRDLCfgFn3RYac4Oas1UOO+Efnv2ecGKMCdGfPlGPCoIlrs6ab8FJl8YG1xGtGNem9JQ==}
112
112
  engines: {node: '>=24'}
113
113
 
114
- '@ai-ecoverse/slicc-spectrum@1.68.0':
115
- resolution: {integrity: sha512-X4YdicEzvSvoaFC1zcVNXkQroENlXxqXe9ipF6YxW3G1F1L4+q5oDUfX7zUx4kD1ecpvtacH/k3szc6DS9HKdg==}
114
+ '@ai-ecoverse/slicc-spectrum@1.77.0':
115
+ resolution: {integrity: sha512-2IDp53NpmNoqKqdIgtv3H+wEAEYCp3Z4GeNp0DFnzqx/PUiC9crEdKt9ce3a3NHNJKtcPeDGwr1lu7GLRfEWPg==}
116
116
  engines: {node: '>=24'}
117
117
  peerDependencies:
118
118
  '@shikijs/langs': 4.5.0
@@ -207,7 +207,7 @@ snapshots:
207
207
 
208
208
  '@ai-ecoverse/slicc-kernel@1.102.5': {}
209
209
 
210
- '@ai-ecoverse/slicc-spectrum@1.68.0': {}
210
+ '@ai-ecoverse/slicc-spectrum@1.77.0': {}
211
211
 
212
212
  '@ai-ecoverse/wasi-pnpm@12.9.1-8': {}
213
213