@ai-ecoverse/slicc-cdp 1.26.2 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@
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`, and `open` when that port is absent or unreachable, GET `/json/version` and `/json/list` on `127.0.0.1:9222-9229`. An unreachable seven-profiles port falls through to that probe, so `open` may attach to a personal browser that already has a seven tab. 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 only while that browser still has a seven tab, and later commands show only tabs this tool created. 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. Launch never binds those ports. 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. 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
12
 
13
13
  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
14
 
@@ -56,7 +56,7 @@ A non-2xx discovery response prints the status and the body and exits non-zero.
56
56
 
57
57
  ## curlwright
58
58
 
59
- `curlwright` is the Rust binary in `crates/curlwright`. It runs curl-style requests as a page-context `fetch()` in an already-open tab, so that tab's cookies, origin, and service worker apply. It uses `--cdp`, else `SLICC_CDP_URL`, else a live `seven-profiles` DevToolsActivePort. On the host, if none of those exist, it exits without dialing port 9222. Ports 9222-9229 inside those files are not dialed. The wasm build still uses port 9222. The shared CDP client is `crates/cdp-client`. Without `--tab`, it uses the `current` target this tool saved for the working directory under the user config dir when that tab is still open, otherwise the single open tab on the request URL's origin. It does not read a `.playwright-cli/session.json` in the working directory and it does not read the saved endpoint. Any other case exits 2 and lists `--tab` choices. A tab on a different origin is not used unless `--tab` or that session names it. A request URL on a protected origin (any `sliccy.ai` host, the vault, or `//` to one) is refused before any tab is chosen, with `curlwright: slicc: refused: target is on seven's origin`, and so is `--tab` on a protected tab.
59
+ `curlwright` is the Rust binary in `crates/curlwright`. It runs curl-style requests as a page-context `fetch()` in an already-open tab, so that tab's cookies, origin, and service worker apply. It uses `--cdp`, else `SLICC_CDP_URL`, else a live `seven-profiles` DevToolsActivePort. On the host, if none of those exist, it uses the first of `127.0.0.1:9222-9229` whose `/json/version` answers, in the order `playwright-cli` probes them, and exits only when none does. Ports 9222-9229 inside those files are dialed like any other. The wasm build still uses port 9222. The shared CDP client is `crates/cdp-client`. Without `--tab`, it uses the `current` target this tool saved for the working directory under the user config dir when that tab is still open, otherwise the single open tab on the request URL's origin. It does not read a `.playwright-cli/session.json` in the working directory and it does not read the saved endpoint. Any other case exits 2 and lists `--tab` choices. A tab on a different origin is not used unless `--tab` or that session names it. A request URL on a protected origin (any `sliccy.ai` host, the vault, or `//` to one) is refused before any tab is chosen, with `curlwright: slicc: refused: target is on seven's origin`, and so is `--tab` on a protected tab.
60
60
 
61
61
  ## Browser
62
62
 
@@ -64,7 +64,7 @@ On the host, the package can find, install and launch a Chrome for a test suite
64
64
 
65
65
  - **`findBrowser({ version })`:** `$CHROME_PATH`, else the newest Chrome for Testing that `install-browser` put under the install root, else a system Chrome or Chromium (`/Applications`, `/usr/bin`, `/snap/bin`, Program Files). With `version` (a full version or a milestone) only that installed Chrome for Testing counts, and `$CHROME_PATH` is not used. Returns `{ executable, source, version? }` or `null`.
