@ai-ecoverse/slicc-spectrum 1.35.0 → 1.36.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/dist/slicc-ui.js CHANGED
@@ -8636,6 +8636,9 @@ var ModelElement = class extends i2 {
8636
8636
  this.#off = [];
8637
8637
  }
8638
8638
  };
8639
+ function changesOf(model) {
8640
+ return model.changes ?? model.files;
8641
+ }
8639
8642
  function resolveColor(scheme, prefersDark) {
8640
8643
  if (scheme === "system") return prefersDark ? "dark" : "light";
8641
8644
  return scheme;
@@ -9240,6 +9243,11 @@ var dialogStyles = i`
9240
9243
  --mod-alert-dialog-description-to-buttons: var(--swc-spacing-500);
9241
9244
  --system-alert-dialog-divider-background-color: transparent;
9242
9245
  }
9246
+ @media (max-width: 512px) {
9247
+ sp-alert-dialog {
9248
+ --mod-alert-dialog-min-width: calc(100vw - 2 * var(--swc-spacing-300));
9249
+ }
9250
+ }
9243
9251
  p {
9244
9252
  margin: 0;
9245
9253
  }
@@ -9253,7 +9261,7 @@ var dialogStyles = i`
9253
9261
  }
9254
9262
  `;
9255
9263
  var SliccConfirm = class extends i2 {
9256
- static properties = { heading: {}, body: {}, action: {}, variant: {} };
9264
+ static properties = { heading: {}, body: {}, action: {}, variant: {}, cancel: {} };
9257
9265
  trigger = null;
9258
9266
  #result = Promise.withResolvers();
9259
9267
  constructor() {
@@ -9262,6 +9270,7 @@ var SliccConfirm = class extends i2 {
9262
9270
  this.body = "";
9263
9271
  this.action = "";
9264
9272
  this.variant = "destructive";
9273
+ this.cancel = "Cancel";
9265
9274
  }
9266
9275
  static styles = dialogStyles;
9267
9276
  get result() {
@@ -9290,7 +9299,7 @@ var SliccConfirm = class extends i2 {
9290
9299
  <sp-alert-dialog variant=${this.variant}>
9291
9300
  <h2 id="title" slot="heading">${this.heading}</h2>
9292
9301
  <p id="body">${this.body}</p>
9293
- <swc-button slot="button" variant="secondary" fill-style="outline" data-cancel @click=${() => this.#dialog.close()}>Cancel</swc-button>
9302
+ <swc-button slot="button" variant="secondary" fill-style="outline" data-cancel @click=${() => this.#dialog.close()}>${this.cancel}</swc-button>
9294
9303
  <swc-button
9295
9304
  slot="button"
9296
9305
  variant=${this.variant === "destructive" ? "negative" : "accent"}
@@ -9309,6 +9318,7 @@ function confirm(options) {
9309
9318
  element2.body = options.body;
9310
9319
  element2.action = options.action;
9311
9320
  element2.variant = options.variant ?? "destructive";
9321
+ element2.cancel = options.cancel ?? "Cancel";
9312
9322
  element2.trigger = trigger2;
9313
9323
  themeOf(trigger2).append(element2);
9314
9324
  return element2.result;
@@ -9992,6 +10002,9 @@ function agentName(model, id) {
9992
10002
  if (!id) return "you";
9993
10003
  return model?.agent.list().find((agent) => agent.id === id)?.name ?? id;
9994
10004
  }
10005
+ function author(model, change) {
10006
+ return change.agentId === null && change.repo ? null : agentName(model, change.agentId);
10007
+ }
9995
10008
  function request(target, type, path) {
9996
10009
  target.dispatchEvent(new CustomEvent(type, { detail: { path }, bubbles: true, composed: true }));
9997
10010
  }
@@ -10074,6 +10087,25 @@ function statusMark(status2, announce = true) {
10074
10087
  function failure(error) {
10075
10088
  return error instanceof Error ? error.message : String(error);
10076
10089
  }
10090
+ var errorCss = i`
10091
+ .error {
10092
+ display: flex;
10093
+ align-items: flex-start;
10094
+ gap: var(--swc-spacing-75);
10095
+ flex: none;
10096
+ color: var(--swc-negative-content-color-default);
10097
+ background: var(--swc-background-layer-1-color);
10098
+ white-space: normal;
10099
+ }
10100
+ .error:not(:empty) {
10101
+ padding: var(--swc-spacing-75) var(--swc-spacing-100) var(--swc-spacing-75) var(--swc-spacing-200);
10102
+ border-bottom: var(--swc-border-width-100) solid var(--swc-gray-200);
10103
+ }
10104
+ .error swc-icon-alert-diamond {
10105
+ flex: none;
10106
+ color: var(--swc-negative-content-color-default);
10107
+ }
10108
+ `;
10077
10109
  var SliccFiles = class extends ModelElement {
10078
10110
  static properties = {
10079
10111
  ...ModelElement.properties,
@@ -10101,6 +10133,7 @@ var SliccFiles = class extends ModelElement {
10101
10133
  static styles = [
10102
10134
  shared,
10103
10135
  panelCss,
10136
+ errorCss,
10104
10137
  i`
