@ai-ecoverse/slicc-spectrum 1.86.1 → 1.86.3
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 +25 -10
- package/dist/{chunk-ZGJM5WUN.js → chunk-SQG7U2FN.js} +1046 -20
- package/dist/{chunk-ZGJM5WUN.js.map → chunk-SQG7U2FN.js.map} +4 -4
- package/dist/ghostty-vt.wasm +0 -0
- package/dist/slicc-terminal.js +1 -1
- package/dist/slicc-ui.js +203 -34
- package/dist/slicc-ui.js.map +4 -4
- package/dist/types/app/browser.d.ts +2 -1
- package/dist/types/app/files.d.ts +1 -0
- package/dist/types/app/memory.d.ts +2 -4
- package/dist/types/app/messages.d.ts +2 -0
- package/dist/types/app/monitor.d.ts +2 -4
- package/dist/types/app/view-state.d.ts +20 -0
- package/dist/types/ghostty.d.ts +2 -0
- package/package.json +3 -2
- package/dist/wterm.wasm +0 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# slicc-spectrum
|
|
2
2
|
|
|
3
3
|
Web components for SLICC: `<slicc-terminal>`, and SLICC's app UI on [Spectrum Web Components](https://opensource.adobe.com/spectrum-web-components/) (see [UI](#ui)).
|
|
4
|
-
`<slicc-terminal>` is a terminal built on [wterm](https://github.com/vercel-labs/wterm) (`@wterm/dom` 0.5.4
|
|
4
|
+
`<slicc-terminal>` is a terminal built on [wterm](https://github.com/vercel-labs/wterm) (`@wterm/dom` 0.5.4 on the Ghostty VT core, `@wterm/ghostty` 0.5.4) that talks to [`@ai-ecoverse/slicc-kernel`](https://github.com/ai-ecoverse/slicc-kernel) through a small backend interface.
|
|
5
5
|
It is a standards custom element with no framework and no shadow root, so it can move to a shared web-components repo unchanged.
|
|
6
6
|
|
|
7
7
|
```html
|
|
@@ -27,6 +27,7 @@ Setting it closes the current session and opens a new one.
|
|
|
27
27
|
|
|
28
28
|
Fixed grid size.
|
|
29
29
|
Without either, the grid fits the element and follows its size.
|
|
30
|
+
When the width changes, soft-wrapped lines reflow to it, on the screen and in the scrollback, with their colours and attributes; lines that ended in a newline stay as they are.
|
|
30
31
|
|
|
31
32
|
### `ready`
|
|
32
33
|
|
|
@@ -64,7 +65,8 @@ Sends `SIGINT`, `SIGTSTP`, `SIGQUIT` or `SIGHUP` to the backend.
|
|
|
64
65
|
|
|
65
66
|
### `readText()`
|
|
66
67
|
|
|
67
|
-
Resolves with the text of the scrollback and the screen.
|
|
68
|
+
Resolves with the text of the scrollback and the screen, with soft-wrapped lines joined into one.
|
|
69
|
+
The scrollback keeps 4 MB of cells, about 3,500 lines at 80 columns and 1,200 at 200.
|
|
68
70
|
|
|
69
71
|
### `focus()`
|
|
70
72
|
|
|
@@ -143,8 +145,8 @@ The stylesheet (wterm's plus the theme) is constructed once per document and ado
|
|
|
143
145
|
|
|
144
146
|
## Distribution
|
|
145
147
|
|
|
146
|
-
`npm run build` writes `dist/slicc-terminal.js` (one ESM bundle with no bare imports), its source map and `dist/wterm.wasm
|
|
147
|
-
The bundle loads the WASM with `new URL('./
|
|
148
|
+
`npm run build` writes `dist/slicc-terminal.js` (one ESM bundle with no bare imports), its source map and `dist/ghostty-vt.wasm` (Ghostty's VT core, about 580 kB; it replaced the 27 kB `dist/wterm.wasm` of wterm's built-in core).
|
|
149
|
+
The bundle loads the WASM with `new URL('./ghostty-vt.wasm', import.meta.url)`, so `dist/` works from any path, including from OPFS through the slicc-bios service worker. It is fetched once per page and compiled once per URL, streaming when it is served as `application/wasm`, and each terminal gets its own instance. wterm's base64-inlined copy of its built-in WASM is left out of the bundle.
|
|
148
150
|
TypeScript declarations go to `dist/types/`, and the package's `types` export points at them.
|
|
149
151
|
Set `SliccTerminal.wasmUrl` before the first element connects to load it from elsewhere.
|
|
150
152
|
`dist/swc.css` (exported as `@ai-ecoverse/slicc-spectrum/swc.css`) is the pinned `@adobe/spectrum-wc` stylesheet with its tokens inlined, one file with no `@import`.
|
|
@@ -154,8 +156,14 @@ A page that puts a UI element straight into the document, such as a guest's page
|
|
|
154
156
|
|
|
155
157
|
Things found while building this against wterm 0.5.4, recorded here, not pushed upstream:
|
|
156
158
|
|
|
157
|
-
- The Zig core
|
|
158
|
-
|
|
159
|
+
- The built-in Zig core doesn't reflow: on a resize it cuts or pads each row and keeps no soft-wrap flags (its bridge has no `getRowMetadata`), so a line wrapped at 45 columns stays on two rows at 120, and `readText()` and copy split it.
|
|
160
|
+
It also maps 24-bit colours (`38;2;r;g;b`) to the nearest of the 256 palette colours.
|
|
161
|
+
The element runs on `@wterm/ghostty` instead, which reflows on resize, keeps wrap flags in the scrollback and renders 24-bit and 256 colours exactly (xterm's 0/95/135/175/215/255 cube).
|
|
162
|
+
- Ghostty resolves palette colours 0–15 to RGB inside the WASM, so wterm's `--term-color-N` variables (and `--slicc-terminal-color-N`) would stop applying.
|
|
163
|
+
The element gives the core a palette of 16 marker colours (`#51cc00` … `#51cc0f`) and maps cells in those colours back to palette indexes, so the CSS variables theme them and follow a theme switch, in the scrollback too. Text drawn in exactly one of those 24-bit colours shows in the theme's palette colour instead.
|
|
164
|
+
- Ghostty answers OSC 10 and OSC 11 queries itself, with the colours it was loaded with. The element drops those replies and answers from the theme it shows.
|
|
165
|
+
- Ghostty's `scrollbackLimit` is in bytes and allocated in pages, so the number of lines it keeps depends on the width. Its default of 10,000 bytes keeps about 300 lines at 200 columns; the element asks for 4 MB.
|
|
166
|
+
- `WTerm.destroy()` doesn't dispose a core passed in as `core`. The element disposes it.
|
|
159
167
|
- wterm sends pasted text with its `\n` line breaks unchanged, whereas xterm.js turns them into `\r`. The element does that conversion itself.
|
|
160
168
|
- `@wterm/core` always ships the WASM inlined as base64 behind a dynamic import. A build without it, or an explicit entry point that takes a URL, would save the bundler plugin.
|
|
161
169
|
- wterm focuses its input when it finishes mounting. `<slicc-terminals>` hands focus back to where it was unless the terminal was focused on purpose.
|
|
@@ -219,6 +227,7 @@ The sans stack (`--swc-sans-font-family-stack`, also used by the 1.12 components
|
|
|
219
227
|
|
|
220
228
|
The shell: header with the agent picker, status items, the update status, the network indicator, the tray, the View menu and the theme switch, rails, and a `<slicc-dock>`.
|
|
221
229
|
Saves the dock layout per screen class to `storage` (default `localStorage`) under `layoutKey`.
|
|
230
|
+
The dock builds new panel content whenever it lays panels out again (a switch between phone, tablet and desktop, or a layout reset), so what the user opens in a panel (sections, cones, rows, folders, disclosures) lives outside the element, per model and panel (`view-state.ts`, in memory only): a rebuilt panel shows it again, and a click on the outgoing panel while the new one mounts reaches the new one too.
|
|
222
231
|
While connected it sets `overscroll-behavior` to `none !important` on the page's `html` and `body`, so only scroll areas inside panels rubber-band.
|
|
223
232
|
It sets the page's `color-scheme` to its resolved theme, and when the page has a `theme-color` meta per `prefers-color-scheme`, gives every one of them the content of the meta for that theme, so the page and the installed app's title bar follow the app's setting instead of the OS.
|
|
224
233
|
When the last app on the page is removed, the page's own inline values and `theme-color` contents come back.
|
|
@@ -240,7 +249,7 @@ A tree (`role="tree"`) of cones, with their scoops listed under them.
|
|
|
240
249
|
A cone with scoops starts with a quiet disclosure chevron (`data-action="toggle-cone"`, `swc-icon-chevron-right`, turned down when open and mirrored right to left); it's `aria-hidden` and out of the Tab order, since the row's `aria-expanded` carries the state.
|
|
241
250
|
The chevron only expands and collapses; a click on the row, <kbd>Enter</kbd> or <kbd>Space</kbd> selects the agent and makes it the active one, which also expands its cone.
|
|
242
251
|
<kbd>→</kbd> expands a cone and then moves to its first scoop, <kbd>←</kbd> moves from a scoop to its cone and then collapses it, and neither changes the active agent.
|
|
243
|
-
Several cones can be open at once, and the active agent
|
|
252
|
+
Several cones can be open at once, and they stay open for every view of the panel on the same model, so a layout switch keeps them; when the active agent has changed since the panel last showed it, its cone opens again as the panel mounts, so on a phone a cone you tapped still shows its scoops when you come back to Agents, and a cone you closed stays closed.
|
|
244
253
|
When the active scoop's cone is collapsed, the cone row takes the Tab stop.
|
|
245
254
|
A row's first line starts with one circle: its unread count when there are unread messages (`99+` from a hundred up, at `--swc-font-size-50`, white on the accent fill, or on the negative fill when the cone is in error), otherwise a dot coloured by status.
|
|
246
255
|
Then comes the name; the context fill, when it's high, sits in the top right corner.
|
|
@@ -272,6 +281,7 @@ A command's icon is the favicon of the site it names when an open browser tab al
|
|
|
272
281
|
A running run pulses (still, with a dashed ring, under `prefers-reduced-motion`), a done or cancelled one is grey and a failed one red, each with a corner glyph.
|
|
273
282
|
The card (`.tool[data-tool][data-status][data-kind]`, a `details.run` under a pill and a `div[role=region]` named by its `title` and status under a strip) has no header of its own, no chevron, title, tool name or status: its input (a shell command after `$`), an edit's `diff` shown as a diff view, its output wrapped rather than cut off, an `image`, such as a screenshot, an optional `meta` such as a timeout, a standalone tool message's time ("Ran at 16:12", `.ran`, by the two-minute rule), and its `notes` (`{ severity, text }`, such as "Exited with code 5" or "Full output in /tmp/…") as lines under the output, `li[data-note][data-severity]`: `error` with an alert icon in the negative colour, `warn` with an alert icon and `info` with an info icon, both subdued; media galleries with images, video and audio; action cards for tools, pull requests and status; plans and checklists; inline diffs; question prompts (as decision cards, below); delegations; link previews; errors with a fix-it action, as a grey card (`.error-card[role=alert]`, `data-id` on system errors) inset by a wide margin on each side, a narrower one under 480 px: a red alert icon, the title in bold, the detail subdued and the action on the right, or under the detail below 360 px, announced as "Error: " and the title; a content-filter stop offers **Drop the last turn**, which rewinds that turn and puts its prompt back into the composer; when the turns right before it failed too, the button reads **Drop N failed turns** and rewinds to before the first of them, putting the latest prompt back), system messages (error cards; compactions and notices, rewinds and model changes included, as full-width dividers with a line on each side, like the day: a compaction shows only its title, its `text` kept for screen readers, one that lost messages (`state: 'fallback'`, by default "Compaction failed, transcript truncated", or `discarded`, "Context discarded") an alert icon in the negative colour, and a notice its title and text on one line, `role="note"`; a divider that wraps keeps a short line on each side) and licks, SLICC's events into a cone, on every channel, on the right (`.lick-turn`): a byline with the title and the time by the two-minute rule, then a dashed box (`.lick[data-id][data-channel]`) with the text and the count (×3); emoji pills on its bottom edge (`.reactions .reaction`, `aria-hidden`, each named by its `title`) give the channel (⏰ Schedule, 🪝 Webhook, ✨ Sprinkle, …) and the outcome (👍 Allowed, 👎 Denied, also said in the box's hidden text).
|
|
274
283
|
A lick with a body is a `details.lick` whose head (`summary.lick-head`, with a quiet chevron that turns when open) toggles it with a click, <kbd>Enter</kbd> or <kbd>Space</kbd>; clicking the body doesn't close it.
|
|
284
|
+
Open licks and open tool runs hold for every view of the chat on the same model, so a layout switch keeps them.
|
|
275
285
|
A lick's `severity` (`warn` or `error`) adds an alert icon to its byline, a coloured edge to its box and a spoken prefix.
|
|
276
286
|
Pending permission requests (`sudo-request` licks with `state: 'pending'`) and open questions are decision cards in the centre column (`.decision-turn[data-pending]`, `data-id` the lick's or the question's), inset like a tool cluster (a wide margin on each side, a narrower one under 480 px), with their buttons on the right: **Deny**, then **Allow** (`data-action` `deny` and `allow`), or the question's options.
|
|
277
287
|
A request with `expiresAt` counts down as m:ss; the count is hidden from screen readers, which hear its end time, then "Less than a minute left" and "Timed out", so the log's live region doesn't speak every second; a timed-out request (`data-expired`) loses its buttons.
|
|
@@ -341,6 +351,7 @@ A quiet line under it (`[data-seat-note]`) says who reviews ("The host reviews w
|
|
|
341
351
|
#### `<slicc-files>`
|
|
342
352
|
|
|
343
353
|
The file system as a `<slicc-file-tree>`, with pending changes as git status.
|
|
354
|
+
It starts with the folders of the pending changes open; once the user opens or closes a folder, every view of Files on the same model shows the same folders open, a rebuilt one included.
|
|
344
355
|
Opening a file opens it in a tab.
|
|
345
356
|
With `files.mountFolder`, **Mount a folder…** (`data-action="mount-folder"`) mounts a local folder, then selects and expands it in the tree; with `files.mounts`, a **Mounted** strip lists the mount points (with `files.mountInfo`, each mount with a `source` reads `/mnt/proj · ref-node/proj`, `data-source` on its `.path`), each with **Eject** (`data-action="eject"`, `data-path` the mount point) when the port has `eject`.
|
|
346
357
|
With `files.needsFolder`, a **Needs a folder** section lists the mount points waiting for a folder, each with **Insert folder…** (`data-action="insert-folder"`, `data-id` the mount point), which calls `mountFolder(path)`.
|
|
@@ -382,6 +393,7 @@ It opens on the most recently driven tab (`.focused`), or on the tab overview: c
|
|
|
382
393
|
The focused tab has **All tabs** (`data-action="all-tabs"`), a tab picker (a list of tabs at 720 px and wider), the URL with **Copy** (`data-action="copy-url"`) and **Open** (`data-action="open-tab"`, activates the tab), who's using it (`.driving[data-driving=agent|user|none]`; a controlled tab without an agent reads **In use** and has no Stop) with a small **Stop <agent>** (`data-action="stop-agent"`) in the same row, which keeps its height with or without an agent, a view-only preview (`figure[data-view]`: `live` while watching with a frame under 3 s old, `shot` with "Updated N s ago", `none`) and the recent actions (`li[data-action-id][data-kind][data-status]`, failures with their error inline), the tab's own filtered first, then the latest 50, with **Show more** (`data-action="more-actions"`) adding 50 earlier ones each time up to all the port has ("Showing the latest N of M"); the list scrolls and takes focus.
|
|
383
394
|
Actions with a URL (`open`, `goto`, `request`) expand (`data-action="action-url"`, `aria-expanded`) to show the full URL, or the request line, under the shortened one.
|
|
384
395
|
Below 480 px they fold into **Recent actions (n)**, a chevron disclosure counting all of them, with the last one showing.
|
|
396
|
+
The tab the user opened (or **All tabs**), expanded URLs and an open **Recent actions** hold for every view of the panel on the same model, so a layout switch keeps them; a closed tab lets go, and the panel opens on the most recently driven tab again.
|
|
385
397
|
Labels, URLs and errors are text only.
|
|
386
398
|
With no tabs and `browser.via` `null` in the network status, it says browser control isn't connected (`data-browser="none"`) with the extension link and the commands to install and run slicc (`curl -fsSL https://get.sliccy.ai/slicc | sh`, then `slicc`, or `npx sliccy@next` with Node).
|
|
387
399
|
The Browser rail button carries a dot (`data-driven`) while a tab is in use.
|
|
@@ -419,6 +431,7 @@ Then **Rules SLICC refused** (`[data-refused]`), where the rules live (`[data-po
|
|
|
419
431
|
The section's `data-vault` is `locked`, `unlocked` or `loading`.
|
|
420
432
|
A popup the browser blocked shows how to allow it (`[data-popup=blocked]`).
|
|
421
433
|
Widened-rule notices aren't shown.
|
|
434
|
+
An open **Removed** list (`details[data-removed]`) stays open across a layout switch.
|
|
422
435
|
|
|
423
436
|
#### `<slicc-vault-button>`
|
|
424
437
|
|
|
@@ -433,7 +446,7 @@ It closes, clearing the field, when the request leaves `waiting` or while the va
|
|
|
433
446
|
|
|
434
447
|
#### `<slicc-updates>`
|
|
435
448
|
|
|
436
|
-
Install / Update: component states, version changes, last checks, download and link counts, action buttons, failures with Retry, and collapsible install logs.
|
|
449
|
+
Install / Update: component states, version changes, last checks, download and link counts, action buttons, failures with Retry, and collapsible install logs, which stay open across a layout switch.
|
|
437
450
|
Opens at boot until the agent is ready without failures.
|
|
438
451
|
Background updates stay in the header's update status; new failures reopen the panel, and after a reload into a boot that isn't ready yet such a panel closes once the agent is ready.
|
|
439
452
|
Every automatic close is saved to the layout.
|
|
@@ -447,7 +460,7 @@ What agents remember, grouped by section: search, filter by scope and tag, expan
|
|
|
447
460
|
The scope picker starts on **Everyone** (`*`), which lists every memory with its scope on it (`.scope[data-scope]`); `global` reads **Shared** whatever the port calls it, and the cones and roles follow.
|
|
448
461
|
The count (“N of M memories”) counts the memories in the picked scope.
|
|
449
462
|
With a search or tag filter that hides everything it says “No memories match.”, otherwise “No memories yet.”, “No shared memories yet.” or “No memories for {scope} yet.”
|
|
450
|
-
Each memory is a row (`li.row[data-id]`) that opens in place: open rows (`data-open`) take the accent's subtle background and turn their chevron down, and show the body with **Edit** and **Forget** (`data-action="edit"`, `data-action="forget"`).
|
|
463
|
+
Each memory is a row (`li.row[data-id]`) that opens in place, and stays open across a layout switch: open rows (`data-open`) take the accent's subtle background and turn their chevron down, and show the body with **Edit** and **Forget** (`data-action="edit"`, `data-action="forget"`).
|
|
451
464
|
Under the summary, the tag is a subtle badge (`swc-badge[data-tag]`: User indigo, Feedback purple, Project seafoam), then the scope and, for free text outside an entry, “From MEMORY.md” (`.from`).
|
|
452
465
|
Below 560 px of panel width, the search takes its own line over the two pickers.
|
|
453
466
|
The search field is the shared one from `search.ts` (`sp-search[data-action=search]`), as in Files.
|
|
@@ -458,7 +471,7 @@ The live monitor: vitals (`.vital[data-id]`), each a meter when it has a `ratio`
|
|
|
458
471
|
Each card keeps its place whatever it shows: the value line never wraps (a unit or delta that doesn't fit is left out whole rather than cut, and stays in the line's `title` and its text; a vital's optional `hint` replaces that tooltip, such as the exact reset time behind "resets in 4 days"), a card without a `series` keeps the sparkline's room, a meter keeps its description's line, and a card left alone on the last row spans it, so short and long values, 0% and 100%, and missing data move nothing below them.
|
|
459
472
|
Then alerts (an alert's optional `command` shows after its detail, led by its `commandLabel` or "Run", as unwrapped code with **Copy**, `[data-command]` and `data-action="copy-command"`), and the sections (the agent's Tasks, Processes and Recent problems, then terminals, tabs, pending changes and tray followers; cones and sprinkles have their own panels; any other section an agent sends, such as an older agent's `agents` or `sprinkles`, renders the same way).
|
|
460
473
|
Each section (`li.section[data-id]`) shows its count and an attention badge, and opens its surface with **Open** where one exists; the counts line up in one column whether or not a section has **Open**, and a section without rows keeps its name in line with the others (`agents`, `terminals` and `processes` → terminal, `tabs`, `changes`).
|
|
461
|
-
A section with rows expands into them with its toggle (`.toggle`, `aria-expanded`; `data-open` on the section): collapsed by default, expanded while a row is `warn` or `error`, until the user toggles it.
|
|
474
|
+
A section with rows expands into them with its toggle (`.toggle`, `aria-expanded`; `data-open` on the section): collapsed by default, expanded while a row is `warn` or `error`, until the user toggles it; that choice holds for every view of the monitor on the same model, so a layout switch keeps it.
|
|
462
475
|
Each row (`li.row[data-status]`, `data-id` from the row's `id`) shows a status light (blue active, gray idle, orange warn, red error, with the status spoken), the name, the meta line and its badges, indented by `depth` (`data-depth`, up to 6).
|
|
463
476
|
|
|
464
477
|
#### `<slicc-freezer>`
|
|
@@ -504,6 +517,7 @@ The URL is never stored or shown again: closing the dialog drops it.
|
|
|
504
517
|
The header's **Network** indicator (`data-network`, `data-health`) opens it: a status light, green for `ok`, yellow for `limited` and red for `failing`, with the state in its text and label and `detail` as its tooltip, which adds "Tailscale is connected." while the tailnet runs; on a phone, a cloud icon for the state.
|
|
505
518
|
While a linked device asks to follow, controls the agent, watches it or has a terminal open, an indicator (`data-remote`, `ask`, `prompt`, `terminal` or `watch`) sits before it, **{name} asks to follow**, **Controlled by**, **Terminal open from** or **Watched by** the device's name (or the number of devices; in that order of precedence), says who does what in its tooltip and opens the panel too.
|
|
506
519
|
Offered when the model has a `network` port, a `guests` port, or both.
|
|
520
|
+
**Link another device** and **Other ways to reach the whole web** stay open across a layout switch once opened.
|
|
507
521
|
With `guests` and no `network`, it shows only the Guests section (no connection, Sync, Leaders, Tailscale, Linked devices, Get the whole web or failures), still titled Network with its rail icon, and the header's Network and remote indicators stay hidden; the tray's connection chip is then a plain status.
|
|
508
522
|
|
|
509
523
|
#### `<slicc-tray>`
|
|
@@ -530,6 +544,7 @@ Not for direct use.
|
|
|
530
544
|
|
|
531
545
|
Generic.
|
|
532
546
|
[`@pierre/trees`](https://www.npmjs.com/package/@pierre/trees) through its `web-components` entry: `paths` (folders end in `/`), `gitStatus`, `expanded`, `query` (shows only the paths that match it; empty shows all), `reveal(path, focus)`.
|
|
547
|
+
`expanded` also opens and closes the folders of a mounted tree, a `tree-expand` event (`detail.expanded`) reports the open folders when the user changes them, and the tree keeps them when it's moved, such as into a floating group.
|
|
533
548
|
It has no search field of its own.
|
|
534
549
|
Fires `file-open` on click and on <kbd>Enter</kbd>, and `tree-search` (`detail.key`) when a letter or digit is typed in it, for the panel's search field.
|
|
535
550
|
|