@ai-ecoverse/slicc-spectrum 1.108.0 → 1.108.2

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/dist/slicc-ui.js CHANGED
@@ -63,10 +63,11 @@ import {
63
63
  define
64
64
  } from "./chunk-SQG7U2FN.js";
65
65
  import {
66
+ isPolicyPaused,
66
67
  isVaultFailure,
67
68
  nameProblem,
68
69
  valueProblem
69
- } from "./chunk-XQHRTHDQ.js";
70
+ } from "./chunk-BUSDBLS7.js";
70
71
  import {
71
72
  Emitter
72
73
  } from "./chunk-T5NHW4KC.js";
@@ -34855,6 +34856,7 @@ function widening(change, devices) {
34855
34856
  }
34856
34857
  }
34857
34858
  function failureText(error) {
34859
+ if (isPolicyPaused(error)) return "Secrets are paused until the missing policy file is back";
34858
34860
  const text4 = isVaultFailure(error) ? codeTexts[error.code] : void 0;
34859
34861
  return text4 ?? (error instanceof Error ? error.message : "The vault did not answer");
34860
34862
  }
@@ -52712,7 +52714,23 @@ var sessionTrust = {
52712
52714
  };
52713
52715
  var sessionProtocol = (protocol) => Object.hasOwn(sessionProtocols, protocol) ? sessionProtocols[protocol] : protocol;
52714
52716
  var sessionTrusted = (verifiedBy) => verifiedBy && Object.hasOwn(sessionTrust, verifiedBy) ? `${sessionTrust[verifiedBy]}, ` : "";
