@ai-ecoverse/slicc-spectrum 1.102.0 → 1.103.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 +33 -6
- package/dist/{chunk-3IV5AAUZ.js → chunk-7O5TLOZV.js} +57 -11
- package/dist/chunk-7O5TLOZV.js.map +7 -0
- package/dist/slicc-dummy.js +120 -9
- package/dist/slicc-dummy.js.map +3 -3
- package/dist/slicc-kernel-model.js +1 -1
- package/dist/slicc-ui.js +498 -168
- package/dist/slicc-ui.js.map +4 -4
- package/dist/types/app/messages.d.ts +5 -1
- package/dist/types/app/settings.d.ts +2 -2
- package/dist/types/app/sign-in.d.ts +19 -0
- package/dist/types/app/updates.d.ts +17 -1
- package/dist/types/dummy/fixtures.d.ts +7 -1
- package/dist/types/dummy/index.d.ts +3 -3
- package/dist/types/dummy/settings.d.ts +5 -3
- package/dist/types/dummy/updates.d.ts +2 -1
- package/dist/types/dummy.d.ts +1 -1
- package/dist/types/model/types.d.ts +17 -1
- package/package.json +3 -3
- package/dist/chunk-3IV5AAUZ.js.map +0 -7
package/README.md
CHANGED
|
@@ -423,6 +423,16 @@ The Browser rail button carries a dot (`data-driven`) while a tab is in use.
|
|
|
423
423
|
Theme, the model and thinking level for new cones, composer and diff preferences (push to talk only where the browser has speech recognition), and accounts to connect, reconnect or disconnect.
|
|
424
424
|
When the `updates` port has `setDeveloper`, an Updates row has the **Developer mode** switch (`sp-switch[data-setting=developer]`, `checked` from `developer()` on every `items`), described as "Check npm for newer releases that aren't certified yet, and offer them as betas in Install / Update."; while `setDeveloper(on)` is pending it is disabled with `aria-busy` and a progress circle, and a rejection shows its message under it (`[data-error]`).
|
|
425
425
|
An account whose status is `signing-in` (or a non-API-key account while its `connect` is pending) reads “Signing in…”; when the port has `cancel(id)`, its row offers Cancel (`data-action="cancel-sign-in"`), and the rejected `connect` that follows shows no error.
|
|
426
|
+
A `signing-in` account can carry `signIn` (`{ url, code? }`), which only counts while it is `signing-in`: the embedder's `connect(id)` opens the pop-up in the click and sends it to `url`, and Spectrum never opens a window itself.
|
|
427
|
+
With a `code` (a device code), the row (`.notes`), the **Add {name}** step (under its buttons, so they don't move) and the chat's expired-session card read “Enter this code on the sign-in page:” over the code in large monospace (`[data-id=sign-in-code]`, `user-select: all`) and a quiet **Copy** (size `m`, `s` in the chat card like its other buttons, `data-action="copy-sign-in-code"`, “Copy the code”) that writes it to the clipboard and reads “Copied”, also in a polite status, for two seconds, or “Couldn’t copy” when the clipboard refuses.
|
|
428
|
+
A `url` is a quiet **Open the sign-in page** link (`data-action="open-sign-in"`, a new tab with `rel="noopener noreferrer"`), for when the window was closed or blocked, only when it is `https:`, has no username, password or port, and its exact hostname is a known sign-in host for that account's id (`signInHosts` in `sign-in.ts`: `openai-codex` `auth.openai.com`, `xai` `accounts.x.ai`, `kimi-coding` `www.kimi.com`).
|
|
429
|
+
Any other `url` shows as plain selectable text (`[data-id=sign-in-url]`), with no link and no Copy, under a quiet warning with an alert icon (`[data-id=sign-in-unknown]`): “This sign-in page isn’t one SLICC knows. Check the address before you go there.”; the code and its Copy stay.
|
|
430
|
+
Without `signIn`, the signing-in view is unchanged, and the code and link go once the account is no longer `signing-in`.
|
|
431
|
+
An account with `auth: 'oauth'` and `secret: 'api-key'` signs in or takes a key: its primary action signs in, calling `connect(id, undefined, undefined, { method: 'sign-in' })` within the click.
|
|
432
|
+
Under it, a quiet standalone link-style button **Use an API key instead** (`button.swc-Link[data-action="use-key"]`), aligned with the row's text, opens the account's key form without Cancel and focuses its field (underlined in LinkText in forced colors), and **Sign in instead** (`data-action="use-sign-in"`) under the form closes it and focuses the sign-in button again.
|
|
433
|
+
Its key goes to `vault.put` as for any `store: 'vault'` account (or as the `secret` without one), then to `connect(id, undefined, fields, { method: 'key' })`, and it never reads “Signing in…” while that is pending.
|
|
434
|
+
Disconnect and Remove delete its key record first, as for any vault-backed key, and **Sign in instead** is hidden while its key connect is pending.
|
|
435
|
+
Every other account calls `connect` without `options`, as before.
|
|
426
436
|
Accounts with `group: 'mcp'` (MCP servers) get their own **MCP servers** heading (`.accounts[data-group=mcp]`).
|
|
427
437
|
An `api-key` account asks for its `secret`: “{provider} API key” by default, “{provider} token” for `secret: 'token'`; when it is `expired` it reads **API key rejected** or **Token rejected**.
|
|
428
438
|
An MCP server with `auth: 'oauth'` signs in in a pop-up: its button reads **Sign in**, and it reads **Needs sign-in** when `disconnected` and **Sign-in expired** when `expired`.
|
|
@@ -478,12 +488,17 @@ It closes, clearing the field, when the request leaves `waiting` or while the va
|
|
|
478
488
|
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.
|
|
479
489
|
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
490
|
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.
|
|
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.
|
|
491
|
+
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"), built from the package name alone as `https://www.npmjs.com/package/<name>` with each part of a scoped name encoded, never from npm's homepage or repository. Pins and additions in Your packages show no link. Every link opens in a new tab.
|
|
482
492
|
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.
|
|
483
493
|
Opens at boot until the agent is ready without failures.
|
|
484
494
|
Background updates stay in the header's update status; new failures reopen the panel, and after a reload into a boot that isn't ready yet such a panel closes once the agent is ready.
|
|
485
495
|
Every automatic close is saved to the layout.
|
|
486
|
-
When the port offers packages, an Optional packages section lists them below as compact rows, each with its state, version,
|
|
496
|
+
When the port offers packages, an Optional packages section lists them below as compact rows, each with its state, version, size, requirements, commands, progress, errors and Install log; packages never count in the header or keep the panel open at boot.
|
|
497
|
+
A row's description is clamped to two lines at every width, and the row's buttons carry it as their accessible description (`ariaDescribedByElements`), so it can always be read in full.
|
|
498
|
+
While npm hasn't answered for a row (`registry: 'checking'`) its description slot reads "Checking npm…"; when npm can't be reached (`registry: 'unreachable'`) the row shows no description line at all, since the section hint says it once (`li[data-registry]`). Such a row has no Install and no light, an installed one keeps its version, Remove, npm page and Install log, and `retry` is never shown on it.
|
|
499
|
+
When a row is unreachable the section hint reads "Couldn’t reach npm, so versions and sizes aren’t shown." with one secondary **Retry** next to it (`data-action="retry-registry"`, named "Retry reaching npm", only when the port has `refreshPackages`). While it runs the hint reads "Checking npm…" and Retry is pending; when npm still can't be reached, the hint goes back and a polite live region (`[data-still]`) says "Still couldn’t reach npm." once. Retry keeps focus while it stays, and hands focus to the Optional packages heading whenever it goes while focused. An unreachable row that isn't installed shows only its label, and no row with `registry` describes its buttons.
|
|
500
|
+
A row with `withheld` reads "Not offered: <reason>." in a subdued line under its description (`[data-withheld]`, capped at 200 characters), and never shows Install or Update: an outdated withheld row reads Installed with its installed version.
|
|
501
|
+
A row with `newer` offers its older `offered` version as usual and says why the latest isn't offered in the same subdued line (`[data-newer]`), such as "0.26.0 isn’t offered yet: needs slicc-kernel 1.48.0 or newer."; a row that has both shows only `withheld`
|
|
487
502
|
With a port that has `setDeveloper`, a row's `npm` check shows under its version: "npm: no newer release", "Checking npm…", its `reason` when the check failed (the state light stays), "{installed} (certified) · {latest} on npm, not offered: {reason}" (a certified update keeps its target, "6.6.0 (certified) → 6.7.0 · …", and so does a beta row, "6.13.5 beta · certified 6.6.0 → 6.7.0"), or, when `offered`, "{installed} (certified) · {latest} on npm, not certified" with "12 packages change in /opt/agent." (the folder in the label's parentheses; "1 package changes …"), followed by "@slicc/kernel-bridge and @slicc/vault stay at their certified versions." for `gated` ("… stays at its certified version." for one) and **Install beta**; `article[data-npm]` is the state.
|
|
488
503
|
A row with `beta` has a notice **Beta** badge by its name (`[data-beta]`), a notice "Beta installed" light while it is `current` or `installed` ("Up to date" means the certified version only; Ready to apply, Failed and the running states keep their words), reads "{version} beta · certified {certified}" and offers **Back to certified** next to its other actions; Install beta shows only while `npm` is `offered`.
|
|
489
504
|
While `npm` is `offered`, What’s new covers the releases from the installed version up to npm's `latest`, so an offered beta lists its own notes.
|
|
@@ -765,6 +780,7 @@ Theme, model, thinking level, composer and diff preferences, the models on offer
|
|
|
765
780
|
A model can say it is its provider's `default`.
|
|
766
781
|
Emit `settings` or `accounts` when the models on offer change.
|
|
767
782
|
The optional `providers()` returns the `ProviderOption`s that can be added (`{ id, name, description?, auth: 'api-key' | 'oauth' | 'fields' | 'local', fields?, keyUrl?, needs?, blocked?, vaultName? }`, sorted by name, added ones included), with a `providers` event when they change; `id` is pi-ai's provider id and becomes the `Account.id`. With it, `accounts()` lists only added accounts, `connect(id, secret?, fields?)` adds one (`group: 'providers'`; a `fields` provider becomes an `api-key` account with `store: 'vault'` and only its non-secret `fields`), and the optional `remove(id)` drops one. `Account` adds `keyUrl`, `description`, `vaultName`, the vault record for its key (else pi-ai's environment-variable name), and `url`, an `mcp:<server>` account's server URL. `needs: 'cors-free-transport'` on either is static (the provider doesn't answer a browser); `blocked: 'cors-free-transport'` is live, set while the current transport can't reach it, and cleared by a `providers` and an `accounts` event when an extension or a linked slicc appears.
|
|
783
|
+
`Account.signIn` (`{ url, code? }`) is what a `signing-in` account's sign-in page and device code are, and `connect` takes an optional fourth `options` (`{ method: 'sign-in' | 'key' }`) for an account that signs in or takes a key (`auth: 'oauth'` with `secret: 'api-key'`).
|
|
768
784
|
|
|
769
785
|
#### `changes` (optional)
|
|
770
786
|
|
|
@@ -823,8 +839,12 @@ A row's and a package's optional `releases` (`UpdateRelease[]`) lists the GitHub
|
|
|
823
839
|
Optional `developer()` (false by default) and `setDeveloper(on)`, on the owner's page only, turn developer mode on and off; `setDeveloper` resolves once settled or rejects with a displayed error, and the port emits `items` when either changes.
|
|
824
840
|
A row's optional `beta` (`{ version, certified }`) is set while a beta is installed, and its optional `npm` (`{ state, latest?, reason?, changes?: { count, gated } }`, `state` one of `checking`, `current`, `offered`, `not-offered` or `failed`) is `null` while developer mode is off.
|
|
825
841
|
Missing ports preserve existing adapters and report disconnected information in the panel.
|
|
826
|
-
Optional `packages()` returns `PackageItem` rows for optional tools, each with a short catalog `id`, its npm `package` (shown in the name's tooltip and at the top of its Install log), `label`,
|
|
827
|
-
Install Python again to use it."; the dummy adds that one when a required package is removed), `state` (`available`, `queued`, `installing`, `installed`, `outdated`, `updating`, `removing` or `failed`), the installed `version`, the `offered` version and its `size` in bytes, `progress` (`InstallProgress`, or `null` for an indeterminate bar), `error`, `actions` (`install`, `update`, `remove`, `retry`, `unpin`) and an optional `log`.
|
|
842
|
+
Optional `packages()` returns `PackageItem` rows for optional tools, each with a short catalog `id`, its npm `package` (shown in the name's tooltip and at the top of its Install log), `label`, the `description` (npm's, untrusted: HTML tags and comments go and their text stays, entities are decoded, markdown emphasis, inline code, links and images become their text, leading headings, quotes, list markers and code fences go, then whitespace collapses and it's capped at 300 characters with "…"; it's never rendered as markup or a link), the `commands` it provides, `requires` (other package ids, read as "Uses Python" while it's installed, or "Installs Python too" on a row that isn't installed yet; an installed row leaves out a requirement that isn't installed, since its warning says so), optional `notes` (curated caveats, short plain-text lines shown muted under the row and never clamped, stripped the same way and each capped at 300 characters, such as "1 untested dependency: …"; leave it out when there's nothing to say), optional `warnings` (lines with an alert icon, `data-warnings`, such as "Needs Python, which isn't installed.
|
|
843
|
+
Install Python again to use it."; the dummy adds that one when a required package is removed), `state` (`available`, `queued`, `installing`, `installed`, `outdated`, `updating`, `removing` or `failed`), the installed `version`, the `offered` version and its `size` in bytes (read "28.4 MB on disk" with `unpacked: true`, when it's npm's `dist.unpackedSize`, else the bare size), `progress` (`InstallProgress`, or `null` for an indeterminate bar), `error`, `actions` (`install`, `update`, `remove`, `retry`, `unpin`) and an optional `log`.
|
|
844
|
+
The description is npm's, and curated caveats go in `notes`, shown under it.
|
|
845
|
+
Optional `registry` is `checking` or `unreachable` while the port has no npm data for the row, fresh or cached: send it with `offered: null`, no `size`, an empty `description` and no `commands`, keep an installed row's actions, and give a row that isn't installed `retry` (which refetches, so a spectrum without `registry` can still retry) or nothing while checking.
|
|
846
|
+
Optional `withheld` is the reason, in words and without a prefix, that seven offers no version of a package npm has, such as "needs slicc-kernel 1.48.0 or newer"; send it with `offered: null` and no `install` or `update`, and for an installed package send `newer` instead (an installed row with `withheld` still reads "Not offered: <reason>.").
|
|
847
|
+
Optional `newer` (`{ version, reason }`) is npm's latest when it doesn't pass the gate but the `offered` older version does, with its blocker in the same words as `withheld`.
|
|
828
848
|
A row with `origin: 'user'` (ids such as `user:user:<name>`) goes into Your packages, `section[data-section="user-packages"]`, which only shows when there is one; its `pin` holds `base` (the version seven ships, or `null` for a package seven doesn't ship), the user's `range` and the `project` folder, such as `/opt/user`.
|
|
829
849
|
An installed pin reads "Pinned" with `0.24.0 · seven ships 0.25.0 · in /opt/agent` ("the version seven ships" when they match), and an addition reads "Added" with `^1.2.0 → 1.2.4 · in /opt/user`; `.meta[data-pin]` is `pinned` or `added`.
|
|
830
850
|
A pin that is `removing` reads "Unpinning"; other states keep their usual lights.
|
|
@@ -835,8 +855,9 @@ Each install the panel doesn't own shows in the meta line as `[data-install]`, s
|
|
|
835
855
|
When no install is the panel's, `[data-managed]` under it reads "Managed by pnpm. Remove it with `pnpm remove -g <package>`." (the command in a `code` element; or "Installed outside this panel. Remove it where it was installed." for another manager).
|
|
836
856
|
Offer `update` for such a row to update it in place, for that user and with that manager, never as a second copy; never offer `remove` for it.
|
|
837
857
|
Emit `packages` whenever they change.
|
|
858
|
+
Optional `refreshPackages()` refetches the catalog from npm, flips the rows without data to `checking`, emits `packages`, and resolves when the fetch settles; a rejection is ignored, since the rows say what happened.
|
|
838
859
|
`actPackage(id, action)` keeps the row's button pending until it settles; it shows any confirm itself, resolves without a change when that confirm is cancelled, and rejects with a displayed error on a real failure.
|
|
839
|
-
Hooks: `section[data-section="packages"]`, `li[data-id][data-state]`, buttons with `data-action`, `[data-requires]`, `[data-notes]` and `[data-error]`.
|
|
860
|
+
Hooks: `section[data-section="packages"]`, `li[data-id][data-state]`, buttons with `data-action`, `li[data-registry]`, `[data-withheld]`, `[data-newer]`, `[data-size]`, `[data-requires]`, `[data-notes]` and `[data-error]`.
|
|
840
861
|
Real installer wiring belongs to ai-ecoverse/slicc-bios#70.
|
|
841
862
|
|
|
842
863
|
#### `network` (optional)
|
|
@@ -978,7 +999,9 @@ The dummy supports `createDummyModel({ updates: 'boot' | 'starting' | 'current'
|
|
|
978
999
|
Fixtures stay stable for inspection; `model.updates.setScenario('current')` completes boot.
|
|
979
1000
|
The dummy's kernel offers three releases from 1.12.0 to 1.13.0, two of them certified, the agent one release to 0.25.0, and the syntax grammars only their installed release; its uv package offers two releases, Python links its release and the other installed packages their npm pages.
|
|
980
1001
|
Dummy Update now and Retry simulate download and link progress, and a dummy package install reports half its `size` in bytes on the way; Restart agent and Reload only change fixture state, never restart a real process or reload the browser.
|
|
981
|
-
`createDummyModel({ packages: 'mixed' | 'empty' | 'fail' | 'user' | 'elsewhere' | 'off' })` (or `?packages=` on `/ui/`, off by default) adds invented optional packages in every state: Install and Retry finish after a short wait and install missing requirements too, `fail` makes them fail, `user` adds a pinned agent-kit and two additions (one with a warning) that Unpin and Remove take out of the list, `elsewhere` has git installed for cone with pnpm and TypeScript there at an older version, whose Update keeps it in place, and Biome both from the panel and for cone, whose Remove leaves cone's copy, and removing Python while uv is installed asks through the `confirm` option (the `/ui/` page passes spectrum's `confirm`).
|
|
1002
|
+
`createDummyModel({ packages: 'mixed' | 'empty' | 'fail' | 'user' | 'elsewhere' | 'npm' | 'checking' | 'offline' | 'off' })` (or `?packages=` on `/ui/`, off by default) adds invented optional packages in every state: Install and Retry finish after a short wait and install missing requirements too, `fail` makes them fail, `user` adds a pinned agent-kit and two additions (one with a warning) that Unpin and Remove take out of the list, `elsewhere` has git installed for cone with pnpm and TypeScript there at an older version, whose Update keeps it in place, and Biome both from the panel and for cone, whose Remove leaves cone's copy, and removing Python while uv is installed asks through the `confirm` option (the `/ui/` page passes spectrum's `confirm`).
|
|
1003
|
+
`npm` is that catalog as it comes from npm: sizes on disk, TypeScript with a description over 300 characters that looks like markdown, Ruff with a curated note, esbuild offered at 0.25.10 while 0.26.0 isn't, PDF tools withheld and Biome installed at 2.2.4 while 2.3.0 isn't offered yet, with a hostile `homepage` and `repository` its npm page link ignores.
|
|
1004
|
+
`checking` and `offline` are the same rows before npm answers and when it can't be reached; the section Retry checks again (so does a row's `retry`, which only a spectrum without `registry` shows), and `offline` fails the first time and answers the second.
|
|
982
1005
|
`createDummyModel({ beta: 'offered' | 'installed' | 'blocked' | 'failed' | 'off' })` (or `?beta=` on `/ui/`, off by default) turns developer mode on with an invented agent at 6.6.0 (certified) and 6.13.5 on npm, 12 packages and nothing gated: `offered` offers Install beta, `installed` runs the beta, `blocked` isn't offered because it needs a newer kernel, and `failed` is a failed beta install with Retry and Install beta; `setDeveloper` toggles it after a short wait (checking npm again when turned on), and Install beta and Back to certified simulate a short install.
|
|
983
1006
|
`updateFixtures`, `betaFixtures`, `packageFixtures` and `DummyUpdates` are exported from `/dummy`.
|
|
984
1007
|
`createDummyModel({ mounts: 'mount' | 'cancel' | 'fail' | 'needs' })` (or `?mounts=` on `/ui/`) turns on the optional mount members, which are off by default: `mountFolder` mounts invented files at `/mnt/photos`, resolves with `null`, or rejects, as `model.files.mount.scenario` says; `needs` also lists `/mnt/photos` in `needsFolder()` until a folder is inserted there.
|
|
@@ -1027,6 +1050,10 @@ With `starting`, after 100 ticks of the dummy clock (3 s at the default delay) t
|
|
|
1027
1050
|
`createDummyModel({ import: 'v6' | 'again' | 'fail' | 'cancel-check' })` (`?import=` on `/ui/`, off by default) adds `importProfile`, `importCancel` and `importing` to the agent: any zip previews an invented export from www.sliccy.ai (3 cones, 14 scoops, 2 frozen, Anthropic and OpenAI to sign in to again, 2 mounts and a flagged `files/cones/cone/.env`), and the import ticks to 14 in a few steps and adds 3 frozen cones with `v6: true` and the report `/root/v6-import-2026-10-18.md`; a second preview says when, and **Import again** adds fresh copies. `again` starts with an earlier import, `fail` rejects with "That zip isn’t a SLICC 6 profile export.", and `cancel-check` checks slowly. `DummyImport` and its fixtures (`importPreview`, `importCones`, `importReport`, …) are exported from `/dummy`.
|
|
1028
1051
|
|
|
1029
1052
|
The kitchen sink's “docs-pass failed” card is an expired-session error for the invented `ai-adobe` account (Adobe AI, harbor-ops@example.com, `expired`, OAuth): **Log in** goes `signing-in`, then `connected` after a short wait, and the dummy records each `connect` in `settings.connects` (`{ id, gesture }`, whether `navigator.userActivation.isActive` was true at the call); inbox-triage's “Tickets connector” card names `mcp:tickets`, a token account, so its **Log in** opens Settings at that row; `createDummyModel({ login: 'fail' })` (`?login=fail` on `/ui/`) makes OAuth sign-ins reject with “The sign-in window was closed before it finished.”
|
|
1053
|
+
The dummy's sign-ins carry `signIn` while `signing-in`: OpenAI Codex a device code on its known host (`{ url: 'https://auth.openai.com/codex/device', code: 'WDJB-MJHT' }`, `deviceSignIn`); `createDummyModel({ login: 'code' })` (`?login=code` on `/ui/`) gives every OAuth sign-in that device code, `login: 'url'` (`?login=url`) only a sign-in page on that host (`pageSignIn`), and `login: 'lookalike'` (`?login=lookalike`) the device code on `https://auth.openai.com.example.net/device` (`lookalikeSignIn`), so only OpenAI Codex gets a link.
|
|
1054
|
+
Those three scenarios also add an expired OpenAI Codex account (`openai-codex`, `codexAccount`) and point the kitchen sink's “docs-pass failed” card at it, so its **Log in** shows the code with the link (or, with `lookalike`, the warning).
|
|
1055
|
+
The dummy records a `connect`'s `options` in `settings.connects`, and `{ method: 'key' }` connects without a sign-in, reading “API key”.
|
|
1056
|
+
`createDummyModel({ accounts: 'dual' })` (`?accounts=dual`) is `accounts: 'vault'` plus the invented Lumen AI (`lumen`, `auth: 'oauth'`, `secret: 'api-key'`, `store: 'vault'`, `keyUrl`, `vaultName: 'LUMEN_API_KEY'`), which signs in or takes a key.
|
|
1030
1057
|
`createDummyModel({ providers: 'none' })` (`?providers=none` on `/ui/`) starts with no model provider connected: `models()` offers only the models of connected accounts, and connecting OpenAI offers the invented GPT-6 and GPT-6 mini (its `default`).
|
|
1031
1058
|
`createDummyModel({ providers: 'all' })` (`?providers=all` on `/ui/`) adds `providers()` and `remove` with 14 invented providers (`providerFixtures` from `/dummy`): API keys for Anthropic, Cerebras, Groq, Mistral, OpenAI and OpenRouter, OAuth for Adobe AI, GitHub Copilot and OpenAI Codex, fields for Amazon Bedrock (region), Azure OpenAI (endpoint, a `customBase`, and deployment) and Cloudflare (account id, CORS-free, its own `vaultName`), and Ollama and LM Studio on this device; today's rows start as added, with Amazon Bedrock and a connected Ollama (`providerAccounts(accounts)`, `providerAccount(option)`). `connect` adds a provider and drops it again when it fails or is cancelled, a key or field starting with `bad` is refused (“{name} didn’t accept that key.”), an endpoint without `https://` is refused, and `remove` drops it.
|
|
1032
1059
|
`createDummyModel({ providers: 'all', transport: 'none' })` (`?providers=all&transport=none`) has no CORS-free transport: every provider with `needs` is also `blocked`, and Cloudflare starts connected, so it reads Unreachable. `model.settings.setTransport('extension')` (or `'link'`) clears `blocked` live, with a `providers` and an `accounts` event, and `setTransport('none')` sets it again.
|
|
@@ -1150,6 +1150,38 @@ var accounts = [
|
|
|
1150
1150
|
group: "mcp"
|
|
1151
1151
|
}
|
|
1152
1152
|
];
|
|
1153
|
+
var dualAccount = {
|
|
1154
|
+
id: "lumen",
|
|
1155
|
+
provider: "Lumen AI",
|
|
1156
|
+
identity: "",
|
|
1157
|
+
status: "disconnected",
|
|
1158
|
+
auth: "oauth",
|
|
1159
|
+
secret: "api-key",
|
|
1160
|
+
store: "vault",
|
|
1161
|
+
keyUrl: "https://console.lumen.example/keys",
|
|
1162
|
+
vaultName: "LUMEN_API_KEY"
|
|
1163
|
+
};
|
|
1164
|
+
var codexAccount = {
|
|
1165
|
+
id: "openai-codex",
|
|
1166
|
+
provider: "OpenAI Codex",
|
|
1167
|
+
identity: "harbor-ops@example.com",
|
|
1168
|
+
status: "expired",
|
|
1169
|
+
auth: "oauth"
|
|
1170
|
+
};
|
|
1171
|
+
var deviceSignIn = {
|
|
1172
|
+
url: "https://auth.openai.com/codex/device",
|
|
1173
|
+
code: "WDJB-MJHT"
|
|
1174
|
+
};
|
|
1175
|
+
var pageSignIn = {
|
|
1176
|
+
url: "https://auth.openai.com/oauth/authorize?client_id=slicc-dummy&response_type=code&state=7f3a"
|
|
1177
|
+
};
|
|
1178
|
+
var lookalikeSignIn = {
|
|
1179
|
+
url: "https://auth.openai.com.example.net/device",
|
|
1180
|
+
code: "WDJB-MJHT"
|
|
1181
|
+
};
|
|
1182
|
+
var signIns = /* @__PURE__ */ new Map([
|
|
1183
|
+
["openai-codex", deviceSignIn]
|
|
1184
|
+
]);
|
|
1153
1185
|
var agents = [
|
|
1154
1186
|
{
|
|
1155
1187
|
id: "cone-sliccy",
|
|
@@ -1810,6 +1842,7 @@ var DummySettings = class extends Emitter {
|
|
|
1810
1842
|
#signIns = /* @__PURE__ */ new Map();
|
|
1811
1843
|
#gated;
|
|
1812
1844
|
#fails;
|
|
1845
|
+
#login;
|
|
1813
1846
|
#transport;
|
|
1814
1847
|
#options = [];
|
|
1815
1848
|
connects = [];
|
|
@@ -1824,6 +1857,7 @@ var DummySettings = class extends Emitter {
|
|
|
1824
1857
|
this.remove = async (id) => this.#drop(id);
|
|
1825
1858
|
}
|
|
1826
1859
|
this.#fails = login === "fail";
|
|
1860
|
+
this.#login = login;
|
|
1827
1861
|
this.#gated = gated;
|
|
1828
1862
|
this.#keys = keys;
|
|
1829
1863
|
this.#storage = storage;
|
|
@@ -1868,9 +1902,12 @@ var DummySettings = class extends Emitter {
|
|
|
1868
1902
|
this.emit("accounts", this.accounts());
|
|
1869
1903
|
}
|
|
1870
1904
|
#set(id, patch) {
|
|
1871
|
-
this.#accounts = this.#accounts.map(
|
|
1872
|
-
(account
|
|
1873
|
-
|
|
1905
|
+
this.#accounts = this.#accounts.map((account) => {
|
|
1906
|
+
if (account.id !== id) return account;
|
|
1907
|
+
const next = { ...account, ...patch };
|
|
1908
|
+
if (next.status !== "signing-in") delete next.signIn;
|
|
1909
|
+
return next;
|
|
1910
|
+
});
|
|
1874
1911
|
this.emit("accounts", this.accounts());
|
|
1875
1912
|
}
|
|
1876
1913
|
#drop(id) {
|
|
@@ -1885,25 +1922,27 @@ var DummySettings = class extends Emitter {
|
|
|
1885
1922
|
this.emit("accounts", this.accounts());
|
|
1886
1923
|
return true;
|
|
1887
1924
|
}
|
|
1888
|
-
async connect(id, secret, fields) {
|
|
1925
|
+
async connect(id, secret, fields, options2) {
|
|
1889
1926
|
const activation = globalThis.navigator?.userActivation;
|
|
1890
1927
|
this.connects.push({
|
|
1891
1928
|
id,
|
|
1892
1929
|
gesture: activation ? activation.isActive : null,
|
|
1893
|
-
...fields ? { fields } : {}
|
|
1930
|
+
...fields ? { fields } : {},
|
|
1931
|
+
...options2 ? { options: options2 } : {}
|
|
1894
1932
|
});
|
|
1895
1933
|
const fresh = this.#add(id);
|
|
1896
1934
|
try {
|
|
1897
|
-
if (!await this.#connect(id, secret, fields) && fresh)
|
|
1935
|
+
if (!await this.#connect(id, secret, fields, options2?.method === "key") && fresh)
|
|
1936
|
+
this.#drop(id);
|
|
1898
1937
|
} catch (error) {
|
|
1899
1938
|
if (fresh) this.#drop(id);
|
|
1900
1939
|
throw error;
|
|
1901
1940
|
}
|
|
1902
1941
|
}
|
|
1903
|
-
async #connect(id, secret, fields) {
|
|
1942
|
+
async #connect(id, secret, fields, key) {
|
|
1904
1943
|
const account = this.#accounts.find((candidate) => candidate.id === id);
|
|
1905
1944
|
const local = account?.auth === "local";
|
|
1906
|
-
const window = !!account && account.auth !== "api-key" && !local;
|
|
1945
|
+
const window = !!account && account.auth !== "api-key" && !local && !key;
|
|
1907
1946
|
if (window && !await this.#signIn(account)) return false;
|
|
1908
1947
|
if (window && this.#fails) {
|
|
1909
1948
|
this.#set(id, { status: account.status });
|
|
@@ -1918,14 +1957,14 @@ var DummySettings = class extends Emitter {
|
|
|
1918
1957
|
throw new Error(`${account?.provider} didn\u2019t accept that key.`);
|
|
1919
1958
|
if (fields?.endpoint?.includes("://") && !fields.endpoint.startsWith("https://"))
|
|
1920
1959
|
throw new Error("The endpoint must use https://.");
|
|
1921
|
-
const identity = account?.group === "mcp" ? account.identity : local ? "On this device" : account?.auth === "api-key" ? ["API key", ...chosen(account
|
|
1960
|
+
const identity = account?.group === "mcp" ? account.identity : local ? "On this device" : account?.auth === "api-key" || key ? ["API key", ...chosen(account?.fields, fields)].join(" \xB7 ") : account?.identity || `${id}-user@example.com`;
|
|
1922
1961
|
this.#set(id, { status: "connected", identity, ...kept(account?.fields, fields) });
|
|
1923
1962
|
return true;
|
|
1924
1963
|
}
|
|
1925
1964
|
#signIn(account) {
|
|
1926
1965
|
const before = this.#signIns.get(account.id)?.before ?? account.status;
|
|
1927
1966
|
this.#signIns.get(account.id)?.stop();
|
|
1928
|
-
this.#set(account.id, { status: "signing-in" });
|
|
1967
|
+
this.#set(account.id, { status: "signing-in", ...this.#hint(account.id) });
|
|
1929
1968
|
return new Promise((resolve) => {
|
|
1930
1969
|
const stop = () => {
|
|
1931
1970
|
this.#signIns.delete(account.id);
|
|
@@ -1940,6 +1979,11 @@ var DummySettings = class extends Emitter {
|
|
|
1940
1979
|
});
|
|
1941
1980
|
});
|
|
1942
1981
|
}
|
|
1982
|
+
#hint(id) {
|
|
1983
|
+
const scenario = { code: deviceSignIn, url: pageSignIn, lookalike: lookalikeSignIn };
|
|
1984
|
+
const signIn = this.#login && this.#login in scenario ? scenario[this.#login] : signIns.get(id);
|
|
1985
|
+
return signIn ? { signIn } : {};
|
|
1986
|
+
}
|
|
1943
1987
|
cancel(id) {
|
|
1944
1988
|
this.#signIns.get(id)?.stop();
|
|
1945
1989
|
}
|
|
@@ -1962,6 +2006,8 @@ export {
|
|
|
1962
2006
|
laterModels,
|
|
1963
2007
|
defaults,
|
|
1964
2008
|
accounts,
|
|
2009
|
+
dualAccount,
|
|
2010
|
+
codexAccount,
|
|
1965
2011
|
agents,
|
|
1966
2012
|
queues,
|
|
1967
2013
|
conversations,
|
|
@@ -1973,4 +2019,4 @@ export {
|
|
|
1973
2019
|
dummySettingsKey,
|
|
1974
2020
|
DummySettings
|
|
1975
2021
|
};
|
|
1976
|
-
//# sourceMappingURL=chunk-
|
|
2022
|
+
//# sourceMappingURL=chunk-7O5TLOZV.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 AccountSignIn,\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 dualAccount: Account = {\n id: 'lumen',\n provider: 'Lumen AI',\n identity: '',\n status: 'disconnected',\n auth: 'oauth',\n secret: 'api-key',\n store: 'vault',\n keyUrl: 'https://console.lumen.example/keys',\n vaultName: 'LUMEN_API_KEY',\n};\n\nexport const codexAccount: Account = {\n id: 'openai-codex',\n provider: 'OpenAI Codex',\n identity: 'harbor-ops@example.com',\n status: 'expired',\n auth: 'oauth',\n};\n\nexport const deviceSignIn: AccountSignIn = {\n url: 'https://auth.openai.com/codex/device',\n code: 'WDJB-MJHT',\n};\n\nexport const pageSignIn: AccountSignIn = {\n url: 'https://auth.openai.com/oauth/authorize?client_id=slicc-dummy&response_type=code&state=7f3a',\n};\n\nexport const lookalikeSignIn: AccountSignIn = {\n url: 'https://auth.openai.com.example.net/device',\n code: 'WDJB-MJHT',\n};\n\nexport const signIns: ReadonlyMap<string, AccountSignIn> = new Map([\n ['openai-codex', deviceSignIn],\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 ConnectOptions,\n ModelOption,\n ProviderOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '../model/types.ts';\nimport type { Clock } from './clock.ts';\nimport { deviceSignIn, lookalikeSignIn, pageSignIn, signIns } from './fixtures.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\nexport type DummyLogin = 'ok' | 'fail' | 'code' | 'url' | 'lookalike';\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 #login: DummyLogin | undefined;\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 options?: ConnectOptions;\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?: DummyLogin,\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.#login = login;\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 if (account.id !== id) return account;\n const next = { ...account, ...patch };\n if (next.status !== 'signing-in') delete next.signIn;\n return next;\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(\n id: string,\n secret?: string,\n fields?: Record<string, string>,\n options?: ConnectOptions\n ): 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 ...(options ? { options } : {}),\n });\n const fresh = this.#add(id);\n try {\n if (!(await this.#connect(id, secret, fields, options?.method === 'key')) && fresh)\n this.#drop(id);\n } catch (error) {\n if (fresh) this.#drop(id);\n throw error;\n }\n }\n\n async #connect(\n id: string,\n secret: string | undefined,\n fields: Record<string, string> | undefined,\n key: boolean\n ): 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 && !key;\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' || 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', ...this.#hint(account.id) });\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 #hint(id: string): Pick<Account, 'signIn'> {\n const scenario = { code: deviceSignIn, url: pageSignIn, lookalike: lookalikeSignIn };\n const signIn =\n this.#login && this.#login in scenario\n ? scenario[this.#login as keyof typeof scenario]\n : signIns.get(id);\n return signIn ? { signIn } : {};\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", "options"]
|
|
7
|
+
}
|