66
66
  - **`installBrowser({ version, channel, withDeps })`:** downloads Chrome for Testing for this platform, unzips it, checks that `--version` prints the expected version (on Windows, which prints nothing, that the build's `<version>.manifest` is there), and marks it with `.slicc-cdp-browser.json`. An exact version that is already installed is used without the network. The install root is `$SLICC_BROWSERS_PATH`, else `~/Library/Caches/slicc-cdp/browsers`, `$XDG_CACHE_HOME/slicc-cdp/browsers` (default `~/.cache`), or `%LOCALAPPDATA%\slicc-cdp\browsers`. `withDeps` is opt-in. On Linux it runs `apt-get satisfy` on the build's `deb.deps`, as root or with `sudo -n`, and otherwise fails saying so.
67
- - **`launchBrowser({ executable, userDataDir, port, headless, sandbox, args })`:** starts the browser with `--remote-debugging-port` (0 by default) on `127.0.0.1`. Without `userDataDir` the profile is a fresh `slicc-cdp-profile-*` directory in the temp dir, never the user's, and `close()` kills the browser and removes the profile. Ports 9222-9229 are refused, and so are `args` that set the debugging port, address, pipe or profile. A fixed `port` that already answers is refused. Returns `{ child, executable, userDataDir, port, wsUrl, close }`. With port 0 the `wsUrl` comes from a fresh `DevToolsActivePort`, which is removed before launch. Otherwise it comes from `/json/version` on that port. The sandbox stays on unless `sandbox: false`. Linux without unprivileged user namespaces (Ubuntu 23.10 and later, GitHub's `ubuntu-latest` included) needs that, or Chrome aborts with "No usable sandbox".
67
+ - **`launchBrowser({ executable, userDataDir, port, headless, sandbox, args, platform })`:** starts the browser with `--remote-debugging-port` (0 by default) on `127.0.0.1`. Without `userDataDir` the profile is a fresh `slicc-cdp-profile-*` directory in the temp dir, never the user's, and `close()` kills the browser and removes the profile. Ports 9222-9229 are refused, and so are `args` that set the debugging port, address, pipe, profile or profile directory. They are matched the way Chrome parses its command line: one or two leading dashes, or a leading `/` when `platform` (default `process.platform`) is `win32`, the name up to the first `=`, in any case. Anything after a `--` is not a switch to Chrome and is left alone. A fixed `port` that already answers is refused. Returns `{ child, executable, userDataDir, port, wsUrl, close }`. With port 0 the `wsUrl` comes from a fresh `DevToolsActivePort`, which is removed before launch. Otherwise it comes from `/json/version` on that port. The sandbox stays on unless `sandbox: false`. Linux without unprivileged user namespaces (Ubuntu 23.10 and later, GitHub's `ubuntu-latest` included) needs that, or Chrome aborts with "No usable sandbox".
68
68
 
69
69
  The `slicc-cdp` bin does the same from a shell:
70
70
 
@@ -135,6 +135,20 @@ curlwright --cdp http://127.0.0.1:9333 https://example.com/
135
135
  curlwright --cdp http://127.0.0.1:9333 -I https://example.com/
136
136
  ```
137
137
 
138
- `playwright-cli list` prints `connected`, `debug ports`, and `launchable`. An empty section is the line `none`. `connected` includes an explicit `--cdp` or `SLICC_CDP_URL` browser and each live `DevToolsActivePort`, as `browser - <websocket url>`. It does not launch a browser and does not open a websocket. On the host it also probes catalog ports `127.0.0.1:9222-9229` with GET `/json/version` and GET `/json/list`, reports `source` `probe`, and drops every tab that is not a seven origin. `playwright-cli list --json` prints one JSON document and no text sections. A child of `seven-profiles` is a `profile`. A default user-data directory is a `browser`. `https://<label>.sliccy.ai:443/` counts as seven. Any other explicit port does not.
138
+ `playwright-cli list` prints `connected`, `debug ports`, and `launchable`. An empty section is the line `none`. `connected` includes an explicit `--cdp` or `SLICC_CDP_URL` browser and each live `DevToolsActivePort`, as `browser - <websocket url>`. It does not launch a browser and does not open a websocket. On the host it also probes catalog ports `127.0.0.1:9222-9229` with GET `/json/version` and GET `/json/list`, reports `source` `probe`. In `--json`, an endpoint's `tabs` lists every page except those on protected origins, and `sevenTabs` keeps only the seven ones. `playwright-cli list --json` prints one JSON document and no text sections. A child of `seven-profiles` is a `profile`. A default user-data directory is a `browser`. `https://<label>.sliccy.ai:443/` counts as seven. Any other explicit port does not.
139
139
 
