@ai-ecoverse/slicc-spectrum 1.101.2 → 1.102.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
@@ -272,24 +272,25 @@ When cones share a name, their accessible names and the Delete cone, Freezer and
272
272
  One thread's conversation (its `agent`, or the active agent if unset), by day.
273
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.
274
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.
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.
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.
277
- A strip and its cards share one width, the column less a wide margin on each side, so they read as centred, and their edges line up.
278
- Icons fill from the start of a space kept for five, so a run that grows doesn't move its strip or its label; past five, the strip shows the newest five and scrolls back to the older ones, with <kbd>Tab</kbd> or a swipe, and returns to the newest when a run is added or the strip comes back into view.
279
- The label sits at the end and is cut with an ellipsis before it reaches that space.
280
- Under 480 px of column width the label takes a row of its own under the icons, which then show as many whole icons as fit.
281
- A cluster's label comes from the agent port's optional `toolLabel(agentId, callIds)`, asked once for each agent port, agent and set of runs; while a growing run waits for its new label, it keeps its last one, and without `toolLabel` the label is empty.
282
- A command's icon is the favicon of the site it names when an open browser tab already has a `data:` favicon for it (nothing is fetched; otherwise the globe), else the file browser's icon for the file it names, else the code icon; other tools show their kind's icon.
283
- 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.
284
- 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, 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, 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; 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, …) and the outcome (👍 Allowed, 👎 Denied, also said in the box's hidden text).
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 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, …) and the outcome (👍 Allowed, 👎 Denied, also said in the box's hidden text).
285
276
  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.
286
- Open licks and open tool runs hold for every view of the chat on the same model, so a layout switch keeps them.
277
+ 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
+ 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
+ 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
+ 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
+ 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.
283
+ 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.
284
+ 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.
285
+ 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.
286
+ Open licks, statuses and steps hold for every view of the chat on the same model, so a layout switch keeps them.
287
287
  A lick's `severity` (`warn` or `error`) adds an alert icon to its byline, a coloured edge to its box and a spoken prefix.
288
288
  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.
289
289
  A `scoop-notify` lick never shows the agent's bracketed status line: a `text` that is `[scoop … completed]`, `failed` or `stopped` (or `[@… completed]`) reads "Scoop {name} finished", "Scoop {name} failed" or "Scoop {name} stopped", the name being its `title` without the role in brackets, a failed or stopped one takes the `error` tone and a ❌ pill, named and announced as Scoop failed or Scoop stopped, instead of ✅, and its body, without that line, renders as markdown (`.report .text`), its headings stepped down to the chat's `####` size so the card doesn't outshout the chat.
290
- 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.
290
+ 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 by 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.
291
+ A request's command (its `body`, `pre.command`) is never cut: it wraps in full, in monospace, open or closed. When it runs past four lines (measured as rendered), the card shows the first four, a subdued "Show the full command to allow it." (`[data-allow-hint]`) and a quiet **Show the full command** with a chevron (`data-action="full-command"`, `data-shown` on it while shown, its `aria-expanded` on Spectrum's inner button, then **Hide the full command**), and has no **Allow** until the whole command shows; Deny and the countdown always stay. Showing it scrolls the whole card into the region when it fits, else its actions. A shown command stays shown for every view of the chat while the request waits; guests and timed-out requests show it whole.
291
292
  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.
