@ai-ecoverse/slicc-spectrum 1.99.2 → 1.100.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
@@ -270,6 +270,7 @@ When cones share a name, their accessible names and the Delete cone, Freezer and
270
270
  #### `<slicc-chat>`
271
271
 
272
272
  One thread's conversation (its `agent`, or the active agent if unset), by day.
273
+ Files dragged anywhere over the pane (not text, links or the dock's own drags) show Spectrum's drop zone over the whole pane (`swc-dropzone[data-surface=drop]`, in its dragged state: an accent border on an opaque accent-subtle fill, so the transcript doesn't show through), with an illustrated message: an attach icon, "Drop files to attach" and what it takes ("Images, text and other files up to 25 MB each join your next message. Folders can’t be attached."); a polite status (`[data-announce=drop]`) says "Drop to attach files to your message". The zone stays while the drag crosses into the composer or another child, and goes 100 ms after the drag leaves the pane (`SliccChat.leaveAfter`), on drop and on <kbd>Esc</kbd>. A drop anywhere on the pane attaches to the composer; while there is no composer (watch-only, frozen), on a guest seat, or while the composer waits to reconnect, the pane shows no zone and still consumes the file drag (`dropEffect` `none`), so a drop never opens the file in the tab.
273
274
  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.
274
275
  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; thinking; tool runs, one icon per run (`<slicc-tool-runs>`): three or more runs in a row form a cluster, a strip of icon buttons (`data-action="open-run"`, `data-target` the call's id, named by its `title` and status, `aria-expanded`) that each open one run's card below it, and on the right the model's label for the run, a button (`data-action="open-cluster"`, `aria-expanded`, named "Show all runs" while it has no text) that opens every card; the strip's tooltip and the group's accessible name sum it up, such as "3 commands, 1 read.
275
276
  Done"; prose breaks a run, hidden thinking and source links don't, and a standalone tool message or a done reply with only tool calls continues the run before it on the same day, its `data-id` moving onto its first card (`.tool[data-id]`); a single run is a strip of one, its icon and its `title` as the label, which opens with <kbd>Enter</kbd> or <kbd>Space</kbd> like the strip's buttons.
@@ -335,7 +336,7 @@ Renders nothing without the port.
335
336
  The message box.
336
337
  <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.
337
338
  `/` completes commands (`/clear`, `/compact`, `/model`, `/thinking`, `/scoop`, `/stop`, `/freeze` when the port can freeze, `/theme`) and their arguments, `@` mentions agents and files.
338
- Attach from the computer, from SLICC's files, a browser screenshot or a shared secret (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), or paste and drop files (25 MB each).
339
+ Attach from the computer, from SLICC's files, a browser screenshot or a shared secret (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), 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).
339
340
  <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.
340
341
  Queued messages wait above it, 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.
341
342
  Model and thinking pickers.
@@ -471,6 +472,8 @@ It closes, clearing the field, when the request leaves `waiting` or while the va
471
472
  #### `<slicc-updates>`
472
473
 
473
474
  Install / Update: component states, version changes, last checks, download and link counts, action buttons, failures with Retry, and collapsible install logs behind a quiet chevron, which stay open across a layout switch.
475
+ A row with a pending version change (`from → to`, or a package's `version → offered`) and release notes shows a What’s new disclosure after the row's actions (in package rows, after the command chips), next to the Install log, `details[data-releases]` with `summary[data-action="whats-new"]`, which stays open across a layout switch like the log. It lists every release after the installed version up to the new one, newest first, each as `.release[data-version]` with its version linking to the release page (`a[data-action="release-notes"]`, named "Kernel 1.13.0 release notes") and its notes rendered as markdown in strict mode (`markdown(text, { strict: true })`: raw HTML tags are dropped and their text kept as plain text, only `https:` links stay links, and an image becomes a link with its alt text, so nothing loads; the notes' headings sit one level under the release's, through `level`). Notes over 8 KB (8,192 characters) per release are cut at the last line break before that, with "…" and a Read the full notes link (`[data-cut]`, named "Read the full notes for Kernel 1.13.0"); a release whose `url` isn't `https:` shows its version as plain text. The `<!-- cert-verify -->` block is dropped, and a block that starts with "certified" shows as a subtle Certified badge (`[data-certified]`); a heading line naming the version is dropped too, since the link already shows it. Without notes in the range there is no disclosure.
476
+ An up-to-date row (no pending change) links its installed release with Release notes next to the version; an installed optional package without one links its npm page instead (`a[data-action="npm-page"]`, named "npm page for Biome 2.2.4"). Pins and additions in Your packages show no link. Every link opens in a new tab.
474
477
  An install shows one bar for update rows and package rows alike: it fills 0–50% while downloading and 50–100% while linking (`value` against `max-value="100"`). While the row runs it never goes back, not when pnpm's total grows and not when progress drops out between passes. While a download reports `bytes` with a total above 0, the first half fills by bytes and the value label reads "10.0 MB of 40.0 MB". Otherwise, and always while linking, the label falls back to the phase's "n of m" count. The bar starts at 0 again once the row settles.
475
478
  Opens at boot until the agent is ready without failures.
476
479
  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.
@@ -485,8 +488,8 @@ What agents remember, grouped by section: search, filter by scope and tag, expan
485
488
  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.
486
489
  The count (“N of M memories”) counts the memories in the picked scope.
487
490
  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.”
488
- Each memory is a row (`li.row[data-id]`, divided from the next by a rule) with one structure open or closed: the title line (`.head`, the disclosure button) keeps its chevron, title and marks where they are, and the text below it (`.content`) shows two lines closed and grows into the full text in place when the row opens, so opening only adds height below. It stays open across a layout switch. Open rows (`data-open`) take no fill, so nothing reads as selected; the chevron turns down. Height and chevron move like Spectrum's accordion (`--swc-animation-duration-100`, ease in and out), and not at all under `prefers-reduced-motion`. A click on a closed row's text opens it too.
489
- An open row ends in an action row at the trailing end: **Edit** and **Forget** (`data-action="edit"`, `data-action="forget"`), Forget in the negative content colour and asking first with the destructive confirm.
491
+ Each memory is a row (`li.row[data-id]`, divided from the next by one straight hairline, a square-ended `--swc-border-width-100` rule in the neutral border colour that spans the row, even where the row's hover fill is rounded) with one structure open or closed: the title line (`.head`, the disclosure button) keeps its chevron, title and marks where they are, and the text below it (`.content`) shows two whole lines closed (the clamp leaves room for one paragraph gap, so a second paragraph's first line is never half cut and doesn't move when the row opens) and grows into the full text in place when the row opens, so opening only adds height below. It stays open across a layout switch. Open rows (`data-open`) take no fill, so nothing reads as selected; the chevron turns down. Height and chevron move like Spectrum's accordion (`--swc-animation-duration-100`, ease in and out), and not at all under `prefers-reduced-motion`. A click on a closed row's text opens it too.
492
+ An open row ends in an action row: first its tag and scope in words next to their icons (`.meta [data-label=tag]`, `[data-label=scope]`, such as “Project” and “harbor only”), since touch has no tooltips, while a closed row shows only the icons; the open row hides its title-line tag and scope icons (`visibility: hidden`, so the title keeps its place) instead of showing them twice; then at the trailing end **Edit** and **Forget** (`data-action="edit"`, `data-action="forget"`), Forget in the negative content colour and asking first with the destructive confirm.
490
493
  At the end of the title line, small icons (`.mark`, `role="img"` with an `aria-label` and a tooltip) carry the metadata: the tag (`.tag[data-tag]`: User a file with a person, Feedback a comment, Project a briefcase), “From MEMORY.md” for free text outside an entry (`.from`), and under Everyone the scope (`.scope[data-scope]`: Shared a group of people, a cone a person, a role a person with a gear, labelled “Shared” or “{name} only”).
491
494
  The tag is left out where the list already says it: under a section heading that names it (Projects, User, Feedback) and while the tag filter picks it.
492
495
  Below 560 px of panel width, the search takes its own line over the two pickers.
@@ -806,6 +809,7 @@ Use `queued` for a row that waits for another component before it starts; it rea
806
809
  Use `starting` for an installed row that is only starting up: it reads "Starting" without a checked line, and the header shows a neutral "Starting" only when nothing is failed, updating or ready.
807
810
  A `failed` row with an installed `from` version reads "Update failed".
808
811
  `act(id, action)` resolves when dispatched or rejects with a displayed error; actions are `retry`, `update-now`, `restart-agent` and `reload`.
812
+ A row's and a package's optional `releases` (`UpdateRelease[]`) lists the GitHub releases the embedder knows for it, each with its `version`, the release page `url` and optional `notes` (the release body, semantic-release markdown as GitHub returns it). Send every release after the installed version up to the new one, so the panel can show the whole range, plus the installed one for its link; spectrum orders them by version and never fetches them itself. Leave it out, or leave out `notes`, when there's nothing to show.
809
813
  Missing ports preserve existing adapters and report disconnected information in the panel.
810
814
  Optional `packages()` returns `PackageItem` rows for optional tools, each with a short catalog `id`, its npm `package` (shown in the name's tooltip and at the top of its Install log), `label`, a one-sentence `description`, the `commands` it provides, `requires` (other package ids, read as "Uses Python" while it's installed, or "Installs Python too" on a row that isn't installed yet; an installed row leaves out a requirement that isn't installed, since its warning says so), optional `notes` (short plain-text lines shown muted under the row, such as "1 untested dependency: …"; leave it out when there's nothing to say), optional `warnings` (lines with an alert icon, `data-warnings`, such as "Needs Python, which isn't installed.
811
815
  Install Python again to use it."; the dummy adds that one when a required package is removed), `state` (`available`, `queued`, `installing`, `installed`, `outdated`, `updating`, `removing` or `failed`), the installed `version`, the `offered` version and its `size` in bytes, `progress` (`InstallProgress`, or `null` for an indeterminate bar), `error`, `actions` (`install`, `update`, `remove`, `retry`, `unpin`) and an optional `log`.
@@ -959,6 +963,7 @@ Pass only the surfaces a follower has to `<slicc-app>` (agents, chat, terminal a
959
963
 
960
964
  The dummy supports `createDummyModel({ updates: 'boot' | 'starting' | 'current' | 'available' | 'restart' | 'failure' })`, also selectable with `?updates=` on `/ui/`.
961
965
  Fixtures stay stable for inspection; `model.updates.setScenario('current')` completes boot.
966
+ The dummy's kernel offers three releases from 1.12.0 to 1.13.0, two of them certified, the agent one release to 0.25.0, and the syntax grammars only their installed release; its uv package offers two releases, Python links its release and the other installed packages their npm pages.
962
967
  Dummy Update now and Retry simulate download and link progress, and a dummy package install reports half its `size` in bytes on the way; Restart agent and Reload only change fixture state, never restart a real process or reload the browser.
963
968
  `createDummyModel({ packages: 'mixed' | 'empty' | 'fail' | 'user' | 'elsewhere' | 'off' })` (or `?packages=` on `/ui/`, off by default) adds invented optional packages in every state: Install and Retry finish after a short wait and install missing requirements too, `fail` makes them fail, `user` adds a pinned agent-kit and two additions (one with a warning) that Unpin and Remove take out of the list, `elsewhere` has git installed for cone with pnpm and TypeScript there at an older version, whose Update keeps it in place, and Biome both from the panel and for cone, whose Remove leaves cone's copy, and removing Python while uv is installed asks through the `confirm` option (the `/ui/` page passes spectrum's `confirm`).
964
969
  `updateFixtures`, `packageFixtures` and `DummyUpdates` are exported from `/dummy`.
@@ -4944,6 +4944,65 @@ var DummyTray = class extends Emitter {
4944
4944
 
4945
4945
  // src/dummy/updates.ts
4946
4946
  var checkedAt = Date.UTC(2026, 9, 8, 8, 42);
4947
+ var tag = (repo, version, notes2) => ({
4948
+ version,
4949
+ url: `https://github.com/harbor-demo/${repo}/releases/tag/v${version}`,
4950
+ ...notes2 ? { notes: notes2 } : {}
4951
+ });
4952
+ var certified = (name2, version) => `
4953
+
4954
+ <!-- cert-verify -->
4955
+ certified @harbor/${name2}@${version} sha256=0f3c9a1e (covers ${version}; downstream: PASS)
4956
+ <!-- /cert-verify -->
4957
+ `;
4958
+ var notes = (repo, version, sections) => `# [${version}](https://github.com/harbor-demo/${repo}/compare/v${version}) (2026-10-07)
4959
+
4960
+ ${sections}`;
4961
+ var releaseFixtures = {
4962
+ kernel: [
4963
+ tag(
4964
+ "harbor-kernel",
4965
+ "1.13.0",
4966
+ notes(
4967
+ "harbor-kernel",
4968
+ "1.13.0",
4969
+ "### Features\n\n* **fs:** watch a folder and get one event per batch of changes\n* **jobs:** `wait -n` returns the first job that finishes"
4970
+ ) + certified("harbor-kernel", "1.13.0")
4971
+ ),
4972
+ tag(
4973
+ "harbor-kernel",
4974
+ "1.12.2",
4975
+ notes(
4976
+ "harbor-kernel",
4977
+ "1.12.2",
4978
+ "### Bug Fixes\n\n* **net:** a slow DNS answer no longer stalls the next request"
4979
+ ) + certified("harbor-kernel", "1.12.2")
4980
+ ),
4981
+ tag(
4982
+ "harbor-kernel",
4983
+ "1.12.1",
4984
+ notes(
4985
+ "harbor-kernel",
4986
+ "1.12.1",
4987
+ "### Bug Fixes\n\n* **tty:** resizing a terminal mid-line keeps the cursor on its column"
4988
+ )
4989
+ ),
4990
+ tag("harbor-kernel", "1.12.0")
4991
+ ],
4992
+ agent: [
4993
+ tag(
4994
+ "harbor-agent",
4995
+ "0.25.0",
4996
+ notes(
4997
+ "harbor-agent",
4998
+ "0.25.0",
4999
+ "### Features\n\n* **tools:** the agent can read a tide table from a CSV file\n\n### Bug Fixes\n\n* **chat:** a long answer keeps its code blocks intact when it is cut"
5000
+ )
5001
+ ),
5002
+ tag("harbor-agent", "0.24.0")
5003
+ ],
5004
+ grammars: [tag("harbor-grammars", "4.5.0")]
5005
+ };
4947
5006
  function updateFixtures(scenario) {
4948
5007
  const components = [
4949
5008
  ["bios", "BIOS packages", "0.8.2"],
@@ -4963,7 +5022,8 @@ function updateFixtures(scenario) {
4963
5022
  to: version,
4964
5023
  checkedAt,
4965
5024
  error: null,
4966
- actions: []
5025
+ actions: [],
5026
+ ...releaseFixtures[kind] ? { releases: releaseFixtures[kind] } : {}
4967
5027
  }));
4968
5028
  const agent = items[2];
4969
5029
  if (scenario === "boot") {
@@ -5118,7 +5178,28 @@ function packageFixtures(scenario) {
5118
5178
  notes: ["1 untested dependency: @harbor/wasi-sockets@0.4.2-1"],
5119
5179
  actions: ["remove"]
5120
5180
  });
5121
- patch("uv", { state: "outdated", version: "0.8.1", actions: ["update", "remove"] });
5181
+ patch("python", {
5182
+ releases: [
5183
+ { version: "3.13.1", url: "https://github.com/harbor-demo/python-wasm/releases/tag/v3.13.1" }
5184
+ ]
5185
+ });
5186
+ patch("uv", {
5187
+ state: "outdated",
5188
+ version: "0.8.1",
5189
+ actions: ["update", "remove"],
5190
+ releases: [
5191
+ {
5192
+ version: "0.9.2",
5193
+ url: "https://github.com/harbor-demo/uv-wasm/releases/tag/v0.9.2",
5194
+ notes: "## 0.9.2\n\n### Bug Fixes\n\n* `uv run` finds the project in a parent folder again"
5195
+ },
5196
+ {
5197
+ version: "0.9.0",
5198
+ url: "https://github.com/harbor-demo/uv-wasm/releases/tag/v0.9.0",
5199
+ notes: "## 0.9.0\n\n### Features\n\n* `uv add` keeps the comments in `pyproject.toml`"
5200
+ }
5201
+ ]
5202
+ });
5122
5203
  patch("esbuild", {
5123
5204
  state: "installing",
5124
5205
  actions: [],