@ai-ecoverse/slicc-spectrum 1.98.0 → 1.99.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
@@ -349,7 +349,11 @@ On a follower while the link reconnects, the field is disabled and says so; the
349
349
  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]`).
350
350
  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.
351
351
  A line that comes back closes an open `/` or `@` popup.
352
- 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; a page reload drops them.
352
+ 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.
353
+ 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.
354
+ Only a reload of the same tab brings them back (the navigation's type is `reload`); any other load, such as a duplicated tab that got a copy of the storage, clears them, so nothing is sent twice.
355
+ After a reload the rows come back in order with their text, and a second, muted line says "Not kept after reload: tides.csv" (`[data-lost]`), since attachments can't be restored; on arrival the text is sent without them.
356
+ A row that had only attachments shows an alert icon instead of the clock and reads "Not sent. Attach the files again." (`[data-unsent]`, with a **Dismiss** close button) instead of "Sent when the agent starts", isn't sent, and stays until it's dismissed; the "Not kept after reload" line starts with an alert icon too.
353
357
  Text typed but not sent while it starts is kept for the page the same way, and stays in the field once the agent arrives.
354
358
  While the agent holds tool results for the vault (`agent.hold()`), a status line above it says "Waiting for the vault" or "Unlock the vault to continue", with how many results are held, and offers the vault's **Unlock** button when locked and the model has a `vault`; if the browser blocks the vault window, the line says to allow pop-ups.
355
359
  With the model's `seat` set it's a guest's composer: <kbd>Enter</kbd> and the send button send through `agent.send(cone, text)`, <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a line and <kbd>↑</kbd>/<kbd>↓</kbd> walk the guest's own messages; there's no steer, queue, Stop, attachments (the field is `collapsed`, so its + is hidden and inert, and pasted files are ignored), `/` commands, `@` mentions, + menu or push to talk, and it never reads files; its description is "Enter sends, Shift+Enter adds a new line."
@@ -478,8 +482,10 @@ What agents remember, grouped by section: search, filter by scope and tag, expan
478
482
  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.
479
483
  The count (“N of M memories”) counts the memories in the picked scope.
480
484
  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.”
481
- 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"`).
482
- 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`).
485
+ 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.
486
+ 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.
487
+ 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”).
488
+ 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.
483
489
  Below 560 px of panel width, the search takes its own line over the two pickers.
484
490
  The search field is the shared one from `search.ts` (`sp-search[data-action=search]`), as in Files.
485
491
 
@@ -804,6 +810,11 @@ A row with `origin: 'user'` (ids such as `user:user:<name>`) goes into Your pack
804
810
  An installed pin reads "Pinned" with `0.24.0 · seven ships 0.25.0 · in /opt/agent` ("the version seven ships" when they match), and an addition reads "Added" with `^1.2.0 → 1.2.4 · in /opt/user`; `.meta[data-pin]` is `pinned` or `added`.
805
811
  A pin that is `removing` reads "Unpinning"; other states keep their usual lights.
806
812
  Offer `unpin` for pins and `remove` for additions.
813
+ Optional `installs` lists where a package is installed, each with its `version`, `where` (a folder such as `/home/cone/.local/share/pnpm`), an optional `user` and an optional `manager` (`pnpm` or `panel`).
814
+ A row with any install never offers `install`, nor `remove` unless one install's `manager` is `panel`, and one the port still reports as `available` reads Installed, or Update available when `offered` differs, with its first install's `version`.
815
+ Each install the panel doesn't own shows in the meta line as `[data-install]`, such as "for cone, via pnpm" or "in /opt/tools", with its version in front when it differs from the row's; when the panel's copy sits next to others it reads "the panel’s copy" (`[data-install="panel"]`) and Remove's accessible name is "Remove the panel’s copy of <label>", since it removes only that copy.
816
+ When no install is the panel's, `[data-managed]` under it reads "Managed by pnpm. Remove it with `pnpm remove -g <package>`." (the command in a `code` element; or "Installed outside this panel. Remove it where it was installed." for another manager).
817
+ Offer `update` for such a row to update it in place, for that user and with that manager, never as a second copy; never offer `remove` for it.
807
818
  Emit `packages` whenever they change.
808
819
  `actPackage(id, action)` keeps the row's button pending until it settles; it shows any confirm itself, resolves without a change when that confirm is cancelled, and rejects with a displayed error on a real failure.
809
820
  Hooks: `section[data-section="packages"]`, `li[data-id][data-state]`, buttons with `data-action`, `[data-requires]`, `[data-notes]` and `[data-error]`.
@@ -946,7 +957,7 @@ Pass only the surfaces a follower has to `<slicc-app>` (agents, chat, terminal a
946
957
  The dummy supports `createDummyModel({ updates: 'boot' | 'starting' | 'current' | 'available' | 'restart' | 'failure' })`, also selectable with `?updates=` on `/ui/`.
947
958
  Fixtures stay stable for inspection; `model.updates.setScenario('current')` completes boot.
948
959
  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.
949
- `createDummyModel({ packages: 'mixed' | 'empty' | 'fail' | 'user' | '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, and removing Python while uv is installed asks through the `confirm` option (the `/ui/` page passes spectrum's `confirm`).
960
+ `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`).
950
961
  `updateFixtures`, `packageFixtures` and `DummyUpdates` are exported from `/dummy`.