10105
10138
  :host {
10106
10139
  container-type: inline-size;
@@ -10117,23 +10150,6 @@ var SliccFiles = class extends ModelElement {
10117
10150
  .mount {
10118
10151
  flex: none;
10119
10152
  }
10120
- .error {
10121
- display: flex;
10122
- align-items: flex-start;
10123
- gap: var(--swc-spacing-75);
10124
- flex: none;
10125
- color: var(--swc-negative-content-color-default);
10126
- background: var(--swc-background-layer-1-color);
10127
- white-space: normal;
10128
- }
10129
- .error:not(:empty) {
10130
- padding: var(--swc-spacing-75) var(--swc-spacing-100) var(--swc-spacing-75) var(--swc-spacing-200);
10131
- border-bottom: var(--swc-border-width-100) solid var(--swc-gray-200);
10132
- }
10133
- .error swc-icon-alert-diamond {
10134
- flex: none;
10135
- color: var(--swc-negative-content-color-default);
10136
- }
10137
10153
  .mounts {
10138
10154
  flex: none;
10139
10155
  display: flex;
@@ -10190,7 +10206,7 @@ var SliccFiles = class extends ModelElement {
10190
10206
  this.#mounts(model.files);
10191
10207
  return [
10192
10208
  model.files.on("files", (entries) => this.#load(entries)),
10193
- model.files.on("changes", () => this.#sync()),
10209
+ changesOf(model).on("changes", () => this.#sync()),
10194
10210
  model.files.on("mounts", () => this.#mounts(model.files))
10195
10211
  ];
10196
10212
  }
@@ -10212,7 +10228,7 @@ var SliccFiles = class extends ModelElement {
10212
10228
  }
10213
10229
  #sync() {
10214
10230
  const tree = this.#tree();
10215
- const changes = this.model?.files.changes() ?? [];
10231
+ const changes = this.model ? changesOf(this.model).changes() : [];
10216
10232
  if (!tree) return;
10217
10233
  if (tree.paths.length === 0) tree.expanded = ancestors(changes.map((change) => change.path));
10218
10234
  tree.paths = treePaths(this.#entries);
@@ -10457,7 +10473,7 @@ var SliccFileView = class extends ThemedElement {
10457
10473
  model.files.on("file", (path) => {
10458
10474
  if (path === this.path) void this.#read(model);
10459
10475
  }),
10460
- model.files.on("changes", () => this.requestUpdate())
10476
+ changesOf(model).on("changes", () => this.requestUpdate())
10461
10477
  ];
10462
10478
  }
10463
10479
  async #read(model) {
@@ -10470,12 +10486,14 @@ var SliccFileView = class extends ThemedElement {
10470
10486
  }
10471
10487
  }
10472
10488
  render() {
10473
- const change = this.model?.files.changes().find((candidate) => candidate.path === this.path);
10489
+ const port = this.model ? changesOf(this.model) : null;
10490
+ const change = port && !port.unavailable?.() ? port.changes().find((candidate) => candidate.path === this.path) : void 0;
10491
+ const by = change && author(this.model, change);
10474
10492
  return b`<div class="bar">
10475
10493
  <span class="path" title=${this.path}>${this.path}</span>
10476
10494
  <span class="spacer"></span>
10477
10495
  ${change ? b`${statusMark(change.status, false)}
10478
- <span>${statusLabels[change.status]} by ${agentName(this.model, change.agentId)}</span>
10496
+ <span>${by ? `${statusLabels[change.status]} by ${by}` : statusLabels[change.status]}</span>
10479
10497
  <swc-action-button size="s" quiet @click=${() => request(this, "open-diff", this.path)}>
10480
10498
  <swc-icon-compare slot="icon"></swc-icon-compare>Diff
10481
10499
  </swc-action-button>` : A}
@@ -10599,8 +10617,12 @@ var routes = {
10599
10617
  var automation = {
10600
10618
  extension: "Browser automation: through the SLICC extension.",
10601
10619
  proxy: "Browser automation: through slicc-node.",
10602
- none: "Browser automation: not available. Install the extension or run slicc-node."
10620
+ none: "Browser automation: not available. Install the extension or run slicc-node.",
10621
+ declined: "Browser automation: off for this session. You declined it; reload to be asked again."
10603
10622
  };
10623
+ function automationOf(browser) {
10624
+ return browser.declined ? "declined" : browser.via ?? "none";
10625
+ }
10604
10626
  function networkLabel(status2) {
10605
10627
  return `Network: ${networkHealth[status2.health][1].toLowerCase()}`;
10606
10628
  }
@@ -10831,7 +10853,7 @@ var SliccNetwork = class extends ModelElement {
10831
10853
  </div>
10832
10854
  <p data-route=${status2.route ?? "none"}>${routes[status2.route ?? "none"]}</p>
10833
10855
  ${status2.detail ? b`<p class="detail">${status2.detail}</p>` : A}
10834
- ${status2.browser ? b`<p data-browser=${status2.browser.via ?? "none"}>${automation[status2.browser.via ?? "none"]}${status2.browser.detail ? b` <span class="detail">${status2.browser.detail}</span>` : A}</p>` : A}
10856
+ ${status2.browser ? b`<p data-browser=${automationOf(status2.browser)} class=${status2.browser.declined ? "muted" : ""}>${automation[automationOf(status2.browser)]}${status2.browser.detail ? b` <span class="detail">${status2.browser.detail}</span>` : A}</p>` : A}
10835
10857
  ${this.model?.network?.check ? b`<div class="actions"><swc-button size="m" variant="secondary" data-action="check" ?pending=${this.checking} @click=${() => this.check()}>Check again</swc-button></div>` : A}
10836
10858
  ${this.error ? b`<div class="error" role="alert"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${this.error}</span></div>` : A}
10837
10859
  </section>`;
@@ -14981,7 +15003,7 @@ var SliccApp = class extends ThemedElement {
14981
15003
  margin-inline-end: var(--swc-spacing-200);
14982
15004
  }
14983
15005
  :host([screen='phone']) header sp-picker {
14984
- min-width: 0;
15006
+ min-width: calc(var(--swc-spacing-400) * 4);
14985
15007
  width: 0;
14986
15008
  flex: 1;
14987
15009
  }
@@ -15033,7 +15055,7 @@ var SliccApp = class extends ThemedElement {
15033
15055
  }
15034
15056
  update();
15035
15057
  }),
15036
- model.files.on("changes", update),
15058
+ changesOf(model).on("changes", update),
15037
15059
  model.terminals.on("terminals", () => {
15038
15060
  this.#prune();
15039
15061
  update();
@@ -15120,10 +15142,12 @@ var SliccApp = class extends ThemedElement {
15120
15142
  if (!port || !this.#offers("updates")) return;
15121
15143
  const change = this.#updatesVisibility?.change(port, layout);
15122
15144
  if (change === "open") {
15123
- if (this.dock.has("updates")) this.dock.reveal("updates");
15124
- else {
15125
- this.show("updates");
15126
- if (!port.ready()) this.dock.api.getPanel("updates")?.api.updateParameters({ boot: true });
15145
+ const restored = this.dock.api.getPanel("updates");
15146
+ if (restored) this.dock.reveal("updates");
15147
+ else this.show("updates");
15148
+ if (!port.ready() && restored?.params?.boot !== false) {
15149
+ this.dock.api.getPanel("updates")?.api.updateParameters({ boot: true });
15150
+ this.#save();
15127
15151
  }
15128
15152
  } else if (this.dock.api.getPanel("updates")?.params?.boot && port.ready() && !port.list().some((item2) => item2.state === "failed")) {
15129
15153
  this.dock.close("updates");
@@ -15281,7 +15305,8 @@ var SliccApp = class extends ThemedElement {
15281
15305
  return changes ? b`<span class="badged">${button}<swc-badge size="s" variant="neutral" aria-hidden="true">${changes}</swc-badge></span>${tooltip}` : b`${button}${tooltip}`;
15282
15306
  }
15283
15307
  #changes() {
15284
- return this.model?.files.changes().length ?? 0;
15308
+ const port = this.model ? changesOf(this.model) : null;
15309
+ return port && !port.unavailable?.() ? port.changes().length : 0;
15285
15310
  }
15286
15311
  #more(items) {
15287
15312
  if (!items.length) return A;
@@ -15399,8 +15424,9 @@ var SliccApp = class extends ThemedElement {
15399
15424
  if (!updates) return A;
15400
15425
  const text2 = updates[0].toUpperCase() + updates.slice(1);
15401
15426
  return b`<swc-action-button id="updates" quiet size="s" data-updates accessible-label=${`Install / Update: ${updates}`} @click=${() => this.show("updates")}>
15402
- <swc-status-light size="s" variant=${updatesVariant(updates)}>${text2}</swc-status-light>
15403
- </swc-action-button>`;
15427
+ <swc-status-light size="s" variant=${updatesVariant(updates)}>${this.screen === "phone" ? A : text2}</swc-status-light>
15428
+ </swc-action-button>
15429
+ <swc-tooltip for="updates" placement="bottom">${text2}</swc-tooltip>`;
15404
15430
  }
15405
15431
  #networkIndicator() {
15406
15432
  const port = this.model?.network;
@@ -16746,15 +16772,50 @@ var layouts = [
16746
16772
  function folder(path) {
16747
16773
  return path.slice(0, path.lastIndexOf("/")) || "/";
16748
16774
  }
16749
- var confirmRevert = (path) => confirm({
16750
- title: `Revert ${basename(path)}?`,
16751
- body: `This discards the agent\u2019s edits to ${path}. You can\u2019t undo this.`,
16752
- action: "Revert"
16753
- });
16775
+ function where(change) {
16776
+ const at = folder(change.path);
16777
+ if (!change.repo) return at;
16778
+ if (at === change.repo) return "";
16779
+ return at.startsWith(`${change.repo}/`) ? at.slice(change.repo.length + 1) : at;
16780
+ }
16781
+ function lost(changes) {
16782
+ const kind = changes.every((change) => change.repo) ? "uncommitted" : "pending";
16783
+ return `${changes.length === 1 ? "Its" : "Their"} ${kind} changes are discarded and can\u2019t be undone.`;
16784
+ }
16785
+ var confirmRevert = (change) => confirm({ title: `Revert ${basename(change.path)}?`, body: lost([change]), action: "Revert" });
16786
+ async function revertPaths(port, paths) {
16787
+ const errors = [];
16788
+ for (const path of paths) {
16789
+ try {
16790
+ await port.revert(path);
16791
+ } catch (error) {
16792
+ errors.push(failure(error));
16793
+ }
16794
+ }
16795
+ if (errors.length > 1) return `Couldn\u2019t revert ${errors.length} files. ${errors[0]}`;
16796
+ return errors[0] ?? "";
16797
+ }
16798
+ function groups(changes) {
16799
+ const byRepo = /* @__PURE__ */ new Map();
16800
+ for (const change of changes) {
16801
+ const key2 = change.repo ?? "";
16802
+ byRepo.set(key2, [...byRepo.get(key2) ?? [], change]);
16803
+ }
16804
+ return [...byRepo];
16805
+ }
16806
+ function errorLine(error) {
16807
+ return b`<div class="error" role="status" aria-live="polite">${error ? b`<swc-icon-alert-diamond size="s" aria-hidden="true"></swc-icon-alert-diamond><span>${error}</span>` : A}</div>`;
16808
+ }
16754
16809
  var SliccChanges = class extends ModelElement {
16810
+ static properties = { ...ModelElement.properties, error: { state: true } };
16811
+ constructor() {
16812
+ super();
16813
+ this.error = "";
16814
+ }
16755
16815
  static styles = [
16756
16816
  shared,
16757
16817
  panelCss,
16818
+ errorCss,
16758
16819
  i`
16759
16820
  ul {
16760
16821
  list-style: none;
@@ -16764,7 +16825,24 @@ var SliccChanges = class extends ModelElement {
16764
16825
  flex: 1;
16765
16826
  min-height: 0;
16766
16827
  }
16767
- li {
16828
+ ul ul {
16829
+ padding: 0;
16830
+ overflow: visible;
16831
+ }
16832
+ .repo {
16833
+ display: flex;
16834
+ gap: var(--swc-spacing-100);
16835
+ padding: var(--swc-spacing-100) var(--swc-spacing-200) var(--swc-spacing-50);
16836
+ font-size: var(--swc-font-size-75);
16837
+ font-weight: var(--swc-bold-font-weight);
16838
+ color: var(--swc-neutral-subdued-content-color-default);
16839
+ }
16840
+ .repo span:first-child {
16841
+ overflow: hidden;
16842
+ text-overflow: ellipsis;
16843
+ white-space: nowrap;
16844
+ }
16845
+ li[data-path] {
16768
16846
  display: grid;
16769
16847
  grid-template-columns: auto minmax(0, auto) minmax(0, 1fr) auto;
16770
16848
  align-items: center;
@@ -16773,11 +16851,11 @@ var SliccChanges = class extends ModelElement {
16773
16851
  padding: 0 var(--swc-spacing-75) 0 var(--swc-spacing-200);
16774
16852
  cursor: pointer;
16775
16853
  }
16776
- li:hover,
16777
- li:focus-within {
16854
+ li[data-path]:hover,
16855
+ li[data-path]:focus-within {
16778
16856
  background: var(--swc-gray-100);
16779
16857
  }
16780
- li:focus-visible {
16858
+ li[data-path]:focus-visible {
16781
16859
  outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
16782
16860
  outline-offset: calc(-1 * var(--swc-focus-indicator-thickness));
16783
16861
  }
@@ -16797,12 +16875,12 @@ var SliccChanges = class extends ModelElement {
16797
16875
  display: flex;
16798
16876
  visibility: hidden;
16799
16877
  }
16800
- li:hover .actions,
16801
- li:focus-within .actions {
16878
+ li[data-path]:hover .actions,
16879
+ li[data-path]:focus-within .actions {
16802
16880
  visibility: visible;
16803
16881
  }
16804
16882
  @media (hover: none), (pointer: coarse) {
16805
- li {
16883
+ li[data-path] {
16806
16884
  min-height: var(--swc-component-height-200);
16807
16885
  }
16808
16886
  .actions {
@@ -16812,33 +16890,41 @@ var SliccChanges = class extends ModelElement {
16812
16890
  `
16813
16891
  ];
16814
16892
  subscribe(model) {
16815
- return [model.files.on("changes", () => this.requestUpdate())];
16893
+ return [changesOf(model).on("changes", () => this.requestUpdate())];
16816
16894
  }
16817
16895
  focus() {
16818
- this.focusOn("li");
16896
+ this.focusOn("li[data-path]");
16897
+ }
16898
+ #port() {
16899
+ return changesOf(this.model);
16819
16900
  }
16820
16901
  #accept(event2, path) {
16821
16902
  event2.stopPropagation();
16822
- this.model?.files.accept(path);
16903
+ this.#port().accept(path);
16823
16904
  }
16824
- async #revert(event2, path) {
16905
+ async #revert(event2, change) {
16825
16906
  event2.stopPropagation();
16826
- if (await confirmRevert(path)) await this.model?.files.revert(path);
16907
+ this.error = "";
16908
+ if (await confirmRevert(change)) this.error = await revertPaths(this.#port(), [change.path]);
16827
16909
  }
16828
16910
  async #all(action) {
16829
- const files = this.model?.files;
16830
- const changes = files?.changes() ?? [];
16911
+ const port = this.#port();
16912
+ const changes = port.changes();
16913
+ this.error = "";
16914
+ if (action === "accept") {
16915
+ for (const change of changes) port.accept(change.path);
16916
+ return;
16917
+ }
16831
16918
  const count = changes.length;
16832
16919
  const title = `Revert ${count} ${count === 1 ? "change" : "changes"}?`;
16833
- const body4 = "This discards the agents\u2019 edits and puts every file back. You can\u2019t undo this.";
16834
- if (action === "revert" && !await confirm({ title, body: body4, action: "Revert all" })) return;
16835
- for (const change of changes) {
16836
- if (action === "accept") files?.accept(change.path);
16837
- else void files?.revert(change.path);
16838
- }
16920
+ if (await confirm({ title, body: lost(changes), action: "Revert all" }))
16921
+ this.error = await revertPaths(
16922
+ port,
16923
+ changes.map((change) => change.path)
16924
+ );
16839
16925
  }
16840
16926
  #keydown(event2) {
16841
- const items = [...this.renderRoot.querySelectorAll("li")];
16927
+ const items = [...this.renderRoot.querySelectorAll("li[data-path]")];
16842
16928
  const index = items.indexOf(this.renderRoot.activeElement);
16843
16929
  if (index < 0) return;
16844
16930
  const moves = {
@@ -16856,15 +16942,17 @@ var SliccChanges = class extends ModelElement {
16856
16942
  }
16857
16943
  }
16858
16944
  #row(change) {
16945
+ const by = author(this.model, change);
16946
+ const at = where(change);
16859
16947
  return b`<li
16860
16948
  tabindex="0"
16861
16949
  data-path=${change.path}
16862
- title=${`${change.path}, ${change.status} by ${agentName(this.model, change.agentId)}`}
16950
+ title=${`${change.path}, ${change.status}${by ? ` by ${by}` : ""}`}
16863
16951
  @click=${() => request(this, "open-diff", change.path)}
16864
16952
  >
16865
16953
  ${statusMark(change.status)}
16866
16954
  <span class="name">${basename(change.path)}</span>
16867
- <span class="where"><bdi>${folder(change.path)} · ${agentName(this.model, change.agentId)}</bdi></span>
16955
+ <span class="where"><bdi>${[at, by].filter(Boolean).join(" \xB7 ")}</bdi></span>
16868
16956
  <span class="actions">
16869
16957
  <swc-action-button
16870
16958
  size="xs"
@@ -16880,33 +16968,53 @@ var SliccChanges = class extends ModelElement {
16880
16968
  quiet
16881
16969
  accessible-label=${`Revert ${basename(change.path)}`}
16882
16970
  title="Revert"
16883
- @click=${(event2) => this.#revert(event2, change.path)}
16971
+ @click=${(event2) => this.#revert(event2, change)}
16884
16972
  >
16885
16973
  <swc-icon-revert slot="icon"></swc-icon-revert>
16886
16974
  </swc-action-button>
16887
16975
  </span>
16888
16976
  </li>`;
16889
16977
  }
16978
+ #list(changes) {
16979
+ const grouped = groups(changes);
16980
+ if (grouped.length < 2)
16981
+ return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${changes.map((change) => this.#row(change))}</ul>`;
16982
+ return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${grouped.map(
16983
+ ([repo, items]) => b`<li data-repo=${repo}>
16984
+ <div class="repo" title=${repo}>
16985
+ <span>${repo || "Outside a repository"}</span>
16986
+ <span>${items.length}</span>
16987
+ </div>
16988
+ <ul aria-label=${repo || "Outside a repository"}>${items.map((change) => this.#row(change))}</ul>
16989
+ </li>`
16990
+ )}</ul>`;
16991
+ }
16890
16992
  render() {
16891
- const changes = this.model?.files.changes() ?? [];
16993
+ const port = this.model ? changesOf(this.model) : null;
16994
+ const unavailable = port?.unavailable?.() ?? null;
16995
+ if (unavailable) return b`<div class="note" data-unavailable>${unavailable}</div>`;
16996
+ const changes = port?.changes() ?? [];
16892
16997
  return b`<div class="bar">
16893
16998
  <span>${changes.length} pending ${changes.length === 1 ? "change" : "changes"}</span>
16894
16999
  <span class="spacer"></span>
16895
17000
  ${changes.length ? b`<swc-action-button size="s" quiet @click=${() => this.#all("accept")}>Accept all</swc-action-button>
16896
17001
  <swc-action-button size="s" quiet @click=${() => this.#all("revert")}>Revert all</swc-action-button>` : A}
16897
17002
  </div>
16898
- ${changes.length ? b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${changes.map((change) => this.#row(change))}</ul>` : b`<div class="note">No pending changes. Edits by agents show up here for review.</div>`}`;
17003
+ ${errorLine(this.error)}
17004
+ ${changes.length ? this.#list(changes) : b`<div class="note">No pending changes. Edits by agents show up here for review.</div>`}`;
16899
17005
  }
16900
17006
  };
16901
17007
  var SliccDiffPanel = class extends ThemedElement {
16902
- static properties = { ...ThemedElement.properties, path: {} };
17008
+ static properties = { ...ThemedElement.properties, path: {}, error: { state: true } };
16903
17009
  constructor() {
16904
17010
  super();
16905
17011
  this.path = "";
17012
+ this.error = "";
16906
17013
  }
16907
17014
  static styles = [
16908
17015
  shared,
16909
17016
  panelCss,
17017
+ errorCss,
16910
17018
  i`
16911
17019
  slicc-diff-view {
16912
17020
  flex: 1;
@@ -16928,17 +17036,34 @@ var SliccDiffPanel = class extends ThemedElement {
16928
17036
  `
16929
17037
  ];
16930
17038
  subscribe(model) {
16931
- return [...super.subscribe(model), model.files.on("changes", () => this.requestUpdate())];
17039
+ return [...super.subscribe(model), changesOf(model).on("changes", () => this.requestUpdate())];
16932
17040
  }
16933
- async #revert() {
16934
- if (await confirmRevert(this.path)) await this.model?.files.revert(this.path);
17041
+ async #revert(port, change) {
17042
+ this.error = "";
17043
+ if (await confirmRevert(change)) this.error = await revertPaths(port, [this.path]);
17044
+ }
17045
+ #body(change, style) {
17046
+ if (change.before === null && change.after === null) {
17047
+ return b`<div class="note" data-diff="none">
17048
+ No diff for this file: it’s binary or over 1 MB.
17049
+ ${change.status === "deleted" ? A : b`<swc-action-button size="s" quiet @click=${() => request(this, "open-file", this.path)}>Open the file</swc-action-button>`}
17050
+ </div>`;
17051
+ }
17052
+ return b`<slicc-diff-view
17053
+ path=${this.path}
17054
+ color=${this.color}
17055
+ diff-style=${style}
17056
+ .oldText=${change.before}
17057
+ .newText=${change.after}
17058
+ ></slicc-diff-view>`;
16935
17059
  }
16936
17060
  #style(style) {
16937
17061
  this.model?.settings.update({ diffStyle: style });
16938
17062
  }
16939
17063
  render() {
16940
17064
  const model = this.model;
16941
- const change = model?.files.changes().find((candidate) => candidate.path === this.path);
17065
+ const port = model ? changesOf(model) : null;
17066
+ const change = port?.changes().find((candidate) => candidate.path === this.path);
16942
17067
  const style = model?.settings.get().diffStyle ?? "unified";
16943
17068
  if (!change) {
16944
17069
  return b`<div class="bar"><span class="path" title=${this.path}>${this.path}</span></div>
@@ -16947,12 +17072,13 @@ var SliccDiffPanel = class extends ThemedElement {
16947
17072
  <swc-action-button size="s" quiet @click=${() => request(this, "open-file", this.path)}>Open the file</swc-action-button>
16948
17073
  </div>`;
16949
17074
  }
17075
+ const by = author(model, change);
16950
17076
  return b`<div class="bar">
16951
17077
  ${statusMark(change.status, false)}
16952
17078
  <span class="path" title=${this.path}>${this.path}</span>
16953
- <span>${statusLabels[change.status]} by ${agentName(model, change.agentId)}</span>
17079
+ <span>${statusLabels[change.status]}${by ? ` by ${by}` : ""}</span>
16954
17080
  <span class="spacer"></span>
16955
- <swc-action-group size="s" compact accessible-label="Diff layout">
17081
+ ${change.before === null && change.after === null ? A : b`<swc-action-group size="s" compact accessible-label="Diff layout">
16956
17082
  ${layouts.map(
16957
17083
  ([value, label]) => b`<swc-action-button
16958
17084
  class=${value === style ? "selected" : ""}
@@ -16962,21 +17088,16 @@ var SliccDiffPanel = class extends ThemedElement {
16962
17088
  >${label}</swc-action-button
16963
17089
  >`
16964
17090
  )}
16965
- </swc-action-group>
16966
- <swc-action-button size="s" quiet @click=${() => model?.files.accept(this.path)}>
17091
+ </swc-action-group>`}
17092
+ <swc-action-button size="s" quiet @click=${() => port?.accept(this.path)}>
16967
17093
  <swc-icon-checkmark slot="icon"></swc-icon-checkmark>Accept
16968
17094
  </swc-action-button>
16969
- <swc-action-button size="s" quiet @click=${() => this.#revert()}>
17095
+ <swc-action-button size="s" quiet @click=${() => this.#revert(port, change)}>
16970
17096
  <swc-icon-revert slot="icon"></swc-icon-revert>Revert
16971
17097
  </swc-action-button>
16972
17098
  </div>
16973
- <slicc-diff-view
16974
- path=${this.path}
16975
- color=${this.color}
16976
- diff-style=${style}
16977
- .oldText=${change.before}
16978
- .newText=${change.after}
16979
- ></slicc-diff-view>`;
17099
+ ${errorLine(this.error)}
17100
+ ${this.#body(change, style)}`;
16980
17101
  }
16981
17102
  };
16982
17103
 
@@ -22680,10 +22801,10 @@ var tagLabels = {
22680
22801
  project: "Project"
22681
22802
  };
22682
22803
  function sections(memories) {
22683
- const groups = /* @__PURE__ */ new Map();
22804
+ const groups2 = /* @__PURE__ */ new Map();
22684
22805
  for (const memory of memories)
22685
- groups.set(memory.section, [...groups.get(memory.section) ?? [], memory]);
22686
- return [...groups];
22806
+ groups2.set(memory.section, [...groups2.get(memory.section) ?? [], memory]);
22807
+ return [...groups2];
22687
22808
  }
22688
22809
  var SliccMemory = class extends ModelElement {
22689
22810
  static properties = {
@@ -23933,13 +24054,9 @@ var SliccTray = class extends ModelElement {
23933
24054
  align-items: center;
23934
24055
  gap: var(--swc-spacing-50);
23935
24056
  }
23936
- .chip .short,
23937
24057
  :host([compact]) .chip .detail {
23938
24058
  display: none;
23939
24059
  }
23940
- :host([compact]) .chip .short {
23941
- display: inline;
23942
- }
23943
24060
  .muted {
23944
24061
  color: var(--swc-neutral-subdued-content-color-default);
23945
24062
  }
@@ -24016,7 +24133,7 @@ var SliccTray = class extends ModelElement {
24016
24133
  >
24017
24134
  <span>
24018
24135
  <swc-status-light size="s" variant=${connectionVariant[status2.connection]}>
24019
- <span class="detail">${light}</span><span class="short">${connection}</span>
24136
+ <span class="detail">${light}</span>
24020
24137
  </swc-status-light>
24021
24138
  <span class="detail muted followers"><swc-icon-user-group size="s"></swc-icon-user-group>${status2.followers.length}</span>
24022
24139
  </span>
@@ -31566,12 +31683,12 @@ function charactersToExpressionCached(subset) {
31566
31683
  return cached;
31567
31684
  }
31568
31685
  function charactersToExpression(subset) {
31569
- const groups = [];
31686
+ const groups2 = [];
31570
31687
  let index = -1;
31571
31688
  while (++index < subset.length) {
31572
- groups.push(subset[index].replace(regexEscapeRegex, "\\$&"));
31689
+ groups2.push(subset[index].replace(regexEscapeRegex, "\\$&"));
31573
31690
  }
31574
- return new RegExp("(?:" + groups.join("|") + ")", "g");
31691
+ return new RegExp("(?:" + groups2.join("|") + ")", "g");
31575
31692
  }
31576
31693
 
31577
31694
  // node_modules/stringify-entities/lib/util/to-hexadecimal.js
@@ -51638,8 +51755,8 @@ var BaseGrid = class extends Resizable {
51638
51755
  this._onDidRemove.fire(group);
51639
51756
  }
51640
51757
  if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
51641
- const groups = Array.from(this._groups.values());
51642
- this.doSetGroupActive(groups.length > 0 ? groups[0].value : void 0);
51758
+ const groups2 = Array.from(this._groups.values());
51759
+ this.doSetGroupActive(groups2.length > 0 ? groups2[0].value : void 0);
51643
51760
  }
51644
51761
  return view;
51645
51762
  }
@@ -61967,7 +62084,7 @@ var StrictEventsSequencing = class extends CompositeDisposable {
61967
62084
  }
61968
62085
  init() {
61969
62086
  const panels = /* @__PURE__ */ new Set();
61970
- const groups = /* @__PURE__ */ new Set();
62087
+ const groups2 = /* @__PURE__ */ new Set();
61971
62088
  this.addDisposables(this.accessor.onDidAddPanel((panel) => {
61972
62089
  if (panels.has(panel.api.id)) throw new Error(`dockview: Invalid event sequence. [onDidAddPanel] called for panel ${panel.api.id} but panel already exists`);
61973
62090
  else panels.add(panel.api.id);
@@ -61975,10 +62092,10 @@ var StrictEventsSequencing = class extends CompositeDisposable {
61975
62092
  if (panels.has(panel.api.id)) panels.delete(panel.api.id);
61976
62093
  else throw new Error(`dockview: Invalid event sequence. [onDidRemovePanel] called for panel ${panel.api.id} but panel does not exists`);
61977
62094
  }), this.accessor.onDidAddGroup((group) => {
61978
- if (groups.has(group.api.id)) throw new Error(`dockview: Invalid event sequence. [onDidAddGroup] called for group ${group.api.id} but group already exists`);
61979
- else groups.add(group.api.id);
62095
+ if (groups2.has(group.api.id)) throw new Error(`dockview: Invalid event sequence. [onDidAddGroup] called for group ${group.api.id} but group already exists`);
62096
+ else groups2.add(group.api.id);
61980
62097
  }), this.accessor.onDidRemoveGroup((group) => {
61981
- if (groups.has(group.api.id)) groups.delete(group.api.id);
62098
+ if (groups2.has(group.api.id)) groups2.delete(group.api.id);
61982
62099
  else throw new Error(`dockview: Invalid event sequence. [onDidRemoveGroup] called for group ${group.api.id} but group does not exists`);
61983
62100
  }));
61984
62101
  }
@@ -64772,9 +64889,9 @@ var DockviewComponent = class extends BaseGrid {
64772
64889
  this.mutation("clear", () => this._doClear());
64773
64890
  }
64774
64891
  _doClear() {
64775
- const groups = Array.from(this._groups.values()).map((_9) => _9.value);
64892
+ const groups2 = Array.from(this._groups.values()).map((_9) => _9.value);
64776
64893
  const hasActiveGroup = !!this.activeGroup;
64777
- for (const group of groups) {
64894
+ for (const group of groups2) {
64778
64895
  var _this$_edgeGroupServi9;
64779
64896
  if ((_this$_edgeGroupServi9 = this._edgeGroupService) === null || _this$_edgeGroupServi9 === void 0 ? void 0 : _this$_edgeGroupServi9.includes(group)) {
64780
64897
  const panels = [...group.panels];
@@ -65027,8 +65144,8 @@ var DockviewComponent = class extends BaseGrid {
65027
65144
  */
65028
65145
  activateFallbackGroupIfRemoved(removed, skipActive) {
65029
65146
  if (!skipActive && this._activeGroup === removed) {
65030
- const groups = Array.from(this._groups.values());
65031
- this.doSetGroupAndPanelActive(groups.length > 0 ? groups[0].value : void 0);
65147
+ const groups2 = Array.from(this._groups.values());
65148
+ this.doSetGroupAndPanelActive(groups2.length > 0 ? groups2[0].value : void 0);
65032
65149
  }
65033
65150
  }
65034
65151
  doRemoveGroup(group, options) {
@@ -65972,10 +66089,10 @@ var SliccDock = class extends HTMLElement {
65972
66089
  this.#contents.get(id)?.focus();
65973
66090
  }
65974
66091
  cycleGroup(delta) {
65975
- const groups = this.api.groups.filter((group) => group.activePanel);
65976
- if (groups.length === 0) return null;
65977
- const current = groups.indexOf(this.api.activeGroup);
65978
- const next = groups[(current + delta + groups.length) % groups.length];
66092
+ const groups2 = this.api.groups.filter((group) => group.activePanel);
66093
+ if (groups2.length === 0) return null;
66094
+ const current = groups2.indexOf(this.api.activeGroup);
66095
+ const next = groups2[(current + delta + groups2.length) % groups2.length];
65979
66096
  const id = next.activePanel?.id;
65980
66097
  this.focusPanel(id);
65981
66098
  return id;