@ai-ecoverse/slicc-cdp 1.27.8 → 1.29.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 +108 -2
- package/bin/curlwright.wasm +0 -0
- package/bin/playwright-cli.wasm +0 -0
- package/package.json +4 -4
- package/src/cli.js +10 -1
package/README.md
CHANGED
|
@@ -8,7 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
The binary is `crates/playwright-cli`. Host `open` launches a browser into `<config>/slicc/seven-profiles/<id>` when no debugger is already connected, and inside slicc it only opens a tab. It does not invent a debugger path.
|
|
10
10
|
|
|
11
|
-
Connect, in order: `--cdp`, else `SLICC_CDP_URL`, else a live `DevToolsActivePort` under `<config>/slicc/seven-profiles`, else a loopback endpoint this tool saved at `<config>/slicc/playwright-cli/sessions/<hash>.json`. A `.playwright-cli/session.json` in the working directory is ignored. In the kernel, the wasm builds keep it at `<state>/slicc/playwright-cli/sessions/<hash>.json`, where `<state>` is `$XDG_STATE_HOME`, else `$XDG_CONFIG_HOME`, else `$HOME/.config`, and the hash is of `$PWD`. When that is not writable, `playwright-cli` prints `playwright-cli: running without saved state (<reason>)` on stderr and the command still succeeds, except `route` and `unroute`, which fail because they only save state. A child of that directory is a profile only when its name is a browser id: it starts with a letter or digit, then letters, digits, `.`, `_`, or `-`, at most 64 characters, and it does not contain `..`. Dotfiles, including `.migrated-from-profiles`, are not profiles. `playwright-cli` does not migrate `slicc/profiles`. Host `list` GETs `/json/version` and `/json/list` on `127.0.0.1:9222-9229`, and host `open` GETs `/json/version` there when that port is absent or unreachable. `open` attaches to the first of those ports whose `/json/version` answers, with or without a seven tab, and an unreachable seven-profiles port falls through to that probe. A successful command writes the loopback endpoint it used, its provenance, and the ids of tabs it created. A saved endpoint is reused only when it is loopback. A probe-derived session is reused while that browser still answers `/json/version`. Every command shows and drives all of a browser's tabs, not only the ones this tool created, except tabs on protected origins, which stay refused. An explicit `--cdp` or `SLICC_CDP_URL` may name any host, and that URL is not saved unless it is loopback. Host `open` and `tab-new` treat an unreachable saved endpoint as absent, then probe and may launch. Other commands report that connection error. When nothing answers, launch passes `--remote-debugging-port` with the first free port from 9222 to 9229, or 0 when all are busy. `SLICC_CDP_PORTS=<from>-<to>` replaces 9222-9229 for the probes and the launch, and while it is set no command dials loopback 9222-9229. It is for tests. The wasm build still uses port 9222. A `ws://` URL is dialed as given. An `http://` URL is discovery. On the native build a `wss://` URL is dialed as given. The WASI build has no TLS, so `wss://` and `https://` fail there. `--runtime <name>` is appended to the query of the URL that is opened and is not interpreted.
|
|
11
|
+
Connect, in order: `--cdp`, else `SLICC_CDP_URL`, else a live `DevToolsActivePort` under `<config>/slicc/seven-profiles`, else a loopback endpoint this tool saved at `<config>/slicc/playwright-cli/sessions/<hash>.json`. A `.playwright-cli/session.json` in the working directory is ignored. In the kernel, the wasm builds keep it at `<state>/slicc/playwright-cli/sessions/<hash>.json`, where `<state>` is `$XDG_STATE_HOME`, else `$XDG_CONFIG_HOME`, else `$HOME/.config`, and the hash is of `$PWD`. When that is not writable, `playwright-cli` prints `playwright-cli: running without saved state (<reason>)` on stderr and the command still succeeds, except `route` and `unroute`, which fail because they only save state. A child of that directory is a profile only when its name is a browser id: it starts with a letter or digit, then letters, digits, `.`, `_`, or `-`, at most 64 characters, and it does not contain `..`. Dotfiles, including `.migrated-from-profiles`, are not profiles. `playwright-cli` does not migrate `slicc/profiles`. Host `list` GETs `/json/version` and `/json/list` on `127.0.0.1:9222-9229`, and host `open` GETs `/json/version` there when that port is absent or unreachable. `open` attaches to the first of those ports whose `/json/version` answers, with or without a seven tab, and an unreachable seven-profiles port falls through to that probe. A successful command writes the loopback endpoint it used, its provenance, and the ids of tabs it created. It also keeps each tab's console and request log until the tab closes., redacted as listed below. A saved endpoint is reused only when it is loopback. A probe-derived session is reused while that browser still answers `/json/version`. Every command shows and drives all of a browser's tabs, not only the ones this tool created, except tabs on protected origins, which stay refused. An explicit `--cdp` or `SLICC_CDP_URL` may name any host, and that URL is not saved unless it is loopback. Host `open` and `tab-new` treat an unreachable saved endpoint as absent, then probe and may launch. Other commands report that connection error. When nothing answers, launch passes `--remote-debugging-port` with the first free port from 9222 to 9229, or 0 when all are busy. `SLICC_CDP_PORTS=<from>-<to>` replaces 9222-9229 for the probes and the launch, and while it is set no command dials loopback 9222-9229. It is for tests. The wasm build still uses port 9222. A `ws://` URL is dialed as given. An `http://` URL is discovery. On the native build a `wss://` URL is dialed as given. The WASI build has no TLS, so `wss://` and `https://` fail there. `--runtime <name>` is appended to the query of the URL that is opened and is not interpreted.
|
|
12
|
+
|
|
13
|
+
Only the saved session file is redacted:
|
|
14
|
+
|
|
15
|
+
- **Headers:** the values of `Cookie`, `Set-Cookie`, `Authorization`, `Proxy-Authorization`, and any request or response header whose name contains `token`, `secret`, `key`, `auth`, `session`, `csrf` or `cookie`, become `[redacted]`.
|
|
16
|
+
- **URLs:** request URLs, URL-valued headers such as `Referer` and `Location`, and console source URLs lose their user info and fragment. Query values whose key contains `token`, `secret`, `key`, `auth`, `code`, `sig`, `session` or `password` become `[redacted]`.
|
|
17
|
+
- **Request bodies:** dropped.
|
|
18
|
+
- **Console entries:** dropped when the text holds a `Bearer` or `Basic` credential, a JWT, `cookie` with an `=`, or a pair such as `token=…` or `"password": "…"` whose value is at least 8 characters. Other entries are cut at 2048 bytes.
|
|
19
|
+
|
|
20
|
+
The output of the command that captured an entry still shows it. Response bodies, route headers and the saved endpoint are kept as they are.
|
|
12
21
|
|
|
13
22
|
One browser WebSocket. `Target.attachToTarget` uses `{targetId, flatten: true}`. Later page commands send that `sessionId` at the top level. There is no `/devtools/page/<id>` socket.
|
|
14
23
|
|
|
@@ -24,6 +33,17 @@ Event JSON (NDJSON, one object per line):
|
|
|
24
33
|
{"v":1,"standard":"ard","origin":"https://example.com","url":"https://example.com/.well-known/ard.json","via":"well-known","page":"https://example.com/","targetId":"...","status":"valid","summary":{...}}
|
|
25
34
|
```
|
|
26
35
|
|
|
36
|
+
Payments over HTTP 402: every response in a watched tab, subresources included, with status 402 is decoded as a payment challenge. The watcher never pays, retries, or sends `PAYMENT-SIGNATURE` or `Authorization: Payment`; it only reads the response the page already got. A protected origin's response is never read.
|
|
37
|
+
|
|
38
|
+
- **`x402`** ([x402](https://github.com/coinbase/x402/tree/main/specs)). V2 is read from the base64 JSON `PAYMENT-REQUIRED` header. V1 is read from the JSON body of a 402 with a JSON content type. The body is fetched once with `Network.getResponseBody` after it has loaded, up to 1 MiB. `summary` is `{status: 402, version, resource, offers: [{scheme, network, amount, asset, payTo, expires, maxTimeoutSeconds}]}`. `amount` is V2's `amount` or V1's `maxAmountRequired`, kept as the string the server sent.
|
|
39
|
+
- **`mpp`** ([Machine Payments Protocol](https://datatracker.ietf.org/doc/draft-httpauth-payment/)). It is read from each `WWW-Authenticate: Payment` challenge, whose `request` parameter is decoded as base64url JSON. `summary` is `{status: 402, resource, offers: [{method, intent, realm, amount, asset, expires}]}`, with `amount` and `asset` (the request's `currency`) as sent. One response can carry both standards.
|
|
40
|
+
- **Invalid challenges:** a challenge that doesn't decode is reported with `status: "invalid"` and a `reason`, and the watcher goes on. Its `summary` is only `{status: 402, challenge}`, the raw header capped at 1 KiB. Possible reasons:
|
|
41
|
+
- `PAYMENT-REQUIRED is not base64 JSON`;
|
|
42
|
+
- `request is not base64url JSON`;
|
|
43
|
+
- `no x402 payload`: a legacy `X-Payment` header, or a body without `x402Version`/`accepts`;
|
|
44
|
+
- `body unavailable`: the body was evicted or the load failed.
|
|
45
|
+
- **Limits:** events are deduplicated per origin, standard and resource, since each paid resource has its own price. A tab reports at most 50 events per payment standard, so a page that loops 402s can't flood the output. `--once` waits up to 2 s after the load event for the tab's requests to finish (and 402 bodies to be read), so the 402s of subresources are reported. A `--once` run can therefore take up to 2 s longer than the load.
|
|
46
|
+
|
|
27
47
|
Sinks:
|
|
28
48
|
|
|
29
49
|
- **stdout** (default): NDJSON. Pipe into `jq` or an agent reader.
|
|
@@ -32,6 +52,14 @@ Sinks:
|
|
|
32
52
|
|
|
33
53
|
Opt-out: `--off` exits immediately. A file at `<config>/slicc/discover.disabled` (the same user config dir as the saved session) disables the watcher; checked at start and on SIGHUP.
|
|
34
54
|
|
|
55
|
+
UCP ([Universal Commerce Protocol](https://ucp.dev/specification/overview/)) is probed by default: one same-origin `GET /.well-known/ucp` per origin, through the guard and capped like the other well-known probes. The listed endpoints are never called.
|
|
56
|
+
- **Validation:** the profile must have `ucp.version` (`YYYY-MM-DD`), `ucp.services` and `ucp.payment_handlers` (both required, empty allowed). Each service entry needs `version`, `spec`, a `transport` of `rest`, `mcp`, `a2a` or `embedded`, and an `endpoint` (`embedded` may give only a `schema`).
|
|
57
|
+
- **Summary:** `{version, services: {name: [{transport, endpoint}]}, capabilities: ["name@version"], paymentHandlers, hasKeys, ap2, mcp, a2a}`.
|
|
58
|
+
- `mcp` lists the MCP server candidates and `a2a` the agent-card URLs. Protected endpoints are left out.
|
|
59
|
+
- `hasKeys` only says whether `keys[]` is non-empty; no key material is reported.
|
|
60
|
+
- `ap2` is true when a capability or payment handler names the AP2 extension (a name segment starting with `ap2`, such as `dev.ucp.common.payment.ap2_mandate`). AP2 has no discovery of its own.
|
|
61
|
+
- **Versions:** a version other than 2026-01-23, 2026-04-08 or 2026-08-25 is still `valid`, with `summary.note: "unknown version"`.
|
|
62
|
+
|
|
35
63
|
Example `--exec` hook for Claude Code:
|
|
36
64
|
|
|
37
65
|
```sh
|
|
@@ -74,6 +102,8 @@ npx slicc-cdp install-browser --channel stable --with-deps
|
|
|
74
102
|
npx slicc-cdp find-browser
|
|
75
103
|
```
|
|
76
104
|
|
|
105
|
+
The bin runs through an npm bin link, a symlinked package dir, and `--preserve-symlinks-main`, because it compares the real paths of `process.argv[1]` and its own module. Node resolves a module's relative imports from the path it was loaded by, so `node --preserve-symlinks-main` on a symlink to `cli.js` alone cannot load `./browser.js`; link the package dir instead.
|
|
106
|
+
|
|
77
107
|
Trust: Chrome for Testing publishes no checksums or signatures for its zips. `installBrowser` downloads only over HTTPS, only from `googlechromelabs.github.io` (the version index) and `storage.googleapis.com` (the zips). Redirects are refused. The only checks are the byte count and the version, so you are trusting those Google hosts and TLS. Pin an exact version (`--version x.y.z.w`) in CI, so a run gets the build you tested.
|
|
78
108
|
|
|
79
109
|
## Kernel commands
|
|
@@ -84,6 +114,80 @@ Inside the kernel the browser socket is `SLICC_CDP_URL`: `ws://127.0.0.1:9222/de
|
|
|
84
114
|
|
|
85
115
|
Routes in the kernel use these CDP methods through the facade, always with a tab's `sessionId`: `Fetch.enable`, `Fetch.disable`, `Fetch.continueRequest`, `Fetch.fulfillRequest`, the `Fetch.requestPaused` event, and `Target.getTargetInfo`. The `slicc-cdp-client` API can also send `Fetch.failRequest`, `Fetch.getResponseBody` and `Fetch.continueResponse`; `playwright-cli` doesn't.
|
|
86
116
|
|
|
117
|
+
## Backend contract
|
|
118
|
+
|
|
119
|
+
This is what `playwright-cli`, `curlwright`, `slicc-cdp-client` and the JS `CDPClient` need from a CDP backend: Chrome, slicc-extension's `sliccExtension.cdp`, bios's link and guard, or slicc-node. `crates/cdp-client/src/contract.rs` holds the same lists. Its unit test scans the production code in `crates/*/src` and fails when a list misses a sessionless call, a handled browser-level event or a session domain, or names one the code no longer uses. It also fails when this section disagrees with the lists or with `shield.rs`, or when a cited function or const no longer holds what it is cited for.
|
|
120
|
+
|
|
121
|
+
One browser WebSocket carries everything. An `http` endpoint is read as `GET /json/version`, which must return `webSocketDebuggerUrl` (`crates/cdp-client/src/connect.rs` `websocket_url_from_version`). When nothing names an endpoint, the host probes the `probe_ports` of the slicc-browsers catalog, `127.0.0.1:9222-9229` (`crates/cdp-client/src/ports.rs` `catalog_from`). Requests are `{id, method, params}` with an optional top-level `sessionId`. Replies are `{id, result}` or `{id, error: {message}}`. The client reports an error as `<method>: <message>` (`crates/cdp-client/src/cdp.rs` `raw_call`). Events are `{method, params}`, with `sessionId` when they come from a session.
|
|
122
|
+
|
|
123
|
+
### Browser-level methods
|
|
124
|
+
|
|
125
|
+
These are sent with no `sessionId`.
|
|
126
|
+
|
|
127
|
+
- `Target.getTargets` with `{}`. Reads `targetId`, `type`, `url` and `title` from each of `targetInfos`. Only `type: "page"` is a tab. The client never lists a protected tab, and a backend may leave them out (`crates/playwright-cli/src/browser.rs` `list_pages`).
|
|
128
|
+
- `Target.getTargetInfo` with `{targetId}`. Reads `targetInfo.type`, `url`, `openerId`. An error for a `frameId` is fine (`crates/cdp-client/src/cdp.rs` `target_protected`).
|
|
129
|
+
- `Target.setDiscoverTargets` with `{discover: true}`, once per connection before the first guard attach (`crates/cdp-client/src/cdp.rs` `touch`). `discover` sends it with the same params (`crates/playwright-cli/src/agent_discover.rs` `run`).
|
|
130
|
+
- `Target.createTarget` with `{url: "about:blank", background}`. Must return `targetId`. Any other `url` is sent as `Page.navigate` on the guard session once the guard is up (`crates/cdp-client/src/cdp.rs` `create_target`).
|
|
131
|
+
- `Target.attachToTarget` with `{targetId, flatten: true}`. Must return `sessionId` (`crates/cdp-client/src/cdp.rs` `attach`).
|
|
132
|
+
- `Target.detachFromTarget` with `{sessionId}` (`crates/cdp-client/src/cdp.rs` `detach`).
|
|
133
|
+
- `Target.closeTarget` with `{targetId}` (`crates/playwright-cli/src/browser.rs` `close_target`).
|
|
134
|
+
- `Target.activateTarget` with `{targetId}`. `open` ignores an error, `tab-select` reports it (`crates/playwright-cli/src/browser.rs` `activate`).
|
|
135
|
+
- `Browser.getVersion` with `{}`. Optional, `webmcp-call` only. Reads `product` as `Chrome/NNN` or `HeadlessChrome/NNN` (`crates/playwright-cli/src/webmcp.rs` `chrome_major_version`).
|
|
136
|
+
- `Slicc.action` with `{phase, kind, ...}`. An optional notification for the slicc panel that is never awaited, so a backend may ignore it or answer with an error (`crates/playwright-cli/src/action.rs` `begin`).
|
|
137
|
+
|
|
138
|
+
The JS `CDPClient` sends only `Target.getTargets` (`src/page.js` `listTargets`) and `Target.attachToTarget` with `flatten: true` (`src/cdp-client.js` `attach`) without a session.
|
|
139
|
+
|
|
140
|
+
### Browser-level events
|
|
141
|
+
|
|
142
|
+
A backend may omit any of these.
|
|
143
|
+
|
|
144
|
+
- `Target.attachedToTarget` with `sessionId` and `targetInfo.targetId`. Registers the guard session if it comes before the attach reply (`crates/cdp-client/src/cdp.rs` `adopt_guard_attach`).
|
|
145
|
+
- `Target.targetCreated` with `targetInfo` (`crates/cdp-client/src/cdp.rs` `watch`).
|
|
146
|
+
- `Target.targetInfoChanged` with `targetInfo`. A protected `url` marks the tab protected (`crates/cdp-client/src/cdp.rs` `watch`).
|
|
147
|
+
- `Target.targetDestroyed` with `targetId` (`crates/cdp-client/src/cdp.rs` `watch`).
|
|
148
|
+
- `Target.detachedFromTarget` with `sessionId` (`crates/cdp-client/src/cdp.rs` `watch`).
|
|
149
|
+
|
|
150
|
+
### Guard
|
|
151
|
+
|
|
152
|
+
- Every attach uses `flatten: true`. A non-flat `Target.attachToTarget` or `Target.setAutoAttach` is refused before it is sent (`crates/cdp-client/src/cdp.rs` `admit`), and so is `autoAttach: true` (`crates/cdp-client/src/cdp.rs` `admit`).
|
|
153
|
+
- Before a tab is used, the client attaches a guard session of its own. It is registered from the `Target.attachToTarget` reply (`crates/cdp-client/src/cdp.rs` `touch`) or from the `Target.attachedToTarget` event (`crates/cdp-client/src/cdp.rs` `adopt_guard_attach`), whichever comes first.
|
|
154
|
+
- `Target.setDiscoverTargets`, the attach and the setup steps share one `GUARD_SETUP` budget of 30 s (`crates/cdp-client/src/cdp.rs` `GUARD_SETUP`).
|
|
155
|
+
- The guard's `Fetch.enable` is `{patterns: [{urlPattern: "*", resourceType: "Document", requestStage: "Request"}]}` and decides per paused request (`crates/cdp-client/src/cdp.rs` `touch`). A backend must accept it. A backend's shield may refuse any interception pattern that names a protected origin, and clients never send one: `route` checks each `pattern` and refuses such a route before `Fetch.enable` is sent (`crates/cdp-client/src/fetch.rs` `enable`). Sending one broke bios and the extension on 2026-10-17.
|
|
156
|
+
- Then `Network.enable` and `Network.setBypassServiceWorker` with `{bypass: true}`, which must succeed (`crates/cdp-client/src/cdp.rs` `touch`).
|
|
157
|
+
- `Page.enable` and `Runtime.enable` are optional. Each gets at most `OPTIONAL_STEP`, 10 s of what is left (`crates/cdp-client/src/cdp.rs` `OPTIONAL_STEP`). An error reply, `<method>: <message>`, is ignored (`crates/cdp-client/src/cdp.rs` `touch`). A timeout prints `slicc: guard: <method> timed out; continuing` (`crates/cdp-client/src/cdp.rs` `touch`).
|
|
158
|
+
- Any other failure detaches the guard and marks the tab unguarded, so every later command on it is refused (`abandon`, `crates/cdp-client/src/cdp.rs` `touch`).
|
|
159
|
+
|
|
160
|
+
### Refused before sending
|
|
161
|
+
|
|
162
|
+
The client refuses these before sending, so a backend needn't implement them (`crates/cdp-client/src/shield.rs` `browser_wide`).
|
|
163
|
+
|
|
164
|
+
- `Target.exposeDevToolsProtocol`.
|
|
165
|
+
- `Target.sendMessageToTarget`. Attach with `flatten: true` instead.
|
|
166
|
+
- `Target.attachToBrowserTarget`.
|
|
167
|
+
- `Tracing.start`.
|
|
168
|
+
- `Extensions.loadUnpacked`.
|
|
169
|
+
- `Network.clearBrowserCookies`.
|
|
170
|
+
- `Storage.clearCookies` unless its `browserContextId` came from this client's `Target.createBrowserContext`.
|
|
171
|
+
- `Browser.resetPermissions` on the same terms.
|
|
172
|
+
- `Browser.setPermission` with no `origin`, on the same terms.
|
|
173
|
+
- `Browser.grantPermissions` with no `origin`, on the same terms.
|
|
174
|
+
- `Network.setRequestInterception`.
|
|
175
|
+
- `Fetch.*` with no `sessionId`.
|
|
176
|
+
|
|
177
|
+
### Session-level domains
|
|
178
|
+
|
|
179
|
+
Everything else goes over a flat session, with a top-level `sessionId`.
|
|
180
|
+
|
|
181
|
+
- `Page`
|
|
182
|
+
- `Runtime`
|
|
183
|
+
- `DOM`
|
|
184
|
+
- `Input`
|
|
185
|
+
- `Network`
|
|
186
|
+
- `Fetch`
|
|
187
|
+
- `Accessibility`
|
|
188
|
+
|
|
189
|
+
`slicc-cdp-client` also lets a caller `IO.read` a stream that a session reply handed out (`crates/cdp-client/src/cdp.rs` `admit`).
|
|
190
|
+
|
|
87
191
|
## Package
|
|
88
192
|
|
|
89
193
|
Node ≥ 24. `npm run lint` runs `slicc-lint`. Releases use semantic-release on `main`. Git `package.json` stays `0.0.0`. The published version is the release tag.
|
|
@@ -143,6 +247,8 @@ curlwright --cdp http://127.0.0.1:9333 -I https://example.com/
|
|
|
143
247
|
|
|
144
248
|
A developer's own Chrome listens on `127.0.0.1:9222-9229`, so no test touches those ports. `npm run test:integration` and `npm run test:unit` set `SLICC_CDP_PORTS=9300-9309` unless it is already set, and so do `.cargo/config.toml` for `cargo test` and the CI workflows. Node test runs preload `test/integration/ports.mjs`, which sets the same default and makes any connect to loopback 9222-9229 from the test process throw. It matches the host as written (`localhost`, `*.localhost`, `127.x`, `0.0.0.0`, `::1`, `::`), not the address a name resolves to, so a hosts-file name or a service such as `lvh.me` that resolves to loopback gets past it; the CLIs check the resolved address too. `SLICC_CDP_PORTS` is for tests. While it is set, `playwright-cli` and `curlwright` probe and launch on that range, and loopback 9222-9229 are unreachable: they panic and exit 101 before dialing, even for an explicit `--cdp` or `SLICC_CDP_URL`. A test that needs other ports sets its own range. Run local builds the same way, for example `SLICC_CDP_PORTS=9300-9309 target/debug/playwright-cli list`. `cargo run` in this repository already gets the range from `.cargo/config.toml`, so to reach a browser on 9222-9229 run the built binary with `SLICC_CDP_PORTS` unset.
|
|
145
249
|
|
|
250
|
+
A workflow step that gates a merge, a release or a cert runs its script through `node scripts/gate.mjs <name> -- <command>`. The script prints a verdict line `<name>: PASS <detail>`, and the gate fails on a non-zero exit or when that line is missing, so an early `exit 0`, a skipped script or empty output fails the step. Evidence steps pass `--accept PASS,FAIL,INCOMPLETE`, because the record step judges their status. For `node --test` the gate takes `--tap`: it needs `# fail 0` and at least one test that ran, not counting a file with no tests or a skipped test. `scripts/test-integration.mjs` prints `integration: PASS <n> tests` the same way. `test/integration/gate.test.mjs` checks that every such workflow step is gated.
|
|
251
|
+
|
|
146
252
|
## Release supply-chain verification
|
|
147
253
|
|
|
148
254
|
Release publishes its complete signed assets without an in-release behaviour-certification gate. The code-only `verify-release.yml` runs **after** `publish-release`, or independently from main with `gh workflow run verify-release.yml --ref main -f version=1.26.2`. It hashes the exact npm tarball, verifies registry integrity and signed SLSA v1 (GitHub-hosted `release.yml` on main), requires `gitCommit = gitHead = tag` on main, verifies all four macOS signatures and notarisation, and requires the full checksum inventory including the installer and notices. Missing evidence is red `INCOMPLETE`; a mismatch is a red supply-chain `FAIL`, with integrity failure taking precedence.
|
|
@@ -167,6 +273,6 @@ A complete record emits `certified-candidate @ai-ecoverse/slicc-cdp@<v> sha256=<
|
|
|
167
273
|
|
|
168
274
|
The `scripts/cert/pr-*` tools prepare an initially non-required PR certification lane. They are not yet wired to a production workflow or a required check. Main-owned tools must land before that workflow uses them. Test-only changes and all package manifest changes, including scripts-only `postinstall` changes, take the full review. The planned merge-group pass-through is exact-head, ancestry-bound and code-only, consuming immutable trusted PR records and a fresh shared self-guard receipt.
|
|
169
275
|
|
|
170
|
-
The model reviewer uses the kernel lane's pinned `claude-code-action/base-action`, but keeps `--tools ""` and does not request `--json-schema`: that combination returned no `structured_output` in the live bootstrap proof. Unlike the kernel's filesystem-writing reviewer, this model cannot read or write files or execute commands. Main-owned `pr-review.mjs` parses only the execution receipt's successful final result: one complete JSON object or one fenced `json` block with nothing else. It validates the exact schema and head/commit binding; malformed output, free-text keywords and missing execution are
|
|
276
|
+
The model reviewer uses the kernel lane's pinned `claude-code-action/base-action`, but keeps `--tools ""` and does not request `--json-schema`: that combination returned no `structured_output` in the live bootstrap proof. Unlike the kernel's filesystem-writing reviewer, this model cannot read or write files or execute commands. Main-owned `pr-review.mjs` parses only the execution receipt's successful final result: one complete JSON object or one fenced `json` block with nothing else. It validates the exact schema and head/commit binding, hashes the execution receipt, and requires exactly one `system/init` receipt with empty `tools` and `mcp_servers` arrays. Any advertised tool or MCP server is `INCOMPLETE` with `review model had tools`; absent or malformed capability receipts are also `INCOMPLETE`. The invocation flag alone is not proof of tool isolation; malformed output, free-text keywords and missing execution are never a substitute verdict.
|
|
171
277
|
|
|
172
278
|
Mandatory bios evidence uses `ai-ecoverse/slicc-bios/.github/workflows/canary.yml` pinned to merged commit `4025d6aabc2c06add216183064d81914a171cd64`, with `packages-update-cdp` and `guard` shards, repeat three, against both unpublished base and candidate packs. Main prepares distinct `base` and `candidate` labels and verifies both pack hashes without executing them. The consumer checks the producer's real `result` output: pinned bios ref, caller run, repeat, labelled artifact URL, exact override version/hash and artifact-source status binding, counts and completion arrays. The producer summary has no structured candidate `source` field; its exact artifact/run/hash status and override hash are checked, not an invented field or `ok` alone. Candidate regressions/failures are `FAIL`; missing calls, unfinished shards, skips, flaky results or malformed output are `INCOMPLETE`. Both-failing rows remain visible as flags rather than being mistaken for new regressions. The final record independently revalidates both result documents against its own byte-checked packs. The pin alone never makes the slot pass: the rollout workflow still needs two literal pinned canary calls and complete results. Required checks and rulesets need separate rollout approval. The shared guard's accepted residual is: self-guard catches accidental cert-path edits; not enforced against a deliberate rewrite of the workflow.
|
package/bin/curlwright.wasm
CHANGED
|
Binary file
|
package/bin/playwright-cli.wasm
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-cdp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
4
4
|
"description": "SLICC's CDP layer: client, browser API, transports, HAR, and ARIA snapshot",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
"chrome": "156.0.8078.4"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@ai-ecoverse/slicc-kernel": "1.
|
|
72
|
-
"@ai-ecoverse/slicc-shared-web": "1.23.
|
|
71
|
+
"@ai-ecoverse/slicc-kernel": "1.122.1",
|
|
72
|
+
"@ai-ecoverse/slicc-shared-web": "1.23.2",
|
|
73
73
|
"@biomejs/biome": "2.5.15",
|
|
74
74
|
"lefthook": "2.2.1",
|
|
75
75
|
"semantic-release": "25.0.9",
|
|
76
|
-
"@ai-ecoverse/slicc-browsers": "1.7.
|
|
76
|
+
"@ai-ecoverse/slicc-browsers": "1.7.9"
|
|
77
77
|
}
|
|
78
78
|
}
|
package/src/cli.js
CHANGED
|
@@ -77,7 +77,16 @@ export async function main(
|
|
|
77
77
|
return 2;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
function isMain(argv1, moduleUrl) {
|
|
81
|
+
if (!argv1) return false;
|
|
82
|
+
try {
|
|
83
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const invoked = isMain(process.argv[1], import.meta.url);
|
|
81
90
|
if (invoked) {
|
|
82
91
|
main(process.argv.slice(2)).then(
|
|
83
92
|
(code) => {
|