@ai-ecoverse/slicc-spectrum 1.103.0 → 1.103.2

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
@@ -199,6 +199,7 @@ Every surface has a home side, left, center or right.
199
199
  Every panel has an icon in the left or right rail (on a phone, in one bar at the bottom, with the rest in its More menu).
200
200
  The icon stays when its panel is open; while the panel is visible it shows selected (`.selected`, `data-visible`, labelled "{Title}, shown").
201
201
  One click puts a closed panel back on its side, next to its neighbours, or brings an open one to the front.
202
+ A touch or pen tap on a rail button closes its tooltip: a Gen2 `swc-tooltip` ignores focus that comes in the same task as `pointerdown`, but a tap focuses the button a task later, so the tooltip opened and stayed while the button kept focus (after a tap on Chat, which leaves focus where it is).
202
203
  Each thread, a cone's or a scoop's conversation, opens in its own chat panel (`chat:<agent id>`), as a tab in the same group as the other chats.
203
204
  Selecting a thread opens or reveals its tab, activating a chat tab selects its thread, and a thread's chat closes when the thread goes away (frozen or deleted).
204
205
 
@@ -276,7 +277,7 @@ User messages (with attachments and a quiet timestamp, `time.when`, by that rule
276
277
  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.
277
278
  A reply's tool calls are the steps of its response status (`swc-response-status[slot=status]`, `data-id` the reply's), at the top of the reply: one `swc-response-status-step` per call (`id` `run-` and the call's id, `data-tool`, `data-status`, `data-kind`, and `data-id` the message the call came from), labelled with the tool and its `title`, `active` while it runs, `complete` when done and `stopped` when it failed or was cancelled, which its label says in words (" · Failed", " · Cancelled").
278
279
  The status keeps `data-action="open-cluster"` and each step `data-action="open-run"` with `data-target` the call's id: clicking the host from script opens it, as the old strip's buttons did, and opening a step opens its status too.
279
- A step whose call has anything to show labels itself with a button (`.run-toggle`, `aria-expanded`, `aria-controls`) that opens the call under the step's row, at the full width of the column and indented to the step's text, in our own region (`.run-detail#detail-` and the call's id, `role="listitem"`, `hidden` while closed, `data-target` the call's id), not in Spectrum's 340 px description; the step carries `data-open` while it's open. The region is the call: its input (a shell command after `$`), an edit's `diff` shown as a diff view, its output, both kept on their lines and scrolling sideways rather than wrapping, with its ANSI styles shown (bold, dim, italic, underline, inverse, and the 16, 256 and truecolor foregrounds and backgrounds; the 16 foregrounds come from `--slicc-terminal-color-0` to `-15` when an embedder sets them, else the terminal panel's light tokens, which adapt in dark (so a card in dark uses Spectrum's colors, not the panel's VS Code ones); the 16 backgrounds are Spectrum's subtle tints under the default text, black a solid grey under the lightest grey, so text keeps 4.5:1; a 256 or truecolor background gets black or white text by its luminance unless the program set a 256 or truecolor foreground too; 256 and truecolor foregrounds show as sent; dim subdues default text and turns a bright color into its normal one) and every other escape stripped, a partial escape at the end of streamed output waiting for the rest (the model still sees the raw bytes, and a copy gets the text without escapes), an `image`, such as a screenshot, an optional `meta` such as a timeout, the time a joined call ran ("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.
280
+ A step whose call has anything to show labels itself with a button (`.run-toggle`, `aria-expanded`, `aria-controls`) that opens the call under the step's row, at the full width of the column and indented to the step's text, in our own region (`.run-detail#detail-` and the call's id, `role="listitem"`, `hidden` while closed, `data-target` the call's id), not in Spectrum's 340 px description; the step carries `data-open` while it's open. The region is the call: its input (a shell command after `$`), an edit's `diff` shown as a diff view, its output, both kept on their lines and scrolling sideways rather than wrapping, with its ANSI styles shown (bold, dim, italic, underline, inverse, and the 16, 256 and truecolor foregrounds and backgrounds; the 16 foregrounds come from `--slicc-terminal-color-0` to `-15` when an embedder sets them, else the terminal panel's light tokens, which adapt in dark (so a card in dark uses Spectrum's colors, not the panel's VS Code ones); the 16 backgrounds are Spectrum's subtle tints under the default text, black a solid grey under the lightest grey, so text keeps 4.5:1; a 256 or truecolor background shows as a tint, blended toward the card (12% in light, 25% in dark), and one too close to the card to see, such as white on a light card, gets a grey tint toward the card's text instead; a 256 or truecolor foreground keeps its hue but moves toward black or white until it has 4.5:1 on the card or its tint, and other text on such a tint takes the card's text colour under the same floor; the card and its text colour are read once for light and once for dark, so the colours follow the theme through `light-dark()`; dim subdues default text and turns a bright color into its normal one) and every other escape stripped, a partial escape at the end of streamed output waiting for the rest (the model still sees the raw bytes, and a copy gets the text without escapes), an `image`, such as a screenshot, an optional `meta` such as a timeout, the time a joined call ran ("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.
280
281
  The status's header is always one line: while the reply streams or the agent works on the run, it is `active`, with the running call (or the last one) as its label and that call's kind as its loader, and each label stays for at least a second before the next one replaces it, so streamed arguments don't make it flicker; a reply without calls shows "Generating response" only until its first text or visible thinking.
281
282
  Done, the status stays as `complete`, also when a call never left `running` (the step stays `active`): one call reads as its tool and `title`, more as the model's label for them or, until there is one, a count of the two most common kinds and the rest, such as "3 commands, 1 read" or "5 commands, 4 agent steps and 9 more", led by any failures ("1 failed, 1 cancelled · "), so the one-line header never cuts them off; a stopped reply says so.
282
283
  Every call of a reply is in its one status, above its text; a later reply with text starts a new run, while a standalone tool message or a reply with only tool calls, streaming or done, joins the status of the run before it on the same day (hidden thinking and source links don't count as text), so a turn never collapses when its calls finish and past messages never move down.
@@ -351,7 +352,7 @@ The field's status icon, which is decorative, follows the input: the AI logo whe
351
352
  Drafts are kept per agent.
352
353
  On a follower while the link reconnects, the field is disabled and says so; the draft stays.
353
354
  While the agent port's `starting()` returns a line (no agent yet, but one is on its way), the composer stays usable: its placeholder is that line, there are no `/` or `@` popups, and sending, attachments included, adds a row above the field that reads "Sent when the agent starts" (`li.queued[data-mode="starting"]`), which can be dropped (`data-action="unqueue"`); a row with text and files says how many files go with it (`[data-files]`).
354
- Whenever the model changes or its agent port fires `starting` or `agents`, and the current model's port has no line (`null`, or no `starting` at all) and `agent.list()` has an agent, the composer sends the rows in order to that model's active agent (else the first one) through `agent.send`, the first like a normal send and the rest with `mode: 'queue'`, and the rows go; if the line clears with no agent, the rows stay until one comes.
355
+ Whenever the model changes or its agent port fires `starting` or `agents`, and the current model's port has no line (`null`, or no `starting` at all) and `agent.list()` has an agent, the page sends the rows in order to that model's active agent (else the first one) through `agent.send`, the first like a normal send and the rest with `mode: 'queue'`, and the rows go; if the line clears with no agent, the rows stay until one comes. Inside `<slicc-app>`, the app sends them for its current `model`, once, whether or not a composer is connected, so they also go while the chat is hidden (dockview detaches hidden panels, such as when Install / Update opens in the chat's group); a composer outside `<slicc-app>` sends them for its document, once however many are connected.
355
356
  A line that comes back closes an open `/` or `@` popup.
356
357
  The rows are kept for the page (for the `<slicc-app>` the composer is in, else for the document), not for the model, so a model swap (an embedder that puts a new `SliccModel` on `<slicc-app>` once the agent is there), a layout switch and a dock rebuild keep them.
357
358
  They're also kept in `sessionStorage` (`slicc-spectrum.starting`, so per origin and per tab) until they're sent or dropped: each row's text and `mode`, and only the name, type and size of its attachments, never their contents; each page (each `<slicc-app>`, or the document) rewrites only its own rows there.
@@ -628,6 +629,7 @@ Files and diffs open in one editor group next to the chat.
628
629
  Panels ask for them with `open-file` and `open-diff` events (`{ path }`), which `<slicc-app>` handles, or call `app.open('file' | 'diff', path)`.
629
630
 
630
631
  Keys: <kbd>Alt</kbd>+<kbd>1</kbd>… opens and focuses a panel, <kbd>F6</kbd> and <kbd>Shift</kbd>+<kbd>F6</kbd> move between groups, <kbd>Ctrl</kbd>+<kbd>]</kbd> and <kbd>Ctrl</kbd>+<kbd>[</kbd> between tabs, <kbd>Alt</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd> switches the theme.
632
+ Focusing a chat panel this way, or with `show('chat')`, right after a touch or pen tap leaves focus where it is, so no on-screen keyboard opens and the empty log shows no ring; after a key or a mouse click it focuses the composer (its log without one) with a fine pointer, and the log with a coarse one.
631
633
  In terminal and browser tab strips, <kbd>←</kbd> and <kbd>→</kbd> switch tabs.
632
634
  In the agents and changes lists, arrows, <kbd>Home</kbd>, <kbd>End</kbd> and <kbd>Enter</kbd>; in the file tree, its own arrow keys and <kbd>Enter</kbd> to open.
633
635
  In the composer, <kbd>Enter</kbd> sends, <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a line and <kbd>Esc</kbd> stops a reply.
@@ -1151,17 +1153,15 @@ npm test
1151
1153
  ```
1152
1154
 
1153
1155
  `npm test` builds `dist/` and runs the integration tests in headless Chromium over raw CDP, through the [harness from slicc-shared-web](https://github.com/ai-ecoverse/slicc-shared-web#integration-test-harness), against a fake backend (`test/integration/page/fake-backend.js`).
1154
- It writes CPU profiles, screenshots and console logs to `artifacts/`, and V8 coverage of `dist/` to `coverage/` only with `SLICC_COVERAGE=1` (CI leaves it off, since nothing reads it; the unit tests' diff coverage is separate).
1156
+ It writes CPU profiles, screenshots and console logs to `artifacts/`, and V8 coverage of `dist/` to `coverage/` only with `SLICC_COVERAGE=1` (CI leaves it off, since nothing reads it).
1155
1157
  The test page is served cross-origin isolated (COOP/COEP), as slicc-kernel requires.
1156
1158
  `test/integration/kernel.test.mjs` runs `bash -i` end to end on `@ai-ecoverse/slicc-kernel` (a pinned dev dependency), with `@ai-ecoverse/wasm-bash` and `@ai-ecoverse/wasm-coreutils` installed into OPFS by the page (`/kernel.html`).
1157
1159
  `npm start` serves the test page on port 8080, and the UI at `/ui/`.
1158
1160
  `test/integration/kernel-ui.test.mjs` boots `<slicc-app>` on the kernel model (`/kernel-ui/`): a command in the terminal, its file in the tree, an edit in a file tab read back in the terminal, a second terminal, and a reload.
1159
1161
  `test/integration/ui.test.mjs` covers the shell, the layout (moving, closing, floating, reopening and reloading), streaming a reply with a tool call, stopping it, switching themes and the keyboard, and saves screenshots to `artifacts/ui/`.
1160
1162
 
1161
- The Biome, TypeScript, lefthook, Renovate and CI configuration comes from [slicc-shared-web](https://github.com/ai-ecoverse/slicc-shared-web), which also provides the `slicc-lint-comments`, `slicc-no-unit-tests` and `slicc-diff-cover` commands used by `npm run lint` and the pre-commit hook.
1162
-
1163
- Unit tests live in `test/unit/`, which is gitignored.
1164
- The pre-commit hook runs them in Node against happy-dom under monocart and fails the commit unless the staged lines in `src/` are fully covered (`slicc-diff-cover`, which runs `diff-cover --fail-under 100` and needs [uv](https://docs.astral.sh/uv/)).
1163
+ The Biome, TypeScript, lefthook, Renovate and CI configuration comes from [slicc-shared-web](https://github.com/ai-ecoverse/slicc-shared-web), which also provides the `slicc-lint`, `slicc-lint-comments` and `slicc-agents-md` commands used by `npm run lint` and the pre-commit hook.
1164
+ This repo turns off shared-web's `no unit tests in git` and `diff coverage` pre-commit jobs in `lefthook.yml`: every change comes with committed tests, normally integration tests in `test/integration/`.
1165
1165
 
1166
1166
  ## Design review
1167
1167
 
@@ -1279,6 +1279,26 @@ function colours() {
1279
1279
  { type: "text", text: "Printed it in **color**." }
1280
1280
  ];
1281
1281
  }
1282
+ var extendedOutput = [
1283
+ "cube \x1B[38;5;16m16\x1B[0m \x1B[38;5;21m21\x1B[0m \x1B[38;5;46m46\x1B[0m \x1B[38;5;196m196\x1B[0m \x1B[38;5;226m226\x1B[0m \x1B[38;5;231m231\x1B[0m \x1B[38;5;244m244\x1B[0m\n",
1284
+ "rgb \x1B[38;2;20;20;20mslate\x1B[0m \x1B[38;2;0;120;255mharbor\x1B[0m \x1B[38;2;255;140;0mbuoy\x1B[0m \x1B[38;2;240;240;240mfog\x1B[0m\n",
1285
+ "tint \x1B[48;5;231m 231 \x1B[0m \x1B[48;5;226m 226 \x1B[0m \x1B[48;5;16m 16 \x1B[0m \x1B[48;5;21m 21 \x1B[0m \x1B[48;2;255;255;0m beacon \x1B[0m \x1B[48;2;0;0;139m deep \x1B[0m\n",
1286
+ "both \x1B[38;5;226;48;5;231m flare \x1B[0m \x1B[38;2;20;20;20;48;2;255;255;0m pier \x1B[0m \x1B[7;38;5;196m alarm \x1B[0m\n"
1287
+ ].join("");
1288
+ function extendedColours() {
1289
+ return [
1290
+ {
1291
+ type: "tool",
1292
+ name: "bash",
1293
+ title: "Print 256 and truecolor",
1294
+ input: "./swatch --256 --truecolor",
1295
+ output: extendedOutput,
1296
+ paths: [],
1297
+ ticks: 20
1298
+ },
1299
+ { type: "text", text: "Printed the **256** and **truecolor** swatches." }
1300
+ ];
1301
+ }
1282
1302
  function edit() {
1283
1303
  return [
1284
1304
  {
@@ -1680,6 +1700,7 @@ function script(prompt, attachments = []) {
1680
1700
  if (/\b(ask|choose|decide)\b/.test(text)) return { steps: ask(), suggestion };
1681
1701
  if (/\b(debug|investigate)\b/.test(text)) return { steps: investigate(), suggestion };
1682
1702
  if (/\b(search|grep)\b/.test(text)) return { steps: search(), suggestion };
1703
+ if (/\b(256|truecolou?r)\b/.test(text)) return { steps: extendedColours(), suggestion };
1683
1704
  if (/\bcolou?rs?\b/.test(text)) return { steps: colours(), suggestion };
1684
1705
  if (/\btests?\b/.test(text)) return { steps: test(), suggestion };
1685
1706
  if (/\b(fix|edit|add|change)\b/.test(text)) return { steps: edit(), suggestion };