@ai-ecoverse/slicc-spectrum 1.73.2 → 1.75.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
@@ -8837,6 +8837,10 @@ var shared = i`
8837
8837
  padding: 0 var(--swc-spacing-75);
8838
8838
  }
8839
8839
  `;
8840
+ function speech() {
8841
+ const scope = globalThis;
8842
+ return scope.SpeechRecognition ?? scope.webkitSpeechRecognition;
8843
+ }
8840
8844
 
8841
8845
  // node_modules/@adobe/spectrum-wc/dist/components/button/button.js
8842
8846
  var t42 = i`.swc-Button{--_swc-button-border-width: 2px;--_swc-button-min-block-size: var(--swc-button-min-block-size, var(--swc-component-height-100));gap:var(--swc-button-gap, 6px);max-inline-size:var(--swc-button-max-inline-size, inherit);min-block-size:var(--_swc-button-min-block-size);padding-block:calc(var(--swc-button-padding-vertical, 7px) - var(--_swc-button-border-width));padding-inline:calc(var(--swc-button-edge-to-text, var(--swc-base-padding-horizontal-medium)) - var(--_swc-button-border-width));font-family:var(--swc-sans-font-family-stack);font-size:var(--swc-button-font-size, var(--swc-font-size-100));font-weight:700;line-height:round(down,1.3em,1px);color:var(--swc-button-content-color-default, var(--swc-gray-25));background-color:var(--swc-button-background-color-default, var(--swc-gray-800));border-color:var(--swc-button-border-color-default, transparent);border-width:var(--_swc-button-border-width);border-radius:var(--swc-button-border-radius, calc(var(--_swc-button-min-block-size) / 2));transition-timing-function:cubic-bezier(.45,0,.4,1);transition-duration:.13s;transition-property:outline,border-color,color,background-color,transform}.swc-Button:hover{color:var(--swc-button-content-color-hover, var(--swc-gray-25));background-color:var(--swc-button-background-color-hover, var(--swc-gray-900));border-color:var(--swc-button-border-color-hover, transparent)}.swc-Button:focus-visible{color:var(--swc-button-content-color-focus, var(--swc-gray-25));background-color:var(--swc-button-background-color-focus, var(--swc-gray-900));border-color:var(--swc-button-border-color-focus, transparent)}.swc-Button:active{color:var(--swc-button-content-color-down, var(--swc-gray-25));background-color:var(--swc-button-background-color-down, var(--swc-gray-900));border-color:var(--swc-button-border-color-down, transparent);transform:var(--swc-button-down-state-transform, perspective(var(--_swc-button-min-block-size)) translate3d(0, 0, -2px));will-change:transform}.swc-Button-label{text-align:center}.swc-Button--hasIcon .swc-Button-label{text-align:start}slot[name=icon]::slotted(*),.swc-PendingSpinner{--_swc-button-icon-size: var(--swc-button-icon-size, var(--swc-workflow-icon-medium));--_swc-button-icon-block-size: var(--swc-button-icon-block-size, var(--_swc-button-icon-size));--_swc-pending-spinner-size: var(--_swc-button-icon-size);box-sizing:border-box;flex-shrink:0;align-self:flex-start;inline-size:var(--swc-button-icon-inline-size, var(--_swc-button-icon-size));block-size:var(--_swc-button-icon-block-size);margin-block:calc((var(--_swc-button-icon-block-size) - 1lh) / 2 * -1);margin-inline-start:calc(var(--swc-button-edge-to-visual, var(--swc-base-padding-horizontal-medium)) - var(--swc-button-edge-to-text, var(--swc-base-padding-horizontal-medium)))}slot[name=icon]::slotted(*){color:inherit;fill:currentcolor}:host([size=\"s\"]){--swc-button-min-block-size: var(--swc-component-height-75);--swc-button-font-size: var(--swc-font-size-75);--swc-button-gap: 4px;--swc-button-edge-to-text: var(--swc-base-padding-horizontal-small);--swc-button-edge-to-visual: var(--swc-base-padding-horizontal-small);--swc-button-edge-to-visual-only: 4px;--swc-button-padding-vertical: 4px;--swc-button-icon-size: var(--swc-workflow-icon-small)}:host([size=\"l\"]){--swc-button-min-block-size: var(--swc-component-height-200);--swc-button-font-size: var(--swc-font-size-200);--swc-button-gap: 6px;--swc-button-edge-to-text: var(--swc-base-padding-horizontal-large);--swc-button-edge-to-visual: var(--swc-base-padding-horizontal-large);--swc-button-edge-to-visual-only: 7px;--swc-button-padding-vertical: 10px;--swc-button-icon-size: var(--swc-workflow-icon-large)}:host([size=\"xl\"]){--swc-button-min-block-size: var(--swc-component-height-300);--swc-button-font-size: var(--swc-font-size-300);--swc-button-gap: 6px;--swc-button-edge-to-text: var(--swc-base-padding-horizontal-extra-large);--swc-button-edge-to-visual: var(--swc-base-padding-horizontal-extra-large);--swc-button-edge-to-visual-only: 9px;--swc-button-padding-vertical: 13px;--swc-button-icon-size: var(--swc-workflow-icon-extra-large)}:host([variant=\"accent\"]){--swc-button-content-color-default: rgb(255, 255, 255);--swc-button-content-color-hover: rgb(255, 255, 255);--swc-button-content-color-down: rgb(255, 255, 255);--swc-button-content-color-focus: rgb(255, 255, 255);--swc-button-background-color-default: var(--swc-accent-background-color-default);--swc-button-background-color-hover: var(--swc-accent-background-color-hover);--swc-button-background-color-down: var(--swc-accent-background-color-down);--swc-button-background-color-focus: var(--swc-accent-background-color-key-focus)}:host([variant=\"negative\"]){--swc-button-content-color-default: rgb(255, 255, 255);--swc-button-content-color-hover: rgb(255, 255, 255);--swc-button-content-color-down: rgb(255, 255, 255);--swc-button-content-color-focus: rgb(255, 255, 255);--swc-button-background-color-default: var(--swc-negative-background-color-default);--swc-button-background-color-hover: var(--swc-negative-background-color-hover);--swc-button-background-color-down: var(--swc-negative-background-color-down);--swc-button-background-color-focus: var(--swc-negative-background-color-key-focus)}:host([variant=\"secondary\"]){--swc-button-content-color-default: var(--swc-gray-800);--swc-button-content-color-hover: var(--swc-gray-900);--swc-button-content-color-down: var(--swc-gray-900);--swc-button-content-color-focus: var(--swc-gray-900);--swc-button-background-color-default: var(--swc-gray-100);--swc-button-background-color-hover: var(--swc-gray-200);--swc-button-background-color-down: var(--swc-gray-200);--swc-button-background-color-focus: var(--swc-gray-200)}:host([variant=\"primary\"][fill-style=\"outline\"]){--swc-button-background-color-default: transparent;--swc-button-background-color-hover: var(--swc-gray-100);--swc-button-background-color-down: var(--swc-gray-100);--swc-button-background-color-focus: var(--swc-gray-100);--swc-button-border-color-default: var(--swc-gray-800);--swc-button-border-color-hover: var(--swc-gray-900);--swc-button-border-color-down: var(--swc-gray-900);--swc-button-border-color-focus: var(--swc-gray-900);--swc-button-content-color-default: var(--swc-gray-800);--swc-button-content-color-hover: var(--swc-gray-900);--swc-button-content-color-down: var(--swc-gray-900);--swc-button-content-color-focus: var(--swc-gray-900);--swc-button-background-color-disabled: transparent;--swc-button-border-color-disabled: var(--swc-gray-300)}:host([variant=\"secondary\"][fill-style=\"outline\"]){--swc-button-background-color-default: transparent;--swc-button-background-color-hover: var(--swc-gray-100);--swc-button-background-color-down: var(--swc-gray-100);--swc-button-background-color-focus: var(--swc-gray-100);--swc-button-border-color-default: var(--swc-gray-300);--swc-button-border-color-hover: var(--swc-gray-400);--swc-button-border-color-down: var(--swc-gray-400);--swc-button-border-color-focus: var(--swc-gray-400);--swc-button-background-color-disabled: transparent;--swc-button-border-color-disabled: var(--swc-gray-300)}:host([static-color=\"white\"]){--swc-button-focus-indicator-color: var(--swc-white);--swc-button-background-color-default: rgba(255, 255, 255, .85);--swc-button-background-color-hover: rgba(255, 255, 255, .94);--swc-button-background-color-down: rgba(255, 255, 255, .94);--swc-button-background-color-focus: rgba(255, 255, 255, .94);--swc-button-content-color-default: rgb(0, 0, 0);--swc-button-content-color-hover: rgb(0, 0, 0);--swc-button-content-color-down: rgb(0, 0, 0);--swc-button-content-color-focus: rgb(0, 0, 0);--swc-button-background-color-disabled: var(--swc-transparent-white-100);--swc-button-border-color-disabled: transparent;--swc-button-content-color-disabled: var(--swc-transparent-white-400)}:host([static-color=\"white\"][variant=\"secondary\"]){--swc-button-background-color-default: rgba(255, 255, 255, .11);--swc-button-background-color-hover: rgba(255, 255, 255, .14);--swc-button-background-color-down: rgba(255, 255, 255, .14);--swc-button-background-color-focus: rgba(255, 255, 255, .14);--swc-button-content-color-default: rgba(255, 255, 255, .85);--swc-button-content-color-hover: rgba(255, 255, 255, .94);--swc-button-content-color-down: rgba(255, 255, 255, .94);--swc-button-content-color-focus: rgba(255, 255, 255, .94)}:host([static-color=\"white\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(255, 255, 255, 0);--swc-button-background-color-hover: rgba(255, 255, 255, .11);--swc-button-background-color-down: rgba(255, 255, 255, .11);--swc-button-background-color-focus: rgba(255, 255, 255, .11);--swc-button-border-color-default: rgba(255, 255, 255, .85);--swc-button-border-color-hover: rgba(255, 255, 255, .94);--swc-button-border-color-down: rgba(255, 255, 255, .94);--swc-button-border-color-focus: rgba(255, 255, 255, .94);--swc-button-content-color-default: rgba(255, 255, 255, .85);--swc-button-content-color-hover: rgba(255, 255, 255, .94);--swc-button-content-color-down: rgba(255, 255, 255, .94);--swc-button-content-color-focus: rgba(255, 255, 255, .94);--swc-button-background-color-disabled: rgba(255, 255, 255, 0);--swc-button-border-color-disabled: var(--swc-transparent-white-300);--swc-button-content-color-disabled: var(--swc-transparent-white-400)}:host([static-color=\"white\"][variant=\"secondary\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(255, 255, 255, 0);--swc-button-background-color-hover: rgba(255, 255, 255, .11);--swc-button-background-color-down: rgba(255, 255, 255, .11);--swc-button-background-color-focus: rgba(255, 255, 255, .11);--swc-button-border-color-default: rgba(255, 255, 255, .17);--swc-button-border-color-hover: rgba(255, 255, 255, .21);--swc-button-border-color-down: rgba(255, 255, 255, .21);--swc-button-border-color-focus: rgba(255, 255, 255, .21)}:host([static-color=\"black\"]){--swc-button-focus-indicator-color: var(--swc-black);--swc-button-background-color-default: rgba(0, 0, 0, .84);--swc-button-background-color-hover: rgba(0, 0, 0, .93);--swc-button-background-color-down: rgba(0, 0, 0, .93);--swc-button-background-color-focus: rgba(0, 0, 0, .93);--swc-button-content-color-default: rgb(255, 255, 255);--swc-button-content-color-hover: rgb(255, 255, 255);--swc-button-content-color-down: rgb(255, 255, 255);--swc-button-content-color-focus: rgb(255, 255, 255);--swc-button-background-color-disabled: var(--swc-transparent-black-100);--swc-button-border-color-disabled: transparent;--swc-button-content-color-disabled: var(--swc-transparent-black-400)}:host([static-color=\"black\"][variant=\"secondary\"]){--swc-button-background-color-default: rgba(0, 0, 0, .09);--swc-button-background-color-hover: rgba(0, 0, 0, .12);--swc-button-background-color-down: rgba(0, 0, 0, .12);--swc-button-background-color-focus: rgba(0, 0, 0, .12);--swc-button-content-color-default: rgba(0, 0, 0, .84);--swc-button-content-color-hover: rgba(0, 0, 0, .93);--swc-button-content-color-down: rgba(0, 0, 0, .93);--swc-button-content-color-focus: rgba(0, 0, 0, .93)}:host([static-color=\"black\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(0, 0, 0, 0);--swc-button-background-color-hover: rgba(0, 0, 0, .09);--swc-button-background-color-down: rgba(0, 0, 0, .09);--swc-button-background-color-focus: rgba(0, 0, 0, .09);--swc-button-border-color-default: rgba(0, 0, 0, .84);--swc-button-border-color-hover: rgba(0, 0, 0, .93);--swc-button-border-color-down: rgba(0, 0, 0, .93);--swc-button-border-color-focus: rgba(0, 0, 0, .93);--swc-button-content-color-default: rgba(0, 0, 0, .84);--swc-button-content-color-hover: rgba(0, 0, 0, .93);--swc-button-content-color-down: rgba(0, 0, 0, .93);--swc-button-content-color-focus: rgba(0, 0, 0, .93);--swc-button-background-color-disabled: rgba(0, 0, 0, 0);--swc-button-border-color-disabled: var(--swc-transparent-black-300);--swc-button-content-color-disabled: var(--swc-transparent-black-400)}:host([static-color=\"black\"][variant=\"secondary\"][fill-style=\"outline\"]){--swc-button-background-color-default: rgba(0, 0, 0, 0);--swc-button-background-color-hover: rgba(0, 0, 0, .09);--swc-button-background-color-down: rgba(0, 0, 0, .09);--swc-button-background-color-focus: rgba(0, 0, 0, .09);--swc-button-border-color-default: rgba(0, 0, 0, .15);--swc-button-border-color-hover: rgba(0, 0, 0, .22);--swc-button-border-color-down: rgba(0, 0, 0, .22);--swc-button-border-color-focus: rgba(0, 0, 0, .22)}.swc-Button--iconOnly{--swc-button-border-radius: 50%;--swc-button-gap: 0;inline-size:var(--_swc-button-min-block-size);padding-inline:calc(var(--swc-button-edge-to-visual-only, 5px) - var(--_swc-button-border-width))}.swc-Button--iconOnly slot[name=icon]::slotted(*){--swc-button-edge-to-visual: 0;align-self:center}:host([pending]) .swc-Button{cursor:default}.swc-Button--pendingActive{--swc-button-down-state-transform: none;justify-content:center;inline-size:var(--swc-pending-inline-size);transition:none;--swc-button-background-color-default: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-background-color-hover: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-background-color-down: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-background-color-focus: var(--swc-button-background-color-disabled, var(--swc-gray-100));--swc-button-border-color-default: var(--swc-button-border-color-disabled, transparent);--swc-button-border-color-hover: var(--swc-button-border-color-disabled, transparent);--swc-button-border-color-down: var(--swc-button-border-color-disabled, transparent);--swc-button-border-color-focus: var(--swc-button-border-color-disabled, transparent);--swc-button-content-color-default: var(--swc-button-content-color-disabled, var(--swc-gray-400));--swc-button-content-color-hover: var(--swc-button-content-color-disabled, var(--swc-gray-400));--swc-button-content-color-down: var(--swc-button-content-color-disabled, var(--swc-gray-400));--swc-button-content-color-focus: var(--swc-button-content-color-disabled, var(--swc-gray-400))}.swc-Button--pendingActive .swc-Button-label,.swc-Button--pendingActive slot[name=icon]::slotted(*){display:none}:host([truncate]) .swc-Button-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host([justified]){flex-grow:1;justify-self:stretch;inline-size:100%}:host([justified]) .swc-Button{inline-size:100%}@media(prefers-reduced-motion:reduce){.swc-Button{transition-duration:0ms}}@media(forced-colors:active){.swc-Button--pendingActive{--swc-button-background-color-default: ButtonFace;--swc-button-background-color-hover: ButtonFace;--swc-button-background-color-down: ButtonFace;--swc-button-background-color-focus: ButtonFace;--swc-button-border-color-default: GrayText;--swc-button-border-color-hover: GrayText;--swc-button-border-color-down: GrayText;--swc-button-border-color-focus: GrayText;--swc-button-content-color-default: GrayText;--swc-button-content-color-hover: GrayText;--swc-button-content-color-down: GrayText;--swc-button-content-color-focus: GrayText}}`;
