@ai-ecoverse/slicc-spectrum 1.4.0 → 1.6.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.
Files changed (43) hide show
  1. package/README.md +32 -6
  2. package/dist/{chunk-SBRFYELH.js → chunk-4JUIYZ4Q.js} +4 -4
  3. package/dist/{chunk-DKUZSKYB.js → chunk-CDYGCBW7.js} +4 -4
  4. package/dist/{chunk-YPQKCWWG.js → chunk-FXM4K5WL.js} +4 -4
  5. package/dist/{chunk-C6RSQDMS.js → chunk-H57UPFSK.js} +2 -2
  6. package/dist/{chunk-FFZJVWZQ.js → chunk-JCRICTXR.js} +5 -5
  7. package/dist/{chunk-6JNYNXUQ.js → chunk-LR5GBIK7.js} +7 -7
  8. package/dist/{chunk-6GSDEWD5.js → chunk-MJOCPOXZ.js} +8 -8
  9. package/dist/{chunk-JUNZW2NI.js → chunk-N27WNL5Q.js} +3 -3
  10. package/dist/chunk-WCSKGA5W.js +30 -0
  11. package/dist/chunk-WCSKGA5W.js.map +7 -0
  12. package/dist/chunk-YWO2TNED.js +71 -0
  13. package/dist/chunk-YWO2TNED.js.map +7 -0
  14. package/dist/slicc-dummy.js +4 -62
  15. package/dist/slicc-dummy.js.map +4 -4
  16. package/dist/slicc-kernel-model.js +379 -0
  17. package/dist/slicc-kernel-model.js.map +7 -0
  18. package/dist/slicc-terminal.js +3 -26
  19. package/dist/slicc-terminal.js.map +3 -3
  20. package/dist/slicc-ui.js +586 -77
  21. package/dist/slicc-ui.js.map +4 -4
  22. package/dist/types/app/app.d.ts +7 -1
  23. package/dist/types/app/chat.d.ts +8 -0
  24. package/dist/types/app/composer.d.ts +4 -1
  25. package/dist/types/app/dips.d.ts +13 -0
  26. package/dist/types/app/files.d.ts +11 -0
  27. package/dist/types/app/panels.d.ts +15 -4
  28. package/dist/types/app/spectrum.d.ts +3 -0
  29. package/dist/types/components/dock.d.ts +2 -0
  30. package/dist/types/kernel/files.d.ts +20 -0
  31. package/dist/types/kernel/idle.d.ts +51 -0
  32. package/dist/types/kernel/index.d.ts +17 -0
  33. package/dist/types/kernel/terminals.d.ts +21 -0
  34. package/dist/types/kernel.d.ts +7 -0
  35. package/package.json +6 -2
  36. /package/dist/{chunk-SBRFYELH.js.map → chunk-4JUIYZ4Q.js.map} +0 -0
  37. /package/dist/{chunk-DKUZSKYB.js.map → chunk-CDYGCBW7.js.map} +0 -0
  38. /package/dist/{chunk-YPQKCWWG.js.map → chunk-FXM4K5WL.js.map} +0 -0
  39. /package/dist/{chunk-C6RSQDMS.js.map → chunk-H57UPFSK.js.map} +0 -0
  40. /package/dist/{chunk-FFZJVWZQ.js.map → chunk-JCRICTXR.js.map} +0 -0
  41. /package/dist/{chunk-6JNYNXUQ.js.map → chunk-LR5GBIK7.js.map} +0 -0
  42. /package/dist/{chunk-6GSDEWD5.js.map → chunk-MJOCPOXZ.js.map} +0 -0
  43. /package/dist/{chunk-JUNZW2NI.js.map → chunk-N27WNL5Q.js.map} +0 -0
package/README.md CHANGED
@@ -103,7 +103,7 @@ Things found while building this against wterm 0.5.4, recorded here, not pushed
103
103
 
104
104
  ## UI
105
105
 
106
- `dist/slicc-ui.js` is SLICC's app shell on Spectrum Web Components 1.12 with the Spectrum 2 theme (`<sp-theme system="spectrum-two">`), in light and dark. It runs against a typed model, not against the kernel, the agent or the browser directly, and is not wired to any of them yet. `dist/slicc-dummy.js` provides a dummy model that streams replies and tool calls with timers.
106
+ `dist/slicc-ui.js` is SLICC's app shell on Spectrum Web Components 1.12 with the Spectrum 2 theme (`<sp-theme system="spectrum-two">`), in light and dark. It runs against a typed model, not against the kernel, the agent or the browser directly. `dist/slicc-dummy.js` provides a dummy model that streams replies and tool calls with timers, and `dist/slicc-kernel-model.js` a real one for files and terminals on slicc-kernel (see [Kernel model](#kernel-model)).
107
107
 
