@ai-ecoverse/slicc-bios 1.55.2 → 1.55.4

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
@@ -143,7 +143,7 @@ The kernel runs with users on (slicc-kernel ≥ 1.81.0): files have owners and m
143
143
  - **Global packages** (`pnpm add -g` into `/usr/local/share/pnpm`) aren't protected and run untagged.
144
144
  - **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*.
145
145
  - **Sudo approvals through the agent** (slicc-agent ≥ 5.9.0): while the agent runs, the kernel's `approve` hook hands each request to the agent's `owner.approve(req, { signal, where })`. It becomes a `sudo` item in the agent's approvals, which every owner device answers with the same powers: this tab, other tabs, and linked followers with or without Control, *Always allow* included where bios offered it. bios sets `req.always` from the checks below, and turns an *Always* it didn't offer into *Allow once*. A request from a follower's shell names that device (`where`, "on <device>"), and each linked device's agent port is opened with `owner.port({ device })`, so the item records which device answered. The tab hands its own approvals port to `createAgentModel(connection, { approvals })`, so `model.approvals` lists both sets. When the agent can't take a request (it rejects with `EAGAIN`: released, restarting or an older worker) or isn't running, bios's own dialog below asks instead.
146
- - **Sudo approvals in bios's dialog:** 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.
146
+ - **Sudo approvals in bios's dialog:** 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`, where `certain`, `maybe` and `once` all count; `once` is `xargs` running a program whose write flags spectrum gates, such as `xargs sort`, which may get a write flag from its input; 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.
147
147
  - **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.
148
148
  - **Schedules** (slicc-agent ≥ 5.9.0, slicc-kernel ≥ 1.110.0): each user's kernel crontab (`/var/spool/cron/crontabs/<user>`, `crontab -l`) holds them, and the kernel runs a due job as its user. A job that runs `agent send <target> '<message>'` comes back as a cron lick. The agent moves an older agent's `~/.slicc/crontab` lines into the file owner's crontab (as `# name: <name>` and `<schedule> agent send …`) and keeps the file as `~/.slicc/crontab.migrated`.
149
149
  - **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.