@@ -9777,10 +9781,18 @@ function following(model) {
9777
9781
  return state2 && !followPage(state2) ? state2 : null;
9778
9782
  }
9779
9783
  function watchOnly(model) {
9784
+ const text2 = model?.agent?.readOnly?.();
9785
+ if (text2) return text2;
9780
9786
  const state2 = following(model);
9781
9787
  if (!state2 || state2.access.control) return "";
9782
9788
  return `Watch only. To send prompts from this device, allow Control for it on ${state2.owner}.`;
9783
9789
  }
9790
+ function onWatch(model, listener) {
9791
+ return [
9792
+ ...model.agent.readOnly ? [model.agent.on("readOnly", listener)] : [],
9793
+ ...model.follow ? [model.follow.on("follow", listener)] : []
9794
+ ];
9795
+ }
9784
9796
  function terminalsAllowed(model) {
9785
9797
  const state2 = model?.follow?.state();
9786
9798
  return !state2 || !!state2.access.terminal;
@@ -10646,7 +10658,7 @@ function watchTitles(model, update) {
10646
10658
  const seen = /* @__PURE__ */ new Map();
10647
10659
  const check3 = (id) => {
10648
10660
  const agent = model.agent.list().find((candidate) => candidate.id === id);
10649
- if (agent?.kind !== "cone") return;
10661
+ if (!agent) return;
10650
10662
  const title = agentTitle(model, agent);
10651
10663
  if (seen.get(id) === title) return;
10652
10664
  seen.set(id, title);
@@ -10745,7 +10757,7 @@ var SliccFreezer = class extends ModelElement {
10745
10757
  model.agent.on("frozen", update),
10746
10758
  model.agent.on("active", update),
10747
10759
  model.agent.on("agents", update),
10748
- ...model.follow ? [model.follow.on("follow", update)] : []
10760
+ ...onWatch(model, update)
10749
10761
  ];
10750
10762
  }
10751
10763
  focus() {
@@ -11406,11 +11418,25 @@ async function createCone(model, trigger2) {
11406
11418
  if (created) port.select(created.id);
11407
11419
  return created;
11408
11420
  }
11421
+ var statusOrder = ["working", "thinking", "waiting", "error", "idle"];
11422
+ function scoopSummary(scoops) {
11423
+ if (scoops.length === 0) return "";
11424
+ const counts = statusOrder.map((status2) => [status2, scoops.filter((scoop) => scoop.status === status2).length]).filter(([, count]) => count > 0).map(([status2, count]) => `${count} ${statusLabel[status2].toLowerCase()}`);
11425
+ return `${scoops.length} scoop${scoops.length === 1 ? "" : "s"}: ${counts.join(", ")}`;
11426
+ }
11427
+ function unreadCount(unread) {
11428
+ return unread > 9 ? "9+" : String(unread);
11429
+ }
11409
11430
  function fillShown(fill2) {
11410
11431
  return fill2 >= 0.5;
11411
11432
  }
11412
11433
  var SliccAgents = class extends ModelElement {
11413
11434
  static properties = { ...ModelElement.properties, errors: { state: true } };
11435
+ #expanded = null;
11436
+ #pointer = false;
11437
+ #modality = (event2) => {
11438
+ this.#pointer = event2.type === "pointerdown";
11439
+ };
11414
11440
  constructor() {
11415
11441
  super();
11416
11442
  this.errors = {};
@@ -11419,16 +11445,22 @@ var SliccAgents = class extends ModelElement {
11419
11445
  shared,
11420
11446
  i`
11421
11447
  :host {
11422
- display: block;
11448
+ display: flex;
11449
+ flex-direction: column;
11423
11450
  height: 100%;
11424
- overflow-y: auto;
11451
+ overflow: hidden;
11425
11452
  background: var(--swc-background-layer-1-color);
11426
11453
  color: var(--swc-neutral-content-color-default);
11427
11454
  font-size: var(--swc-font-size-100);
11428
11455
  }
11456
+ .list {
11457
+ flex: 1;
11458
+ min-block-size: 0;
11459
+ overflow-y: auto;
11460
+ }
11429
11461
  .actions {
11430
11462
  display: flex;
11431
- padding: var(--swc-spacing-75) var(--swc-spacing-100) 0;
11463
+ padding: var(--swc-spacing-75) var(--swc-spacing-100);
11432
11464
  }
11433
11465
  ul {
11434
11466
  list-style: none;
@@ -11436,31 +11468,67 @@ var SliccAgents = class extends ModelElement {
11436
11468
  padding: var(--swc-spacing-75) 0;
11437
11469
  }
11438
11470
  li {
11471
+ --row-background: var(--swc-background-layer-1-color);
11472
+ --row-head: 1lh;
11473
+ --row-description: calc(2 * 1.4 * var(--swc-font-size-75));
11474
+ position: relative;
11439
11475
  display: grid;
11440
- grid-template-columns: minmax(0, 1fr) auto auto auto;
11441
- grid-template-areas: 'name unread fill drop' 'title unread fill drop' 'status unread fill drop' 'error error error error';
11476
+ grid-template-columns: minmax(0, 1fr) auto;
11477
+ grid-template-areas: 'head fill' 'description description' 'ribbon ribbon' 'error error';
11478
+ grid-template-rows: var(--row-head) var(--row-description) var(--swc-spacing-100);
11442
11479
  align-items: center;
11443
11480
  column-gap: var(--swc-spacing-100);
11444
11481
  padding: var(--swc-spacing-75) var(--swc-spacing-200);
11482
+ background: var(--row-background);
11445
11483
  cursor: pointer;
11446
11484
  }
11447
11485
  li.scoop {
11448
- grid-template-areas: 'name unread fill drop' 'status unread fill drop' 'error error error error';
11449
11486
  padding-inline-start: calc(var(--swc-spacing-200) + var(--swc-spacing-300));
11450
11487
  }
11451
11488
  li:hover {
11452
- background: var(--swc-gray-100);
11489
+ --row-background: var(--swc-gray-100);
11453
11490
  }
11454
11491
  li[aria-selected='true'] {
11455
- background: var(--swc-gray-200);
11456
- box-shadow: inset var(--swc-spacing-50) 0 0 var(--swc-accent-visual-color);
11492
+ --row-background: var(--swc-gray-200);
11457
11493
  }
11458
11494
  li:focus-visible {
11459
11495
  outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
11460
11496
  outline-offset: calc(-1 * var(--swc-focus-indicator-thickness));
11461
11497
  }
11498
+ .head {
11499
+ grid-area: head;
11500
+ display: flex;
11501
+ align-items: center;
11502
+ gap: var(--swc-spacing-75);
11503
+ min-inline-size: 0;
11504
+ }
11505
+ .head > * {
11506
+ flex: none;
11507
+ }
11508
+ .marker {
11509
+ flex: none;
11510
+ display: inline-flex;
11511
+ align-items: center;
11512
+ justify-content: center;
11513
+ inline-size: var(--swc-spacing-200);
11514
+ block-size: var(--swc-spacing-200);
11515
+ border-radius: var(--swc-corner-radius-full);
11516
+ font-size: var(--swc-font-size-25);
11517
+ font-variant-numeric: tabular-nums;
11518
+ line-height: 1;
11519
+ }
11520
+ .marker.unread {
11521
+ box-sizing: border-box;
11522
+ inline-size: auto;
11523
+ min-inline-size: var(--swc-spacing-200);
11524
+ padding-inline: var(--swc-spacing-50);
11525
+ background: var(--swc-accent-background-color-default);
11526
+ color: var(--swc-white);
11527
+ font-weight: var(--swc-bold-font-weight);
11528
+ }
11462
11529
  .name {
11463
- grid-area: name;
11530
+ flex: 0 1 auto;
11531
+ min-inline-size: 0;
11464
11532
  overflow: hidden;
11465
11533
  text-overflow: ellipsis;
11466
11534
  white-space: nowrap;
@@ -11469,29 +11537,58 @@ var SliccAgents = class extends ModelElement {
11469
11537
  font-weight: var(--swc-bold-font-weight);
11470
11538
  }
11471
11539
  .title {
11472
- grid-area: title;
11540
+ grid-area: description;
11541
+ display: -webkit-box;
11542
+ -webkit-box-orient: vertical;
11543
+ -webkit-line-clamp: 2;
11473
11544
  overflow: hidden;
11474
- text-overflow: ellipsis;
11475
- white-space: nowrap;
11545
+ overflow-wrap: anywhere;
11546
+ line-height: 1.4;
11476
11547
  font-size: var(--swc-font-size-75);
11477
11548
  color: var(--swc-neutral-subdued-content-color-default);
11478
11549
  }
11479
- .unread {
11480
- --swc-badge-height: var(--swc-spacing-300);
11481
- --swc-badge-padding-block: var(--swc-spacing-50);
11482
- --swc-badge-padding-inline: var(--swc-spacing-75);
11483
- --swc-badge-corner-radius: var(--swc-spacing-100);
11484
- --swc-badge-line-height: 1;
11485
- grid-area: unread;
11486
- align-self: center;
11550
+ .state {
11551
+ color: var(--swc-neutral-content-color-default);
11552
+ }
11553
+ .ribbon {
11554
+ grid-area: ribbon;
11555
+ display: flex;
11556
+ align-items: center;
11557
+ gap: var(--swc-spacing-50);
11558
+ overflow: hidden;
11559
+ }
11560
+ .status,
11561
+ .segment {
11562
+ background: var(--swc-neutral-visual-color);
11563
+ }
11564
+ .status[data-status='thinking'],
11565
+ .status[data-status='working'],
11566
+ .segment[data-status='thinking'],
11567
+ .segment[data-status='working'] {
11568
+ background: var(--swc-informative-visual-color);
11569
+ }
11570
+ .status[data-status='waiting'],
11571
+ .segment[data-status='waiting'] {
11572
+ background: var(--swc-notice-visual-color);
11573
+ }
11574
+ .status[data-status='error'],
11575
+ .segment[data-status='error'] {
11576
+ background: var(--swc-negative-visual-color);
11577
+ }
11578
+ .segment {
11579
+ flex: none;
11580
+ inline-size: var(--swc-spacing-200);
11581
+ block-size: var(--swc-spacing-50);
11582
+ border-radius: var(--swc-corner-radius-full);
11487
11583
  }
11488
11584
  .fill {
11489
11585
  grid-area: fill;
11586
+ position: relative;
11587
+ z-index: 1;
11588
+ align-self: start;
11490
11589
  font-size: var(--swc-font-size-75);
11491
11590
  font-variant-numeric: tabular-nums;
11492
11591
  color: var(--swc-neutral-subdued-content-color-default);
11493
- min-width: 4ch;
11494
- text-align: end;
11495
11592
  }
11496
11593
  .fill[data-variant='notice'] {
11497
11594
  color: var(--swc-notice-color-1000);
@@ -11501,18 +11598,20 @@ var SliccAgents = class extends ModelElement {
11501
11598
  color: var(--swc-negative-color-1000);
11502
11599
  font-weight: var(--swc-bold-font-weight);
11503
11600
  }
11504
- swc-status-light {
11505
- grid-area: status;
11506
- justify-self: start;
11507
- }
11508
- .drop {
11509
- grid-area: drop;
11510
- margin-block: calc(-1 * var(--swc-spacing-100));
11511
- visibility: hidden;
11601
+ .drop-cell {
11602
+ position: absolute;
11603
+ inset-block: 0;
11604
+ inset-inline-end: 0;
11605
+ display: flex;
11606
+ align-items: center;
11607
+ padding-inline: var(--swc-spacing-100);
11608
+ background: var(--row-background);
11609
+ opacity: 0;
11512
11610
  }
11513
- li:hover .drop,
11514
- li:focus-within .drop {
11515
- visibility: visible;
11611
+ li:hover .drop-cell,
11612
+ li:focus-visible .drop-cell,
11613
+ .drop-cell[data-shown] {
11614
+ opacity: 1;
11516
11615
  }
11517
11616
  .error {
11518
11617
  grid-area: error;
@@ -11529,23 +11628,46 @@ var SliccAgents = class extends ModelElement {
11529
11628
  white-space: nowrap;
11530
11629
  }
11531
11630
  @media (hover: none), (pointer: coarse) {
11532
- .drop {
11533
- visibility: visible;
11631
+ .drop-cell {
11632
+ opacity: 1;
11534
11633
  }
11535
11634
  }
11536
11635
  `
11537
11636
  ];
11538
11637
  subscribe(model) {
11638
+ const focused2 = this.#focused(model);
11639
+ this.#expanded = focused2?.kind === "scoop" ? focused2.parentId : null;
11539
11640
  return [
11540
11641
  model.agent.on("agents", () => this.requestUpdate()),
11541
- model.agent.on("active", () => this.requestUpdate()),
11642
+ model.agent.on("active", () => {
11643
+ const next = this.#focused(model);
11644
+ if (next) this.#expanded = next.kind === "cone" ? next.id : next.parentId;
11645
+ this.requestUpdate();
11646
+ }),
11542
11647
  watchTitles(model, () => this.requestUpdate()),
11543
- ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : []
11648
+ ...onWatch(model, () => this.requestUpdate()),
11649
+ this.#watchPointer()
11544
11650
  ];
11545
11651
  }
11652
+ #watchPointer() {
11653
+ const types = ["pointerdown", "keydown"];
11654
+ for (const type of types) globalThis.addEventListener(type, this.#modality, true);
11655
+ return () => {
11656
+ for (const type of types) globalThis.removeEventListener(type, this.#modality, true);
11657
+ };
11658
+ }
11659
+ #focused(model) {
11660
+ return model.agent.list().find((agent) => agent.id === model.agent.active());
11661
+ }
11546
11662
  #select(id) {
11547
11663
  this.model?.agent.select(id);
11548
11664
  }
11665
+ #pick(agent) {
11666
+ const open = agent.kind === "cone" && this.#expanded !== agent.id;
11667
+ this.#select(agent.id);
11668
+ if (agent.kind === "cone") this.#expanded = open ? agent.id : null;
11669
+ this.requestUpdate();
11670
+ }
11549
11671
  focus() {
11550
11672
  this.focusOn('li[tabindex="0"]');
11551
11673
  }
@@ -11564,21 +11686,44 @@ var SliccAgents = class extends ModelElement {
11564
11686
  if (event2.key in moves) {
11565
11687
  event2.preventDefault();
11566
11688
  items[Math.max(0, Math.min(items.length - 1, moves[event2.key]))]?.focus();
11567
- } else if (event2.key === "Enter" || event2.key === " ") {
11689
+ return;
11690
+ }
11691
+ const agent = this.model?.agent.list().find((item2) => item2.id === items[index]?.dataset.id);
11692
+ if (!agent) return;
11693
+ if (event2.key === "Enter" || event2.key === " ") {
11694
+ event2.preventDefault();
11695
+ this.#pick(agent);
11696
+ } else if (event2.key === "ArrowRight" && this.#scoops(agent).length > 0) {
11697
+ event2.preventDefault();
11698
+ if (this.#expanded === agent.id) items[index + 1].focus();
11699
+ else this.#pick(agent);
11700
+ } else if (event2.key === "ArrowLeft" && agent.kind === "scoop") {
11568
11701
  event2.preventDefault();
11569
- const id = items[index]?.dataset.id;
11570
- if (id) this.#select(id);
11702
+ items.find((item2) => item2.dataset.id === agent.parentId)?.focus();
11703
+ } else if (event2.key === "ArrowLeft" && this.#expanded === agent.id) {
11704
+ event2.preventDefault();
11705
+ this.#pick(agent);
11571
11706
  } else if (event2.key === "Delete") {
11572
- const agent = this.model?.agent.list().find((item2) => item2.id === items[index]?.dataset.id);
11573
- if (agent && this.#droppable(agent)) {
11707
+ if (this.#droppable(agent)) {
11574
11708
  event2.preventDefault();
11575
11709
  void this.#drop(agent, items[index]);
11576
- } else if (agent && this.#deletable(agent)) {
11710
+ } else if (this.#deletable(agent)) {
11577
11711
  event2.preventDefault();
11578
11712
  void this.#deleteCone(agent, items[index]);
11579
11713
  }
11580
11714
  }
11581
11715
  }
11716
+ #scoops(agent) {
11717
+ if (agent.kind !== "cone") return [];
11718
+ return this.model.agent.list().filter((other) => other.parentId === agent.id);
11719
+ }
11720
+ #focusin(event2) {
11721
+ const cell = event2.target.closest(".drop-cell");
11722
+ cell?.toggleAttribute("data-shown", !this.#pointer);
11723
+ }
11724
+ #focusout(event2) {
11725
+ event2.target.closest(".drop-cell")?.removeAttribute("data-shown");
11726
+ }
11582
11727
  #droppable(agent) {
11583
11728
  return agent.kind === "scoop" && Boolean(this.model?.agent.drop) && !watchOnly(this.model);
11584
11729
  }
@@ -11616,69 +11761,89 @@ var SliccAgents = class extends ModelElement {
11616
11761
  await this.updateComplete;
11617
11762
  this.focus();
11618
11763
  }
11619
- #dropButton(agent) {
11764
+ #dropButton(agent, selected) {
11620
11765
  if (!this.#droppable(agent)) return A;
11621
11766
  const id = `drop-${agent.id}`;
11622
11767
  const label = `Drop scoop ${agent.name}`;
11623
- return b`<swc-action-button
11624
- id=${id}
11625
- class="drop"
11626
- size="l"
11627
- quiet
11628
- tabindex="-1"
11629
- data-action="drop"
11630
- accessible-label=${label}
11631
- @click=${(event2) => {
11768
+ return b`<span class="drop-cell"
11769
+ ><swc-action-button
11770
+ id=${id}
11771
+ class="drop"
11772
+ size="l"
11773
+ quiet
11774
+ tabindex=${selected ? "0" : "-1"}
11775
+ data-action="drop"
11776
+ accessible-label=${label}
11777
+ @click=${(event2) => {
11632
11778
  event2.stopPropagation();
11633
11779
  void this.#drop(agent, event2.currentTarget);
11634
11780
  }}
11635
- ><swc-icon-close slot="icon"></swc-icon-close></swc-action-button
11636
- ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip>`;
11781
+ ><swc-icon-close slot="icon"></swc-icon-close></swc-action-button
11782
+ ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip></span
11783
+ >`;
11637
11784
  }
11638
- #deleteButton(agent) {
11785
+ #deleteButton(agent, selected) {
11639
11786
  if (!this.#deletable(agent)) return A;
11640
11787
  const id = `delete-${agent.id}`;
11641
11788
  const label = `Delete cone ${coneLabel(this.model, agent)}`;
11642
- return b`<swc-action-button
11643
- id=${id}
11644
- class="drop"
11645
- size="l"
11646
- quiet
11647
- tabindex="-1"
11648
- data-action="delete-cone"
11649
- accessible-label=${label}
11650
- @click=${(event2) => {
11789
+ return b`<span class="drop-cell"
11790
+ ><swc-action-button
11791
+ id=${id}
11792
+ class="drop"
11793
+ size="l"
11794
+ quiet
11795
+ tabindex=${selected ? "0" : "-1"}
11796
+ data-action="delete-cone"
11797
+ accessible-label=${label}
11798
+ @click=${(event2) => {
11651
11799
  event2.stopPropagation();
11652
11800
  void this.#deleteCone(agent, event2.currentTarget);
11653
11801
  }}
11654
- ><swc-icon-delete slot="icon"></swc-icon-delete></swc-action-button
11655
- ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip>`;
11802
+ ><swc-icon-delete slot="icon"></swc-icon-delete></swc-action-button
11803
+ ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip></span
11804
+ >`;
11805
+ }
11806
+ #ribbon(scoops) {
11807
+ if (scoops.length === 0) return A;
11808
+ return b`<span class="ribbon" aria-hidden="true">${scoops.map(
11809
+ (scoop) => b`<span class="segment" data-status=${scoop.status}></span>`
11810
+ )}</span>`;
11656
11811
  }