108
108
  ```html
109
109
  <slicc-app></slicc-app>
@@ -119,7 +119,9 @@ Things found while building this against wterm 0.5.4, recorded here, not pushed
119
119
 
120
120
  ### Layouts and rails
121
121
 
122
- The layout follows the width of `<slicc-app>`, which it reflects as its `screen` attribute: `phone` (under 640 px) has one column, `tablet` (under 1200 px) two, `desktop` three, like SLICC v6. Each screen class starts with few panels open and saves its own layout (`slicc-ui.layout.<screen>`). Every surface has a home side, left, center or right. Closed panels wait as icons in the left and right rails (on a phone, in one bar at the bottom); one click puts a panel back on its side, next to its neighbours.
122
+ The layout follows the width of `<slicc-app>`, which it reflects as its `screen` attribute: `phone` (under 640 px) has one column, `tablet` (under 1200 px) two, `desktop` three, like SLICC v6. Each screen class starts with few panels open and saves its own layout (`slicc-ui.layout.v2.<screen>`). Every surface has a home side, left, center or right. Closed panels wait as icons in the left and right rails (on a phone, in one bar at the bottom); one click puts a panel back on its side, next to its neighbours. Each thread, a cone's or a scoop's conversation, opens in its own chat panel (`chat:<agent id>`), as a tab in the same group as the other chats. Selecting a thread opens or reveals its tab, activating a chat tab selects its thread, and a thread's chat closes when the thread goes away (frozen or deleted).
123
+
124
+ `surfaces` on `<slicc-app>` (default: every surface, exported as `surfaces`) is what the app offers: the panels it can open, the View menu, the rails and `Alt+1…9`. A saved layout with a panel it doesn't offer is dropped for the default. An embedder can pass a subset with its own `open` per screen class. The agent picker, the tray and the agent part of the status bar show only when `chat` is offered, the change count only with `changes`, and the settings button only with `settings`. Elements with `slot="status"` go into the status bar, after the built-in items.
123
125
 
124
126
  ### Fonts
125
127
 
@@ -132,7 +134,7 @@ Text is Adobe Clean and code Spectrum's Source Code Pro. Source Code Pro (OFL) i
132
134
  | `<slicc-app>` | The shell: header with the agent picker, the View menu and the theme switch, rails, a `<slicc-dock>`, and a status bar. Saves the dock layout per screen class to `storage` (default `localStorage`) under `layoutKey`. |
133
135
  | `<slicc-dock>` | Generic. [dockview-core](https://dockview.dev/) 8 with a theme mapped to Spectrum tokens, in its own shadow root. Panels come from `factories` (`name → (params) => HTMLElement`). `open`, `close`, `has`, `content`, `focusPanel`, `cycleGroup`, `cycleTab`, `toJSON`, `restore`, `clear`, and the full `api`. Tabs have a context menu (close, close others, float, maximize). Events: `layout-change`, `active-panel-change`, `panel-close`. |
134
136
  | `<slicc-agents>` | Cones with their scoops, status, context fill and unread count. Selecting one makes it the active agent. |
135
- | `<slicc-chat>` | The active agent's conversation, by day: user messages (with attachments, steered, or delegated from another cone), assistant messages (Markdown with tables, task lists, quotes, code and images; thinking; tool calls, grouped into a collapsible cluster from three in a row; media galleries with images, video and audio; action cards for tools, pull requests and status; plans and checklists; inline diffs; question prompts; delegations; link previews; errors with a fix-it action), standalone tool results, system messages (compaction markers, error cards, notices) and licks, SLICC's events into a cone, on every channel. Permission requests are allowed or denied in place. |
137
+ | `<slicc-chat>` | One thread's conversation (its `agent`, or the active agent if unset), by day: user messages (with attachments, steered, or delegated from another cone), assistant messages (Markdown with tables, task lists, quotes, code and images; thinking; tool calls, grouped into a collapsible cluster from three in a row; media galleries with images, video and audio; action cards for tools, pull requests and status; plans and checklists; inline diffs; question prompts; delegations; link previews; errors with a fix-it action), standalone tool results, system messages (compaction markers, error cards, notices) and licks, SLICC's events into a cone, on every channel. Permission requests are allowed or denied in place. |
136
138
  | `<slicc-composer>` | The message box. <kbd>Enter</kbd> sends, or queues behind a running reply; <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>Enter</kbd> steers (interrupts); <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a line; <kbd>Tab</kbd> takes the suggested follow-up; <kbd>↑</kbd>/<kbd>↓</kbd> at the start or end walk this agent's history; <kbd>Esc</kbd> stops. `/` completes commands (`/clear`, `/compact`, `/model`, `/thinking`, `/scoop`, `/stop`, `/theme`) and their arguments, `@` mentions agents and files. Attach from the computer, from SLICC's files, a browser screenshot or a shared secret, or paste and drop files (25 MB each). Queued messages wait above it, to send now or drop. Model and thinking pickers, and dictation where the browser has speech recognition. Drafts are kept per agent. |
137
139
  | `<slicc-files>` | The file system as a `<slicc-file-tree>`, with pending changes as git status. Opening a file opens it in a tab. |
138
140
  | `<slicc-file-view>` | One file (`path`), highlighted, with its pending change and a link to the diff. |
@@ -144,7 +146,7 @@ Text is Adobe Clean and code Spectrum's Source Code Pro. Source Code Pro (OFL) i
144
146
  | `<slicc-memory>` | What agents remember, globally or per cone, grouped by section: search, filter by tag, expand, edit, add and forget. |
145
147
  | `<slicc-monitor>` | The live monitor: vitals with sparklines (active agents, spend, budget, fullest context), alerts, and the topology (cones and scoops, terminals, tabs, pending changes, sprinkles, tray followers). |
146
148
  | `<slicc-freezer>` | Frozen cones, archived with their scoops: thaw to bring one back, delete, or freeze the active cone (also `/freeze`). |
147
- | `<slicc-sprinkle>` | A SLICC sprinkle (`.shtml`), as a panel or, with `inline`, as a dip in the chat that grows to fit. It runs in a sandboxed frame (`allow-scripts` only) with SLICC's sprinkle theme (the `--s2-*` tokens and `.sprinkle-*` classes), the app's fonts, and Lucide icons (`<i data-lucide>`, `LucideIcons.render()`). Its only way back is `slicc.lick({ action, data })`, which reaches the owning cone as a `sprinkle` lick. Panel sprinkles sit at the top of the right rail with their Lucide icon. |
149
+ | `<slicc-sprinkle>` | A SLICC sprinkle (`.shtml`), as a panel or, with `inline`, as a dip in the chat that grows to fit. A dip has a tab-like handle: drag it into the dock (or onto a rail, or use its open-as-panel button) and it lives on as a sprinkle panel, with a note in the chat where it was; which dips are out is saved in `slicc-ui.dips`. It runs in a sandboxed frame (`allow-scripts` only) with SLICC's sprinkle theme (the `--s2-*` tokens and `.sprinkle-*` classes), the app's fonts, and Lucide icons (`<i data-lucide>`, `LucideIcons.render()`). Its only way back is `slicc.lick({ action, data })`, which reaches the owning cone as a `sprinkle` lick. Panel sprinkles sit at the top of the right rail with their Lucide icon. |
148
150
  | `<slicc-tray>` | The tray indicator in the header: connection, the float's name, followers and budget; its panel adds role, runtime, spend, the follower list, the join link, and disconnect or reconnect. |
149
151
  | `<slicc-file-tree>` | Generic. [`@pierre/trees`](https://www.npmjs.com/package/@pierre/trees) through its `web-components` entry: `paths` (folders end in `/`), `gitStatus`, `expanded`, `reveal(path, focus)`. Fires `file-open` on click and on <kbd>Enter</kbd>. |
150
152
  | `<slicc-code-view>` | Generic. A highlighted file through [`@pierre/diffs`](https://www.npmjs.com/package/@pierre/diffs): `path`, `contents`, `color`. |
@@ -170,11 +172,35 @@ Keys: <kbd>Alt</kbd>+<kbd>1</kbd>… opens and focuses a panel, <kbd>F6</kbd> an
170
172
  | `sprinkles` | `@ai-ecoverse/slicc-agent` | Sprinkles (`inline` ones show as dips in the chat, not in the rail) and `send`, which turns a sprinkle's lick into a lick on its cone. |
171
173
  | `tray` | the tray protocol | Connection, role, float kind, followers, spend and budget; `reconnect` and `disconnect`. |
172
174
 
175
+ ### Kernel model
176
+
177
+ `@ai-ecoverse/slicc-spectrum/kernel` (`dist/slicc-kernel-model.js`) backs the sections that work without an agent:
178
+
179
+ ```js
180
+ import { createKernel } from '@ai-ecoverse/slicc-kernel';
181
+ import { createKernelModel } from '@ai-ecoverse/slicc-spectrum/kernel';
182
+ import { surfaces } from '@ai-ecoverse/slicc-spectrum/ui';
183
+
184
+ const root = await navigator.storage.getDirectory();
185
+ const kernel = await createKernel({ root });
186
+ const app = document.querySelector('slicc-app');
187
+ app.surfaces = surfaces.filter((item) => item.id === 'files' || item.id === 'terminal');
188
+ app.model = createKernelModel({ kernel, root, storage: localStorage, files: { skip: ['/node_modules'] } });
189
+ ```
190
+
191
+ - **`KernelFiles`** lists the OPFS root as the tree, reads and writes files through the OPFS API, and removes them recursively. Directories in `skip` show up but aren't scanned. `start()` rescans on every `FileSystemObserver` record, or every `interval` ms (default 2000) where the browser can't observe OPFS, and emits `files` and a `file` per changed file, so open tabs follow what the terminal writes. Without an agent there are no pending changes.
192
+ - **`KernelTerminals`** opens `bash -i` (or `argv`) in `cwd` (default `/home`) through `kernelBackend`, one session per terminal, as many as the user opens. `open` (default 1) is how many it starts with.
193
+ - Everything else is idle (`IdleAgent`, `IdleBrowser`, `IdleMemory`, `IdleMonitor`, `IdleSprinkles`, `IdleTray`, from `idleModel(storage)`): empty lists, and actions that need a backend throw. Settings are kept in `storage`. Leave their surfaces out of `surfaces`.
194
+
195
+ Each section is its own port, so an embedder can mix real and dummy per section, for example `{ ...createDummyModel(), files: new KernelFiles(root) }`.
196
+
197
+ `<slicc-file-view>` has **Edit**: the file opens in a plain text area, and **Save** or `Mod+S` writes it through `files.write`; `Escape` cancels.
198
+
173
199
  The `kitchen-sink` cone holds every kind of message, content and lick in one conversation, for design work and screenshots. The dummy's fixtures are invented: a small forecast API called harbor, with cones, scoops, a conversation per agent, pending changes, browser tabs and accounts. Its only sprinkles are SLICC's own: `welcome` (the onboarding wizard, as a dip in the sliccy cone) and `suggestions`, copied from `slicc` (`packages/vfs-root/shared/sprinkles/`, commit `aa29784`) with their comments stripped, as is the sprinkle theme in `src/app/sprinkle-theme.css`. Without file access, `suggestions` shows its empty state. Its replies are scripted by keyword (tests, fix or add, open or docs, files, anything else), and their tool calls act on the other ports: an edit writes a file and shows up as a change, a browse opens a tab.
174
200
 
175
201
  ### Distribution
176
202
 
177
- The UI is ESM with code splitting: `slicc-ui.js`, `slicc-dummy.js` and `chunk-*.js` next to them in `dist/`, with no bare imports, so the folder can be served as plain files from OPFS. dockview's ESM build has no CSS; the build takes it from dockview's UMD bundle. `@pierre/diffs` highlights with Shiki. `dist/` carries the grammars SLICC needs most (CSS, diff, HTML, JavaScript, JSON, JSX, Markdown, Python, shell, SQL, TOML, TSX, TypeScript, XML, YAML); every other grammar and theme stays out of `dist/` and loads the first time a file needs it. It loads from `grammarBase` first, if set, and then from `https://cdn.jsdelivr.net/npm/@shikijs/` (pinned to the installed version, CORS and CORP headers set). For offline use, install the optional peer dependencies `@shikijs/langs` and `@shikijs/themes` (pinned to the same version; plain relative ESM, no bare imports), serve them, and point `grammarBase` (on `<slicc-app>`, or `setGrammarBase()`) at the folder holding `langs/` and `themes/`, for example `/node_modules/@shikijs/`. The build fails if the peer versions drift from the installed ones. `SLICC_GRAMMAR_BASE` points the build at another CDN. `dist/` is about 55 files and 5.5 MB of JavaScript. The build fails if React is bundled; `@pierre/trees` lists React as a peer dependency, so npm installs it, but the `web-components` entry runs on Preact. Types are in `dist/types/ui.d.ts` and `dist/types/dummy.d.ts`, exported as `@ai-ecoverse/slicc-spectrum/ui` and `/dummy`.
203
+ The UI is ESM with code splitting: `slicc-ui.js`, `slicc-dummy.js` and `chunk-*.js` next to them in `dist/`, with no bare imports, so the folder can be served as plain files from OPFS. dockview's ESM build has no CSS; the build takes it from dockview's UMD bundle. `@pierre/diffs` highlights with Shiki. `dist/` carries the grammars SLICC needs most (CSS, diff, HTML, JavaScript, JSON, JSX, Markdown, Python, shell, SQL, TOML, TSX, TypeScript, XML, YAML); every other grammar and theme stays out of `dist/` and loads the first time a file needs it. It loads from `grammarBase` first, if set, and then from `https://cdn.jsdelivr.net/npm/@shikijs/` (pinned to the installed version, CORS and CORP headers set). For offline use, install the optional peer dependencies `@shikijs/langs` and `@shikijs/themes` (pinned to the same version; plain relative ESM, no bare imports), serve them, and point `grammarBase` (on `<slicc-app>`, or `setGrammarBase()`) at the folder holding `langs/` and `themes/`, for example `/node_modules/@shikijs/`. The build fails if the peer versions drift from the installed ones. `SLICC_GRAMMAR_BASE` points the build at another CDN. `dist/` is about 55 files and 5.5 MB of JavaScript. The build fails if React is bundled; `@pierre/trees` lists React as a peer dependency, so npm installs it, but the `web-components` entry runs on Preact. Types are in `dist/types/ui.d.ts`, `dist/types/dummy.d.ts` and `dist/types/kernel.d.ts`, exported as `@ai-ecoverse/slicc-spectrum/ui`, `/dummy` and `/kernel`.
178
204
 
