@ai-ecoverse/slicc-spectrum 1.96.1 → 1.98.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 +14 -3
- package/dist/{chunk-YUDOYEMB.js → chunk-LOQJK2JE.js} +10 -2
- package/dist/{chunk-YUDOYEMB.js.map → chunk-LOQJK2JE.js.map} +2 -2
- package/dist/slicc-dummy.js +104 -31
- package/dist/slicc-dummy.js.map +3 -3
- package/dist/slicc-kernel-model.js +1 -1
- package/dist/slicc-ui.js +272 -66
- package/dist/slicc-ui.js.map +3 -3
- package/dist/types/app/panels.d.ts +1 -1
- package/dist/types/dummy/agent.d.ts +4 -0
- package/dist/types/dummy/index.d.ts +2 -1
- package/dist/types/dummy/notices.d.ts +4 -2
- package/dist/types/dummy/vault.d.ts +6 -0
- package/dist/types/model/types.d.ts +4 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -303,6 +303,7 @@ Between the header and the transcript, a `<slicc-notices>` shows the model's not
|
|
|
303
303
|
On a follower without Control, or while the agent port's `readOnly()` returns a line, a note (`p[data-follow="watch"]`, that line first, else the follow-based one) takes the composer's place, the header shows the model's name instead of the pickers and New conversation, and there's no suggested follow-up.
|
|
304
304
|
An empty chat says "No messages yet.
|
|
305
305
|
Ask sliccy something." with the agent's name, and only "No messages yet." while watch-only.
|
|
306
|
+
While the agent port's `starting()` returns a line, the chat has no empty state (`[data-empty]`): the embedder's notice says what's going on.
|
|
306
307
|
With the model's `seat` set, the chat is a guest's page: the header shows only the cone's name (`[data-seat-cone]`) and its status, with no pickers, meter or New conversation; the guest's own messages (`origin` `guest` whose `seat` is the seat's `id`, or, without a `seat`, whose `from` is its `label`) read as the reader's own, with no name, while other guests keep "From {label}" and the host's messages read "From the host"; an open question or a permission request takes the normal card border, without its buttons, form, countdown or pile (no `data-pending`), and says "The host answers this."
|
|
307
308
|
(`[data-host-answers]`, subdued); once answered, it shows the answer as everyone sees it; a reviewed guest message's outcome (a notice titled "It was approved.", "Nobody approved this in time.", "It was declined." or "It was withdrawn.", with the message as its text) reads as the quoted message, cut to one line, then the outcome (`.marker[data-ended]`); an approved one shows only "It was approved.", since the delivered message follows right after it; inline sprinkles inert with "View only on this device", error cards have no action and there's no suggested follow-up; the models aren't settled, and files can't be dropped.
|
|
308
309
|
An empty guest chat says "No messages yet.
|
|
@@ -345,6 +346,11 @@ There's no row of key hints: the keys are the field's accessible description ("E
|
|
|
345
346
|
The field's status icon, which is decorative, follows the input: the AI logo when empty, a pencil while typing, a brush for a moment after <kbd>Backspace</kbd> or <kbd>Delete</kbd>, a microphone while dictating; it stays the AI logo while a reply streams, and it swaps without animation.
|
|
346
347
|
Drafts are kept per agent.
|
|
347
348
|
On a follower while the link reconnects, the field is disabled and says so; the draft stays.
|
|
349
|
+
While the agent port's `starting()` returns a line (no agent yet, but one is on its way), the composer stays usable: its placeholder is that line, there are no `/` or `@` popups, and sending, attachments included, adds a row above the field that reads "Sent when the agent starts" (`li.queued[data-mode="starting"]`), which can be dropped (`data-action="unqueue"`); a row with text and files says how many files go with it (`[data-files]`).
|
|
350
|
+
Whenever the model changes or its agent port fires `starting` or `agents`, and the current model's port has no line (`null`, or no `starting` at all) and `agent.list()` has an agent, the composer sends the rows in order to that model's active agent (else the first one) through `agent.send`, the first like a normal send and the rest with `mode: 'queue'`, and the rows go; if the line clears with no agent, the rows stay until one comes.
|
|
351
|
+
A line that comes back closes an open `/` or `@` popup.
|
|
352
|
+
The rows are kept for the page (for the `<slicc-app>` the composer is in, else for the document), not for the model, so a model swap (an embedder that puts a new `SliccModel` on `<slicc-app>` once the agent is there), a layout switch and a dock rebuild keep them; a page reload drops them.
|
|
353
|
+
Text typed but not sent while it starts is kept for the page the same way, and stays in the field once the agent arrives.
|
|
348
354
|
While the agent holds tool results for the vault (`agent.hold()`), a status line above it says "Waiting for the vault" or "Unlock the vault to continue", with how many results are held, and offers the vault's **Unlock** button when locked and the model has a `vault`; if the browser blocks the vault window, the line says to allow pop-ups.
|
|
349
355
|
With the model's `seat` set it's a guest's composer: <kbd>Enter</kbd> and the send button send through `agent.send(cone, text)`, <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a line and <kbd>↑</kbd>/<kbd>↓</kbd> walk the guest's own messages; there's no steer, queue, Stop, attachments (the field is `collapsed`, so its + is hidden and inert, and pasted files are ignored), `/` commands, `@` mentions, + menu or push to talk, and it never reads files; its description is "Enter sends, Shift+Enter adds a new line."
|
|
350
356
|
A rejected send shows the rejection's message above the field (`[data-send-error]`, `role="alert"`) and puts the draft back, ahead of anything typed since.
|
|
@@ -408,7 +414,7 @@ An account whose status is `signing-in` (or a non-API-key account while its `con
|
|
|
408
414
|
Accounts with `group: 'mcp'` (MCP servers) get their own **MCP servers** heading (`.accounts[data-group=mcp]`).
|
|
409
415
|
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**.
|
|
410
416
|
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`.
|
|
411
|
-
An account with `fields` (`{ name, label, required?, placeholder?, help?, customBase?, options?, value? }`) shows a plain labelled input for each, with its `placeholder`, its current `value` and its `help` as a line under it, and their values go to `connect(id, secret?, fields)`; the key field above them gets a visible `sp-field-label` too ("Amazon Bedrock API key"), and both span the form's width. A field with `options` (`{ value, label }`) is an `sp-picker[data-account-field]` instead, labelled by an `sp-field-label` (clicking it focuses the picker), `aria-required` when required, with its `help` under it and in its `description` slot, and when refused `invalid`, with “Select a {label}.” in its `description` slot and under it without a second icon, so a provider can offer only the values it accepts, such as Bedrock's regions; it starts on the field's current `value`, otherwise, or when `value` is none of the options, on the first option, and it never holds back Connect in the provider picker, since it always has a choice. An empty `options` list is a disabled picker reading “None available”, never a free-text input, with the help text “Nothing to choose from yet. You can connect without it.” under it in the same field group (`[data-empty]`), and doesn't hold up Save even when `required`. The plain inputs' border is `--swc-neutral-visual-color`, which keeps 3:1 against the page. The dummy's Amazon Bedrock account has a region picker; connecting keeps the chosen values as the fields' `value` and shows the chosen options' labels in the row (“API key · Europe (Frankfurt)”).
|
|
417
|
+
An account with `fields` (`{ name, label, required?, placeholder?, help?, customBase?, options?, value? }`) shows a plain labelled input for each, with its `placeholder`, its current `value` and its `help` as a line under it, and their values go to `connect(id, secret?, fields)`; the key field above them gets a visible `sp-field-label` too ("Amazon Bedrock API key"), and both span the form's width. A field with `options` (`{ value, label }`) is an `sp-picker[data-account-field]` instead, labelled by an `sp-field-label` (clicking it focuses the picker), `aria-required` when required, with its `help` under it and in its `description` slot, and when refused `invalid`, with “Select a {label}.” in its `description` slot and under it without a second icon, so a provider can offer only the values it accepts, such as Bedrock's regions; it starts on the field's current `value`, otherwise, or when `value` is none of the options, on the first option, and it never holds back Connect in the provider picker, since it always has a choice. An empty `options` list is a disabled picker reading “None available”, never a free-text input, with the help text “Nothing to choose from yet. You can connect without it.” under it in the same field group (`[data-empty]`), and doesn't hold up Save even when `required`. The plain inputs' border is `--swc-neutral-visual-color`, which keeps 3:1 against the page. The dummy's Amazon Bedrock account has a region picker; connecting keeps the chosen values as the fields' `value` and shows the chosen options' labels in the row (“API key · Europe (Frankfurt)”). A field with `vaultSetting` fills that vault setting: the first save puts the key with `settings` holding every such field that has a value (a `customBase` field only when its value is a bare name, such as an Azure resource; an `https:` one goes through `endpoints` instead), and once the key's record is live and the vault port has `settings` (and `put`), the key may be left empty, so **Connect** waits only for the required fields and an edit sends the full object through `vault.settings(name, 'model', settings)` before the endpoint change and `connect`. A refusal shows on the field it names (its `vaultSetting`, name or label), else on the key or the form, and stops before `connect`; when a keyless edit fails after its `settings` call, the record's previous settings are put back. Records saved without settings keep working until they're saved again.
|
|
412
418
|
An account with `store: 'vault'` keeps its key in the vault when the `vault` port has `put`: the masked key field (C5's value rules) goes to `vault.put(name, key, undefined, { kind: 'model', provider: account.id })` (or `{ kind: 'mcp', server }` for `mcp:<server>` accounts, named `MCP_<SERVER>_TOKEN`; model records use pi-ai's environment-variable name), then `connect(id)` runs without the secret; a connected one says “Key kept in the vault”, “Token kept in the vault” or “Kept in the vault”, and Disconnect removes the record first.
|
|
413
419
|
Without `store: 'vault'` or `vault.put`, the key goes to `connect(id, secret)` as before.
|
|
414
420
|
An `mcp:<server>` account with an `https:` `url` (the server's URL), when the `vault` port has `endpoints`, asks before its token is saved: “Connect to {url}?”, “SLICC sends this token only to {url}.”, **Connect** with Cancel focused; then the token goes to `vault.put`, the URL to `vault.endpoints({ add: { mcp: [{ server, url }] } })` and the account to `connect`, and a refusal shows on the token field and stops. The page keeps its own registrations (server and URL, not secret) in `localStorage` under `slicc-spectrum.mcp-endpoints`, written after a successful add or change and cleared after Disconnect takes the URL back. When the account's `url` differs from that registration, or, with none, from a first-use pin (the record's `url` while `SecretView.pinned` is `true`; a bridge's loopback `url` without `pinned` never counts), the row adds **Reconnect** (`data-action=reconnect-mcp`) and the note “The server moved to {url}. Reconnect to send the token there.” (`[data-notice=moved]`); after the same confirm, one `endpoints` call removes the old registration (none for a pin, which a registration overrides) and adds the new, then `connect` runs. Disconnect takes the URL back after removing the token. Settings registers MCP URLs itself, never through the agent.
|
|
@@ -705,6 +711,7 @@ Assistant messages stream: the same message is re-emitted as its parts grow and
|
|
|
705
711
|
The optional `toolLabel(agentId, callIds)` resolves with a short label for a cluster of tool runs (`callIds` in order), such as "Compare the docs with the live API", or `null`; the agent dedupes, caches and persists it.
|
|
706
712
|
Spectrum asks once a cluster forms and again each time it grows, once per set of ids, and shows the label at the end of the strip.
|
|
707
713
|
The optional `readOnly()` returns a line, or `null`, with a `readOnly` event when it changes: while it's a non-empty string, such as when this follower runs a different major version from its owner, every surface is watch-only just as a follower without Control is (no composer, no cone or conversation actions, no pickers, no Stop, no Accept or Revert in Changes, inline sprinkles view only, no model settling), and the line takes the place of the follow-based watch-only note under the chat.
|
|
714
|
+
The optional `starting()` returns a line, or `null`, with a `starting` event when it changes: while it's a non-empty string, there's no agent yet but one is on its way (such as while seven installs its first agent, or replaces one), the chat drops its empty state and the composer queues what's sent until an agent is there (see `<slicc-composer>`); without it, or at `null`, nothing changes.
|
|
708
715
|
|
|
709
716
|
#### `files`
|
|
710
717
|
|
|
@@ -895,7 +902,7 @@ The vault's view for SLICC, typed after `@ai-ecoverse/slicc-vault` (spectrum re-
|
|
|
895
902
|
`status()` returns the `VaultStatus` (`locked`, `lock`, `scrub`, `waiting` requests, and optional `exportedAt` and `backupReminder`) or `null` while loading, and `list()` the `VaultList` (`secrets` as `SecretView`s, `refused` rules, `exits`, and the first `audit` page with `auditMore`) or `null`.
|
|
896
903
|
Emit `status` and `list` when they change (bios re-lists after the vault's `changed` events), and `availability` when the optional `availability()` (`connecting`, `waiting`, `locked` or `ready`) changes.
|
|
897
904
|
`audit(before?, limit?)` resolves with an older `AuditPage` (`before` is a `seq`).
|
|
898
|
-
The optional page ops, each hiding its control when missing: `put(name, value, request?)` (a value request's `put` must use its `name`), `cancel(request)`, `remove(name, kind?)`, `restore(name, kind?)`, `import(kind, bytes, { password?, pick? })` (a `pick` stage, then `done`), `export(passphrase)` (the bundle's bytes), `lock()`, `dismissBackupReminder()` and `endpoints({ add?, remove? })`, which registers or takes back the URLs a page-sealed credential may be filled on (each an `EndpointSet`, `{ model?: [{ name, url }], mcp?: [{ server, url }] }`, a model URL bound to one record by name), checks the whole change first (`EINVAL` changes nothing) and rejects with a sentence. Settings registers them itself, never through the agent.
|
|
905
|
+
The optional page ops, each hiding its control when missing: `put(name, value, request?)` (a value request's `put` must use its `name`), `cancel(request)`, `remove(name, kind?)`, `restore(name, kind?)`, `import(kind, bytes, { password?, pick? })` (a `pick` stage, then `done`), `export(passphrase)` (the bundle's bytes), `lock()`, `dismissBackupReminder()` and `endpoints({ add?, remove? })`, which registers or takes back the URLs a page-sealed credential may be filled on (each an `EndpointSet`, `{ model?: [{ name, url }], mcp?: [{ server, url }] }`, a model URL bound to one record by name), checks the whole change first (`EINVAL` changes nothing) and rejects with a sentence. Settings registers them itself, never through the agent. `settings(name, kind, settings)` replaces a record's tenant settings as a whole without touching its key (the vault's `put` without a value); `put`'s options take the same `settings` on a first save.
|
|
899
906
|
They reject with a `VaultFailure`, an `Error` with an `ErrorCode` `code` (`isVaultFailure` from `/ui`).
|
|
900
907
|
Values go to the vault only through `put`, and never through another port.
|
|
901
908
|
`button()` returns a new `VaultButton`, `{ element, post(message), listen(fn) }` returning an unsubscribe: bios wraps the vault's `button.html` frame and its postMessage protocol, and spectrum only sends `ButtonMessage`s and receives `ButtonEvent`s.
|
|
@@ -980,6 +987,10 @@ The SLICC you follow runs a newer version.
|
|
|
980
987
|
Update this one to send prompts.", and shows a warning notice without a close button (`[data-notice="readonly"]`) in place of any other notices.
|
|
981
988
|
`model.agent.setReadOnly(text)` changes it, and `null` ends it.
|
|
982
989
|
|
|
990
|
+
`createDummyModel({ agent: 'starting' | 'waiting' })` (`?agent=` on `/ui/`, default `ready`) starts with no agents while `starting()` returns "Seven is installing its agent.", and shows an info notice without a close button (`[data-notice="starting"]`) that goes with the line; `<slicc-app>` opens the chat with no agent (the `chat` panel, as `show('chat')` does) when it starts while `starting()` has a line and its layout has no chat; once an agent is active, that agent's chat takes the `chat` panel's place in the dock, focused if focus was in it, and the `chat` panel closes, also when a saved layout brings it back.
|
|
991
|
+
With `starting`, after 100 ticks of the dummy clock (3 s at the default delay) the usual cones arrive and the line clears; `waiting` waits for `model.agent.arrive()`, which does the same.
|
|
992
|
+
`model.agent.setStarting(line)` changes the line (and `null` clears it with no agent), and either one cancels the scheduled arrival.
|
|
993
|
+
|
|
983
994
|
`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`.
|
|
984
995
|
|
|
985
996
|
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.”
|
|
@@ -995,7 +1006,7 @@ Like slicc-agent's snapshot, the dummy's vitals are the budget, Spend, Active ag
|
|
|
995
1006
|
(`guest-follower`: the same without `decide`), or (`guest-always`) one guest tool call from Seat 2 (Mara) to `read_file` with `always: true`.
|
|
996
1007
|
Decisions are recorded in `model.approvals.decisions`, and `model.approvals.end(id, reason)` ends a request.
|
|
997
1008
|
|
|
998
|
-
`createDummyModel({ vault: 'empty' | 'secrets' | 'policy' | 'locked' | 'request' | 'backup' | 'waiting' | 'purged' | 'endpoints-fail' | 'off' })` (`?vault=` on `/ui/`, off by default; `notice` is kept as another name for `policy`) adds an invented vault: no secrets yet; five secrets (an API key, a jerk lease from pier-nuc revealed to `pier publish`, a Tide Mail sign-in, one without a rule and a removed one) with an activity log that pages back once; the same with a refused rule and a policy change in the log; locked before the first unlock, with a waiting request from docs-pass; unlocked with a `fnox set` request for `TIDE_STATION_TOKEN`; the secrets with a due backup reminder; or a vault that hasn't answered yet (`model.vault.arrive()` brings it); `endpoints-fail` is the secrets with an `endpoints` that refuses (an MCP URL with “The vault refused {url} for this token. Check the server's address, then try again.”, a model URL with “The vault refused that endpoint. Check the address and try again.”). The dummy vault records each `endpoints` change in `model.vault.endpointChanges`.
|
|
1009
|
+
`createDummyModel({ vault: 'empty' | 'secrets' | 'policy' | 'locked' | 'request' | 'backup' | 'waiting' | 'purged' | 'endpoints-fail' | 'off' })` (`?vault=` on `/ui/`, off by default; `notice` is kept as another name for `policy`) adds an invented vault: no secrets yet; five secrets (an API key, a jerk lease from pier-nuc revealed to `pier publish`, a Tide Mail sign-in, one without a rule and a removed one) with an activity log that pages back once; the same with a refused rule and a policy change in the log; locked before the first unlock, with a waiting request from docs-pass; unlocked with a `fnox set` request for `TIDE_STATION_TOKEN`; the secrets with a due backup reminder; or a vault that hasn't answered yet (`model.vault.arrive()` brings it); Cloudflare's Account ID and AI Gateway ID and Azure's endpoint carry `vaultSetting`s; the dummy vault keeps `settings` on its records, logs each `settings` call in `model.vault.settingsCalls`, and refuses a setting whose value starts with `bad` (“The vault refused {KEY}. Check that value and try again.”). `endpoints-fail` is the secrets with an `endpoints` that refuses (an MCP URL with “The vault refused {url} for this token. Check the server's address, then try again.”, a model URL with “The vault refused that endpoint. Check the address and try again.”). The dummy vault records each `endpoints` change in `model.vault.endpointChanges`.
|
|
999
1010
|
`purged` is `secrets` plus two `endpoints` audit entries: one with `purged` and `adopted`, and one `pinned` (`DOCS_MCP_TOKEN` on docs.example) that Unpin turns into an `unpinned` entry; `vaultPurged` and `vaultPinned` are exported.
|
|
1000
1011
|
It implements every op with the vault's checks, and keeps only names: `model.vault.puts` records `{ name, request? }`, `cancelled` the cancelled requests, `imports` each import's kind, size and pick, and `exported` the exports.
|
|
1001
1012
|
Import offers five invented candidates (one replaces a secret, one is a model key, one is refused with a reason that the done stage repeats; KeePass adds a `_2` duplicate), six answers ENOTSUP, page ops are recorded with `uid: null, tag: null`, and value ops while locked answer EACCES.
|
|
@@ -1669,6 +1669,7 @@ var options = [
|
|
|
1669
1669
|
label: "Endpoint",
|
|
1670
1670
|
required: true,
|
|
1671
1671
|
customBase: true,
|
|
1672
|
+
vaultSetting: "AZURE_OPENAI_RESOURCE_NAME",
|
|
1672
1673
|
placeholder: "https://harbor.openai.azure.example",
|
|
1673
1674
|
help: "The resource\u2019s endpoint, from Keys and endpoint."
|
|
1674
1675
|
},
|
|
@@ -1689,7 +1690,14 @@ var options = [
|
|
|
1689
1690
|
label: "Account ID",
|
|
1690
1691
|
required: true,
|
|
1691
1692
|
placeholder: "3f2a9c\u2026",
|
|
1692
|
-
help: "On the right of the Workers AI page."
|
|
1693
|
+
help: "On the right of the Workers AI page.",
|
|
1694
|
+
vaultSetting: "CLOUDFLARE_ACCOUNT_ID"
|
|
1695
|
+
},
|
|
1696
|
+
{
|
|
1697
|
+
name: "gateway",
|
|
1698
|
+
label: "AI Gateway ID",
|
|
1699
|
+
placeholder: "harbor-gateway",
|
|
1700
|
+
vaultSetting: "CLOUDFLARE_GATEWAY_ID"
|
|
1693
1701
|
}
|
|
1694
1702
|
],
|
|
1695
1703
|
vaultName: "CLOUDFLARE_WORKERS_AI_API_KEY"
|
|
@@ -1941,4 +1949,4 @@ export {
|
|
|
1941
1949
|
dummySettingsKey,
|
|
1942
1950
|
DummySettings
|
|
1943
1951
|
};
|
|
1944
|
-
//# sourceMappingURL=chunk-
|
|
1952
|
+
//# sourceMappingURL=chunk-LOQJK2JE.js.map
|