951
962
  `createDummyModel({ mounts: 'mount' | 'cancel' | 'fail' | 'needs' })` (or `?mounts=` on `/ui/`) turns on the optional mount members, which are off by default: `mountFolder` mounts invented files at `/mnt/photos`, resolves with `null`, or rejects, as `model.files.mount.scenario` says; `needs` also lists `/mnt/photos` in `needsFolder()` until a folder is inserted there.
952
963
  `createDummyModel({ network: 'ok' | 'limited' | 'failing' | 'off' })` (or `?network=` on `/ui/`, default `limited`) sets the dummy network: slicc on this computer as a linked device (`route: 'link'`, with browser automation through it), the page fetch with CORS failures, or no route, all invented; `off` leaves out the port.
@@ -3291,7 +3291,7 @@ var memories = [
3291
3291
  scope: "cone-harbor",
3292
3292
  section: "Conventions",
3293
3293
  title: "Cache keys",
3294
- body: "Cache keys are `city:UTC-date`. Never key on local time.",
3294
+ body: "Cache keys are `city:UTC-date`. Never key on local time.\n\nThe warmer fills the next day\u2019s keys at 23:00 UTC, so a key built from local time misses it and every request goes upstream until midnight. `npm run cache:check` lists the keys that don\u2019t match.",
3295
3295
  tag: "project",
3296
3296
  updatedAt: now - 2 * day4
3297
3297
  },
@@ -5131,6 +5131,24 @@ function packageFixtures(scenario) {
5131
5131
  actions: ["retry"],
5132
5132
  log: "Packages: +1\nERR_PNPM_FETCH_TIMEOUT Request timed out after 30000ms"
5133
5133
  });
5134
+ if (scenario === "elsewhere") {
5135
+ const cone = (version) => [
5136
+ { version, where: "/home/cone/.local/share/pnpm", user: "cone", manager: "pnpm" }
5137
+ ];
5138
+ patch("git", { state: "installed", version: "2.47.1", actions: [], installs: cone("2.47.1") });
5139
+ patch("tsc", {
5140
+ state: "outdated",
5141
+ version: "5.8.2",
5142
+ actions: ["update"],
5143
+ installs: cone("5.8.2")
5144
+ });
5145
+ patch("biome", {
5146
+ installs: [
5147
+ { version: "2.2.4", where: "/usr/local/share/pnpm", manager: "panel" },
5148
+ ...cone("2.2.4")
5149
+ ]
5150
+ });
5151
+ }
5134
5152
  return scenario === "user" ? [...items, ...userPackages()] : items;
5135
5153
  }
5136
5154
  var DummyUpdates = class extends Emitter {
@@ -5191,6 +5209,16 @@ var DummyUpdates = class extends Emitter {
5191
5209
  }
5192
5210
  this.#patchPackage(id, { state: "removing", error: null, actions: [] });
5193
5211
  await this.#clock.sleep(2);
5212
+ const kept = item.installs?.filter((install) => install.manager !== "panel") ?? [];
5213
+ if (kept.length) {
5214
+ this.#patchPackage(id, {
5215
+ state: "installed",
5216
+ version: kept[0].version,
5217
+ installs: kept,
5218
+ log: void 0
5219
+ });
5220
+ return;
5221
+ }
5194
5222
  this.#patchPackage(id, {
5195
5223
  state: "available",
5196
5224
  version: null,
@@ -5244,7 +5272,13 @@ ERR_PNPM_FETCH_TIMEOUT Request timed out after 30000ms`
5244
5272
  state: "installed",
5245
5273
  version: item.offered,
5246
5274
  progress: null,
5247
- actions: ["remove"],
5275
+ actions: item.installs ? [] : ["remove"],
5276
+ ...item.installs ? {
5277
+ installs: item.installs.map((install) => ({
5278
+ ...install,
5279
+ version: item.offered
5280
+ }))
5281
+ } : {},
5248
5282
  log: `${log}
5249
5283
  Progress: resolved 1, downloaded 1, added 1
5250
5284
  Done in 3.8s`