@ai-ecoverse/slicc 1.32.0 → 1.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -5
- package/bin/slicc.js +27 -1
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`slicc` is SLICC's command line for seven, the SLICC on `*.sliccy.ai`. It is one binary for macOS, Windows and Linux. It launches and links browsers, and shares a machine's network, compute and browsers with a running seven over a WebRTC link. `npx sliccy` and Sliccstart.app run this binary. It replaces slicc-node and slicc-swift.
|
|
4
4
|
|
|
5
|
-
**Status:** being built. `slicc` (the default flow), `slicc attach` (with the `cdp` capability), `slicc <join-url> follow`, remote control with `prompt`, `watch` and `abort`, host folders with `--mount`, `slicc browsers`, `slicc launch`, `update`, `--version` and `--help` work so far, plus a hidden diagnostic, `slicc <join-url> follow --signal-only [--timeout 2m]`. It attaches through the tray hub, prints a summary of the leader's offer (its size, media sections, candidate count and DTLS fingerprint) and the ICE server URLs (credentials are never printed), and exits without answering. The link protocol is drafted alongside seven's link exit and moves into this README once both sides pass a shared test.
|
|
5
|
+
**Status:** being built. `slicc` (the default flow), `slicc attach` (with the `cdp` capability), `slicc <join-url> follow`, remote control with `prompt`, `watch` and `abort`, host folders with `--mount`, `slicc browsers`, `slicc launch`, `update`, `install`, `--version` and `--help` work so far, plus a hidden diagnostic, `slicc <join-url> follow --signal-only [--timeout 2m]`. It attaches through the tray hub, prints a summary of the leader's offer (its size, media sections, candidate count and DTLS fingerprint) and the ICE server URLs (credentials are never printed), and exits without answering. The link protocol is drafted alongside seven's link exit and moves into this README once both sides pass a shared test.
|
|
6
6
|
|
|
7
7
|
## Commands (planned)
|
|
8
8
|
|
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
| `slicc <join-url> prompt <text>`, `watch`, `abort` | send a prompt to seven's agent and stream its answer, follow the agent as it works, or abort its run; `--cdp <url>` instead of a join URL links locally (works now; see [Remote control](#remote-control-slicc-prompt-watch-and-abort)) |
|
|
16
16
|
| `slicc browsers --json` | list running CDP endpoints and installed browsers, ranked |
|
|
17
17
|
| `slicc update [--check]` | replace this binary with the latest release (works now; see [Updates](#updates)) |
|
|
18
|
+
| `slicc install jerk\|fnox` | install slicc-jerk or fnox into slicc's data folder (works now; see [Companion tools](#companion-tools)) |
|
|
18
19
|
|
|
19
20
|
## Install
|
|
20
21
|
|
|
21
|
-
- **npm:** `npm install -g @ai-ecoverse/slicc`, or `npx @ai-ecoverse/slicc`. The package is a small Node launcher; npm picks one of the platform packages `@ai-ecoverse/slicc-<os>-<arch>` (`darwin`, `linux`, `windows` × `amd64`, `arm64`) through `optionalDependencies` and their `os` and `cpu` fields. The launcher runs that binary with the same arguments, stdio and environment plus `SLICC_LAUNCHER=npm`, forwards `SIGTERM`, `SIGHUP`, `SIGQUIT` and `SIGUSR2` to it, and `SIGINT` too when stdin is not a terminal (a terminal's Ctrl-C already reaches the binary; on Windows the console delivers Ctrl-C and Ctrl-Break to both). It exits with the binary's exit code, or dies of the same signal. An install with `--omit=optional` has no binary, and the launcher says so.
|
|
22
|
+
- **npm:** `npm install -g @ai-ecoverse/slicc`, or `npx @ai-ecoverse/slicc`. The package is a small Node launcher; npm picks one of the platform packages `@ai-ecoverse/slicc-<os>-<arch>` (`darwin`, `linux`, `windows` × `amd64`, `arm64`) through `optionalDependencies` and their `os` and `cpu` fields. The launcher runs that binary with the same arguments, stdio and environment plus `SLICC_LAUNCHER=npm`, forwards `SIGTERM`, `SIGHUP`, `SIGQUIT` and `SIGUSR2` to it, and `SIGINT` too when stdin is not a terminal (a terminal's Ctrl-C already reaches the binary; on Windows the console delivers Ctrl-C and Ctrl-Break to both). It exits with the binary's exit code, or dies of the same signal. An install with `--omit=optional` has no binary, and the launcher says so. The companion tools come the same way (see [Companion tools](#companion-tools)).
|
|
22
23
|
- **GitHub releases:** every release of `ai-ecoverse/slicc-cli` carries `slicc-<os>-<arch>` (`.exe` on Windows) for all six targets, plus `SHA256SUMS`. See [Verifying a download](#verifying-a-download).
|
|
23
24
|
- **Go:** `go install github.com/ai-ecoverse/slicc-cli/cmd/slicc@latest`. See [Install with Go](#install-with-go).
|
|
24
25
|
|
|
@@ -145,6 +146,21 @@ Signing:
|
|
|
145
146
|
- **macOS:** the binaries are signed with a Developer ID, with the hardened runtime, and notarized. A bare binary can't carry a stapled ticket (only apps, disk images and installer packages can), so Gatekeeper checks the notarization online the first time it runs. Inside Sliccstart.app the binary is stapled with the app.
|
|
146
147
|
- **Windows:** the binaries are unsigned for now. Authenticode signing through Azure Trusted Signing comes before general availability. Until then a browser download gets a SmartScreen warning, and AppLocker, WDAC or Intune policies can block the binary.
|
|
147
148
|
|
|
149
|
+
## Companion tools
|
|
150
|
+
|
|
151
|
+
slicc works with two tools that run on this machine: slicc-jerk (`jerk`), which gets tokens for seven's vault, and fnox. slicc finds them on `PATH` or in `bin` of its data folder: `~/Library/Application Support/slicc` on macOS, `$XDG_DATA_HOME/slicc` (default `~/.local/share/slicc`) on Linux, `%LOCALAPPDATA%\slicc` on Windows. That folder is never shared over `fs` (see [Host folders](#host-folders)). When its `bin` exists, slicc appends it to its own `PATH` at start, so its children (the SSH runner, and jerk calling fnox) find the tools too; a copy already on `PATH` wins.
|
|
152
|
+
|
|
153
|
+
**With npm.** `@ai-ecoverse/slicc` and `sliccy` list `@ai-ecoverse/slicc-jerk` and `@ai-ecoverse/fnox` as `optionalDependencies` (`^` the latest release), but only those that are on the registry when the release is staged (`npm-stage.mjs --companions`); the others are left out with a notice. The publish check that waits for the platform packages doesn't wait for them. The launcher puts the `node_modules/.bin` of each installed companion package first on `PATH` for the binary, so `jerk` and `fnox` resolve for slicc and its children.
|
|
154
|
+
|
|
155
|
+
**`slicc install jerk|fnox`** installs one into the data folder's `bin`:
|
|
156
|
+
- `jerk` from the latest release of `ai-ecoverse/slicc-jerk`, `fnox` from the latest release of `ai-ecoverse/fnox-build`;
|
|
157
|
+
- **the release contract** (the same as slicc-cli's own): a plain binary `<name>-<os>-<arch>` (`.exe` on Windows; `darwin`, `linux`, `windows` × `amd64`, `arm64`), and `SHA256SUMS` with a line for it, both attested by the repo's `release.yml`;
|
|
158
|
+
- slicc checks the download against `SHA256SUMS`, then installs it only once its `--version` names the release's version, through a rename next to the old one (as `slicc update` does);
|
|
159
|
+
- it says `installed <name> <version> at <path>; its SHA-256 matches the release's SHA256SUMS (the attestation isn't checked yet)`, or `<name> <version> is already installed at <path>`;
|
|
160
|
+
- the GitHub API base follows `SLICC_UPDATE_API_BASE`, as for `update`.
|
|
161
|
+
|
|
162
|
+
Only a user runs `slicc install`. Nothing on a link starts an install.
|
|
163
|
+
|
|
148
164
|
## Updates
|
|
149
165
|
|
|
150
166
|
`slicc update` replaces the running binary (symlinks resolved) with the latest GitHub release of `ai-ecoverse/slicc-cli`. It downloads the asset for this OS and CPU and checks it against the release's `SHA256SUMS`. The new binary has to answer `--version` with the release's version before anything is replaced. The swap is a rename next to the old binary; on Windows the running binary is first moved aside to `<name>.old`, which the next run deletes. `slicc update --check` only reports.
|
|
@@ -501,12 +517,30 @@ Only browsers the user named are listed: the one seven runs in, `--cdp` and `--c
|
|
|
501
517
|
- **Refused**, with `{"id":…,"sessionId"?:…,"error":{"code":-32000,"message":"slicc: refused: target is on seven's origin"}}`, never forwarded: `Target.createTarget`, `Page.navigate` and anything else whose `url` is protected; `Page.navigateToHistoryEntry` to an entry whose URL is protected (the node looks it up with `Page.getNavigationHistory`); `Target.attachToTarget`, `activateTarget`, `closeTarget`, `autoAttachRelated`, `Browser.getWindowForTarget` and any other command whose `targetId` or `frameId` is a protected target; and every command on a session whose target is protected, or became so. `Target.getTargetInfo` and `Target.detachFromTarget` stay allowed.
|
|
502
518
|
- **Origins and storage.** A command whose `origin`, `securityOrigin`, `ownerOrigin`, `issuerOrigin`, `topLevelOrigin`, `topLevelSite`, `embeddedOrigin`, `requestingOrigin`, `scopeURL` or `manifestId` is protected, or whose `storageKey` or `cacheId` names seven's storage, is refused the same way. This covers `Storage.*`, `IndexedDB.*`, `CacheStorage.*`, `DOMStorage.*`, `FileSystem.*`, `ServiceWorker.*`, `PWA.*`, `Browser.setPermission` and `Browser.grantPermissions`. Free-form values (`expression`, `arguments`, `value`, `headers`, `postData` and the like) aren't searched.
|
|
503
519
|
- **Cookies.** `Network.getCookies`, `Network.getAllCookies`, `Storage.getCookies` and `Page.getCookies` answer without the cookies whose domain is protected (`sliccy.ai` and every subdomain, and each extra origin's host and its parents: cookies ignore ports), and without partitioned cookies whose `partitionKey.topLevelSite` is such a site. `Network.setCookie`, `setCookies`, `deleteCookies`, `Storage.setCookies` and `Page.deleteCookie` for such a domain, a URL on such a host, or a partition key under such a site, are refused with `slicc: refused: cookies on seven's origin`. So are `Network.clearBrowserCookies` and `Storage.clearCookies`, except in a browser context this stream created with `Target.createBrowserContext`.
|
|
504
|
-
- **Requests a page makes to seven.** For a request whose URL is protected, `Network.*` and `Fetch.*` events lose their `Cookie` and `Set-Cookie` headers, their raw header texts and their cookie lists, and `requestWillBeSentExtraInfo` drops seven's cookies from `associatedCookies` for any request. For a WebSocket, WebTransport or EventSource on a protected origin (`ws:` and `wss:` count as `http:` and `https:`), `webSocketWillSendHandshakeRequest`, `webSocketHandshakeResponseReceived`, `webSocketFrameError`, `eventSourceMessageReceived` and `dataReceived` are dropped. Reading such a request's body (`Network.getResponseBody`, `Fetch.getResponseBody`, `takeResponseBody…AsStream`, `Audits.getEncodedResponse` and the like) is refused. Continuing, failing or fulfilling it is allowed.
|
|
520
|
+
- **Requests a page makes to seven.** For a request whose URL is protected, `Network.*` and `Fetch.*` events lose their `Cookie` and `Set-Cookie` headers, their raw header texts and their cookie lists, and `requestWillBeSentExtraInfo` drops seven's cookies from `associatedCookies` for any request. For a WebSocket, WebTransport or EventSource on a protected origin (`ws:` and `wss:` count as `http:` and `https:`), `webSocketWillSendHandshakeRequest`, `webSocketHandshakeResponseReceived`, `webSocketFrameError`, `eventSourceMessageReceived` and `dataReceived` are dropped. Reading such a request's body (`Network.getResponseBody`, `Fetch.getResponseBody`, `takeResponseBody…AsStream`, `Audits.getEncodedResponse` and the like) is refused. Continuing, failing or fulfilling it is allowed, except for a document request, which the node fails itself (see the next items).
|
|
505
521
|
- **Browser-wide commands**, refused with their own reason after `slicc: refused: `: `Target.exposeDevToolsProtocol` (it would give a page the whole browser) and `Target.sendMessageToTarget` (attach with `flatten: true` instead), on any target; `Fetch.enable` on the browser itself (a page session is fine); `Tracing.start`; `Extensions.loadUnpacked`; and `Browser.setPermission`, `Browser.grantPermissions` without an `origin` and `Browser.resetPermissions`, except in a browser context this stream created.
|
|
506
522
|
- **Auto-attach.** With `Target.setAutoAttach`, a session to a protected target is detached by the node at once (`Target.detachFromTarget` on its parent session), and the page never sees its `attachedToTarget` or `detachedFromTarget`.
|
|
507
|
-
- **Navigation by other means.** A script's `location = …`, a link, `window.open` or a server redirect
|
|
523
|
+
- **Navigation by other means.** A script's `location = …`, a link, `window.open` or a server redirect isn't a command the node can refuse, so the node guards the network instead.
|
|
524
|
+
- A target the stream attached to (`Target.attachToTarget`, or auto-attach that reached the page) or created (`Target.createTarget`) is *touched*, for as long as the stream is open, even after the page detached. That includes every tab the browser opens while the stream auto-attaches to new tabs.
|
|
525
|
+
- On each touched page, iframe, background page or webview target the node attaches a session of its own, which the page never sees. On it, the node enables `Fetch` for document requests to protected hosts (`resourceType: Document`, request stage), and `Network` with `Network.setBypassServiceWorker`, so a service worker can't hand out a document without a request.
|
|
526
|
+
- The node fails each such request into a protected origin with `Fetch.failRequest` (`BlockedByClient`), and the target shows Chrome's error page instead. Every other request continues untouched. So a touched target never loads a protected document, and nothing the stream installed on it (`Page.addScriptToEvaluateOnNewDocument`, `Fetch`, `Network`, `Page.setBypassCSP`, emulation, overrides) ever runs there.
|
|
527
|
+
- Seven's own tab and its vault frame are never touched, because attaching to them is refused.
|
|
528
|
+
- Page commands on a touched target's session wait until the node's own session there is ready. That takes at most 10 s; after that, or when the node's session can't be set up or is lost, they are refused with `slicc: refused: slicc can't keep seven's origin out of this target`.
|
|
529
|
+
- In touched targets, service workers are bypassed for every request, not only for protected ones.
|
|
530
|
+
- 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.
|
|
531
|
+
- 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 `Fetch.requestPaused` (`resourceType: Document`, protected URL, either stage) itself, and the page never sees it.
|
|
532
|
+
- 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. A request the node failed also leaves the target on the protected URL, showing the error page. Either way the node detaches every page session on the target, drops their events and results, and refuses further commands on them; the page gets `Target.detachedFromTarget`.
|
|
533
|
+
- **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:
|
|
534
|
+
- The page doesn't get its `attachedToTarget` yet, its events are dropped, and page commands on it are refused.
|
|
535
|
+
- If the page asked for `waitForDebuggerOnStart`, the node runs `Runtime.runIfWaitingForDebugger` on it itself.
|
|
536
|
+
- Once the target has a URL (`Target.targetInfoChanged`), a protected target's session is detached without the page seeing it. Otherwise the page gets `attachedToTarget` with the current `targetInfo` and `waitingForDebugger: false`. The target has already started, so a script the page adds for new documents in such a frame or popup misses its first one.
|
|
537
|
+
- A target that has no URL after 10 s is treated as protected. A session that the node does forward makes the target touched (see above).
|
|
508
538
|
- **Listing.** `Target.getTargets`, `Target.getTargetInfo`, `Target.targetCreated` and `Target.targetInfoChanged` still show protected targets, so seven knows its tab exists, but their `url` and `title` are only the origin (`https://seven.sliccy.ai`, or `about:blank`). Service worker registrations and versions on a protected origin are left out of `ServiceWorker` events, and `Storage`, `DOMStorage` and `BackgroundService` events that name a protected origin are dropped.
|
|
509
|
-
- **Limits.**
|
|
539
|
+
- **Limits.**
|
|
540
|
+
- The filter relies on Chrome's site isolation. A seven frame inside a page of another site is a target of its own (`iframe`), which the node protects. A page the stream never touched can still frame seven, though, and once the stream touches that page, a screenshot of it shows the frame. A same-site frame shares its parent's process and isn't a target. Every `sliccy.ai` host is protected, so this only matters for an extra origin, such as one port of `127.0.0.1` framed by a page on another.
|
|
541
|
+
- A document that arrives without a request isn't failed: a page restored from the back/forward cache, and a `blob:` or `filesystem:` URL of a protected origin (which only that origin can make). The node detaches after the commit, as above, and commands that were already on their way may still have run in the new page.
|
|
542
|
+
- If the node loses its own session (`ECONNRESET: slicc lost track of the browser's targets`), it refuses every command and resets the stream unless the browser closes within 2 s.
|
|
543
|
+
- The node's own setup connection (see [Local setup](#local-setup-slicc-attach)) is not a `cdp` stream and isn't filtered.
|
|
510
544
|
|
|
511
545
|
**List changes.** The node checks every listed browser's debugging port every 2 s. One that fails twice in a row is removed: its open streams get `RESET ECONNRESET: browser quit`, and a later OPEN for it gets `ENOENT`. Once its port answers again it is listed again under the same id. A browser removed through the API (`Registry.Remove`, for the TUI) has its streams reset with `ECONNRESET: browser removed`.
|
|
512
546
|
|
package/bin/slicc.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
const { spawn } = require('node:child_process');
|
|
5
5
|
const fs = require('node:fs');
|
|
6
6
|
const os = require('node:os');
|
|
7
|
+
const path = require('node:path');
|
|
7
8
|
const tty = require('node:tty');
|
|
8
9
|
|
|
9
10
|
const targets = {
|
|
@@ -43,6 +44,31 @@ function binaryPath() {
|
|
|
43
44
|
return bin;
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
const companions = { '@ai-ecoverse/slicc-jerk': 'jerk', '@ai-ecoverse/fnox': 'fnox' };
|
|
48
|
+
|
|
49
|
+
function companionDirs() {
|
|
50
|
+
const names = (bin) => (process.platform === 'win32' ? [`${bin}.cmd`, `${bin}.exe`, bin] : [bin]);
|
|
51
|
+
const dirs = [];
|
|
52
|
+
for (const [pkg, bin] of Object.entries(companions)) {
|
|
53
|
+
for (const modules of require.resolve.paths(pkg) || []) {
|
|
54
|
+
if (!fs.existsSync(path.join(modules, pkg, 'package.json'))) continue;
|
|
55
|
+
const dir = path.join(modules, '.bin');
|
|
56
|
+
if (names(bin).some((n) => fs.existsSync(path.join(dir, n))) && !dirs.includes(dir)) dirs.push(dir);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return dirs;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function childEnv() {
|
|
64
|
+
const env = { ...process.env, SLICC_LAUNCHER: 'npm' };
|
|
65
|
+
const dirs = companionDirs();
|
|
66
|
+
if (!dirs.length) return env;
|
|
67
|
+
const key = Object.keys(env).find((k) => k.toUpperCase() === 'PATH') || 'PATH';
|
|
68
|
+
env[key] = [...dirs, env[key]].filter(Boolean).join(path.delimiter);
|
|
69
|
+
return env;
|
|
70
|
+
}
|
|
71
|
+
|
|
46
72
|
const forwarded =
|
|
47
73
|
process.platform === 'win32' ? [] : ['SIGTERM', 'SIGHUP', 'SIGQUIT', 'SIGUSR2'];
|
|
48
74
|
const swallowed = process.platform === 'win32' ? ['SIGINT', 'SIGBREAK'] : [];
|
|
@@ -52,7 +78,7 @@ if (process.platform !== 'win32') {
|
|
|
52
78
|
|
|
53
79
|
const child = spawn(binaryPath(), process.argv.slice(2), {
|
|
54
80
|
stdio: 'inherit',
|
|
55
|
-
env:
|
|
81
|
+
env: childEnv(),
|
|
56
82
|
});
|
|
57
83
|
|
|
58
84
|
const handlers = new Map();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.1",
|
|
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,11 +18,12 @@
|
|
|
18
18
|
"node": ">=18"
|
|
19
19
|
},
|
|
20
20
|
"optionalDependencies": {
|
|
21
|
-
"@ai-ecoverse/slicc-darwin-arm64": "1.
|
|
22
|
-
"@ai-ecoverse/slicc-darwin-amd64": "1.
|
|
23
|
-
"@ai-ecoverse/slicc-linux-arm64": "1.
|
|
24
|
-
"@ai-ecoverse/slicc-linux-amd64": "1.
|
|
25
|
-
"@ai-ecoverse/slicc-windows-arm64": "1.
|
|
26
|
-
"@ai-ecoverse/slicc-windows-amd64": "1.
|
|
21
|
+
"@ai-ecoverse/slicc-darwin-arm64": "1.33.1",
|
|
22
|
+
"@ai-ecoverse/slicc-darwin-amd64": "1.33.1",
|
|
23
|
+
"@ai-ecoverse/slicc-linux-arm64": "1.33.1",
|
|
24
|
+
"@ai-ecoverse/slicc-linux-amd64": "1.33.1",
|
|
25
|
+
"@ai-ecoverse/slicc-windows-arm64": "1.33.1",
|
|
26
|
+
"@ai-ecoverse/slicc-windows-amd64": "1.33.1",
|
|
27
|
+
"@ai-ecoverse/slicc-jerk": "^0.3.0"
|
|
27
28
|
}
|
|
28
29
|
}
|