@ai-ecoverse/slicc-bios 1.10.1 → 1.11.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 CHANGED
@@ -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, the GitHub CLI, OpenSSH, Python, Node.js (slicc-jsh's `node` and `jsh`), `sliccy:browser` for `.jsh` scripts, Ruby, Perl, Biome, the PDF tools (poppler), qpdf, rsync, screen, SQLite, dig, websocat, GnuPG and fnox.
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, the GitHub CLI, OpenSSH, `slicc` (see [Sevens this kernel follows](#network)), Python, Node.js (slicc-jsh's `node` and `jsh`), `sliccy:browser` for `.jsh` scripts, Ruby, Perl, Biome, the PDF tools (poppler), qpdf, rsync, 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.
@@ -331,7 +331,7 @@ seven can also join a tailnet, with a patched build of Tailscale's wasm client (
331
331
  - **No agent:** with no agent running, or a slicc-agent without page-side webhooks, the delivery is dropped with a warning. The hub has already answered the sender `202`.
332
332
  - **Remote control (`agent`):** a linked CLI can prompt, watch and stop seven's agent (`slicc prompt`, `slicc watch`, `slicc abort`). The page offers cap `agent` to a CLI on this computer always, and to a remote device only after **Control** is turned on for it in Linked devices. That setting is kept per device certificate and cleared by unlinking it. Any other link's agent OPEN gets `EACCES`.
333
333
  - Each `OPEN { kind: 'agent', op }` goes to the agent of the tab that runs the kernel, on its active cone, through slicc-agent's `remoteControl`. `prompt` answers OPENED with how the prompt was delivered (or `RESET EBUSY` for `whenBusy: 'reject'` while busy), then streams NDJSON events from the prompt's own `user` event to its `end` line. A prompt over about 60 KiB comes as `length` bytes after an empty OPENED, and the first line then says how it was delivered. `watch` answers with the transcript `head` (and `gap` when `since` is gone), then streams events. `abort` answers `{ aborted }`.
334
- - A CLI that goes away ends its stream but never aborts the run; aborting is explicit.
334
+ - A CLI that goes away ends its stream but never aborts the run; aborting is explicit. A `watch` the CLI half-closes right after OPENED, as slicc does, still ends at once when it is later reset or its link closes, so **Watching** clears without waiting for the agent's next event.
335
335
  - Linked devices lists every device that has linked, offline ones too, with its control setting, and shows **Prompting** or **Watching** while a CLI does, also in the header.
336
336
  - 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.
337
337
  - **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.
@@ -374,6 +374,14 @@ seven can also join a tailnet, with a patched build of Tailscale's wasm client (
374
374
  - **Chat (`pi`):** with View, the follower opens `OPEN { kind: 'pi' }` and gets the owner's agent, the same replicated chat a follower tab has. The owner bridges the stream to `owner.port({ readOnly, pages: false })` with slicc-agent's `bridgePort` (agent ≥ 3.32.0), read-only unless the device has Control, and without `pages`, so a follower's agent can't drive the owner's panels. The follower builds its `AgentConnection` with `linkEndpoint` and `connectAgent`, and spectrum's agent model on top. The stream carries slicc-agent's frames: a `u32` length, a `u8` tag (data, hello or close) and the payload. Without Control, a send, steer or stop is refused by the owner's agent with `EACCES`, and the chat shows that it watches only. Changing Control resets the stream, so the follower reconnects with the new access, and losing View resets it with `EACCES`. The follower installs `/opt/agent` itself, for `page.js` and the agent model, in a kernel it starts only for that install. Linked devices shows *Watching* while a follower's chat is open.
375
375
  - **Terminals (`terminal`):** with View and Terminal, the follower's Terminal panel opens shells in the owner's kernel. Each one is `OPEN { kind: 'terminal', cols, rows, cwd? }`, and the owner runs `bash -i` there with its own terminals' prompt, as the same user its own terminals use (root today, so Terminal is a root shell on the owner's SLICC), and answers OPENED `{ pid }`. Both directions then carry records, each a `u32` length, a `u8` type and a payload: `0` terminal bytes, `1` a resize as `{ cols, rows }` JSON, `2` a signal name (`INT`, `TSTP`, `QUIT`, `HUP`), and, from the owner only, `3` the shell's exit status as a decimal string, just before END. A bad record or size resets the stream with `EPROTO` or `EINVAL`. The follower's END closes the shell, and the owner ends the stream when the shell exits. Linked devices shows *Terminal open* while one runs (`terminals`), and turning Terminal or View off resets every open shell with `EACCES`.
376
376
  - **Names:** both sides call themselves `SLICC on <platform>` (`navigator.userAgentData.platform`). When two show the same name, the first four hex digits of the certificate fingerprint are added.
377
+ - **Sevens this kernel follows (the in-kernel `slicc`):** the optional `slicc` package (`@ai-ecoverse/wasi-slicc`, slicc-cli's client commands built for `wasip1`) runs `slicc <join-url> prompt|watch|abort` in seven's terminal against another seven's agent, as slicc-cli's README specifies in §1.4 and §5.16. The program never touches WebRTC, the hub or the join state: it reaches the page's **link facade** at `SLICC_LINK_URL` (`tcp://127.0.0.1:7400`), which `os/os.js` declares with `createKernel({ facades: { link: { port: 7400, hook } } })` (`os/facade.js`, slicc-kernel ≥ 1.90.0), and the page follows that seven's tray for it (`os/leaders.js`).
378
+ - **Who may:** only under kernel users `enforce`, and only root and members of `sudo` (cones), as the kernel's stamp on the connection says. A scoop gets `EACCES` and a `connect` denial in `denials.log`; under `off` and `report` everyone gets `EACCES`.
379
+ - **The facade:** one connection per stream, in records of a `u8` type (`1` control, `2` data, `3` end), a `u32` length and the payload. The first record is `{ v: 1, join, open }`, and the page answers `{ opened }` or `{ reset: 'ERRNO: message' }`. Only `kind: 'agent'` with `prompt`, `watch` or `abort` opens, with only the fields those take. A long prompt (`length`) is answered at once, read whole, and sent on with the length of what it became. After that, only a `reset` may come as control, and it passes on just its errno.
380
+ - **Secrets:** while the vault holds values, every outgoing prompt passes its scrubber (`redact`, on an agent-role port of the page's own), so a value leaves as its placeholder. While the scrubber is locked, the answer is `EACCES: unlock the vault to continue`.
381
+ - **The link:** the page attaches as runtime `slicc-link/1`, so the other seven treats it as a CLI: it needs **Allow remote control** for this device in its Linked devices, or the answer is `EACCES` with that hint (and the link is closed, so the next run sees a fresh HELLO). The page's HELLO has `caps: []` and a fresh `node`, it opens only `agent` streams, and it refuses every stream the other seven opens with `EACCES`. There is one link per join URL, dialled on demand (45 s per dial, with retries after 1, 2 and 5 s), kept while a stream uses it and closed 10 minutes after the last one ends.
382
+ - **Identity and state:** one certificate per hub origin in the IndexedDB database `slicc-follow`, under `link:<hub>`, apart from a follower tab's own. `localStorage` (`slicc-os.leaders`, the newest 16) keys each join URL's state by its SHA-256 and keeps only a moved tray's new URL. The join URL itself is never stored, logged or put in an error. An `UNLINKED` refusal deletes that hub's certificate and state, so the next run is a new device.
383
+ - **Refusals:** a join URL on a hub seven doesn't link through, a forged or expired one, and an unlink are `EACCES`, so `slicc` exits 3 with the reason. A tray that can't be reached in time is `ENOTCONN`, which `watch` retries.
384
+ - **Tests:** `test/integration/follow-slicc.test.mjs` runs the real `slicc` from the catalog as a cone in seven's terminal against a second seven's real agent over a fake tray hub: refused until Allow remote control, then prompt, watch and abort; a vault value scrubbed on the way out; a forged URL, another hub, a scoop and an unlinked device refused; and a fake leader whose `unlink`, `join`, `agent` and `kernel` OPENs are refused while it is followed.
377
385
  - **The tray:** its capabilities are kept in `localStorage` (`slicc-os.tray`), so the join URL survives reloads. A hub that forgot the tray gets a new one. The leader socket pings every 30 s and reconnects with backoff. Elsewhere (`localhost`, tests) the tray starts only when `localStorage['slicc-os.tray-hub']` names a hub.
378
386
  - **Kernel side:** the kernel gets one uplink and one route table, the union of what the active exits offer, pushed with `kernel.setRoutes`.
379
387
  - **Choosing an exit:** for each destination, an exit that claims it (a tailnet address or MagicDNS name) wins. Otherwise the default exit takes it: the one that offers a default route, for example Tailscale with an exit node. Otherwise HTTP stays on the picked transport, and raw connections are `ENETUNREACH`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-bios",
3
- "version": "1.10.1",
3
+ "version": "1.11.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.42.0",
45
+ "@ai-ecoverse/slicc": "1.42.4",
46
46
  "@ai-ecoverse/slicc-browsers": "1.7.6",
47
47
  "@ai-ecoverse/slicc-node": "2.5.1",
48
48
  "@ai-ecoverse/slicc-shared-web": "1.23.1",
@@ -260,6 +260,10 @@
260
260
  "integrity": "sha512-UYnMCCev7OQYAOGJ+sO/wbmZGg5mOlsaa8zJPtsrere2mrKHczvwMYmLnGeC1cqV3XW/AwRlMNk0j+S3pYUZ2A==",
261
261
  "sha256": "d7db54ccdade9379aff3fa90fd8b07bb48990d96097fde39691b0fa17bffe2fe"
262
262
  },
263
+ "@ai-ecoverse/wasi-slicc@1.41.0": {
264
+ "integrity": "sha512-uPFR8MkUZ5IeDF6EHEehG74ZXpS5imlxZLSxqevMtbPTeNUHOMl+jTHo4INnPE6avtT1aY5LQnAPs1EM8Nh8Aw==",
265
+ "sha256": "15d742df5303089573122181d510d9e8700fff6c72cb0f3cbed650ecccabf3a9"
266
+ },
263
267
  "@ai-ecoverse/wasix-gnupg@2.4.9-4": {
264
268
  "integrity": "sha512-O1V9mpj62CiI6gkKcD0YxBaHKRZ3pDLdwVB8hif2DBOin4bQsWaHgUn0P7jaoArIUjlD/Ak3Wk/u+wJawto/FA==",
265
269
  "sha256": "7b36fec5ff7585373c8f22482b245641e38d979d61c470383b030d678a3893ff"
@@ -20,6 +20,13 @@
20
20
  "commands": ["ssh", "scp", "sftp", "ssh-keygen", "ssh-add"],
21
21
  "size": 3355615
22
22
  },
23
+ "@ai-ecoverse/wasi-slicc": {
24
+ "id": "slicc",
25
+ "label": "slicc",
26
+ "description": "Prompts, watches and aborts another seven's agent from this terminal: slicc <join-url> prompt, watch or abort. For root and cones; the other seven must allow remote control from this one in its Linked devices.",
27
+ "commands": ["slicc"],
28
+ "size": 1324902
29
+ },
23
30
  "@ai-ecoverse/wasix-python": {
24
31
  "id": "python",
25
32
  "label": "Python",
@@ -12,6 +12,7 @@
12
12
  "@ai-ecoverse/wasi-dig": "0.1.0-2",
13
13
  "@ai-ecoverse/wasi-fnox": "1.39.0-2",
14
14
  "@ai-ecoverse/wasi-gh": "2.102.0-1",
15
+ "@ai-ecoverse/wasi-slicc": "1.41.0",
15
16
  "@ai-ecoverse/wasix-gnupg": "2.4.9-5",
16
17
  "@ai-ecoverse/wasix-openssh": "10.6.0-6",
17
18
  "@ai-ecoverse/wasix-perl": "5.42.0-11",
@@ -94,6 +95,15 @@
94
95
  "slicc-kernel": ">=1.30.0"
95
96
  }
96
97
  },
98
+ "node_modules/@ai-ecoverse/wasi-slicc": {
99
+ "version": "1.41.0",
100
+ "resolved": "https://registry.npmjs.org/@ai-ecoverse/wasi-slicc/-/wasi-slicc-1.41.0.tgz",
101
+ "integrity": "sha512-uPFR8MkUZ5IeDF6EHEehG74ZXpS5imlxZLSxqevMtbPTeNUHOMl+jTHo4INnPE6avtT1aY5LQnAPs1EM8Nh8Aw==",
102
+ "license": "Apache-2.0",
103
+ "engines": {
104
+ "slicc-kernel": ">=1.92.0"
105
+ }
106
+ },
97
107
  "node_modules/@ai-ecoverse/wasix-gnupg": {
98
108
  "version": "2.4.9-5",
99
109
  "resolved": "https://registry.npmjs.org/@ai-ecoverse/wasix-gnupg/-/wasix-gnupg-2.4.9-5.tgz",
@@ -9,6 +9,7 @@
9
9
  "@ai-ecoverse/wasi-dig": "0.1.0-2",
10
10
  "@ai-ecoverse/wasi-fnox": "1.39.0-2",
11
11
  "@ai-ecoverse/wasi-gh": "2.102.0-1",
12
+ "@ai-ecoverse/wasi-slicc": "1.41.0",
12
13
  "@ai-ecoverse/wasix-gnupg": "2.4.9-5",
13
14
  "@ai-ecoverse/wasix-openssh": "10.6.0-6",
14
15
  "@ai-ecoverse/wasix-perl": "5.42.0-11",