52715
- function auditLine(entry, devices, named2) {
52717
+ function returned(entries) {
52718
+ const paused = /* @__PURE__ */ new Set();
52719
+ const back = /* @__PURE__ */ new Map();
52720
+ for (const entry of [...entries].reverse()) {
52721
+ if (entry.type !== "policy") continue;
52722
+ if (entry.absent) paused.add(entry.file);
52723
+ else if (entry.accepted && paused.delete(entry.file)) back.set(entry.seq, paused.size === 0);
52724
+ }
52725
+ return back;
52726
+ }
52727
+ function policyHead(entry, running2) {
52728
+ if (entry.absent) return "was removed. Secrets are paused until it\u2019s back.";
52729
+ if (running2 !== void 0)
52730
+ return running2 ? "is back. Secrets are running again." : "is back. Secrets stay paused until the other file is back.";
52731
+ return entry.accepted ? "changed" : "changed and was refused";
52732
+ }
52733
+ function auditLine(entry, devices, named2, back = /* @__PURE__ */ new Map()) {
52716
52734
  switch (entry.type) {
52717
52735
  case "inject":
52718
52736
  case "forward":
@@ -52734,7 +52752,7 @@ function auditLine(entry, devices, named2) {
52734
52752
  case "refresh":
52735
52753
  return entry.grant ? b`Refreshed automatically with the sign-in <code>${entry.grant}</code>` : b`Refreshed automatically`;
52736
52754
  default:
52737
- return b`<code>${entry.file}</code> ${entry.accepted ? "changed" : "changed and was refused"}${changes(entry, devices).map(([kind, line]) => b`<span class="change" data-change=${kind}>${line}</span>`)}${entry.warning ? b`<span class="warning" data-warning>${entry.warning}</span>` : A}${entry.accepted ? b`<span class="hint" data-hint>If you didn’t mean this, change the file back with sudo.</span>` : A}`;
52755
+ return b`<code>${entry.file}</code> ${policyHead(entry, back.get(entry.seq))}${changes(entry, devices).map(([kind, line]) => b`<span class="change" data-change=${kind}>${line}</span>`)}${entry.warning ? b`<span class="warning" data-warning>${entry.warning}</span>` : A}${entry.accepted && !entry.absent && !back.has(entry.seq) ? b`<span class="hint" data-hint>If you didn’t mean this, change the file back with sudo.</span>` : A}`;
52738
52756
  }
52739
52757
  }
52740
52758
  function merged(...pages2) {
@@ -53662,24 +53680,25 @@ var SliccSecrets = class extends ThemedElement {
53662
53680
  if (this.#mine(vault)) this.unpinning = null;
53663
53681
  }
53664
53682
  }
53665
- #entry(entry, devices, vault, all2 = []) {
53683
+ #entry(entry, devices, vault, all2 = [], back) {
53666
53684
  const date = new Date(entry.at);
53667
53685
  const name = entry.type === "policy" || entry.type === "endpoints" ? null : entry.name;
53668
53686
  return b`<li data-seq=${entry.seq} data-type=${entry.type}>
53669
53687
  <time datetime=${date.toISOString()} title=${date.toLocaleString("en-GB", { dateStyle: "medium", timeStyle: "short" })}>${since(entry.at)}</time>
53670
- <span class="what">${name ? b`<code>${name}</code> · ` : A}${auditLine(entry, devices, (provider) => this.#provider(provider))}${entry.type === "policy" || entry.type === "refresh" || entry.type === "endpoints" ? A : b` <span class="by">by ${who(entry)}</span>`}${entry.type === "endpoints" && vault ? this.#unpin(vault, entry, all2) : A}</span>
53688
+ <span class="what">${name ? b`<code>${name}</code> · ` : A}${auditLine(entry, devices, (provider) => this.#provider(provider), back)}${entry.type === "policy" || entry.type === "refresh" || entry.type === "endpoints" ? A : b` <span class="by">by ${who(entry)}</span>`}${entry.type === "endpoints" && vault ? this.#unpin(vault, entry, all2) : A}</span>
53671
53689
  </li>`;
53672
53690
  }
53673
53691
  #audit(vault, list6, entries, devices) {
53674
53692
  const shown4 = this.reveals ? entries.filter((entry) => entry.type === "materialize") : entries;
53675
53693
  const more = this.more ?? list6.auditMore;
53694
+ const back = returned(entries);
53676
53695
  return b`<div class="audit-head">
53677
53696
  <h3 id="secrets-audit">Activity</h3>
53678
53697
  <sp-switch size="s" data-action="reveals" .checked=${this.reveals} @change=${(event2) => {
53679
53698
  this.reveals = event2.target.checked;
53680
53699
  }}>Only reveals to programs</sp-switch>
53681
53700
  </div>
53682
- ${shown4.length ? b`<ol class="audit" aria-labelledby="secrets-audit">${shown4.map((entry) => this.#entry(entry, devices, vault, entries))}</ol>` : b`<p class="muted" data-audit-empty>${this.reveals ? more ? "No reveals in the activity loaded so far." : "No program has been given a secret." : "Nothing has used a secret yet."}</p>`}
53701
+ ${shown4.length ? b`<ol class="audit" aria-labelledby="secrets-audit">${shown4.map((entry) => this.#entry(entry, devices, vault, entries, back))}</ol>` : b`<p class="muted" data-audit-empty>${this.reveals ? more ? "No reveals in the activity loaded so far." : "No program has been given a secret." : "Nothing has used a secret yet."}</p>`}
53683
53702
  ${more ? b`<div class="row"><swc-button size="s" variant="secondary" fill-style="outline" data-action="older" ?pending=${this.loading} @click=${() => this.showOlder(vault, entries)}>Show older</swc-button></div>` : A}`;
53684
53703
  }
53685
53704
  #feedback() {
@@ -53708,11 +53727,16 @@ var SliccSecrets = class extends ThemedElement {
53708
53727
  </div>
53709
53728
  </div>`;
53710
53729
  }
53730
+ #paused(status2) {
53731
+ const [first2, ...rest] = (status2.policy ?? []).filter((file) => file.paused);
53732
+ if (!first2) return A;
53733
+ return b`<swc-status-light size="m" variant="notice" data-paused>Paused: <code>${first2.path}</code> ${rest.length ? `and ${rest.length} more are` : "is"} missing</swc-status-light>`;
53734
+ }
53711
53735
  #header(vault, status2) {
53712
53736
  if (!status2) return A;
53713
53737
  if (this.#offline)
53714
53738
  return b`<swc-status-light size="m" variant="neutral">Waiting</swc-status-light>`;
53715
- return b`<swc-status-light size="m" variant=${status2.locked ? "notice" : "positive"}>${status2.locked ? "Locked" : "Unlocked"}</swc-status-light><span class="muted">${lockModes[status2.lock]}</span>
53739
+ return b`<swc-status-light size="m" variant=${status2.locked ? "notice" : "positive"}>${status2.locked ? "Locked" : "Unlocked"}</swc-status-light>${this.#paused(status2)}<span class="muted">${lockModes[status2.lock]}</span>
53716
53740
  <span class="controls">${status2.locked ? b`${status2.scrub?.needed && !status2.scrub.ready ? b`<span class="availability" role="status" data-availability="unlock"><swc-icon-info-circle size="s" aria-hidden="true"></swc-icon-info-circle><span>Unlock the vault to continue</span></span>` : A}${this.#button({ intent: { kind: "unlock" }, label: "Unlock", variant: "accent" }, "unlock")}` : b`${vault.lock ? b`<swc-button size="m" variant="secondary" fill-style="outline" data-action="lock" ?pending=${this.acting.has("lock")} @click=${() => this.lockVault(vault)}>Lock</swc-button>` : A}
53717
53741
  ${this.#button({ intent: { kind: "protect" }, label: status2.lock === "auto" ? "Protect with a passkey" : "Change protection" }, "protect")}`}</span>`;
53718
53742
  }
@@ -53845,6 +53869,18 @@ var removeBodies = {
53845
53869
  local: "Models from it stop working."
53846
53870
  };
53847
53871
  var serverGone = "Agents can\u2019t use it any more.";
53872
+ var serversFailure = "mcp";
53873
+ function serverLeft(account, left) {
53874
+ const url = left.some(([part2]) => part2 === "url");
53875
+ const record = left.some(([part2]) => part2 === "record");
53876
+ const held2 = account.auth === "oauth" ? "sign-in" : "token";
53877
+ const locked = left.some(
53878
+ ([, error]) => isVaultFailure(error) && error.code === "EACCES" && !isPolicyPaused(error)
53879
+ );
53880
+ const what = !url ? `its ${held2} stayed in the vault` : record ? `its ${held2} and URL stayed in the vault` : "the vault kept its URL";
53881
+ 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.";
53882
+ return `${account.provider} is removed, but ${what}. ${next}`;
53883
+ }
53848
53884
  var refusedEntry = "This entry was refused. Remove it and add it again here.";
53849
53885
  var urlSecret = "This URL contains a secret. Remove it, turn on Uses a token, and paste the token when you connect.";
53850
53886
  var sentence2 = (text4) => text4.charAt(0).toUpperCase() + text4.slice(1);
@@ -54339,6 +54375,7 @@ var SliccSettings = class extends ThemedElement {
54339
54375
  queueMicrotask(() => settleModels(model));
54340
54376
  this.removing = /* @__PURE__ */ new Set();
54341
54377
  this.refusals = {};
54378
+ if (this.failure?.id === serversFailure) this.failure = null;
54342
54379
  void this.#readRefusals(model);
54343
54380
  if (model.updates !== this.#developerPort) {
54344
54381
  this.#developerPort = model.updates;
@@ -55163,16 +55200,26 @@ var SliccSettings = class extends ThemedElement {
55163
55200
  const held2 = account.auth === "oauth" ? "sign-in" : "token";
55164
55201
  return `Its ${held2} is deleted from the vault. ${serverGone}`;
55165
55202
  }
55166
- async #clearServer(model, account) {
55203
+ #serverClear(model, account) {
55167
55204
  const vault = model.vault;
55168
55205
  const server = serverOf(account);
55169
55206
  const records = vault?.remove ? this.#serverRecords(account, vault) : [];
55170
55207
  const held2 = !!vault?.remove && this.#heldRecords(account, vault).length > 0;
55171
55208
  const pinned = !!this.#pinned(account);
55172
55209
  const url = registrations2()[server] ?? (held2 && !pinned && this.#mcpUrl(account));
55173
- for (const [name, kind] of records) await gone2(vault, name, kind);
55174
- if (url) await vault?.endpoints?.({ remove: { mcp: [{ server, url }] } });
55175
- register(server, void 0);
55210
+ return async () => {
55211
+ const left = [];
55212
+ for (const [name, kind] of records)
55213
+ await gone2(vault, name, kind).catch((error) => left.push(["record", error]));
55214
+ try {
55215
+ if (url) await vault?.endpoints?.({ remove: { mcp: [{ server, url }] } });
55216
+ register(server, void 0);
55217
+ } catch (error) {
55218
+ register(server, url);
55219
+ left.push(["url", error]);
55220
+ }
55221
+ return left;
55222
+ };
55176
55223
  }
55177
55224
  #markRemoving(id, on2) {
55178
55225
  const rest = [...this.removing].filter((candidate) => candidate !== id);
@@ -55210,10 +55257,13 @@ var SliccSettings = class extends ThemedElement {
55210
55257
  if (this.model === model) this.failure = { id, message };
55211
55258
  };
55212
55259
  try {
55213
- await this.#clearServer(model, account);
55260
+ const clear2 = this.#serverClear(model, account);
55214
55261
  const edit = await model.settings.removeServer?.(id);
55215
- if (!edit.ok) refused3(sentence2(edit.reason));
55216
- else if (this.model === model) this.focusOn("[data-action=add-server]");
55262
+ if (!edit.ok) return refused3(sentence2(edit.reason));
55263
+ const left = await clear2();
55264
+ if (this.model !== model) return;
55265
+ if (left.length) this.failure = { id: serversFailure, message: serverLeft(account, left) };
55266
+ this.focusOn("[data-action=add-server]");
55217
55267
  } catch (error) {
55218
55268
  refused3(failureText(error));
55219
55269
  }
@@ -55317,13 +55367,14 @@ var SliccSettings = class extends ThemedElement {
55317
55367
  }
55318
55368
  #serverList(servers) {
55319
55369
  const add = !!this.model?.settings.addServer;
55320
- if (!(servers.length || add)) return A;
55370
+ const failed2 = this.failure?.id === serversFailure;
55371
+ if (!(servers.length || add || failed2)) return A;
55321
55372
  return b`<h2>MCP servers</h2>
55322
55373
  <div class="accounts" data-group="mcp">${c(
55323
55374
  servers,
55324
55375
  (account) => account.id,
55325
55376
  (account) => this.#account(account)
55326
- )}</div>
55377
+ )}${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
55378
  ${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
55379
  }
55329
55380
  #notice(row, size4 = "long") {