@ai-ecoverse/slicc 1.22.0 → 1.24.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 +132 -12
- package/package.json +7 -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`, `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`, 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.
|
|
6
6
|
|
|
7
7
|
## Commands (planned)
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
| `slicc` | pick browsers in a small TUI; Enter launches or attaches to the best match, opens seven and links it (works now; see [The default](#the-default-slicc)) |
|
|
12
12
|
| `slicc attach --cdp <url>` | link a seven that is open in an already-running CDP browser (works now; see [Local setup](#local-setup-slicc-attach)) |
|
|
13
13
|
| `slicc launch` | launch a browser with CDP in a separate SLICC profile and print its CDP URL |
|
|
14
|
-
| `slicc <join-url> follow [--exit] [--runner …] [--cdp <url>]` | follow a seven's tray from another machine and offer its network, compute (over SSH) or
|
|
14
|
+
| `slicc <join-url> follow [--exit] [--runner …] [--cdp <url>] [--mount <path>]` | follow a seven's tray from another machine and offer its network, compute (over SSH), browsers or folders (`--exit`, `--runner`, `--cdp` and `--mount` work now; see [Remote setup](#remote-setup-slicc-join-url-follow)) |
|
|
15
15
|
| `slicc browsers --json` | list running CDP endpoints and installed browsers, ranked |
|
|
16
16
|
| `slicc update [--check]` | replace this binary with the latest release (works now; see [Updates](#updates)) |
|
|
17
17
|
|
|
@@ -60,7 +60,8 @@ Release builds send operational telemetry through [go-optel](https://github.com/
|
|
|
60
60
|
|
|
61
61
|
```
|
|
62
62
|
slicc [--browser <id>]... [--cdp <url>]... [--page <url>] [--origin <origin>]... [--profile <name>] [--headless]
|
|
63
|
-
[--name <name>] [--kernel-port <n>] [--no-kernel] [--allow <rule>]... [--deny <rule>]... [--
|
|
63
|
+
[--name <name>] [--kernel-port <n>] [--no-kernel] [--allow <rule>]... [--deny <rule>]... [--mount <path>[:<name>][:ro]]...
|
|
64
|
+
[--yes] [--plain] [--json]
|
|
64
65
|
[--runner <argv…> [--]] [--shell <argv…> [--]] [--eval <argv…> [--]] [--eval-quiet <dur>] [--sftp | --no-sftp]
|
|
65
66
|
```
|
|
66
67
|
|
|
@@ -75,7 +76,7 @@ slicc [--browser <id>]... [--cdp <url>]... [--page <url>] [--origin <origin>]...
|
|
|
75
76
|
|
|
76
77
|
An Electron app can't host seven. Each further browser is an extra: an installed one is launched without a start page, and an endpoint is used as it is. Then the link is set up as for `slicc attach` (see [Local setup](#local-setup-slicc-attach)): over CDP with the browser that hosts seven, the first page tab on an allowed origin.
|
|
77
78
|
|
|
78
|
-
**What the link offers:** `net` (tcp, resolve), `http`, and `cdp` with the browser that hosts seven (`seven: true`) and every extra, under the local policy with all of their debugging ports protected; and kernel services on `--kernel-port` (default 80; `--no-kernel` turns them off) when seven offers `kernel-in` (see [Kernel services](#kernel-services)); and `ssh` only with `--runner` (see [SSH server](#ssh-server)). seven gets full control of every listed browser.
|
|
79
|
+
**What the link offers:** `net` (tcp, resolve), `http`, and `cdp` with the browser that hosts seven (`seven: true`) and every extra, under the local policy with all of their debugging ports protected; and kernel services on `--kernel-port` (default 80; `--no-kernel` turns them off) when seven offers `kernel-in` (see [Kernel services](#kernel-services)); and `ssh` only with `--runner` (see [SSH server](#ssh-server)); and `fs` with each `--mount` folder (see [Host folders](#host-folders)). seven gets full control of every listed browser.
|
|
79
80
|
|
|
80
81
|
The cdp list follows the browsers: an extra that stops answering is taken off the list (`browser-gone`), and listed again with the same id when it answers on the same endpoint again (`browser-back`).
|
|
81
82
|
|
|
@@ -83,7 +84,7 @@ The cdp list follows the browsers: an extra that stops answering is taken off th
|
|
|
83
84
|
- `--browser <id>`: an id from `slicc browsers` (an installed id such as `chrome`, or `cdp:<host>:<port>`), or a name, case-insensitively. Repeatable: the first hosts seven, the others are extras. Without it, the best match that can host seven.
|
|
84
85
|
- `--cdp <url>`: also consider this CDP endpoint, as `slicc browsers --cdp`.
|
|
85
86
|
- `--page <url>`: the seven page, default `https://seven.sliccy.ai/`. It must be `http` or `https`, and its origin is accepted as a seven origin.
|
|
86
|
-
- `--origin`, `--name`, `--allow`, `--deny`, `--kernel-port`, `--no-kernel`, and the compute flags `--runner`, `--shell`, `--eval`, `--eval-quiet`, `--sftp`, `--no-sftp`: as for `slicc attach`. Without `--runner` there is no `ssh`.
|
|
87
|
+
- `--origin`, `--name`, `--allow`, `--deny`, `--kernel-port`, `--no-kernel`, `--mount`, and the compute flags `--runner`, `--shell`, `--eval`, `--eval-quiet`, `--sftp`, `--no-sftp`: as for `slicc attach`. Without `--runner` there is no `ssh`.
|
|
87
88
|
- `--profile <name>`: the SLICC profile for a launched browser that hosts seven.
|
|
88
89
|
- `--headless`: launch browsers without a window.
|
|
89
90
|
- `--yes`, `--plain`: no picker. `--json`: NDJSON events, below.
|
|
@@ -223,6 +224,7 @@ Plain output: the CDP HTTP URL on stdout, status lines on stderr. With `--json`,
|
|
|
223
224
|
```
|
|
224
225
|
slicc attach --cdp <url> [--cdp-extra <url>]... [--origin <origin>]... [--signal cdp|stdio] [--name <name>] [--allow <rule>]... [--deny <rule>]...
|
|
225
226
|
[--runner <argv…> [--]] [--shell <argv…> [--]] [--eval <argv…> [--]] [--eval-quiet <dur>] [--sftp | --no-sftp] [--kernel-port <n>] [--no-kernel]
|
|
227
|
+
[--mount <path>[:<name>][:ro]]...
|
|
226
228
|
```
|
|
227
229
|
|
|
228
230
|
`attach` links a seven that is open in a running CDP browser and serves the link until it is interrupted (`SIGINT`, `SIGTERM`), or until stdin closes with `--signal stdio`. Status lines go to stderr, and `SLICC_DEBUG=1` adds diagnostics, pion's included. pion never writes to stderr itself.
|
|
@@ -238,6 +240,7 @@ slicc attach --cdp <url> [--cdp-extra <url>]... [--origin <origin>]... [--signal
|
|
|
238
240
|
- `--shell <argv…>`: the interactive form for `ssh` without a command, in the same argv syntax. The default is derived from the runner.
|
|
239
241
|
- `--eval <argv…>` and `--eval-quiet <duration>`: the REPL behind the `slicc-eval` subsystem (for example `--eval python3 -i`), and the silence that ends one response (default `500ms`).
|
|
240
242
|
- `--sftp`, `--no-sftp`: serve the `sftp` subsystem or not. The default is on only for a plain local shell as the runner.
|
|
243
|
+
- `--mount <path>[:<name>][:ro]`: share this folder with seven's kernel (cap `fs`, repeatable); see [Host folders](#host-folders).
|
|
241
244
|
- `--kernel-port`: the local port for [kernel services](#kernel-services) (1–65535, default `80`).
|
|
242
245
|
- `--no-kernel`: no kernel services; nothing listens.
|
|
243
246
|
|
|
@@ -280,7 +283,7 @@ One WebRTC peer connection. seven offers and the node answers. The node:
|
|
|
280
283
|
- **Resets with `EOPNOTSUPP`:** an OPEN for a kind it doesn't serve.
|
|
281
284
|
- **Closes the link:** an unknown frame type, a short or malformed frame (END with a payload, CREDIT that isn't 4 bytes), stream id 0, a reused id, an id with the wrong parity (page streams are odd, node streams even), or a second OPEN on a stream channel.
|
|
282
285
|
|
|
283
|
-
HELLO from `attach`: `{ "v": 1, "role": "node", "name", "host", "version", "mode": "local", "caps": ["net", "http", "cdp"], "routes": { "prefixes": [], "exit": true }, "policy": { "allow", "deny", "summary" }, "browsers": [ … ] }`. `cdp` and `browsers` are there when at least one browser is listed (see [`cdp`](#cdp-browser-control)). With `--runner`, `caps` adds `"ssh"` and HELLO adds `"sshHostKey": "ssh-ed25519 AAAA…"`, the host key in `authorized_keys` form, so the page can write `<host>.slicc.internal <key>` into the kernel's `known_hosts`.
|
|
286
|
+
HELLO from `attach`: `{ "v": 1, "role": "node", "name", "host", "version", "mode": "local", "caps": ["net", "http", "cdp"], "routes": { "prefixes": [], "exit": true }, "policy": { "allow", "deny", "summary" }, "browsers": [ … ] }`. `cdp` and `browsers` are there when at least one browser is listed (see [`cdp`](#cdp-browser-control)). With `--runner`, `caps` adds `"ssh"` and HELLO adds `"sshHostKey": "ssh-ed25519 AAAA…"`, the host key in `authorized_keys` form, so the page can write `<host>.slicc.internal <key>` into the kernel's `known_hosts`. With `--mount`, `caps` adds `"fs"` and HELLO adds `"mounts"` (see [Host folders](#host-folders)).
|
|
284
287
|
|
|
285
288
|
**`ssh`** (cap `ssh`), page → node, with `--runner` only:
|
|
286
289
|
- OPEN `{ "kind": "ssh" }`, OPENED `{}` at once. The stream's bytes are one SSH connection to the node's SSH server.
|
|
@@ -344,7 +347,7 @@ HELLO from `attach`: `{ "v": 1, "role": "node", "name", "host", "version", "mode
|
|
|
344
347
|
|
|
345
348
|
**`browsers` updates** (page cap `browsers`), node → page. When the list changes while a link is up and the page's HELLO has `browsers` in `caps`, the node opens `OPEN { "kind": "browsers", "browsers": [ … ] }` on the control channel with the full current list in HELLO's shape. It replaces the previous list; there are no deltas. The page answers OPENED `{}` and END, and the node sends END. Updates are sent one at a time per link, a change that comes while one is in flight is sent after it, with the list as it is then, and an update the page doesn't finish within 10 s is reset with `ETIMEDOUT`. A change between the HELLO and the link coming up is sent as an update right away.
|
|
346
349
|
|
|
347
|
-
`test/integration/testdata/link/link.js` is a page-side implementation of the link (framing, credit, both channel layouts, the violation rules, and `resolve` and raw-fetch helpers) that the integration tests run in Chrome against `slicc attach`. `cdp.js` next to it is a CDP client over `cdp` streams, and `page.js` answers `browsers` updates. Loaded with `?kernel`, the test page lists `kernel-in` and answers `kernel` OPENs with `kernel.js`, a small HTTP and WebSocket echo server in the page.
|
|
350
|
+
`test/integration/testdata/link/link.js` is a page-side implementation of the link (framing, credit, both channel layouts, the violation rules, and `resolve` and raw-fetch helpers) that the integration tests run in Chrome against `slicc attach`. `cdp.js` next to it is a CDP client over `cdp` streams, `fs.js` an op-shaped client for `fs` streams (`call`, `list`, `read`, `write`, `watch`), and `page.js` answers `browsers` and `mounts` updates. Loaded with `?kernel`, the test page lists `kernel-in` and answers `kernel` OPENs with `kernel.js`, a small HTTP and WebSocket echo server in the page.
|
|
348
351
|
|
|
349
352
|
### Kernel services
|
|
350
353
|
|
|
@@ -380,6 +383,119 @@ The browser's connection waits unread for `OPENED`.
|
|
|
380
383
|
|
|
381
384
|
**Security.** The `Host` check defends against DNS rebinding. Kernel services are reachable like any dev server on localhost: by any local process, and by any web page Chrome lets reach loopback. Use `--no-kernel` to keep them inside the page.
|
|
382
385
|
|
|
386
|
+
## Host folders
|
|
387
|
+
|
|
388
|
+
`--mount <path>[:<name>][:ro]` shares a folder of this machine with seven's kernel, which mounts it with its `hostfs` driver. It is repeatable and works on `slicc`, `slicc attach` and `slicc <join-url> follow`. This is slicc-node's hostfs (its README, *Host folders*), with the same operations and the same rules, carried on `fs` link streams instead of HTTP. There are no tokens: the link is the trust boundary, as for `ssh`, and seven decides which kernel mounts it creates. With `follow`, the folders go to the seven on the other machine.
|
|
389
|
+
|
|
390
|
+
**Export.**
|
|
391
|
+
- A trailing `:ro` makes the folder read-only. After that, the text after the last `:` is the name if it isn't empty and has no `/` or `\`, so `C:\work` is a path and `C:\work:proj` is named `proj`. The default name is the folder's own.
|
|
392
|
+
- The folder is resolved with `realpath` at start. A missing path or a file is skipped with `--mount <spec>: not an existing folder, skipping`, a name of `.` or `..` with `invalid name, skipping`, and a second folder under a name already used with `the name <name> is taken, skipping`.
|
|
393
|
+
- Names never reveal host paths, and neither does anything else on the link.
|
|
394
|
+
- Without a folder, the node doesn't advertise `fs`, and an `fs` OPEN gets `EOPNOTSUPP`.
|
|
395
|
+
|
|
396
|
+
**HELLO.** `caps` lists `fs`, and `"mounts"` lists the folders:
|
|
397
|
+
|
|
398
|
+
```json
|
|
399
|
+
"mounts": [{ "name": "project", "readonly": false,
|
|
400
|
+
"capabilities": { "maxIo": 16777216, "symlinks": true, "chmod": true,
|
|
401
|
+
"caseInsensitive": true, "normalization": "nfd-insensitive", "ranges": true } }]
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
- `capabilities` is slicc-node's grant answer, so seven hands it to the driver unchanged.
|
|
405
|
+
- `symlinks` and `chmod` are `false` on Windows and `true` elsewhere.
|
|
406
|
+
- `caseInsensitive` is probed per folder on its own volume. The last component of the folder's path that has letters is looked up again with its case swapped, and the probe is `true` when that finds the same file. When no component has letters, it is `true` on macOS and Windows.
|
|
407
|
+
- `normalization` is `nfd-insensitive` on macOS and `none` elsewhere.
|
|
408
|
+
- `ranges: true` says `setattr` takes `size`, so the kernel reads and writes in pages.
|
|
409
|
+
|
|
410
|
+
**Streams.** Each operation is one stream, `OPEN { "kind": "fs", "mount", "readonly"?, "op", …arguments }`. An OPEN is one frame, so at most 64 KiB.
|
|
411
|
+
- The node answers OPENED (followed by DATA for `list` and `read`), then END. The page sends END once it has OPENED.
|
|
412
|
+
- An error is `RESET <ERRNO>: <message>`, before OPENED or, for `list`, `read`, `write` and `watch`, after it.
|
|
413
|
+
- `readonly: true` on an OPEN makes that call `EROFS` if it writes, opens for writing or changes the namespace, even on a writable folder. A `:ro` folder is that way for every call.
|
|
414
|
+
- `read` and `list` may go on the control channel or on their own stream channel. Pages should give reads over 64 KiB their own channel. `write` and `watch` belong on their own channel.
|
|
415
|
+
|
|
416
|
+
**Paths** are relative to the folder, `/`-separated, with `""` (or a missing or `null` `path`) for the root. Empty and `.` components are ignored.
|
|
417
|
+
- `..` and a leading `/` are `EACCES`, and NUL is `EINVAL`. On Windows `\` and `:` are `EINVAL` too, which also rules out alternate data streams and drive letters.
|
|
418
|
+
- Every operation resolves the parent directory with `realpath`, and refuses it with `EACCES` when it lies outside the folder.
|
|
419
|
+
- The last component gets lstat semantics. The kernel follows symlinks itself, so `stat` reports a symlink as one, `list` on a symlink is `ENOTDIR`, and `open` on a symlink is `ELOOP`.
|
|
420
|
+
- Operations that change the namespace run one at a time, and no other operation runs alongside them. The lock covers every link and every folder of the node, so no page can swap a directory for a symlink between the check and the use.
|
|
421
|
+
|
|
422
|
+
**Operations**, with slicc-node's arguments and answers:
|
|
423
|
+
|
|
424
|
+
| op | arguments | answer |
|
|
425
|
+
| --- | --- | --- |
|
|
426
|
+
| `stat` | `path` | OPENED `attr` |
|
|
427
|
+
| `list` | `path` | OPENED `{}`, then NDJSON lines `{"name","attr"}` as DATA; an entry that vanishes meanwhile is left out |
|
|
428
|
+
| `mkdir` | `path` | `{}`; not recursive, mode `0777` minus the umask |
|
|
429
|
+
| `rmdir` | `path` | `{}` |
|
|
430
|
+
| `unlink` | `path` | `{}`; `EISDIR` for a directory |
|
|
431
|
+
| `rename` | `from`, `to` | `{}`, `rename(2)`; it replaces a file or an empty directory, a directory onto a non-empty one is `ENOTEMPTY`, a directory onto a file `ENOTDIR`, a file onto a directory `EISDIR` |
|
|
432
|
+
| `symlink` | `target`, `path` | `{}`; `target` is stored as given; `EPERM` on Windows |
|
|
433
|
+
| `readlink` | `path` | `{ "target" }`; `EINVAL` for anything but a symlink |
|
|
434
|
+
| `setattr` | `path`, `size?`, `mode?`, `mtime?` (ms) | `{}`; `size` truncates or extends with zeros, like `truncate(2)`, then `mode` and `mtime` apply. `size` on a directory is `EISDIR`, `size` or `mode` on a symlink is `EINVAL`, and `mtime` doesn't follow a symlink |
|
|
435
|
+
| `statfs` | | `{ "bsize", "blocks", "bfree", "bavail" }` of the folder's volume |
|
|
436
|
+
| `open` | `path`, `write?`, `create?`, `truncate?`, `exclusive?`, `mode?` | `{ "fh", "attr" }` |
|
|
437
|
+
| `read` | `fh`, `offset`, `size` (≤ `maxIo`), `ifMatch?` | OPENED `{ "etag", "size", "offset", "length" }`, then `length` bytes as DATA |
|
|
438
|
+
| `write` | `fh`, `offset` | OPENED `{}`; the page sends the bytes, then END, and the node ENDs once they are written |
|
|
439
|
+
| `release` | `fh` | `{ "attr" }` for a write handle, `{}` otherwise |
|
|
440
|
+
| `watch` | `mounts` (no `mount`) | OPENED `{}`, then NDJSON lines as DATA |
|
|
441
|
+
|
|
442
|
+
- `attr` is `{ "kind": "file"|"directory"|"symlink", "size", "mtime" (ms, fractional), "mode" (permission bits), "ino", "etag" }`.
|
|
443
|
+
- `etag` is `"<size>-<mtimeNs>-<ino>"`, quotes included, so `attr.etag` and `ifMatch` compare as plain strings.
|
|
444
|
+
- The folder's root can't be removed or renamed, or replaced by a rename (`EBUSY`).
|
|
445
|
+
- **Arguments:**
|
|
446
|
+
- `write`, `create`, `truncate`, `exclusive` and `readonly` count when they are truthy, as in JavaScript.
|
|
447
|
+
- Offsets and sizes are integers from 0 to 2^53−1, `mode` an integer up to `0o7777`, and `mtime` a number. `fh` is a positive integer, and any other `fh` is `EBADF`.
|
|
448
|
+
- A `path`, `from`, `to` or `target` that isn't a string is `EINVAL`, and so is any other argument of the wrong type, `null` included.
|
|
449
|
+
- An unknown `op`, or no `op`, is `EINVAL`. A `mount` that isn't exported is `ENOENT` with `no such folder`.
|
|
450
|
+
|
|
451
|
+
**Handles.** `open` without `write`, `create`, `truncate` or `exclusive` gives a name handle, which holds nothing open between calls. Any of those flags gives a write handle, which keeps the file open (read and write) until `release`.
|
|
452
|
+
- `create`, `exclusive` (with `create`), `truncate` and `mode` (default `0666` minus the umask) apply at `open`, and their errors come back there. A directory is `EISDIR` (`EEXIST` with `create` and `exclusive`), anything but a regular file `EINVAL`.
|
|
453
|
+
- Handles are numbered per link from 1. A link holds at most 4096 per folder, and the next `open` is `EMFILE`.
|
|
454
|
+
- An `fh` sent with another `mount` than the one it was opened on is `EBADF`, and so is one already released.
|
|
455
|
+
- When the link closes, its handles close. What was written stays, as with a crashed local process.
|
|
456
|
+
|
|
457
|
+
**Reads.** A read on a name handle opens the file again, through the path rules. When `ifMatch` is given and differs from the file's current etag, it is `ESTALE` with `file changed since it was opened`, so the kernel starts over instead of mixing two versions. A read on a write handle reads its descriptor and ignores `ifMatch`.
|
|
458
|
+
- OPENED carries the file's `etag` and `size` with the `offset` asked for and the `length` that follows. The read is short at EOF, and `length` is 0 past it.
|
|
459
|
+
- If the file shrinks while the bytes are being sent, the stream is `RESET ESTALE`.
|
|
460
|
+
|
|
461
|
+
**Writes happen in place,** like `open(2)` and `pwrite(2)`, in any order and with holes. Writing in place keeps hard links, extended attributes, ACLs and ownership. Programs that want atomic replacement write a temporary file and rename it, and those are operations too.
|
|
462
|
+
- Before OPENED, the node checks the call: `EROFS` for a read-only folder or `readonly: true`, `EINVAL` for a bad `offset`, `EBADF` for an unknown handle, one from another folder, or a name handle.
|
|
463
|
+
- Each DATA is written at its place before it is credited, so the stream window bounds the memory used. More than `maxIo` bytes in one call is `RESET EINVAL`, and what came before stays written.
|
|
464
|
+
- After the page's END and the last write, the node sends END. A page RESET leaves what was written.
|
|
465
|
+
|
|
466
|
+
**Watch.** `OPEN { "kind": "fs", "op": "watch", "mounts": ["project", …] }` streams NDJSON lines until the page sends END or the link closes:
|
|
467
|
+
|
|
468
|
+
```
|
|
469
|
+
{"mount":"project","paths":["src/a.ts","src"]}
|
|
470
|
+
{"mount":"project","all":true}
|
|
471
|
+
{"ping":1}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
- A missing or empty `mounts`, or one that isn't a list of strings, is `EINVAL`, and a name that isn't exported is `ENOENT`.
|
|
475
|
+
- `paths` name what changed and its parent directory (`""` for the root), coalesced over 50 ms. Past 256 paths the line is `all`, and so is a change the watcher can't name (the root itself, an event-queue overflow).
|
|
476
|
+
- A watcher that fails or can't start is retried every second. It sends one `all` when it is lost and one when it is back. A folder that is renamed away or removed is lost until it comes back.
|
|
477
|
+
- A ping goes out every 15 s.
|
|
478
|
+
- Changes seven made itself come back too.
|
|
479
|
+
- One watcher per folder serves every watch stream on every link, and it lingers 5 s after the last stream ends, so replacing a watch is cheap.
|
|
480
|
+
- A page that doesn't read gets its backlog folded into one `all` per folder instead of a growing queue.
|
|
481
|
+
|
|
482
|
+
The watcher per OS:
|
|
483
|
+
- **Linux:** inotify through fsnotify, one watch per directory, so the node walks the folder at start and adds every new directory. Symlinks aren't followed. A tree past `fs.inotify.max_user_watches` makes the watcher fail, which is then retried every second.
|
|
484
|
+
- **macOS:** kqueue through fsnotify, which holds one descriptor per watched directory and file. A very large tree can run out of descriptors in the same way.
|
|
485
|
+
- **Windows:** one `ReadDirectoryChangesW` on the folder with `bWatchSubtree`, which is what libuv does. A handle on every directory would stop Windows from renaming any of their parents.
|
|
486
|
+
|
|
487
|
+
**Mount updates** (page cap `mounts`). When folders are added or removed while a link is up (`fs.Server.Add` and `Remove`, for the TUI), the node opens `OPEN { "kind": "mounts", "mounts": [ … ] }` on the control channel, with the full list in HELLO's shape. It replaces the previous list, and there are no deltas. The page answers OPENED `{}` and END, and the node sends END. Updates go one at a time per link, and one the page doesn't finish within 10 s is reset with `ETIMEDOUT`. A removed folder's handles close (`EBADF` if the name comes back), its operations are `ENOENT`, and a watch stream covering it ends with `RESET ENOENT: no such folder`. `--mount` alone never changes the set.
|
|
488
|
+
|
|
489
|
+
**Errors.** The code is the POSIX name, `EIO` when there is none. The message is libuv's lower-case text for it (`no such file or directory`), or slicc-node's own for the cases it names (`path escapes the folder`, `read-only folder`, `file changed since it was opened`, `the folder root cannot be moved or removed`). It never contains a host path. Windows errors are mapped the way libuv maps them, for example `ERROR_ACCESS_DENIED` to `EPERM` and `ERROR_SHARING_VIOLATION` to `EBUSY`.
|
|
490
|
+
|
|
491
|
+
**Windows.**
|
|
492
|
+
- Paths go through `\\?\` and `GetFinalPathNameByHandle`, so device names (`CON`, `NUL`) and 8.3 short names are plain names inside the folder.
|
|
493
|
+
- Files are opened with `FILE_SHARE_DELETE` and without following reparse points.
|
|
494
|
+
- Symlinks and junctions both show as `kind: "symlink"`, `readlink` works on both, and `unlink` removes the link itself.
|
|
495
|
+
- `ino` is the file index, and `mode` is `0666`, or `0444` for a read-only file, plus `0111` for a directory. `setattr` `mode` sets or clears the read-only attribute.
|
|
496
|
+
- `unlink` clears the read-only attribute first, as `DeleteFile` would refuse otherwise.
|
|
497
|
+
- `rename` gives the POSIX answers above, replacing an empty directory itself.
|
|
498
|
+
|
|
383
499
|
## Network policy
|
|
384
500
|
|
|
385
501
|
A node checks every address it connects to for the link's `tcp`, `http` and `ssh` forwarding, and drops refused addresses from `resolve` answers. The check runs on each address actually connected, after DNS and for every Happy Eyeballs attempt, so a name can't rebind past it. A refusal is `EACCES`.
|
|
@@ -457,6 +573,7 @@ A command that can't start exits 127 with the reason on stderr.
|
|
|
457
573
|
```
|
|
458
574
|
slicc <join-url> follow [--exit] [--allow <rule>]... [--deny <rule>]... [--name <name>] [--cdp <url>]...
|
|
459
575
|
[--runner <argv…> [--]] [--shell <argv…> [--]] [--eval <argv…> [--]] [--eval-quiet <dur>] [--sftp | --no-sftp]
|
|
576
|
+
[--mount <path>[:<name>][:ro]]...
|
|
460
577
|
```
|
|
461
578
|
|
|
462
579
|
`follow` links this machine to a seven on another machine through the tray hub (see [Tray hub signaling](#tray-hub-signaling-remote-setup)). It serves the link until interrupted (`SIGINT`, `SIGTERM`) and reconnects when the link drops. Status lines go to stderr, and `SLICC_DEBUG=1` adds diagnostics. The join URL is never printed.
|
|
@@ -467,8 +584,9 @@ slicc <join-url> follow [--exit] [--allow <rule>]... [--deny <rule>]... [--name
|
|
|
467
584
|
- `--name`: the link's `name` and `host` in HELLO, as for `attach`.
|
|
468
585
|
- `--runner`, `--shell`, `--eval`, `--eval-quiet`, `--sftp`, `--no-sftp`: compute over SSH (cap `ssh`), exactly as for `attach`. `direct-tcpip` forwarding goes through the remote policy, so it reaches public addresses only unless `--allow` says otherwise. `--runner` works with or without `--exit`.
|
|
469
586
|
- `--cdp <url>`: let seven drive this browser over the link (repeatable, in any form `slicc browsers --cdp` takes; each must answer when `follow` starts). See [`cdp`](#cdp-browser-control), and its warning: the seven on the other machine gets full control of every browser listed. No browser is `seven: true`. Without `--cdp`, `follow` doesn't offer `cdp`, and a `cdp` OPEN is refused with `EOPNOTSUPP`. Each browser's debugging port and its own endpoint addresses are [denied](#network-policy) to `tcp`, `http` and `ssh` forwarding.
|
|
587
|
+
- `--mount <path>[:<name>][:ro]`: share this folder with the seven on the other machine (cap `fs`, repeatable); see [Host folders](#host-folders). It can read the folder, and change it unless `:ro`.
|
|
470
588
|
|
|
471
|
-
HELLO from `follow`: `{ "v": 1, "role": "node", "name", "host", "version", "mode": "remote", "caps", "routes": { "prefixes": [], "exit" }, "policy" }`. `caps` holds `net` and `http` with `--exit`, `ssh` with `--runner` (plus `sshHostKey`), `cdp` (and HELLO `browsers`) with `--cdp`, and always `join`.
|
|
589
|
+
HELLO from `follow`: `{ "v": 1, "role": "node", "name", "host", "version", "mode": "remote", "caps", "routes": { "prefixes": [], "exit" }, "policy" }`. `caps` holds `net` and `http` with `--exit`, `ssh` with `--runner` (plus `sshHostKey`), `cdp` (and HELLO `browsers`) with `--cdp`, `fs` (and HELLO `mounts`) with `--mount`, and always `join`.
|
|
472
590
|
|
|
473
591
|
**Identity.** The device is its DTLS certificate. `follow` keeps one ECDSA P-256 certificate per hub origin (`scheme://host:port`), valid for 20 years, in `<config>/slicc/tray-certs.json` (mode `0600`). Every link to that hub uses it, so the fingerprint stays the same across reconnects, restarts and updates. The first run on a hub mints it and says `new device, fingerprint sha-256 …`; later runs say `device, fingerprint …`. Every dial attaches with a fresh `controllerId`, which is only a routing handle.
|
|
474
592
|
|
|
@@ -522,15 +640,17 @@ The real-Chrome tests in `test/integration/` launch headless, so they run the ex
|
|
|
522
640
|
semantic-release cuts releases from `main` in `.github/workflows/release.yml`, on a macOS runner:
|
|
523
641
|
1. `scripts/release-plan.mjs` asks semantic-release (dry run) for the next version, and stops when there is none.
|
|
524
642
|
2. `scripts/package.sh <version>` builds `darwin`, `linux` and `windows` × `amd64`, `arm64` with `CGO_ENABLED=0`, `-trimpath` and `-X main.version=<version>`. It signs and notarizes the darwin binaries, signs the windows binaries with jsign against Azure Trusted Signing, and writes `SHA256SUMS`. Without the signing secrets (forks, pull requests) it warns and leaves those binaries unsigned.
|
|
525
|
-
3. `scripts/npm-stage.mjs` stages `@ai-ecoverse/slicc` and the six platform packages
|
|
643
|
+
3. `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 a `sliccy` bin 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.
|
|
526
644
|
4. `actions/attest-build-provenance` attests every binary.
|
|
527
|
-
5. semantic-release checks the version again, 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)
|
|
645
|
+
5. semantic-release checks the version again, 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.
|
|
528
646
|
|
|
529
|
-
On pull requests the same workflow runs as a dry run: an unsigned build of all six targets, the npm packages packed with `--dry-run`, and each binary run with `--version` on its own OS and CPU.
|
|
647
|
+
On pull requests the same workflow runs as a dry run: an unsigned build of all six targets, the npm packages and `sliccy` (with `--tag next`) packed with `--dry-run`, and each binary run with `--version` on its own OS and CPU.
|
|
530
648
|
|
|
531
649
|
The workflow reads these repository secrets. Each group is optional, and a missing group leaves its binaries unsigned:
|
|
532
650
|
- macOS signing: `APPLE_CERTIFICATE_BASE64`, `APPLE_DEVELOPER_CERTIFICATE_PASSWORD`;
|
|
533
651
|
- notarization: `APPLE_API_KEY_ID`, `APPLE_API_KEY_ISSUER_ID`, `APPLE_API_KEY_P8_BASE64`;
|
|
534
652
|
- Windows signing: `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_TRUSTED_SIGNING_ENDPOINT`, `AZURE_TRUSTED_SIGNING_ACCOUNT`, `AZURE_TRUSTED_SIGNING_PROFILE`, and `AZURE_CLIENT_SECRET` unless the app registration trusts this workflow through a federated credential (OIDC).
|
|
535
653
|
|
|
536
|
-
npm needs no token. `npm run trust` (fledgling) configures trusted publishing for the seven packages listed under `fledgling.include` in `package.json`. Publishing to npm is off until the repository variable `SLICC_NPM_PUBLISH` is `true`; until then a release
|
|
654
|
+
npm needs no token. `npm run trust` (fledgling) configures trusted publishing for the seven packages listed under `fledgling.include` in `package.json`. Publishing to npm is off until the repository variable `SLICC_NPM_PUBLISH` is `true`, and `sliccy` stays off until `SLICCY_NEXT_PUBLISH` is `true`; until then a release skips them with a notice.
|
|
655
|
+
|
|
656
|
+
`sliccy` only ever goes to the `next` dist-tag, so `npx sliccy` keeps running SLICC six and `npx sliccy@next` runs this binary. `npm-publish.mjs` refuses, even in a dry run, to publish `sliccy` with any tag but `next` or with a version that doesn't match `^7\.0\.0-next\.`. Nothing here changes `sliccy`'s other dist-tags.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
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,11 @@
|
|
|
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.24.0",
|
|
22
|
+
"@ai-ecoverse/slicc-darwin-amd64": "1.24.0",
|
|
23
|
+
"@ai-ecoverse/slicc-linux-arm64": "1.24.0",
|
|
24
|
+
"@ai-ecoverse/slicc-linux-amd64": "1.24.0",
|
|
25
|
+
"@ai-ecoverse/slicc-windows-arm64": "1.24.0",
|
|
26
|
+
"@ai-ecoverse/slicc-windows-amd64": "1.24.0"
|
|
27
27
|
}
|
|
28
28
|
}
|