140
- `--cdp` still wins over `SLICC_CDP_URL`, which wins over a live `seven-profiles` DevToolsActivePort, which wins over a loopback session this tool saved under the user config dir, for `playwright-cli`. A `.playwright-cli/session.json` in the working directory is ignored. An unreachable saved endpoint does not stop `open` or `tab-new`. `curlwright` does not read that session endpoint. Saved state never dials a non-loopback host. `open` then reuses a catalog probe port only when that browser already has a seven tab, including when the seven-profiles port is unreachable. Launch never binds `127.0.0.1:9222-9229`. `curlwright` still does not dial those ports unless `--cdp` or `SLICC_CDP_URL` names that URL. Node `connect()` requires `options.url` or `SLICC_CDP_URL` and does not dial port 9222 by itself. The wasm build still uses port 9222. A crate installed from crates.io prints its crate version. In this repository, and in the npm wasm builds, `--version` prints the `package.json` version. The release workflow writes that version into the crate manifests before `cargo publish`, and only after semantic-release has published the npm package. Git keeps the crate versions at `0.0.0`.
140
+ `--cdp` still wins over `SLICC_CDP_URL`, which wins over a live `seven-profiles` DevToolsActivePort, which wins over a loopback session this tool saved under the user config dir, for `playwright-cli`. A `.playwright-cli/session.json` in the working directory is ignored. An unreachable saved endpoint does not stop `open` or `tab-new`. `curlwright` does not read that session endpoint. Saved state never dials a non-loopback host. `open` then reuses a catalog probe port whatever its tabs, including when the seven-profiles port is unreachable. Launch binds the first free port of `127.0.0.1:9222-9229`. `curlwright` probes those ports too when nothing else names a browser. Node `connect()` requires `options.url` or `SLICC_CDP_URL` and does not dial port 9222 by itself. The wasm build still uses port 9222. A crate installed from crates.io prints its crate version. In this repository, and in the npm wasm builds, `--version` prints the `package.json` version. The release workflow writes that version into the crate manifests before `cargo publish`, and only after semantic-release has published the npm package. Git keeps the crate versions at `0.0.0`.
141
+
142
+ ## Release certification
143
+
144
+ `cert-review.yml` is reusable and runs after each release has published its npm package, crates and draft assets. Replay an exact version from main with `gh workflow run cert-review.yml --ref main -f version=1.26.2`; `-f dry_run=true` retains the evidence without writing a release or commit status. No job changes the npm `certified` tag. Every reusable job has an explicit status-aware condition, so a skipped ancestor in the release caller does not silently skip evidence. `cert-call-proof.yml` makes a main-only dry-run call with the same release needs and a deliberately skipped asset ancestor; its verifier requires all seven evidence jobs and the resulting record. Shared browser fixtures use the current harness API independently of the older implementation under test, and per-worker summaries retain results defined in imported test helpers.
145
+
146
+ Hosted planning chooses the newest earlier successful cert-review record, skipping failed and unreviewed releases, with `scripts/cert/base.json` as the lane-approved fallback. Rust is pinned by the tag's `rust-toolchain.toml`, a recorded historical release pin, or the compiler version in that exact release's CI log. The same resolved version, commit, baseline, harness, pins and workflow attempt identify every result document.
147
+
148
+ The bench pool rebuilds both wasm files byte-for-byte against npm, runs the pinned shared guard runner through the Rust client's public bridge with controls and liveness, runs the same guard suite on the previous certified client's source, and runs the tagged integration suites on published JavaScript, native assets and wasm in the tagged kernel pin. Source-built Rust drivers used by existing integration wrappers are named separately from published command bytes. Guard owner additions remain in the suite. Non-executable shared-set descriptions and explicit upstream non-applicable rows remain visible and are not counted as executed passes.
149
+
150
+ Fix commit bodies declare `Proves: <test-id>, ...`; `.cert/proofs.json` provides committed PR-to-id declarations for historical fixes. `scripts/cert/proof-tests.json` binds integration ids to exact public test files/titles; `vector:<id>/<target>/<variant>` selects a shared guard row. Planning derives and deduplicates the named set from the git delta and the PR that first introduced each fix. A fix without ids is a known test gap listed on the line, not a fabricated proof and not missing evidence. Named tests must actually pass on the candidate and fail on the previous certified release. Missing named results or an unrun NEGATIVE are `INCOMPLETE`; a named test that passes on the baseline reads `proof does not discriminate`. Any additional NEGATIVE failure is flagged on the line, never silently credited to a fix. Committed external Rust integration drivers run against both public library versions without copying a private test module or replacing the subject implementation.
151
+
152
+ Hosted jobs verify the full release checksums and all four macOS signatures, identifiers, Developer ID team and notarisation. Only replay mode for commits before #224 may report `legacy: checksum set unavailable`; the asset bytes and GitHub digests still verify, and any present checksum mismatch still fails. Release mode and every commit from #224 onward require a complete checksum set without exception. A separate fresh hosted record job independently downloads the exact npm version with `npm pack`, hashes it in code, verifies registry integrity and signed SLSA provenance, requires gitHead = provenance commit = tag on main, and compares the four crates.io versions and source manifests to the tag. It validates all result documents and job outcomes before emitting `record.json`, the job summary, a cert-review status and the release's Certification evidence section.
153
+
154
+ A complete record emits `certified-candidate @ai-ecoverse/slicc-cdp@<v> sha256=<hex> gitHead=<sha> guard=GUARD-PASS(slicc-cdp@<sha>; vectors @ai-ecoverse/slicc-browsers@<v>)`. Missing evidence emits `cert-ci: INCOMPLETE`; a coded integrity or test failure emits `cert-ci: FAIL`. The cert lane reviews exceptions and retains the authoritative dist-tag decision during this phase. Subsequent publish-only-certified work will certify immutable packed bytes before a hosted main-only publisher sends those same bytes directly to npm latest, then verify provenance, with no candidate npm tag or promotion credential.
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-cdp",
3
- "version": "1.26.2",
3
+ "version": "1.27.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",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "scripts": {
53
53
  "prepare": "lefthook install && node scripts/allow-crate-readmes.mjs",
54
- "build:wasm": "cargo build --release --target wasm32-wasip1 -p slicc-cdp -p curlwright && mkdir -p bin && cp target/wasm32-wasip1/release/playwright-cli.wasm bin/playwright-cli.wasm && cp target/wasm32-wasip1/release/curlwright.wasm bin/curlwright.wasm",
54
+ "build:wasm": "cargo build --locked --release --target wasm32-wasip1 -p slicc-cdp -p curlwright && mkdir -p bin && cp target/wasm32-wasip1/release/playwright-cli.wasm bin/playwright-cli.wasm && cp target/wasm32-wasip1/release/curlwright.wasm bin/curlwright.wasm",
55
55
  "prepublishOnly": "npm run build:wasm",
56
56
  "lint": "slicc-lint",
57
57
  "typecheck": "node --check src/index.js && node --check src/cdp-client.js && node --check src/connect.js && node --check src/page.js && node --check src/browser.js && node --check src/cli.js && node --check packages/sliccy-browser/src/browser.js && node --check packages/sliccy-browser/src/fetch-script.js",
@@ -68,10 +68,11 @@
68
68
  "chrome": "156.0.8078.4"
69
69
  },
