@ai-ecoverse/slicc-spectrum 2.3.0 → 2.4.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/dist/slicc-ui.js CHANGED
@@ -10403,10 +10403,10 @@ function parseAnsi(text4, streaming = false) {
10403
10403
  const runs = [];
10404
10404
  let style2 = plain;
10405
10405
  let start2 = 0;
10406
- const push2 = (end) => {
10407
- if (end <= start2) return;
10406
+ const push2 = (end2) => {
10407
+ if (end2 <= start2) return;
10408
10408
  const last = runs.at(-1);
10409
- const piece = text4.slice(start2, end);
10409
+ const piece = text4.slice(start2, end2);
10410
10410
  if (last?.style === style2) last.text += piece;
10411
10411
  else runs.push({ text: piece, style: style2 });
10412
10412
  };
@@ -10536,53 +10536,30 @@ function ansi(text4, streaming = false, surface2) {
10536
10536
  }
10537
10537
 
10538
10538
  // src/app/command.ts
10539
- var toShow = "Show the full command to allow it.";
10540
10539
  var toScroll = "Scroll to the end of the command to allow it.";
10541
- var clampCss = i`
10542
- .command [data-clamp] {
10543
- display: block;
10544
- max-block-size: 4lh;
10545
- overflow: hidden;
10546
- }
10547
- .full-command .chevron {
10548
- transition: transform var(--swc-animation-duration-100) var(--swc-animation-ease-out);
10549
- }
10550
- .full-command[data-shown] .chevron {
10551
- transform: rotate(180deg);
10552
- }
10553
- @media (prefers-reduced-motion: reduce) {
10554
- .full-command .chevron {
10555
- transition: none;
10556
- }
10540
+ var endCss = i`
10541
+ .command .end {
10542
+ display: inline-block;
10543
+ inline-size: 0;
10544
+ block-size: 0;
10557
10545
  }
10558
10546
  `;
10559
- var Cuts = class {
10560
- #cuts = /* @__PURE__ */ new Map();
10561
- #root;
10562
- #changed;
10563
- #observer = new ResizeObserver(() => this.measure());
10564
- constructor(root, changed2) {
10565
- this.#root = root;
10566
- this.#changed = changed2;
10567
- }
10568
- get(id) {
10569
- return this.#cuts.get(id);
10570
- }
10571
- measure() {
10572
- let changed2 = false;
10573
- for (const command2 of this.#root().querySelectorAll(".command [data-clamp]")) {
10574
- this.#observer.observe(command2);
10575
- const id = command2.dataset.clamp;
10576
- const cut = command2.clientHeight ? command2.scrollHeight > command2.clientHeight + 1 : void 0;
10577
- if (this.#cuts.get(id) === cut) continue;
10578
- changed2 = true;
10579
- if (cut === void 0) this.#cuts.delete(id);
10580
- else this.#cuts.set(id, cut);
10581
- }
10582
- if (changed2) this.#changed();
10547
+ var end = (id) => b`<span class="end" data-end=${id}></span>`;
10548
+ var Watched = class {
10549
+ #observer;
10550
+ #targets = /* @__PURE__ */ new Set();
10551
+ constructor(observer) {
10552
+ this.#observer = observer;
10553
+ }
10554
+ sync(targets) {
10555
+ const next = new Set(targets);
10556
+ for (const target of this.#targets) if (!next.has(target)) this.#observer.unobserve(target);
10557
+ for (const target of next) if (!this.#targets.has(target)) this.#observer.observe(target);
10558
+ this.#targets = next;
10583
10559
  }
10584
10560
  disconnect() {
10585
10561
  this.#observer.disconnect();
10562
+ this.#targets.clear();
10586
10563
  }
10587
10564
  };
10588
10565
  var Ends = class {
@@ -10622,16 +10599,62 @@ var Ends = class {
10622
10599
  this.#seen.delete(id);
10623
10600
  this.#looked.delete(id);
10624
10601
  }
10602
+ #watched = new Watched(this.#observer);
10625
10603
  observe() {
10626
- for (const end of this.#root().querySelectorAll("[data-end]"))
10627
- this.#observer.observe(end);
10604
+ this.#watched.sync(this.#root().querySelectorAll("[data-end]"));
10628
10605
  }
10629
10606
  disconnect() {
10630
- this.#observer.disconnect();
10607
+ this.#watched.disconnect();
10608
+ }
10609
+ };
10610
+ var Arming = class {
10611
+ #ms;
10612
+ #changed = 0;
10613
+ #pressed = 0;
10614
+ #layout = "";
10615
+ constructor(ms) {
10616
+ this.#ms = ms;
10617
+ }
10618
+ arm() {
10619
+ this.#changed = performance.now();
10620
+ }
10621
+ press = () => {
10622
+ this.#pressed = performance.now();
10623
+ };
10624
+ settled(at = performance.now()) {
10625
+ return at - this.#changed >= this.#ms();
10626
+ }
10627
+ counts(event2) {
10628
+ return this.settled(event2.detail ? this.#pressed : performance.now());
10629
+ }
10630
+ watch(layout2) {
10631
+ if (layout2 === this.#layout) return;
10632
+ this.#layout = layout2;
10633
+ this.arm();
10634
+ }
10635
+ forget() {
10636
+ this.#layout = "";
10631
10637
  }
10632
10638
  };
10633
- function fullCommand(shown6, toggle) {
10634
- return b`<swc-action-button size="s" quiet class="full-command" data-action="full-command" data-shown=${shown6 ? "" : A} aria-expanded=${shown6 ? "true" : "false"} @click=${toggle}><swc-icon-chevron-down slot="icon" class="chevron" aria-hidden="true"></swc-icon-chevron-down>${shown6 ? "Hide the full command" : "Show the full command"}</swc-action-button>`;
10639
+ function layout(buttons, head = [], frame) {
10640
+ const box = frame?.getBoundingClientRect();
10641
+ const x5 = box ? box.left - frame.scrollLeft : 0;
10642
+ const y8 = box ? box.top - frame.scrollTop : 0;
10643
+ return JSON.stringify([
10644
+ ...head,
10645
+ box ? [box.left, box.top].map(Math.round) : null,
10646
+ buttons.map((button) => {
10647
+ const { left, top, width, height } = button.getBoundingClientRect();
10648
+ return [
10649
+ button.closest("[data-id]")?.dataset.id ?? null,
10650
+ button.dataset.action,
10651
+ button.textContent,
10652
+ button.hasAttribute("disabled"),
10653
+ button.hasAttribute("pending"),
10654
+ ...width || height ? [left - x5, top - y8, width, height].map(Math.round) : []
10655
+ ];
10656
+ })
10657
+ ]);
10635
10658
  }
10636
10659
 
10637
10660
  // node_modules/@adobe/spectrum-wc/dist/components/ui-icons/ui-icons.types.js
@@ -14484,13 +14507,13 @@ function decodeNamedCharacterReference(value) {
14484
14507
 
14485
14508
  // node_modules/micromark-util-chunked/index.js
14486
14509
  function splice(list6, start2, remove2, items) {
14487
- const end = list6.length;
14510
+ const end2 = list6.length;
14488
14511
  let chunkStart = 0;
14489
14512
  let parameters;
14490
14513
  if (start2 < 0) {
14491
- start2 = -start2 > end ? 0 : end + start2;
14514
+ start2 = -start2 > end2 ? 0 : end2 + start2;
14492
14515
  } else {
14493
- start2 = start2 > end ? end : start2;
14516
+ start2 = start2 > end2 ? end2 : start2;
14494
14517
  }
14495
14518
  remove2 = remove2 > 0 ? remove2 : 0;
14496
14519
  if (items.length < 1e4) {
@@ -15044,11 +15067,11 @@ function resolveAllAttention(events, context) {
15044
15067
  const start2 = {
15045
15068
  ...events[open][1].end
15046
15069
  };
15047
- const end = {
15070
+ const end2 = {
15048
15071
  ...events[index2][1].start
15049
15072
  };
15050
15073
  movePoint(start2, -use);
15051
- movePoint(end, use);
15074
+ movePoint(end2, use);
15052
15075
  const openingSequence = {
15053
15076
  type: use > 1 ? "strongSequence" : "emphasisSequence",
15054
15077
  start: start2,
@@ -15061,7 +15084,7 @@ function resolveAllAttention(events, context) {
15061
15084
  start: {
15062
15085
  ...events[index2][1].start
15063
15086
  },
15064
- end
15087
+ end: end2
15065
15088
  };
15066
15089
  const text4 = {
15067
15090
  type: use > 1 ? "strongText" : "emphasisText",
@@ -15825,8 +15848,8 @@ var SpliceBuffer = class {
15825
15848
  * @returns {Array<T>}
15826
15849
  * Array of items.
15827
15850
  */
15828
- slice(start2, end) {
15829
- const stop = end === null || end === void 0 ? Number.POSITIVE_INFINITY : end;
15851
+ slice(start2, end2) {
15852
+ const stop = end2 === null || end2 === void 0 ? Number.POSITIVE_INFINITY : end2;
15830
15853
  if (stop < this.left.length) {
15831
15854
  return this.left.slice(start2, stop);
15832
15855
  }
@@ -17123,7 +17146,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17123
17146
  return comment(code3);
17124
17147
  }
17125
17148
  function commentEnd(code3) {
17126
- return code3 === 62 ? end(code3) : code3 === 45 ? commentClose(code3) : comment(code3);
17149
+ return code3 === 62 ? end2(code3) : code3 === 45 ? commentClose(code3) : comment(code3);
17127
17150
  }
17128
17151
  function cdataOpenInside(code3) {
17129
17152
  const value = "CDATA[";
@@ -17157,7 +17180,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17157
17180
  }
17158
17181
  function cdataEnd(code3) {
17159
17182
  if (code3 === 62) {
17160
- return end(code3);
17183
+ return end2(code3);
17161
17184
  }
17162
17185
  if (code3 === 93) {
17163
17186
  effects.consume(code3);
@@ -17167,7 +17190,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17167
17190
  }
17168
17191
  function declaration(code3) {
17169
17192
  if (code3 === null || code3 === 62) {
17170
- return end(code3);
17193
+ return end2(code3);
17171
17194
  }
17172
17195
  if (markdownLineEnding(code3)) {
17173
17196
  returnState = declaration;
@@ -17192,7 +17215,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17192
17215
  return instruction;
17193
17216
  }
17194
17217
  function instructionClose(code3) {
17195
- return code3 === 62 ? end(code3) : instruction(code3);
17218
+ return code3 === 62 ? end2(code3) : instruction(code3);
17196
17219
  }
17197
17220
  function tagCloseStart(code3) {
17198
17221
  if (asciiAlpha(code3)) {
@@ -17217,7 +17240,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17217
17240
  effects.consume(code3);
17218
17241
  return tagCloseBetween;
17219
17242
  }
17220
- return end(code3);
17243
+ return end2(code3);
17221
17244
  }
17222
17245
  function tagOpen(code3) {
17223
17246
  if (code3 === 45 || asciiAlphanumeric(code3)) {
@@ -17232,7 +17255,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17232
17255
  function tagOpenBetween(code3) {
17233
17256
  if (code3 === 47) {
17234
17257
  effects.consume(code3);
17235
- return end;
17258
+ return end2;
17236
17259
  }
17237
17260
  if (code3 === 58 || code3 === 95 || asciiAlpha(code3)) {
17238
17261
  effects.consume(code3);
@@ -17246,7 +17269,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17246
17269
  effects.consume(code3);
17247
17270
  return tagOpenBetween;
17248
17271
  }
17249
- return end(code3);
17272
+ return end2(code3);
17250
17273
  }
17251
17274
  function tagOpenAttributeName(code3) {
17252
17275
  if (code3 === 45 || code3 === 46 || code3 === 58 || code3 === 95 || asciiAlphanumeric(code3)) {
@@ -17322,7 +17345,7 @@ function tokenizeHtmlText(effects, ok4, nok) {
17322
17345
  }
17323
17346
  return nok(code3);
17324
17347
  }
17325
- function end(code3) {
17348
+ function end2(code3) {
17326
17349
  if (code3 === 62) {
17327
17350
  effects.consume(code3);
17328
17351
  effects.exit("htmlTextData");
@@ -18538,7 +18561,7 @@ function preprocess() {
18538
18561
  let start2 = true;
18539
18562
  let atCarriageReturn;
18540
18563
  return preprocessor;
18541
- function preprocessor(value, encoding, end) {
18564
+ function preprocessor(value, encoding, end2) {
18542
18565
  value = buffer + (typeof value === "string" ? value.toString() : new TextDecoder(encoding || void 0).decode(value));
18543
18566
  const chunks = [];
18544
18567
  let startPosition = 0;
@@ -18597,7 +18620,7 @@ function preprocess() {
18597
18620
  }
18598
18621
  startPosition = endPosition + 1;
18599
18622
  }
18600
- if (end) {
18623
+ if (end2) {
18601
18624
  if (atCarriageReturn) {
18602
18625
  chunks.push(-5);
18603
18626
  }
@@ -18850,7 +18873,7 @@ function compiler(options2) {
18850
18873
  }
18851
18874
  }
18852
18875
  function prepareList(events, start2) {
18853
- const end = events.length - 1;
18876
+ const end2 = events.length - 1;
18854
18877
  let index2 = start2 - 1;
18855
18878
  let containerBalance = -1;
18856
18879
  let listSpread = false;
@@ -18859,7 +18882,7 @@ function compiler(options2) {
18859
18882
  let firstBlankLineIndex;
18860
18883
  let atMarker;
18861
18884
  const insertions = [];
18862
- while (++index2 <= end) {
18885
+ while (++index2 <= end2) {
18863
18886
  const event2 = events[index2];
18864
18887
  switch (event2[1].type) {
18865
18888
  case "listUnordered":
@@ -20896,8 +20919,8 @@ function flushCell(map, context, range2, rowKind, rowEnd, previousCell) {
20896
20919
  map.add(range2[2], 0, [["enter", valueToken, context]]);
20897
20920
  if (rowKind !== 2) {
20898
20921
  const start2 = context.events[range2[2]];
20899
- const end = context.events[range2[3]];
20900
- start2[1].end = Object.assign({}, end[1].end);
20922
+ const end2 = context.events[range2[3]];
20923
+ start2[1].end = Object.assign({}, end2[1].end);
20901
20924
  start2[1].type = "chunkText";
20902
20925
  start2[1].contentType = "text";
20903
20926
  if (range2[3] > range2[2] + 1) {
@@ -21711,19 +21734,19 @@ var InteractionManager = class {
21711
21734
  lineNumber: range2.start,
21712
21735
  side: range2.side
21713
21736
  };
21714
- const end = {
21737
+ const end2 = {
21715
21738
  lineNumber: range2.end,
21716
21739
  side: range2.endSide ?? range2.side
21717
21740
  };
21718
21741
  const startIndex = this.selectionPointRowIndex(start2);
21719
- const endIndex = this.selectionPointRowIndex(end);
21742
+ const endIndex = this.selectionPointRowIndex(end2);
21720
21743
  if (startIndex == null || endIndex == null) return;
21721
21744
  return startIndex > endIndex ? {
21722
- top: end,
21745
+ top: end2,
21723
21746
  bottom: start2
21724
21747
  } : {
21725
21748
  top: start2,
21726
- bottom: end
21749
+ bottom: end2
21727
21750
  };
21728
21751
  }
21729
21752
  selectionPointRowIndex(point3) {
@@ -22040,10 +22063,10 @@ var InteractionManager = class {
22040
22063
  buildSelectedLineRange(anchor, current) {
22041
22064
  return this.buildSelectionRange(anchor.lineNumber, current.lineNumber, anchor.side, current.side);
22042
22065
  }
22043
- buildSelectionRange(start2, end, side, endSide) {
22066
+ buildSelectionRange(start2, end2, side, endSide) {
22044
22067
  return {
22045
22068
  start: start2,
22046
- end,
22069
+ end: end2,
22047
22070
  ...side != null ? { side } : {},
22048
22071
  ...side !== endSide && endSide != null ? { endSide } : {}
22049
22072
  };
@@ -23383,8 +23406,8 @@ function linesFromFileContents(contents) {
23383
23406
  const offsets = computeLineOffsets(contents);
23384
23407
  return Array.from({ length: offsets.length }, (_7, i26) => {
23385
23408
  const start2 = offsets[i26];
23386
- const end = offsets[i26 + 1] ?? contents.length;
23387
- return contents.slice(start2, end);
23409
+ const end2 = offsets[i26 + 1] ?? contents.length;
23410
+ return contents.slice(start2, end2);
23388
23411
  });
23389
23412
  }
23390
23413
 
@@ -25957,12 +25980,12 @@ function getLoadedFileCacheKey(oldFile, newFile) {
25957
25980
 
25958
25981
  // node_modules/@pierre/diffs/dist/utils/cleanLastNewline.js
25959
25982
  function cleanLastNewline(contents) {
25960
- let end = contents.length;
25961
- if (contents.charCodeAt(end - 1) === 10) {
25962
- end--;
25963
- if (contents.charCodeAt(end - 1) === 13) end--;
25983
+ let end2 = contents.length;
25984
+ if (contents.charCodeAt(end2 - 1) === 10) {
25985
+ end2--;
25986
+ if (contents.charCodeAt(end2 - 1) === 13) end2--;
25964
25987
  }
25965
- return contents.slice(0, end);
25988
+ return contents.slice(0, end2);
25966
25989
  }
25967
25990
 
25968
25991
  // node_modules/@pierre/diffs/dist/utils/detachString.js
@@ -27747,12 +27770,12 @@ function getNearestRenderableAdditionLine({ fileDiff, lineNumber, direction, exp
27747
27770
  }
27748
27771
  if (lineNumber >= modeledEnd) return lineNumber;
27749
27772
  if (direction === "down") {
27750
- for (const [start2, end] of ranges2) if (end > lineNumber) return Math.max(start2, lineNumber);
27773
+ for (const [start2, end2] of ranges2) if (end2 > lineNumber) return Math.max(start2, lineNumber);
27751
27774
  return;
27752
27775
  }
27753
27776
  for (let index2 = ranges2.length - 1; index2 >= 0; index2--) {
27754
- const [start2, end] = ranges2[index2];
27755
- if (start2 <= lineNumber) return Math.min(end - 1, lineNumber);
27777
+ const [start2, end2] = ranges2[index2];
27778
+ if (start2 <= lineNumber) return Math.min(end2 - 1, lineNumber);
27756
27779
  }
27757
27780
  }
27758
27781
 
@@ -28116,20 +28139,20 @@ function getContextLineIterationBounds(state2, count2, diffStyle) {
28116
28139
  const ranges2 = [];
28117
28140
  function pushRange(currentCount) {
28118
28141
  const start3 = Math.max(0, state2.viewportStart - currentCount);
28119
- const end2 = Math.min(count2, state2.viewportEnd - currentCount);
28120
- if (end2 > start3) ranges2.push([start3, end2]);
28142
+ const end3 = Math.min(count2, state2.viewportEnd - currentCount);
28143
+ if (end3 > start3) ranges2.push([start3, end3]);
28121
28144
  }
28122
28145
  if (diffStyle !== "split") pushRange(state2.unifiedCount);
28123
28146
  if (diffStyle !== "unified") pushRange(state2.splitCount);
28124
28147
  if (ranges2.length === 0) return [0, 0];
28125
28148
  let start2 = ranges2[0][0];
28126
- let end = ranges2[0][1];
28149
+ let end2 = ranges2[0][1];
28127
28150
  for (let index2 = 1; index2 < ranges2.length; index2++) {
28128
28151
  const range2 = ranges2[index2];
28129
28152
  start2 = Math.min(start2, range2[0]);
28130
- end = Math.max(end, range2[1]);
28153
+ end2 = Math.max(end2, range2[1]);
28131
28154
  }
28132
- return [start2, end];
28155
+ return [start2, end2];
28133
28156
  }
28134
28157
  function walkContextLines(state2, count2, diffStyle, callback, onSkippedStart, shouldBreak) {
28135
28158
  const [startIndex, endIndex] = getContextLineIterationBounds(state2, count2, diffStyle);
@@ -28169,8 +28192,8 @@ function getChangeIterationRanges(state2, content3, diffStyle) {
28169
28192
  }
28170
28193
  function pushRange(range2, kind) {
28171
28194
  if (range2 == null) return;
28172
- const [start2, end] = mapRangeToIteration(range2, kind);
28173
- if (end > start2) iterationRanges.push([start2, end]);
28195
+ const [start2, end2] = mapRangeToIteration(range2, kind);
28196
+ if (end2 > start2) iterationRanges.push([start2, end2]);
28174
28197
  }
28175
28198
  if (useUnified) {
28176
28199
  pushRange(getVisibleRange(state2.unifiedCount, content3.deletions), "deletions");
@@ -28183,10 +28206,10 @@ function getChangeIterationRanges(state2, content3, diffStyle) {
28183
28206
  if (iterationRanges.length === 0) return iterationRanges;
28184
28207
  iterationRanges.sort((a20, b10) => a20[0] - b10[0]);
28185
28208
  const merged2 = [iterationRanges[0]];
28186
- for (const [start2, end] of iterationRanges.slice(1)) {
28209
+ for (const [start2, end2] of iterationRanges.slice(1)) {
28187
28210
  const last = merged2[merged2.length - 1];
28188
- if (start2 <= last[1]) last[1] = Math.max(last[1], end);
28189
- else merged2.push([start2, end]);
28211
+ if (start2 <= last[1]) last[1] = Math.max(last[1], end2);
28212
+ else merged2.push([start2, end2]);
28190
28213
  }
28191
28214
  return merged2;
28192
28215
  }
@@ -28651,8 +28674,8 @@ function getAffectedHunkIndexes(diff, changedAdditionLineIndexes) {
28651
28674
  }
28652
28675
  function findHunkIndexForAdditionLine(diff, line) {
28653
28676
  for (const [hunkIndex, hunk] of diff.hunks.entries()) {
28654
- const end = hunk.additionLineIndex + hunk.additionCount;
28655
- if (line >= hunk.additionLineIndex && line < end) return hunkIndex;
28677
+ const end2 = hunk.additionLineIndex + hunk.additionCount;
28678
+ if (line >= hunk.additionLineIndex && line < end2) return hunkIndex;
28656
28679
  }
28657
28680
  }
28658
28681
  function reparseHunkRegion(diff, hunkIndex, parseDiffOptions) {
@@ -28904,10 +28927,10 @@ function rebuildExpansionFromAnchors(diff, anchors) {
28904
28927
  if (gapEnd <= gapStart) return;
28905
28928
  let fromStart = 0;
28906
28929
  let fromEnd = 0;
28907
- for (const [start2, end] of anchors) {
28908
- if (end <= gapStart || start2 >= gapEnd) continue;
28909
- if (start2 <= gapStart) fromStart = Math.max(fromStart, Math.min(end, gapEnd) - gapStart);
28910
- if (end >= gapEnd) fromEnd = Math.max(fromEnd, gapEnd - Math.max(start2, gapStart));
28930
+ for (const [start2, end2] of anchors) {
28931
+ if (end2 <= gapStart || start2 >= gapEnd) continue;
28932
+ if (start2 <= gapStart) fromStart = Math.max(fromStart, Math.min(end2, gapEnd) - gapStart);
28933
+ if (end2 >= gapEnd) fromEnd = Math.max(fromEnd, gapEnd - Math.max(start2, gapStart));
28911
28934
  }
28912
28935
  if (fromStart > 0 || fromEnd > 0) rebuilt.set(key, {
28913
28936
  fromStart,
@@ -32778,8 +32801,8 @@ var closing = /^[\s>]*(`{3,}|~{3,})[ \t]*$/;
32778
32801
  function sealed(source) {
32779
32802
  const lines = source.split("\n");
32780
32803
  const open = lines[0].match(opening)[1];
32781
- const end = lines.length > 1 ? lines.at(-1).match(closing)?.[1] : void 0;
32782
- return !!end && end[0] === open[0] && end.length >= open.length;
32804
+ const end2 = lines.length > 1 ? lines.at(-1).match(closing)?.[1] : void 0;
32805
+ return !!end2 && end2[0] === open[0] && end2.length >= open.length;
32783
32806
  }
32784
32807
  function seal(nodes, source) {
32785
32808
  for (const node2 of nodes) {
@@ -33991,10 +34014,10 @@ function show(turn) {
33991
34014
  ].find((candidate) => candidate.dataset.place === turn.dataset.id);
33992
34015
  const log = place4?.closest(".log");
33993
34016
  if (!log) return;
33994
- const end = Number.parseFloat(getComputedStyle(log).scrollPaddingBlockEnd) || 0;
34017
+ const end2 = Number.parseFloat(getComputedStyle(log).scrollPaddingBlockEnd) || 0;
33995
34018
  const at = place4.getBoundingClientRect().top - log.getBoundingClientRect().top;
33996
34019
  log.scrollTo({
33997
- top: log.scrollTop + at - log.clientHeight + end,
34020
+ top: log.scrollTop + at - log.clientHeight + end2,
33998
34021
  behavior: still() ? "auto" : "smooth"
33999
34022
  });
34000
34023
  }
@@ -34007,16 +34030,19 @@ function spokenLeft(left, at) {
34007
34030
  return left <= 6e4 ? "Less than a minute left" : `Expires at ${deadline(at)}`;
34008
34031
  }
34009
34032
  function decide(message, handlers, settled4) {
34010
- const commands3 = settled4 || !message.body ? void 0 : handlers.commands;
34011
- const full = commands3?.has(message.id) ?? true;
34012
- const cut = commands3?.cut(message.id);
34013
- const toggle = commands3 && (full || cut) ? fullCommand(full, () => commands3.toggle(message.id)) : A;
34014
- const actions2 = b`${commands3 && !full && cut ? b`<p class="allow-hint" data-allow-hint>${toShow}</p>` : A}<div class="decide">
34015
- ${toggle}
34016
- <swc-button size="s" variant="secondary" fill-style="outline" data-action="deny" ?disabled=${handlers.readOnly} @click=${() => handlers.resolve(message.id, "dismissed")}>Deny</swc-button>
34017
- ${full || cut === false ? b`<swc-button size="s" variant="accent" data-action="allow" ?disabled=${handlers.readOnly} @click=${() => handlers.resolve(message.id, "confirmed")}>Allow</swc-button>` : A}
34033
+ const { id, body: body2 } = message;
34034
+ const commands3 = settled4 ? void 0 : handlers.commands;
34035
+ const gated = !!body2 && !!commands3;
34036
+ const whole = !gated || !!commands3?.seen(id);
34037
+ const choose = (event2, state2) => {
34038
+ if (commands3?.armed(event2) === false || state2 === "confirmed" && !whole) return;
34039
+ handlers.resolve(id, state2);
34040
+ };
34041
+ const actions2 = b`<div class="decide">
34042
+ <swc-button size="s" variant="secondary" fill-style="outline" data-action="deny" ?disabled=${handlers.readOnly} @click=${(event2) => choose(event2, "dismissed")}>Deny</swc-button>
34043
+ <swc-button size="s" variant="accent" data-action="allow" ?disabled=${handlers.readOnly || !whole} @click=${(event2) => choose(event2, "confirmed")}>Allow</swc-button>
34018
34044
  </div>`;
34019
- const command2 = message.body ? b`<pre class="command"><span class="lines" data-clamp=${full ? A : message.id}>${message.body}</span></pre>` : A;
34045
+ const command2 = body2 ? b`<pre class="command"><span class="lines">${body2}${gated ? end(id) : A}</span></pre>` : A;
34020
34046
  return { actions: actions2, command: command2 };
34021
34047
  }
34022
34048
  function decision(message, handlers) {
@@ -34811,14 +34837,6 @@ var messageCss = i`
34811
34837
  justify-content: flex-end;
34812
34838
  padding: 0;
34813
34839
  }
34814
- .decide .full-command {
34815
- margin-inline-end: auto;
34816
- }
34817
- .decision .allow-hint {
34818
- margin: 0;
34819
- color: var(--swc-neutral-subdued-content-color-default);
34820
- font-size: var(--swc-font-size-75);
34821
- }
34822
34840
  .question.decision .options {
34823
34841
  display: flex;
34824
34842
  flex-wrap: wrap;
@@ -35601,6 +35619,10 @@ var SliccComposer = class extends ThemedElement {
35601
35619
  const released = event2 instanceof KeyboardEvent && (event2.code === "KeyM" || event2.key === "Alt");
35602
35620
  if (this.dictating && (released || event2.type === "blur")) this.dictate();
35603
35621
  };
35622
+ #outside = (event2) => {
35623
+ const form = this.renderRoot.querySelector("form.secret");
35624
+ if (form && !this.sharing && !event2.composedPath().includes(form)) this.closeSecret();
35625
+ };
35604
35626
  #keys = { capture: true, handleEvent: (event2) => this.#keydown(event2) };
35605
35627
  constructor() {
35606
35628
  super();
@@ -35894,8 +35916,10 @@ var SliccComposer = class extends ThemedElement {
35894
35916
  outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
35895
35917
  outline-offset: var(--swc-focus-ring-gap);
35896
35918
  }
35897
- .secret swc-button {
35898
- justify-self: start;
35919
+ .secret .buttons {
35920
+ display: flex;
35921
+ flex-wrap: wrap;
35922
+ gap: var(--swc-spacing-100);
35899
35923
  }
35900
35924
  .secret-error {
35901
35925
  display: flex;
@@ -35933,6 +35957,7 @@ var SliccComposer = class extends ThemedElement {
35933
35957
  clearTimeout(this.#abandon);
35934
35958
  globalThis.addEventListener("keyup", this.#release);
35935
35959
  globalThis.addEventListener("blur", this.#release);
35960
+ globalThis.addEventListener("pointerdown", this.#outside, true);
35936
35961
  if (this.hasUpdated) this.#wire();
35937
35962
  }
35938
35963
  firstUpdated() {
@@ -35942,6 +35967,7 @@ var SliccComposer = class extends ThemedElement {
35942
35967
  super.disconnectedCallback();
35943
35968
  globalThis.removeEventListener("keyup", this.#release);
35944
35969
  globalThis.removeEventListener("blur", this.#release);
35970
+ globalThis.removeEventListener("pointerdown", this.#outside, true);
35945
35971
  clearValues(this.renderRoot);
35946
35972
  const kept3 = this.#waiting.draft?.attachments;
35947
35973
  const held2 = [
@@ -36288,6 +36314,10 @@ ${this.value}` : text4;
36288
36314
  const takes = commands.some((command2) => command2.name === name && command2.args);
36289
36315
  this.popup = found && (found.kind !== "argument" || takes) ? { ...found, items: this.#choices(found.kind, found.query), index: 0 } : null;
36290
36316
  }
36317
+ closeSecret() {
36318
+ clearValues(this.renderRoot);
36319
+ this.popup = null;
36320
+ }
36291
36321
  openPopup(kind) {
36292
36322
  clearValues(this.renderRoot);
36293
36323
  this.secretError = null;
@@ -36531,9 +36561,7 @@ ${this.value}` : text4;
36531
36561
  );
36532
36562
  };
36533
36563
  const close = (event2) => {
36534
- if (event2.key !== "Escape") return;
36535
- clearValues(this.renderRoot);
36536
- this.popup = null;
36564
+ if (event2.key === "Escape") this.closeSecret();
36537
36565
  };
36538
36566
  const bad = (name) => this.secretField === name ? "true" : A;
36539
36567
  const described2 = (name) => this.secretField === name ? "secret-error" : A;
@@ -36543,7 +36571,10 @@ ${this.value}` : text4;
36543
36571
  <label class="field"><span>Name</span><input name="name" placeholder="API_TOKEN" autocomplete="off" spellcheck="false" aria-invalid=${bad("name")} aria-describedby=${described2("name")} /></label>
36544
36572
  ${valued ? b`<label class="field"><span>Value</span><input name="value" type="password" autocomplete="off" spellcheck="false" aria-invalid=${bad("value")} aria-describedby=${described2("value")} /></label>` : A}
36545
36573
  ${this.secretError ? b`<span class="secret-error" role="alert" id="secret-error" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${this.secretError}</span></span>` : A}
36546
- <swc-button size="s" variant="accent" data-action="share-secret" ?pending=${this.sharing} @click=${(event2) => event2.currentTarget.closest("form")?.requestSubmit()}>Share</swc-button>
36574
+ <span class="buttons">
36575
+ <swc-button size="s" variant="accent" data-action="share-secret" ?pending=${this.sharing} @click=${(event2) => event2.currentTarget.closest("form")?.requestSubmit()}>Share</swc-button>
36576
+ <swc-button size="s" variant="secondary" fill-style="outline" data-action="cancel-secret" ?disabled=${this.sharing} @click=${() => this.closeSecret()}>Cancel</swc-button>
36577
+ </span>
36547
36578
  </form>`;
36548
36579
  }
36549
36580
  const title2 = {
@@ -36871,8 +36902,8 @@ var ModelFilter = class {
36871
36902
  }
36872
36903
  if (event2.key.trim().length !== 1 || event2.ctrlKey || event2.metaKey || event2.altKey) return;
36873
36904
  search3.focus();
36874
- const end = search3.focusElement.value.length;
36875
- search3.focusElement.setSelectionRange(end, end);
36905
+ const end2 = search3.focusElement.value.length;
36906
+ search3.focusElement.setSelectionRange(end2, end2);
36876
36907
  }
36877
36908
  };
36878
36909
  #key = (event2) => {
@@ -37215,14 +37246,28 @@ function pendingAsks(messages) {
37215
37246
  );
37216
37247
  });
37217
37248
  }
37218
- function into(card2, dock2) {
37219
- const box = card2.getBoundingClientRect();
37249
+ function into(card2, dock2, target) {
37220
37250
  const view = dock2.getBoundingClientRect();
37221
37251
  const start2 = view.top + (Number.parseFloat(getComputedStyle(dock2).scrollPaddingBlockStart) || 0);
37252
+ const fits2 = card2.getBoundingClientRect().height <= view.bottom - start2;
37253
+ const box = (fits2 ? card2 : target).getBoundingClientRect();
37222
37254
  if (box.top < start2) dock2.scrollTop -= start2 - box.top;
37223
37255
  else if (box.bottom > view.bottom)
37224
37256
  dock2.scrollTop += Math.min(box.bottom - view.bottom, box.top - start2);
37225
37257
  }
37258
+ function lift(turn, dock2, raised) {
37259
+ const decide2 = turn.querySelector(".decide");
37260
+ if (!decide2) return raised;
37261
+ const style2 = getComputedStyle(dock2);
37262
+ const view = dock2.getBoundingClientRect();
37263
+ const start2 = view.top + (Number.parseFloat(style2.scrollPaddingBlockStart) || 0);
37264
+ const end2 = view.bottom - (Number.parseFloat(style2.scrollPaddingBlockEnd) || 0);
37265
+ const top = (turn.querySelector(".command") ?? turn).getBoundingClientRect().top;
37266
+ const need = decide2.getBoundingClientRect().bottom - end2;
37267
+ const base = dock2.scrollTop - raised;
37268
+ dock2.scrollTop = base + (need <= top - start2 ? raised + Math.max(0, need) : 0);
37269
+ return dock2.scrollTop - base;
37270
+ }
37226
37271
  var place = (id) => b`<div class="ask-place" data-place=${id} aria-hidden="true"></div>`;
37227
37272
  function dock(entries, messages, seat) {
37228
37273
  const docked = new Map(seat ? [] : pendingAsks(messages));
@@ -37345,7 +37390,7 @@ var SliccChat = class _SliccChat extends ThemedElement {
37345
37390
  fade,
37346
37391
  markdownCss,
37347
37392
  messageCss,
37348
- clampCss,
37393
+ endCss,
37349
37394
  r(link_default),
37350
37395
  signInCss,
37351
37396
  i`
@@ -37605,8 +37650,14 @@ var SliccChat = class _SliccChat extends ThemedElement {
37605
37650
  #licks = new ViewSet(this, "chat:licks");
37606
37651
  #runs = new ViewSet(this, "chat:runs");
37607
37652
  #details = /* @__PURE__ */ new Set();
37608
- #commands = new ViewSet(this, "chat:commands");
37609
- #cuts = new Cuts(
37653
+ arming = 500;
37654
+ #arming = new Arming(() => this.arming);
37655
+ #moves = new Watched(new ResizeObserver(() => this.#settle()));
37656
+ #moved = () => this.#settle();
37657
+ #lifted = "";
37658
+ #lifting = "";
37659
+ #raised = 0;
37660
+ #ends = new Ends(
37610
37661
  () => this.renderRoot,
37611
37662
  () => this.requestUpdate()
37612
37663
  );
@@ -37621,12 +37672,8 @@ var SliccChat = class _SliccChat extends ThemedElement {
37621
37672
  }
37622
37673
  },
37623
37674
  commands: {
37624
- cut: (id) => this.#cuts.get(id),
37625
- has: (id) => this.#commands.has(id),
37626
- toggle: (id) => {
37627
- this.#commands.toggle(id);
37628
- void this.updateComplete.then(() => this.#reach(id));
37629
- }
37675
+ seen: (id) => this.#ends.has(id),
37676
+ armed: (event2) => this.#arming.counts(event2)
37630
37677
  },
37631
37678
  color: "light",
37632
37679
  model: null,
@@ -37705,27 +37752,52 @@ var SliccChat = class _SliccChat extends ThemedElement {
37705
37752
  const target = event2.target;
37706
37753
  this.#held = target.closest(".decision-turn[data-pending]")?.dataset.id ?? "";
37707
37754
  const card2 = target.closest(".ask");
37708
- if (card2) into(card2, card2.closest(".asks"));
37755
+ if (card2) into(card2, card2.closest(".asks"), target);
37709
37756
  };
37710
37757
  #more = () => {
37711
37758
  const dock2 = this.renderRoot.querySelector(".asks");
37712
37759
  if (!dock2) return;
37713
- const end = Number.parseFloat(getComputedStyle(dock2).paddingBlockEnd) || 0;
37760
+ const end2 = Number.parseFloat(getComputedStyle(dock2).paddingBlockEnd) || 0;
37714
37761
  dock2.toggleAttribute(
37715
37762
  "data-more",
37716
- dock2.scrollHeight - dock2.scrollTop - dock2.clientHeight > end + 1
37763
+ dock2.scrollHeight - dock2.scrollTop - dock2.clientHeight > end2 + 1
37717
37764
  );
37718
37765
  };
37719
- #reach(id) {
37766
+ #settle() {
37767
+ this.#lift();
37768
+ const dock2 = this.renderRoot.querySelector(".asks");
37769
+ const buttons = [...this.renderRoot.querySelectorAll(".asks .decide swc-button")];
37770
+ this.#arming.watch(layout(buttons, [], dock2));
37771
+ }
37772
+ #lift() {
37720
37773
  const dock2 = this.renderRoot.querySelector(".asks");
37721
- const turn = [...dock2?.querySelectorAll(".decision-turn") ?? []].find(
37722
- (candidate) => candidate.dataset.id === id
37774
+ const turn = [...dock2?.querySelectorAll(".ask .decision-turn") ?? []].at(-1);
37775
+ const id = turn?.dataset.id ?? "";
37776
+ if (id !== this.#lifted) {
37777
+ this.#lifting = id;
37778
+ this.#raised = 0;
37779
+ }
37780
+ this.#lifted = id;
37781
+ if (!this.#lifting || !dock2 || !turn || dock2.hasAttribute("data-open")) return;
37782
+ const raised = lift(turn, dock2, this.#raised);
37783
+ if (raised !== this.#raised) this.#arming.arm();
37784
+ this.#raised = raised;
37785
+ }
37786
+ #stay = () => {
37787
+ this.#lifting = "";
37788
+ };
37789
+ #press = () => {
37790
+ this.#stay();
37791
+ this.#arming.press();
37792
+ };
37793
+ #guard() {
37794
+ this.#ends.observe();
37795
+ this.#moves.sync(
37796
+ this.renderRoot.querySelectorAll(
37797
+ "header, slicc-notices, .asks, .asks .decision, .asks .decide swc-button"
37798
+ )
37723
37799
  );
37724
- if (!dock2 || !turn) return;
37725
- const style2 = getComputedStyle(dock2);
37726
- const room = dock2.clientHeight - (Number.parseFloat(style2.scrollPaddingBlockStart) || 0) - (Number.parseFloat(style2.scrollPaddingBlockEnd) || 0);
37727
- const target = turn.offsetHeight <= room ? turn : turn.querySelector(".decide");
37728
- target?.scrollIntoView({ block: "nearest" });
37800
+ this.#settle();
37729
37801
  }
37730
37802
  #refocus() {
37731
37803
  if (!this.#held || this.renderRoot.activeElement) return;
@@ -37834,11 +37906,11 @@ var SliccChat = class _SliccChat extends ThemedElement {
37834
37906
  #bottom() {
37835
37907
  return this.#gap() <= this.#slack();
37836
37908
  }
37837
- #pin(end = true) {
37909
+ #pin(end2 = true) {
37838
37910
  if (!this.#stuck) return;
37839
37911
  const log = this.#log();
37840
37912
  const card2 = log.querySelector("swc-conversation-thread")?.lastElementChild ?? null;
37841
- const held2 = !end && card2 !== null && card2 === this.#card;
37913
+ const held2 = !end2 && card2 !== null && card2 === this.#card;
37842
37914
  this.#card = card2;
37843
37915
  log.scrollTop = held2 ? this.#head(log, card2) : log.scrollHeight;
37844
37916
  this.#last = log.scrollTop;
@@ -37923,15 +37995,21 @@ var SliccChat = class _SliccChat extends ThemedElement {
37923
37995
  this.#probed = null;
37924
37996
  globalThis.addEventListener("pointerup", this.#release, true);
37925
37997
  globalThis.addEventListener("pointercancel", this.#release, true);
37998
+ globalThis.addEventListener("resize", this.#moved);
37926
37999
  if (this.hasUpdated) this.#observe();
37927
38000
  }
37928
38001
  disconnectedCallback() {
37929
38002
  super.disconnectedCallback();
37930
38003
  globalThis.removeEventListener("pointerup", this.#release, true);
37931
38004
  globalThis.removeEventListener("pointercancel", this.#release, true);
38005
+ globalThis.removeEventListener("resize", this.#moved);
37932
38006
  this.#resize.disconnect();
37933
38007
  this.#fit.disconnect();
37934
- this.#cuts.disconnect();
38008
+ this.#ends.disconnect();
38009
+ this.#moves.disconnect();
38010
+ this.#lifted = "";
38011
+ this.#lifting = "";
38012
+ this.#arming.forget();
37935
38013
  this.#fitted = void 0;
37936
38014
  clearInterval(this.#tick);
37937
38015
  this.#tick = void 0;
@@ -37960,7 +38038,7 @@ var SliccChat = class _SliccChat extends ThemedElement {
37960
38038
  const asks = [...this.renderRoot.querySelectorAll(".ask-list .decision-turn")];
37961
38039
  for (const turn of asks) turn.tabIndex = 0;
37962
38040
  this.#more();
37963
- this.#cuts.measure();
38041
+ this.#guard();
37964
38042
  }
37965
38043
  #timed() {
37966
38044
  const model = this.model;
@@ -38179,7 +38257,7 @@ var SliccChat = class _SliccChat extends ThemedElement {
38179
38257
  this.#all = !open;
38180
38258
  this.requestUpdate();
38181
38259
  };
38182
- return b`<section class="asks" aria-label="Waiting for you" ?data-open=${open} @scroll=${this.#more}><div class="column">
38260
+ return b`<section class="asks" aria-label="Waiting for you" ?data-open=${open} @scroll=${this.#more} @pointerdown=${this.#press} @wheel=${this.#stay} @touchstart=${this.#stay} @keydown=${this.#stay} @focusin=${this.#stay}><div class="column">
38183
38261
  ${older.length ? b`<div class="waiting"><swc-action-button size="s" quiet data-action="show-waiting" aria-expanded=${open ? "true" : "false"} @click=${toggle}><swc-icon-chevron-down slot="icon"></swc-icon-chevron-down>${asks.length} waiting</swc-action-button>${timed.length ? askTimer(Math.min(...timed)) : A}</div>` : A}
38184
38262
  <div class="ask-list" aria-live="polite">${c(
38185
38263
  asks,
@@ -39523,13 +39601,19 @@ function importProfile(options2) {
39523
39601
 
39524
39602
  // src/app/names.ts
39525
39603
  var untitled = "No messages yet";
39604
+ var earlier = "Earlier messages";
39605
+ var unnamed = "Untitled chat";
39526
39606
  function short(text4, max2 = 60) {
39527
39607
  return text4.length > max2 ? `${text4.slice(0, max2 - 1).trimEnd()}\u2026` : text4;
39528
39608
  }
39529
39609
  function agentTitle(model, agent) {
39530
39610
  if (agent.title !== void 0) return agent.title.trim();
39531
- const first2 = model.agent.messages(agent.id).find((message) => message.role === "user");
39532
- return first2?.role === "user" ? first2.text.trim().split("\n")[0].trim() : "";
39611
+ const messages = model.agent.messages(agent.id);
39612
+ const first2 = messages.find((message) => message.role === "user");
39613
+ const line = first2?.role === "user" ? first2.text.trim().split("\n")[0].trim() : "";
39614
+ if (line) return line;
39615
+ if (model.agent.hasOlder?.(agent.id)) return earlier;
39616
+ return messages.length ? unnamed : "";
39533
39617
  }
39534
39618
  function twinned(name, id, rows2) {
39535
39619
  return rows2.some((row) => row.id !== id && row.name === name);
@@ -48218,11 +48302,11 @@ var UpdateVisibility = class {
48218
48302
  constructor(ready) {
48219
48303
  this.#boot = !ready;
48220
48304
  }
48221
- change(port, layout = false) {
48305
+ change(port, layout2 = false) {
48222
48306
  const failed2 = new Set(
48223
48307
  port.list().filter((item2) => item2.state === "failed").map((item2) => item2.id)
48224
48308
  );
48225
- const open = (this.#initial || layout) && this.#boot || [...failed2].some((id) => !this.#failed.has(id));
48309
+ const open = (this.#initial || layout2) && this.#boot || [...failed2].some((id) => !this.#failed.has(id));
48226
48310
  this.#initial = false;
48227
48311
  this.#failed = failed2;
48228
48312
  if (this.#boot && port.ready() && failed2.size === 0) {
@@ -49100,6 +49184,9 @@ var SliccApp = class extends ThemedElement {
49100
49184
  flex-direction: column;
49101
49185
  height: 100%;
49102
49186
  }
49187
+ .shell slicc-live {
49188
+ flex: none;
49189
+ }
49103
49190
  .shell[data-alone] header > :not(.brand),
49104
49191
  .shell[data-alone] main,
49105
49192
  .shell[data-alone] .rail.bottom {
@@ -49420,10 +49507,10 @@ var SliccApp = class extends ThemedElement {
49420
49507
  const model = this.model;
49421
49508
  if (!model) return;
49422
49509
  this.panels.quietly(() => {
49423
- const layout = this.#started !== this.screen;
49424
- if (layout) this.#start(model);
49510
+ const layout2 = this.#started !== this.screen;
49511
+ if (layout2) this.#start(model);
49425
49512
  else if (changed2.has("model")) this.#rebind(model);
49426
- this.#updates(layout);
49513
+ this.#updates(layout2);
49427
49514
  this.#retitle();
49428
49515
  });
49429
49516
  }
@@ -49433,14 +49520,14 @@ var SliccApp = class extends ThemedElement {
49433
49520
  if (panel && panel.title !== sprinkle.title) panel.api.setTitle(sprinkle.title);
49434
49521
  }
49435
49522
  }
49436
- #updates(layout) {
49523
+ #updates(layout2) {
49437
49524
  const port = this.model?.updates;
49438
49525
  if (port !== this.#updatesPort) {
49439
49526
  this.#updatesPort = port;
49440
49527
  this.#updatesVisibility = port ? new UpdateVisibility(port.ready()) : null;
49441
49528
  }
49442
49529
  if (!port || !this.#offers("updates")) return;
49443
- const change = this.#updatesVisibility?.change(port, layout);
49530
+ const change = this.#updatesVisibility?.change(port, layout2);
49444
49531
  if (change === "open") {
49445
49532
  const restored = this.dock.api.getPanel("updates");
49446
49533
  if (restored) this.dock.reveal("updates");
@@ -49524,8 +49611,8 @@ var SliccApp = class extends ThemedElement {
49524
49611
  this.#saving = true;
49525
49612
  this.#save();
49526
49613
  }
49527
- #offered(layout, factories) {
49528
- return Object.values(layout?.panels ?? {}).every(
49614
+ #offered(layout2, factories) {
49615
+ return Object.values(layout2?.panels ?? {}).every(
49529
49616
  (panel) => (panel.contentComponent ?? "") in factories
49530
49617
  );
49531
49618
  }
@@ -49932,6 +50019,7 @@ var SliccApp = class extends ThemedElement {
49932
50019
  ) : A}
49933
50020
  ${this.#headerButton("theme", color2 === "dark" ? "Switch to light theme" : "Switch to dark theme", b`<swc-icon-contrast slot="icon"></swc-icon-contrast>`, () => this.toggleColor())}
49934
50021
  </header>
50022
+ ${this.model?.live ? b`<slicc-live .model=${this.model} ?compact=${this.screen === "phone"}></slicc-live>` : A}
49935
50023
  ${lonely ? b`<div class="alone" role="status" data-tabs="alone"><p>${alone2}</p></div>` : A}
49936
50024
  ${paused && !lonely ? b`<div class="alone" data-follow=${paused.kind}><slicc-follow page .model=${this.model}></slicc-follow></div>` : A}
49937
50025
  <main>
@@ -51238,6 +51326,45 @@ function trayAsking(approval) {
51238
51326
  return `${name} wants a new join URL. Linked devices move to it, and the old one stops working.`;
51239
51327
  return `${name} wants to unlink ${approval.device?.name ?? "a device"} from this seven.`;
51240
51328
  }
51329
+ var captureActs = {
51330
+ "screen:still": ["take a picture of your screen", "take pictures of your screen"],
51331
+ "screen:video": ["record your screen", "record your screen"],
51332
+ "camera:still": ["take a photo with your camera", "take photos with your camera"],
51333
+ "camera:video": ["record your camera", "record your camera"],
51334
+ "microphone:audio": ["record your microphone", "record your microphone"]
51335
+ };
51336
+ function captureAct(detail) {
51337
+ const fallback = `capture your ${detail.what}`;
51338
+ return captureActs[`${detail.what}:${detail.mode}`] ?? [fallback, fallback];
51339
+ }
51340
+ function captureLine(approval) {
51341
+ const { detail } = approval;
51342
+ const [act2] = captureAct(detail);
51343
+ const device = detail.device ? ` (${detail.device})` : "";
51344
+ const still2 = detail.mode === "still";
51345
+ const span = detail.seconds ? ` for up to ${detail.seconds} ${detail.seconds === 1 ? "second" : "seconds"}` : " until it\u2019s stopped";
51346
+ const audio = [
51347
+ detail.system ? "system audio" : "",
51348
+ detail.microphone && detail.what !== "microphone" ? "microphone" : ""
51349
+ ].filter(Boolean);
51350
+ const extra = still2 || !audio.length ? "" : `, with your ${audio.join(" and ")}`;
51351
+ const line = `${act2}${device}${still2 ? "" : span}${extra}`;
51352
+ return `${line[0].toUpperCase()}${line.slice(1)} \xB7 ${detail.program}`;
51353
+ }
51354
+ function captureAsking(approval) {
51355
+ return `${approval.agentName ?? "This cone"} wants to use your ${approval.detail.what} for ${approval.requester.name}:`;
51356
+ }
51357
+ function captureWaiting(approval) {
51358
+ return `${approval.agentName ?? "This cone"} wants to use your ${approval.detail.what} for ${approval.requester.name}, which waits for the owner's approval.`;
51359
+ }
51360
+ function captureAlwaysHint(approval) {
51361
+ const [, acts] = captureAct(approval.detail);
51362
+ const picker = approval.detail.what === "screen" ? " You still choose what to share each time." : "";
51363
+ return `Always allow lets ${approval.agentName ?? "this cone"} ${acts} for ${approval.requester.name} without asking again.${picker}`;
51364
+ }
51365
+ function clickWhere(approval) {
51366
+ return approval.device ? `Click in seven\u2019s tab on ${approval.device.name}.` : "Click in seven\u2019s tab.";
51367
+ }
51241
51368
  function secretTitle(approval) {
51242
51369
  return approval.mode === "reveal" ? `Reveal ${approval.name} to a program?` : `Enter a value for ${approval.name}?`;
51243
51370
  }
@@ -51263,7 +51390,8 @@ function secretWaiting(approval) {
51263
51390
  function approved(approval) {
51264
51391
  if (approval.kind === "sudo") return sudo(approval);
51265
51392
  if (approval.kind === "secret") return processLine(approval);
51266
- if (approval.kind === "guest-message" || approval.kind === "tray") return "";
51393
+ if (approval.kind === "guest-message" || approval.kind === "tray" || approval.kind === "click" || approval.kind === "capture")
51394
+ return "";
51267
51395
  if (approval.summary.trim()) return approval.summary;
51268
51396
  return approval.args?.trim() ? `${approval.tool}
51269
51397
  ${approval.args}` : "";
@@ -51272,6 +51400,7 @@ function truncated(approval) {
51272
51400
  return approval.kind === "guest-tool" && !approval.summary.trim() && !!approval.argsTruncated;
51273
51401
  }
51274
51402
  function hintOf(approval) {
51403
+ if (approval.kind === "capture") return captureAlwaysHint(approval);
51275
51404
  return approval.kind === "sudo" ? commandText(alwaysHint(approval), false) : guestAlwaysHint(approval);
51276
51405
  }
51277
51406
  var tooLong = "This request is too long to show in full, so it can\u2019t be allowed.";
@@ -51283,13 +51412,18 @@ var levels2 = {
51283
51412
  2: { name: "permissions", label: "Changes permissions." },
51284
51413
  3: { name: "harm", label: "Could harm the system." }
51285
51414
  };
51415
+ var captureLevels = {
51416
+ 1: { name: "routine", label: "Routine capture." },
51417
+ 2: { name: "permissions", label: "Records what you share." },
51418
+ 3: { name: "harm", label: "Could expose something private." }
51419
+ };
51286
51420
  var fits = (aligned) => aligned === void 0 ? "" : aligned ? " It fits what you asked for." : " It isn\u2019t clear it serves what you asked for.";
51287
51421
  function leveled(approval) {
51288
51422
  const level = approval.verdict?.level;
51289
51423
  return level === 1 || level === 2 || level === 3 ? level : null;
51290
51424
  }
51291
51425
  function offersAlways(approval) {
51292
- return approval.kind !== "tray" && approval.kind !== "secret" && approval.always && (approval.kind !== "sudo" || leveled(approval) !== null);
51426
+ return approval.kind !== "tray" && approval.kind !== "secret" && approval.kind !== "click" && approval.always && (approval.kind !== "sudo" || leveled(approval) !== null);
51293
51427
  }
51294
51428
  function verdictNote(approval) {
51295
51429
  if (approval.kind !== "sudo" || offersAlways(approval)) return "";
@@ -51307,7 +51441,7 @@ function judged(approval) {
51307
51441
  const { verdict, judging, verdictError } = approval;
51308
51442
  const level = leveled(approval);
51309
51443
  if (verdict && level) {
51310
- const { name, label } = levels2[level];
51444
+ const { name, label } = (approval.kind === "capture" ? captureLevels : levels2)[level];
51311
51445
  return b`<div class="judged" data-verdict=${name} data-level=${level}>${level === 3 ? b`<swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle>` : A}<p><strong>${label}</strong>${verdict.reason ? b` ${shown5(verdict.reason)}` : ""}${fits(verdict.aligned)}</p></div>`;
51312
51446
  }
51313
51447
  if (judging) return b`<div class="judged" data-verdict="checking"><p>Checking…</p></div>`;
@@ -51345,6 +51479,16 @@ var titles = {
51345
51479
  ask: "",
51346
51480
  elsewhere: "Answered elsewhere",
51347
51481
  expired: "Secret request timed out"
51482
+ },
51483
+ click: {
51484
+ ask: "",
51485
+ elsewhere: "Answered elsewhere",
51486
+ expired: "Click request timed out"
51487
+ },
51488
+ capture: {
51489
+ ask: "Allow a guest\u2019s capture?",
51490
+ elsewhere: "Answered elsewhere",
51491
+ expired: "Capture request timed out"
51348
51492
  }
51349
51493
  };
51350
51494
  var approvalKinds = Object.freeze(
@@ -51353,11 +51497,31 @@ var approvalKinds = Object.freeze(
51353
51497
  function title(approval) {
51354
51498
  if (approval.kind === "tray") return trayTitle(approval);
51355
51499
  if (approval.kind === "secret") return secretTitle(approval);
51500
+ if (approval.kind === "click") return approval.title;
51356
51501
  return titles[approval.kind].ask;
51357
51502
  }
51358
51503
  var toAnswer = "Scroll to the end of the command to answer it.";
51504
+ function extras(approval) {
51505
+ if (approval.kind === "secret")
51506
+ return [
51507
+ approval.mode,
51508
+ approval.name,
51509
+ approval.reveal,
51510
+ approval.prompt ?? "",
51511
+ approval.requester
51512
+ ];
51513
+ if (approval.kind === "click")
51514
+ return [approval.title, approval.body, approval.action, approval.here, approval.device ?? null];
51515
+ if (approval.kind === "capture") return [approval.detail, approval.requester];
51516
+ return [];
51517
+ }
51518
+ function answerable(approval, decision2) {
51519
+ if (decision2 === "deny") return true;
51520
+ if (approval.kind === "secret") return false;
51521
+ return approval.kind !== "click" || approval.here;
51522
+ }
51359
51523
  function identity(approval) {
51360
- const extra = approval.kind === "secret" ? [approval.mode, approval.name, approval.reveal, approval.prompt ?? "", approval.requester] : [];
51524
+ const extra = extras(approval);
51361
51525
  return JSON.stringify([approval.kind, approval.createdAt, approved(approval), ...extra]);
51362
51526
  }
51363
51527
  function gone(reason) {
@@ -51373,10 +51537,9 @@ var SliccApprovals = class extends ModelElement {
51373
51537
  frameError: { state: true }
51374
51538
  };
51375
51539
  arming = 500;
51376
- #changed = 0;
51377
- #pressed = 0;
51378
- #layout = "";
51379
- #moves = new ResizeObserver(() => this.#settle());
51540
+ #arming = new Arming(() => this.arming);
51541
+ #moves = new Watched(new ResizeObserver(() => this.#settle()));
51542
+ #moved = () => this.#settle();
51380
51543
  #showing = null;
51381
51544
  #pending = /* @__PURE__ */ new Set();
51382
51545
  #done = /* @__PURE__ */ new Set();
@@ -51403,6 +51566,7 @@ var SliccApprovals = class extends ModelElement {
51403
51566
  static styles = [
51404
51567
  dialogStyles,
51405
51568
  controlStyles,
51569
+ endCss,
51406
51570
  i`
51407
51571
  :host {
51408
51572
  display: contents;
@@ -51424,17 +51588,12 @@ var SliccApprovals = class extends ModelElement {
51424
51588
  white-space: pre-wrap;
51425
51589
  overflow-wrap: anywhere;
51426
51590
  }
51427
- .command .lines:not([data-clamp]) {
51591
+ .command .lines {
51428
51592
  display: block;
51429
51593
  max-block-size: min(16lh, 50dvh);
51430
51594
  overflow: auto;
51431
51595
  overscroll-behavior: contain;
51432
51596
  }
51433
- .command .end {
51434
- display: inline-block;
51435
- inline-size: 0;
51436
- block-size: 0;
51437
- }
51438
51597
  .guest {
51439
51598
  margin-block-start: var(--swc-spacing-200);
51440
51599
  padding: var(--swc-spacing-200) var(--swc-spacing-300);
@@ -51463,6 +51622,11 @@ var SliccApprovals = class extends ModelElement {
51463
51622
  .cwd {
51464
51623
  overflow-wrap: anywhere;
51465
51624
  }
51625
+ .where {
51626
+ margin-block-start: var(--swc-spacing-200);
51627
+ font-weight: var(--swc-bold-font-weight);
51628
+ overflow-wrap: anywhere;
51629
+ }
51466
51630
  .timer {
51467
51631
  margin-block-start: var(--swc-spacing-300);
51468
51632
  font-variant-numeric: tabular-nums;
@@ -51612,11 +51776,16 @@ var SliccApprovals = class extends ModelElement {
51612
51776
  })
51613
51777
  ];
51614
51778
  }
51779
+ connectedCallback() {
51780
+ super.connectedCallback();
51781
+ globalThis.addEventListener("resize", this.#moved);
51782
+ }
51615
51783
  disconnectedCallback() {
51616
51784
  super.disconnectedCallback();
51785
+ globalThis.removeEventListener("resize", this.#moved);
51617
51786
  this.#tick(false);
51618
51787
  this.#showing = null;
51619
- this.#layout = "";
51788
+ this.#arming.forget();
51620
51789
  this.#moves.disconnect();
51621
51790
  this.#ends.disconnect();
51622
51791
  }
@@ -51630,7 +51799,7 @@ var SliccApprovals = class extends ModelElement {
51630
51799
  async decide(approval, decision2) {
51631
51800
  const port = this.model?.approvals;
51632
51801
  const { id } = approval;
51633
- if (!port?.decide || this.busy || this.gone || this.#showing?.id !== id || this.#done.has(id) || this.#closed.has(id) || approval.kind === "secret" && decision2 !== "deny" || decision2 !== "deny" && (!this.#settled(performance.now()) || !this.#whole(approval)))
51802
+ if (!port?.decide || this.busy || this.gone || this.#showing?.id !== id || this.#done.has(id) || this.#closed.has(id) || !answerable(approval, decision2) || decision2 !== "deny" && (!this.#arming.settled() || !this.#whole(approval)))
51634
51803
  return;
51635
51804
  const live = port.list().find(({ id: id2 }) => id2 === approval.id);
51636
51805
  if (decision2 === "always" && !(live && offersAlways(live))) return;
@@ -51686,34 +51855,15 @@ var SliccApprovals = class extends ModelElement {
51686
51855
  if (next?.id === showing?.id) return;
51687
51856
  this.frameError = null;
51688
51857
  this.#showing = next;
51689
- this.#changed = performance.now();
51690
- }
51691
- #settled(at) {
51692
- return at - this.#changed >= this.arming;
51858
+ this.#arming.arm();
51693
51859
  }
51694
51860
  #settle() {
51695
51861
  const dialog = this.renderRoot.querySelector("dialog");
51696
51862
  const buttons = [...this.renderRoot.querySelectorAll("[slot=button]")];
51697
- const layout = JSON.stringify([
51698
- dialog?.dataset.approval,
51699
- dialog?.dataset.gone,
51700
- buttons.map((button) => {
51701
- const { left, top, width, height } = button.getBoundingClientRect();
51702
- return [
51703
- button.dataset.action,
51704
- button.textContent,
51705
- button.hasAttribute("disabled"),
51706
- button.hasAttribute("pending"),
51707
- ...[left, top, width, height].map(Math.round)
51708
- ];
51709
- })
51710
- ]);
51711
- if (layout === this.#layout) return;
51712
- this.#layout = layout;
51713
- this.#changed = performance.now();
51863
+ this.#arming.watch(layout(buttons, [dialog?.dataset.approval, dialog?.dataset.gone]));
51714
51864
  }
51715
51865
  #click(event2, approval, decision2) {
51716
- if (!this.#settled(event2.detail ? this.#pressed : performance.now())) return;
51866
+ if (!this.#arming.counts(event2)) return;
51717
51867
  void this.decide(approval, decision2);
51718
51868
  }
51719
51869
  updated(changed2) {
@@ -51722,9 +51872,7 @@ var SliccApprovals = class extends ModelElement {
51722
51872
  this.#tick(this.isConnected && all2.length > 0);
51723
51873
  this.#ends.observe();
51724
51874
  const dialog = this.renderRoot.querySelector("dialog");
51725
- if (dialog)
51726
- for (const box of dialog.querySelectorAll("sp-alert-dialog, [slot=button]"))
51727
- this.#moves.observe(box);
51875
+ this.#moves.sync(dialog?.querySelectorAll("sp-alert-dialog, [slot=button]") ?? []);
51728
51876
  this.#settle();
51729
51877
  const key = dialog ? `${dialog.dataset.approval}:${this.#generation.get(dialog.dataset.approval)}:${dialog.dataset.gone ?? ""}:${dialog.hasAttribute("data-rejected")}` : "";
51730
51878
  if (key === this.#shown) return;
@@ -51807,7 +51955,7 @@ var SliccApprovals = class extends ModelElement {
51807
51955
  #dialog(approval, key, content3) {
51808
51956
  return i23(
51809
51957
  key,
51810
- b`<dialog role="alertdialog" aria-labelledby="title" aria-describedby="asking" data-approval=${approval.id} data-kind=${approval.kind} data-requester=${approval.requester.kind} data-gone=${this.gone?.reason ?? A} data-rejected=${!this.gone && this.failure?.id === approval.id ? "" : A} @pointerdown=${() => this.#pressed = performance.now()} @cancel=${(event2) => this.#cancel(event2, approval)}>${content3}</dialog>`
51958
+ b`<dialog role="alertdialog" aria-labelledby="title" aria-describedby="asking" data-approval=${approval.id} data-kind=${approval.kind} data-requester=${approval.requester.kind} data-gone=${this.gone?.reason ?? A} data-rejected=${!this.gone && this.failure?.id === approval.id ? "" : A} @pointerdown=${this.#arming.press} @cancel=${(event2) => this.#cancel(event2, approval)}>${content3}</dialog>`
51811
51959
  );
51812
51960
  }
51813
51961
  #whole(approval) {
@@ -51823,10 +51971,16 @@ var SliccApprovals = class extends ModelElement {
51823
51971
  const text4 = approved(approval);
51824
51972
  if (!text4) return b`<p class="hint" data-id="no-details">This request has no details.</p>`;
51825
51973
  const command2 = approval.kind === "sudo" || approval.kind === "secret";
51826
- return b`<pre class="command" data-command=${command2 ? "" : A} data-summary=${command2 ? A : ""}><span class="lines">${command2 ? commandText(text4) : text4}${pending ? b`<span class="end" data-end=${id}></span>` : A}</span></pre>`;
51974
+ return b`<pre class="command" data-command=${command2 ? "" : A} data-summary=${command2 ? A : ""}><span class="lines">${command2 ? commandText(text4) : text4}${pending ? end(id) : A}</span></pre>`;
51827
51975
  }
51828
51976
  #request(approval, pending = false) {
51829
51977
  if (approval.kind === "tray") return b`<p id="asking">${trayAsking(approval)}</p>`;
51978
+ if (approval.kind === "click")
51979
+ return b`<p id="asking">${commandText(approval.body, false)}</p>
51980
+ ${approval.here ? A : b`<p class="where" data-where>${commandText(clickWhere(approval), false)}</p>`}`;
51981
+ if (approval.kind === "capture")
51982
+ return b`<p id="asking">${commandText(captureAsking(approval), false)}</p>
51983
+ <div class="guest" data-capture>${commandText(captureLine(approval), false)}</div>`;
51830
51984
  if (approval.kind === "sudo")
51831
51985
  return b`<p id="asking">${commandText(asking2(approval), false)}:</p>
51832
51986
  ${this.#command(approval, pending)}`;
@@ -51845,16 +51999,18 @@ var SliccApprovals = class extends ModelElement {
51845
51999
  ${files.length ? b`<ul class="files" data-attachments>${files.map((file) => b`<li>${file.name} · ${file.mimeType} · ${size3(file.size)}</li>`)}</ul>` : A}`;
51846
52000
  }
51847
52001
  #notes(approval, gate, always) {
51848
- if (approval.kind === "tray" || approval.kind === "secret") return A;
52002
+ if (approval.kind === "tray" || approval.kind === "secret" || approval.kind === "click")
52003
+ return A;
51849
52004
  const note = verdictNote(approval);
51850
52005
  return b`<div class="notes" data-notes><div class="judge" aria-live="polite">${judged(approval)}${note ? b`<p class="hint" data-verdict-note>${note}</p>` : A}</div>${gate ? b`<p class="hint" data-allow-hint>${gate}</p>` : A}${always ? b`<p class="hint" data-always-hint>${hintOf(approval)}</p>` : A}</div>`;
51851
52006
  }
51852
52007
  #actions(approval, rejected, always) {
51853
52008
  if (rejected)
51854
52009
  return b`<swc-button slot="button" variant="secondary" fill-style="outline" data-action="close" @click=${() => this.#dismiss(approval)}>Close</swc-button>`;
51855
- return b`${this.#button(approval, "deny", "Deny", "secondary")}
52010
+ const click = approval.kind === "click";
52011
+ return b`${this.#button(approval, "deny", click ? "Cancel" : "Deny", "secondary")}
51856
52012
  ${always ? this.#button(approval, "always", inCwd(approval) ? "Always allow in this directory" : "Always allow", "secondary") : A}
51857
- ${approval.kind === "secret" ? A : this.#button(approval, "once", "Allow once", "accent")}`;
52013
+ ${answerable(approval, "once") ? this.#button(approval, "once", click ? approval.action : "Allow once", "accent") : A}`;
51858
52014
  }
51859
52015
  render() {
51860
52016
  if (this.gone) {
@@ -51865,7 +52021,7 @@ var SliccApprovals = class extends ModelElement {
51865
52021
  b`<sp-alert-dialog variant="information" data-approval-kind=${approval2.kind}>
51866
52022
  <h2 id="title" slot="heading">${titles[approval2.kind][reason]}</h2>
51867
52023
  ${this.#request(approval2)}
51868
- ${reason === "expired" ? b`<p class="timer" data-timer>Denied because nobody answered in time.</p>` : A}
52024
+ ${reason === "expired" ? b`<p class="timer" data-timer>${approval2.kind === "click" ? "Cancelled because nobody clicked in time." : "Denied because nobody answered in time."}</p>` : A}
51869
52025
  <swc-button slot="button" variant="secondary" fill-style="outline" data-action="close" @click=${() => this.close()}>Close</swc-button>
51870
52026
  </sp-alert-dialog>`
51871
52027
  );
@@ -51880,13 +52036,13 @@ var SliccApprovals = class extends ModelElement {
51880
52036
  return this.#dialog(
51881
52037
  approval,
51882
52038
  `${approval.id}:${this.#generation.get(approval.id)}`,
51883
- b`<sp-alert-dialog variant="warning" data-approval-kind=${approval.kind}>
52039
+ b`<sp-alert-dialog variant=${approval.kind === "click" ? "information" : "warning"} data-approval-kind=${approval.kind}>
51884
52040
  <h2 id="title" slot="heading">${commandText(title(approval), false)}</h2>
51885
52041
  ${this.#request(approval, true)}
51886
52042
  ${approval.kind === "sudo" && approval.cwd ? b`<p class="cwd">In ${commandText(approval.cwd, false)}</p>` : A}
51887
52043
  ${this.#notes(approval, gate, always)}
51888
52044
  ${approval.kind === "secret" && !failure3 ? this.#frame(approval) : A}
51889
- ${failure3 ? b`<p class="problem" role="alert" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${failure3}</span></p>` : b`<p class="timer" data-timer>Denied automatically in ${countdown(approval.expiresAt - this.now)}.</p>`}
52045
+ ${failure3 ? b`<p class="problem" role="alert" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${failure3}</span></p>` : b`<p class="timer" data-timer>${approval.kind === "click" ? "Cancelled" : "Denied"} automatically in ${countdown(approval.expiresAt - this.now)}.</p>`}
51890
52046
  <p class="more" data-more=${rest.length ? "" : A}>${rest.length === 1 ? "1 more request is waiting." : rest.length ? `${rest.length} more requests are waiting.` : ""}</p>
51891
52047
  ${this.#actions(approval, !!failure3, always)}
51892
52048
  </sp-alert-dialog>`
@@ -53621,6 +53777,116 @@ var SliccDiffPanel = class extends ThemedElement {
53621
53777
  }
53622
53778
  };
53623
53779
 
53780
+ // src/app/live.ts
53781
+ function elapsed(ms) {
53782
+ const seconds = Math.max(0, Math.floor(ms / 1e3));
53783
+ return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
53784
+ }
53785
+ function liveLine(item2, now) {
53786
+ return [item2.label, item2.what, item2.asker, elapsed(now - item2.since)].filter(Boolean).join(" \xB7 ");
53787
+ }
53788
+ var SliccLive = class extends ModelElement {
53789
+ static properties = {
53790
+ ...ModelElement.properties,
53791
+ compact: { type: Boolean, reflect: true },
53792
+ now: { state: true }
53793
+ };
53794
+ #timer = null;
53795
+ constructor() {
53796
+ super();
53797
+ this.compact = false;
53798
+ this.now = Date.now();
53799
+ }
53800
+ static styles = i`
53801
+ :host {
53802
+ display: block;
53803
+ }
53804
+ .live {
53805
+ display: flex;
53806
+ flex-direction: column;
53807
+ gap: var(--swc-spacing-50);
53808
+ padding: var(--swc-spacing-75) var(--swc-spacing-200);
53809
+ border-bottom: var(--swc-border-width-100) solid var(--swc-gray-200);
53810
+ background: var(--swc-background-layer-1-color);
53811
+ font-size: var(--swc-font-size-75);
53812
+ color: var(--swc-neutral-content-color-default);
53813
+ }
53814
+ .chip {
53815
+ display: flex;
53816
+ align-items: center;
53817
+ gap: var(--swc-spacing-100);
53818
+ min-width: 0;
53819
+ }
53820
+ .dot {
53821
+ flex: none;
53822
+ inline-size: var(--swc-spacing-100);
53823
+ block-size: var(--swc-spacing-100);
53824
+ border-radius: 50%;
53825
+ background: var(--swc-negative-visual-color);
53826
+ }
53827
+ .text {
53828
+ flex: 0 1 auto;
53829
+ min-width: 0;
53830
+ overflow: hidden;
53831
+ white-space: nowrap;
53832
+ text-overflow: ellipsis;
53833
+ font-variant-numeric: tabular-nums;
53834
+ }
53835
+ .label {
53836
+ font-weight: var(--swc-bold-font-weight);
53837
+ }
53838
+ :host([compact]) .detail {
53839
+ display: none;
53840
+ }
53841
+ swc-action-button {
53842
+ flex: none;
53843
+ }
53844
+ `;
53845
+ subscribe(model) {
53846
+ return model.live ? [
53847
+ model.live.on("items", () => {
53848
+ this.now = Date.now();
53849
+ this.requestUpdate();
53850
+ })
53851
+ ] : [];
53852
+ }
53853
+ disconnectedCallback() {
53854
+ super.disconnectedCallback();
53855
+ this.#tick(false);
53856
+ }
53857
+ #items() {
53858
+ return this.model?.live?.items() ?? [];
53859
+ }
53860
+ #tick(on2) {
53861
+ if (on2 && !this.#timer) this.#timer = setInterval(() => this.now = Date.now(), 1e3);
53862
+ if (!on2 && this.#timer) {
53863
+ clearInterval(this.#timer);
53864
+ this.#timer = null;
53865
+ }
53866
+ }
53867
+ updated(changed2) {
53868
+ super.updated(changed2);
53869
+ this.#tick(this.isConnected && this.#items().length > 0);
53870
+ }
53871
+ #chip(item2) {
53872
+ const rest = liveLine({ ...item2, label: "" }, this.now);
53873
+ return b`<div class="chip" role="listitem" data-id=${item2.id} data-kind=${item2.kind}>
53874
+ <span class="dot" aria-hidden="true"></span>
53875
+ <span class="text" title=${liveLine(item2, this.now)}><span class="label">${item2.label}</span><span class="detail"> · ${rest}</span></span>
53876
+ <swc-action-button size="s" quiet data-action="live-act" accessible-label=${`${item2.action.label}: ${item2.label}`} @click=${() => this.model?.live?.act(item2.id)}>${item2.action.label}</swc-action-button>
53877
+ </div>`;
53878
+ }
53879
+ render() {
53880
+ const items = this.#items();
53881
+ if (!items.length) return A;
53882
+ return b`<div class="live" role="list" aria-label="Live now" data-surface="live">${c(
53883
+ items,
53884
+ (item2) => item2.id,
53885
+ (item2) => this.#chip(item2)
53886
+ )}</div>`;
53887
+ }
53888
+ };
53889
+
53624
53890
  // src/app/lucide.ts
53625
53891
  var library = null;
53626
53892
  function load2() {
@@ -54445,6 +54711,25 @@ var SliccNotices = class extends ModelElement {
54445
54711
  <p>It waits for the owner's answer. Denied automatically at ${deadline(approval.expiresAt)}.</p>
54446
54712
  </div>
54447
54713
  </div>`;
54714
+ if (approval.kind === "click")
54715
+ return b`<div class="notice" role="status" data-approval-notice=${approval.id} data-approval-kind="click" data-tone="warning">
54716
+ <swc-icon-alert-triangle></swc-icon-alert-triangle>
54717
+ <div class="text">
54718
+ <span class="title">${commandText(approval.title, false)}</span>
54719
+ <p>${commandText(approval.body, false)}</p>
54720
+ <p>${commandText(clickWhere(approval), false)} Cancelled automatically at ${deadline(approval.expiresAt)}.</p>
54721
+ </div>
54722
+ </div>`;
54723
+ if (approval.kind === "capture")
54724
+ return b`<div class="notice" role="status" data-approval-notice=${approval.id} data-approval-kind="capture" data-tone="warning">
54725
+ <swc-icon-alert-triangle></swc-icon-alert-triangle>
54726
+ <div class="text">
54727
+ <span class="title">Waiting for approval of a guest’s capture</span>
54728
+ <p>${commandText(captureWaiting(approval), false)}</p>
54729
+ <p>${commandText(captureLine(approval), false)}</p>
54730
+ <p>Denied automatically at ${deadline(approval.expiresAt)}.</p>
54731
+ </div>
54732
+ </div>`;
54448
54733
  if (approval.kind !== "sudo")
54449
54734
  return b`<div class="notice" role="status" data-approval-notice=${approval.id} data-approval-kind=${approval.kind} data-tone="warning">
54450
54735
  <swc-icon-alert-triangle></swc-icon-alert-triangle>
@@ -54828,7 +55113,8 @@ var SliccSettings = class extends ThemedElement {
54828
55113
  .switched {
54829
55114
  grid-column: 2;
54830
55115
  }
54831
- .developer {
55116
+ .developer,
55117
+ .capture {
54832
55118
  display: grid;
54833
55119
  gap: var(--swc-spacing-75);
54834
55120
  padding-block: var(--swc-spacing-75);
@@ -54839,7 +55125,8 @@ var SliccSettings = class extends ThemedElement {
54839
55125
  gap: var(--swc-spacing-100);
54840
55126
  }
54841
55127
  .developer .hint,
54842
- .developer .failure {
55128
+ .developer .failure,
55129
+ .capture .hint {
54843
55130
  margin: 0;
54844
55131
  line-height: var(--swc-line-height-200);
54845
55132
  }
@@ -55091,7 +55378,8 @@ var SliccSettings = class extends ThemedElement {
55091
55378
  settle3();
55092
55379
  }),
55093
55380
  model.settings.on("providers", update),
55094
- ...model.vault ? [model.vault.on("status", update), model.vault.on("list", update)] : []
55381
+ ...model.vault ? [model.vault.on("status", update), model.vault.on("list", update)] : [],
55382
+ ...model.switches ? [model.switches.on("switches", update)] : []
55095
55383
  ];
55096
55384
  }
55097
55385
  focus() {
@@ -55160,6 +55448,27 @@ var SliccSettings = class extends ThemedElement {
55160
55448
  </div>
55161
55449
  </div>`;
55162
55450
  }
55451
+ #switches() {
55452
+ const port = this.model?.switches;
55453
+ const list6 = port?.list() ?? [];
55454
+ if (!port || !list6.length) return A;
55455
+ return b`<h2 data-section="switches">Capture and devices</h2>
55456
+ <div class="rows">
55457
+ <div class="row">
55458
+ <span class="label">Allow</span>
55459
+ <div class="capture">
55460
+ <div class="switches" data-surface="switches">
55461
+ ${c(
55462
+ list6,
55463
+ (item2) => item2.key,
55464
+ (item2) => b`<sp-switch .checked=${l(item2.on)} data-id=${item2.key} @change=${(event2) => port.set(item2.key, this.#checked(event2))}>${item2.label}</sp-switch>`
55465
+ )}
55466
+ </div>
55467
+ <p class="hint">Programs can capture only what’s on here. Turning one off stops what’s live under it.</p>
55468
+ </div>
55469
+ </div>
55470
+ </div>`;
55471
+ }
55163
55472
  #cancelled = /* @__PURE__ */ new Set();
55164
55473
  #busy(id, on2) {
55165
55474
  const rest = [...this.pending].filter((candidate) => candidate !== id);
@@ -56375,6 +56684,7 @@ var SliccSettings = class extends ThemedElement {
56375
56684
  </div>
56376
56685
  ${this.#developerRow()}
56377
56686
  </div>
56687
+ ${this.#switches()}
56378
56688
  <h2 data-section="accounts">Accounts</h2>
56379
56689
  ${this.#providerList(providers)}
56380
56690
  ${this.#serverList(servers)}
@@ -56432,9 +56742,9 @@ function args(value, start2) {
56432
56742
  function branch(value, side) {
56433
56743
  const at = value.indexOf("light-dark(");
56434
56744
  if (at < 0) return value;
56435
- const [parts3, end] = args(value, at + "light-dark(".length);
56745
+ const [parts3, end2] = args(value, at + "light-dark(".length);
56436
56746
  const picked2 = branch((parts3[side] ?? "").trim(), side);
56437
- return value.slice(0, at) + picked2 + branch(value.slice(end + 1), side);
56747
+ return value.slice(0, at) + picked2 + branch(value.slice(end2 + 1), side);
56438
56748
  }
56439
56749
  function frameTokens(found) {
56440
56750
  const entries = [...found];
@@ -59022,20 +59332,20 @@ var Splitview = class {
59022
59332
  this.distributeEmptySpace();
59023
59333
  this.layoutViews();
59024
59334
  };
59025
- const end = () => {
59335
+ const end2 = () => {
59026
59336
  for (const item2 of this.viewItems) item2.enabled = true;
59027
59337
  iframes.release();
59028
59338
  this.saveProportions();
59029
59339
  doc.removeEventListener("pointermove", onPointerMove);
59030
- doc.removeEventListener("pointerup", end);
59031
- doc.removeEventListener("pointercancel", end);
59032
- doc.removeEventListener("contextmenu", end);
59340
+ doc.removeEventListener("pointerup", end2);
59341
+ doc.removeEventListener("pointercancel", end2);
59342
+ doc.removeEventListener("contextmenu", end2);
59033
59343
  this._onDidSashEnd.fire(void 0);
59034
59344
  };
59035
59345
  doc.addEventListener("pointermove", onPointerMove);
59036
- doc.addEventListener("pointerup", end);
59037
- doc.addEventListener("pointercancel", end);
59038
- doc.addEventListener("contextmenu", end);
59346
+ doc.addEventListener("pointerup", end2);
59347
+ doc.addEventListener("pointercancel", end2);
59348
+ doc.addEventListener("contextmenu", end2);
59039
59349
  };
59040
59350
  sash.addEventListener("pointerdown", onPointerStart);
59041
59351
  const sashItem = {
@@ -69105,7 +69415,7 @@ var Overlay = class Overlay2 extends CompositeDisposable {
69105
69415
  captureTarget.setPointerCapture(pointerId);
69106
69416
  } catch (_unused) {
69107
69417
  }
69108
- const end = () => {
69418
+ const end2 = () => {
69109
69419
  toggleClass(this._element, "dv-resize-container-dragging", false);
69110
69420
  this._dragMove.value = Disposable.NONE;
69111
69421
  this._onDidChangeEnd.fire();
@@ -69173,7 +69483,7 @@ var Overlay = class Overlay2 extends CompositeDisposable {
69173
69483
  hasMoved = true;
69174
69484
  this._onDidStartMoving.fire();
69175
69485
  }
69176
- }), addDisposableListener(globalThis.window, "pointerup", end), addDisposableListener(globalThis.window, "pointercancel", end));
69486
+ }), addDisposableListener(globalThis.window, "pointerup", end2), addDisposableListener(globalThis.window, "pointercancel", end2));
69177
69487
  };
69178
69488
  this.addDisposables(addDisposableListener(dragTarget, "pointerdown", (event2) => {
69179
69489
  if (event2.defaultPrevented) {
@@ -69205,7 +69515,7 @@ var Overlay = class Overlay2 extends CompositeDisposable {
69205
69515
  resizeHandleElement.setPointerCapture(pointerId);
69206
69516
  } catch (_unused3) {
69207
69517
  }
69208
- const end = () => {
69518
+ const end2 = () => {
69209
69519
  move.dispose();
69210
69520
  this._onDidChangeEnd.fire();
69211
69521
  };
@@ -69297,7 +69607,7 @@ var Overlay = class Overlay2 extends CompositeDisposable {
69297
69607
  resizeHandleElement.releasePointerCapture(pointerId);
69298
69608
  } catch (_unused4) {
69299
69609
  }
69300
- } }, addDisposableListener(globalThis.window, "pointerup", end), addDisposableListener(globalThis.window, "pointercancel", end));
69610
+ } }, addDisposableListener(globalThis.window, "pointerup", end2), addDisposableListener(globalThis.window, "pointercancel", end2));
69301
69611
  }));
69302
69612
  }
69303
69613
  getMinimumWidth(width) {
@@ -75348,10 +75658,10 @@ var SliccDock = class extends HTMLElement {
75348
75658
  toJSON() {
75349
75659
  return this.api.toJSON();
75350
75660
  }
75351
- restore(layout) {
75352
- if (!layout) return false;
75661
+ restore(layout2) {
75662
+ if (!layout2) return false;
75353
75663
  try {
75354
- this.api.fromJSON(layout);
75664
+ this.api.fromJSON(layout2);
75355
75665
  return this.api.panels.length > 0;
75356
75666
  } catch {
75357
75667
  this.api.clear();
@@ -78269,12 +78579,12 @@ function getVisibleRowContext(state2, index2) {
78269
78579
  subtreeEndIndex: getVisibleRowSubtreeEndIndex(state2, selected.cursor, selected.index, totalVisibleCount)
78270
78580
  };
78271
78581
  }
78272
- function getVisibleSlice(state2, start2, end) {
78582
+ function getVisibleSlice(state2, start2, end2) {
78273
78583
  const instrumentation = state2.instrumentation;
78274
78584
  const totalVisibleCount = getVisibleCount(state2);
78275
- if (totalVisibleCount <= 0 || end < start2) return [];
78585
+ if (totalVisibleCount <= 0 || end2 < start2) return [];
78276
78586
  const normalizedStart = Math.max(0, Math.min(start2, totalVisibleCount - 1));
78277
- const normalizedEnd = Math.max(normalizedStart, Math.min(end, totalVisibleCount - 1));
78587
+ const normalizedEnd = Math.max(normalizedStart, Math.min(end2, totalVisibleCount - 1));
78278
78588
  if (instrumentation == null) {
78279
78589
  if (normalizedStart === 0) return collectVisibleRowsDFS(state2, normalizedEnd + 1);
78280
78590
  const rows3 = [];
@@ -78892,8 +79202,8 @@ var PathStore = class PathStore2 {
78892
79202
  getVisibleCount() {
78893
79203
  return withBenchmarkPhase(this.#state.instrumentation, "store.getVisibleCount", () => getVisibleCount(this.#state));
78894
79204
  }
78895
- getVisibleSlice(start2, end) {
78896
- return withBenchmarkPhase(this.#state.instrumentation, "store.getVisibleSlice", () => getVisibleSlice(this.#state, start2, end));
79205
+ getVisibleSlice(start2, end2) {
79206
+ return withBenchmarkPhase(this.#state.instrumentation, "store.getVisibleSlice", () => getVisibleSlice(this.#state, start2, end2));
78897
79207
  }
78898
79208
  getVisibleRowContext(index2) {
78899
79209
  return withBenchmarkPhase(this.#state.instrumentation, "store.getVisibleRowContext", () => getVisibleRowContext(this.#state, index2));
@@ -79956,10 +80266,10 @@ var FileTreeController = class FileTreeController2 {
79956
80266
  getVisibleCount() {
79957
80267
  return this.#visibleCount;
79958
80268
  }
79959
- getVisibleRows(start2, end) {
79960
- if (end < start2 || this.#visibleCount === 0) return [];
80269
+ getVisibleRows(start2, end2) {
80270
+ if (end2 < start2 || this.#visibleCount === 0) return [];
79961
80271
  const boundedStart = Math.max(0, start2);
79962
- const boundedEnd = Math.min(this.#visibleCount - 1, end);
80272
+ const boundedEnd = Math.min(this.#visibleCount - 1, end2);
79963
80273
  if (boundedEnd < boundedStart) return [];
79964
80274
  const boundedLength = boundedEnd - boundedStart + 1;
79965
80275
  if (this.#searchVisibleIndices == null && !this.#hasFullProjection && boundedEnd >= this.#projectionPaths.length && boundedLength <= CONTEXT_VISIBLE_ROW_RANGE_LIMIT) {
@@ -84263,8 +84573,8 @@ var FileTree = class {
84263
84573
  getVisibleCount() {
84264
84574
  return this.#controller.getVisibleCount();
84265
84575
  }
84266
- getVisibleRows(start2, end) {
84267
- return this.#controller.getVisibleRows(start2, end);
84576
+ getVisibleRows(start2, end2) {
84577
+ return this.#controller.getVisibleRows(start2, end2);
84268
84578
  }
84269
84579
  getSelectedPaths() {
84270
84580
  return this.#controller.getSelectedPaths();
@@ -85009,6 +85319,7 @@ var elements = {
85009
85319
  "slicc-sprinkle": SliccSprinkle,
85010
85320
  "slicc-lucide": SliccLucide,
85011
85321
  "slicc-tray": SliccTray,
85322
+ "slicc-live": SliccLive,
85012
85323
  "slicc-follow": SliccFollow,
85013
85324
  "slicc-updates": SliccUpdates,
85014
85325
  "slicc-network": SliccNetwork,
@@ -85054,6 +85365,7 @@ export {
85054
85365
  SliccFollow,
85055
85366
  SliccFreezerImport,
85056
85367
  SliccGuestInvite,
85368
+ SliccLive,
85057
85369
  SliccNetwork,
85058
85370
  SliccNotices,
85059
85371
  SliccPrompt,