@ai-ecoverse/slicc-spectrum 1.108.0 → 1.108.1
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 +2 -2
- package/dist/slicc-ui.js +34 -9
- package/dist/slicc-ui.js.map +3 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -438,7 +438,7 @@ Disconnect and Remove delete its key record first, as for any vault-backed key,
|
|
|
438
438
|
Every other account calls `connect` without `options`, as before.
|
|
439
439
|
Accounts with `group: 'mcp'` (MCP servers) get their own **MCP servers** heading (`.accounts[data-group=mcp]`).
|
|
440
440
|
With `settings.addServer` the heading shows even with no servers, and **Add server** (`data-action="add-server"`) opens a form (`form[data-form=add-server]`) with Name and URL (`input[data-server-field=name|url]`), **Uses a token** (`sp-switch[data-server-field=token]`, with its help line `[data-token-help]` only while it's on), **Add** (`data-action="save"`) and Cancel (`data-action="cancel"`). The page checks only the obvious, on the field (`[data-problem=name|url]`, focused): an empty field, a name outside letters, digits, `_` and `-`, a URL that isn't `https:`. Then it calls `addServer(name, { url })`, or `{ url, token: true }`: Add is pending and Cancel disabled until the answer, a refusal shows in the form and keeps what was typed (`code: 'url-secret'` on the URL field, invalid and focused, as “This URL contains a secret. Remove it, turn on Uses a token, and paste the token when you connect.”; any other `code`, or none, as `reason` with a capital first letter in `[data-problem=form]`, and a rejection there in `failureText`'s words), and `{ ok: true }` closes and resets it. The row comes with the `accounts` event, never from the answer.
|
|
441
|
-
With `settings.removeServer` every MCP row adds **Remove** (`data-action="remove-server"`, a quiet delete icon named “Remove {server}”), which asks “Remove {server}?” (“Its token is deleted from the vault. Agents can’t use it any more.”, “Its sign-in is deleted…” for OAuth, and only “Agents can’t use it any more.” when the vault holds no record for it, whatever the row's `auth`) with a destructive **Remove** and Cancel focused. It
|
|
441
|
+
With `settings.removeServer` every MCP row adds **Remove** (`data-action="remove-server"`, a quiet delete icon named “Remove {server}”), which asks “Remove {server}?” (“Its token is deleted from the vault. Agents can’t use it any more.”, “Its sign-in is deleted…” for OAuth, and only “Agents can’t use it any more.” when the vault holds no record for it, whatever the row's `auth`) with a destructive **Remove** and Cancel focused. It calls `removeServer(id)` first, since the agent decides: `{ ok: false, reason }` (with a capital first letter) or a rejection shows in the row (`.failure`), keeps it, and leaves the vault, the registration and the `slicc-spectrum.mcp-endpoints` entry as they were. Only after `{ ok: true }` does it remove the row's vault records (`MCP_<SERVER>_TOKEN` on a token row, plus any live `mcp` record of that server, which a disabled or refused row can still hold), take back the page's registration or, with none, the URL of a token it held and that isn't a pin, and drop the `slicc-spectrum.mcp-endpoints` entry; if the vault refuses to take the URL back, the entry keeps that URL, so removing the server again after adding it takes it back. It tries every step, using what the row held when Remove was confirmed, and a failure shows below the rows (`[data-failure=servers]`), because the row is about to go. The line names what stayed, with “sign-in” for “token” on an OAuth row: “{server} is removed, but its token stayed in the vault.” and “Open Secrets to remove it.”, or “Unlock the vault, then remove it under Secrets.” when the vault was locked; a URL reads “the vault kept its URL”, both read “its token and URL stayed in the vault”, and either of those ends “Add the server and remove it again.”, after “Unlock the vault, then” when locked, since Secrets can't remove a URL. The row reads **Removing…** with its buttons disabled until an `accounts` event no longer lists it. There is no edit: remove and add again.
|
|
442
442
|
`Account.state` shows on MCP rows in words, after **Token rejected** and **Sign-in expired**: `connecting` **Connecting…**, `needs-secret` **Needs a token**, `needs-auth` **Needs sign-in**, `failed` **Couldn’t connect**, `disabled` **Disabled**, `refused` **Refused**, `connected` as `status`, and rows with no `state` as before. A row with `auth: 'local'`, `state: 'disabled'` or `state: 'refused'` has no sign-in, so it offers neither Connect nor Disconnect nor the moved note, whatever its `status`; a token or OAuth row that failed keeps Connect, which is how a new token gets in. A refused row shows its reason from `settings.refusals()` with a capital first letter (`[data-refusal]`), read again on every `accounts` event while a row is refused, or “This entry was refused. Remove it and add it again here.” when the method is missing, fails or has no entry for it, in the host's place, after the host when it has one.
|
|
443
443
|
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**.
|
|
444
444
|
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`.
|
|
@@ -791,7 +791,7 @@ Theme, model, thinking level, composer and diff preferences, the models on offer
|
|
|
791
791
|
A model can say it is its provider's `default`.
|
|
792
792
|
Emit `settings` or `accounts` when the models on offer change.
|
|
793
793
|
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.
|
|
794
|
-
The optional `addServer(name, entry)` and `removeServer(id)` exist only on the owner's connection and answer `McpEdit` (`{ ok: true }` or `{ ok: false, code?, reason }`, an answer and not a rejection, with nothing written; `code` is an `McpRefusalCode`); `name` is the `mcp.json` key, `entry` is `{ url, token? }` plus any `mcp.json` field, `id` is the row's `mcp:<server>`, and the row changes with the `accounts` event once the file watch reconciles. `removeServer` forgets the server's local OAuth state only; the vault records and the page's registration are Settings' to remove
|
|
794
|
+
The optional `addServer(name, entry)` and `removeServer(id)` exist only on the owner's connection and answer `McpEdit` (`{ ok: true }` or `{ ok: false, code?, reason }`, an answer and not a rejection, with nothing written; `code` is an `McpRefusalCode`); `name` is the `mcp.json` key, `entry` is `{ url, token? }` plus any `mcp.json` field, `id` is the row's `mcp:<server>`, and the row changes with the `accounts` event once the file watch reconciles. `removeServer` forgets the server's local OAuth state only; the vault records and the page's registration are Settings' to remove once it answers `{ ok: true }`. The optional owner-only `refusals()` answers `{ [server]: { code, reason } }` for the refused entries, which aren't on the replicated rows. `Account.state` (`McpState`: `connecting`, `connected`, `needs-secret`, `needs-auth`, `failed`, `disabled` or `refused`) says how an MCP server is doing, and `auth: 'local'` on one means it has no sign-in; `identity` is its host (`''` for a refused entry with no URL), and `url` has no user, password, query or fragment.
|
|
795
795
|
`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'`).
|
|
796
796
|
|
|
797
797
|
#### `changes` (optional)
|
package/dist/slicc-ui.js
CHANGED
|
@@ -53845,6 +53845,16 @@ var removeBodies = {
|
|
|
53845
53845
|
local: "Models from it stop working."
|
|
53846
53846
|
};
|
|
53847
53847
|
var serverGone = "Agents can\u2019t use it any more.";
|
|
53848
|
+
var serversFailure = "mcp";
|
|
53849
|
+
function serverLeft(account, left) {
|
|
53850
|
+
const url = left.some(([part2]) => part2 === "url");
|
|
53851
|
+
const record = left.some(([part2]) => part2 === "record");
|
|
53852
|
+
const held2 = account.auth === "oauth" ? "sign-in" : "token";
|
|
53853
|
+
const locked = left.some(([, error]) => isVaultFailure(error) && error.code === "EACCES");
|
|
53854
|
+
const what = !url ? `its ${held2} stayed in the vault` : record ? `its ${held2} and URL stayed in the vault` : "the vault kept its URL";
|
|
53855
|
+
const next = url ? locked ? "Unlock the vault, then add the server and remove it again." : "Add the server and remove it again." : locked ? "Unlock the vault, then remove it under Secrets." : "Open Secrets to remove it.";
|
|
53856
|
+
return `${account.provider} is removed, but ${what}. ${next}`;
|
|
53857
|
+
}
|
|
53848
53858
|
var refusedEntry = "This entry was refused. Remove it and add it again here.";
|
|
53849
53859
|
var urlSecret = "This URL contains a secret. Remove it, turn on Uses a token, and paste the token when you connect.";
|
|
53850
53860
|
var sentence2 = (text4) => text4.charAt(0).toUpperCase() + text4.slice(1);
|
|
@@ -54339,6 +54349,7 @@ var SliccSettings = class extends ThemedElement {
|
|
|
54339
54349
|
queueMicrotask(() => settleModels(model));
|
|
54340
54350
|
this.removing = /* @__PURE__ */ new Set();
|
|
54341
54351
|
this.refusals = {};
|
|
54352
|
+
if (this.failure?.id === serversFailure) this.failure = null;
|
|
54342
54353
|
void this.#readRefusals(model);
|
|
54343
54354
|
if (model.updates !== this.#developerPort) {
|
|
54344
54355
|
this.#developerPort = model.updates;
|
|
@@ -55163,16 +55174,26 @@ var SliccSettings = class extends ThemedElement {
|
|
|
55163
55174
|
const held2 = account.auth === "oauth" ? "sign-in" : "token";
|
|
55164
55175
|
return `Its ${held2} is deleted from the vault. ${serverGone}`;
|
|
55165
55176
|
}
|
|
55166
|
-
|
|
55177
|
+
#serverClear(model, account) {
|
|
55167
55178
|
const vault = model.vault;
|
|
55168
55179
|
const server = serverOf(account);
|
|
55169
55180
|
const records = vault?.remove ? this.#serverRecords(account, vault) : [];
|
|
55170
55181
|
const held2 = !!vault?.remove && this.#heldRecords(account, vault).length > 0;
|
|
55171
55182
|
const pinned = !!this.#pinned(account);
|
|
55172
55183
|
const url = registrations2()[server] ?? (held2 && !pinned && this.#mcpUrl(account));
|
|
55173
|
-
|
|
55174
|
-
|
|
55175
|
-
|
|
55184
|
+
return async () => {
|
|
55185
|
+
const left = [];
|
|
55186
|
+
for (const [name, kind] of records)
|
|
55187
|
+
await gone2(vault, name, kind).catch((error) => left.push(["record", error]));
|
|
55188
|
+
try {
|
|
55189
|
+
if (url) await vault?.endpoints?.({ remove: { mcp: [{ server, url }] } });
|
|
55190
|
+
register(server, void 0);
|
|
55191
|
+
} catch (error) {
|
|
55192
|
+
register(server, url);
|
|
55193
|
+
left.push(["url", error]);
|
|
55194
|
+
}
|
|
55195
|
+
return left;
|
|
55196
|
+
};
|
|
55176
55197
|
}
|
|
55177
55198
|
#markRemoving(id, on2) {
|
|
55178
55199
|
const rest = [...this.removing].filter((candidate) => candidate !== id);
|
|
@@ -55210,10 +55231,13 @@ var SliccSettings = class extends ThemedElement {
|
|
|
55210
55231
|
if (this.model === model) this.failure = { id, message };
|
|
55211
55232
|
};
|
|
55212
55233
|
try {
|
|
55213
|
-
|
|
55234
|
+
const clear2 = this.#serverClear(model, account);
|
|
55214
55235
|
const edit = await model.settings.removeServer?.(id);
|
|
55215
|
-
if (!edit.ok) refused3(sentence2(edit.reason));
|
|
55216
|
-
|
|
55236
|
+
if (!edit.ok) return refused3(sentence2(edit.reason));
|
|
55237
|
+
const left = await clear2();
|
|
55238
|
+
if (this.model !== model) return;
|
|
55239
|
+
if (left.length) this.failure = { id: serversFailure, message: serverLeft(account, left) };
|
|
55240
|
+
this.focusOn("[data-action=add-server]");
|
|
55217
55241
|
} catch (error) {
|
|
55218
55242
|
refused3(failureText(error));
|
|
55219
55243
|
}
|
|
@@ -55317,13 +55341,14 @@ var SliccSettings = class extends ThemedElement {
|
|
|
55317
55341
|
}
|
|
55318
55342
|
#serverList(servers) {
|
|
55319
55343
|
const add = !!this.model?.settings.addServer;
|
|
55320
|
-
|
|
55344
|
+
const failed2 = this.failure?.id === serversFailure;
|
|
55345
|
+
if (!(servers.length || add || failed2)) return A;
|
|
55321
55346
|
return b`<h2>MCP servers</h2>
|
|
55322
55347
|
<div class="accounts" data-group="mcp">${c(
|
|
55323
55348
|
servers,
|
|
55324
55349
|
(account) => account.id,
|
|
55325
55350
|
(account) => this.#account(account)
|
|
55326
|
-
)}</div>
|
|
55351
|
+
)}${failed2 ? b`<div class="failure" role="alert" data-failure="servers"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${this.failure?.message}</span></div>` : A}</div>
|
|
55327
55352
|
${add && this.serverOpen ? this.#serverForm() : add ? b`<div class="add"><swc-action-button size="m" quiet data-action="add-server" @click=${() => this.#openServerForm()}><swc-icon-add slot="icon"></swc-icon-add>Add server</swc-action-button></div>` : A}`;
|
|
55328
55353
|
}
|
|
55329
55354
|
#notice(row, size4 = "long") {
|