70
70
  "devDependencies": {
71
- "@ai-ecoverse/slicc-kernel": "1.97.1",
72
- "@ai-ecoverse/slicc-shared-web": "1.20.0",
71
+ "@ai-ecoverse/slicc-kernel": "1.110.1",
72
+ "@ai-ecoverse/slicc-shared-web": "1.21.1",
73
73
  "@biomejs/biome": "2.5.15",
74
74
  "lefthook": "2.2.1",
75
- "semantic-release": "25.0.9"
75
+ "semantic-release": "25.0.9",
76
+ "@ai-ecoverse/slicc-browsers": "1.7.3"
76
77
  }
77
78
  }
package/src/browser.js CHANGED
@@ -342,10 +342,20 @@ export const OWNED_SWITCHES = [
342
342
  '--remote-debugging-address',
343
343
  '--remote-debugging-pipe',
344
344
  '--user-data-dir',
345
+ '--profile-directory',
345
346
  ];
346
347
 
347
- function owned(arg) {
348
- return OWNED_SWITCHES.some((name) => arg === name || arg.startsWith(`${name}=`));
348
+ function switchName(arg, platform = process.platform) {
349
+ const text = String(arg);
350
+ const prefix =
351
+ /^--?/.exec(text)?.[0] ?? (platform === 'win32' && text.startsWith('/') ? '/' : '');
352
+ if (!prefix) return null;
353
+ return text.slice(prefix.length).split('=')[0].toLowerCase();
354
+ }
355
+
356
+ function owned(arg, platform) {
357
+ const name = switchName(arg, platform);
358
+ return name !== null && OWNED_SWITCHES.some((owned) => owned.slice(2) === name);
349
359
  }
350
360
 
351
361
  const pause = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -391,6 +401,7 @@ export async function launchBrowser({
391
401
  env = process.env,
392
402
  timeout = 30000,
393
403
  fetch: fetchImpl = fetch,
404
+ platform = process.platform,
394
405
  } = {}) {
395
406
  const path = executable ?? (await findBrowser({ env }))?.executable;
396
407
  if (!path) {
@@ -401,7 +412,8 @@ export async function launchBrowser({
401
412
  if (reserved(port)) {
402
413
  throw new Error(`refusing to bind port ${port} (9222-9229 belong to the kernel and the probe)`);
403
414
  }
404
- const taken = args.find(owned);
415
+ const end = args.indexOf('--');
416
+ const taken = (end < 0 ? args : args.slice(0, end)).find((arg) => owned(arg, platform));
405
417
  if (taken) {
406
418
  throw new Error(`args may not set ${taken}: use the port and userDataDir options`);
407
419
  }
package/src/index.d.ts CHANGED
@@ -94,4 +94,5 @@ export declare function launchBrowser(options?: {
94
94
  args?: string[];
95
95
  env?: Record<string, string | undefined>;
96
96
  timeout?: number;
97
+ platform?: string;
97
98
  }): Promise<LaunchedBrowser>;