@ai-ecoverse/slicc 1.47.0 → 1.47.2
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 +19 -10
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -394,7 +394,7 @@ The cdp list follows the browsers: an extra that stops answering is taken off th
|
|
|
394
394
|
- `launched`: `browser` (the id), `name`, `version?`, `role` (`seven` or `extra`), `pid`, `profile?`, `profileDir?`, `cdp`, `webSocketDebuggerUrl`.
|
|
395
395
|
- `attached`: `browser`, `name`, `version?`, `role`, `launched?` (`true` when this run launched it), `cdp`, `webSocketDebuggerUrl?`. For `seven` slicc is connected to it over CDP; an `extra` is listed for `cdp`.
|
|
396
396
|
- `foreign-browser`: `browser`, `name`, `profile?`, `cdp`, `openedTab` (`true` when slicc opened the seven tab, `false` when one was open). It follows `attached` when the browser hosting seven is an endpoint slicc didn't launch and the user didn't choose it (see above), and always when it is SLICC six's Chrome, with `profile` `six` or `six:<port>`. The same line goes to stderr.
|
|
397
|
-
- `linked`: `peer?` (the name in seven's HELLO), `tab?` (the seven tab's
|
|
397
|
+
- `linked`: `peer?` (the name in seven's HELLO), `tab?` (the seven tab's origin, never its path or fragment), `caps`, `policy` (the summary).
|
|
398
398
|
- `link-lost`: `reason?` when slicc or seven closed the link (`slicc is exiting`, `slicc is relinking`, seven's `bye` reason, `replaced by a new offer`), or `message?` for a failure. seven sets the link up again after a reload, and a new `linked` follows.
|
|
399
399
|
- `browser-gone`, `browser-back`: `browser`, `name`, `role`. A browser stopped answering and left the cdp list, or answers again and is back on it.
|
|
400
400
|
- `browser-slow`: `browser`, `name`, `role`, `elapsed` (seconds). A browser slicc launched hasn't written its `DevToolsActivePort` yet, every 10 s from 10 s on (see [`slicc launch`](#slicc-launch---browser-id---profile-name---url-url---headless---no-seven-flags---json)). The dashboard and plain mode show it as `<name> is still starting (slow disk?), <n> s so far`.
|
|
@@ -407,7 +407,7 @@ The cdp list follows the browsers: an extra that stops answering is taken off th
|
|
|
407
407
|
{"schema":1,"event":"discovered","entries":[…]}
|
|
408
408
|
{"schema":1,"event":"launched","browser":"chrome","name":"Google Chrome","version":"154.0.8037.98","role":"seven","pid":4242,"profile":"chrome","profileDir":"…/slicc/seven-profiles/chrome","cdp":"http://127.0.0.1:53211","webSocketDebuggerUrl":"ws://127.0.0.1:53211/devtools/browser/…"}
|
|
409
409
|
{"schema":1,"event":"attached","browser":"chrome","name":"Google Chrome","version":"154.0.8037.98","role":"seven","launched":true,"cdp":"http://127.0.0.1:53211","webSocketDebuggerUrl":"ws://127.0.0.1:53211/devtools/browser/…"}
|
|
410
|
-
{"schema":1,"event":"linked","tab":"https://seven.sliccy.ai
|
|
410
|
+
{"schema":1,"event":"linked","tab":"https://seven.sliccy.ai","peer":"seven","caps":["net","http","credentialed","ws","cdp"],"policy":"every public address, this machine, and the local network"}
|
|
411
411
|
{"schema":1,"event":"link-lost","reason":"slicc is exiting"}
|
|
412
412
|
{"schema":1,"event":"closed","browsers":["chrome"]}
|
|
413
413
|
```
|
|
@@ -461,7 +461,7 @@ Endpoints are merged by host and port. A `DevToolsActivePort` file wins over `--
|
|
|
461
461
|
"browser": "chrome",
|
|
462
462
|
"userDataDir": "/Users/me/Library/Application Support/Google/Chrome",
|
|
463
463
|
"sevenOpen": true,
|
|
464
|
-
"sevenTabs": [{ "id": "…", "url": "https://lars.sliccy.ai
|
|
464
|
+
"sevenTabs": [{ "id": "…", "url": "https://lars.sliccy.ai", "title": "https://lars.sliccy.ai" }]
|
|
465
465
|
}
|
|
466
466
|
},
|
|
467
467
|
{
|
|
@@ -488,7 +488,7 @@ Endpoints are merged by host and port. A `DevToolsActivePort` file wins over `--
|
|
|
488
488
|
```
|
|
489
489
|
|
|
490
490
|
- Entry: `id` (an installed id, or `cdp:<host>:<port>`), `kind` (`endpoint` or `installed`), `tier` (1–6), `name`, `version?`, and either `endpoint` or `installed`.
|
|
491
|
-
- `endpoint`: `cdp` (the HTTP base URL), `webSocketDebuggerUrl`, `name`, `version?`, `product?` and `userAgent?` (from `/json/version`), `source` (`devtools-active-port`, `flag`, `process` or `probe`), `browser?` (the installed id whose user-data dir held the file), `userDataDir?` (the dir that held the file, or a process's `--user-data-dir`), `profile?` (the SLICC profile name), `wsOnly?`, `six?` (`true` for SLICC six's Chrome), `sevenOpen`, `sevenTabs` (always a list).
|
|
491
|
+
- `endpoint`: `cdp` (the HTTP base URL), `webSocketDebuggerUrl`, `name`, `version?`, `product?` and `userAgent?` (from `/json/version`), `source` (`devtools-active-port`, `flag`, `process` or `probe`), `browser?` (the installed id whose user-data dir held the file), `userDataDir?` (the dir that held the file, or a process's `--user-data-dir`), `profile?` (the SLICC profile name), `wsOnly?`, `six?` (`true` for SLICC six's Chrome), `sevenOpen`, `sevenTabs` (always a list; each tab's `url` and `title` are its origin, as the CDP relay shows them).
|
|
492
492
|
- `installed`: `id`, `name`, `engine` (`chromium` or `electron`), `channel?`, `version?`, `path` (the `.app`, executable or flatpak dir), `executable` (for a flatpak, the `flatpak` binary), `bundleId?`, `via?` (`snap` or `flatpak`), `package?` (the snap or flatpak id), `userDataDir?` (the browser's default), `debugSupport` (`supported`, `disabled` or `unknown`), `debugBuild?`.
|
|
493
493
|
|
|
494
494
|
Without `--json`, the same list is a table: id, name, version, state and where. The state of six's Chrome ends with `SLICC six's profile`.
|
|
@@ -816,7 +816,7 @@ Only browsers the user named are listed: the one seven runs in, `--cdp` and `--c
|
|
|
816
816
|
- Seven's own tab and its vault frame are never touched, because attaching to them is refused.
|
|
817
817
|
- Page commands on a touched target's session wait, in order, until the node's own session there is ready; commands on other sessions of the stream don't wait. No page command on that session reaches the browser before the node's session is ready. The node's `Network.enable` and `Network.setBypassServiceWorker` answer only once the target's renderer does, which a loaded host can take a minute or more to start, so the wait has no fixed length. It fails closed on no progress, or at an outer bound:
|
|
818
818
|
- **Progress** for a target whose setup is under way is the answer to the node's attach to it, or any answer or event on the node's own guard session for that target. Answers and events on the page's sessions, and on other targets, don't count, so a guard that stays silent fails at the 30 s bound even while the browser and the page stay busy. The node checks the bounds every quarter of the shorter one (7.5 s by default).
|
|
819
|
-
- **Idle bound:** a setup with no progress for 30 s fails, within one check of it (37.5 s).
|
|
819
|
+
- **Idle bound:** a setup with no progress for 30 s fails, within one check of it (37.5 s). Only time the node spends waiting on the browser's socket counts toward the 30 s. The node reads the browser's messages one at a time and passes each on before it reads the next, so a page that is slow to credit its window stops the reads, and the guard's answers wait unread behind the page's messages. That time doesn't count, for setups and unknown sessions alike, and a stop over 2 s is logged under `SLICC_DEBUG`. The outer bound still counts it.
|
|
820
820
|
- **Outer bound:** a setup still under way 5 min after it started fails, whatever its progress.
|
|
821
821
|
- **Refusals:** when a setup call fails, the node's session is lost or the target closes, the waiting commands, and any after them, are refused at once with `slicc: refused: slicc can't keep seven's origin out of this target`. When a bound fires, the message names it: `…: its guard made no progress in 30s` or `…: its guard wasn't ready in 5m0s`.
|
|
822
822
|
- **Caps:** more than 4096 waiting commands, or 64 MiB of them, on one stream reset it with `ENOBUFS`.
|
|
@@ -827,7 +827,16 @@ Only browsers the user named are listed: the one seven runs in, `--cdp` and `--c
|
|
|
827
827
|
- In touched targets, service workers are bypassed for every request, not only for protected ones.
|
|
828
828
|
- The guard covers every frame that shares the touched target's process. A cross-site iframe's navigation pauses in its parent's target, before the iframe becomes a target of its own, with the frame's id as `frameId` (the id the iframe target gets later). A popup's request pauses in the popup's target, with its `targetId` as `frameId`. A redirect into a protected origin pauses again at the request stage, with `redirectedRequestId`, even when the first URL didn't match.
|
|
829
829
|
- The page's own `Fetch.enable` on a page session still works. Chrome chains the interceptors of a target's sessions, the most recently enabled first, so the page's interceptor could see a protected document's request before the node's does, or after the node failed it, at the response stage. The node fails such a request itself, and the page never sees it (see *Paused requests to seven* above).
|
|
830
|
-
- When a target commits a protected origin all the same (see the limits below), the node sees it arrive (`Target.targetInfoChanged`) only after the browser committed it.
|
|
830
|
+
- When a target commits a protected origin all the same (see the limits below), the node sees it arrive (`Target.targetInfoChanged`) only after the browser committed it. The node then detaches every page session on the target, drops their events and results, and refuses further commands on them; the page gets `Target.detachedFromTarget`.
|
|
831
|
+
- **Error pages.** A request the node failed (or any failed load) leaves the target on Chrome's error page, which the browser still reports under the protected URL it failed to load. The error page holds no content from that URL, so it doesn't lock the target. But it does name the URL (its reload button and `loadTimeData` carry the full failed URL, which after a server redirect can hold a secret the page never saw). So from the commit (`Page.frameNavigated` with a protected `unreachableUrl`) until the next commit, a page session on the target may only:
|
|
832
|
+
- navigate (not to a `javascript:` URL, which `Page.navigate` refuses everywhere with `slicc: refused: Page.navigate to a javascript: URL runs script in the page; use Runtime.evaluate`), reload (but not with a `scriptToEvaluateOnLoad`, which would run in the reloaded error page), stop, close and bring it to front (`Page.navigate`, `reload`, `stopLoading`, `close`, `bringToFront`, `navigateToHistoryEntry`);
|
|
833
|
+
- read and reset its history and frame tree (`Page.getNavigationHistory`, `resetNavigationHistory`, `getFrameTree`) and set lifecycle events;
|
|
834
|
+
- remove a script for new documents (`Page.removeScriptToEvaluateOnNewDocument`; adding one is refused, since it would run in the error page a reload commits again);
|
|
835
|
+
- release it from the debugger (`Runtime.runIfWaitingForDebugger`);
|
|
836
|
+
- enable or disable the `Page`, `Runtime`, `Target`, `Inspector`, `Network`, `Log` and `Fetch` domains, and settle its own interceptions (`Fetch.continueRequest`, `continueResponse`, `failRequest`, `fulfillRequest`, `continueWithAuth`, `Network.continueInterceptedRequest`), so a navigation away that the page intercepts never hangs;
|
|
837
|
+
- and use `Target.setAutoAttach`, `detachFromTarget`, `closeTarget`, `getTargetInfo` and `activateTarget`.
|
|
838
|
+
|
|
839
|
+
Anything else (`Runtime.evaluate`, `DOM.*`, snapshots, screenshots and so on) is refused with `slicc: refused: the target shows Chrome's error page for a protected URL, which names it; slicc only lets a page navigate, reload or close it`. Events on its sessions are filtered too: only `Target.*`, `Inspector.*`, `Network.*`, `Fetch.*`, the `Runtime` execution-context events and the `Page` navigation, loading, frame, lifecycle, window, download and interstitial events reach the page. So console messages, exceptions, `Log` entries, `DOM`, `CSS`, `Overlay` and `Debugger` events, and `Page.screencastFrame` (a screencast the page started before the tab failed would show the error page) are dropped. The node also remembers the last 16 protected URLs a target's error pages failed to load, and replaces each of them, as is and in its percent-encoded and decoded forms, with its origin in every string of every message on that target's sessions, opaque values (`value`, `preview`, `arguments`, `returnValue`) included. A command the page sent on the target's sessions before such a commit, other than the allowed ones above, can't answer from the error page either: if its answer arrives after the commit, the page gets `slicc: refused: the target committed Chrome's error page for a protected URL while this command ran, so slicc dropped its answer` instead (a screenshot, PDF or evaluation in flight would otherwise show the error page). Its URL and title are still redacted to the origin in listings and target events. Chrome's error pages for other URLs stay fully readable. The node tracks each touched target's main frame on its guard session (`Page.enable`): the last different-document commit (`Page.frameNavigated`) was an error page when its document is `chrome-error://chromewebdata/` (slicc-browsers' `errorPage.url`, whose `target` is `previous`) and it has an `unreachableUrl`, and that holds only while the target reports exactly that URL and no navigation is under way (`Page.frameStartedNavigating`, other than same-document, until its `Page.frameNavigated`, its document request's `Network.loadingFailed`, or the frame's `Page.frameStoppedLoading`, which also ends any doubt from an event the node couldn't read or from more than 64 navigations in flight, since nothing is in flight once the frame stops loading). Otherwise, or before the guard is ready, a protected URL locks the target as above. An error page neither locks nor unlocks: a target that was already protected stays so. An error page for a URL slicc can't parse is never exempt: it locks, as the unparseable rule says. That's stricter than slicc-browsers' `errorPage` rule, which exempts any URL's error page (nothing loaded there, so the unparseable case opens no hole the parseable one doesn't). slicc-browsers accepts it as over-protection, and no shared vector forces either answer.
|
|
831
840
|
- **Auto-attach of targets without a URL.** A cross-site iframe can attach before its URL is known (`url: ""`, which stays empty while it waits for the debugger), and so can a `window.open` popup. So when an auto-attached session (one that doesn't answer the page's own `Target.attachToTarget`) is to a page or iframe target with an empty URL, the node holds it:
|
|
832
841
|
- The page doesn't get its `attachedToTarget` yet, its events are dropped, and page commands on it are refused.
|
|
833
842
|
- If the page asked for `waitForDebuggerOnStart`, the node runs `Runtime.runIfWaitingForDebugger` on it itself.
|
|
@@ -1685,7 +1694,7 @@ On a [§1.3](#13-local-setup-without-cdp-loopback-signalling) loopback link, `un
|
|
|
1685
1694
|
- **`follow`:** only the browsers named with `--cdp <url>`. Without one, `follow` doesn't advertise `cdp`, because a remote seven gets full control of every browser listed. `follow` never marks a browser `seven: true`.
|
|
1686
1695
|
- **Protected ports:** every listed browser's debugging port is protected in the policy on both commands, so a `tcp` stream can't reach the raw port even under `--allow` or `--expose-debug-port` ([§6.5](#65-debugging-ports-every-mode)).
|
|
1687
1696
|
|
|
1688
|
-
- **Protected origins (PRE-1):** the node filters every `cdp` stream against `protectedOrigins` from slicc-browsers (≥ 1.4.0: `*.sliccy.ai` at any depth, any port, http and https; `vault.sliccy.ai` by name; plus the setup's extra origins). It refuses navigating to, attaching to, or driving targets on those origins, and storage, cookie and permission access for them, as **CDP errors** `{"error":{"code":-32000,"message":"slicc: refused: …"}}`, not RESETs. It detaches sessions that land on them and redacts their `url`/`title` in listings to the origin.
|
|
1697
|
+
- **Protected origins (PRE-1):** the node filters every `cdp` stream against `protectedOrigins` from slicc-browsers (≥ 1.4.0: `*.sliccy.ai` at any depth, any port, http and https; `vault.sliccy.ai` by name; plus the setup's extra origins). It refuses navigating to, attaching to, or driving targets on those origins, and storage, cookie and permission access for them, as **CDP errors** `{"error":{"code":-32000,"message":"slicc: refused: …"}}`, not RESETs. It detaches sessions that land on them and redacts their `url`/`title` in listings to the origin. A target on Chrome's error page for a protected URL isn't locked (it holds no content from that URL), but its `url`/`title` are still redacted, and since the error page names the URL, page commands on it are limited to navigating, reloading, closing and enabling domains (others are refused, see [`cdp`](#cdp-browser-control)).
|
|
1689
1698
|
- **Privileged browser pages** (≥ 1.8.0) count as protected origins: every URL in `protectedSchemes` (`chrome:`, `chrome-untrusted:`, `chrome-extension:`, `devtools:`, `file:`, from 1.8.5 `chrome-search:`, `chrome-native:`, `chrome-distiller:`, `isolated-app:`, `chrome-experimental-site-token-provider:`, `externalfile:` and `content:`, `edge:`, `brave:`, `opera:`, `vivaldi:`, `arc:`) except the new tab pages in `schemeExceptions`, and never `chrome-error:`; `view-source:`, `blob:` and `filesystem:` by what they wrap; `about:` aliases as the `chrome://` URL they become (`aboutScheme`). Targets of a `targetTypes` type (`browser_ui`) are protected whatever their URL, and never listed or announced to the page. The refusal text is the same.
|
|
1690
1699
|
- **URLs that don't parse** (WHATWG) count as protected wherever the node judges a URL the browser will load or has loaded: a command's destination (`Target.createTarget`, `Page.navigate`, `Fetch.continueRequest`, `Network.continueInterceptedRequest`, `Network.loadNetworkResource`, `PWA.launch`, `PWA.install`, cookie commands' `url` or `urls`, history entries) is refused with `slicc: refused: slicc can't parse this URL, so it could be a protected page`, and a target, main frame, execution context, request, WebSocket or service worker the browser reports on such a URL is redacted, refused, detached or hidden like seven's. An empty URL and the opaque origins `null` and `://` are not affected (a `blob:null/…` URL is: its inner `null/…` doesn't parse), and a target on such a URL isn't listed at all, and URLs the node only reads (storage keys, script URLs) keep "unparseable isn't protected", and in what the page gets such a URL is cut whole. Chrome canonicalises some URLs WHATWG rejects (`http://exa mple.sliccy.ai/` → `http://exa%20mple.sliccy.ai/`, U+200D → `xn--1ug`, invalid `xn--` labels), so this is what keeps those `sliccy.ai` hosts protected. The cost: pages on such exotic hosts, and Chrome's error pages for them, are cut even when they aren't protected. The rule and its refusal come from slicc-browsers' catalog (`protectedOrigins.unparseable` and `unparseableRefusal`, ≥ 1.10.0). [`cdp` (browser control)](#cdp-browser-control) has the details.
|
|
1691
1700
|
- **In targets the stream touched** (attached to or created): the node fails every protected document load with `net::ERR_BLOCKED_BY_CLIENT`, so instrumentation installed before a navigation can never run in a protected document. That covers redirects, service-worker-served navigations and the page's own Fetch interception.
|
|
@@ -2101,7 +2110,7 @@ CI installs a pinned release: `go install github.com/ai-ecoverse/slicc-cli/cmd/s
|
|
|
2101
2110
|
|
|
2102
2111
|
Go 1.26 and Node ≥ 24 (for the lint tools). `npm run build` writes `bin/slicc`. `npm run lint` runs the slicc lint tools, `gofmt`, `go mod tidy -diff`, `go vet` and golangci-lint. `npm test` runs the integration tests in `test/integration/`, which build the binary and drive it; run `npm ci` first, since the [Inside seven](#inside-seven) tests need the pinned `@ai-ecoverse/slicc-kernel`. Unit tests stay next to the code and out of git (`npm run test:unit`). `go build` and `npm run build` link no version, so these binaries report `dev`. `npm run dist` cross-builds all six targets into `artifacts/release/` with `SHA256SUMS`, unsigned. `npm run npm:stage` then stages the npm packages into `dist/npm/`, and `npm run npm:check` packs them with `npm publish --dry-run`.
|
|
2103
2112
|
|
|
2104
|
-
**Test shards.** CI splits the integration tests into shards with `scripts/test-shard.mjs <index>/<count> <go test args>`. The split is greedy by measured time: `test/integration/shard-times.json` holds each top-level test's seconds per platform (`darwin`, `linux`, `win32`), each test goes to the shard with the least time so far, and a test without a time counts as the platform's median. The last shard runs everything the others don't, so a test that isn't in any list yet still runs. CI has two matrices. **The light matrix** runs on
|
|
2113
|
+
**Test shards.** CI splits the integration tests into shards with `scripts/test-shard.mjs <index>/<count> <go test args>`. The split is greedy by measured time: `test/integration/shard-times.json` holds each top-level test's seconds per platform (`darwin`, `linux`, `win32`), each test goes to the shard with the least time so far, and a test without a time counts as the platform's median. The last shard runs everything the others don't, so a test that isn't in any list yet still runs. CI has two matrices. **The light matrix** runs on the merge queue (`merge_group`) and every push to `main`, which is the run the release waits for: the three Linux shards with `-race`, and two shards each on macOS and Windows (`1/2` and `2/2`, each with a 20-minute `-timeout`) without `-race`, so a queue group or a push needs two macOS and two Windows test runners. **A pull request** runs only the light matrix's Linux shards, beside `lint`, `installer-assets` and the installer checks: hosted macOS runners are the scarce ones, and the pull request's own merge group runs every OS before anything lands on `main`. The `all-os` label gives a pull request the whole light matrix, for changes to platform code: the `runner` job reads the pull request's labels when it runs (its `os` output, `linux` or `all`), so after adding the label, push or re-run all of the CI run's jobs. The aggregate `ci` prints which matrix ran (`test matrix: Linux only …` or `every OS`). With one leg each, both ran 19 to 23 of their 25 minutes, and a macOS leg timed out in a pull request. **The full matrix** runs in every release from `main`, on the commit it releases, beside the release build: `release.yml`'s `full` job calls `ci.yml` (`workflow_call` with `full: true`), which then runs three shards on Linux, three on Windows and four on macOS, whose runners vary the most (the same shard took from 400 s to 570 s) and run the guard vectors slowest, so each stays well inside its 15 minutes, every leg with `-race`, and the installer's macOS curl check too. On the org's hosted macOS pool the full matrix takes an hour or more, longer than merges often arrive: when `main` moves on meanwhile, that run's semantic-release skips as behind, and the newer commit's run releases (see [Releases](#releases)). Only one push run on `main` runs at a time, and only the newest push waits: a newer push replaces a pending one, never the one running, so a steady stream of merges queues at most two light matrices. **Node:** the `test` job runs on Node 26, in both matrices. On Node 24.21.0, V8 crashed the WASI kernel harness (`run.mjs`, the `TestWasi*` tests) about once in a hundred runs on Windows (`exit status 0xc0000005`, 15 crashes in 1600 runs against none in 1600 on Node 26), and occasionally on Linux and macOS (`Check failed: jit_page…`). Node 24, which npm users still run, stays covered by `installer-assets`: it stages and dry-runs the npm packages on Node 24, and runs the npm launcher tests (`TestNPM*` and `TestSliccy*`, `npx sliccy@next` among them) on it. The [guard vectors](https://github.com/ai-ecoverse/slicc-browsers#guard-vectors) (`TestCDPProtectVectorsPrompt` and `TestCDPProtectVectorsLagging`, one per detach variant) run on Linux in the light matrix, and on every OS in the full matrix: the light matrix's macOS and Windows legs skip them with `SLICC_GUARD_VECTORS=0`. On macOS both leave out the C9 vectors (extension worlds; the `C9.` prefix that `guardSkippedOn` in `guardrunner_test.go` returns for `darwin`, and the run logs why): there their unguarded control hung in Chrome itself (`Runtime.getProperties` for minutes, [#344](https://github.com/ai-ecoverse/slicc-cli/issues/344)), so no row passed and the full matrix went red on a guard that held. On Linux and Windows the C9 vectors run like the rest, and `TestCDPGuardVectorsSkipC9OnlyOnMacOS` keeps the skip to macOS. `TestCDPHidesExtensionWorlds` (`protectworld_test.go`) covers the extension-world guard on every OS. CI runs them with `-v`, so `node scripts/shard-times.mjs --run <CI run id>` refreshes the file from a finished `main` run's logs (`<platform>=<log file>` reads local `go test -v` output instead); a test the logs only show as skipped (the guard vectors on macOS and Windows, in a `main` run) keeps the time it had. Commit the result when tests get much slower or faster. `TestEachCIShardFitsItsTimeout` fails when a shard of either matrix adds up to more than three quarters of its `-timeout` by those times (without the guard vectors where it skips them), or when its job's `timeout-minutes` leaves less than 5 minutes past its `-timeout`: then add a shard. The `/3` and `/4` shards have 15 minutes: refreshed in October 2026, the times put each at 540 to 610 s, past three quarters of 12. Linux has three shards for that reason: with two, a shard ran 719 s of its 12 minutes, and the next run hit the timeout. **Retries.** In the release's full matrix only, each leg runs `test-shard.mjs --retry 1`: when `go test` fails, it runs the failed top-level tests once more (`-run` with their names, the other flags unchanged), and the leg passes when they all pass then. A test that passed on its retry is named in the PASS line (`…; TestX passed on retry`) and as a `flaky tests` warning on the run. A shard that hit its `-timeout`, or failed without naming a failed test (a build failure), isn't retried, and pull requests, the merge queue and pushes never retry, so a flaky test still shows there. The full matrix's jobs get 45 minutes, room for a shard and its retry. When a shard does hit its `-timeout`, `go test` panics naming whichever test was running then, so `test-shard.mjs` adds a line with how long that test had run, what the finished tests took against the times' prediction, and the slowest of them. **Runners.** CI's first job, `runner`, picks where the Linux jobs run with `.github/runner.mjs`: the pool named by `vars.CERT_RUNNER` (now `cloud-run-job`, one Cloud Run task per job; unset, `ubuntu-latest`) for pushes, the release's full build (`workflow_run` and `workflow_dispatch`), same-repo pull requests and merge groups whose entries are all same-repo, and GitHub's hosted `ubuntu-latest` for fork pull requests, merge groups with a fork entry, and when the decider fails. It gives two labels through the same rule: `runner` for the heavy jobs (the Linux test shards and `installer-assets`) and `light` (`vars.CERT_LIGHT_RUNNER`, unset `ubuntu-latest`) for `lint`, `installer (ubuntu-curl)` and the aggregate `ci`, so where a fork gets `ubuntu-latest` it gets it for both. `vars.CI_RUNNER` forces one runner, for both labels, for every event, fork pull requests and merge groups included, so it is never a rollback; `vars.CERT_RUNNER` is the one pool variable, and changing it is the rollback, with every rule here still applied. The `runner` job itself runs hosted for fork pull requests, otherwise on `vars.CERT_LIGHT_RUNNER` (or `vars.CERT_RUNNER`); it loads `runner.mjs` from `main`, never from the code under test, which may be a fork's: a pull request's base commit, and for a merge group the head of `main` (`merge_group.base_ref`), not the group's parent commit (`base_sha`), which can be the speculative commit of the group ahead of it in the queue, with that group's pull requests in it. That keeps the decider's own answer trusted; a fork pull request that edits `ci.yml` itself is stopped only by the repository's approval rule for outside contributors' workflows and the pool's runner-group access. The Alpine installer check stays hosted (it needs Docker), and macOS and Windows always run hosted. In `release.yml`, the dispatch-only `ci` wait, the `fresh` check and the `report` job run on `vars.CERT_LIGHT_RUNNER`, as do the Linux legs of `smoke` (hosted for fork pull requests) and `install-smoke` on `vars.CERT_RUNNER`, each falling back to `ubuntu-latest`, and every job with `id-token: write` (`release`, `sliccy-next`) on a GitHub-hosted runner. No workflow names a pool literally.
|
|
2105
2114
|
|
|
2106
2115
|
**Test names: `--hosts <file>`** (test-only, left out of `--help`). `slicc attach`, `slicc open`, `slicc pair` and `slicc <join-url> follow` take a hosts file, so tests get deterministic names without public DNS. Each line is `<ip> <name> [<name>…]`, and `#` starts a comment. Names match case-insensitively, with or without a trailing dot, and a name on several lines gets every address, in file order. Wherever the node resolves a name (`resolve`, `tcp` by name, `http`, and the policy's [browser endpoints](#network-policy)), a name in the file gets the file's addresses of the requested family, possibly none, and never the system resolver's. Other names go to the system resolver. The policy applies afterwards as usual: `resolve` drops refused addresses, and a dial to a refused address is `EACCES`. `tcp` and `http` try the addresses in file order. A file that can't be read or parsed exits 2. A name mapped to a loopback address only helps the node's own dials, `http` and `tcp` by name: a seven kernel that gets a loopback address from `resolve` dials its own loopback, because loopback never goes out through an exit. For end-to-end exit tests, map test names to a non-loopback address of the machine.
|
|
2107
2116
|
|
|
@@ -2147,7 +2156,7 @@ semantic-release cuts releases from `main` in `.github/workflows/release.yml`. T
|
|
|
2147
2156
|
2. `scripts/package.sh <version>` builds `darwin`, `linux` and `windows` × `amd64`, `arm64` with `CGO_ENABLED=0`, `-trimpath`, `-buildvcs=false` and `-X main.version=<version>`, and `slicc-wasip1-wasm.wasm` (`GOOS=wasip1 GOARCH=wasm`) the same way, with the Go toolchain `go.mod` names (see [Reproducing a release](#reproducing-a-release)). It signs and notarizes the darwin binaries and writes `SHA256SUMS`. The windows and linux binaries are not signed. Without the Apple signing secrets (forks, pull requests) it warns and leaves the darwin binaries unsigned.
|
|
2148
2157
|
3. (still in `build`) `scripts/npm-stage.mjs` stages `@ai-ecoverse/slicc` and the six platform packages into `dist/npm/`. It also stages the same launcher as `sliccy` (with two bins, `sliccy` and `slicc`, and a short preview README) into `dist/npm-next/`, as version `7.0.0-next.<version>`, with exact `optionalDependencies` on this release's platform packages. `npx sliccy@next` runs the bin named after the package, `sliccy`, and both bins run the same launcher. `--bin <name>` (repeatable) overrides the bins of any staged launcher. `--wasi` also stages `@ai-ecoverse/wasi-slicc` into `dist/npm/wasi-slicc/` from `slicc-wasip1-wasm.wasm` and `npm/wasi-slicc/host/slicc-host.mjs`, with README.md's [Inside seven](#inside-seven) section as its README; `--wasi-only` stages only that package.
|
|
2149
2158
|
4. The `release` job unpacks the build, checking its `dist/VERSION` against the planned version, and `actions/attest-build-provenance` attests every binary, the `.wasm` included, through `SHA256SUMS`.
|
|
2150
|
-
5. semantic-release checks the version again (`dist/VERSION`, and `scripts/go-major.mjs`, see below), tags, creates the GitHub release with every binary and `SHA256SUMS`, then `scripts/npm-publish.mjs` publishes the platform packages and the launcher through npm trusted publishing (OIDC, with provenance), and then `sliccy` with `--tag next`. Versions already on npm are skipped. Before publishing `sliccy`, the script checks that every exact-pinned `optionalDependencies` version is on the registry, waits up to `SLICC_REGISTRY_WAIT_SECONDS` (default 900) for freshly published ones to appear, and fails otherwise (exit code 3), so a `sliccy` version never points at missing platform packages.
|
|
2159
|
+
5. semantic-release checks the version again (`dist/VERSION`, and `scripts/go-major.mjs`, see below), tags, creates the GitHub release with every binary and `SHA256SUMS`, then `scripts/npm-publish.mjs` publishes the platform packages and the launcher through npm trusted publishing (OIDC, with provenance), and then `sliccy` with `--tag next`. Versions already on npm are skipped. Before publishing `sliccy`, the script checks that every exact-pinned `optionalDependencies` version is on the registry, waits up to `SLICC_REGISTRY_WAIT_SECONDS` (default 900) for freshly published ones to appear, and fails otherwise (exit code 3), so a `sliccy` version never points at missing platform packages. Then the `release` job asks `git ls-remote` whether `v<version>` is on `origin` at the commit it built, and only then outputs the version. When semantic-release published nothing (for example because `main` moved on during the full matrix, so the checkout is behind), there is no output: `install-smoke` and `sliccy-next` skip, and the run stays green with no `release-red` issue. An `origin` it can't read fails the job.
|
|
2151
2160
|
6. `scripts/go-warm.sh <version>`, once the tag is on `origin`, asks `proxy.golang.org` for the module at `v<version>` (`go list -m` with a scratch module cache) and asks `pkg.go.dev` to fetch it. The proxy fetch is retried briefly; the `pkg.go.dev` fetch is one attempt of at most 10 s, since the proxy fetch already gets the version indexed. Both only warn, and the step can't fail the release.
|
|
2152
2161
|
|
|
2153
2162
|
**Certification in the pull request** (`.github/workflows/cert-review-pr.yml`, `tools/cert-review/`). Every same-repo pull request gets the commit status `cert-review` on its head, which the merge queue requires beside `ci`. Fork pull requests get none: only Lars merges one. Every tool runs from the pull request's base commit, main's copy, never from the code under test, which is only built and tested; the review uses `refs/pull/N/merge` and records its first parent and the head.
|
|
@@ -2159,7 +2168,7 @@ semantic-release cuts releases from `main` in `.github/workflows/release.yml`. T
|
|
|
2159
2168
|
- **suite** (heavy runner): the candidate leg runs the whole integration suite on the merge commit on Linux (`go test -json`); the base leg is the NEGATIVE: main's tree with the pull request's whole `test/` diff applied, running only its tests, against main's own binary. A fix whose test fails there and passes on the candidate is `negative`; passing on both is `no-negative`; not compiling or skipping on main is `prev-not-run`. Gaps are known issues, never a FAIL by themselves.
|
|
2160
2169
|
- **bios** runs seven's own canary on the candidate wasm when classify sees `slicc-wasip1-wasm.wasm` or the `@ai-ecoverse/wasi-slicc` tarball differ from main's build: it calls slicc-bios's `canary.yml` as a reusable workflow, pinned to the commit in `tools/cert-review/bios.json`, with build's `cert-build-wasi-slicc-<v>` artifact as the candidate (strict binding: its run, artifact id, artifact digest and tarball sha256, never its name alone) and the shards that install the in-kernel slicc (`follow-chat`, whose `follow-slicc.test.mjs` follows another seven). It passes no secret. The canary's shards run on hosted runners. It runs only while the repository variable `CERT_BIOS_CANARY` is `on`, and that variable stays unset until [slicc-bios#599](https://github.com/ai-ecoverse/slicc-bios/issues/599) is fixed: the canary binds an artifact candidate's tarball, but the in-kernel pnpm still resolves its version on the npm registry, so every new wasm would read as a regression. While it's off, record gets `--bios-off ai-ecoverse/slicc-bios#599`, and the line says `bios: off (ai-ecoverse/slicc-bios#599), wasm changed` (an unchanged wasm still says `bios: not needed, wasm unchanged`).
|
|
2161
2170
|
- **review** (light runner) runs `claude-code-action/base-action` on that evidence with `AWS_BEARER_TOKEN_BEDROCK`, the workflow's only secret, in that step only; without the key the step skips and the line says `INCOMPLETE: no reviewer key`. Its read-only `gh` calls use the runner's own `gh`; nothing downloads one, and a runner without it makes the review INCOMPLETE. The reviewer writes only `verdict.json` and `comment.md`, in a folder of its own: a `fail` can add a defect, but nothing it writes can clear one decided in code.
|
|
2162
|
-
- **record** (code only) recomputes the findings from the code-made evidence (delta, suite and rebuild artifacts), re-hashes the build artifact against build's `SHA256SUMS` hash, checks the rebuild, reads CI's results on the head (the macOS, Windows and Linux test legs and `ci`, waiting up to an hour), bios's canary report (`bios-canary`, by the id and digest the call returned, its pin, this run, this build's tarball and every pinned shard) and the verdict. A byte or reproducibility mismatch, a failing canary test, or the reviewer's fail, is `cert-ci: FAIL` (failure); missing evidence (a known issue that can't be read or doesn't exist included, and a canary that left no result, missed a shard, or was flaky) is `cert-ci: INCOMPLETE` (error: re-run the failed jobs); otherwise `certified ai-ecoverse/slicc-cli PR #N at <head>, build <v> SHA256SUMS sha256=<hex> (wasm sha256=<hex>; bios: follow-chat pass at slicc-bios@<sha>, bios: not needed, wasm unchanged, or bios: off (<issue>), wasm changed; reproducible: …; ci: …; known: …; test gaps: …)`. **report** posts it as the status and a sticky comment.
|
|
2171
|
+
- **record** (code only) recomputes the findings from the code-made evidence (delta, suite and rebuild artifacts), re-hashes the build artifact against build's `SHA256SUMS` hash, checks the rebuild, reads CI's results on the head (the macOS, Windows and Linux test legs and `ci`, waiting up to an hour; a pull request's CI run whose `runner` decided Linux only, read from its `test matrix` annotation `os=linux` in the same check suite as a green `ci`, and whose workflow run is a `pull_request` one, needs no macOS or Windows leg, and the comment says `not run on this PR (Linux-only; the merge queue runs every OS)`; on any other run every OS is still required, and a leg that ran must pass), bios's canary report (`bios-canary`, by the id and digest the call returned, its pin, this run, this build's tarball and every pinned shard) and the verdict. A byte or reproducibility mismatch, a failing canary test, or the reviewer's fail, is `cert-ci: FAIL` (failure); missing evidence (a known issue that can't be read or doesn't exist included, and a canary that left no result, missed a shard, or was flaky) is `cert-ci: INCOMPLETE` (error: re-run the failed jobs); otherwise `certified ai-ecoverse/slicc-cli PR #N at <head>, build <v> SHA256SUMS sha256=<hex> (wasm sha256=<hex>; bios: follow-chat pass at slicc-bios@<sha>, bios: not needed, wasm unchanged, or bios: off (<issue>), wasm changed; reproducible: …; ci: …; known: …; test gaps: …)`. **report** posts it as the status and a sticky comment.
|
|
2163
2172
|
- **No silent pass.** Every step that runs a cert tool requires that tool's verdict: plan's `build=`, a posted status from classify and the lookup, a `certified …` line and a `success` record before report posts success, and in `cert-verify.yml` the reproduction's and the darwin check's verdict lines, verify's `certified slicc-cli@<version> binaries …` line and the notes job's `notes: …` line. A tool that exits 0 and prints nothing fails its step, and the status is `error`.
|
|
2164
2173
|
- **Evidence by artifact id and digest.** Every job that uploads evidence hands on the artifact's id and digest as job outputs, one pair per matrix side. Every consumer downloads by `artifact-ids` with `digest-mismatch: error`, never by name or pattern, and no upload overwrites another. A download that failed counts as no evidence. The review and record take from each producer's artifact only its own files (`gather.mjs`: the candidate suite gives `candidate.*`, main's gives `prev.*`), so one job can't plant another's evidence. classify, record and cert-verify's verify list the run's artifacts: an artifact under a declared id with another name or digest, or a `cert-*` artifact from this attempt that no producer declared, is `cert-ci: INCOMPLETE` (classify posts `error`). Artifacts left by an earlier attempt of the run are ignored.
|
|
2165
2174
|
- **merge group**: CI's deterministic suites, plus a code-only lookup that each pull request in the group has a green status on the head being merged; otherwise red, naming it. No build, review or model.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc",
|
|
3
|
-
"version": "1.47.
|
|
3
|
+
"version": "1.47.2",
|
|
4
4
|
"description": "SLICC's command line for seven: links a machine's network, compute and browsers to seven over WebRTC",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"node": ">=18"
|
|
19
19
|
},
|
|
20
20
|
"optionalDependencies": {
|
|
21
|
-
"@ai-ecoverse/slicc-darwin-arm64": "1.47.
|
|
22
|
-
"@ai-ecoverse/slicc-darwin-amd64": "1.47.
|
|
23
|
-
"@ai-ecoverse/slicc-linux-arm64": "1.47.
|
|
24
|
-
"@ai-ecoverse/slicc-linux-amd64": "1.47.
|
|
25
|
-
"@ai-ecoverse/slicc-windows-arm64": "1.47.
|
|
26
|
-
"@ai-ecoverse/slicc-windows-amd64": "1.47.
|
|
27
|
-
"@ai-ecoverse/slicc-jerk": "^1.1
|
|
21
|
+
"@ai-ecoverse/slicc-darwin-arm64": "1.47.2",
|
|
22
|
+
"@ai-ecoverse/slicc-darwin-amd64": "1.47.2",
|
|
23
|
+
"@ai-ecoverse/slicc-linux-arm64": "1.47.2",
|
|
24
|
+
"@ai-ecoverse/slicc-linux-amd64": "1.47.2",
|
|
25
|
+
"@ai-ecoverse/slicc-windows-arm64": "1.47.2",
|
|
26
|
+
"@ai-ecoverse/slicc-windows-amd64": "1.47.2",
|
|
27
|
+
"@ai-ecoverse/slicc-jerk": "^1.2.1"
|
|
28
28
|
}
|
|
29
29
|
}
|