11657
11812
  #row(agent, active) {
11658
11813
  const selected = agent.id === active;
11659
11814
  const error = this.errors[agent.id];
11660
11815
  const model = this.model;
11661
- const title = agent.kind === "cone" ? agentTitle(model, agent) : null;
11816
+ const title = agentTitle(model, agent);
11817
+ const scoops = this.#scoops(agent);
11818
+ const open = this.#expanded === agent.id;
11662
11819
  const unread = selected ? 0 : agent.unread;
11663
11820
  const label = `${coneLabel(model, agent)}: ${statusLabel[agent.status]}, ${percent(agent.contextFill)} context${unread ? `, ${unread} unread` : ""}${error ? `. ${error}` : ""}`;
11821
+ const summary = scoopSummary(scoops);
11664
11822
  return b`<li
11665
- role="option"
11823
+ role="treeitem"
11824
+ id=${`row-${agent.id}`}
11666
11825
  class=${agent.kind}
11667
11826
  data-id=${agent.id}
11827
+ aria-level=${agent.kind === "cone" ? "1" : "2"}
11668
11828
  aria-selected=${selected ? "true" : "false"}
11829
+ aria-expanded=${scoops.length ? String(open) : A}
11830
+ aria-controls=${open && scoops.length ? scoops.map((scoop) => `row-${scoop.id}`).join(" ") : A}
11669
11831
  aria-label=${label}
11832
+ aria-description=${summary || A}
11670
11833
  tabindex=${selected ? "0" : "-1"}
11671
11834
  aria-keyshortcuts=${this.#droppable(agent) || this.#deletable(agent) ? "Delete" : A}
11672
- title=${label}
11673
- @click=${() => this.#select(agent.id)}
11835
+ title=${summary ? `${label}. ${summary}` : label}
11836
+ @click=${() => this.#pick(agent)}
11674
11837
  >
11675
- <span class="name">${agent.name}</span>
11676
- ${title === null ? A : b`<span class="title">${title || untitled}</span>`}
11677
- ${unread ? b`<swc-badge class="unread" size="s" variant="accent">${unread}</swc-badge>` : A}
11838
+ <div class="head">
11839
+ ${unread ? b`<span class="marker unread" aria-hidden="true">${unreadCount(unread)}</span>` : b`<span class="marker status" data-status=${agent.status} aria-hidden="true"></span>`}
11840
+ <span class="name">${agent.name}</span>
11841
+ </div>
11678
11842
  ${fillShown(agent.contextFill) ? b`<span class="fill" data-variant=${meterVariant2(agent.contextFill)}>${percent(agent.contextFill)}</span>` : A}
11679
- ${statusLight(agent.status)}
11680
- ${this.#dropButton(agent)}
11681
- ${this.#deleteButton(agent)}
11843
+ <span class="title"><span class="state">${statusLabel[agent.status]}</span> · ${title || untitled}</span>
11844
+ ${this.#ribbon(scoops)}
11845
+ ${this.#dropButton(agent, selected)}
11846
+ ${this.#deleteButton(agent, selected)}
11682
11847
  ${error ? b`<span class="error">${error}</span>` : A}
11683
11848
  </li>`;