@@ -172,6 +172,8 @@ A local folder can be mounted into seven as on Linux ([#73](https://github.com/a
172
172
  2. **Once it's installed,** the page imports `page.js` and `spectrum/index.js` from `/opt/agent/node_modules/@ai-ecoverse/slicc-agent/dist/`. `startAgent` takes the Web Lock `slicc-agent`, starts `agent-worker.js` from there as a module worker and hands it a port to the page's kernel, so the agent's `bash`, `read`, `write` and `edit` run on the same kernel and files as the terminal. The page swaps in `createAgentModel()` when the worker connects. On later loads the agent starts at once, before any network check, so chat works offline. If another tab owns the agent, this tab has terminals and files only.
173
173
  3. **The conversation** is kept in SQLite in OPFS (`/.slicc/agent/`).
174
174
 
175
+ CI checks the agent lockfile used by both beta checks and owner-pin updates against npm publish times, requiring third-party dependencies to exceed the workspace's `minimumReleaseAge` by one hour before a bump can ship.
176
+
175
177
  **The `panel` command** (slicc-agent ≥ 3.43.0, spectrum ≥ 1.60.0) lets the agent arrange seven's panels. Every local tab, the one that owns the agent and the tabs that follow it in the same browser, gives `createAgentModel()` a `page` bridge with its tab id, and the bridge runs spectrum's `panelCommand(app, argv, caller)` on that tab. A page that follows seven over a link never gets one. So `panel open monitor left`, `panel reset` and the other verbs in the agent's `bash` act on the tab showing the caller's cone, `panel tabs` lists the tabs, and `--tab <id>` picks one. Each terminal a tab opens has `SLICC_TAB` set to that tab's id, so `panel` typed in it acts on that tab.
176
178
 
177
179
  Under users `'off'` and `'report'`, `/opt/agent` is an ordinary pnpm project, so `cd /opt/agent && pnpm upgrade` updates the agent in place, and the pin survives seven's updates ([Your packages](#your-packages)), and the service worker drops its resolution cache when `/opt/agent`'s lockfile or `.modules.yaml` changes. When an update installs a new `/opt/agent` while the agent runs, the **Agent** row says *Ready to apply* and offers **Restart agent** (D16). It waits until the agent is idle, then stops the agent worker, imports the newly installed `page.js` and `spectrum/index.js` again and starts the new `agent-worker.js` with them; durable resumes the conversation from SQLite, and the page reconnects and swaps in the new connection and the new adapter's `createAgentModel()`, closing the old connection. The kernel, terminals and the page itself keep running. The page holds one module instance per URL, so each restart, and each retry after a failed import (Chrome keeps a module's failure under its URL too), imports the adapter as `page.js?run=<n>` with a new `n`; the service worker ignores `run` when it reads the file and adds the same `run` to every import that resolves inside `/opt/agent`, so the adapter's own files and dependencies load from the new install while the base set's modules stay shared. If the restart fails, no agent worker is left running and the row offers **Retry**, which starts the installed agent.
@@ -427,13 +429,15 @@ An older extension, or one that cannot report a supported release version, refus
427
429
 
428
430
  - **Known limit:** extensions that refuse `Target.setAutoAttach` leave an ordinary page with a cross-site iframe locked for paint, DOM, CSS, accessibility and input. The guard fails closed when it cannot place the child.
429
431
 
430
- **Sign-in tabs are held for life (#754).** A sign-in popup shows its token or code in its URL and on the IdP's pages, and the guard can't scrub a page's own content. So the owner tab holds every sign-in tab from the moment it opens. A held tab is never listed, attached, auto-attached or reported to a program on any origin, until it closes. Its events, `urlFragment` included, never reach the program.
432
+ **Sign-in tabs are held for life (#754).** A sign-in popup shows its token or code in its URL and on the IdP's pages, and the guard cannot scrub a page's own content. The owner holds it before sign-in starts. A held tab and its descendants are not listed, attached, auto-attached or reported to a program on any origin until they close.
431
433
  - **Seven's own sign-in:** the popup opens on `about:blank#slicc-sign-in-<nonce>`. bios asks the owner over the `slicc-held` BroadcastChannel to hold it. The owner finds that target by its marker URL on each browser host (slicc-extension, a DevTools port), holds it, and only then is the popup sent to the IdP. The owner answers `held` once it has held the tab on every listed host, `none` when no host is listed, and `unheld` otherwise, including when a listed host can't be opened. On `unheld`, on `none` while bios sees a host, or on no answer within 6 s while a host is connected, the sign-in stops before the IdP and says so; it never goes on unheld. On `none`, the sign-in goes on, and the owner keeps it as in flight for 11 minutes (in `localStorage`, `slicc-os.sign-in-flight`, so a reload keeps it). Before any program gets a browser connection, the owner sweeps every host: it holds sign-in tabs still on `about:blank`, and while a sign-in is in flight, every page a protected page opened. So a host that connects in the middle of a sign-in never sees its tab.
432
- - **The guard decides by itself, too:** a page that a held tab opened is held, on any URL, and so are its own popups in turn, and so are the frames and workers of a held tab (`parentId`). A page seven (or another protected page) opened with opener access (`canAccessOpener`), or that is still on `about:blank`, is held the first time any guard sees it.
433
- - **Other sign-in tabs:** a watcher in the owner tab holds every page that a protected page (seven or the vault) opened and that is still on `about:blank`, and a popup that a held tab opens, such as the IdP's own. It goes through slicc-extension and only polls every 250 ms once a program or a sign-in needs the browser, and the extension reports no opener access, so only marked popups are held reliably there: an unmarked popup that leaves `about:blank` before the next poll can be missed, and a program could then list it, URL and fragment included (a known gap). Seven's own Adobe sign-in carries the marker. The agent's MCP OAuth and device-code popups carry it from slicc-agent 6.19.15 (#550), which seven pins: they ask on `slicc-held` and navigate only on `held` or `none`, so they are held before they leave `about:blank`, and with no holder answering the agent's sign-in fails.
434
+ - **The guard decides by itself, too:** every child of a held opener stays held, whatever its origin, including the frames and workers of a held tab (`parentId`). The cross-origin exception applies only to an opener that is itself an unheld HTTP(S) page on seven's or the vault's protected origin, including seven's runtime origin. A settled ordinary HTTP(S) child of that page can remain drivable when fresh, consistent child and opener metadata proves their origins differ and the opener has no held ancestry after applying the opener rules to each fresh ancestor in its opener and parent chains. Same-origin and inherited `about:blank` or `about:srcdoc` children stay held. An initial empty target explicitly reporting no opener access is not made permanently held merely by that empty metadata; its eventual document is checked before use. Empty targets with opener access remain held.
435
+ - **Other sign-in tabs:** the owner watcher holds children of held tabs on every origin. For unheld protected-origin openers, outside sign-in flight it holds children with opener access and inherited about:blank or about:srcdoc children, while skipping other children without opener access; the guard still checks them at attach time. It retains earlier target observations to establish holds, including standalone blank-child events. Its cross-origin exception requires both targets in the same fresh batch; a retained opener URL cannot waive a hold. While sign-in is in flight, the sweep still holds cross-origin children of a protected opener. The watcher connects through slicc-extension and polls every 250 ms once a program or sign-in needs the browser. Only marked popups are held reliably there: an unmarked popup that leaves its initial inherited document before it is observed can be missed (a known gap). Seven's Adobe sign-in and the agent's MCP OAuth and device-code popups carry the hold marker before navigating; without a required holder's answer, sign-in fails.
434
436
  - **Kept:** held tab ids are kept in `localStorage` (`slicc-os.held-targets`, the 32 most recently held or seen again), so a reload of the owner keeps them.
435
437
  - **The watcher's connections:** it connects to slicc-extension only once a program or a sign-in needs the browser. Before any program gets a browser connection, the owner sweeps every host; if that listing fails, the program gets no connection, and no host connection is opened for it.
436
- - **A tab only lent seven's protection** is one that seven opened with no opener access, or that inherited it only from about:blank. It becomes drivable once it commits an ordinary `http:`, `https:` or `data:` page, whether the program saw it at creation or later. Real protected origins stay protected for life, a `blob:` of seven's origin included.
438
+ - **Ordinary cross-origin HTTPS children** of seven's or the vault's own unheld pages are no longer held merely by the opener rules when fresh settled metadata proves the difference. A blank-first or inherited empty child, such as `window.open('')` followed by a location assignment, stays held for the tab's life after navigating or losing its opener. An existing hold, including a bare target id stored by an older version, is never released merely because opener metadata disappears or no sign-in is in flight.
439
+ - **Fresh session checks:** before a command on a page session is forwarded, fresh target metadata and opener ancestry are checked, including CSS, session Fetch and Runtime or DOM metadata commands, except Page.handleJavaScriptDialog when the existing dialog prelude admits it without reading the page. A page reporting opener access without an opener id is refused as unknown.
440
+ - **Cross-origin opener handles** can still send messages, navigate where browser rules permit, focus or blur the window, close a script-closable window, inspect `closed` and `length`, and expose `frames` or indexed window references. They do not permit cross-origin DOM reads.
437
441
 
438
442
  A tab a program creates through the guard opens in the background, behind seven, unless it passes `background: false`. A program that needs seven to keep rendering should open tabs, the default, and not `newWindow`: even unfocused, a new window can cover seven's window, and Chrome then throttles seven ([slicc-extension#105](https://github.com/ai-ecoverse/slicc-extension/issues/105)).
439
443
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-bios",
3
- "version": "1.55.2",
3
+ "version": "1.55.4",
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",
@@ -54,7 +54,7 @@
54
54
  "@ai-ecoverse/slicc-cdp": "1.45.0",
55
55
  "@ai-ecoverse/slicc-kernel": "1.173.3",
56
56
  "@ai-ecoverse/slicc-shared-web": "2.13.10",
57
- "@ai-ecoverse/slicc-spectrum": "1.111.0",
57
+ "@ai-ecoverse/slicc-spectrum": "1.111.2",
58
58
  "@ai-ecoverse/slicc-vault": "1.22.0",
59
59
  "@biomejs/biome": "2.6.3",
60
60
  "aws4fetch": "1.0.20",
@@ -10,7 +10,7 @@
10
10
  "@ai-ecoverse/slicc-browsers": "1.19.0",
11
11
  "@ai-ecoverse/slicc-capture": "1.4.1",
12
12
  "@ai-ecoverse/slicc-kernel": "1.173.3",
13
- "@ai-ecoverse/slicc-spectrum": "1.111.0",
13
+ "@ai-ecoverse/slicc-spectrum": "1.111.2",
14
14
  "@ai-ecoverse/wasi-fnox": "1.43.0-1",
15
15
  "@ai-ecoverse/wasi-pnpm": "12.9.1-21",
16
16
  "@ai-ecoverse/wasm-bash": "5.3.0-23",
@@ -146,9 +146,9 @@
146
146
  }
147
147
  },
148
148
  "node_modules/@ai-ecoverse/slicc-spectrum": {
149
- "version": "1.111.0",
150
- "resolved": "https://registry.npmjs.org/@ai-ecoverse/slicc-spectrum/-/slicc-spectrum-1.111.0.tgz",
151
- "integrity": "sha512-ic+Fu4UvgT8KeOUPymP4p1eJsVpJsnqxc6/V+qjDIQo1nurZ+w3n8LTEMMyYRrzDxM/MkcT1ZmtCiLk/Wn3L2g==",
149
+ "version": "1.111.2",
150
+ "resolved": "https://registry.npmjs.org/@ai-ecoverse/slicc-spectrum/-/slicc-spectrum-1.111.2.tgz",
151
+ "integrity": "sha512-cwuPI7+KEzw09SyfVguXc2QJdeXtihjGOPpkXzbzcEHWlHbLitaCzdQ9SBYf/yQntuejqPcNaxGrWWq+yrOcRA==",
152
152
  "license": "Apache-2.0",
153
153
  "engines": {
154
154
  "node": ">=24"
@@ -7,7 +7,7 @@
7
7
  "@ai-ecoverse/slicc-browsers": "1.19.0",
8
8
  "@ai-ecoverse/slicc-capture": "1.4.1",
9
9
  "@ai-ecoverse/slicc-kernel": "1.173.3",
10
- "@ai-ecoverse/slicc-spectrum": "1.111.0",
10
+ "@ai-ecoverse/slicc-spectrum": "1.111.2",
11
11
  "@ai-ecoverse/wasi-fnox": "1.43.0-1",
12
12
  "@ai-ecoverse/wasi-pnpm": "12.9.1-21",
13
13
  "@ai-ecoverse/wasm-bash": "5.3.0-23",
@@ -21,8 +21,8 @@ importers:
21
21
  specifier: 1.173.3
22
22
  version: 1.173.3
23
23
  '@ai-ecoverse/slicc-spectrum':
24
- specifier: 1.111.0
25
- version: 1.111.0
24
+ specifier: 1.111.2
25
+ version: 1.111.2
26
26
  '@ai-ecoverse/wasi-fnox':
27
27
  specifier: 1.43.0-1
28
28
  version: 1.43.0-1
@@ -105,8 +105,8 @@ packages:
105
105
  webgpu:
106
106
  optional: true
107
107
 
108
- '@ai-ecoverse/slicc-spectrum@1.111.0':
109
- resolution: {integrity: sha512-ic+Fu4UvgT8KeOUPymP4p1eJsVpJsnqxc6/V+qjDIQo1nurZ+w3n8LTEMMyYRrzDxM/MkcT1ZmtCiLk/Wn3L2g==}
108
+ '@ai-ecoverse/slicc-spectrum@1.111.2':
109
+ resolution: {integrity: sha512-cwuPI7+KEzw09SyfVguXc2QJdeXtihjGOPpkXzbzcEHWlHbLitaCzdQ9SBYf/yQntuejqPcNaxGrWWq+yrOcRA==}
110
110
  engines: {node: '>=24'}
111
111
 
112
112
  '@ai-ecoverse/wasi-fnox@1.43.0-1':
@@ -270,7 +270,7 @@ snapshots:
270
270
  - utf-8-validate
271
271
  optional: true
272
272
 
273
- '@ai-ecoverse/slicc-spectrum@1.111.0': {}
273
+ '@ai-ecoverse/slicc-spectrum@1.111.2': {}
274
274
 
275
275
  '@ai-ecoverse/wasi-fnox@1.43.0-1': {}
276
276