179
205
  ### dockview notes
180
206
 
@@ -189,7 +215,7 @@ npm run lint
189
215
  npm test
190
216
  ```
191
217
 
192
- `npm test` builds `dist/` and runs the integration tests in headless Chromium over raw CDP, through the [harness from slicc-shared-web](https://github.com/ai-ecoverse/slicc-shared-web#integration-test-harness), against a fake backend (`test/integration/page/fake-backend.js`). It writes V8 coverage to `coverage/` and CPU profiles, screenshots and console logs to `artifacts/`. The test page is served cross-origin isolated (COOP/COEP), as slicc-kernel requires. `test/integration/kernel.test.mjs` runs `bash -i` end to end on `@ai-ecoverse/slicc-kernel` (a pinned dev dependency), with `@ai-ecoverse/wasm-bash` and `@ai-ecoverse/wasm-coreutils` installed into OPFS by the page (`/kernel.html`). `npm start` serves the test page on port 8080, and the UI at `/ui/`. `test/integration/ui.test.mjs` covers the shell, the layout (moving, closing, floating, reopening and reloading), streaming a reply with a tool call, stopping it, switching themes and the keyboard, and saves screenshots to `artifacts/ui/`.
218
+ `npm test` builds `dist/` and runs the integration tests in headless Chromium over raw CDP, through the [harness from slicc-shared-web](https://github.com/ai-ecoverse/slicc-shared-web#integration-test-harness), against a fake backend (`test/integration/page/fake-backend.js`). It writes V8 coverage to `coverage/` and CPU profiles, screenshots and console logs to `artifacts/`. The test page is served cross-origin isolated (COOP/COEP), as slicc-kernel requires. `test/integration/kernel.test.mjs` runs `bash -i` end to end on `@ai-ecoverse/slicc-kernel` (a pinned dev dependency), with `@ai-ecoverse/wasm-bash` and `@ai-ecoverse/wasm-coreutils` installed into OPFS by the page (`/kernel.html`). `npm start` serves the test page on port 8080, and the UI at `/ui/`. `test/integration/kernel-ui.test.mjs` boots `<slicc-app>` on the kernel model (`/kernel-ui/`): a command in the terminal, its file in the tree, an edit in a file tab read back in the terminal, a second terminal, and a reload. `test/integration/ui.test.mjs` covers the shell, the layout (moving, closing, floating, reopening and reloading), streaming a reply with a tool call, stopping it, switching themes and the keyboard, and saves screenshots to `artifacts/ui/`.
193
219
 
194
220
  The Biome, TypeScript, lefthook, Renovate and CI configuration comes from [slicc-shared-web](https://github.com/ai-ecoverse/slicc-shared-web), which also provides the `slicc-lint-comments`, `slicc-no-unit-tests` and `slicc-diff-cover` commands used by `npm run lint` and the pre-commit hook.
195
221
 
@@ -1,9 +1,9 @@
1
- import {
2
- defineElement
3
- } from "./chunk-6A6NIESE.js";
4
1
  import {
5
2
  o
6
3
  } from "./chunk-2BBOXTOJ.js";
4
+ import {
5
+ defineElement
6
+ } from "./chunk-6A6NIESE.js";
7
7
  import {
8
8
  SpectrumElement,
9
9
  b,
@@ -231,4 +231,4 @@ export {
231
231
  * SPDX-License-Identifier: BSD-3-Clause
232
232
  *)
233
233
  */
234
- //# sourceMappingURL=chunk-SBRFYELH.js.map
234
+ //# sourceMappingURL=chunk-4JUIYZ4Q.js.map
@@ -243,7 +243,7 @@ var AbstractOverlay = class _AbstractOverlay extends SpectrumElement {
243
243
  document.dispatchEvent(e2);
244
244
  }
245
245
  static async open(e2, r3, n2, a) {
246
- await import("./chunk-FFZJVWZQ.js");
246
+ await import("./chunk-JCRICTXR.js");
247
247
  const m = arguments.length === 2, l2 = n2 || e2, t = new this();
248
248
  let p = false;
249
249
  t.dispose = () => {
@@ -2164,9 +2164,9 @@ var InteractionController = class {
2164
2164
  return;
2165
2165
  }
2166
2166
  e2 && (customElements.whenDefined("sp-overlay").then(async () => {
2167
- const { Overlay: t } = await import("./chunk-C6RSQDMS.js");
2167
+ const { Overlay: t } = await import("./chunk-H57UPFSK.js");
2168
2168
  this.overlay = new t(), this.overlay.open = true, this.target[lastInteractionType] = this.type;
2169
- }), import("./chunk-FFZJVWZQ.js"));
2169
+ }), import("./chunk-JCRICTXR.js"));
2170
2170
  }
2171
2171
  }
2172
2172
  get overlay() {
@@ -2635,4 +2635,4 @@ export {
2635
2635
  LONGPRESS_INSTRUCTIONS,
2636
2636
  Overlay
2637
2637
  };
2638
- //# sourceMappingURL=chunk-DKUZSKYB.js.map
2638
+ //# sourceMappingURL=chunk-CDYGCBW7.js.map
@@ -1,9 +1,9 @@
1
- import {
2
- css_default
3
- } from "./chunk-LY7WVBCB.js";
4
1
  import {
5
2
  javascript_default
6
3
  } from "./chunk-TAZBKRHT.js";
4
+ import {
5
+ css_default
6
+ } from "./chunk-LY7WVBCB.js";
7
7
  import "./chunk-AXQFWXYZ.js";
8
8
 
9
9
  // node_modules/@shikijs/langs/dist/html.mjs
@@ -16,4 +16,4 @@ var html_default = [
16
16
  export {
17
17
  html_default as default
18
18
  };
19
- //# sourceMappingURL=chunk-YPQKCWWG.js.map
19
+ //# sourceMappingURL=chunk-FXM4K5WL.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  LONGPRESS_INSTRUCTIONS,
3
3
  Overlay
4
- } from "./chunk-DKUZSKYB.js";
4
+ } from "./chunk-CDYGCBW7.js";
5
5
  import "./chunk-IBQ4O4NO.js";
6
6
  import "./chunk-ZMBN6APP.js";
7
7
  import "./chunk-Y4Z7K443.js";
@@ -14,4 +14,4 @@ export {
14
14
  LONGPRESS_INSTRUCTIONS,
15
15
  Overlay
16
16
  };
17
- //# sourceMappingURL=chunk-C6RSQDMS.js.map
17
+ //# sourceMappingURL=chunk-H57UPFSK.js.map
@@ -1,18 +1,18 @@
1
- import {
2
- defineElement
3
- } from "./chunk-6A6NIESE.js";
4
1
  import {
5
2
  Overlay
6
- } from "./chunk-DKUZSKYB.js";
3
+ } from "./chunk-CDYGCBW7.js";
7
4
  import "./chunk-IBQ4O4NO.js";
8
5
  import "./chunk-ZMBN6APP.js";
9
6
  import "./chunk-Y4Z7K443.js";
10
7
  import "./chunk-364Y2XOJ.js";
11
8
  import "./chunk-ER3HU7OE.js";
12
9
  import "./chunk-2BBOXTOJ.js";
10
+ import {
11
+ defineElement
12
+ } from "./chunk-6A6NIESE.js";
13
13
  import "./chunk-TS7SL372.js";
14
14
  import "./chunk-AXQFWXYZ.js";
15
15
 
16
16
  // node_modules/@spectrum-web-components/overlay/sp-overlay.js
17
17
  defineElement("sp-overlay", Overlay);
18
- //# sourceMappingURL=chunk-FFZJVWZQ.js.map
18
+ //# sourceMappingURL=chunk-JCRICTXR.js.map
@@ -1,16 +1,16 @@
1
- import {
2
- MatchMediaController
3
- } from "./chunk-5OVGH7HO.js";
4
- import {
5
- defineElement
6
- } from "./chunk-6A6NIESE.js";
7
1
  import {
8
2
  firstFocusableIn
9
3
  } from "./chunk-IBQ4O4NO.js";
10
4
  import "./chunk-ZMBN6APP.js";
5
+ import {
6
+ MatchMediaController
7
+ } from "./chunk-5OVGH7HO.js";
11
8
  import {
12
9
  r
13
10
  } from "./chunk-ER3HU7OE.js";
11
+ import {
12
+ defineElement
13
+ } from "./chunk-6A6NIESE.js";
14
14
  import {
15
15
  A,
16
16
  SpectrumElement,
@@ -177,4 +177,4 @@ i3([n({ type: Boolean, reflect: true })], Tray.prototype, "open", 2), i3([e(".tr
177
177
 
178
178
  // node_modules/@spectrum-web-components/tray/sp-tray.js
179
179
  defineElement("sp-tray", Tray);
180
- //# sourceMappingURL=chunk-6JNYNXUQ.js.map
180
+ //# sourceMappingURL=chunk-LR5GBIK7.js.map
@@ -1,15 +1,15 @@
1
- import {
2
- DependencyManagerController
3
- } from "./chunk-EN3XGF2M.js";
4
- import {
5
- defineElement
6
- } from "./chunk-6A6NIESE.js";
7
1
  import {
8
2
  focusableSelector
9
3
  } from "./chunk-ZMBN6APP.js";
4
+ import {
5
+ DependencyManagerController
6
+ } from "./chunk-EN3XGF2M.js";
10
7
  import {
11
8
  o
12
9
  } from "./chunk-2BBOXTOJ.js";
10
+ import {
11
+ defineElement
12
+ } from "./chunk-6A6NIESE.js";
13
13
  import {
14
14
  SpectrumElement,
15
15
  b,
@@ -146,7 +146,7 @@ var Tooltip = class extends SpectrumElement {
146
146
  <span id="tip" aria-hidden="true"></span>
147
147
  </sp-tooltip-openable>
148
148
  `;