292
- While pending, cards leave the log for their own region between the header and the log (`section.asks`, named "Waiting for you"), so they never cover the transcript and the log ends below them; the log keeps an empty marker where each was asked (`.ask-place[data-place]`, the card's `data-id`). The region shows the newest card; with more than one waiting, a bar above it (**N waiting**, `data-action="show-waiting"`, `aria-expanded`) shows them all, oldest first (`.asks[data-open]`), and shows the countdown of the soonest timed card it hides. A hidden card stays mounted (`.ask[hidden]`), so a typed answer survives, and a new ask never hides the card that has focus: the list opens instead. Showing another agent closes the list and its details. The region is opaque, with a hairline and a soft shadow on its bottom edge. Open, each card is compact: its title line and its actions, the request's text and its command each cut to one line, the command still in monospace so nobody allows what they can't see, and the rest behind a quiet chevron (**Show details**, `data-action="ask-detail"`, `data-detail` on the card while shown). The region takes at most half the chat's height and always leaves the log room for the composer and its fade (and a few lines more while closed); when the cards need more, it scrolls inside, the bar stays on top, a fade at the bottom edge (`.asks[data-more]`) says more is below, and the scrollbar shows on hover and focus. Every card is a tab stop before its actions, and focusing anything in a card scrolls the whole card into the region.
293
+ While pending, cards leave the log for their own region between the header and the log (`section.asks`, named "Waiting for you"), so they never cover the transcript and the log ends below them; the log keeps an empty marker where each was asked (`.ask-place[data-place]`, the card's `data-id`). The region shows the newest card; with more than one waiting, a bar above it (**N waiting**, `data-action="show-waiting"`, `aria-expanded`) shows them all, oldest first (`.asks[data-open]`), and shows the countdown of the soonest timed card it hides. A hidden card stays mounted (`.ask[hidden]`), so a typed answer survives, and a new ask never hides the card that has focus: the list opens instead. Showing another agent closes the list and its details. The region is opaque, with a hairline and a soft shadow on its bottom edge. Open, each card is compact: its title line, its command and its actions, the request's text cut to one line and the rest of it behind a quiet chevron (**Show details**, `data-action="ask-detail"`, `data-detail` on the card while shown). The region takes at most half the chat's height and always leaves the log room for the composer and its fade (and a few lines more while closed); when the cards need more, it scrolls inside, the bar stays on top, a fade at the bottom edge (`.asks[data-more]`) says more is below, and the scrollbar shows on hover and focus. Every card is a tab stop before its actions, and focusing anything in a card scrolls the whole card into the region.
293
294
  Clicking a waiting card (not its controls), or <kbd>Enter</kbd> on it, scrolls the log to where it was asked, at the bottom of the view above the composer.
294
295
  When a card leaves the region (answered, timed out or decided elsewhere) while it has focus, focus moves to the newest card still waiting, else the composer; a timed-out card goes back to its place in the log.
295
296
  Under `prefers-reduced-motion`, nothing animates and the scroll is instant.
@@ -320,6 +321,7 @@ The model's `notices` as in-line alerts with their actions and a close button (n
320
321
  The model's waiting `approvals` as a modal alert dialog, one at a time, oldest first; `<slicc-app>` mounts it.
321
322
  Renders nothing without `approvals.decide`.
322
323
  A request that `secretRules()` flags shows a warning (`[data-secret-rules]`, the path or token) and no **Always allow (**Always allow in this directory**, with the cwd in its hint, when the approval has `alwaysScope: 'cwd'` and a `cwd`)**.
324
+ The command (`[data-command]`, or a guest tool call's `[data-summary]`) wraps in full; past four lines the dialog shows the first four and **Show the full command** (as in the chat, `data-action="full-command"` with `data-shown`), and shown, it scrolls inside its own box of at most `min(16lh, 50dvh)`. Always allow, its hint and Allow once wait until the end of the command has been in view (a zero-size `[data-end]` after its last line), and so does the element's `decide()` for anything but `deny`; once seen, the end stays seen while the request waits, and hiding the command again hides them again. Until then a subdued line (`[data-allow-hint]`) says "Show the full command to allow it." or, shown, "Scroll to the end of the command to allow it." The dialog keeps one width, so only its height changes. A closed request shows its command whole.
323
325
  Focus starts on Deny (on Close once `decide` rejects) and goes back, after Deny, Always allow, Allow once, <kbd>Esc</kbd> or Close, to what had it when the dialog opened; inside a terminal, to that `<slicc-terminal>` through its own `focus()`, even when it remounted meanwhile.
324
326
  Guest requests (`guest-message`, `guest-tool`) get their own copy, the guest's text as plain text (`[data-guest-text]`), attachments (`[data-attachments]`), the automatic check's verdict (`[data-verdict]`), and Deny and Allow once, plus **Always allow** (`data-action="always"`) with a hint saying what it covers when the approval's `always` is `true`; the dialog body carries `[data-approval-kind]` and fills the dialog's width at every size.
325
327
 
@@ -475,6 +477,7 @@ It closes, clearing the field, when the request leaves `waiting` or while the va
475
477
 
476
478
  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.
477
479
  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"). Only the newest (`.release[data-newest]`) shows its notes; each older release is a collapsed header, `details.release` with `summary[data-action="release"]` holding the same chevron, its version link and badge across the full row and named "Kernel 1.12.2 notes, certified", that opens to its notes indented under its title and stays open across a layout switch like the disclosure (an older release without notes is a plain header). The notes are 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.
480
+ Certified is shown only for ai-ecoverse releases (a `url` of `https://github.com/ai-ecoverse/<repo>/releases/…`) whose cert block names the same package and version (`certified <pkg>@<version>`; the package is checked on package rows, which know their npm name), and any other cert block is still dropped without a badge.
478
481
  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.
479
482
  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.
480
483
  Opens at boot until the agent is ready without failures.
@@ -727,8 +730,8 @@ The optional `importProfile(file, { preview, again? })` takes a SLICC 6 profile
727
730
  `importCancel()` stops it, and `importing()` returns a `ProfileImportProgress` (`phase`: `idle`, `checking`, `writing`, `done` or `failed`, with `done`, `total` and `text`), with an `importing` event; the UI never sees kernel paths, so the adapter decides how the file reaches the agent.
728
731
  Names don't have to be unique, and an optional `Agent.title` names a cone's conversation; without it, the first user message does.
729
732
  Assistant messages stream: the same message is re-emitted as its parts grow and its tool calls go from `running` to `done`.
730
- The optional `toolLabel(agentId, callIds)` resolves with a short label for a cluster of tool runs (`callIds` in order), such as "Compare the docs with the live API", or `null`; the agent dedupes, caches and persists it.
731
- Spectrum asks once a cluster forms and again each time it grows, once per set of ids, and shows the label at the end of the strip.
733
+ The optional `toolLabel(agentId, callIds)` resolves with a short label for a run of tool calls (`callIds` in order), such as "Compare the docs with the live API", or `null`; the agent dedupes, caches and persists it.
734
+ Spectrum asks once a reply's status has two calls and again each time it grows, once per set of ids, and shows the label once the status is complete.
732
735
  The optional `readOnly()` returns a line, or `null`, with a `readOnly` event when it changes: while it's a non-empty string, such as when this follower runs a different major version from its owner, every surface is watch-only just as a follower without Control is (no composer, no cone or conversation actions, no pickers, no Stop, no Accept or Revert in Changes, inline sprinkles view only, no model settling), and the line takes the place of the follow-based watch-only note under the chat.
733
736
  The optional `starting()` returns a line, or `null`, with a `starting` event when it changes: while it's a non-empty string, there's no agent yet but one is on its way (such as while seven installs its first agent, or replaces one), the chat drops its empty state and the composer queues what's sent until an agent is there (see `<slicc-composer>`); without it, or at `null`, nothing changes.
734
737
 
@@ -916,8 +919,8 @@ When a request ends without a decision in this tab, emit `ended` with `{ id, rea
916
919
  Without `ended`, a request that leaves the list reads as expired past `expiresAt` and answered before it.
917
920
  Without `decide`, each request is a warning notice in the chat panels: "Waiting for sudo approval", who asks and the command, and "It waits for the owner's approval.
918
921
  Denied automatically at {time}."
919
- A guest request has `kind` `guest-message` (`text`, optional `attachments` of `{ name, mimeType, size }`) or `guest-tool` (`tool`, `summary`), plus `requester` (`kind` `guest`), `agentId`, optional `agentName`, `createdAt`, `expiresAt`, `always` (offer Always allow, a policy default the owner can change) and an optional `verdict` (`{ decision: 'allow' | 'deny' | 'unsure', reason }`, the automatic check's view).
920
- Its dialog (`[data-approval-kind]` on the body) reads "Allow a guest’s message?" with "{name} wants to send this to {agentName ?? 'this cone'}:", the text as plain text in a scrolling box (`[data-guest-text]`, never Markdown or HTML) and the attachments as name · type · size (`[data-attachments]`), or "Allow a guest’s tool call?" with "{agentName ?? 'This cone'} wants to run {tool} for {name}:" and the summary (`[data-summary]`); then "The automatic check would allow this: {reason}", "…deny this: {reason}" or "The automatic check wasn’t sure: {reason}" (`[data-verdict]`, the decision in the attribute).
922
+ A guest request has `kind` `guest-message` (`text`, optional `attachments` of `{ name, mimeType, size }`) or `guest-tool` (`tool`, `summary`, optional `args`, the call's arguments as text, which the embedder pretty-prints, and `argsTruncated`, `true` when only a prefix of them came), plus `requester` (`kind` `guest`), `agentId`, optional `agentName`, `createdAt`, `expiresAt`, `always` (offer Always allow, a policy default the owner can change) and an optional `verdict` (`{ decision: 'allow' | 'deny' | 'unsure', reason }`, the automatic check's view).
923
+ Its dialog (`[data-approval-kind]` on the body) reads "Allow a guest’s message?" with "{name} wants to send this to {agentName ?? 'this cone'}:", the text as plain text in a scrolling box (`[data-guest-text]`, never Markdown or HTML) and the attachments as name · type · size (`[data-attachments]`), or "Allow a guest’s tool call?" with "{agentName ?? 'This cone'} wants to run {tool} for {name}:" and the summary (`[data-summary]`); when the summary is blank, the block shows the tool's name on its first line and then `args` instead, under the same four-line and end-of-command rules, and with no `args` either, "This request has no details." (`[data-id="no-details"]`) and Allow as usual; with a blank summary and `argsTruncated`, the dialog never offers Allow once or Always allow and `decide()` takes only `deny`, saying "This request is too long to show in full, so it can’t be allowed." (`[data-allow-hint]`) while the args still show; then "The automatic check would allow this: {reason}", "…deny this: {reason}" or "The automatic check wasn’t sure: {reason}" (`[data-verdict]`, the decision in the attribute).
921
924
  It offers **Deny** and **Allow once**, and, when `always` is `true`, **Always allow** (`always`, which calls `decide(id, 'always')`) with the hint "Always allow lets {name} send messages to {agentName ?? 'this cone'} without asking again." or "Always allow lets {agentName ?? 'this cone'} run exactly this {tool} call for {name} without asking again.".
922
925
  `decide` gets no `reason` from the UI; a rejected `decide` shows its message inline (`[data-error]`) with only **Close**, as for sudo.
923
926
  Ended guest requests read "Answered elsewhere", "Guest message timed out" or "Guest tool call timed out".
@@ -1032,8 +1035,9 @@ The dummy's `docs` and `tickets` MCP accounts have a `url`, the dummy vault reco
1032
1035
  `createDummyModel({ monitor: 'agent' })` (`?monitor=agent` on `/ui/`) adds the agent's Tasks (a tree by `depth`), Processes and Recent problems sections to the monitor, and its Running vital.
1033
1036
  Like slicc-agent's snapshot, the dummy's vitals are the budget, Spend, Active agents, Processes and Process memory (both with a `series`) and Fullest context.
1034
1037
 
1035
- `createDummyModel({ approvals: 'agent' | 'user' | 'many' | 'follower' | 'fail' | 'soon' | 'elsewhere' | 'withdrawn' | 'secrets' | 'guest' | 'guest-follower' | 'guest-always' })` (`?approvals=` on `/ui/`) adds waiting sudo requests: one from an agent, one from a terminal user, three in a row (the last as `www-data`), one without `decide`, one whose `decide` fails, one that expires in 24 seconds, or two whose first is answered in another tab or withdrawn after a few seconds, or one from an agent that copies a file over `/etc/fnox/config.toml`, or (`guest`) three guest requests: a message from Seat 2 (Mara) with attachments and an allow verdict, a tool call with a deny verdict, and a message whose `decide` rejects with "Someone else already answered this."
1036
- (`guest-follower`: the same without `decide`), or (`guest-always`) one guest tool call from Seat 2 (Mara) to `read_file` with `always: true`.
1038
+ `createDummyModel({ approvals: 'agent' | 'user' | 'many' | 'follower' | 'fail' | 'soon' | 'elsewhere' | 'withdrawn' | 'secrets' | 'guest' | 'guest-follower' | 'guest-always' | 'long' | 'guest-args' | 'guest-empty' | 'guest-truncated' })` (`?approvals=` on `/ui/`) adds waiting sudo requests: one from an agent, one from a terminal user, three in a row (the last as `www-data`), one without `decide`, one whose `decide` fails, one that expires in 24 seconds, or two whose first is answered in another tab or withdrawn after a few seconds, or one from an agent that copies a file over `/etc/fnox/config.toml`, or (`guest`) three guest requests: a message from Seat 2 (Mara) with attachments and an allow verdict, a tool call with a deny verdict, and a message whose `decide` rejects with "Someone else already answered this."
1039
+ (`guest-follower`: the same without `decide`), or (`guest-always`) one guest tool call from Seat 2 (Mara) to `read_file` with `always: true`, or (`long`) one sudo request whose seven-line command ends in `curl … | sh`, or one guest `write_file` call with a blank `summary`: with seven lines of `args` ending in the same tail (`guest-args`), with no `args` (`guest-empty`), or with a prefix of them and `argsTruncated` (`guest-truncated`).
1040
+ `createDummyModel({ asks: 'long' })` (`?asks=long`) adds a pending sudo request with that seven-line command to kitchen-sink (`k-long`).
1037
1041
  Decisions are recorded in `model.approvals.decisions`, and `model.approvals.end(id, reason)` ends a request.
1038
1042
 
1039
1043
  `createDummyModel({ vault: 'empty' | 'secrets' | 'policy' | 'locked' | 'request' | 'backup' | 'waiting' | 'purged' | 'endpoints-fail' | 'off' })` (`?vault=` on `/ui/`, off by default; `notice` is kept as another name for `policy`) adds an invented vault: no secrets yet; five secrets (an API key, a jerk lease from pier-nuc revealed to `pier publish`, a Tide Mail sign-in, one without a rule and a removed one) with an activity log that pages back once; the same with a refused rule and a policy change in the log; locked before the first unlock, with a waiting request from docs-pass; unlocked with a `fnox set` request for `TIDE_STATION_TOKEN`; the secrets with a due backup reminder; or a vault that hasn't answered yet (`model.vault.arrive()` brings it); Cloudflare's Account ID and AI Gateway ID and Azure's endpoint carry `vaultSetting`s; the dummy vault keeps `settings` on its records, logs each `settings` call in `model.vault.settingsCalls`, and refuses a setting whose value starts with `bad` (“The vault refused {KEY}. Check that value and try again.”). `endpoints-fail` is the secrets with an `endpoints` that refuses (an MCP URL with “The vault refused {url} for this token. Check the server's address, then try again.”, a model URL with “The vault refused that endpoint. Check the address and try again.”). The dummy vault records each `endpoints` change in `model.vault.endpointChanges`.
@@ -1080,16 +1084,17 @@ Each section is its own port, so an embedder can mix real and dummy per section,
1080
1084
  `<slicc-file-view>` has **Edit**: the file opens in a plain text area, and **Save** or `Mod+S` writes it through `files.write`; `Escape` cancels.
1081
1085
 
1082
1086
  The `kitchen-sink` cone holds every kind of message, content and lick in one conversation, for design work and screenshots.
1083
- Its clusters carry invented labels, which the dummy's `toolLabel` answers after a short pause, keyed by the title of the cluster's first call; one is long enough to be cut.
1087
+ Its runs of tool calls carry invented labels, which the dummy's `toolLabel` answers after a short pause, keyed by the title of the run's first call; one is long enough to be cut.
1084
1088
  Each reply to it is paced to take about 20 seconds, so its streaming states can be looked at.
1085
1089
  A prompt that says search or grep runs a search.
1086
- Its tool turn has two clusters and a standalone run with URL, file and plain commands in every state, and two dummy browser tabs carry invented `data:` favicons.
1090
+ Its tool turn has two runs and a standalone tool message with URL, file and plain commands in every state, and two dummy browser tabs carry invented `data:` favicons.
1087
1091
  The dummy's fixtures are invented: a small forecast API called harbor, with cones, scoops, a conversation per agent, pending changes (one of them binary, without a diff), browser tabs and accounts.
1088
1092
  The harbor cone ends with three `scoop-notify` licks: amber-heron's, finished with a `summary`, a markdown body and a `report` at `/shared/scoop-notifications/amber-heron.md`; grey-tern's, failed, with no summary; and salt-gull's, only the legacy bracketed line.
1089
1093
  Its only sprinkles are SLICC's own: `welcome` (the onboarding wizard, as a dip in the sliccy cone) and `suggestions`, copied from `slicc` (`packages/vfs-root/shared/sprinkles/`, commit `aa29784`) with their comments stripped, as is the sprinkle theme in `src/app/sprinkle-theme.css`.
1090
1094
  `suggestions` reads its stream from the invented `/home/.gelatiere/suggestions.json` through the bridge; there is no `/home/.welcomed`, so `welcome` starts its wizard.
1091
- Its replies are scripted by keyword (debug or investigate, tests, fix or add, open or docs, files, anything else), and their tool calls act on the other ports: an edit writes a file and shows up as a change, a browse opens a tab.
1092
- Debugging runs seven commands in a row, so its cluster grows past five while it streams.
1095
+ Its replies are scripted by keyword (replay, debug or investigate, tests, fix or add, open or docs, files, anything else), and their tool calls act on the other ports: an edit writes a file and shows up as a change, a browse opens a tab.
1096
+ Debugging runs seven commands in a row in one reply, so its status grows a step at a time while it streams.
1097
+ Replay plays a longer run across ten replies, with long commands whose arguments stream in and tool-only replies in a row, for checking that past messages never move down; `?replay` on the UI test page starts it on load.
1093
1098
 
1094
1099
  ### Distribution
1095
1100
 
@@ -720,6 +720,28 @@ function events() {
720
720
  }
721
721
  ];
722
722
  }
723
+ var longCommand = [
724
+ "cd /workspace/harbor && \\",
725
+ " npm ci --no-audit --no-fund && \\",
726
+ " npm run lint && \\",
727
+ " npm run build && \\",
728
+ " npm test -- --reporter=dot && \\",
729
+ ' git tag -a v1.9.0 -m "Release 1.9.0" && \\',
730
+ " curl https://example.com/x | sh"
731
+ ].join("\n");
732
+ function longAsk(now = Date.now()) {
733
+ return {
734
+ id: "k-long",
735
+ role: "lick",
736
+ channel: "sudo-request",
737
+ title: "quiet-otter",
738
+ text: "Wants to test, tag and publish 1.9.0",
739
+ body: longCommand,
740
+ state: "pending",
741
+ createdAt: now,
742
+ expiresAt: now + 10 * 6e4
743
+ };
744
+ }
723
745
  function showcase() {
724
746
  return [...opening(), ...runs(), ...work(), ...events()];
725
747
  }
@@ -1927,6 +1949,8 @@ var DummySettings = class extends Emitter {
1927
1949
  };
1928
1950
 
1929
1951
  export {
1952
+ longCommand,
1953
+ longAsk,
1930
1954
  clock,
1931
1955
  files,
1932
1956
  directories,
@@ -1949,4 +1973,4 @@ export {
1949
1973
  dummySettingsKey,
1950
1974
  DummySettings
1951
1975
  };
1952
- //# sourceMappingURL=chunk-LOQJK2JE.js.map
1976
+ //# sourceMappingURL=chunk-3IV5AAUZ.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/dummy/showcase.ts", "../src/dummy/fixtures.ts", "../src/dummy/providers.ts", "../src/dummy/clock.ts", "../src/dummy/settings.ts"],
4
+ "sourcesContent": ["import type { Agent, LickChannel, Message, ToolCall, UserMessage } from '../model/types.ts';\n\nconst start = Date.UTC(2026, 9, 4, 16, 0);\nconst at = (minutes: number) => start + minutes * 60_000;\n\nexport function picture(\n label: string,\n from: string,\n to: string,\n width = 640,\n height = 400\n): string {\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\"><defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"${from}\"/><stop offset=\"1\" stop-color=\"${to}\"/></linearGradient></defs><rect width=\"${width}\" height=\"${height}\" fill=\"url(#g)\"/><text x=\"50%\" y=\"50%\" font-family=\"sans-serif\" font-size=\"${Math.round(height / 9)}\" fill=\"#ffffff\" text-anchor=\"middle\" dominant-baseline=\"middle\">${label}</text></svg>`;\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;\n}\n\nexport function tone(seconds = 0.6, frequency = 440, rate = 8000): string {\n const samples = Math.round(seconds * rate);\n const bytes = new Uint8Array(44 + samples);\n const view = new DataView(bytes.buffer);\n const text = (offset: number, value: string) => {\n for (let i = 0; i < value.length; i++) bytes[offset + i] = value.charCodeAt(i);\n };\n text(0, 'RIFF');\n view.setUint32(4, 36 + samples, true);\n text(8, 'WAVEfmt ');\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, 1, true);\n view.setUint32(24, rate, true);\n view.setUint32(28, rate, true);\n view.setUint16(32, 1, true);\n view.setUint16(34, 8, true);\n text(36, 'data');\n view.setUint32(40, samples, true);\n for (let i = 0; i < samples; i++) {\n const fade = Math.min(1, (samples - i) / (rate / 10));\n bytes[44 + i] = 128 + Math.round(60 * fade * Math.sin((2 * Math.PI * frequency * i) / rate));\n }\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return `data:audio/wav;base64,${btoa(binary)}`;\n}\n\nfunction tool(\n id: string,\n name: string,\n title: string,\n input: string,\n output: string,\n extra: Partial<ToolCall> = {}\n): ToolCall {\n return { id, name, title, input, output, status: 'done', paths: [], ...extra };\n}\n\nconst markdown = [\n '## The forecast API in one page',\n '',\n 'harbor answers `GET /forecast?city=\u2026` with the day\u2019s **high**, **low** and a *short summary*, and caches per city for an hour. ~~XML output~~ is gone.',\n '',\n '### How a request flows',\n '',\n '1. The worker parses the city.',\n '2. The cache answers if it has a fresh entry:',\n ' - same UTC day',\n ' - younger than one hour',\n '3. Otherwise the upstream call runs, with three retries.',\n '',\n '> Upstream is slow at the top of the hour. Retries back off at 250, 500 and 1000 ms.',\n '',\n '```ts',\n 'export async function forecast(city: string): Promise<Forecast> {',\n ' const cached = cache.get(city);',\n ' if (cached) return cached;',\n ' return cache.set(city, await retry(() => upstream(city)));',\n '}',\n '```',\n '',\n '| Route | Cache | Typical latency |',\n '| --- | --- | ---: |',\n '| `/forecast` | 1 hour, per city | 38 ms |',\n '| `/health` | none | 2 ms |',\n '| `/forecast` (miss) | \u2014 | 410 ms |',\n '',\n '- [x] TTL fix merged',\n '- [ ] Move the cache to KV',\n '',\n 'Details are in the [API reference](https://api.example.com/docs/v2/forecast). A long path that must wrap: `/workspace/harbor/node_modules/.cache/wrangler/state/v3/cache/miniflare-CacheObject/7c1f0e3b9a5d4e2f8b6a1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f.sqlite`.',\n].join('\\n');\n\nconst toolShapes: ToolCall[] = [\n tool('k-t1', 'bash', 'Count the routes', \"rg -c 'pathname ===' src\", 'src/index.ts:2'),\n tool(\n 'k-t2',\n 'read_file',\n 'Read the router',\n '/workspace/harbor/src/index.ts',\n \"import { forecast } from './routes/forecast.ts';\\n\u2026\",\n {\n paths: ['/workspace/harbor/src/index.ts'],\n }\n ),\n tool(\n 'k-t3',\n 'write_file',\n 'Create the KV binding notes',\n '/workspace/harbor/docs/kv.md',\n 'Wrote 18 lines',\n {\n paths: ['/workspace/harbor/docs/kv.md'],\n }\n ),\n tool(\n 'k-t4',\n 'edit_file',\n 'Rename the cache key',\n '/workspace/harbor/src/lib/cache.ts',\n 'No match for \"cityKey(\" in src/lib/cache.ts',\n {\n status: 'error',\n paths: ['/workspace/harbor/src/lib/cache.ts'],\n }\n ),\n tool(\n 'k-t5',\n 'grep',\n 'Find TODOs',\n 'TODO --glob \"src/**\"',\n 'src/routes/forecast.ts:14: TODO: cache negative results\\nsrc/lib/units.ts:3: TODO: round half to even'\n ),\n tool(\n 'k-t6',\n 'web_fetch',\n 'Fetch the API changelog',\n 'https://api.example.com/changelog.json',\n '{ \"latest\": \"2.4.1\", \"breaking\": false }'\n ),\n tool(\n 'k-t7',\n 'browser',\n 'Screenshot the preview',\n 'screenshot http://localhost:8787/',\n 'Captured 1280\u00D7800',\n {\n image: picture('localhost:8787', '#3b63fb', '#0a7a43', 640, 400),\n }\n ),\n tool(\n 'k-t8',\n 'scoop_scoop',\n 'Start a scoop for the docs',\n 'name: docs-pass\\ntask: Update the forecast page to Celsius',\n 'Scoop docs-pass is running'\n ),\n tool(\n 'k-t9',\n 'feed_scoop',\n 'Hand the screenshots to docs-pass',\n 'scoop_name: docs-pass\\nmessage: Use the new screenshots in /tmp/shots',\n 'Delivered'\n ),\n tool(\n 'k-t10',\n 'send_message',\n 'Tell quiet-otter the tests pass',\n 'to: quiet-otter\\nmessage: CI is green, merge when ready',\n 'Delivered'\n ),\n tool(\n 'k-t11',\n 'drop_scoop',\n 'Wrap up amber-heron',\n 'scoop_name: amber-heron',\n 'Dropped amber-heron; its notes are in /shared/notes'\n ),\n tool(\n 'k-t12',\n 'update_global_memory',\n 'Remember the cache rule',\n 'Cache keys are per city and per UTC day.',\n 'Memory updated (3 sections, 412 characters)'\n ),\n tool(\n 'k-mcp',\n 'mcp__docs__search',\n 'docs \u00B7 search',\n '{\\n \"query\": \"forecast units\"\\n}',\n '2 pages: /forecast, /units'\n ),\n tool('k-t13', 'bash', 'Deploy to staging', 'wrangler deploy --env staging', 'Stopped', {\n status: 'cancelled',\n }),\n tool('k-t14', 'bash', 'Watch the logs', 'wrangler tail --env staging', '', { status: 'running' }),\n tool(\n 'k-t16',\n 'bash',\n 'Check the staging routes',\n 'wrangler routes list --env staging',\n '\\x1b[1mROUTE ZONE WORKER ENV\\x1b[0m\\nforecast.harbor.example/v2/forecast/* harbor.example \\x1b[36mharbor-forecast-v2\\x1b[0m \\x1b[2mstaging\\x1b[0m\\n\\x1b[33mwarning:\\x1b[0m the zone \\x1b[1mharbor.example\\x1b[0m has \\x1b[37m2\\x1b[0m routes on an old plan\\n\\x1b[1;31merror:\\x1b[0m the route forecast.harbor.example/v2/units/* belongs to another account; ask its owner to release it first',\n {\n status: 'error',\n notes: [\n { severity: 'error', text: 'Exited with code 5' },\n {\n severity: 'warn',\n text: 'Output truncated: 12 lines and 1,840 bytes dropped from the start',\n },\n { severity: 'info', text: 'Full output in /tmp/pi-bash-7f3a.log' },\n ],\n }\n ),\n];\n\nconst licks: Array<[LickChannel, string, string, string | undefined, Partial<Message>]> = [\n [\n 'webhook',\n 'GitHub \u00B7 pull_request.opened',\n 'example/harbor#58 Add retries for upstream timeouts',\n '{\\n \"action\": \"opened\",\\n \"number\": 58,\\n \"repository\": { \"full_name\": \"example/harbor\" }\\n}',\n {},\n ],\n [\n 'cron',\n 'Every weekday 09:00',\n 'Morning summary for the harbor cone',\n undefined,\n { count: 3 } as Partial<Message>,\n ],\n [\n 'sprinkle',\n 'Release board',\n 'Button \u201CShip 1.9.0\u201D clicked',\n '{ \"button\": \"ship\", \"version\": \"1.9.0\" }',\n {},\n ],\n [\n 'fswatch',\n '/workspace/harbor/src',\n '2 files changed',\n 'modified /workspace/harbor/src/lib/cache.ts\\ncreated /workspace/harbor/src/lib/retry.ts',\n {},\n ],\n [\n 'session-reload',\n 'Session restored',\n 'The page reloaded; 4 cones resumed from storage',\n undefined,\n {},\n ],\n [\n 'navigate',\n 'api.example.com',\n 'A page offered a SLICC handoff: open the forecast docs',\n '{ \"verb\": \"open\", \"target\": \"https://api.example.com/docs/v2/forecast\" }',\n {},\n ],\n [\n 'discovery',\n 'api.example.com',\n 'Found an ai-catalog.json with 3 tools',\n 'https://api.example.com/.well-known/ai-catalog.json',\n {},\n ],\n ['upgrade', 'SLICC updated', '6.4.0 \u2192 6.5.0', undefined, {}],\n [\n 'workflow',\n 'release-notes',\n 'Step 2 of 4 finished: collect merged pull requests',\n undefined,\n {},\n ],\n ['bash', 'Job 3', 'npm run build exited with status 0 after 41 s', undefined, {}],\n ['jshd', 'collect.jsh', 'Script finished: 12 pull requests since v1.8.0', undefined, {}],\n ['preview', 'Preview bridge', 'Connected from localhost:8787', undefined, {}],\n [\n 'cherry',\n 'Host page',\n 'Event \u201Ccart-updated\u201D from shop.example.com',\n '{ \"items\": 3, \"total\": 42.5 }',\n {},\n ],\n ['scoop-notify', 'docs-pass', 'Finished: the forecast page now shows Celsius', undefined, {}],\n ['scoop-idle', 'amber-heron', 'Idle for 30 minutes', undefined, {}],\n ['scoop-wait', 'quiet-otter', 'The wait for CI resolved: all checks passed', undefined, {}],\n [\n 'sudo-request',\n 'docs-pass',\n 'Wants to push to example/harbor (branch docs/celsius)',\n 'git push origin docs/celsius',\n { state: 'pending', expiresAt: Date.now() + 10 * 60_000 } as Partial<Message>,\n ],\n [\n 'sudo-request',\n 'quiet-otter',\n 'Wants to read secrets: UPSTREAM_TOKEN',\n undefined,\n { state: 'confirmed' } as Partial<Message>,\n ],\n [\n 'sudo-request',\n 'amber-heron',\n 'Wants to run: rm -rf /workspace/harbor/node_modules',\n undefined,\n { state: 'dismissed' } as Partial<Message>,\n ],\n];\n\nconst attachmentsMessage: UserMessage = {\n id: 'k-u2',\n role: 'user',\n text: 'Here is the mockup, my notes and the old spec.',\n createdAt: at(4),\n attachments: [\n {\n id: 'k-a1',\n name: 'forecast-card.png',\n kind: 'image',\n mimeType: 'image/png',\n size: 48211,\n url: picture('Mockup', '#f5a623', '#d0021b', 480, 320),\n },\n {\n id: 'k-a2',\n name: 'notes.txt',\n kind: 'text',\n mimeType: 'text/plain',\n size: 214,\n text: 'Show \u00B0C first.\\nRound to whole degrees.\\nKeep the summary under 60 characters.',\n },\n {\n id: 'k-a3',\n name: 'spec-v1.pdf',\n kind: 'file',\n mimeType: 'application/pdf',\n size: 1_204_331,\n path: '/home/user/downloads/spec-v1.pdf',\n },\n {\n id: 'k-a4',\n name: 'UPSTREAM_TOKEN',\n kind: 'secret',\n mimeType: 'application/octet-stream',\n size: 0,\n },\n {\n id: 'k-a5',\n name: 'recording.mov',\n kind: 'file',\n mimeType: 'video/quicktime',\n size: 98_304_000,\n error: 'Too large: attachments are limited to 25 MB',\n },\n ],\n};\n\nexport const showcaseAgent: Agent = {\n id: 'cone-kitchen',\n name: 'kitchen-sink',\n kind: 'cone',\n parentId: null,\n status: 'idle',\n model: 'claude-opus-5-5',\n contextFill: 0.47,\n unread: 0,\n};\n\nfunction opening(): Message[] {\n return [\n {\n id: 'k-u1',\n role: 'user',\n text: 'Give me the full tour of harbor, everything you can show.',\n createdAt: at(0),\n },\n {\n id: 'k-m1',\n role: 'assistant',\n status: 'done',\n createdAt: at(1),\n model: 'claude-sonnet-5-5',\n usage: { input: 18_204, output: 912, cost: 0.31 },\n parts: [\n {\n type: 'thinking',\n text: 'Start with the shape of the API, then show the pieces one kind at a time.',\n },\n { type: 'text', text: markdown },\n ],\n },\n attachmentsMessage,\n {\n id: 'k-m2',\n role: 'assistant',\n status: 'done',\n createdAt: at(5),\n model: 'claude-sonnet-5-5',\n parts: [\n {\n type: 'text',\n text: 'Mockup, notes and spec received. The recording was too large to attach. Here are the current screens and the alert sound:',\n },\n {\n type: 'media',\n items: [\n {\n kind: 'image',\n src: picture('Forecast card', '#3b63fb', '#7a5af8'),\n alt: 'The forecast card in light mode',\n },\n {\n kind: 'image',\n src: picture('Dark card', '#1d1d1d', '#3b63fb'),\n alt: 'The forecast card in dark mode',\n },\n {\n kind: 'image',\n src: picture('Phone', '#0a7a43', '#12b886', 360, 640),\n alt: 'The forecast card on a phone',\n },\n {\n kind: 'video',\n src: '',\n poster: picture('\u25B6 Walkthrough', '#292929', '#717171'),\n alt: 'A walkthrough of the forecast page',\n },\n { kind: 'audio', src: tone(), alt: 'The storm alert sound' },\n ],\n },\n ],\n },\n { id: 'k-u3', role: 'user', text: 'Show me every tool you used.', createdAt: at(8) },\n {\n id: 'k-m3',\n role: 'assistant',\n status: 'done',\n createdAt: at(9),\n model: 'claude-sonnet-5-5',\n parts: [\n { type: 'text', text: 'Every tool from today\u2019s run, in order:' },\n ...toolShapes.map((call) => ({ type: 'tool' as const, tool: call })),\n ],\n },\n {\n id: 'k-tool1',\n role: 'tool',\n createdAt: at(12),\n tool: tool(\n 'k-t15',\n 'bash',\n 'You ran a command',\n 'git log --oneline -3',\n 'a1b2c3d fix: expire entries from the previous day\\ne4f5a6b feat: retry upstream timeouts\\n0c9d8e7 chore: update wrangler'\n ),\n },\n ];\n}\n\nfunction runs(): Message[] {\n return [\n {\n id: 'k-u6',\n role: 'user',\n text: 'Get the forecast docs ready for the Celsius release.',\n createdAt: at(13),\n },\n {\n id: 'k-m8',\n role: 'assistant',\n status: 'done',\n createdAt: at(13.1),\n model: 'claude-sonnet-5-5',\n parts: [\n { type: 'text', text: 'Checking what the docs and the API say today.' },\n ...[\n tool(\n 'k-r1',\n 'bash',\n 'Ask the API for Lisbon',\n 'curl -s https://api.example.com/v2/forecast?city=Lisbon',\n '{ \"city\": \"Lisbon\", \"high\": 71, \"low\": 58, \"unit\": \"F\" }'\n ),\n tool(\n 'k-r2',\n 'bash',\n 'Read the forecast page',\n 'cat /workspace/harbor/docs/forecast.md',\n '# Forecast\\n\\nTemperatures are in Fahrenheit.'\n ),\n tool('k-r3', 'bash', 'See what changed', 'git status --short', ' M src/lib/units.ts'),\n tool(\n 'k-r4',\n 'read_file',\n 'Read the units helper',\n '/workspace/harbor/src/lib/units.ts',\n 'export function toCelsius(f: number): number {\u2026}',\n { paths: ['/workspace/harbor/src/lib/units.ts'] }\n ),\n ].map((call) => ({ type: 'tool' as const, tool: call })),\n {\n type: 'text',\n text: 'The page still says Fahrenheit. Updating it, then building and testing.',\n },\n ...[\n tool(\n 'k-r5',\n 'edit_file',\n 'Switch the page to Celsius',\n '/workspace/harbor/docs/forecast.md',\n 'Edited 1 line',\n {\n paths: ['/workspace/harbor/docs/forecast.md'],\n diff: {\n before: '# Forecast\\n\\nTemperatures are in Fahrenheit.\\n',\n after: '# Forecast\\n\\nTemperatures are in Celsius.\\n',\n },\n }\n ),\n tool('k-r6', 'bash', 'Build the site', 'npm run build', 'Built 14 pages in 2.1s', {\n meta: 'timeout 120s',\n }),\n tool(\n 'k-r7',\n 'bash',\n 'Run the unit tests',\n 'npx vitest run src/lib/units.test.ts',\n 'FAIL src/lib/units.test.ts > rounds half to even\\nExpected 22, received 21',\n {\n status: 'error',\n notes: [{ severity: 'error', text: 'Exited with code 1' }],\n }\n ),\n tool(\n 'k-r8',\n 'bash',\n 'Open the release pull request',\n 'gh pr create --repo https://git.example.com/example/harbor --title \"Celsius docs\"',\n 'Stopped before the tests pass',\n { status: 'cancelled' }\n ),\n tool('k-r9', 'bash', 'Watch the preview logs', 'wrangler tail --env preview', '', {\n status: 'running',\n }),\n ].map((call) => ({ type: 'tool' as const, tool: call })),\n {\n type: 'text',\n text: 'One test fails on rounding, so the pull request waits for the fix.',\n },\n ],\n },\n {\n id: 'k-tool2',\n role: 'tool',\n createdAt: at(13.5),\n tool: tool(\n 'k-r10',\n 'bash',\n 'Check the preview port',\n 'lsof -i :8787',\n 'workerd 4120 harbor 12u IPv4 TCP localhost:8787 (LISTEN)'\n ),\n },\n ];\n}\n\nfunction work(): Message[] {\n return [\n {\n id: 'k-m4',\n role: 'assistant',\n status: 'done',\n createdAt: at(14),\n model: 'claude-sonnet-5-5',\n parts: [\n { type: 'text', text: 'Here is where things stand.' },\n { type: 'sprinkle', sprinkle: 'status' },\n {\n type: 'delegation',\n kind: 'scoop',\n scoop: 'docs-pass',\n text: 'Started a scoop to update the docs',\n },\n {\n type: 'delegation',\n kind: 'feed',\n scoop: 'docs-pass',\n text: 'Handed over the new screenshots',\n },\n {\n type: 'delegation',\n kind: 'sprinkle',\n scoop: 'suggestions',\n text: 'Opened the suggestions sprinkle',\n },\n { type: 'delegation', kind: 'drop', scoop: 'amber-heron', text: 'Wrapped up amber-heron' },\n ],\n },\n {\n id: 'k-m5',\n role: 'assistant',\n status: 'done',\n createdAt: at(18),\n model: 'claude-sonnet-5-5',\n parts: [\n { type: 'text', text: 'Three decisions from earlier:' },\n {\n type: 'question',\n question: {\n id: 'k-q1',\n kind: 'yes-no',\n question: 'Tag 1.9.0 after the merge?',\n options: [],\n state: 'answered',\n answer: 'Yes',\n },\n },\n {\n type: 'question',\n question: {\n id: 'k-q2',\n kind: 'text',\n question: 'What should the release be called?',\n options: [],\n state: 'inert',\n },\n },\n {\n type: 'question',\n question: {\n id: 'k-q3',\n kind: 'choice',\n question: 'Where should the cache live?',\n options: ['Keep it in memory', 'Move it to KV', 'Decide after the load test'],\n state: 'open',\n },\n },\n ],\n },\n ];\n}\n\nfunction events(): Message[] {\n return [\n {\n id: 'k-s1',\n role: 'system',\n kind: 'compaction',\n title: 'Context compacted',\n text: '58 earlier messages were summarized.',\n trigger: 'threshold',\n state: 'summarized',\n createdAt: at(1440),\n },\n {\n id: 'k-s2',\n role: 'system',\n kind: 'compaction',\n title: 'Compaction failed, transcript truncated',\n text: 'The summary failed, so the oldest 20 messages were dropped instead.',\n trigger: 'overflow',\n state: 'fallback',\n createdAt: at(1441),\n },\n ...licks.map(\n ([channel, title, text, body, extra], index): Message =>\n ({\n id: `k-l${index + 1}`,\n role: 'lick',\n channel,\n title,\n text,\n createdAt: at(1445 + index),\n ...(body ? { body } : {}),\n ...extra,\n }) as Message\n ),\n {\n id: 'k-u4',\n role: 'user',\n text: 'Actually, stop the deploy, staging is frozen today.',\n mode: 'steer',\n createdAt: at(1470),\n },\n {\n id: 'k-m6',\n role: 'assistant',\n status: 'stopped',\n createdAt: at(1470),\n model: 'claude-haiku-4-5',\n parts: [{ type: 'text', text: 'Stopping the staging deploy and leaving' }],\n },\n {\n id: 'k-u5',\n role: 'user',\n text: 'Update the forecast page to Celsius and use the new screenshots.',\n from: 'harbor',\n createdAt: at(1472),\n },\n {\n id: 'k-m7',\n role: 'assistant',\n status: 'error',\n createdAt: at(1475),\n model: 'claude-haiku-4-5',\n parts: [\n {\n type: 'thinking',\n text: 'The model rejected the request because the context is too large.',\n },\n {\n type: 'error',\n message: 'The request is too large for this model.',\n detail: 'The model returned 413: the request is larger than its context window.',\n action: 'change-model',\n },\n ],\n },\n {\n id: 'k-s3',\n role: 'system',\n kind: 'error',\n title: 'docs-pass failed',\n text: 'The Adobe session expired. Log in again to continue.',\n action: 'login',\n account: 'ai-adobe',\n createdAt: at(1476),\n },\n {\n id: 'k-s4',\n role: 'system',\n kind: 'error',\n title: 'Rate limited',\n text: 'Anthropic answered 429. Retrying in 30 seconds.',\n action: 'retry',\n createdAt: at(1477),\n },\n {\n id: 'k-s5',\n role: 'system',\n kind: 'notice',\n title: 'Model changed',\n text: 'to Claude Opus 5.5 (Anthropic)',\n createdAt: at(1478),\n },\n ];\n}\n\nexport const longCommand = [\n 'cd /workspace/harbor && \\\\',\n ' npm ci --no-audit --no-fund && \\\\',\n ' npm run lint && \\\\',\n ' npm run build && \\\\',\n ' npm test -- --reporter=dot && \\\\',\n ' git tag -a v1.9.0 -m \"Release 1.9.0\" && \\\\',\n ' curl https://example.com/x | sh',\n].join('\\n');\n\nexport function longAsk(now = Date.now()): Message {\n return {\n id: 'k-long',\n role: 'lick',\n channel: 'sudo-request',\n title: 'quiet-otter',\n text: 'Wants to test, tag and publish 1.9.0',\n body: longCommand,\n state: 'pending',\n createdAt: now,\n expiresAt: now + 10 * 60_000,\n };\n}\n\nexport function showcase(): Message[] {\n return [...opening(), ...runs(), ...work(), ...events()];\n}\n\nexport function showcaseQueue(): UserMessage[] {\n return [\n {\n id: 'k-q-1',\n role: 'user',\n text: 'Then open a pull request for the docs.',\n createdAt: at(1480),\n queued: true,\n mode: 'queue',\n },\n {\n id: 'k-q-2',\n role: 'user',\n text: 'And post the link in the release channel.',\n createdAt: at(1481),\n queued: true,\n mode: 'queue',\n },\n ];\n}\n", "import type {\n Account,\n Agent,\n BrowserTab,\n Change,\n Message,\n ModelOption,\n Settings,\n TerminalInfo,\n UserMessage,\n} from '../model/types.ts';\nimport { showcase, showcaseAgent, showcaseQueue } from './showcase.ts';\n\nconst cacheBefore = `export interface Entry<T> {\n value: T;\n storedAt: number;\n}\n\nconst TTL = 60 * 60 * 1000;\n\nexport class ForecastCache<T> {\n #entries = new Map<string, Entry<T>>();\n\n get(key: string, now = Date.now()): T | undefined {\n const entry = this.#entries.get(key);\n if (!entry) return undefined;\n const day = new Date(entry.storedAt).getDate();\n if (day !== new Date(now).getDate()) return entry.value;\n if (now - entry.storedAt > TTL) return undefined;\n return entry.value;\n }\n\n set(key: string, value: T, now = Date.now()): void {\n this.#entries.set(key, { value, storedAt: now });\n }\n}\n`;\n\nconst cacheAfter = `export interface Entry<T> {\n value: T;\n storedAt: number;\n}\n\nconst TTL = 60 * 60 * 1000;\n\nexport class ForecastCache<T> {\n #entries = new Map<string, Entry<T>>();\n\n get(key: string, now = Date.now()): T | undefined {\n const entry = this.#entries.get(key);\n if (!entry) return undefined;\n if (dayOf(entry.storedAt) !== dayOf(now)) {\n this.#entries.delete(key);\n return undefined;\n }\n if (now - entry.storedAt > TTL) return undefined;\n return entry.value;\n }\n\n set(key: string, value: T, now = Date.now()): void {\n this.#entries.set(key, { value, storedAt: now });\n }\n}\n\nfunction dayOf(time: number): string {\n return new Date(time).toISOString().slice(0, 10);\n}\n`;\n\nconst retry = `export async function retry<T>(task: () => Promise<T>, attempts = 3, wait = 250): Promise<T> {\n let last: unknown;\n for (let attempt = 0; attempt < attempts; attempt++) {\n try {\n return await task();\n } catch (error) {\n last = error;\n await new Promise((resolve) => setTimeout(resolve, wait * 2 ** attempt));\n }\n }\n throw last;\n}\n`;\n\nconst legacyXml = `export function toXml(forecast: { city: string; high: number; low: number }): string {\n return \\`<forecast city=\"\\${forecast.city}\"><high>\\${forecast.high}</high><low>\\${forecast.low}</low></forecast>\\`;\n}\n`;\n\nconst forecastBefore = `import { ForecastCache } from '../lib/cache.ts';\nimport { toCelsius } from '../lib/units.ts';\n\nconst cache = new ForecastCache<Forecast>();\n\nexport interface Forecast {\n city: string;\n high: number;\n low: number;\n summary: string;\n}\n\nexport async function forecast(city: string, upstream: typeof fetch = fetch): Promise<Forecast> {\n const cached = cache.get(city);\n if (cached) return cached;\n const response = await upstream(\\`https://api.example.com/v2/forecast?city=\\${encodeURIComponent(city)}\\`);\n const body = await response.json();\n const result = {\n city,\n high: toCelsius(body.daily.max),\n low: toCelsius(body.daily.min),\n summary: body.daily.summary,\n };\n cache.set(city, result);\n return result;\n}\n`;\n\nconst forecastAfter = forecastBefore\n .replace(\n \"import { toCelsius } from '../lib/units.ts';\",\n \"import { retry } from '../lib/retry.ts';\\nimport { toCelsius } from '../lib/units.ts';\"\n )\n .replace('const response = await upstream(', 'const response = await retry(() =>\\n upstream(')\n .replace('(city)}`);', '(city)}`)\\n );');\n\nconst units = `export function toCelsius(fahrenheit: number): number {\n return Math.round(((fahrenheit - 32) * 5) / 9);\n}\n\nexport function toFahrenheit(celsius: number): number {\n return Math.round((celsius * 9) / 5 + 32);\n}\n`;\n\nconst unitsTest = `import assert from 'node:assert/strict';\nimport { test } from 'node:test';\nimport { toCelsius, toFahrenheit } from '../src/lib/units.ts';\n\ntest('converts both ways', () => {\n assert.equal(toCelsius(212), 100);\n assert.equal(toFahrenheit(0), 32);\n});\n`;\n\nconst index = `import { forecast } from './routes/forecast.ts';\n\nexport default {\n async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n if (url.pathname === '/health') return new Response('ok');\n const city = url.searchParams.get('city');\n if (!city) return Response.json({ error: 'city is required' }, { status: 400 });\n return Response.json(await forecast(city));\n },\n};\n`;\n\nconst readme = `# harbor\n\nA small forecast API that sits in front of the upstream weather service and caches per city.\n\n## Development\n\n\\`\\`\\`sh\nnpm install\nnpm test\nnpm run dev\n\\`\\`\\`\n\nThe worker listens on \\`http://localhost:8787\\`. Try \\`/forecast?city=Lisbon\\`.\n`;\n\nconst pkg = `{\n \"name\": \"harbor\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"wrangler dev\",\n \"test\": \"node --test test/\"\n },\n \"devDependencies\": {\n \"wrangler\": \"4.40.0\"\n }\n}\n`;\n\nconst skill = `---\nname: release-notes\ndescription: Draft release notes from merged pull requests since the last tag.\n---\n\n1. Run \\`collect.jsh\\` with the repository and the previous tag.\n2. Group the pull requests by label: features, fixes, chores.\n3. Write one sentence per change, in the past tense, without ticket numbers.\n`;\n\nconst collect = `const [repo, since] = process.argv.slice(2);\nconst pulls = await gh(\\`repos/\\${repo}/pulls?state=closed&per_page=100\\`);\nfor (const pull of pulls.filter((p) => p.merged_at > since)) {\n console.log(\\`\\${pull.number}\\\\t\\${pull.labels.map((l) => l.name).join(',')}\\\\t\\${pull.title}\\`);\n}\n`;\n\nconst memory = `# Shared memory\n\n## Preferences\n- Keep replies short. Lead with the result, then the evidence.\n- Run the tests before saying something is fixed.\n\n## Projects\n- harbor: forecast API, deployed as a worker. Cache bugs show up around midnight UTC.\n- release-notes: drafted every Friday from merged pull requests.\n`;\n\nconst standup = `# Standup, 4 October\n\n- harbor: retries for upstream timeouts are in review.\n- Docs: the forecast endpoint page still shows Fahrenheit examples.\n- Next: move the cache to KV once the TTL fix lands.\n`;\n\nconst sample = `{\n \"city\": \"Lisbon\",\n \"daily\": { \"max\": 77, \"min\": 61, \"summary\": \"Clear, light wind from the north\" }\n}\n`;\n\nconst bashrc = `export PS1='\\\\u@slicc:\\\\w\\\\$ '\nalias ll='ls -la'\n`;\n\nconst suggestions = `${JSON.stringify(\n [\n {\n id: 'sug-units',\n kind: 'skill',\n title: 'Unit conversions',\n body: 'You converted Fahrenheit to Celsius by hand in three chats this week. A skill can do it for you.',\n skill: 'unit-converter',\n install:\n 'unit-converter from raw.githubusercontent.com/example/skills/main/unit-converter/SKILL.md',\n },\n {\n id: 'sug-notes',\n kind: 'use-case',\n title: 'Release notes from the week',\n body: 'You write release notes for harbor every Friday. Let the cone draft them from the commits.',\n prompt: 'Draft release notes for harbor from the commits since last Friday.',\n },\n {\n id: 'sug-cache',\n kind: 'tip',\n title: 'Name your cache keys',\n body: 'Forecast cache keys mix the city and the units. Splitting them makes stale entries easier to find.',\n },\n ],\n null,\n 2\n)}\n`;\n\nconst upstreamReport =\n '# Upstream limits\\n\\n## Summary\\n\\nThe forecast upstream allows **60 requests a minute** per key and answers `429` with a `Retry-After` header past that. A one-minute cache keeps harbor well under it.\\n\\n## Findings\\n\\n- Bursts after midnight UTC reach about 40 requests a minute.\\n- `Retry-After` is in seconds, never a date.\\n- Timeouts come from the upstream, not the network: 3 in the last 1,000 calls.\\n';\n\nexport const files: Record<string, string> = {\n '/workspace/harbor/README.md': readme,\n '/workspace/harbor/package.json': pkg,\n '/workspace/harbor/wrangler.toml':\n 'name = \"harbor\"\\nmain = \"src/index.ts\"\\ncompatibility_date = \"2026-09-01\"\\n',\n '/workspace/harbor/.gitignore': 'node_modules/\\n.wrangler/\\n',\n '/workspace/harbor/src/index.ts': index,\n '/workspace/harbor/src/routes/forecast.ts': forecastBefore,\n '/workspace/harbor/src/lib/cache.ts': cacheBefore,\n '/workspace/harbor/src/lib/units.ts': units,\n '/workspace/harbor/src/legacy/xml.ts': legacyXml,\n '/workspace/harbor/static/radar.png': '\\u0089PNG\\r\\n\\u001a\\n',\n '/workspace/harbor/test/units.test.ts': unitsTest,\n '/workspace/skills/release-notes/SKILL.md': skill,\n '/workspace/skills/release-notes/scripts/collect.jsh': collect,\n '/shared/MEMORY.md': memory,\n '/shared/notes/2026-10-04-standup.md': standup,\n '/shared/scoop-notifications/amber-heron.md': upstreamReport,\n '/home/user/.bashrc': bashrc,\n '/home/.gelatiere/suggestions.json': suggestions,\n '/tmp/forecast-sample.json': sample,\n};\n\nexport const directories = ['/sessions', '/home/user/downloads'];\n\nexport const mountPoint = '/mnt/photos';\n\nexport const mounted: Record<string, string> = {\n 'README.md': '# Photos\\n\\nHarbor shots for the forecast pages, one album per season.\\n',\n 'albums/autumn.json': '{ \"title\": \"Autumn\", \"shots\": [\"breakwater-fog\", \"pier-at-dusk\"] }\\n',\n 'albums/winter.json': '{ \"title\": \"Winter\", \"shots\": [\"ice-on-the-buoys\"] }\\n',\n 'captions.txt':\n 'breakwater-fog: low cloud over the outer wall\\npier-at-dusk: lamps on, tide out\\n',\n};\n\nexport const pending: Change[] = [\n {\n path: '/workspace/harbor/src/lib/cache.ts',\n status: 'modified',\n before: cacheBefore,\n after: cacheAfter,\n agentId: 'cone-harbor',\n },\n {\n path: '/workspace/harbor/src/lib/retry.ts',\n status: 'added',\n before: null,\n after: retry,\n agentId: 'scoop-otter',\n },\n {\n path: '/workspace/harbor/src/routes/forecast.ts',\n status: 'modified',\n before: forecastBefore,\n after: forecastAfter,\n agentId: 'scoop-otter',\n },\n {\n path: '/workspace/harbor/src/legacy/xml.ts',\n status: 'deleted',\n before: legacyXml,\n after: null,\n agentId: 'cone-harbor',\n },\n {\n path: '/workspace/harbor/static/radar.png',\n status: 'modified',\n before: null,\n after: null,\n agentId: 'scoop-otter',\n },\n];\n\nexport const skillEdit: Change = {\n path: '/workspace/skills/release-notes/SKILL.md',\n status: 'modified',\n before: skill,\n after: `${skill}4. Link each change to its pull request.\\n`,\n agentId: null,\n};\n\nexport const models: ModelOption[] = [\n { id: 'claude-opus-5-5', label: 'Claude Opus 5.5', provider: 'Anthropic', images: true },\n { id: 'claude-sonnet-5-5', label: 'Claude Sonnet 5.5', provider: 'Anthropic', images: true },\n { id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5', provider: 'Anthropic', images: true },\n { id: 'local-small', label: 'Local (ort-llama)', provider: 'This browser', images: false },\n { id: 'local-guard', label: 'Local guard', provider: 'This browser', kind: 'classifier' },\n { id: 'local-tiny', label: 'Local tiny (no tools)', provider: 'This browser', tools: false },\n];\n\nexport const laterModels: ModelOption[] = [\n { id: 'gpt-6', label: 'GPT-6', provider: 'OpenAI', images: true },\n { id: 'gpt-6-mini', label: 'GPT-6 mini', provider: 'OpenAI', images: true, default: true },\n];\n\nexport const defaults: Settings = {\n color: 'system',\n model: 'claude-sonnet-5-5',\n thinking: 'medium',\n sendOnEnter: true,\n pushToTalk: false,\n showThinking: true,\n diffStyle: 'unified',\n};\n\nexport const accounts: Account[] = [\n { id: 'anthropic', provider: 'Anthropic', identity: 'API key ending 3f2a', status: 'connected' },\n { id: 'github', provider: 'GitHub', identity: '@example-dev', status: 'connected' },\n { id: 'adobe', provider: 'Adobe', identity: 'dev@example.com', status: 'expired' },\n {\n id: 'ai-adobe',\n provider: 'Adobe AI',\n identity: 'harbor-ops@example.com',\n status: 'expired',\n auth: 'oauth',\n },\n { id: 'openai', provider: 'OpenAI', identity: '', status: 'disconnected', auth: 'api-key' },\n {\n id: 'amazon-bedrock',\n provider: 'Amazon Bedrock',\n identity: '',\n status: 'disconnected',\n auth: 'api-key',\n fields: [\n {\n name: 'region',\n label: 'Region',\n required: true,\n options: [\n { value: 'us-east-1', label: 'US East (N. Virginia)' },\n { value: 'us-west-2', label: 'US West (Oregon)' },\n { value: 'eu-central-1', label: 'Europe (Frankfurt)' },\n { value: 'ap-northeast-1', label: 'Asia Pacific (Tokyo)' },\n ],\n value: 'us-west-2',\n },\n ],\n },\n {\n id: 'mcp:docs',\n provider: 'docs',\n identity: 'docs.example',\n url: 'https://docs.example/mcp',\n status: 'connected',\n auth: 'api-key',\n group: 'mcp',\n secret: 'token',\n },\n {\n id: 'mcp:tickets',\n provider: 'tickets',\n identity: 'tickets.example',\n url: 'https://tickets.example/mcp',\n status: 'expired',\n auth: 'api-key',\n group: 'mcp',\n secret: 'token',\n },\n {\n id: 'mcp:design',\n provider: 'design',\n identity: 'design.example',\n status: 'disconnected',\n auth: 'oauth',\n group: 'mcp',\n },\n];\n\nexport const agents: Agent[] = [\n {\n id: 'cone-sliccy',\n name: 'sliccy',\n kind: 'cone',\n parentId: null,\n status: 'idle',\n model: 'claude-sonnet-5-5',\n contextFill: 0.21,\n unread: 0,\n },\n showcaseAgent,\n {\n id: 'cone-harbor',\n name: 'harbor',\n kind: 'cone',\n parentId: null,\n status: 'idle',\n model: 'claude-opus-5-5',\n contextFill: 0.38,\n unread: 0,\n },\n {\n id: 'scoop-otter',\n name: 'quiet-otter',\n kind: 'scoop',\n parentId: 'cone-harbor',\n status: 'working',\n model: 'claude-haiku-4-5',\n contextFill: 0.12,\n unread: 0,\n },\n {\n id: 'scoop-heron',\n name: 'amber-heron',\n kind: 'scoop',\n parentId: 'cone-harbor',\n status: 'idle',\n model: 'claude-haiku-4-5',\n contextFill: 0.04,\n unread: 0,\n },\n {\n id: 'cone-release',\n name: 'release-notes',\n kind: 'cone',\n parentId: null,\n status: 'idle',\n model: 'claude-sonnet-5-5',\n contextFill: 0.7,\n unread: 1,\n },\n {\n id: 'cone-triage',\n name: 'inbox-triage',\n kind: 'cone',\n parentId: null,\n status: 'waiting',\n model: 'claude-sonnet-5-5',\n contextFill: 0.95,\n unread: 2,\n },\n {\n id: 'scoop-wren',\n name: 'tidal-wren',\n kind: 'scoop',\n parentId: 'cone-sliccy',\n status: 'idle',\n model: 'claude-haiku-4-5',\n contextFill: 0.02,\n unread: 0,\n },\n {\n id: 'cone-tides',\n name: 'tide-tables',\n kind: 'cone',\n parentId: null,\n status: 'idle',\n model: 'claude-sonnet-5-5',\n contextFill: 0.31,\n unread: 0,\n frozen: true,\n },\n];\n\nconst start = Date.UTC(2026, 9, 5, 8, 30);\nconst at = (minutes: number) => start + minutes * 60_000;\n\nexport const queues: Record<string, UserMessage[]> = { 'cone-kitchen': showcaseQueue() };\n\nexport const conversations: Record<string, Message[]> = {\n 'cone-kitchen': showcase(),\n 'cone-sliccy': [\n {\n id: 'm-s0',\n role: 'assistant',\n status: 'done',\n createdAt: at(-24 * 60),\n parts: [\n {\n type: 'text',\n text: 'Hi, I am sliccy. Tell me a little about yourself, and I will set things up for you.',\n },\n { type: 'sprinkle', sprinkle: 'welcome' },\n ],\n },\n {\n id: 'm-s1',\n role: 'user',\n text: 'What is on my plate today?',\n createdAt: at(0),\n },\n {\n id: 'm-s2',\n role: 'assistant',\n status: 'done',\n createdAt: at(1),\n parts: [\n {\n type: 'tool',\n tool: {\n id: 't-s1',\n name: 'read_file',\n title: 'Read the standup notes',\n input: '/shared/notes/2026-10-04-standup.md',\n output: standup,\n status: 'done',\n paths: ['/shared/notes/2026-10-04-standup.md'],\n },\n },\n {\n type: 'text',\n text: 'Three things carry over from yesterday:\\n\\n1. **harbor**: the retry change is in review, and the midnight cache bug is still open.\\n2. **Docs**: the forecast page still shows Fahrenheit examples.\\n3. **release-notes** has a draft waiting for you.\\n\\nThe `harbor` cone is the one to start with.',\n },\n ],\n },\n ],\n 'cone-harbor': [\n {\n id: 'm-h1',\n role: 'lick',\n channel: 'webhook',\n title: 'GitHub \u00B7 issue opened',\n text: 'example/harbor#57: Forecast stays on yesterday after midnight UTC',\n createdAt: at(2),\n },\n {\n id: 'm-h2',\n role: 'user',\n text: 'The forecast endpoint serves stale data after midnight UTC. Find out why and fix it.',\n createdAt: at(3),\n },\n {\n id: 'm-h3',\n role: 'assistant',\n status: 'done',\n createdAt: at(4),\n parts: [\n {\n type: 'thinking',\n text: 'Stale after midnight points at the cache expiry. Check how the cache compares days.',\n },\n {\n type: 'tool',\n tool: {\n id: 't-h1',\n name: 'bash',\n title: 'Search for the cache expiry',\n input: 'rg -n \"getDate|TTL\" src',\n output:\n 'src/lib/cache.ts:6:const TTL = 60 * 60 * 1000;\\nsrc/lib/cache.ts:14: const day = new Date(entry.storedAt).getDate();\\nsrc/lib/cache.ts:16: if (now - entry.storedAt > TTL) return undefined;',\n status: 'done',\n paths: ['/workspace/harbor/src/lib/cache.ts'],\n },\n },\n {\n type: 'tool',\n tool: {\n id: 't-h2',\n name: 'read_file',\n title: 'Read the cache',\n input: '/workspace/harbor/src/lib/cache.ts',\n output: cacheBefore,\n status: 'done',\n paths: ['/workspace/harbor/src/lib/cache.ts'],\n },\n },\n {\n type: 'tool',\n tool: {\n id: 't-h3',\n name: 'edit_file',\n title: 'Expire entries from the previous day',\n input: '/workspace/harbor/src/lib/cache.ts',\n output: 'Replaced 1 block (4 lines \u2192 7 lines), added dayOf()',\n status: 'done',\n paths: ['/workspace/harbor/src/lib/cache.ts'],\n diff: { before: cacheBefore, after: cacheAfter },\n },\n },\n {\n type: 'tool',\n tool: {\n id: 't-h4',\n name: 'bash',\n title: 'Run the tests',\n input: 'npm test',\n meta: 'timeout 120s',\n output:\n '> harbor@0.0.0 test\\n> node --test test/\\n\\n\u2714 converts both ways (0.6ms)\\n\u2714 expires entries from the previous day (0.4ms)\\n\u2139 tests 2\\n\u2139 pass 2\\n\u2139 fail 0',\n status: 'done',\n paths: [],\n },\n },\n {\n type: 'text',\n text: 'Found it. `ForecastCache.get` compared **local** calendar days, and when the day changed it returned the old entry instead of dropping it:\\n\\n```ts\\nif (day !== new Date(now).getDate()) return entry.value;\\n```\\n\\nI changed it to compare UTC dates and delete the entry, so the first request after midnight goes upstream. The tests pass.\\n\\n| | Before | After |\\n| --- | --- | --- |\\n| Day compared | local `getDate()` | UTC `toISOString()` |\\n| On a new day | returns stale entry | deletes and refetches |\\n\\nquiet-otter is adding retries for upstream timeouts in a scoop.',\n },\n {\n type: 'delegation',\n kind: 'scoop',\n scoop: 'quiet-otter',\n text: 'Started a scoop to add retries around the upstream fetch',\n },\n ],\n },\n {\n id: 'm-h4',\n role: 'lick',\n channel: 'scoop-notify',\n title: 'quiet-otter',\n text: 'Started: add retries with backoff around the upstream fetch',\n createdAt: at(9),\n },\n {\n id: 'm-h5',\n role: 'lick',\n channel: 'scoop-notify',\n title: 'amber-heron (scout)',\n text: '[scoop amber-heron (scout) completed]',\n summary:\n 'The upstream allows 60 requests a minute, so a one-minute cache keeps harbor under it.',\n report: '/shared/scoop-notifications/amber-heron.md',\n body: `[scoop amber-heron (scout) completed]\\n${upstreamReport}`,\n createdAt: at(11),\n },\n {\n id: 'm-h6',\n role: 'lick',\n channel: 'scoop-notify',\n title: 'grey-tern (worker)',\n text: '[scoop grey-tern (worker) failed]',\n body: '[scoop grey-tern (worker) failed]\\nThe deploy preview timed out after **120 s**. Nothing was pushed.',\n createdAt: at(13),\n },\n {\n id: 'm-h7',\n role: 'lick',\n channel: 'scoop-notify',\n title: 'salt-gull (scout)',\n text: '[scoop salt-gull (scout) completed]',\n createdAt: at(15),\n },\n ],\n 'scoop-otter': [\n {\n id: 'm-o1',\n role: 'user',\n origin: 'agent',\n from: 'harbor',\n text: 'Wrap the upstream fetch in src/routes/forecast.ts with three retries and exponential backoff.',\n createdAt: at(9),\n },\n {\n id: 'm-o2',\n role: 'assistant',\n status: 'done',\n createdAt: at(10),\n parts: [\n {\n type: 'tool',\n tool: {\n id: 't-o1',\n name: 'write_file',\n title: 'Add retry()',\n input: '/workspace/harbor/src/lib/retry.ts',\n output: 'Wrote 12 lines',\n status: 'done',\n paths: ['/workspace/harbor/src/lib/retry.ts'],\n },\n },\n {\n type: 'tool',\n tool: {\n id: 't-o2',\n name: 'edit_file',\n title: 'Use retry() for the upstream call',\n input: '/workspace/harbor/src/routes/forecast.ts',\n output: 'Replaced 1 block',\n status: 'done',\n paths: ['/workspace/harbor/src/routes/forecast.ts'],\n },\n },\n { type: 'text', text: 'Both edits are in. Running the tests next.' },\n ],\n },\n ],\n 'scoop-heron': [],\n 'scoop-wren': [],\n 'cone-tides': [\n {\n id: 'm-f1',\n role: 'user',\n text: 'Add a tide table endpoint next to the forecast, with high and low water per day.',\n createdAt: at(-2900),\n },\n {\n id: 'm-f2',\n role: 'assistant',\n status: 'done',\n createdAt: at(-2898),\n parts: [\n {\n type: 'text',\n text: 'Added `/v1/tides?city=` with the next seven days of high and low water. It reads from the same upstream as the forecast and shares its cache.',\n },\n ],\n },\n ],\n 'cone-release': [\n {\n id: 'm-r1',\n role: 'lick',\n channel: 'cron',\n title: 'Every Friday 09:00',\n text: 'Draft the release notes for example/harbor',\n createdAt: at(-1440),\n },\n {\n id: 'm-r2',\n role: 'assistant',\n status: 'done',\n createdAt: at(-1438),\n parts: [\n {\n type: 'tool',\n tool: {\n id: 't-r1',\n name: 'bash',\n title: 'Collect merged pull requests',\n input: 'collect.jsh example/harbor v1.8.0',\n output:\n '41\\tfix\\tReturn 400 when the city is missing\\n43\\tfeature\\tAdd /health\\n44\\tchore\\tUpdate wrangler to 4.40.0',\n status: 'done',\n paths: ['/workspace/skills/release-notes/scripts/collect.jsh'],\n },\n },\n {\n type: 'text',\n text: '## harbor 1.9.0\\n\\n#### Features\\n- Added a `/health` endpoint.\\n\\n#### Fixes\\n- Requests without a city now get a 400 instead of a 500.\\n\\n#### Chores\\n- Updated wrangler to 4.40.0.',\n },\n ],\n },\n {\n id: 'm-r3',\n role: 'lick',\n channel: 'cron',\n severity: 'error',\n title: 'Crontab',\n text: 'Crontab line 3 is invalid',\n body: '30 25 * * * sweep-drafts\\nThe hour is 25. It must be 0 to 23.',\n createdAt: at(-1430),\n },\n {\n id: 'm-r4',\n role: 'lick',\n channel: 'fswatch',\n severity: 'warn',\n title: '/workspace/notes',\n text: 'File watch on /workspace/notes stopped; retrying',\n createdAt: at(-1429),\n },\n {\n id: 'm-r5',\n role: 'lick',\n channel: 'workflow',\n title: 'Release report',\n text: 'The weekly release report is ready',\n body: 'Summary: harbor 1.9.0 shipped three changes this week, the /health endpoint, a 400 for requests without a city and a wrangler update, with no failed deploys, no rollbacks and two flaky test runs in the forecast suite that passed on retry, so the next release can go out on Friday as planned once the docs pass lands.',\n createdAt: at(-1428),\n },\n ],\n 'cone-triage': [\n {\n id: 'm-t1',\n role: 'system',\n kind: 'compaction',\n trigger: 'threshold',\n state: 'summarized',\n title: 'Context compacted',\n text: '41 earlier messages were summarized to stay under the context limit.',\n createdAt: at(-30),\n },\n {\n id: 'm-t2',\n role: 'assistant',\n status: 'done',\n createdAt: at(-20),\n parts: [\n {\n type: 'text',\n text: 'Two messages need a decision from you:\\n\\n- A vendor asks to move Thursday\u2019s call to Friday.\\n- The staging certificate expires in 6 days. Should I open a ticket?',\n },\n ],\n },\n {\n id: 'm-t3',\n role: 'system',\n kind: 'error',\n action: 'login',\n title: 'Mail connector',\n text: 'The connector returned 401. Reconnect the account in Settings.',\n createdAt: at(-19),\n },\n {\n id: 'm-t4',\n role: 'system',\n kind: 'error',\n action: 'login',\n account: 'mcp:tickets',\n title: 'Tickets connector',\n text: 'The tickets server rejected its token.',\n createdAt: at(-18),\n },\n ],\n};\n\nexport const tabs: BrowserTab[] = [\n {\n id: 'tab-preview',\n title: 'harbor \u00B7 localhost',\n url: 'http://localhost:8787/forecast?city=Lisbon',\n status: 'complete',\n agentId: 'cone-harbor',\n },\n {\n id: 'tab-docs',\n title: 'Forecast API reference',\n url: 'https://api.example.com/docs/v2/forecast',\n status: 'complete',\n agentId: null,\n favicon: `data:image/svg+xml;charset=utf-8,${encodeURIComponent('<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><rect width=\"16\" height=\"16\" rx=\"3\" fill=\"#7a5af8\"/><text x=\"8\" y=\"12\" font-family=\"sans-serif\" font-size=\"11\" font-weight=\"700\" fill=\"#ffffff\" text-anchor=\"middle\">A</text></svg>')}`,\n },\n {\n id: 'tab-pull',\n title: 'Add retries for upstream timeouts \u00B7 Pull request #58',\n url: 'https://git.example.com/example/harbor/pull/58',\n status: 'complete',\n agentId: 'scoop-otter',\n favicon: `data:image/svg+xml;charset=utf-8,${encodeURIComponent('<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><rect width=\"16\" height=\"16\" rx=\"3\" fill=\"#0a7a43\"/><text x=\"8\" y=\"12\" font-family=\"sans-serif\" font-size=\"11\" font-weight=\"700\" fill=\"#ffffff\" text-anchor=\"middle\">G</text></svg>')}`,\n },\n];\n\nexport const terminals: TerminalInfo[] = [\n { id: 'term-1', title: 'bash', cwd: '/workspace/harbor', agentId: null },\n];\n", "import type { Account, ProviderOption } from '../model/types.ts';\nimport { accounts } from './fixtures.ts';\n\nconst options: ProviderOption[] = [\n {\n id: 'ai-adobe',\n name: 'Adobe AI',\n description: 'Models from your Adobe plan',\n auth: 'oauth',\n },\n {\n id: 'amazon-bedrock',\n name: 'Amazon Bedrock',\n description: 'Claude and more through AWS',\n auth: 'fields',\n keyUrl: 'https://console.aws.example/bedrock/api-keys',\n fields: accounts.find((account) => account.id === 'amazon-bedrock')?.fields,\n },\n {\n id: 'anthropic',\n name: 'Anthropic',\n description: 'Claude models with your own key',\n auth: 'api-key',\n keyUrl: 'https://console.anthropic.example/keys',\n },\n {\n id: 'openai',\n name: 'OpenAI',\n description: 'GPT models with your own key',\n auth: 'api-key',\n keyUrl: 'https://platform.openai.example/api-keys',\n },\n {\n id: 'mistral',\n name: 'Mistral',\n description: 'Mistral and Codestral models',\n auth: 'api-key',\n keyUrl: 'https://console.mistral.example/keys',\n },\n {\n id: 'groq',\n name: 'Groq',\n description: 'Fast open models',\n auth: 'api-key',\n keyUrl: 'https://console.groq.example/keys',\n },\n {\n id: 'openrouter',\n name: 'OpenRouter',\n description: 'Many providers behind one key',\n auth: 'api-key',\n keyUrl: 'https://openrouter.example/keys',\n },\n {\n id: 'cerebras',\n name: 'Cerebras',\n description: 'Open models on wafer-scale chips',\n auth: 'api-key',\n keyUrl: 'https://cloud.cerebras.example/keys',\n },\n {\n id: 'github-copilot',\n name: 'GitHub Copilot',\n description: 'Models from your Copilot plan',\n auth: 'oauth',\n },\n {\n id: 'openai-codex',\n name: 'OpenAI Codex',\n description: 'Models from your ChatGPT plan',\n auth: 'oauth',\n },\n {\n id: 'azure-openai',\n name: 'Azure OpenAI',\n description: 'Your own Azure deployment',\n auth: 'fields',\n keyUrl: 'https://portal.azure.example/openai',\n fields: [\n {\n name: 'endpoint',\n label: 'Endpoint',\n required: true,\n customBase: true,\n vaultSetting: 'AZURE_OPENAI_RESOURCE_NAME',\n placeholder: 'https://harbor.openai.azure.example',\n help: 'The resource\u2019s endpoint, from Keys and endpoint.',\n },\n { name: 'deployment', label: 'Deployment', required: true, placeholder: 'harbor-gpt' },\n ],\n vaultName: 'AZURE_OPENAI_API_KEY',\n },\n {\n id: 'cloudflare',\n name: 'Cloudflare',\n description: 'Workers AI models',\n auth: 'fields',\n keyUrl: 'https://dash.cloudflare.example/api-tokens',\n needs: 'cors-free-transport',\n fields: [\n {\n name: 'account',\n label: 'Account ID',\n required: true,\n placeholder: '3f2a9c\u2026',\n help: 'On the right of the Workers AI page.',\n vaultSetting: 'CLOUDFLARE_ACCOUNT_ID',\n },\n {\n name: 'gateway',\n label: 'AI Gateway ID',\n placeholder: 'harbor-gateway',\n vaultSetting: 'CLOUDFLARE_GATEWAY_ID',\n },\n ],\n vaultName: 'CLOUDFLARE_WORKERS_AI_API_KEY',\n },\n {\n id: 'ollama',\n name: 'Ollama',\n description: 'Models running on this device',\n auth: 'local',\n },\n {\n id: 'lm-studio',\n name: 'LM Studio',\n description: 'Models served by LM Studio on this device',\n auth: 'local',\n },\n];\n\nexport const providerFixtures: readonly ProviderOption[] = options.sort((a, b) =>\n a.name.localeCompare(b.name)\n);\n\nexport function providerAccount(option: ProviderOption): Account {\n const keyed = option.auth === 'api-key' || option.auth === 'fields';\n return {\n id: option.id,\n provider: option.name,\n identity: '',\n status: 'disconnected',\n group: 'providers',\n auth: keyed ? 'api-key' : (option.auth as 'oauth' | 'local'),\n ...(keyed ? { store: 'vault' as const } : {}),\n ...(option.fields ? { fields: option.fields } : {}),\n ...(option.keyUrl ? { keyUrl: option.keyUrl } : {}),\n ...(option.description ? { description: option.description } : {}),\n ...(option.needs ? { needs: option.needs } : {}),\n ...(option.blocked ? { blocked: option.blocked } : {}),\n ...(option.vaultName ? { vaultName: option.vaultName } : {}),\n };\n}\n\nexport function providerAccounts(rows: readonly Account[], transport?: 'none'): Account[] {\n const added = (id: string, patch: Partial<Account>): Account => ({\n ...providerAccount(providerFixtures.find((option) => option.id === id) as ProviderOption),\n ...patch,\n });\n const offered = (account: Account) => providerFixtures.find((option) => option.id === account.id);\n const providers = rows\n .filter((account) => account.group !== 'mcp')\n .map((account) => {\n const option = offered(account);\n return option ? { ...providerAccount(option), ...account } : account;\n });\n const servers = rows.filter((account) => account.group === 'mcp');\n return [\n ...providers,\n added('ollama', { status: 'connected', identity: 'On this device' }),\n ...(transport ? [added('cloudflare', { status: 'connected', identity: 'API key' })] : []),\n ...servers,\n ];\n}\n", "export interface Clock {\n delay: number;\n sleep(ticks?: number): Promise<void>;\n}\n\nexport function clock(delay: number): Clock {\n return {\n delay,\n sleep: (ticks = 1) => new Promise((resolve) => setTimeout(resolve, delay * ticks)),\n };\n}\n", "import { Emitter } from '../model/emitter.ts';\nimport type {\n Account,\n AccountField,\n AccountStatus,\n ModelOption,\n ProviderOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '../model/types.ts';\nimport type { Clock } from './clock.ts';\nimport { providerAccount } from './providers.ts';\n\nexport const dummySettingsKey = 'slicc-ui.settings';\nexport const signInClosed = 'The sign-in window was closed before it finished.';\n\nexport type DummyTransport = 'none' | 'extension' | 'link';\n\nfunction chosen(\n fields: readonly AccountField[] | undefined,\n values: Record<string, string> | undefined\n): string[] {\n return (fields ?? []).flatMap((field) => {\n const option = field.options?.find((candidate) => candidate.value === values?.[field.name]);\n return option ? [option.label] : [];\n });\n}\n\nfunction kept(\n fields: readonly AccountField[] | undefined,\n values: Record<string, string> | undefined\n): Pick<Account, 'fields'> {\n if (!(fields && values)) return {};\n return {\n fields: fields.map((field) => ({ ...field, value: values[field.name] ?? field.value })),\n };\n}\n\nexport class DummySettings extends Emitter<SettingsEvents> implements SettingsPort {\n #settings: Settings;\n #accounts: Account[];\n #models: readonly ModelOption[];\n #storage: Storage | null;\n #clock: Clock;\n #keys: readonly string[];\n #signIns = new Map<string, { before: AccountStatus; stop: () => void }>();\n #gated: boolean;\n #fails: boolean;\n #transport: DummyTransport | undefined;\n #options: readonly ProviderOption[] = [];\n readonly connects: Array<{\n id: string;\n gesture: boolean | null;\n fields?: Record<string, string>;\n }> = [];\n providers?: () => readonly ProviderOption[];\n remove?: (id: string) => Promise<void>;\n\n constructor(\n defaults: Settings,\n models: readonly ModelOption[],\n accounts: readonly Account[],\n storage: Storage | null,\n clock: Clock,\n keys: readonly string[] = [dummySettingsKey],\n gated = false,\n login?: 'ok' | 'fail',\n providers?: readonly ProviderOption[],\n transport?: DummyTransport\n ) {\n super();\n this.#transport = transport;\n if (providers) {\n this.#options = providers;\n this.providers = () =>\n this.#transport === 'none' ? providers.map((option) => this.#block(option)) : providers;\n this.remove = async (id) => this.#drop(id);\n }\n this.#fails = login === 'fail';\n this.#gated = gated;\n this.#keys = keys;\n this.#storage = storage;\n this.#clock = clock;\n this.#models = models;\n this.#accounts = accounts.map((account) => ({ ...account }));\n this.#settings = { ...defaults, ...this.#load() };\n }\n\n #load(): Partial<Settings> {\n try {\n const saved = this.#keys\n .map((key) => this.#storage?.getItem(key))\n .find((value) => value != null);\n return JSON.parse(saved ?? '{}');\n } catch {\n return {};\n }\n }\n\n get(): Settings {\n return { ...this.#settings };\n }\n\n update(patch: Partial<Settings>): void {\n this.#settings = { ...this.#settings, ...patch };\n this.#storage?.setItem(this.#keys[0], JSON.stringify(this.#settings));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n if (!this.#gated) return this.#models;\n const live = new Set(\n this.#accounts\n .filter((account) => account.status === 'connected')\n .map((account) => account.provider)\n );\n return this.#models.filter((option) => live.has(option.provider));\n }\n\n accounts(): readonly Account[] {\n return this.#accounts.map((account) => this.#block({ ...account }));\n }\n\n #block<T extends Account | ProviderOption>(row: T): T {\n if (this.#transport !== 'none' || !row.needs) return row;\n return { ...row, blocked: row.needs };\n }\n\n setTransport(transport: DummyTransport): void {\n this.#transport = transport;\n if (this.providers) this.emit('providers', this.providers());\n this.emit('accounts', this.accounts());\n }\n\n #set(id: string, patch: Partial<Account>): void {\n this.#accounts = this.#accounts.map((account) =>\n account.id === id ? { ...account, ...patch } : account\n );\n this.emit('accounts', this.accounts());\n }\n\n #drop(id: string): void {\n this.#signIns.get(id)?.stop();\n this.#accounts = this.#accounts.filter((account) => account.id !== id);\n this.emit('accounts', this.accounts());\n }\n\n #add(id: string): boolean {\n const option = this.#options.find((candidate) => candidate.id === id);\n if (!option || this.#accounts.some((account) => account.id === id)) return false;\n this.#accounts = [...this.#accounts, providerAccount(option)];\n this.emit('accounts', this.accounts());\n return true;\n }\n\n async connect(id: string, secret?: string, fields?: Record<string, string>): Promise<void> {\n const activation = (globalThis.navigator as Navigator | undefined)?.userActivation;\n this.connects.push({\n id,\n gesture: activation ? activation.isActive : null,\n ...(fields ? { fields } : {}),\n });\n const fresh = this.#add(id);\n try {\n if (!(await this.#connect(id, secret, fields)) && fresh) this.#drop(id);\n } catch (error) {\n if (fresh) this.#drop(id);\n throw error;\n }\n }\n\n async #connect(id: string, secret?: string, fields?: Record<string, string>): Promise<boolean> {\n const account = this.#accounts.find((candidate) => candidate.id === id);\n const local = account?.auth === 'local';\n const window = !!account && account.auth !== 'api-key' && !local;\n if (window && !(await this.#signIn(account))) return false;\n if (window && this.#fails) {\n this.#set(id, { status: account.status });\n throw new Error(signInClosed);\n }\n if (!window) await this.#clock.sleep(10);\n if (account?.auth === 'api-key' && account.store !== 'vault' && !secret)\n throw new Error(\n `${account.provider} needs ${account.secret === 'token' ? 'a token' : 'an API key'}`\n );\n if ([secret, ...Object.values(fields ?? {})].some((value) => value?.startsWith('bad')))\n throw new Error(`${account?.provider} didn\u2019t accept that key.`);\n if (fields?.endpoint?.includes('://') && !fields.endpoint.startsWith('https://'))\n throw new Error('The endpoint must use https://.');\n const identity =\n account?.group === 'mcp'\n ? account.identity\n : local\n ? 'On this device'\n : account?.auth === 'api-key'\n ? ['API key', ...chosen(account.fields, fields)].join(' \u00B7 ')\n : account?.identity || `${id}-user@example.com`;\n this.#set(id, { status: 'connected', identity, ...kept(account?.fields, fields) });\n return true;\n }\n\n #signIn(account: Account): Promise<boolean> {\n const before = this.#signIns.get(account.id)?.before ?? account.status;\n this.#signIns.get(account.id)?.stop();\n this.#set(account.id, { status: 'signing-in' });\n return new Promise((resolve) => {\n const stop = () => {\n this.#signIns.delete(account.id);\n this.#set(account.id, { status: before });\n resolve(false);\n };\n this.#signIns.set(account.id, { before, stop });\n void this.#clock.sleep(100).then(() => {\n if (this.#signIns.get(account.id)?.stop !== stop) return;\n this.#signIns.delete(account.id);\n resolve(true);\n });\n });\n }\n\n cancel(id: string): void {\n this.#signIns.get(id)?.stop();\n }\n\n disconnect(id: string): void {\n this.#set(id, { status: 'disconnected' });\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["index", "start", "at", "defaults", "models", "accounts", "clock"]
7
+ }