11684
11849
  }
@@ -11696,12 +11861,15 @@ var SliccAgents = class extends ModelElement {
11696
11861
  </div>`;
11697
11862
  }
11698
11863
  render() {
11699
- const agents = ordered(this.model?.agent.list() ?? []);
11864
+ const list5 = this.model?.agent.list() ?? [];
11700
11865
  const active = this.model?.agent.active() ?? "";
11701
11866
  const errors = Object.values(this.errors);
11702
- return b`${this.#actions()}<ul role="listbox" aria-label="Cones and scoops" @keydown=${this.#keydown}>
11703
- ${agents.map((agent) => this.#row(agent, active))}
11704
- </ul>
11867
+ const rows = ordered(list5).filter(
11868
+ (agent) => agent.kind === "cone" || agent.parentId === this.#expanded
11869
+ );
11870
+ return b`<div class="list"><ul role="tree" aria-label="Cones and scoops" @keydown=${this.#keydown} @focusin=${this.#focusin} @focusout=${this.#focusout}>
11871
+ ${rows.map((agent) => this.#row(agent, active))}
11872
+ </ul></div>${this.#actions()}
11705
11873
  <div class="sr" role="status">${errors.at(-1) ?? ""}</div>`;
11706
11874
  }
11707
11875
  };
@@ -11879,6 +12047,7 @@ function fallbackModel(options) {
11879
12047
  return offered.find((option2) => option2.default) ?? offered[0];
11880
12048
  }
11881
12049
  function controls(model) {
12050
+ if (model.agent.readOnly?.()) return false;
11882
12051
  const state2 = model.follow?.state();
11883
12052
  return !state2 || !!state2.access.control && state2.link === "connected";
11884
12053
  }
@@ -32790,6 +32959,12 @@ var SliccApp = class extends ThemedElement {
32790
32959
  ...model.updates ? [model.updates.on("items", update)] : [],
32791
32960
  ...model.network ? [model.network.on("network", update)] : [],
32792
32961
  ...model.tabs ? [model.tabs.on("tabs", update)] : [],
32962
+ ...model.agent.readOnly ? [
32963
+ model.agent.on("readOnly", () => {
32964
+ settle2();
32965
+ update();
32966
+ })
32967
+ ] : [],
32793
32968
  ...model.follow ? [
32794
32969
  model.follow.on("follow", () => {
32795
32970
  settle2();
@@ -34760,7 +34935,7 @@ var SliccBrowser = class extends ModelElement {
34760
34935
  this.requestUpdate();
34761
34936
  }),
34762
34937
  ...model.network ? [model.network.on("network", () => this.requestUpdate())] : [],
34763
- ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : [],
34938
+ ...onWatch(model, () => this.requestUpdate()),
34764
34939
  () => clearInterval(timer),
34765
34940
  () => resize.disconnect(),
34766
34941
  () => document.removeEventListener("visibilitychange", visibility),
@@ -35429,7 +35604,10 @@ var SliccChanges = class extends ModelElement {
35429
35604
  `
35430
35605
  ];
35431
35606
  subscribe(model) {
35432
- return [changesOf(model).on("changes", () => this.requestUpdate())];
35607
+ return [
35608
+ changesOf(model).on("changes", () => this.requestUpdate()),
35609
+ ...onWatch(model, () => this.requestUpdate())
35610
+ ];
35433
35611
  }
35434
35612
  focus() {
35435
35613
  this.focusOn("li[data-path]");
@@ -35444,7 +35622,8 @@ var SliccChanges = class extends ModelElement {
35444
35622
  async #revert(event2, change) {
35445
35623
  event2.stopPropagation();
35446
35624
  this.error = "";
35447
- if (await confirmRevert(change)) this.error = await revertPaths(this.#port(), [change.path]);
35625
+ if (await confirmRevert(change) && !watchOnly(this.model))
35626
+ this.error = await revertPaths(this.#port(), [change.path]);
35448
35627
  }
35449
35628
  async #all(action) {
35450
35629
  const port = this.#port();
@@ -35456,7 +35635,7 @@ var SliccChanges = class extends ModelElement {
35456
35635
  }
35457
35636
  const count = changes2.length;
35458
35637
  const title = `Revert ${count} ${count === 1 ? "change" : "changes"}?`;
35459
- if (await confirm({ title, body: lost(changes2), action: "Revert all" }))
35638
+ if (await confirm({ title, body: lost(changes2), action: "Revert all" }) && !watchOnly(this.model))
35460
35639
  this.error = await revertPaths(
35461
35640
  port,
35462
35641
  changes2.map((change) => change.path)
@@ -35492,7 +35671,7 @@ var SliccChanges = class extends ModelElement {
35492
35671
  ${statusMark(change.status)}
35493
35672
  <span class="name">${basename(change.path)}</span>
35494
35673
  <span class="where"><bdi>${[at, by].filter(Boolean).join(" \xB7 ")}</bdi></span>
35495
- <span class="actions">
35674
+ ${watchOnly(this.model) ? A : b`<span class="actions">
35496
35675
  <swc-action-button
35497
35676
  size="xs"
35498
35677
  quiet
@@ -35511,7 +35690,7 @@ var SliccChanges = class extends ModelElement {
35511
35690
  >
35512
35691
  <swc-icon-revert slot="icon"></swc-icon-revert>
35513
35692
  </swc-action-button>
35514
- </span>
35693
+ </span>`}
35515
35694
  </li>`;
35516
35695
  }
35517
35696
  #list(changes2) {
@@ -35563,8 +35742,8 @@ var SliccChanges = class extends ModelElement {
35563
35742
  return b`<div class="bar">
35564
35743
  <span class="summary">${changes2.length} pending ${changes2.length === 1 ? "change" : "changes"}</span>
35565
35744
  <span class="spacer"></span>
35566
- ${changes2.length ? b`<swc-action-button size="s" quiet @click=${() => this.#all("accept")}>Accept all</swc-action-button>
35567
- <swc-action-button size="s" quiet @click=${() => this.#all("revert")}>Revert all</swc-action-button>` : A}
35745
+ ${changes2.length && !watchOnly(this.model) ? b`<swc-action-button size="s" quiet data-action="accept-all" @click=${() => this.#all("accept")}>Accept all</swc-action-button>
35746
+ <swc-action-button size="s" quiet data-action="revert-all" @click=${() => this.#all("revert")}>Revert all</swc-action-button>` : A}
35568
35747
  </div>
35569
35748
  ${errorLine(this.error)}
35570
35749
  ${changes2.length ? this.#list(changes2) : b`<div class="note">No pending changes. Edits by agents show up here for review.</div>`}`;
@@ -35619,11 +35798,16 @@ var SliccDiffPanel = class extends ThemedElement {
35619
35798
  `
35620
35799
  ];
35621
35800
  subscribe(model) {
35622
- return [...super.subscribe(model), changesOf(model).on("changes", () => this.requestUpdate())];
35801
+ return [
35802
+ ...super.subscribe(model),
35803
+ changesOf(model).on("changes", () => this.requestUpdate()),
35804
+ ...onWatch(model, () => this.requestUpdate())
35805
+ ];
35623
35806
  }
35624
35807
  async #revert(port, change) {
35625
35808
  this.error = "";
35626
- if (await confirmRevert(change)) this.error = await revertPaths(port, [this.path]);
35809
+ if (await confirmRevert(change) && !watchOnly(this.model))
35810
+ this.error = await revertPaths(port, [this.path]);
35627
35811
  }
35628
35812
  #body(change, style) {
35629
35813
  if (change.before === null && change.after === null) {
@@ -35672,12 +35856,12 @@ var SliccDiffPanel = class extends ThemedElement {
35672
35856
  >`
35673
35857
  )}
35674
35858
  </swc-action-group>`}
35675
- <swc-action-button size="s" quiet data-action="accept" accessible-label="Accept" title="Accept" @click=${() => port?.accept(this.path)}>
35859
+ ${watchOnly(model) ? A : b`<swc-action-button size="s" quiet data-action="accept" accessible-label="Accept" title="Accept" @click=${() => port?.accept(this.path)}>
35676
35860
  <swc-icon-checkmark slot="icon"></swc-icon-checkmark><span class="label">Accept</span>
35677
35861
  </swc-action-button>
35678
35862
  <swc-action-button size="s" quiet data-action="revert" accessible-label="Revert" title="Revert" @click=${() => this.#revert(port, change)}>
35679
35863
  <swc-icon-revert slot="icon"></swc-icon-revert><span class="label">Revert</span>
35680
- </swc-action-button>
35864
+ </swc-action-button>`}
35681
35865
  </div>
35682
35866
  ${errorLine(this.error)}
35683
35867
  ${this.#body(change, style)}`;
@@ -36192,7 +36376,7 @@ var SliccChat = class extends ThemedElement {
36192
36376
  }),
36193
36377
  model.agent.on("agents", settle2),
36194
36378
  ...model.tabs ? [model.tabs.on("tabs", () => this.requestUpdate())] : [],
36195
- ...model.follow ? [model.follow.on("follow", settle2)] : [],
36379
+ ...onWatch(model, settle2),
36196
36380
  model.agent.on("messages", (agentId) => {
36197
36381
  if (agentId === this.#id()) this.#refresh(this.#sent(agentId));
36198
36382
  }),
@@ -37769,6 +37953,10 @@ var SliccComposer = class extends ThemedElement {
37769
37953
  #abandon;
37770
37954
  #recognition = null;
37771
37955
  #erase;
37956
+ #release = (event2) => {
37957
+ const released = event2 instanceof KeyboardEvent && (event2.code === "KeyM" || event2.key === "Alt");
37958
+ if (this.dictating && (released || event2.type === "blur")) this.dictate();
37959
+ };
37772
37960
  #keys = { capture: true, handleEvent: (event2) => this.#keydown(event2) };
37773
37961
  constructor() {
37774
37962
  super();
@@ -37930,27 +38118,6 @@ var SliccComposer = class extends ThemedElement {
37930
38118
  .failed {
37931
38119
  color: var(--swc-negative-content-color-default);
37932
38120
  }
37933
- .below {
37934
- display: flex;
37935
- align-items: center;
37936
- gap: var(--swc-spacing-100);
37937
- max-width: 860px;
37938
- margin: var(--swc-spacing-75) auto 0;
37939
- min-height: var(--swc-component-height-75);
37940
- }
37941
- .below swc-action-button {
37942
- margin-inline-start: auto;
37943
- }
37944
- swc-action-button.selected {
37945
- --swc-action-button-background-color-default: var(--swc-neutral-background-color-selected-default);
37946
- --swc-action-button-background-color-hover: var(--swc-neutral-background-color-selected-hover);
37947
- --swc-action-button-background-color-down: var(--swc-neutral-background-color-selected-down);
37948
- --swc-action-button-background-color-focus: var(--swc-neutral-background-color-selected-key-focus);
37949
- --swc-action-button-content-color-default: var(--swc-gray-25);
37950
- --swc-action-button-content-color-hover: var(--swc-gray-25);
37951
- --swc-action-button-content-color-down: var(--swc-gray-25);
37952
- --swc-action-button-content-color-focus: var(--swc-gray-25);
37953
- }
37954
38121
  .popup {
37955
38122
  position: absolute;
37956
38123
  left: 0;
@@ -38056,6 +38223,8 @@ var SliccComposer = class extends ThemedElement {
38056
38223
  connectedCallback() {
38057
38224
  super.connectedCallback();
38058
38225
  clearTimeout(this.#abandon);
38226
+ globalThis.addEventListener("keyup", this.#release);
38227
+ globalThis.addEventListener("blur", this.#release);
38059
38228
  if (this.hasUpdated) this.#wire();
38060
38229
  }
38061
38230
  firstUpdated() {
@@ -38063,6 +38232,8 @@ var SliccComposer = class extends ThemedElement {
38063
38232
  }
38064
38233
  disconnectedCallback() {
38065
38234
  super.disconnectedCallback();
38235
+ globalThis.removeEventListener("keyup", this.#release);
38236
+ globalThis.removeEventListener("blur", this.#release);
38066
38237
  clearValues(this.renderRoot);
38067
38238
  const held = [
38068
38239
  this.attachments,
@@ -38408,10 +38579,21 @@ var SliccComposer = class extends ThemedElement {
38408
38579
  return this.#recall(-1);
38409
38580
  return false;
38410
38581
  }
38582
+ #talking() {
38583
+ return !!this.model?.settings.get().pushToTalk && !!speech();
38584
+ }
38585
+ #shortcut(event2) {
38586
+ if (event2.key === "Backspace" || event2.key === "Delete") this.#flash();
38587
+ const chord = event2.altKey && !event2.ctrlKey && !event2.metaKey && !event2.shiftKey;
38588
+ if (!chord || event2.code !== "KeyM" || !this.#talking()) return false;
38589
+ event2.preventDefault();
38590
+ if (!event2.repeat) this.dictate();
38591
+ return true;
38592
+ }
38411
38593
  #keydown(event2) {
38412
38594
  const area = this.#textarea;
38413
38595
  if (event2.isComposing || !area || event2.composedPath()[0] !== area) return;
38414
- if (event2.key === "Backspace" || event2.key === "Delete") this.#flash();
38596
+ if (this.#shortcut(event2)) return;
38415
38597
  const sendOnEnter = this.model?.settings.get().sendOnEnter ?? true;
38416
38598
  let handled = this.#popupKey(event2) || this.#historyKey(event2, area);
38417
38599
  if (!handled && event2.key === "Tab" && !event2.shiftKey && !this.value) {
@@ -38451,7 +38633,8 @@ var SliccComposer = class extends ThemedElement {
38451
38633
  keys.push(
38452
38634
  `${enter ? "Shift+Enter" : "Enter"} adds a new line`,
38453
38635
  "/ lists commands",
38454
- "@ mentions"
38636
+ "@ mentions",
38637
+ ...this.#talking() ? ["hold Alt+M to dictate"] : []
38455
38638
  );
38456
38639
  return `${keys.join(", ")}.`;
38457
38640
  }
@@ -38485,17 +38668,23 @@ var SliccComposer = class extends ThemedElement {
38485
38668
  );
38486
38669
  }
38487
38670
  }
38671
+ #toggleTalk = (event2) => {
38672
+ event2.stopPropagation();
38673
+ const settings = this.model?.settings;
38674
+ settings?.update({ pushToTalk: !settings.get().pushToTalk });
38675
+ };
38488
38676
  dictate() {
38489
38677
  if (this.#recognition) {
38490
38678
  this.#recognition.stop();
38491
38679
  return;
38492
38680
  }
38493
- const Speech = globalThis.SpeechRecognition ?? globalThis.webkitSpeechRecognition;
38681
+ const Speech = speech();
38494
38682
  if (!Speech) return;
38495
38683
  const recognition = new Speech();
38496
38684
  recognition.interimResults = false;
38685
+ recognition.continuous = true;
38497
38686
  recognition.onresult = (event2) => {
38498
- const text2 = [...event2.results].map((result) => result[0].transcript).join(" ");
38687
+ const text2 = [...event2.results].slice(event2.resultIndex ?? 0).map((result) => result[0].transcript).join(" ");
38499
38688
  this.value = `${this.value}${this.value && !this.value.endsWith(" ") ? " " : ""}${text2}`;
38500
38689
  };
38501
38690
  recognition.onend = () => {
@@ -38641,7 +38830,8 @@ var SliccComposer = class extends ThemedElement {
38641
38830
  const agent = this.model?.agent.list().find((candidate) => candidate.id === this.#agent);
38642
38831
  const suggestion = this.model?.agent.suggestion(this.#agent);
38643
38832
  const canSend = !!this.value.trim() || this.attachments.some((attachment2) => !attachment2.error);
38644
- const speech = "SpeechRecognition" in globalThis || "webkitSpeechRecognition" in globalThis;
38833
+ const pushToTalk = this.model?.settings.get().pushToTalk ?? false;
38834
+ const talk = !!speech();
38645
38835
  const held = this.#held();
38646
38836
  return b`<div class="column">
38647
38837
  <span id="keys" class="sr" aria-hidden="true">${this.#instructions(busy)}</span>
@@ -38679,6 +38869,10 @@ var SliccComposer = class extends ThemedElement {
38679
38869
  <sp-menu-item value="screenshot">Take a screenshot of the browser tab</sp-menu-item>
38680
38870
  <sp-menu-item value="file">Attach a file from SLICC</sp-menu-item>
38681
38871
  <sp-menu-item value="secret">Share a secret</sp-menu-item>
38872
+ ${talk ? b`<sp-menu-divider></sp-menu-divider>
38873
+ <sp-menu-group selects="multiple" data-group="talk" @change=${this.#toggleTalk}>
38874
+ <sp-menu-item value="push-to-talk" data-action="push-to-talk" ?selected=${pushToTalk}>Enable push to talk<span slot="description">Hold Alt+M to dictate</span></sp-menu-item>
38875
+ </sp-menu-group>` : A}
38682
38876
  </sp-menu>
38683
38877
  </swc-popover>
38684
38878
  <input type="file" multiple @change=${(event2) => {
@@ -38686,17 +38880,7 @@ var SliccComposer = class extends ThemedElement {
38686
38880
  void this.addFiles([...input.files ?? []]);
38687
38881
  input.value = "";
38688
38882
  }} />
38689
- </div>
38690
- ${speech ? b`<div class="below">
38691
- <swc-action-button
38692
- size="s"
38693
- quiet
38694
- class=${this.dictating ? "selected" : ""}
38695
- accessible-label=${this.dictating ? "Stop dictation" : "Dictate"}
38696
- data-action="dictate"
38697
- @click=${() => this.dictate()}
38698
- ><swc-icon-microphone slot="icon"></swc-icon-microphone></swc-action-button>
38699
- </div>` : A}`;
38883
+ </div>`;
38700
38884
  }
38701
38885
  };
38702
38886
 
@@ -39251,7 +39435,7 @@ var SliccNotices = class extends ModelElement {
39251
39435
  (action) => b`<swc-button size="s" variant="secondary" fill-style="outline" data-action=${action.id} ?pending=${pending === action.id} ?disabled=${!!pending && pending !== action.id} @click=${() => void this.act(notice.id, action.id)}>${action.label}</swc-button>`
39252
39436
  )}</div>` : A}
39253
39437
  </div>
39254
- <swc-close-button size="m" data-dismiss accessible-label=${`Dismiss: ${notice.title}`} @click=${() => this.dismiss(notice.id)}></swc-close-button>
39438
+ ${notice.dismissible === false ? A : b`<swc-close-button size="m" data-dismiss accessible-label=${`Dismiss: ${notice.title}`} @click=${() => this.dismiss(notice.id)}></swc-close-button>`}
39255
39439
  </div>`;
39256
39440
  }
39257
39441
  #tabs() {
@@ -39278,7 +39462,9 @@ var SliccNotices = class extends ModelElement {
39278
39462
  }
39279
39463
  render() {
39280
39464
  const port = this.model?.notices;
39281
- const notices = (port?.list() ?? []).filter((notice) => !this.dismissed.has(notice.id));
39465
+ const notices = (port?.list() ?? []).filter(
39466
+ (notice) => notice.dismissible === false || !this.dismissed.has(notice.id)
39467
+ );
39282
39468
  const tabs = this.#tabs();
39283
39469
  const approvals = this.model?.approvals?.decide ? [] : waiting(this.model, Date.now());
39284
39470
  if (!notices.length && !approvals.length && tabs === A) return A;
@@ -40998,6 +41184,7 @@ var SliccSettings = class extends ThemedElement {
40998
41184
  <div class="switches">
40999
41185
  <sp-switch ?checked=${value.sendOnEnter} data-setting="sendOnEnter" @change=${(e122) => this.#update({ sendOnEnter: this.#checked(e122) })}>Enter sends, Shift+Enter adds a line</sp-switch>
41000
41186
  <sp-switch ?checked=${value.showThinking} data-setting="showThinking" @change=${(e122) => this.#update({ showThinking: this.#checked(e122) })}>Show thinking</sp-switch>
41187
+ ${speech() ? b`<sp-switch ?checked=${value.pushToTalk ?? false} data-setting="pushToTalk" @change=${(e122) => this.#update({ pushToTalk: this.#checked(e122) })}>Push to talk: hold Alt+M to dictate</sp-switch>` : A}
41001
41188
  </div>
41002
41189
  </div>
41003
41190
  <div class="row">
@@ -41110,12 +41297,13 @@ var bridge = `(() => {
41110
41297
  }
41111
41298
  node.replaceWith(svg);
41112
41299
  }
41300
+ size();
41113
41301
  };
41114
41302
  const fonts = (list) => {
41115
41303
  for (const font of list) {
41116
41304
  const face = new FontFace(font.family, font.data, { weight: String(font.weight) });
41117
41305
  document.fonts.add(face);
41118
- face.load().catch(() => {});
41306
+ face.load().then(size, () => {});
41119
41307
  }
41120
41308
  };
41121
41309
  addEventListener('message', (event) => {
@@ -41131,6 +41319,7 @@ var bridge = `(() => {
41131
41319
  };
41132
41320
  document.addEventListener('DOMContentLoaded', () => {
41133
41321
  window.LucideIcons.render();
41322
+ size();
41134
41323
  new ResizeObserver(size).observe(document.body);
41135
41324
  });
41136
41325
  post({ type: 'slicc-ready' });
@@ -41432,7 +41621,7 @@ var SliccSprinkle = class extends ThemedElement {
41432
41621
  () => globalThis.removeEventListener("message", this.#message),
41433
41622
  model.sprinkles.on("sprinkles", () => this.requestUpdate()),
41434
41623
  this.#dips.on("change", () => this.requestUpdate()),
41435
- ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : []
41624
+ ...onWatch(model, () => this.requestUpdate())
41436
41625
  ];
41437
41626
  }
41438
41627
  #drag = (event2) => {