149
- return this.selfManaged ? (this.dependencyManager.add("sp-overlay"), import("./chunk-FFZJVWZQ.js"), b`
149
+ return this.selfManaged ? (this.dependencyManager.add("sp-overlay"), import("./chunk-JCRICTXR.js"), b`
150
150
  <sp-overlay
151
151
  ?open=${this.open && !this.disabled && this.dependencyManager.loaded}
152
152
  ?delayed=${this.delayed}
@@ -178,4 +178,4 @@ o3([n({ type: Boolean })], Tooltip.prototype, "delayed", 2), o3([n({ type: Boole
178
178
 
179
179
  // node_modules/@spectrum-web-components/tooltip/sp-tooltip.js
180
180
  defineElement("sp-tooltip", Tooltip);
181
- //# sourceMappingURL=chunk-6GSDEWD5.js.map
181
+ //# sourceMappingURL=chunk-MJOCPOXZ.js.map
@@ -1,8 +1,8 @@
1
- import "./chunk-SBRFYELH.js";
2
- import "./chunk-6A6NIESE.js";
1
+ import "./chunk-4JUIYZ4Q.js";
3
2
  import "./chunk-364Y2XOJ.js";
4
3
  import "./chunk-ER3HU7OE.js";
5
4
  import "./chunk-2BBOXTOJ.js";
5
+ import "./chunk-6A6NIESE.js";
6
6
  import "./chunk-TS7SL372.js";
7
7
  import "./chunk-AXQFWXYZ.js";
8
- //# sourceMappingURL=chunk-JUNZW2NI.js.map
8
+ //# sourceMappingURL=chunk-N27WNL5Q.js.map
@@ -0,0 +1,30 @@
1
+ // src/kernel-backend.ts
2
+ var encoder = new TextEncoder();
3
+ function kernelBackend(kernel, { argv = ["bash", "-i"], cwd, env } = {}) {
4
+ return {
5
+ async open(sink, { cols, rows }) {
6
+ const onData = (bytes) => sink.output(bytes);
7
+ const terminal = await kernel.openTerminal(argv, { cwd, env, cols, rows, onData });
8
+ terminal.exited.then(
9
+ (status) => sink.exit(status),
10
+ (error) => {
11
+ sink.output(encoder.encode(`\r
12
+ ${error instanceof Error ? error.message : error}\r
13
+ `));
14
+ sink.exit(1);
15
+ }
16
+ );
17
+ return {
18
+ write: (data) => terminal.write(data),
19
+ resize: (c, r) => terminal.resize(c, r),
20
+ signal: (name) => terminal.signal(name),
21
+ close: () => terminal.close()
22
+ };
23
+ }
24
+ };
25
+ }
26
+
27
+ export {
28
+ kernelBackend
29
+ };
30
+ //# sourceMappingURL=chunk-WCSKGA5W.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/kernel-backend.ts"],
4
+ "sourcesContent": ["import type { TerminalBackend, TerminalSignal } from './backend.ts';\n\nexport interface KernelTerminal {\n readonly exited: Promise<number>;\n write(data: Uint8Array): void;\n resize(cols: number, rows: number): void;\n signal(name: TerminalSignal): void;\n close(): void;\n}\n\nexport interface KernelTerminalOptions {\n cwd?: string;\n env?: Record<string, string>;\n cols: number;\n rows: number;\n onData: (bytes: Uint8Array) => void;\n}\n\nexport interface TerminalKernel {\n openTerminal(argv: string[], options: KernelTerminalOptions): Promise<KernelTerminal>;\n}\n\nexport interface KernelBackendOptions {\n argv?: string[];\n cwd?: string;\n env?: Record<string, string>;\n}\n\nconst encoder = new TextEncoder();\n\nexport function kernelBackend(\n kernel: TerminalKernel,\n { argv = ['bash', '-i'], cwd, env }: KernelBackendOptions = {}\n): TerminalBackend {\n return {\n async open(sink, { cols, rows }) {\n const onData = (bytes: Uint8Array) => sink.output(bytes);\n const terminal = await kernel.openTerminal(argv, { cwd, env, cols, rows, onData });\n terminal.exited.then(\n (status) => sink.exit(status),\n (error) => {\n sink.output(encoder.encode(`\\r\\n${error instanceof Error ? error.message : error}\\r\\n`));\n sink.exit(1);\n }\n );\n return {\n write: (data) => terminal.write(data),\n resize: (c, r) => terminal.resize(c, r),\n signal: (name) => terminal.signal(name),\n close: () => terminal.close(),\n };\n },\n };\n}\n"],
5
+ "mappings": ";AA4BA,IAAM,UAAU,IAAI,YAAY;AAEzB,SAAS,cACd,QACA,EAAE,OAAO,CAAC,QAAQ,IAAI,GAAG,KAAK,IAAI,IAA0B,CAAC,GAC5C;AACjB,SAAO;AAAA,IACL,MAAM,KAAK,MAAM,EAAE,MAAM,KAAK,GAAG;AAC/B,YAAM,SAAS,CAAC,UAAsB,KAAK,OAAO,KAAK;AACvD,YAAM,WAAW,MAAM,OAAO,aAAa,MAAM,EAAE,KAAK,KAAK,MAAM,MAAM,OAAO,CAAC;AACjF,eAAS,OAAO;AAAA,QACd,CAAC,WAAW,KAAK,KAAK,MAAM;AAAA,QAC5B,CAAC,UAAU;AACT,eAAK,OAAO,QAAQ,OAAO;AAAA,EAAO,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAAA,CAAM,CAAC;AACvF,eAAK,KAAK,CAAC;AAAA,QACb;AAAA,MACF;AACA,aAAO;AAAA,QACL,OAAO,CAAC,SAAS,SAAS,MAAM,IAAI;AAAA,QACpC,QAAQ,CAAC,GAAG,MAAM,SAAS,OAAO,GAAG,CAAC;AAAA,QACtC,QAAQ,CAAC,SAAS,SAAS,OAAO,IAAI;AAAA,QACtC,OAAO,MAAM,SAAS,MAAM;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,71 @@
1
+ import {
2
+ Emitter
3
+ } from "./chunk-T5NHW4KC.js";
4
+
5
+ // src/dummy/clock.ts
6
+ function clock(delay) {
7
+ return {
8
+ delay,
9
+ sleep: (ticks = 1) => new Promise((resolve) => setTimeout(resolve, delay * ticks))
10
+ };
11
+ }
12
+
13
+ // src/dummy/settings.ts
14
+ var key = "slicc-ui.settings";
15
+ var DummySettings = class extends Emitter {
16
+ #settings;
17
+ #accounts;
18
+ #models;
19
+ #storage;
20
+ #clock;
21
+ constructor(defaults, models, accounts, storage, clock2) {
22
+ super();
23
+ this.#storage = storage;
24
+ this.#clock = clock2;
25
+ this.#models = models;
26
+ this.#accounts = accounts.map((account) => ({ ...account }));
27
+ this.#settings = { ...defaults, ...this.#load() };
28
+ }
29
+ #load() {
30
+ try {
31
+ return JSON.parse(this.#storage?.getItem(key) ?? "{}");
32
+ } catch {
33
+ return {};
34
+ }
35
+ }
36
+ get() {
37
+ return { ...this.#settings };
38
+ }
39
+ update(patch) {
40
+ this.#settings = { ...this.#settings, ...patch };
41
+ this.#storage?.setItem(key, JSON.stringify(this.#settings));
42
+ this.emit("settings", this.get());
43
+ }
44
+ models() {
45
+ return this.#models;
46
+ }
47
+ accounts() {
48
+ return this.#accounts.map((account) => ({ ...account }));
49
+ }
50
+ #set(id, patch) {
51
+ this.#accounts = this.#accounts.map(
52
+ (account) => account.id === id ? { ...account, ...patch } : account
53
+ );
54
+ this.emit("accounts", this.accounts());
55
+ }
56
+ async connect(id) {
57
+ await this.#clock.sleep(10);
58
+ const account = this.#accounts.find((candidate) => candidate.id === id);
59
+ const identity = account?.identity || `${id}-user@example.com`;
60
+ this.#set(id, { status: "connected", identity });
61
+ }
62
+ disconnect(id) {
63
+ this.#set(id, { status: "disconnected" });
64
+ }
65
+ };
66
+
67
+ export {
68
+ clock,
69
+ DummySettings
70
+ };
71
+ //# sourceMappingURL=chunk-YWO2TNED.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/dummy/clock.ts", "../src/dummy/settings.ts"],
4
+ "sourcesContent": ["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 ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '../model/types.ts';\nimport type { Clock } from './clock.ts';\n\nconst key = 'slicc-ui.settings';\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\n constructor(\n defaults: Settings,\n models: readonly ModelOption[],\n accounts: readonly Account[],\n storage: Storage | null,\n clock: Clock\n ) {\n super();\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 return JSON.parse(this.#storage?.getItem(key) ?? '{}');\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(key, JSON.stringify(this.#settings));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n return this.#models;\n }\n\n accounts(): readonly Account[] {\n return this.#accounts.map((account) => ({ ...account }));\n }\n\n #set(id: string, patch: Partial<Account>): void {\n this.#accounts = this.#accounts.map((account) =>\n account.id === id ? { ...account, ...patch } : account\n );\n this.emit('accounts', this.accounts());\n }\n\n async connect(id: string): Promise<void> {\n await this.#clock.sleep(10);\n const account = this.#accounts.find((candidate) => candidate.id === id);\n const identity = account?.identity || `${id}-user@example.com`;\n this.#set(id, { status: 'connected', identity });\n }\n\n disconnect(id: string): void {\n this.#set(id, { status: 'disconnected' });\n }\n}\n"],
5
+ "mappings": ";;;;;AAKO,SAAS,MAAM,OAAsB;AAC1C,SAAO;AAAA,IACL;AAAA,IACA,OAAO,CAAC,QAAQ,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,QAAQ,KAAK,CAAC;AAAA,EACnF;AACF;;;ACAA,IAAM,MAAM;AAEL,IAAM,gBAAN,cAA4B,QAAgD;AAAA,EACjF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YACE,UACA,QACA,UACA,SACAA,QACA;AACA,UAAM;AACN,SAAK,WAAW;AAChB,SAAK,SAASA;AACd,SAAK,UAAU;AACf,SAAK,YAAY,SAAS,IAAI,CAAC,aAAa,EAAE,GAAG,QAAQ,EAAE;AAC3D,SAAK,YAAY,EAAE,GAAG,UAAU,GAAG,KAAK,MAAM,EAAE;AAAA,EAClD;AAAA,EAEA,QAA2B;AACzB,QAAI;AACF,aAAO,KAAK,MAAM,KAAK,UAAU,QAAQ,GAAG,KAAK,IAAI;AAAA,IACvD,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAgB;AACd,WAAO,EAAE,GAAG,KAAK,UAAU;AAAA,EAC7B;AAAA,EAEA,OAAO,OAAgC;AACrC,SAAK,YAAY,EAAE,GAAG,KAAK,WAAW,GAAG,MAAM;AAC/C,SAAK,UAAU,QAAQ,KAAK,KAAK,UAAU,KAAK,SAAS,CAAC;AAC1D,SAAK,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,EAClC;AAAA,EAEA,SAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAA+B;AAC7B,WAAO,KAAK,UAAU,IAAI,CAAC,aAAa,EAAE,GAAG,QAAQ,EAAE;AAAA,EACzD;AAAA,EAEA,KAAK,IAAY,OAA+B;AAC9C,SAAK,YAAY,KAAK,UAAU;AAAA,MAAI,CAAC,YACnC,QAAQ,OAAO,KAAK,EAAE,GAAG,SAAS,GAAG,MAAM,IAAI;AAAA,IACjD;AACA,SAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,EACvC;AAAA,EAEA,MAAM,QAAQ,IAA2B;AACvC,UAAM,KAAK,OAAO,MAAM,EAAE;AAC1B,UAAM,UAAU,KAAK,UAAU,KAAK,CAAC,cAAc,UAAU,OAAO,EAAE;AACtE,UAAM,WAAW,SAAS,YAAY,GAAG,EAAE;AAC3C,SAAK,KAAK,IAAI,EAAE,QAAQ,aAAa,SAAS,CAAC;AAAA,EACjD;AAAA,EAEA,WAAW,IAAkB;AAC3B,SAAK,KAAK,IAAI,EAAE,QAAQ,eAAe,CAAC;AAAA,EAC1C;AACF;",
6
+ "names": ["clock"]
7
+ }
@@ -1,3 +1,7 @@
1
+ import {
2
+ DummySettings,
3
+ clock
4
+ } from "./chunk-YWO2TNED.js";
1
5
  import {
2
6
  Emitter
3
7
  } from "./chunk-T5NHW4KC.js";
@@ -662,14 +666,6 @@ var DummyBrowser = class extends Emitter {
662
666
  }
663
667
  };
664
668
 
665
- // src/dummy/clock.ts
666
- function clock(delay) {
667
- return {
668
- delay,
669
- sleep: (ticks = 1) => new Promise((resolve2) => setTimeout(resolve2, delay * ticks))
670
- };
671
- }
672
-
673
669
  // src/dummy/sprinkles/suggestions.shtml
674
670
  var suggestions_default = `<!DOCTYPE html>
675
671
  <html lang="en">
@@ -3339,60 +3335,6 @@ var DummyMonitor = class extends Emitter {
3339
3335
  }
3340
3336
  };
3341
3337
 
3342
- // src/dummy/settings.ts
3343
- var key = "slicc-ui.settings";
3344
- var DummySettings = class extends Emitter {
3345
- #settings;
3346
- #accounts;
3347
- #models;
3348
- #storage;
3349
- #clock;
3350
- constructor(defaults2, models2, accounts2, storage, clock2) {
3351
- super();
3352
- this.#storage = storage;
3353
- this.#clock = clock2;
3354
- this.#models = models2;
3355
- this.#accounts = accounts2.map((account) => ({ ...account }));
3356
- this.#settings = { ...defaults2, ...this.#load() };
3357
- }
3358
- #load() {
3359
- try {
3360
- return JSON.parse(this.#storage?.getItem(key) ?? "{}");
3361
- } catch {
3362
- return {};
3363
- }
3364
- }
3365
- get() {
3366
- return { ...this.#settings };
3367
- }
3368
- update(patch) {
3369
- this.#settings = { ...this.#settings, ...patch };
3370
- this.#storage?.setItem(key, JSON.stringify(this.#settings));
3371
- this.emit("settings", this.get());
3372
- }
3373
- models() {
3374
- return this.#models;
3375
- }
3376
- accounts() {
3377
- return this.#accounts.map((account) => ({ ...account }));
3378
- }
3379
- #set(id, patch) {
3380
- this.#accounts = this.#accounts.map(
3381
- (account) => account.id === id ? { ...account, ...patch } : account
3382
- );
3383
- this.emit("accounts", this.accounts());
3384
- }
3385
- async connect(id) {
3386
- await this.#clock.sleep(10);
3387
- const account = this.#accounts.find((candidate) => candidate.id === id);
3388
- const identity = account?.identity || `${id}-user@example.com`;
3389
- this.#set(id, { status: "connected", identity });
3390
- }
3391
- disconnect(id) {
3392
- this.#set(id, { status: "disconnected" });
3393
- }
3394
- };
3395
-
3396
3338
  // src/dummy/sprinkles.ts
3397
3339
  var DummySprinkles = class extends Emitter {
3398
3340
  #sprinkles;