@ai-ecoverse/slicc-spectrum 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -280,15 +280,15 @@ Files dragged anywhere over the pane (not text, links or the dock's own drags) s
280
280
  A message's time shows only when it is at least two minutes newer than the last time shown, and the first one after each day separator always shows; a hidden time stays for screen readers (`time.sr` with `datetime`, or `.sr` on licks and cards), and a meta row left empty isn't rendered.
281
281
  User messages (with attachments and a quiet timestamp, `time.when`, by that rule; the reader's own carry no name or delivery tag, while `data-mode` and `data-delivered` still say how they went; a message from another cone, a follower or a guest says who sent it, and an agent's request carries its name and an Agent badge; a message from another agent, an agent's request or a message `from` a cone (`origin` `agent`, or `from` set without `origin` `follower` or `guest`), is `[data-remote]`: a subtle indigo bubble and a 🤖 pill on its bottom edge, `aria-hidden` since the byline names the sender; people, the reader included, never get it), assistant messages (with the time by that rule, and the model only on the first reply and whenever it changes from the previous one, `.meta .model` with the usage as its tooltip; without a model the usage is the time's tooltip, and with neither it is the reply's own (`.reply[title]`); the turn always carries the usage as its `aria-description`; the cone's name isn't repeated; Markdown with tables, task lists, quotes, code and images, fenced code highlighted like the Files view (below); thinking; tool calls, as the steps of the reply's response status (below); 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; an error with `action: 'login'` and an `account` (an `Account.id`) signs that account in: **Log in** calls `settings.connect(account)` synchronously in the click when the account is OAuth or needs no secret or fields, so a sign-in pop-up opens within the user gesture, and otherwise, or when `accounts()` doesn't have it, opens Settings at its row; the card follows the account's status from `accounts` (`data-login` is `idle`, `signing-in` or `connected`): while it is `signing-in` or `connect` is pending, **Log in** is pending and reads “Signing in…”, for an OAuth account the detail reads “Continue in the sign-in window that opened.” and, after `SliccChat.closedAfter` (20 s, since a closed window can't be detected), “Closed the sign-in window? Cancel, then Log in again.”, with **Cancel** (`data-action="cancel-login"`) when the port has `cancel`; once `connected`, the card is no longer an alert: a neutral info icon in the detail colour replaces the red one, the "Error: " prefix goes, the title reads “Signed in to {provider} again.” (the account's `provider`), the detail reads “Signed in. Retry to send it again.” (a polite status) and the button becomes **Retry**, which sends the last prompt again only when clicked; a rejected `connect` shows its message as negative help text (`[data-error=login]`), keeps **Log in** and adds a quiet **Open settings** (`data-action="settings"`) to that account; without an `account`, **Log in** opens Settings at Accounts, and watch-only and guest seats keep their gating; 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, 💬 Cone message, …; a channel spectrum does not know falls back to 📎 Notice) and the outcome (👍 Allowed, 👎 Denied, also said in the box's hidden text).
282
282
  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.
283
- 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").
283
+ 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 a human `title` when the agent sent one (without repeating the tool name), or with the tool name and a raw title when the title still looks like a command or path, `active` while it runs, `complete` when done and `stopped` when it failed or was cancelled, which its label says in words (" · Failed", " · Cancelled").
284
284
  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.
285
285
  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()`, and a chat that can't read them (outside the Spectrum theme, where it shows the colours as sent) tries again only when it reconnects or the theme changes; 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.
286
- 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.
287
- 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.
286
+ The status's header is always one line: while the reply streams or the agent works on the run, it is `active`, with the model's cluster label when one has arrived (or the last one for this run), else the running call's human title (or the last call), 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.
287
+ Done, the status stays as `complete`, also when a call never left `running` (the step stays `active`): one call reads as its human title, or the tool and a raw 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 (its label slot stays empty so Spectrum can show that).
288
288
  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.
289
289
  A label never shows what may be a secret: after a sensitive key (`token`, `secret`, `password`, `api_key`, `Authorization` and the like) with `=`, `:` or a flag's space, at a word that starts with a known secret prefix (`ghp_`, `sk-`, `AKIA`, `xoxb-`, `eyJ` and others), or, while the call runs, at a last word that could still grow into one, it ends in "…"; the step's description shows the call as the agent sent it.
290
290
  Spectrum notes: a step's description is at most 340 px wide (`.swc-ResponseStatusStep-detail` has no part or custom property for it), which is why a call opens in our own full-width region instead; a public hook for that width would let it use Spectrum's description. Two Spectrum behaviours are worked around: the header label is one line on a token line height (`--_swc-response-status-label-line-size` and `line-height: 0` on the status), because its cross-fade otherwise lays the label out 1.4 px off its settled place; and the label slot is never empty while active, because Spectrum then shows the running step's own label, which changes with every streamed chunk.
291
- The label for two or more calls comes from the agent port's optional `toolLabel(agentId, callIds)`, asked once for each agent port, agent and set of calls; while a growing run waits for its new label, it keeps its last one.
291
+ The label for two or more calls, and for a single call whose title still looks like a raw command, comes from the agent port's optional `toolLabel(agentId, callIds)`, asked once for each agent port, agent and set of calls while the run is active or done; while a growing run waits for its new label, it keeps its last one.
292
292
  Open licks, statuses and steps hold for every view of the chat on the same model, so a layout switch keeps them.
293
293
  A lick's `severity` (`warn` or `error`) adds an alert icon to its byline, a coloured edge to its box and a spoken prefix.
294
294
  A lick's optional `summary` (one plain line) replaces its `text` in the box and wraps instead of being cut, and its optional `report` (a file path) adds **Open the report** (`data-action="open-report"`, which fires `open-file` with the path) to the expanded lick, so a lick with only a `report` expands too.
@@ -358,7 +358,8 @@ Renders nothing without the port.
358
358
  The message box uses Spectrum Web Components 2.0.0-beta.6. Its explicit accessible names stay "Message" for the textarea, "Send" ("Steer" while busy) for send, "Add" for upload and "Stop" for stop, using `accessible-label`, `send-accessible-label`, `upload-accessible-label` and `stop-accessible-label`. Attachment navigation stays "Show previous attachments" / "Show more attachments", and the strip stays "Uploaded assets strip", through their `*-accessible-label` attributes.
359
359
  <kbd>Enter</kbd> sends, or steers a running reply: the message joins after the current tool round, without interrupting; <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>Enter</kbd> queues a follow-up that runs after the reply and can be withdrawn; <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a line; <kbd>Tab</kbd> takes the suggested follow-up; <kbd>↑</kbd>/<kbd>↓</kbd> at the start or end walk this agent's history; <kbd>Esc</kbd> stops.
360
360
  `/` completes commands (`/clear`, `/compact`, `/model`, `/thinking`, `/scoop`, `/stop`, `/freeze` when the port can freeze, `/theme`) and their arguments, `@` mentions agents and files.
361
- Attach from the computer, from SLICC's files, a browser screenshot or a shared secret (with `vault.enter` and `valueFrame`, the popup (`form.popup.secret`) takes only the name (`input[name=name]`): **Share** (`data-action="share-secret"`) attaches a name the vault already has at once, and for a new name opens `vault.enter({ name })` and shows the vault's own field (`slicc-vault-value`, `form.popup.secret[data-entry]`) in place of a value field, attaching the name on the frame's `done`; for a name the vault has, **Replace value** (`data-action="replace-secret"`) asks before it replaces the value and then opens `vault.enter({ name, replace: true })`; **Back** (`data-action="back-secret"`) cancels the request and goes back to the name, and **Cancel** (`data-action="cancel-secret"`), a press outside the form, Escape and the frame's `escape` cancel it and close the popup (Cancel is disabled and a press outside is ignored while a share is pending), and `enter`'s refusals, the frame's `error` and a `gone` frame ("The vault’s field timed out. Try again.") show inline; a locked vault unlocks in that field; while the vault is away it attaches the name only and opens no request, and a field already open stays through it; with `enter` it never shows a value input. Without `enter`, with a `vault.put`, the popup takes the value too, checks it like Settings › Secrets, puts it in the vault and attaches the name, showing errors inline and clearing the field; an empty value shares a name the vault already has, and a new value for one asks before it replaces it; while the vault is away (`availability()` `connecting` or `waiting`) or locked, it takes no value and says so; without one, it attaches the name and says to add the value in Settings › Secrets; the popup closes on Cancel (`data-action="cancel-secret"`, disabled while a share is pending), on a press outside the form (ignored while a share is pending) and on Escape, each clearing the typed value), or paste and drop files (25 MB each; a dropped folder, told apart by its drag entry, becomes a “Folders can’t be attached” chip, and a file that can't be read a “Could not read the file” chip, instead of an attachment).
361
+ Attach from the computer, from SLICC's files, a screenshot, optional **Record audio** / **Record video** when the model has a `capture` port (video only when `capture.kinds` includes `'video'`; `data-action="record-audio"` / `data-action="record-video"`), or a shared secret (with `vault.enter` and `valueFrame`, the popup (`form.popup.secret`) takes only the name (`input[name=name]`): **Share** (`data-action="share-secret"`) attaches a name the vault already has at once, and for a new name opens `vault.enter({ name })` and shows the vault's own field (`slicc-vault-value`, `form.popup.secret[data-entry]`) in place of a value field, attaching the name on the frame's `done`; for a name the vault has, **Replace value** (`data-action="replace-secret"`) asks before it replaces the value and then opens `vault.enter({ name, replace: true })`; **Back** (`data-action="back-secret"`) cancels the request and goes back to the name, and **Cancel** (`data-action="cancel-secret"`), a press outside the form, Escape and the frame's `escape` cancel it and close the popup (Cancel is disabled and a press outside is ignored while a share is pending), and `enter`'s refusals, the frame's `error` and a `gone` frame ("The vault’s field timed out. Try again.") show inline; a locked vault unlocks in that field; while the vault is away it attaches the name only and opens no request, and a field already open stays through it; with `enter` it never shows a value input. Without `enter`, with a `vault.put`, the popup takes the value too, checks it like Settings › Secrets, puts it in the vault and attaches the name, showing errors inline and clearing the field; an empty value shares a name the vault already has, and a new value for one asks before it replaces it; while the vault is away (`availability()` `connecting` or `waiting`) or locked, it takes no value and says so; without one, it attaches the name and says to add the value in Settings › Secrets; the popup closes on Cancel (`data-action="cancel-secret"`, disabled while a share is pending), on a press outside the form (ignored while a share is pending) and on Escape, each clearing the typed value), or paste and drop files (25 MB each; a dropped folder, told apart by its drag entry, becomes a “Folders can’t be attached” chip, and a file that can't be read a “Could not read the file” chip, instead of an attachment).
362
+ **Take a screenshot** (`value="screenshot"`) prefers `capture.still()` when present (a screen still through the capture port), else the active browser tab through `browser.screenshot`, and never fails silently: with neither a still method nor a usable tab it attaches an error chip ("No screen or browser tab to screenshot"); Chrome denial and other capture failures become error chips too. When `NotAllowedError` meets a matching Capture and devices switch that is off (`switches` keys `screen`, `camera`, `microphone`), the chip keeps the full reason (including Capture and devices) on its `title` tooltip and shows a short subtitle that still names Settings (for example "Microphone is off. Turn it on in Settings."); otherwise it shows the port's own `error.message`, then a generic fallback. Record items call `capture.record('audio'|'video')` inside the click; the live chip's Stop is the recording's `stop()`, `cancel()` discards, and a finished blob attaches like an upload (`kind` `file` / `image` as `addFiles` decides); `NotAllowedError` / `NotSupportedError` attach an error chip, and a user cancel (`AbortError`) attaches nothing. Error chips never go to the agent: `send` keeps only attachments without `error`, and a message that is only an error chip does not send.
362
363
  <kbd>Esc</kbd> in the `+` menu closes it, from any item, and puts focus back on `+`; it goes no further, so it doesn't also stop a reply.
363
364
  Queued messages wait above it in a dashed box (`--swc-neutral-visual-color`, 3:1 or more against the composer in both themes), to send now or drop; a steer the agent still holds (`mode: 'steer'`, `li.queued[data-mode=steer]`) reads "Sends at the next step" and can only be dropped.
364
365
  Model and thinking pickers.
@@ -1001,11 +1002,17 @@ Later backed by: BIOS.
1001
1002
  `items()` returns the `LiveItem`s, what is live in seven now (a recording, later an open serial port): `id`, `kind` (free text: `screen`, `camera`, `microphone`, later `serial`), `label` (such as "Recording screen"), `what` (may be empty), `asker`, `since` (ms) and `action` (`{ label }`, such as "Stop"); emit `items` when the list changes. `act(id)` runs the item's action.
1002
1003
  `<slicc-app>` shows `<slicc-live>` under the header when the port is there: nothing while `items()` is empty, else one chip per item, stacked (`[data-surface=live]`, each chip `[data-id]`): a red dot, then "{label} · {what} · {asker} · m:ss" (`what` left out when empty), ticking once a second from `since`, and a quiet button with `action.label` (`data-action="live-act"`) that calls `act(id)`. On phones (`compact`) a chip keeps only the dot, the label and the button.
1003
1004
 
1005
+ #### `capture` (optional)
1006
+
1007
+ Later backed by: BIOS (page modules behind the same Camera / Microphone / Screen switches and live chips as programmatic capture).
1008
+ A person's click in the composer is the intent: no agent consent and no click item; Chrome's own prompt still applies.
1009
+ `record(kind)` starts inside that click (`kind` `'audio'` or `'video'`) and resolves with a `Recording` (`stop()`, `cancel()`, `finished` resolving to `{ blob, mimeType, name, durationMs }`); it rejects `NotAllowedError` (denied or a switch off) or `NotSupportedError`. The live chip's Stop is the same as `stop()`; `cancel()` discards. Optional `kinds` lists what the port can record (`'audio'` | `'video'`); the composer shows **Record video** only when `'video'` is listed, and **Record audio** whenever the port is present. Optional `still()` takes a screen still (`{ blob, mimeType, name }`) for **Take a screenshot**, under the Screen switch and a short "Taking a photo" live chip. Attachments are made from the blob the same way as an upload. The dummy port (`createDummyModel({ capture: 'on' | 'audio' | 'deny' })`) returns fake media and drives `live` when that port is also on.
1010
+
1004
1011
  #### `switches` (optional)
1005
1012
 
1006
1013
  Later backed by: BIOS.
1007
1014
  `list()` returns the `Switch`es (`key`, `label`, `on`), in order; emit `switches` when they change. `set(key, on)` turns one on or off.
1008
- Settings shows them under "Capture and devices", one switch each (`[data-surface=switches]`, each `sp-switch[data-id={key}]`), with "Programs can capture only what’s on here. Turning one off stops what’s live under it."; without the port, or with an empty list, the section isn't there.
1015
+ Settings shows them under "Capture and devices", one switch each (`[data-surface=switches]`, each `sp-switch[data-id={key}]`), with "Programs and linked devices can use only what’s on here. Turning one off stops what’s live under it."; without the port, or with an empty list, the section isn't there.
1009
1016
 
1010
1017
  #### `vault` (optional)
1011
1018