@ai-ecoverse/slicc-spectrum 1.60.2 → 1.62.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
@@ -6304,10 +6304,10 @@ function getNearestOverflowAncestor(node) {
6304
6304
  }
6305
6305
  return getNearestOverflowAncestor(parentNode);
6306
6306
  }
6307
- function getOverflowAncestors(node, list4, traverseIframes) {
6307
+ function getOverflowAncestors(node, list5, traverseIframes) {
6308
6308
  var _node$ownerDocument2;
6309
- if (list4 === void 0) {
6310
- list4 = [];
6309
+ if (list5 === void 0) {
6310
+ list5 = [];
6311
6311
  }
6312
6312
  if (traverseIframes === void 0) {
6313
6313
  traverseIframes = true;
@@ -6317,9 +6317,9 @@ function getOverflowAncestors(node, list4, traverseIframes) {
6317
6317
  const win = getWindow(scrollableAncestor);
6318
6318
  if (isBody) {
6319
6319
  const frameElement = getFrameElement(win);
6320
- return list4.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
6320
+ return list5.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
6321
6321
  } else {
6322
- return list4.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
6322
+ return list5.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
6323
6323
  }
6324
6324
  }
6325
6325
  function getFrameElement(win) {
@@ -12300,7 +12300,7 @@ function remoteLight(status2) {
12300
12300
  "linked devices are watching the agent."
12301
12301
  )
12302
12302
  ].join(" ");
12303
- const by = (list4) => list4.length === 1 ? list4[0].name : `${list4.length} linked devices`;
12303
+ const by = (list5) => list5.length === 1 ? list5[0].name : `${list5.length} linked devices`;
12304
12304
  if (asking2.length) {
12305
12305
  const text2 = asking2.length === 1 ? `${asking2[0].name} asks to follow` : `${asking2.length} devices ask to follow`;
12306
12306
  return { mode: "ask", variant: "notice", text: text2, tooltip };
@@ -12908,8 +12908,8 @@ var SliccNetwork = class extends ModelElement {
12908
12908
  }
12909
12909
  const device = status2.links?.devices.find((item2) => item2.id === exit.id);
12910
12910
  if (device?.state === "connected") return A;
12911
- const who = device ? `${device.name} is ${device.state}` : "The linked device isn\u2019t connected";
12912
- return b`<div class="warning" data-exit="device" data-held><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><div class="banner"><span>${who}. Internet traffic waits until it’s connected.</span><div class="actions"><swc-button size="s" variant="secondary" fill-style="outline" data-action="exit-direct" ?pending=${this.busy === "exit"} ?disabled=${this.#waiting("exit")} @click=${() => this.#act("exit", () => port.setExit?.(null), "error")}>Send directly</swc-button></div></div></div>`;
12911
+ const who2 = device ? `${device.name} is ${device.state}` : "The linked device isn\u2019t connected";
12912
+ return b`<div class="warning" data-exit="device" data-held><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><div class="banner"><span>${who2}. Internet traffic waits until it’s connected.</span><div class="actions"><swc-button size="s" variant="secondary" fill-style="outline" data-action="exit-direct" ?pending=${this.busy === "exit"} ?disabled=${this.#waiting("exit")} @click=${() => this.#act("exit", () => port.setExit?.(null), "error")}>Send directly</swc-button></div></div></div>`;
12913
12913
  }
12914
12914
  #exitPicker(port, status2) {
12915
12915
  const tailnet = status2.tailnet;
@@ -13694,8 +13694,8 @@ var Panels = class {
13694
13694
  if (bad) return bad;
13695
13695
  this.quietly(() => this.#host.open(id, focus, section));
13696
13696
  if (place3) {
13697
- const moved = this.move(id, place3);
13698
- if (moved.code !== 0) return moved;
13697
+ const moved2 = this.move(id, place3);
13698
+ if (moved2.code !== 0) return moved2;
13699
13699
  }
13700
13700
  return ok(`${focus ? "focused" : info.open ? "showed" : "opened"} ${id}`);
13701
13701
  }
@@ -13816,37 +13816,37 @@ function coneOf(agents, id) {
13816
13816
  }
13817
13817
  return agent?.kind === "cone" ? agent.id : null;
13818
13818
  }
13819
- function resolve(panels, raw2, reachable, cone) {
13819
+ function resolve(panels, raw2, reachable2, cone) {
13820
13820
  if (/^(file|diff):./.test(raw2)) return raw2;
13821
13821
  if (raw2 === "chat") {
13822
13822
  const agent = cone === void 0 ? panels.active() : cone;
13823
- return reachable.some((info) => info.id === `chat:${agent}`) ? `chat:${agent}` : null;
13823
+ return reachable2.some((info) => info.id === `chat:${agent}`) ? `chat:${agent}` : null;
13824
13824
  }
13825
13825
  if (raw2 === "terminal") {
13826
- const terminals = reachable.filter((info) => info.kind === "terminal");
13826
+ const terminals = reachable2.filter((info) => info.kind === "terminal");
13827
13827
  const picked = terminals.find((info) => info.active) ?? terminals.filter((info) => info.open).at(-1) ?? terminals.at(-1);
13828
13828
  return picked?.id ?? null;
13829
13829
  }
13830
- if (reachable.some((info) => info.id === raw2)) return raw2;
13830
+ if (reachable2.some((info) => info.id === raw2)) return raw2;
13831
13831
  const name = raw2.startsWith("sprinkle:") ? raw2.slice(9) : raw2;
13832
- const sprinkles = reachable.filter((info) => info.kind === "sprinkle");
13832
+ const sprinkles = reachable2.filter((info) => info.kind === "sprinkle");
13833
13833
  const found = sprinkles.find((info) => info.id === `sprinkle:${name}`) ?? sprinkles.find((info) => cone && info.id === `sprinkle:${cone}/${name}`) ?? sprinkles.find((info) => info.id.split("/").at(-1) === name);
13834
13834
  return found?.id ?? null;
13835
13835
  }
13836
13836
  function state(info) {
13837
- const shown2 = info.active ? "active" : info.visible ? "shown" : info.open ? "open" : "closed";
13838
- return info.busy ? `${shown2} \xB7 busy: ${info.busy}` : shown2;
13837
+ const shown3 = info.active ? "active" : info.visible ? "shown" : info.open ? "open" : "closed";
13838
+ return info.busy ? `${shown3} \xB7 busy: ${info.busy}` : shown3;
13839
13839
  }
13840
13840
  function table(rows) {
13841
13841
  const lines = [["ID", "TITLE", "STATE"], ...rows.map((row) => [row.id, row.title, state(row)])];
13842
13842
  const widths = [0, 1].map((column) => Math.max(...lines.map((line) => line[column].length)));
13843
- return lines.map(([id, title, shown2]) => `${id.padEnd(widths[0])} ${title.padEnd(widths[1])} ${shown2}`).join("\n");
13843
+ return lines.map(([id, title, shown3]) => `${id.padEnd(widths[0])} ${title.padEnd(widths[1])} ${shown3}`).join("\n");
13844
13844
  }
13845
13845
  var done = (result, note = "") => result.code === 0 ? { stdout: `${result.message}${note}
13846
13846
  `, stderr: "", code: 0 } : { stdout: "", stderr: `panel: ${result.message}
13847
13847
  `, code: result.code };
13848
13848
  function act(scope, parsed) {
13849
- const { panels, reachable, cone } = scope;
13849
+ const { panels, reachable: reachable2, cone } = scope;
13850
13850
  if (parsed.verb === "reset") {
13851
13851
  const recent = scope.agent ? panels.recentClose() : null;
13852
13852
  if (recent)
@@ -13856,11 +13856,11 @@ function act(scope, parsed) {
13856
13856
  return done(panels.reset());
13857
13857
  }
13858
13858
  const raw2 = parsed.id;
13859
- const id = resolve(panels, raw2, reachable, cone);
13859
+ const id = resolve(panels, raw2, reachable2, cone);
13860
13860
  if (!id) return done(unknown(raw2));
13861
13861
  let place3 = parsed.place;
13862
13862
  if (typeof place3 === "object") {
13863
- const ref = resolve(panels, place3.ref, reachable, cone);
13863
+ const ref = resolve(panels, place3.ref, reachable2, cone);
13864
13864
  if (!ref) return done(unknown(place3.ref));
13865
13865
  place3 = { ...place3, ref };
13866
13866
  }
@@ -13895,12 +13895,12 @@ ${help}`, code: 2 };
13895
13895
  const agents = panels.agents();
13896
13896
  const scoped2 = caller.agentId !== null || !!caller.cone;
13897
13897
  const cone = scoped2 ? caller.cone ?? coneOf(agents, caller.agentId) : void 0;
13898
- const reachable = panels.list().filter(
13898
+ const reachable2 = panels.list().filter(
13899
13899
  (info) => !scoped2 || info.agent === null || !!cone && coneOf(agents, info.agent) === cone
13900
13900
  );
13901
13901
  if (parsed.verb !== "list")
13902
- return act({ panels, agent: caller.agentId !== null, cone, reachable }, parsed);
13903
- const body4 = parsed.json ? JSON.stringify(reachable, null, 2) : table(reachable);
13902
+ return act({ panels, agent: caller.agentId !== null, cone, reachable: reachable2 }, parsed);
13903
+ const body4 = parsed.json ? JSON.stringify(reachable2, null, 2) : table(reachable2);
13904
13904
  return { stdout: `${body4}
13905
13905
  `, stderr: "", code: 0 };
13906
13906
  }
@@ -20681,12 +20681,12 @@ function user(message) {
20681
20681
  const tag3 = delivered === "steer" || delivered === "follow-up" ? deliveries[delivered] : null;
20682
20682
  const agent = message.origin === "agent";
20683
20683
  const name = message.from ?? "an agent";
20684
- const who = agent ? name : message.from ? `From ${message.from}` : "You";
20684
+ const who2 = agent ? name : message.from ? `From ${message.from}` : "You";
20685
20685
  const label = agent ? `Request from ${name}` : message.from ? `Message from ${message.from}` : "Your message";
20686
20686
  return b`<swc-conversation-turn type="user" class="message user" accessible-label=${label} data-id=${message.id} data-mode=${message.mode ?? "send"} data-delivered=${delivered ?? "run"} data-origin=${message.origin ?? "user"}>
20687
20687
  <div class="bubble">
20688
20688
  <div class="meta">
20689
- <span class="who">${who}</span><span>${time(message.createdAt)}</span>
20689
+ <span class="who">${who2}</span><span>${time(message.createdAt)}</span>
20690
20690
  ${agent ? b`<swc-badge class="origin" size="s" variant="indigo">Agent</swc-badge>` : A}
20691
20691
  ${tag3 ? b`<swc-badge class="tag" size="s" variant=${delivered === "steer" ? "notice" : "informative"} subtle>${tag3}</swc-badge>` : A}
20692
20692
  </div>
@@ -21945,8 +21945,8 @@ var SliccUpdates = class extends ModelElement {
21945
21945
  #checked(at) {
21946
21946
  if (at === null) return b`<span>Not checked yet</span>`;
21947
21947
  const date = new Date(at);
21948
- const shown2 = date.toLocaleString("en-GB", { dateStyle: "medium", timeStyle: "short" });
21949
- return b`<span>Checked <time datetime=${date.toISOString()}>${shown2}</time></span>`;
21948
+ const shown3 = date.toLocaleString("en-GB", { dateStyle: "medium", timeStyle: "short" });
21949
+ return b`<span>Checked <time datetime=${date.toISOString()}>${shown3}</time></span>`;
21950
21950
  }
21951
21951
  #item(item2) {
21952
21952
  const [variant, state3] = states[item2.state];
@@ -22011,14 +22011,14 @@ var SliccUpdates = class extends ModelElement {
22011
22011
  #package(item2, all2, act2) {
22012
22012
  const light = packageLight(item2);
22013
22013
  const busy = this.busy.get(item2.id);
22014
- const shown2 = busy ? [busy] : act2 ? item2.actions : [];
22014
+ const shown3 = busy ? [busy] : act2 ? item2.actions : [];
22015
22015
  const error = this.problems.get(item2.id) ?? item2.error;
22016
22016
  return b`<li data-id=${item2.id} data-state=${item2.state}>
22017
22017
  <div class="name">
22018
22018
  <h3 title=${item2.package}>${item2.label}</h3>
22019
22019
  ${light ? b`<swc-status-light size="s" variant=${light[0]}>${light[1]}</swc-status-light>` : A}
22020
22020
  </div>
22021
- <div class="buttons">${shown2.map(
22021
+ <div class="buttons">${shown3.map(
22022
22022
  (action) => b`<swc-button
22023
22023
  size="s"
22024
22024
  variant="secondary"
@@ -22035,7 +22035,7 @@ var SliccUpdates = class extends ModelElement {
22035
22035
  (warning) => b`<span><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle>${warning}</span>`
22036
22036
  )}</p>` : A}
22037
22037
  ${item2.commands.length ? b`<p class="commands"><span class="hidden">Commands: </span>${item2.commands.map(
22038
- (command2) => b`<code>${command2}</code>`
22038
+ (command3) => b`<code>${command3}</code>`
22039
22039
  )}</p>` : A}
22040
22040
  ${this.#packageProgress(item2)}
22041
22041
  ${error ? b`<div class="error" role="alert" data-error>
@@ -22716,9 +22716,9 @@ var SliccApp = class extends ThemedElement {
22716
22716
  if (!model) return [];
22717
22717
  const selected = this.#cone();
22718
22718
  const cones = model.agent.list().filter((agent) => agent.kind === "cone");
22719
- const list4 = model.sprinkles.list();
22720
- const order = [selected, ...cones.map((cone) => cone.id), ...list4.map((item2) => item2.agentId)];
22721
- return list4.map((sprinkle) => {
22719
+ const list5 = model.sprinkles.list();
22720
+ const order = [selected, ...cones.map((cone) => cone.id), ...list5.map((item2) => item2.agentId)];
22721
+ return list5.map((sprinkle) => {
22722
22722
  const cone = cones.find((agent) => agent.id === sprinkle.agentId && agent.id !== selected);
22723
22723
  return cone ? { ...sprinkle, title: `${cone.name} / ${sprinkle.title}` } : sprinkle;
22724
22724
  }).sort((a22, b13) => order.indexOf(a22.agentId) - order.indexOf(b13.agentId));
@@ -22774,11 +22774,11 @@ var SliccApp = class extends ThemedElement {
22774
22774
  #rail(items, side) {
22775
22775
  const primary = side === "bottom" ? items.filter((item2) => phoneRail.includes(item2.id)) : items;
22776
22776
  const fit = primary.length < items.length ? Math.min(primary.length, railCapacity(this.#width, Infinity)) : railCapacity(this.#width, items.length);
22777
- const shown2 = side === "bottom" ? primary.slice(0, fit) : items;
22778
- const grouped = new Set(shown2.map((item2) => item2.cone).filter(Boolean)).size > 1;
22779
- return b`<nav class=${`rail ${side}`} aria-label=${`Panels, ${side}`} @dragover=${this.#railOver} @dragleave=${this.#railLeave} @drop=${this.#railDrop}>${shown2.map(
22780
- (item2, index) => b`${grouped && index && shown2[index - 1].cone !== item2.cone ? b`<span class="cones" aria-hidden="true"></span>` : A}${this.#railButton(item2, side)}`
22781
- )}${this.#more(items.filter((item2) => !shown2.includes(item2)))}</nav>`;
22777
+ const shown3 = side === "bottom" ? primary.slice(0, fit) : items;
22778
+ const grouped = new Set(shown3.map((item2) => item2.cone).filter(Boolean)).size > 1;
22779
+ return b`<nav class=${`rail ${side}`} aria-label=${`Panels, ${side}`} @dragover=${this.#railOver} @dragleave=${this.#railLeave} @drop=${this.#railDrop}>${shown3.map(
22780
+ (item2, index) => b`${grouped && index && shown3[index - 1].cone !== item2.cone ? b`<span class="cones" aria-hidden="true"></span>` : A}${this.#railButton(item2, side)}`
22781
+ )}${this.#more(items.filter((item2) => !shown3.includes(item2)))}</nav>`;
22782
22782
  }
22783
22783
  #rails() {
22784
22784
  const dock = this.renderRoot.querySelector("slicc-dock");
@@ -23021,6 +23021,202 @@ function sudo(approval) {
23021
23021
  const as = approval.target && approval.target !== "root" ? `-u ${approval.target} ` : "";
23022
23022
  return `sudo ${as}${approval.command}`;
23023
23023
  }
23024
+ var rulePaths = ["/etc/fnox", "/etc/fnox/config.toml", "/etc/slicc/secrets-policy.toml"];
23025
+ var ruleParents = ["/", "/etc", "/etc/slicc"];
23026
+ function absolute(cwd, word) {
23027
+ const parts2 = [];
23028
+ for (const part2 of `${word.startsWith("/") ? "" : cwd}/${word}`.split("/")) {
23029
+ if (part2 === "..") parts2.pop();
23030
+ else if (part2 && part2 !== ".") parts2.push(part2);
23031
+ const alias = parts2.join("/").match(/^proc\/([^/]+)\/(?:task\/[^/]+\/)?(root|cwd)$/);
23032
+ if (alias?.[2] === "root") parts2.length = 0;
23033
+ else if (alias && /^(?:self|thread-self)$/.test(alias[1]))
23034
+ parts2.splice(0, parts2.length, ...cwd.split("/").filter(Boolean));
23035
+ }
23036
+ return `/${parts2.join("/")}`;
23037
+ }
23038
+ function pattern(path) {
23039
+ const source = path.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, "").replace(/\*\*/g, "").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\u0001/g, "(?:.*/)?").replace(/\u0002/g, ".*");
23040
+ return new RegExp(`^${source}$`);
23041
+ }
23042
+ var opaque = /^\/(?:proc\/[^/]+\/(?:task\/[^/]+\/)?(?:cwd|fd|map_files)|dev\/fd)(?:\/|$)/;
23043
+ var certain = (rules) => rules.startsWith("/") && !opaque.test(rules) && !rules.endsWith("\u2026");
23044
+ var readOnly = [
23045
+ "cat",
23046
+ "cd",
23047
+ "df",
23048
+ "diff",
23049
+ "du",
23050
+ "echo",
23051
+ "file",
23052
+ "grep",
23053
+ "head",
23054
+ "ls",
23055
+ "pwd",
23056
+ "readlink",
23057
+ "realpath",
23058
+ "stat",
23059
+ "tail",
23060
+ "tree",
23061
+ "wc"
23062
+ ];
23063
+ function candidates(word) {
23064
+ if (word === "--") return [];
23065
+ if (word.startsWith("--")) return [word];
23066
+ if (!word.startsWith("-")) return [word];
23067
+ const slash = word.indexOf("/");
23068
+ const cluster2 = Array.from(word.slice(2), (_9, index) => word.slice(index + 2));
23069
+ return [...cluster2, ...slash > 2 ? [word.slice(slash)] : []];
23070
+ }
23071
+ function protects(path, whole) {
23072
+ const inside = (candidate) => candidate === "/etc/fnox" || candidate.startsWith("/etc/fnox/");
23073
+ if (opaque.test(path)) return true;
23074
+ if (/[[{$]/.test(path)) {
23075
+ const prefix = path.slice(0, path.search(/[*?[{$]/));
23076
+ return inside(prefix) || rulePaths.some((rule) => rule.startsWith(prefix));
23077
+ }
23078
+ if (!/[*?]/.test(path))
23079
+ return inside(path) || rulePaths.includes(path) || whole && ruleParents.includes(path);
23080
+ const glob = pattern(path);
23081
+ const top = path.split("/").slice(0, 3).join("/");
23082
+ return rulePaths.some((rule) => glob.test(rule)) || top !== path && pattern(top).test("/etc/fnox") || whole && ruleParents.some((parent) => glob.test(parent));
23083
+ }
23084
+ var command2 = (word) => word.split("/").pop() ?? "";
23085
+ var trusted = (word) => readOnly.includes(word.replace(/^\/(?:usr\/)?bin\/(?=[^/]+$)/, ""));
23086
+ var expansion = /\$\([^)]*\)?|\$\{[^}]*\}?|\$[\w@*#?$!-]*|`[^`]*`?/;
23087
+ function moved(cwds, word) {
23088
+ for (const cwd of [...cwds]) {
23089
+ const next = absolute(cwd, word);
23090
+ if (protects(next, false) || cwds.size >= 64) return next;
23091
+ cwds.add(next);
23092
+ }
23093
+ return null;
23094
+ }
23095
+ function touched(cwds, word, whole) {
23096
+ for (const candidate of candidates(word))
23097
+ for (const cwd of cwds) {
23098
+ const path = absolute(cwd, candidate);
23099
+ if (protects(path, whole)) return path;
23100
+ }
23101
+ return null;
23102
+ }
23103
+ function ansi(command3) {
23104
+ const escape2 = /\\(?:x([0-9a-fA-F]{1,2})|u([0-9a-fA-F]{1,4})|U([0-9a-fA-F]{1,8})|([0-7]{1,3})|([\s\S]))/g;
23105
+ return command3.replace(
23106
+ /\$'((?:[^'\\]|\\[\s\S])*)'/g,
23107
+ (_9, body4) => `'${body4.replace(escape2, (_match, hex, short2, long, octal, plain) => {
23108
+ if (octal) return String.fromCharCode(Number.parseInt(octal, 8));
23109
+ if (plain) return plain;
23110
+ return String.fromCodePoint(
23111
+ Math.min(Number.parseInt(hex ?? short2 ?? long, 16), 1114111)
23112
+ );
23113
+ }).replace(/'/g, "'\\''")}'`
23114
+ ).replace(/\$"/g, '"');
23115
+ }
23116
+ function unglob(command3) {
23117
+ const chars = Array.from(command3);
23118
+ const close = /* @__PURE__ */ new Map();
23119
+ const open = [];
23120
+ for (const [index, char] of chars.entries()) {
23121
+ if (char === "(") open.push(index);
23122
+ else if (char === ")" && open.length) close.set(open.pop(), index);
23123
+ }
23124
+ const out = [];
23125
+ for (let index = 0; index < chars.length; index++) {
23126
+ const end = close.get(index);
23127
+ if (end !== void 0 && /^[?*+@!]$/.test(out.at(-1) ?? "")) {
23128
+ out[out.length - 1] = "*";
23129
+ index = end;
23130
+ } else out.push(chars[index]);
23131
+ }
23132
+ return out.join("");
23133
+ }
23134
+ var separators = /[;&|\n()`]/;
23135
+ function hide2(char) {
23136
+ return separators.test(char) ? String.fromCharCode(57344 + char.charCodeAt(0)) : char;
23137
+ }
23138
+ function unshield(segment2) {
23139
+ return segment2.replace(
23140
+ /[\ue000-\ue07f]/g,
23141
+ (char) => String.fromCharCode(char.charCodeAt(0) - 57344)
23142
+ );
23143
+ }
23144
+ function shield(text2) {
23145
+ let out = "";
23146
+ let quote = "";
23147
+ for (let index = 0; index < text2.length; index++) {
23148
+ const char = text2[index];
23149
+ if (quote === '"' && char === "\\") out += hide2(char) + hide2(text2[++index] ?? "");
23150
+ else if (quote) {
23151
+ out += char === quote ? char : hide2(char);
23152
+ if (char === quote) quote = "";
23153
+ } else if (char === "'" || char === '"') {
23154
+ quote = char;
23155
+ out += char;
23156
+ } else if (char === "\\") out += char + hide2(text2[++index] ?? "");
23157
+ else out += char;
23158
+ }
23159
+ return out;
23160
+ }
23161
+ function quoted(segment2) {
23162
+ const words = [];
23163
+ let word = "";
23164
+ let quote = "";
23165
+ for (let index = 0; index < segment2.length; index++) {
23166
+ const char = segment2[index];
23167
+ if (quote === '"' && char === "\\" && /["\\$`\n]/.test(segment2[index + 1] ?? ""))
23168
+ word += segment2[++index];
23169
+ else if (quote) {
23170
+ if (char === quote) quote = "";
23171
+ else word += char;
23172
+ } else if (char === "'" || char === '"') quote = char;
23173
+ else if (char === "\\") word += segment2[++index] ?? "";
23174
+ else if (/[\s<>=]/.test(char)) {
23175
+ words.push(word);
23176
+ word = "";
23177
+ } else word += char;
23178
+ }
23179
+ return [...words, word];
23180
+ }
23181
+ function commas(words) {
23182
+ return words.flatMap((word) => word.includes(",") ? [word, ...word.split(",")] : [word]).filter(Boolean);
23183
+ }
23184
+ function scan2(words, cwds, whole) {
23185
+ let cd = false;
23186
+ for (const [index, word] of words.entries()) {
23187
+ let hit = null;
23188
+ if (index === 0 || words[index - 1] === "-c") {
23189
+ cd = ["cd", "pushd"].includes(command2(word));
23190
+ hit = touched(cwds, word, whole);
23191
+ } else if (!cd) hit = touched(cwds, word, whole);
23192
+ else if (!word.startsWith("-")) {
23193
+ cd = false;
23194
+ hit = moved(cwds, word);
23195
+ }
23196
+ if (hit) return hit;
23197
+ }
23198
+ return null;
23199
+ }
23200
+ function secretRules(approval) {
23201
+ if (approval.command.length > 4096) return `${approval.command.slice(0, 40)}\u2026`;
23202
+ const start = absolute("/", approval.cwd ?? "/");
23203
+ if (protects(start, false)) return start;
23204
+ const cwds = /* @__PURE__ */ new Set([start]);
23205
+ const text2 = unglob(ansi(approval.command.replace(/\\\n/g, "")));
23206
+ const plain = text2.split(separators).map((segment2) => commas(segment2.split(/[\s<>=]+/).map((word) => word.replace(/['"\\]/g, ""))));
23207
+ const aware = shield(text2).split(separators).map((segment2) => commas(quoted(unshield(segment2))));
23208
+ const segments = JSON.stringify(aware) === JSON.stringify(plain) ? plain : [...plain, ...aware];
23209
+ const whole = segments.some((words) => words.length > 0 && !trusted(words[0]));
23210
+ for (const words of segments) {
23211
+ const hit = scan2(words, cwds, whole);
23212
+ if (hit) return hit;
23213
+ }
23214
+ const named = segments.flat().find((word) => !word.startsWith("/") && /fnox|secrets-policy/.test(word));
23215
+ if (named) return absolute([...cwds].pop() ?? start, named);
23216
+ const home2 = segments.flat().find((word) => /^~(?:[+-](?:\/|$)|.*\/\.\.(?:\/|$))/.test(word));
23217
+ if (home2) return home2;
23218
+ return segments.flat().some((word) => word.includes("$")) || text2.includes("`") ? text2.match(expansion)[0] : null;
23219
+ }
23024
23220
  function waiting(model, now) {
23025
23221
  return [...model?.approvals?.list() ?? []].filter((approval) => approval.expiresAt > now).sort((a22, b13) => a22.createdAt - b13.createdAt);
23026
23222
  }
@@ -23086,6 +23282,27 @@ var SliccApprovals = class extends ModelElement {
23086
23282
  margin-block-start: var(--swc-spacing-300);
23087
23283
  font-variant-numeric: tabular-nums;
23088
23284
  }
23285
+ .rules {
23286
+ display: flex;
23287
+ align-items: flex-start;
23288
+ gap: var(--swc-spacing-100);
23289
+ margin-block-start: var(--swc-spacing-200);
23290
+ padding: var(--swc-spacing-200) var(--swc-spacing-300);
23291
+ border-radius: var(--swc-corner-radius-medium-default);
23292
+ background: var(--swc-notice-subtle-background-color-default);
23293
+ --swc-icon-color: var(--swc-icon-color-notice);
23294
+ }
23295
+ .rules swc-icon-alert-triangle {
23296
+ flex: none;
23297
+ margin-block-start: 0.15em;
23298
+ }
23299
+ .rules p {
23300
+ margin: 0;
23301
+ }
23302
+ .rules code {
23303
+ font-family: var(--swc-code-font-family-stack);
23304
+ overflow-wrap: anywhere;
23305
+ }
23089
23306
  .problem {
23090
23307
  display: flex;
23091
23308
  align-items: flex-start;
@@ -23140,6 +23357,7 @@ var SliccApprovals = class extends ModelElement {
23140
23357
  async decide(approval, decision) {
23141
23358
  const port = this.model?.approvals;
23142
23359
  if (!port?.decide || this.busy || decision !== "deny" && !this.#armed) return;
23360
+ if (decision === "always" && secretRules(approval)) return;
23143
23361
  this.busy = decision;
23144
23362
  this.failure = null;
23145
23363
  this.#pending.add(approval.id);
@@ -23161,15 +23379,15 @@ var SliccApprovals = class extends ModelElement {
23161
23379
  }
23162
23380
  willUpdate(changed) {
23163
23381
  super.willUpdate(changed);
23164
- const list4 = this.#current();
23382
+ const list5 = this.#current();
23165
23383
  const showing = this.#showing;
23166
23384
  if (showing && this.#pending.has(showing.id)) return;
23167
- if (showing && !this.gone && !this.#done.has(showing.id) && !list4.some((approval) => approval.id === showing.id)) {
23385
+ if (showing && !this.gone && !this.#done.has(showing.id) && !list5.some((approval) => approval.id === showing.id)) {
23168
23386
  const reason = this.#ended.get(showing.id) ?? (showing.expiresAt <= this.now ? "expired" : "answered");
23169
23387
  if (reason !== "withdrawn") this.gone = { approval: showing, reason: gone(reason) };
23170
23388
  }
23171
23389
  if (this.gone) return;
23172
- const next = list4[0] ?? null;
23390
+ const next = list5[0] ?? null;
23173
23391
  if (next?.id === showing?.id) return;
23174
23392
  this.#showing = next;
23175
23393
  clearTimeout(this.#arming);
@@ -23240,10 +23458,12 @@ var SliccApprovals = class extends ModelElement {
23240
23458
  );
23241
23459
  }
23242
23460
  const held = this.#showing && this.#pending.has(this.#showing.id) ? this.#showing : null;
23243
- const list4 = this.#current();
23244
- const [approval, ...rest] = held ? [held, ...list4.filter(({ id }) => id !== held.id)] : list4;
23461
+ const list5 = this.#current();
23462
+ const [approval, ...rest] = held ? [held, ...list5.filter(({ id }) => id !== held.id)] : list5;
23245
23463
  if (!approval) return A;
23246
23464
  const failure2 = this.failure?.id === approval.id ? this.failure.message : "";
23465
+ const rules = secretRules(approval);
23466
+ const always = approval.always && !rules;
23247
23467
  return this.#dialog(
23248
23468
  approval,
23249
23469
  approval.id,
@@ -23251,12 +23471,13 @@ var SliccApprovals = class extends ModelElement {
23251
23471
  <h2 id="title" slot="heading">Allow sudo?</h2>
23252
23472
  ${this.#request(approval)}
23253
23473
  ${approval.cwd ? b`<p class="cwd">In ${approval.cwd}</p>` : A}
23254
- ${approval.always ? b`<p class="hint">Always allow lets ${approval.requester.name} run exactly this command with sudo without asking again.</p>` : A}
23474
+ ${rules ? b`<div class="rules" data-secret-rules=${rules}><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><p>${certain(rules) ? b`<strong>This changes secret rules.</strong> It names <code>${rules}</code>, where SLICC keeps which secrets programs may use and where they may be sent.` : b`<strong>This may change secret rules.</strong> SLICC can't tell where <code>${rules}</code> leads, and it could reach the files where SLICC keeps which secrets programs may use and where they may be sent.`} Allow it only if you asked for this change.</p></div>` : A}
23475
+ ${always ? b`<p class="hint">Always allow lets ${approval.requester.name} run exactly this command with sudo without asking again.</p>` : A}
23255
23476
  ${failure2 ? b`<p class="problem" role="alert" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${failure2}</span></p>` : A}
23256
23477
  <p class="timer" data-timer>Denied automatically in ${countdown(approval.expiresAt - this.now)}.</p>
23257
23478
  ${rest.length ? b`<p class="more" data-more>${rest.length === 1 ? "1 more request is waiting." : `${rest.length} more requests are waiting.`}</p>` : A}
23258
23479
  ${this.#button(approval, "deny", "Deny", "secondary")}
23259
- ${approval.always ? this.#button(approval, "always", "Always allow", "secondary") : A}
23480
+ ${always ? this.#button(approval, "always", "Always allow", "secondary") : A}
23260
23481
  ${this.#button(approval, "once", "Allow once", "accent")}
23261
23482
  </sp-alert-dialog>`
23262
23483
  );
@@ -24168,9 +24389,9 @@ var SliccBrowser = class extends ModelElement {
24168
24389
  if (visible2 && tab && !this.#ticker)
24169
24390
  this.#ticker = setInterval(() => this.requestUpdate(), 1e3);
24170
24391
  if (!(visible2 && tab)) this.#still();
24171
- const list4 = this.renderRoot.querySelector(".actions:not(.last)");
24172
- const count = list4?.childElementCount ?? 0;
24173
- if (list4 && count !== this.#count) list4.scrollTop = list4.scrollHeight;
24392
+ const list5 = this.renderRoot.querySelector(".actions:not(.last)");
24393
+ const count = list5?.childElementCount ?? 0;
24394
+ if (list5 && count !== this.#count) list5.scrollTop = list5.scrollHeight;
24174
24395
  this.#count = count;
24175
24396
  }
24176
24397
  #still() {
@@ -25064,18 +25285,18 @@ function failedTurns(messages, messageId) {
25064
25285
  }
25065
25286
  return ids;
25066
25287
  }
25067
- var touched = false;
25288
+ var touched2 = false;
25068
25289
  document.addEventListener(
25069
25290
  "pointerdown",
25070
25291
  (event2) => {
25071
- touched = event2.pointerType !== "mouse";
25292
+ touched2 = event2.pointerType !== "mouse";
25072
25293
  },
25073
25294
  true
25074
25295
  );
25075
25296
  document.addEventListener(
25076
25297
  "keydown",
25077
25298
  () => {
25078
- touched = false;
25299
+ touched2 = false;
25079
25300
  },
25080
25301
  true
25081
25302
  );
@@ -25251,7 +25472,7 @@ var SliccChat = class extends ThemedElement {
25251
25472
  this.#observe();
25252
25473
  }
25253
25474
  focus() {
25254
- if (!touched && globalThis.matchMedia("(pointer: fine)").matches)
25475
+ if (!touched2 && globalThis.matchMedia("(pointer: fine)").matches)
25255
25476
  this.focusOn("slicc-composer", ".log");
25256
25477
  else this.focusOn(".log");
25257
25478
  }
@@ -26257,7 +26478,7 @@ e25("swc-icon-clock", o84);
26257
26478
  // src/app/composer.ts
26258
26479
  var limit = 25 * 1024 * 1024;
26259
26480
  function available(model) {
26260
- return commands2.filter((command2) => command2.available?.(model) ?? true);
26481
+ return commands2.filter((command3) => command3.available?.(model) ?? true);
26261
26482
  }
26262
26483
  var commands2 = [
26263
26484
  {
@@ -26336,20 +26557,21 @@ function trigger(text2, caret) {
26336
26557
  const argument = before.match(/^\/(\w+)\s+(\S*)$/);
26337
26558
  if (argument)
26338
26559
  return { kind: "argument", start: before.length - argument[2].length, query: argument[2] };
26339
- const command2 = before.match(/^\/([\w:-]*)$/);
26340
- if (command2) return { kind: "command", start: 0, query: command2[1] };
26560
+ const command3 = before.match(/^\/([\w:-]*)$/);
26561
+ if (command3) return { kind: "command", start: 0, query: command3[1] };
26341
26562
  const mention = before.match(/(^|\s)@([\w./-]*)$/);
26342
26563
  if (mention)
26343
26564
  return { kind: "mention", start: before.length - mention[2].length - 1, query: mention[2] };
26344
26565
  return null;
26345
26566
  }
26346
- var SliccComposer = class extends ModelElement {
26567
+ var SliccComposer = class extends ThemedElement {
26347
26568
  static properties = {
26348
- ...ModelElement.properties,
26569
+ ...ThemedElement.properties,
26349
26570
  value: { state: true },
26350
26571
  attachments: { state: true },
26351
26572
  popup: { state: true },
26352
26573
  dictating: { state: true },
26574
+ blocked: { state: true },
26353
26575
  agent: {}
26354
26576
  };
26355
26577
  #drafts = /* @__PURE__ */ new Map();
@@ -26365,6 +26587,7 @@ var SliccComposer = class extends ModelElement {
26365
26587
  this.attachments = [];
26366
26588
  this.popup = null;
26367
26589
  this.dictating = false;
26590
+ this.blocked = false;
26368
26591
  this.agent = "";
26369
26592
  }
26370
26593
  static styles = [
@@ -26403,6 +26626,38 @@ var SliccComposer = class extends ModelElement {
26403
26626
  border: var(--swc-border-width-100) dashed var(--swc-gray-300);
26404
26627
  color: var(--swc-neutral-content-color-default);
26405
26628
  }
26629
+ .hold {
26630
+ display: flex;
26631
+ flex-wrap: wrap;
26632
+ align-items: center;
26633
+ gap: var(--swc-spacing-100);
26634
+ margin: 0 0 var(--swc-spacing-100);
26635
+ padding: var(--swc-spacing-75) var(--swc-spacing-100) var(--swc-spacing-75) var(--swc-spacing-200);
26636
+ border-radius: var(--swc-corner-radius-medium-default);
26637
+ background: var(--swc-informative-subtle-background-color-default);
26638
+ color: var(--swc-neutral-content-color-default);
26639
+ }
26640
+ .hold[data-hold='locked'] {
26641
+ background: var(--swc-notice-subtle-background-color-default);
26642
+ }
26643
+ .hold swc-icon-lock,
26644
+ .hold swc-progress-circle {
26645
+ flex: none;
26646
+ }
26647
+ .hold .text {
26648
+ flex: 1;
26649
+ min-inline-size: 12em;
26650
+ }
26651
+ .hold .blocked {
26652
+ flex-basis: 100%;
26653
+ display: flex;
26654
+ align-items: center;
26655
+ gap: var(--swc-spacing-75);
26656
+ color: var(--swc-negative-content-color-default);
26657
+ }
26658
+ .hold .held {
26659
+ color: var(--swc-neutral-subdued-content-color-default);
26660
+ }
26406
26661
  .queued swc-icon-clock {
26407
26662
  flex: none;
26408
26663
  color: var(--swc-neutral-subdued-content-color-default);
@@ -26597,9 +26852,14 @@ var SliccComposer = class extends ModelElement {
26597
26852
  });
26598
26853
  const update = () => this.requestUpdate();
26599
26854
  return [
26855
+ ...super.subscribe(model),
26600
26856
  model.agent.on("active", (id) => {
26601
26857
  if (!this.agent) this.#switch(id);
26602
26858
  }),
26859
+ model.agent.on("hold", (hold) => {
26860
+ if (hold?.reason !== "locked") this.blocked = false;
26861
+ update();
26862
+ }),
26603
26863
  model.agent.on("agents", update),
26604
26864
  model.agent.on("messages", update),
26605
26865
  model.agent.on("message", update),
@@ -26644,14 +26904,14 @@ var SliccComposer = class extends ModelElement {
26644
26904
  const text2 = this.value.trim();
26645
26905
  const attachments = this.attachments.filter((attachment2) => !attachment2.error);
26646
26906
  if (!model || !text2 && attachments.length === 0 || this.#held()) return;
26647
- const command2 = text2.match(/^\/(\w+)(?:\s+(.*))?$/);
26648
- const known = command2 && available(model).find((candidate) => candidate.name === command2[1]);
26907
+ const command3 = text2.match(/^\/(\w+)(?:\s+(.*))?$/);
26908
+ const known = command3 && available(model).find((candidate) => candidate.name === command3[1]);
26649
26909
  this.value = "";
26650
26910
  this.attachments = [];
26651
26911
  this.popup = null;
26652
26912
  this.#history = -1;
26653
26913
  if (known) {
26654
- known.run(model, this.#agent, (command2[2] ?? "").trim());
26914
+ known.run(model, this.#agent, (command3[2] ?? "").trim());
26655
26915
  return;
26656
26916
  }
26657
26917
  const busy = this.#busy();
@@ -26739,22 +26999,22 @@ var SliccComposer = class extends ModelElement {
26739
26999
  const model = this.model;
26740
27000
  if (kind === "command") {
26741
27001
  const usable = available(model);
26742
- const builtins = usable.map((command2) => ({
26743
- value: command2.name,
26744
- label: `/${command2.name}`,
26745
- detail: command2.detail
27002
+ const builtins = usable.map((command3) => ({
27003
+ value: command3.name,
27004
+ label: `/${command3.name}`,
27005
+ detail: command3.detail
26746
27006
  }));
26747
- const own4 = model.agent.commands(this.#agent).filter((command2) => !usable.some((builtin) => builtin.name === command2.name)).map((command2) => ({
26748
- value: command2.name,
26749
- label: `/${command2.name}`,
26750
- detail: command2.description,
26751
- group: command2.kind === "skill" ? "Skills" : "Prompts"
27007
+ const own4 = model.agent.commands(this.#agent).filter((command3) => !usable.some((builtin) => builtin.name === command3.name)).map((command3) => ({
27008
+ value: command3.name,
27009
+ label: `/${command3.name}`,
27010
+ detail: command3.description,
27011
+ group: command3.kind === "skill" ? "Skills" : "Prompts"
26752
27012
  })).sort((a22, b13) => a22.group === b13.group ? 0 : a22.group === "Prompts" ? -1 : 1);
26753
27013
  return filter([...builtins, ...own4], query, Number.POSITIVE_INFINITY);
26754
27014
  }
26755
27015
  if (kind === "argument") {
26756
27016
  const name = this.value.match(/^\/(\w+)/)?.[1];
26757
- return filter(commands2.find((command2) => command2.name === name)?.args?.(model) ?? [], query);
27017
+ return filter(commands2.find((command3) => command3.name === name)?.args?.(model) ?? [], query);
26758
27018
  }
26759
27019
  const files = this.#paths.map((path) => ({
26760
27020
  value: path,
@@ -26774,7 +27034,7 @@ var SliccComposer = class extends ModelElement {
26774
27034
  if (this.popup?.kind === "file" || this.popup?.kind === "secret") return;
26775
27035
  const found = trigger(this.value, area.selectionStart ?? this.value.length);
26776
27036
  const name = this.value.match(/^\/(\w+)/)?.[1];
26777
- const takes = commands2.some((command2) => command2.name === name && command2.args);
27037
+ const takes = commands2.some((command3) => command3.name === name && command3.args);
26778
27038
  this.popup = found && (found.kind !== "argument" || takes) ? { ...found, items: this.#choices(found.kind, found.query), index: 0 } : null;
26779
27039
  }
26780
27040
  openPopup(kind) {
@@ -26985,6 +27245,26 @@ var SliccComposer = class extends ModelElement {
26985
27245
  ) : b`<div class="empty">Nothing matches.</div>`}
26986
27246
  </div>`;
26987
27247
  }
27248
+ #hold() {
27249
+ const hold = this.model?.agent.hold?.();
27250
+ if (!hold) return A;
27251
+ const locked = hold.reason === "locked";
27252
+ const vault = this.model?.vault;
27253
+ const held = hold.held === 1 ? "1 tool result held" : `${hold.held} tool results held`;
27254
+ return b`<div class="hold" role="status" data-hold=${hold.reason}>
27255
+ ${locked ? b`<swc-icon-lock size="s" aria-hidden="true"></swc-icon-lock>` : b`<swc-progress-circle size="s" label="Waiting" aria-hidden="true"></swc-progress-circle>`}
27256
+ <span class="text">${locked ? "Unlock the vault to continue" : "Waiting for the vault"}${hold.held ? b`<span class="held"> · ${held}</span>` : A}</span>
27257
+ ${locked && vault ? b`<slicc-vault-button
27258
+ data-action="unlock-vault"
27259
+ .vault=${vault}
27260
+ .config=${{ intent: { kind: "unlock" }, label: "Unlock", size: "s", variant: "accent", theme: this.color }}
27261
+ @vault-popup=${(event2) => {
27262
+ this.blocked = event2.detail.state === "blocked";
27263
+ }}
27264
+ ></slicc-vault-button>` : A}
27265
+ ${locked && this.blocked ? b`<span class="blocked" role="alert" data-popup="blocked"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle>The browser blocked the vault window. Allow pop-ups for this site, then try again.</span>` : A}
27266
+ </div>`;
27267
+ }
26988
27268
  #queue() {
26989
27269
  const queued = this.model?.agent.queue(this.#agent) ?? [];
26990
27270
  if (queued.length === 0) return A;
@@ -27015,6 +27295,7 @@ var SliccComposer = class extends ModelElement {
27015
27295
  const speech = "SpeechRecognition" in globalThis || "webkitSpeechRecognition" in globalThis;
27016
27296
  const held = this.#held();
27017
27297
  return b`<div class="column">
27298
+ ${this.#hold()}
27018
27299
  ${this.#queue()}
27019
27300
  ${this.#popup()}
27020
27301
  <swc-prompt-field
@@ -27368,8 +27649,8 @@ var SliccMemory = class extends ModelElement {
27368
27649
  const scopes = this.#scopes;
27369
27650
  const scope = this.scope;
27370
27651
  const option2 = (item2) => b`<sp-menu-item value=${item2.id}>${item2.label}</sp-menu-item>`;
27371
- const shown2 = visible(all2, scope, this.tag, this.query);
27372
- return b`<div class="bar"><span>${shown2.length} of ${all2.filter((memory) => memory.scope === scope).length} memories</span><span class="spacer"></span>
27652
+ const shown3 = visible(all2, scope, this.tag, this.query);
27653
+ return b`<div class="bar"><span>${shown3.length} of ${all2.filter((memory) => memory.scope === scope).length} memories</span><span class="spacer"></span>
27373
27654
  <swc-action-button size="s" quiet @click=${() => this.editing = "new"}><swc-icon-add slot="icon"></swc-icon-add>Remember</swc-action-button>
27374
27655
  </div>
27375
27656
  <div class="tools">
@@ -27391,7 +27672,7 @@ var SliccMemory = class extends ModelElement {
27391
27672
  </div>
27392
27673
  <div class="list">
27393
27674
  ${this.editing === "new" ? b`<div class="row">${this.#form({ scope })}</div>` : A}
27394
- ${shown2.length ? sections(shown2).map(
27675
+ ${shown3.length ? sections(shown3).map(
27395
27676
  ([section, items]) => b`<h3>${section}</h3>${items.map((memory) => this.#row(memory))}`
27396
27677
  ) : b`<div class="note">${all2.length ? "No memories match." : "No memories yet."}</div>`}
27397
27678
  </div>`;
@@ -27699,10 +27980,10 @@ var SliccMonitor = class extends ModelElement {
27699
27980
  const surface2 = surfaces2[section.id];
27700
27981
  const rows = section.rows.length > 0;
27701
27982
  const open = rows && (this.expanded[section.id] ?? flag !== null);
27702
- const list4 = `rows-${section.id}`;
27983
+ const list5 = `rows-${section.id}`;
27703
27984
  return b`<li class="section" data-id=${section.id} data-open=${open ? "" : A}>
27704
27985
  <div class="line">
27705
- ${rows ? b`<button class="toggle" aria-expanded=${open ? "true" : "false"} aria-controls=${open ? list4 : A} @click=${() => {
27986
+ ${rows ? b`<button class="toggle" aria-expanded=${open ? "true" : "false"} aria-controls=${open ? list5 : A} @click=${() => {
27706
27987
  this.expanded = { ...this.expanded, [section.id]: !open };
27707
27988
  }}><span class="chevron"><swc-icon-chevron-right size="s" aria-hidden="true"></swc-icon-chevron-right></span><span class="name">${section.label}</span></button>` : b`<span class="chevron"></span><span class="name">${section.label}</span>`}
27708
27989
  ${flag ? b`<swc-badge size="s" variant=${flag.variant} subtle>${flag.text}</swc-badge>` : A}
@@ -27711,7 +27992,7 @@ var SliccMonitor = class extends ModelElement {
27711
27992
  >Open</swc-action-button
27712
27993
  >` : A}
27713
27994
  </div>
27714
- ${open ? b`<ul class="rows" id=${list4} aria-label=${section.label}>${c(
27995
+ ${open ? b`<ul class="rows" id=${list5} aria-label=${section.label}>${c(
27715
27996
  section.rows,
27716
27997
  (row, i25) => row.id ?? i25,
27717
27998
  (row) => this.#row(row)
@@ -27918,6 +28199,748 @@ var SliccNotices = class extends ModelElement {
27918
28199
  }
27919
28200
  };
27920
28201
 
28202
+ // src/app/vault.ts
28203
+ var exitNames = {
28204
+ "vault-direct": "Straight from the vault",
28205
+ "local-proxy": "Local proxy",
28206
+ "cli-v": "Local SLICC, direct",
28207
+ tailscale: "Tailscale",
28208
+ "local-link": "Linked SLICC, through this page"
28209
+ };
28210
+ function devicesOf(model) {
28211
+ return model?.network?.status().links?.devices ?? [];
28212
+ }
28213
+ function deviceName2(id, devices) {
28214
+ return (devices.find((device) => device.id === id)?.name ?? id).replace(/^slicc\b/i, "SLICC");
28215
+ }
28216
+ function exitLabel(exit, devices) {
28217
+ if (exit.startsWith("device:")) return deviceName2(exit.slice("device:".length), devices);
28218
+ return exitNames[exit];
28219
+ }
28220
+ function list4(items) {
28221
+ if (items.length < 2) return items.join("");
28222
+ return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
28223
+ }
28224
+ function ruleLine(rule) {
28225
+ const methods = rule.methods.length ? rule.methods.join(" or ") : "any method";
28226
+ const paths = rule.paths.length ? rule.paths.join(" or ") : "any path";
28227
+ return `${rule.domain}, in ${rule.header}, ${methods}, ${paths}`;
28228
+ }
28229
+ function shellWord(word) {
28230
+ return /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replace(/'/g, "'\\''")}'`;
28231
+ }
28232
+ function execLine(grant) {
28233
+ if (grant === false) return "Never revealed to programs";
28234
+ if (grant === true) return "Revealed to any program that asks";
28235
+ return `Revealed only to ${list4(grant.argv.map((argv) => argv.map(shellWord).join(" ")))}`;
28236
+ }
28237
+ function widening(change, devices) {
28238
+ switch (change.kind) {
28239
+ case "rule":
28240
+ return `${change.secret} may now be sent to ${ruleLine(change.rule)}`;
28241
+ case "methods":
28242
+ return `${change.secret} may now use ${list4(change.methods)} on ${change.domain}`;
28243
+ case "paths":
28244
+ return `${change.secret} may now reach ${list4(change.paths)} on ${change.domain}`;
28245
+ case "exec": {
28246
+ const line = execLine(change.grant);
28247
+ return `${change.secret}: ${line[0].toLowerCase()}${line.slice(1)}`;
28248
+ }
28249
+ case "exit":
28250
+ return `${change.secret} may now leave through ${exitLabel(change.exit, devices)}`;
28251
+ default:
28252
+ return `The limit ${change.field} rose from ${change.from} to ${change.to}`;
28253
+ }
28254
+ }
28255
+ function shown2(element2, style = getComputedStyle(element2)) {
28256
+ return !element2.hidden && !element2.inert && style.display !== "none";
28257
+ }
28258
+ function disabled(element2) {
28259
+ if (element2.matches(":disabled")) return true;
28260
+ if (!element2.matches("button, input, select, textarea")) return false;
28261
+ let fieldset = element2.closest("fieldset[disabled]");
28262
+ while (fieldset) {
28263
+ if (!fieldset.querySelector(":scope > legend")?.contains(element2)) return true;
28264
+ fieldset = fieldset.parentElement?.closest("fieldset[disabled]") ?? null;
28265
+ }
28266
+ return false;
28267
+ }
28268
+ function reachable(element2) {
28269
+ const radio = element2;
28270
+ if (radio.localName !== "input" || radio.type !== "radio" || !radio.name) return true;
28271
+ const root2 = radio.getRootNode();
28272
+ const group = Array.from(root2.querySelectorAll("input[type=radio]")).filter(
28273
+ (other) => other.name === radio.name && other.form === radio.form
28274
+ );
28275
+ const checked = group.find((other) => other.checked);
28276
+ return checked ? checked === radio : radio === group[0] || radio === group.at(-1);
28277
+ }
28278
+ function tabbables(root2, stop, out = []) {
28279
+ for (const child of Array.from(root2.children)) {
28280
+ if (child === stop) {
28281
+ out.push(null);
28282
+ continue;
28283
+ }
28284
+ const style = getComputedStyle(child);
28285
+ if (!shown2(child, style)) continue;
28286
+ if (child.localName === "details" && !child.open) {
28287
+ const summary = child.querySelector(":scope > summary");
28288
+ if (summary && shown2(summary) && getComputedStyle(summary).visibility !== "hidden" && !(summary.hasAttribute("tabindex") && summary.tabIndex < 0))
28289
+ out.push(summary);
28290
+ continue;
28291
+ }
28292
+ if (child.tabIndex >= 0 && !disabled(child) && style.visibility !== "hidden" && reachable(child))
28293
+ out.push(child);
28294
+ if (child.shadowRoot) tabbables(child.shadowRoot, stop, out);
28295
+ tabbables(child, stop, out);
28296
+ }
28297
+ return out;
28298
+ }
28299
+ function sequential(order) {
28300
+ const rank = (element2) => element2 && element2.tabIndex > 0 ? element2.tabIndex : Number.POSITIVE_INFINITY;
28301
+ return [...order].sort((a22, b13) => rank(a22) - rank(b13) || 0);
28302
+ }
28303
+ var SliccVaultButton = class extends i2 {
28304
+ static properties = {
28305
+ vault: { attribute: false },
28306
+ config: { attribute: false }
28307
+ };
28308
+ #button = null;
28309
+ #off = null;
28310
+ #ready = false;
28311
+ #sent = "";
28312
+ static styles = i`
28313
+ :host {
28314
+ display: inline-flex;
28315
+ vertical-align: middle;
28316
+ }
28317
+ iframe {
28318
+ border: 0;
28319
+ background: transparent;
28320
+ color-scheme: normal;
28321
+ }
28322
+ `;
28323
+ constructor() {
28324
+ super();
28325
+ this.vault = null;
28326
+ this.config = null;
28327
+ }
28328
+ connectedCallback() {
28329
+ super.connectedCallback();
28330
+ this.requestUpdate();
28331
+ }
28332
+ disconnectedCallback() {
28333
+ super.disconnectedCallback();
28334
+ this.#drop();
28335
+ }
28336
+ focus() {
28337
+ this.#button?.post({ type: "slicc-vault", v: 1, op: "focus" });
28338
+ }
28339
+ updated(changed) {
28340
+ if (changed.has("vault")) this.#drop();
28341
+ if (!this.#button && this.vault) this.#mount(this.vault);
28342
+ this.#send();
28343
+ }
28344
+ #mount(vault) {
28345
+ const button = vault.button();
28346
+ this.#button = button;
28347
+ this.#off = button.listen((event2) => this.#event(event2));
28348
+ this.renderRoot.append(button.element);
28349
+ }
28350
+ #drop() {
28351
+ this.#off?.();
28352
+ this.#button?.element.remove();
28353
+ this.#button = null;
28354
+ this.#off = null;
28355
+ this.#ready = false;
28356
+ this.#sent = "";
28357
+ }
28358
+ #send() {
28359
+ if (!(this.#ready && this.#button && this.config)) return;
28360
+ const sent = JSON.stringify(this.config);
28361
+ if (sent === this.#sent) return;
28362
+ this.#sent = sent;
28363
+ this.#button.post({ type: "slicc-vault", v: 1, op: "button", button: this.config });
28364
+ }
28365
+ #event(event2) {
28366
+ const element2 = this.#button?.element;
28367
+ if (event2.event === "ready") {
28368
+ this.#ready = true;
28369
+ this.#send();
28370
+ } else if (event2.event === "size") {
28371
+ element2.style.width = `${event2.width}px`;
28372
+ element2.style.height = `${event2.height}px`;
28373
+ element2.style.margin = `${-event2.inset}px`;
28374
+ } else if (event2.event === "label") {
28375
+ element2.title = event2.label;
28376
+ } else if (event2.event === "focus") {
28377
+ const order = sequential(tabbables(this.ownerDocument, this));
28378
+ const at = order.indexOf(null);
28379
+ order[event2.direction === "next" ? at + 1 : at - 1]?.focus();
28380
+ } else if (event2.event === "popup") {
28381
+ const { intent, state: state3, result } = event2;
28382
+ this.dispatchEvent(
28383
+ new CustomEvent("vault-popup", {
28384
+ detail: { intent, state: state3, ...result ? { result } : {} },
28385
+ bubbles: true,
28386
+ composed: true
28387
+ })
28388
+ );
28389
+ }
28390
+ }
28391
+ };
28392
+
28393
+ // src/app/secrets.ts
28394
+ var kinds = { secret: null, grant: "Sign-in", model: "Model key", mcp: "MCP server" };
28395
+ var lockModes = {
28396
+ auto: "Unlocks with this browser",
28397
+ passkey: "Unlocks with a passkey",
28398
+ passphrase: "Unlocks with a passphrase"
28399
+ };
28400
+ function until(at, now = Date.now()) {
28401
+ const minutes = Math.ceil((at - now) / 6e4);
28402
+ if (minutes <= 0) return "expired";
28403
+ if (minutes < 60) return `in ${minutes} min`;
28404
+ const hours = Math.round(minutes / 60);
28405
+ if (hours < 24) return `in ${hours} h`;
28406
+ const days = Math.round(hours / 24);
28407
+ return `in ${days} ${days === 1 ? "day" : "days"}`;
28408
+ }
28409
+ function who(entry) {
28410
+ if (entry.tag) return entry.tag;
28411
+ if (entry.uid === null) return "the vault";
28412
+ return entry.uid === 0 ? "root" : `uid ${entry.uid}`;
28413
+ }
28414
+ function sourceLine(secret, devices) {
28415
+ const on = secret.sourceDevice ? ` on ${deviceName2(secret.sourceDevice, devices)}` : "";
28416
+ const [kind, detail = ""] = secret.source.split(/:(.*)/s);
28417
+ if (kind === "popup") return `Entered in the vault${on}`;
28418
+ if (kind === "process") return `Saved by a program${on}`;
28419
+ if (kind === "import") return `Imported from ${detail}`;
28420
+ if (kind === "oauth") {
28421
+ const as = secret.account ? ` as ${secret.account}` : "";
28422
+ return `Signed in to ${secret.provider ?? detail}${as}`;
28423
+ }
28424
+ return `A jerk lease for ${detail.split("@")[0]}${on}`;
28425
+ }
28426
+ function startOfDay(now) {
28427
+ const date = new Date(now);
28428
+ date.setHours(0, 0, 0, 0);
28429
+ return date.getTime();
28430
+ }
28431
+ function revealed(name, entries, now = Date.now(), more = false) {
28432
+ const reveals = entries.filter(
28433
+ (entry) => entry.type === "materialize" && entry.name === name
28434
+ );
28435
+ if (!reveals.length) return null;
28436
+ const [last] = reveals;
28437
+ const start = startOfDay(now);
28438
+ const today = reveals.filter((entry) => entry.at >= start).length;
28439
+ const partial = more && (entries[entries.length - 1]?.at ?? 0) >= start;
28440
+ const when = today ? `${partial ? "at least " : ""}${today} ${today === 1 ? "time" : "times"} today` : since(last.at, now);
28441
+ return b`Revealed to programs ${when}, last by ${who(last)} with <code>${last.argv}</code>`;
28442
+ }
28443
+ function auditLine(entry, devices) {
28444
+ switch (entry.type) {
28445
+ case "inject":
28446
+ case "forward":
28447
+ return b`${entry.type === "inject" ? "Sent to" : "Forwarded to"} ${entry.domain}: <code>${entry.method} ${entry.path}</code>, through ${exitLabel(entry.exit, devices)}`;
28448
+ case "materialize":
28449
+ return b`Revealed to <code>${entry.argv}</code> in <code>${entry.cwd}</code>`;
28450
+ case "seal":
28451
+ return b`${entry.rotated ? "Value replaced" : "Value saved"}`;
28452
+ case "remove":
28453
+ return b`Removed`;
28454
+ case "restore":
28455
+ return b`Restored`;
28456
+ default: {
28457
+ const count = entry.widened.length;
28458
+ const widened = count ? `, widening ${count} ${count === 1 ? "rule" : "rules"}` : "";
28459
+ return b`<code>${entry.file}</code> ${entry.accepted ? `changed${widened}` : "changed and was refused"}${entry.warning ? b`. ${entry.warning}` : A}`;
28460
+ }
28461
+ }
28462
+ }
28463
+ function merged(...pages) {
28464
+ const bySeq = /* @__PURE__ */ new Map();
28465
+ for (const page of pages) for (const entry of page) bySeq.set(entry.seq, entry);
28466
+ return [...bySeq.values()].sort((a22, b13) => b13.seq - a22.seq);
28467
+ }
28468
+ function prompt2(text2) {
28469
+ return text2.length > 200 ? `${text2.slice(0, 199)}\u2026` : text2;
28470
+ }
28471
+ var SliccSecrets = class extends ThemedElement {
28472
+ static properties = {
28473
+ ...ThemedElement.properties,
28474
+ older: { state: true },
28475
+ more: { state: true },
28476
+ loading: { state: true },
28477
+ reveals: { state: true },
28478
+ popup: { state: true },
28479
+ acking: { state: true },
28480
+ failure: { state: true }
28481
+ };
28482
+ #tick;
28483
+ constructor() {
28484
+ super();
28485
+ this.older = [];
28486
+ this.more = null;
28487
+ this.loading = false;
28488
+ this.reveals = false;
28489
+ this.popup = null;
28490
+ this.acking = /* @__PURE__ */ new Set();
28491
+ this.failure = null;
28492
+ }
28493
+ static styles = i`
28494
+ :host {
28495
+ display: block;
28496
+ container-type: inline-size;
28497
+ }
28498
+ h2 {
28499
+ font-size: var(--swc-heading-size-xs);
28500
+ font-weight: var(--swc-bold-font-weight);
28501
+ line-height: var(--swc-heading-line-height);
28502
+ color: var(--swc-heading-color);
28503
+ margin: 0;
28504
+ }
28505
+ h3 {
28506
+ font-size: var(--swc-font-size-100);
28507
+ font-weight: var(--swc-bold-font-weight);
28508
+ color: var(--swc-heading-color);
28509
+ margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
28510
+ }
28511
+ p {
28512
+ margin: var(--swc-spacing-100) 0;
28513
+ }
28514
+ ul,
28515
+ ol {
28516
+ list-style: none;
28517
+ margin: 0;
28518
+ padding: 0;
28519
+ }
28520
+ code {
28521
+ font-family: var(--swc-code-font-family, ui-monospace, monospace);
28522
+ font-size: 0.9em;
28523
+ overflow-wrap: anywhere;
28524
+ }
28525
+ .head {
28526
+ display: flex;
28527
+ flex-wrap: wrap;
28528
+ align-items: baseline;
28529
+ gap: var(--swc-spacing-200) var(--swc-spacing-300);
28530
+ margin: var(--swc-spacing-500) 0 var(--swc-spacing-200);
28531
+ }
28532
+ .head slicc-vault-button {
28533
+ align-self: center;
28534
+ margin-inline-start: auto;
28535
+ }
28536
+ .muted {
28537
+ color: var(--swc-neutral-subdued-content-color-default);
28538
+ }
28539
+ .box {
28540
+ display: grid;
28541
+ gap: var(--swc-spacing-100);
28542
+ padding: var(--swc-spacing-200) var(--swc-spacing-300);
28543
+ margin: var(--swc-spacing-200) 0;
28544
+ border-radius: var(--swc-corner-radius-100);
28545
+ border: var(--swc-border-width-100) solid var(--swc-gray-200);
28546
+ background: var(--swc-background-layer-1-color);
28547
+ }
28548
+ .box.notice {
28549
+ border-color: var(--swc-notice-visual-color);
28550
+ --swc-icon-color: var(--swc-notice-visual-color);
28551
+ }
28552
+ .box .title {
28553
+ display: flex;
28554
+ align-items: flex-start;
28555
+ gap: var(--swc-spacing-100);
28556
+ font-weight: var(--swc-bold-font-weight);
28557
+ }
28558
+ .box ul {
28559
+ list-style: disc;
28560
+ padding-inline-start: var(--swc-spacing-400);
28561
+ }
28562
+ .box .actions {
28563
+ display: flex;
28564
+ flex-wrap: wrap;
28565
+ align-items: center;
28566
+ gap: var(--swc-spacing-200);
28567
+ }
28568
+ .prompt {
28569
+ margin: 0;
28570
+ padding-inline-start: var(--swc-spacing-200);
28571
+ border-inline-start: var(--swc-border-width-200) solid var(--swc-gray-300);
28572
+ overflow-wrap: anywhere;
28573
+ }
28574
+ .said {
28575
+ white-space: pre-wrap;
28576
+ }
28577
+ .from {
28578
+ display: block;
28579
+ font-size: var(--swc-font-size-75);
28580
+ color: var(--swc-neutral-subdued-content-color-default);
28581
+ }
28582
+ .secrets {
28583
+ display: grid;
28584
+ gap: var(--swc-spacing-200);
28585
+ }
28586
+ .secret {
28587
+ display: grid;
28588
+ grid-template-columns: minmax(0, 1fr) max-content;
28589
+ gap: var(--swc-spacing-100) var(--swc-spacing-300);
28590
+ padding: var(--swc-spacing-200) 0;
28591
+ border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
28592
+ }
28593
+ .secret:first-child {
28594
+ border-top: 0;
28595
+ }
28596
+ .name {
28597
+ display: flex;
28598
+ flex-wrap: wrap;
28599
+ align-items: baseline;
28600
+ gap: var(--swc-spacing-100) var(--swc-spacing-200);
28601
+ min-width: 0;
28602
+ }
28603
+ .name code {
28604
+ font-size: var(--swc-font-size-100);
28605
+ font-weight: var(--swc-bold-font-weight);
28606
+ }
28607
+ .secret slicc-vault-button {
28608
+ align-self: start;
28609
+ }
28610
+ .removed {
28611
+ margin-top: var(--swc-spacing-200);
28612
+ border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
28613
+ padding-top: var(--swc-spacing-200);
28614
+ }
28615
+ .removed summary {
28616
+ cursor: pointer;
28617
+ font-size: var(--swc-font-size-75);
28618
+ color: var(--swc-neutral-subdued-content-color-default);
28619
+ }
28620
+ .removed .secret dl,
28621
+ .removed .secret .name code {
28622
+ color: var(--swc-neutral-subdued-content-color-default);
28623
+ }
28624
+ dl {
28625
+ grid-column: 1 / -1;
28626
+ display: grid;
28627
+ grid-template-columns: max-content minmax(0, 1fr);
28628
+ gap: var(--swc-spacing-50) var(--swc-spacing-300);
28629
+ margin: 0;
28630
+ font-size: var(--swc-font-size-75);
28631
+ line-height: var(--swc-line-height-200);
28632
+ }
28633
+ dt {
28634
+ color: var(--swc-neutral-subdued-content-color-default);
28635
+ }
28636
+ dd {
28637
+ margin: 0;
28638
+ min-width: 0;
28639
+ overflow-wrap: anywhere;
28640
+ }
28641
+ .audit-head {
28642
+ display: flex;
28643
+ flex-wrap: wrap;
28644
+ align-items: baseline;
28645
+ justify-content: space-between;
28646
+ gap: var(--swc-spacing-200);
28647
+ margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
28648
+ }
28649
+ .audit-head h3 {
28650
+ margin-block: 0;
28651
+ }
28652
+ .audit li {
28653
+ display: grid;
28654
+ grid-template-columns: 7em minmax(0, 1fr);
28655
+ gap: var(--swc-spacing-50) var(--swc-spacing-300);
28656
+ padding: var(--swc-spacing-100) 0;
28657
+ border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
28658
+ font-size: var(--swc-font-size-75);
28659
+ line-height: var(--swc-line-height-200);
28660
+ }
28661
+ .audit time {
28662
+ color: var(--swc-neutral-subdued-content-color-default);
28663
+ }
28664
+ .audit .what {
28665
+ overflow-wrap: anywhere;
28666
+ }
28667
+ .audit .by {
28668
+ color: var(--swc-neutral-subdued-content-color-default);
28669
+ }
28670
+ .row {
28671
+ display: flex;
28672
+ flex-wrap: wrap;
28673
+ align-items: center;
28674
+ gap: var(--swc-spacing-200);
28675
+ margin-top: var(--swc-spacing-200);
28676
+ }
28677
+ .error {
28678
+ display: flex;
28679
+ align-items: flex-start;
28680
+ gap: var(--swc-spacing-100);
28681
+ color: var(--swc-negative-content-color-default);
28682
+ font-size: var(--swc-font-size-75);
28683
+ --swc-icon-color: var(--swc-negative-content-color-default);
28684
+ }
28685
+ @container (max-width: 480px) {
28686
+ .secret {
28687
+ grid-template-columns: minmax(0, 1fr);
28688
+ }
28689
+ .secret slicc-vault-button {
28690
+ order: 1;
28691
+ justify-self: start;
28692
+ }
28693
+ dl {
28694
+ grid-template-columns: minmax(0, 1fr);
28695
+ }
28696
+ dd {
28697
+ margin-bottom: var(--swc-spacing-75);
28698
+ }
28699
+ .audit li {
28700
+ grid-template-columns: minmax(0, 1fr);
28701
+ }
28702
+ }
28703
+ `;
28704
+ #pushed = [];
28705
+ disconnectedCallback() {
28706
+ super.disconnectedCallback();
28707
+ clearTimeout(this.#tick);
28708
+ this.older = [];
28709
+ this.more = null;
28710
+ this.#pushed = [];
28711
+ }
28712
+ willUpdate(changed) {
28713
+ super.willUpdate(changed);
28714
+ const before = changed.get("model");
28715
+ if (!changed.has("model") || before?.vault === this.model?.vault) return;
28716
+ this.older = [];
28717
+ this.more = null;
28718
+ this.loading = false;
28719
+ this.popup = null;
28720
+ this.acking = /* @__PURE__ */ new Set();
28721
+ this.failure = null;
28722
+ this.#pushed = [];
28723
+ }
28724
+ updated() {
28725
+ clearTimeout(this.#tick);
28726
+ if (!this.isConnected) return;
28727
+ const now = Date.now();
28728
+ const next = Math.min(
28729
+ now + 6e4,
28730
+ ...(this.model?.vault?.list()?.secrets ?? []).map((secret) => secret.expiresAt ?? Number.POSITIVE_INFINITY).filter((at) => at > now)
28731
+ );
28732
+ this.#tick = setTimeout(() => this.requestUpdate(), next - now);
28733
+ }
28734
+ #listed(vault) {
28735
+ this.#pushed = [];
28736
+ const head2 = vault.list()?.audit ?? [];
28737
+ const last = head2[head2.length - 1];
28738
+ if (this.older.length && (!last || last.seq > this.older[0].seq + 1)) {
28739
+ this.older = [];
28740
+ this.more = null;
28741
+ }
28742
+ this.requestUpdate();
28743
+ }
28744
+ #noticed(notice) {
28745
+ this.#pushed = [...this.#pushed.filter((item2) => item2.id !== notice.id), notice];
28746
+ this.requestUpdate();
28747
+ }
28748
+ subscribe(model) {
28749
+ const update = () => this.requestUpdate();
28750
+ return [
28751
+ ...super.subscribe(model),
28752
+ ...model.vault ? [
28753
+ model.vault.on("status", update),
28754
+ model.vault.on("list", () => this.#listed(model.vault)),
28755
+ model.vault.on("notice", (notice) => this.#noticed(notice))
28756
+ ] : [],
28757
+ ...model.network ? [model.network.on("network", update)] : []
28758
+ ];
28759
+ }
28760
+ #button(config) {
28761
+ const theme3 = this.color;
28762
+ return b`<slicc-vault-button
28763
+ .vault=${this.model?.vault}
28764
+ .config=${{ size: "m", variant: "secondary", ...config, theme: theme3 }}
28765
+ @vault-popup=${(event2) => this.#popup(event2.detail)}
28766
+ ></slicc-vault-button>`;
28767
+ }
28768
+ #popup(detail) {
28769
+ this.popup = detail;
28770
+ }
28771
+ async showOlder(vault, entries) {
28772
+ this.loading = true;
28773
+ this.failure = null;
28774
+ try {
28775
+ const before = entries[entries.length - 1]?.seq;
28776
+ const page = await vault.audit(before);
28777
+ if (this.model?.vault !== vault || !this.isConnected) return;
28778
+ const shown3 = merged(vault.list()?.audit ?? [], this.older);
28779
+ if (shown3[shown3.length - 1]?.seq !== before) return;
28780
+ this.older = merged(this.older, page.audit);
28781
+ this.more = page.more;
28782
+ } catch (error) {
28783
+ if (this.model?.vault === vault && this.isConnected) this.failure = error.message;
28784
+ } finally {
28785
+ if (this.model?.vault === vault) this.loading = false;
28786
+ }
28787
+ }
28788
+ async acknowledge(vault, notice) {
28789
+ if (this.acking.has(notice.id)) return;
28790
+ this.acking = /* @__PURE__ */ new Set([...this.acking, notice.id]);
28791
+ this.failure = null;
28792
+ try {
28793
+ await vault.acknowledge(notice.id);
28794
+ if (this.model?.vault === vault)
28795
+ this.#pushed = this.#pushed.filter((item2) => item2.id !== notice.id);
28796
+ } catch (error) {
28797
+ if (this.model?.vault === vault && this.isConnected) this.failure = error.message;
28798
+ } finally {
28799
+ if (this.model?.vault === vault)
28800
+ this.acking = new Set([...this.acking].filter((id) => id !== notice.id));
28801
+ }
28802
+ }
28803
+ #request(request2) {
28804
+ const asker = who(request2);
28805
+ const what = request2.kind === "value" ? b`${asker} asks for <code>${request2.name}</code>` : request2.kind === "oauth" ? b`${asker} asks you to sign in to ${request2.provider}` : b`${asker} asks for a jerk lease for ${request2.provider}`;
28806
+ return b`<div class="box" data-request=${request2.id}>
28807
+ <span class="title">${what}</span>
28808
+ ${request2.prompt ? b`<p class="prompt" data-prompt><span class="from">From the agent, not checked by SLICC:</span> <span class="said">${prompt2(request2.prompt)}</span></p>` : A}
28809
+ <div class="actions">
28810
+ ${this.#button({ intent: { kind: "request", request: request2.id }, label: "Answer in the vault", variant: "accent" })}
28811
+ <span class="muted">Expires ${until(request2.expiresAt)}</span>
28812
+ </div>
28813
+ </div>`;
28814
+ }
28815
+ #notice(vault, notice, devices) {
28816
+ return b`<div class="box notice" role="alert" data-notice=${notice.id}>
28817
+ <span class="title"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>Rules widened in <code>${notice.file}</code> ${since(notice.at)}</span></span>
28818
+ <ul>${notice.widened.map((change) => b`<li>${widening(change, devices)}</li>`)}</ul>
28819
+ <span>If you didn’t mean this, change the file back with sudo.</span>
28820
+ <div class="actions"><swc-button size="s" variant="secondary" data-action="acknowledge" ?pending=${this.acking.has(notice.id)} @click=${() => this.acknowledge(vault, notice)}>Acknowledge</swc-button></div>
28821
+ </div>`;
28822
+ }
28823
+ #state(secret) {
28824
+ const [variant, label] = secret.state === "removed" ? ["neutral", "Removed"] : secret.expiresAt !== void 0 && secret.expiresAt <= Date.now() ? ["notice", "Expired"] : secret.state === "inert" ? ["neutral", "No rule yet"] : ["positive", "Active"];
28825
+ return b`<swc-status-light size="s" variant=${variant}>${label}</swc-status-light>`;
28826
+ }
28827
+ #action(secret) {
28828
+ if (secret.state === "removed")
28829
+ return this.#button({
28830
+ intent: { kind: "manage", name: secret.name },
28831
+ label: "Manage",
28832
+ size: "s"
28833
+ });
28834
+ if (secret.source.startsWith("oauth:"))
28835
+ return this.#button({
28836
+ intent: { kind: "signin", provider: secret.source.slice("oauth:".length) },
28837
+ label: "Sign in again",
28838
+ size: "s"
28839
+ });
28840
+ return this.#button({
28841
+ intent: { kind: "enter", name: secret.name },
28842
+ label: "Replace value",
28843
+ size: "s"
28844
+ });
28845
+ }
28846
+ #secret(secret, entries, devices, more) {
28847
+ const kind = kinds[secret.kind];
28848
+ const reveal = revealed(secret.name, entries, Date.now(), more);
28849
+ const gone2 = secret.state === "removed";
28850
+ return b`<li class="secret" data-secret=${secret.name} data-state=${secret.state}>
28851
+ <div class="name">
28852
+ <code>${secret.name}</code>
28853
+ ${kind ? b`<swc-badge size="s" variant="neutral" subtle>${kind}</swc-badge>` : A}
28854
+ ${this.#state(secret)}
28855
+ </div>
28856
+ ${this.#action(secret)}
28857
+ <dl>
28858
+ <dt>${gone2 ? "Was sent to" : "Sent to"}</dt>
28859
+ <dd data-rules>${secret.rules.length ? secret.rules.map((rule, index) => b`${index ? b`<br />` : A}${ruleLine(rule)}`) : "Nowhere yet: no rule names it"}</dd>
28860
+ <dt>${gone2 ? "Left through" : "Leaves through"}</dt>
28861
+ <dd data-exits>${list4(secret.exits.map((exit) => exitLabel(exit, devices)))}</dd>
28862
+ <dt>Programs</dt>
28863
+ <dd data-exec>${execLine(secret.exec)}${reveal ? b`<br />${reveal}` : A}</dd>
28864
+ <dt>From</dt>
28865
+ <dd data-source>${sourceLine(secret, devices)}</dd>
28866
+ ${secret.usedAt ? b`<dt>Last used</dt><dd data-used>${since(secret.usedAt)}</dd>` : A}
28867
+ ${secret.expiresAt ? b`<dt>Expires</dt><dd data-expires>${until(secret.expiresAt)}</dd>` : A}
28868
+ ${secret.removedAt ? b`<dt>Removed</dt><dd>${since(secret.removedAt)}</dd>` : A}
28869
+ </dl>
28870
+ </li>`;
28871
+ }
28872
+ #secrets(list5, entries, devices) {
28873
+ const more = this.more ?? list5.auditMore;
28874
+ const row = (secret) => this.#secret(secret, entries, devices, more);
28875
+ const live = list5.secrets.filter((secret) => secret.state !== "removed");
28876
+ const removed = list5.secrets.filter((secret) => secret.state === "removed");
28877
+ return b`${live.length ? b`<ul class="secrets" aria-labelledby="secrets">${live.map(row)}</ul>` : A}
28878
+ ${removed.length ? b`<details class="removed" data-removed>
28879
+ <summary>Removed (${removed.length})</summary>
28880
+ <ul class="secrets">${removed.map(row)}</ul>
28881
+ </details>` : A}`;
28882
+ }
28883
+ #entry(entry, devices) {
28884
+ const date = new Date(entry.at);
28885
+ const name = entry.type === "policy" ? null : entry.name;
28886
+ return b`<li data-seq=${entry.seq} data-type=${entry.type}>
28887
+ <time datetime=${date.toISOString()} title=${date.toLocaleString("en-GB", { dateStyle: "medium", timeStyle: "short" })}>${since(entry.at)}</time>
28888
+ <span class="what">${name ? b`<code>${name}</code> · ` : A}${auditLine(entry, devices)}${entry.type === "policy" ? A : b` <span class="by">by ${who(entry)}</span>`}</span>
28889
+ </li>`;
28890
+ }
28891
+ #audit(vault, list5, entries, devices) {
28892
+ const shown3 = this.reveals ? entries.filter((entry) => entry.type === "materialize") : entries;
28893
+ const more = this.more ?? list5.auditMore;
28894
+ return b`<div class="audit-head">
28895
+ <h3 id="secrets-audit">Activity</h3>
28896
+ <sp-switch size="s" data-action="reveals" .checked=${this.reveals} @change=${(event2) => {
28897
+ this.reveals = event2.target.checked;
28898
+ }}>Only reveals to programs</sp-switch>
28899
+ </div>
28900
+ ${shown3.length ? b`<ol class="audit" aria-labelledby="secrets-audit">${shown3.map((entry) => this.#entry(entry, devices))}</ol>` : b`<p class="muted" data-audit-empty>${this.reveals ? more ? "No reveals in the activity loaded so far." : "No program has been given a secret." : "Nothing has used a secret yet."}</p>`}
28901
+ ${more ? b`<div class="row"><swc-button size="s" variant="secondary" fill-style="outline" data-action="older" ?pending=${this.loading} @click=${() => this.showOlder(vault, entries)}>Show older</swc-button></div>` : A}`;
28902
+ }
28903
+ #feedback() {
28904
+ if (this.popup?.state === "blocked")
28905
+ return b`<div class="error" role="alert" data-popup="blocked"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>The browser blocked the vault window. Allow pop-ups for this site, then try again.</span></div>`;
28906
+ if (this.popup?.state === "done" && this.popup.result)
28907
+ return b`<p role="status" data-popup="done">Saved <code>${this.popup.result.name}</code> in the vault.</p>`;
28908
+ return A;
28909
+ }
28910
+ render() {
28911
+ const vault = this.model?.vault;
28912
+ if (!vault) return A;
28913
+ const status2 = vault.status();
28914
+ const current = vault.list();
28915
+ const devices = devicesOf(this.model);
28916
+ const entries = merged(current?.audit ?? [], this.older);
28917
+ const listed = current?.notices ?? [];
28918
+ const notices = [
28919
+ ...listed,
28920
+ ...this.#pushed.filter((notice) => !listed.some((item2) => item2.id === notice.id))
28921
+ ].filter((notice) => !notice.acknowledged);
28922
+ return b`<section aria-labelledby="secrets" data-vault=${status2 ? status2.locked ? "locked" : "unlocked" : "loading"}>
28923
+ <div class="head">
28924
+ <h2 id="secrets">Secrets</h2>
28925
+ ${status2 ? b`<swc-status-light size="m" variant=${status2.locked ? "notice" : "positive"}>${status2.locked ? "Locked" : "Unlocked"}</swc-status-light><span class="muted">${lockModes[status2.lock]}</span>` : A}
28926
+ ${status2?.locked ? this.#button({ intent: { kind: "unlock" }, label: "Unlock", variant: "accent" }) : this.#button({ intent: { kind: "manage" }, label: "Open the vault" })}
28927
+ </div>
28928
+ <p class="muted">Agents and programs use secrets by name. The values stay in the vault, so SLICC never sees or shows them.</p>
28929
+ ${this.#feedback()}
28930
+ ${this.failure ? b`<div class="error" role="alert" data-error="vault"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${this.failure}</span></div>` : A}
28931
+ ${status2?.waiting.length ? b`<h3>Waiting for you</h3>${status2.waiting.map((request2) => this.#request(request2))}` : A}
28932
+ ${notices.map((notice) => this.#notice(vault, notice, devices))}
28933
+ ${!current ? b`<p class="muted" data-loading>Loading secrets…</p>` : current.secrets.length ? this.#secrets(current, entries, devices) : b`<p data-empty>No secrets yet. When an agent or program needs one, it asks here, and you enter the value in the vault.</p>`}
28934
+ <p class="muted" data-policy>Rules live in <code>/etc/fnox/config.toml</code> and <code>/etc/slicc/secrets-policy.toml</code>. Change them with sudo; SLICC asks you before every change.</p>
28935
+ <div class="row">
28936
+ ${this.#button({ intent: { kind: "import" }, label: "Import\u2026", size: "s" })}
28937
+ ${this.#button({ intent: { kind: "export" }, label: "Export\u2026", size: "s" })}
28938
+ </div>
28939
+ ${current ? this.#audit(vault, current, entries, devices) : A}
28940
+ </section>`;
28941
+ }
28942
+ };
28943
+
27921
28944
  // src/app/settings.ts
27922
28945
  var accountStatus = {
27923
28946
  connected: ["positive", "Connected"],
@@ -28275,6 +29298,7 @@ var SliccSettings = class extends ModelElement {
28275
29298
  <div class="accounts">${providers.map((account) => this.#account(account))}</div>
28276
29299
  ${servers.length ? b`<h2>MCP servers</h2>
28277
29300
  <div class="accounts" data-group="mcp">${servers.map((account) => this.#account(account))}</div>` : A}
29301
+ ${this.model?.vault ? b`<slicc-secrets .model=${this.model}></slicc-secrets>` : A}
28278
29302
  </div>`;
28279
29303
  }
28280
29304
  };
@@ -31070,14 +32094,14 @@ var RegexSource = class {
31070
32094
  return CAPTURING_REGEX_SOURCE.test(regexSource);
31071
32095
  }
31072
32096
  static replaceCaptures(regexSource, captureSource, captureIndices) {
31073
- return regexSource.replace(CAPTURING_REGEX_SOURCE, (match, index, commandIndex, command2) => {
32097
+ return regexSource.replace(CAPTURING_REGEX_SOURCE, (match, index, commandIndex, command3) => {
31074
32098
  let capture = captureIndices[parseInt(index || commandIndex, 10)];
31075
32099
  if (capture) {
31076
32100
  let result = captureSource.substring(capture.start, capture.end);
31077
32101
  while (result[0] === ".") {
31078
32102
  result = result.substring(1);
31079
32103
  }
31080
- switch (command2) {
32104
+ switch (command3) {
31081
32105
  case "downcase":
31082
32106
  return result.toLowerCase();
31083
32107
  case "upcase":
@@ -32091,8 +33115,8 @@ var IncludeOnlyRule = class extends Rule {
32091
33115
  }
32092
33116
  }
32093
33117
  collectPatterns(grammar2, out) {
32094
- for (const pattern of this.patterns) {
32095
- const rule = grammar2.getRule(pattern);
33118
+ for (const pattern2 of this.patterns) {
33119
+ const rule = grammar2.getRule(pattern2);
32096
33120
  rule.collectPatterns(grammar2, out);
32097
33121
  }
32098
33122
  }
@@ -32159,8 +33183,8 @@ var BeginEndRule = class extends Rule {
32159
33183
  _getCachedCompiledPatterns(grammar2, endRegexSource) {
32160
33184
  if (!this._cachedCompiledPatterns) {
32161
33185
  this._cachedCompiledPatterns = new RegExpSourceList();
32162
- for (const pattern of this.patterns) {
32163
- const rule = grammar2.getRule(pattern);
33186
+ for (const pattern2 of this.patterns) {
33187
+ const rule = grammar2.getRule(pattern2);
32164
33188
  rule.collectPatterns(grammar2, this._cachedCompiledPatterns);
32165
33189
  }
32166
33190
  if (this.applyEndPatternLast) {
@@ -32232,8 +33256,8 @@ var BeginWhileRule = class extends Rule {
32232
33256
  _getCachedCompiledPatterns(grammar2) {
32233
33257
  if (!this._cachedCompiledPatterns) {
32234
33258
  this._cachedCompiledPatterns = new RegExpSourceList();
32235
- for (const pattern of this.patterns) {
32236
- const rule = grammar2.getRule(pattern);
33259
+ for (const pattern2 of this.patterns) {
33260
+ const rule = grammar2.getRule(pattern2);
32237
33261
  rule.collectPatterns(grammar2, this._cachedCompiledPatterns);
32238
33262
  }
32239
33263
  }
@@ -32354,14 +33378,14 @@ var RuleFactory = class _RuleFactory {
32354
33378
  let r39 = [];
32355
33379
  if (patterns) {
32356
33380
  for (let i25 = 0, len = patterns.length; i25 < len; i25++) {
32357
- const pattern = patterns[i25];
33381
+ const pattern2 = patterns[i25];
32358
33382
  let ruleId = -1;
32359
- if (pattern.include) {
32360
- const reference2 = parseInclude(pattern.include);
33383
+ if (pattern2.include) {
33384
+ const reference2 = parseInclude(pattern2.include);
32361
33385
  switch (reference2.kind) {
32362
33386
  case 0:
32363
33387
  case 1:
32364
- ruleId = _RuleFactory.getCompiledRuleId(repository[pattern.include], helper, repository);
33388
+ ruleId = _RuleFactory.getCompiledRuleId(repository[pattern2.include], helper, repository);
32365
33389
  break;
32366
33390
  case 2:
32367
33391
  let localIncludedRule = repository[reference2.ruleName];
@@ -32390,7 +33414,7 @@ var RuleFactory = class _RuleFactory {
32390
33414
  break;
32391
33415
  }
32392
33416
  } else {
32393
- ruleId = _RuleFactory.getCompiledRuleId(pattern, helper, repository);
33417
+ ruleId = _RuleFactory.getCompiledRuleId(pattern2, helper, repository);
32394
33418
  }
32395
33419
  if (ruleId !== -1) {
32396
33420
  const rule = helper.getRule(ruleId);
@@ -37233,13 +38257,13 @@ function splitTokens(tokens, breakpoints) {
37233
38257
  });
37234
38258
  });
37235
38259
  }
37236
- function flatTokenVariants(merged, variantsOrder, cssVariablePrefix, defaultColor, colorsRendering = "css-vars") {
38260
+ function flatTokenVariants(merged2, variantsOrder, cssVariablePrefix, defaultColor, colorsRendering = "css-vars") {
37237
38261
  const token2 = {
37238
- content: merged.content,
37239
- explanation: merged.explanation,
37240
- offset: merged.offset
38262
+ content: merged2.content,
38263
+ explanation: merged2.explanation,
38264
+ offset: merged2.offset
37241
38265
  };
37242
- const styles = variantsOrder.map((t88) => getTokenStyleObject(merged.variants[t88]));
38266
+ const styles = variantsOrder.map((t88) => getTokenStyleObject(merged2.variants[t88]));
37243
38267
  const styleKeys = new Set(styles.flatMap((t88) => Object.keys(t88)));
37244
38268
  const mergedStyles = {};
37245
38269
  const varKey = (idx, key2) => {
@@ -39349,25 +40373,25 @@ var namedCaptureDelim = r35`\(\?<(?![=!])(?<captureName>[^>]+)>`;
39349
40373
  var captureDelim = r35`${namedCaptureDelim}|(?<unnamed>\()(?!\?)`;
39350
40374
  var token = new RegExp(r35`${namedCaptureDelim}|${recursiveToken}|\(\?|\\?.`, "gsu");
39351
40375
  var overlappingRecursionMsg = "Cannot use multiple overlapping recursions";
39352
- function recursion(pattern, data) {
40376
+ function recursion(pattern2, data) {
39353
40377
  const { hiddenCaptures, mode } = {
39354
40378
  hiddenCaptures: [],
39355
40379
  mode: "plugin",
39356
40380
  ...data
39357
40381
  };
39358
40382
  let captureTransfers = data?.captureTransfers ?? /* @__PURE__ */ new Map();
39359
- if (!new RegExp(recursiveToken, "su").test(pattern)) {
40383
+ if (!new RegExp(recursiveToken, "su").test(pattern2)) {
39360
40384
  return {
39361
- pattern,
40385
+ pattern: pattern2,
39362
40386
  captureTransfers,
39363
40387
  hiddenCaptures
39364
40388
  };
39365
40389
  }
39366
- if (mode === "plugin" && hasUnescaped(pattern, r35`\(\?\(DEFINE\)`, Context.DEFAULT)) {
40390
+ if (mode === "plugin" && hasUnescaped(pattern2, r35`\(\?\(DEFINE\)`, Context.DEFAULT)) {
39367
40391
  throw new Error("DEFINE groups cannot be used with recursion");
39368
40392
  }
39369
40393
  const addedHiddenCaptures = [];
39370
- const hasNumberedBackref = hasUnescaped(pattern, r35`\\[1-9]`, Context.DEFAULT);
40394
+ const hasNumberedBackref = hasUnescaped(pattern2, r35`\\[1-9]`, Context.DEFAULT);
39371
40395
  const groupContentsStartPos = /* @__PURE__ */ new Map();
39372
40396
  const openGroups = [];
39373
40397
  let hasRecursed = false;
@@ -39375,7 +40399,7 @@ function recursion(pattern, data) {
39375
40399
  let numCapturesPassed = 0;
39376
40400
  let match;
39377
40401
  token.lastIndex = 0;
39378
- while (match = token.exec(pattern)) {
40402
+ while (match = token.exec(pattern2)) {
39379
40403
  const { 0: m15, groups: { captureName, rDepth, gRNameOrNum, gRDepth } } = match;
39380
40404
  if (m15 === "[") {
39381
40405
  numCharClassesOpen++;
@@ -39392,13 +40416,13 @@ function recursion(pattern, data) {
39392
40416
  `${mode === "external" ? "Backrefs" : "Numbered backrefs"} cannot be used with global recursion`
39393
40417
  );
39394
40418
  }
39395
- const left = pattern.slice(0, match.index);
39396
- const right = pattern.slice(token.lastIndex);
40419
+ const left = pattern2.slice(0, match.index);
40420
+ const right = pattern2.slice(token.lastIndex);
39397
40421
  if (hasUnescaped(right, recursiveToken, Context.DEFAULT)) {
39398
40422
  throw new Error(overlappingRecursionMsg);
39399
40423
  }
39400
40424
  const reps = +rDepth - 1;
39401
- pattern = makeRecursive(
40425
+ pattern2 = makeRecursive(
39402
40426
  left,
39403
40427
  right,
39404
40428
  reps,
@@ -39432,7 +40456,7 @@ function recursion(pattern, data) {
39432
40456
  throw new Error(r35`Recursive \g cannot be used outside the referenced group "${mode === "external" ? gRNameOrNum : r35`\g<${gRNameOrNum}&R=${gRDepth}>`}"`);
39433
40457
  }
39434
40458
  const startPos = groupContentsStartPos.get(gRNameOrNum);
39435
- const groupContents = getGroupContents(pattern, startPos);
40459
+ const groupContents = getGroupContents(pattern2, startPos);
39436
40460
  if (hasNumberedBackref && hasUnescaped(groupContents, r35`${namedCaptureDelim}|\((?!\?)`, Context.DEFAULT)) {
39437
40461
  throw new Error(
39438
40462
  // When used in `external` mode by transpilers other than Regex+, backrefs might have
@@ -39440,11 +40464,11 @@ function recursion(pattern, data) {
39440
40464
  `${mode === "external" ? "Backrefs" : "Numbered backrefs"} cannot be used with recursion of capturing groups`
39441
40465
  );
39442
40466
  }
39443
- const groupContentsLeft = pattern.slice(startPos, match.index);
40467
+ const groupContentsLeft = pattern2.slice(startPos, match.index);
39444
40468
  const groupContentsRight = groupContents.slice(groupContentsLeft.length + m15.length);
39445
40469
  const numAddedHiddenCapturesPreExpansion = addedHiddenCaptures.length;
39446
40470
  const reps = +gRDepth - 1;
39447
- const expansion = makeRecursive(
40471
+ const expansion2 = makeRecursive(
39448
40472
  groupContentsLeft,
39449
40473
  groupContentsRight,
39450
40474
  reps,
@@ -39461,10 +40485,10 @@ function recursion(pattern, data) {
39461
40485
  numAddedHiddenCapturesPreExpansion,
39462
40486
  numCapturesPassed
39463
40487
  );
39464
- const pre = pattern.slice(0, startPos);
39465
- const post = pattern.slice(startPos + groupContents.length);
39466
- pattern = `${pre}${expansion}${post}`;
39467
- token.lastIndex += expansion.length - m15.length - groupContentsLeft.length - groupContentsRight.length;
40488
+ const pre = pattern2.slice(0, startPos);
40489
+ const post = pattern2.slice(startPos + groupContents.length);
40490
+ pattern2 = `${pre}${expansion2}${post}`;
40491
+ token.lastIndex += expansion2.length - m15.length - groupContentsLeft.length - groupContentsRight.length;
39468
40492
  openGroups.forEach((g7) => g7.hasRecursedWithin = true);
39469
40493
  hasRecursed = true;
39470
40494
  } else if (captureName) {
@@ -39491,7 +40515,7 @@ function recursion(pattern, data) {
39491
40515
  }
39492
40516
  hiddenCaptures.push(...addedHiddenCaptures);
39493
40517
  return {
39494
- pattern,
40518
+ pattern: pattern2,
39495
40519
  captureTransfers,
39496
40520
  hiddenCaptures
39497
40521
  };
@@ -39522,14 +40546,14 @@ function makeRecursive(left, right, reps, isSubpattern, hiddenCaptures, addedHid
39522
40546
  ];
39523
40547
  return `${left}${repeatWithDepth(`(?:${left}`, "forward", ...rest)}(?:)${repeatWithDepth(`${right})`, "backward", ...rest)}${right}`;
39524
40548
  }
39525
- function repeatWithDepth(pattern, direction, reps, namesInRecursed, hiddenCaptures, addedHiddenCaptures, numCapturesPassed) {
40549
+ function repeatWithDepth(pattern2, direction, reps, namesInRecursed, hiddenCaptures, addedHiddenCaptures, numCapturesPassed) {
39526
40550
  const startNum = 2;
39527
40551
  const getDepthNum = (i25) => direction === "forward" ? i25 + startNum : reps - i25 + startNum - 1;
39528
40552
  let result = "";
39529
40553
  for (let i25 = 0; i25 < reps; i25++) {
39530
40554
  const depthNum = getDepthNum(i25);
39531
40555
  result += replaceUnescaped(
39532
- pattern,
40556
+ pattern2,
39533
40557
  r35`${captureDelim}|\\k<(?<backref>[^>]+)>`,
39534
40558
  ({ 0: m15, groups: { captureName, unnamed, backref } }) => {
39535
40559
  if (backref && namesInRecursed && !namesInRecursed.has(backref)) {
@@ -40612,8 +41636,8 @@ function isLoneGLookaround(node, options) {
40612
41636
  function isValidJsGroupName(name) {
40613
41637
  return /^[$_\p{IDS}][$\u200C\u200D\p{IDC}]*$/u.test(name);
40614
41638
  }
40615
- function parseFragment(pattern, options) {
40616
- const ast = J2(pattern, {
41639
+ function parseFragment(pattern2, options) {
41640
+ const ast = J2(pattern2, {
40617
41641
  ...options,
40618
41642
  // Providing a custom set of Unicode property names avoids converting some JS Unicode
40619
41643
  // properties (ex: `\p{Alpha}`) to Onig POSIX classes
@@ -41209,13 +42233,13 @@ var EmulatedRegExp = class _EmulatedRegExp extends RegExp {
41209
42233
  @param {EmulatedRegExp} pattern
41210
42234
  @param {string} [flags]
41211
42235
  */
41212
- constructor(pattern, flags, options) {
42236
+ constructor(pattern2, flags, options) {
41213
42237
  const lazyCompile = !!options?.lazyCompile;
41214
- if (pattern instanceof RegExp) {
42238
+ if (pattern2 instanceof RegExp) {
41215
42239
  if (options) {
41216
42240
  throw new Error("Cannot provide options when copying a regexp");
41217
42241
  }
41218
- const re3 = pattern;
42242
+ const re3 = pattern2;
41219
42243
  super(re3, flags);
41220
42244
  this.#pattern = re3.source;
41221
42245
  if (re3 instanceof _EmulatedRegExp) {
@@ -41231,8 +42255,8 @@ var EmulatedRegExp = class _EmulatedRegExp extends RegExp {
41231
42255
  transfers: [],
41232
42256
  ...options
41233
42257
  };
41234
- super(lazyCompile ? "" : pattern, flags);
41235
- this.#pattern = pattern;
42258
+ super(lazyCompile ? "" : pattern2, flags);
42259
+ this.#pattern = pattern2;
41236
42260
  this.#captureMap = createCaptureMap(opts.hiddenCaptures, opts.transfers);
41237
42261
  this.#strategy = opts.strategy;
41238
42262
  this.rawOptions = options ?? {};
@@ -41358,13 +42382,13 @@ function createCaptureMap(hiddenCaptures, transfers) {
41358
42382
  }
41359
42383
  return captureMap;
41360
42384
  }
41361
- function createNameMap(pattern) {
42385
+ function createNameMap(pattern2) {
41362
42386
  const re3 = /(?<capture>\((?:\?<(?![=!])(?<name>[^>]+)>|(?!\?)))|\\?./gsu;
41363
42387
  const map = /* @__PURE__ */ new Map();
41364
42388
  let numCharClassesOpen = 0;
41365
42389
  let numCaptures = 0;
41366
42390
  let match;
41367
- while (match = re3.exec(pattern)) {
42391
+ while (match = re3.exec(pattern2)) {
41368
42392
  const { 0: m15, groups: { capture, name } } = match;
41369
42393
  if (m15 === "[") {
41370
42394
  numCharClassesOpen++;
@@ -41381,16 +42405,16 @@ function createNameMap(pattern) {
41381
42405
  }
41382
42406
  return map;
41383
42407
  }
41384
- function toRegExp(pattern, options) {
41385
- const d22 = toRegExpDetails(pattern, options);
42408
+ function toRegExp(pattern2, options) {
42409
+ const d22 = toRegExpDetails(pattern2, options);
41386
42410
  if (d22.options) {
41387
42411
  return new EmulatedRegExp(d22.pattern, d22.flags, d22.options);
41388
42412
  }
41389
42413
  return new RegExp(d22.pattern, d22.flags);
41390
42414
  }
41391
- function toRegExpDetails(pattern, options) {
42415
+ function toRegExpDetails(pattern2, options) {
41392
42416
  const opts = getOptions(options);
41393
- const onigurumaAst = J2(pattern, {
42417
+ const onigurumaAst = J2(pattern2, {
41394
42418
  flags: opts.flags,
41395
42419
  normalizeUnknownPropertyNames: true,
41396
42420
  rules: {
@@ -41443,8 +42467,8 @@ function toRegExpDetails(pattern, options) {
41443
42467
  }
41444
42468
 
41445
42469
  // node_modules/@shikijs/engine-javascript/dist/engine-compile.mjs
41446
- function defaultJavaScriptRegexConstructor(pattern, options) {
41447
- return toRegExp(pattern, {
42470
+ function defaultJavaScriptRegexConstructor(pattern2, options) {
42471
+ return toRegExp(pattern2, {
41448
42472
  global: true,
41449
42473
  hasIndices: true,
41450
42474
  lazyCompileLength: 3e3,
@@ -41464,7 +42488,7 @@ function createJavaScriptRegexEngine(options = {}) {
41464
42488
  cache: /* @__PURE__ */ new Map(),
41465
42489
  ...options
41466
42490
  };
41467
- _options.regexConstructor ||= (pattern) => defaultJavaScriptRegexConstructor(pattern, { target: _options.target });
42491
+ _options.regexConstructor ||= (pattern2) => defaultJavaScriptRegexConstructor(pattern2, { target: _options.target });
41468
42492
  return {
41469
42493
  createScanner(patterns) {
41470
42494
  return new JavaScriptScanner(patterns, _options);
@@ -42794,8 +43818,8 @@ var InteractionManager = class {
42794
43818
  const indexes = this.getLineIndex(point.lineNumber, point.side);
42795
43819
  if (indexes == null) return;
42796
43820
  const lineIndex = this.mode === "diff" ? `${indexes[0]},${indexes[1]}` : `${indexes[0]}`;
42797
- const candidates = this.pre.querySelectorAll(`[data-column-number="${point.lineNumber}"][data-line-index="${lineIndex}"]`);
42798
- for (const element2 of candidates) {
43821
+ const candidates2 = this.pre.querySelectorAll(`[data-column-number="${point.lineNumber}"][data-line-index="${lineIndex}"]`);
43822
+ for (const element2 of candidates2) {
42799
43823
  if (!(element2 instanceof HTMLElement)) continue;
42800
43824
  const target = this.resolvePointerTarget(getElementPath(element2));
42801
43825
  if (!isLinePointerTarget(target)) continue;
@@ -44047,6 +45071,7 @@ var EXTENSION_TO_FILE_FORMAT = {
44047
45071
  mli: "ocaml",
44048
45072
  mll: "ocaml",
44049
45073
  mly: "ocaml",
45074
+ odin: "odin",
44050
45075
  pas: "pascal",
44051
45076
  p: "pascal",
44052
45077
  pl: "prolog",
@@ -44079,6 +45104,17 @@ var EXTENSION_TO_FILE_FORMAT = {
44079
45104
  py: "python",
44080
45105
  pyw: "python",
44081
45106
  pyi: "python",
45107
+ BUCK: "python",
45108
+ BUILD: "python",
45109
+ PACKAGE: "python",
45110
+ WORKSPACE: "python",
45111
+ Tiltfile: "python",
45112
+ bazel: "python",
45113
+ bxl: "python",
45114
+ bzl: "python",
45115
+ bzlmod: "python",
45116
+ star: "python",
45117
+ sky: "python",
44082
45118
  qml: "qml",
44083
45119
  qmldir: "qmldir",
44084
45120
  qss: "qss",
@@ -44189,16 +45225,22 @@ var EXTENSION_TO_FILE_FORMAT = {
44189
45225
  sty: "tex"
44190
45226
  };
44191
45227
  function getFiletypeFromFileName(fileName) {
45228
+ const format = matchFiletypeFromName(fileName);
45229
+ if (format != null) return format;
45230
+ const baseName = fileName.split(/[/\\]/).pop() ?? fileName;
45231
+ return baseName === fileName ? "text" : matchFiletypeFromName(baseName) ?? "text";
45232
+ }
45233
+ function matchFiletypeFromName(fileName) {
44192
45234
  if (CUSTOM_EXTENSION_TO_FILE_FORMAT.has(fileName)) return CUSTOM_EXTENSION_TO_FILE_FORMAT.get(fileName) ?? "text";
44193
- if (EXTENSION_TO_FILE_FORMAT[fileName] != null) return EXTENSION_TO_FILE_FORMAT[fileName];
45235
+ if (Object.hasOwn(EXTENSION_TO_FILE_FORMAT, fileName)) return EXTENSION_TO_FILE_FORMAT[fileName] ?? null;
44194
45236
  const compoundMatch = fileName.match(/\.([^/\\]+\.[^/\\]+)$/);
44195
45237
  if (compoundMatch != null) {
44196
45238
  if (CUSTOM_EXTENSION_TO_FILE_FORMAT.has(compoundMatch[1])) return CUSTOM_EXTENSION_TO_FILE_FORMAT.get(compoundMatch[1]) ?? "text";
44197
- if (EXTENSION_TO_FILE_FORMAT[compoundMatch[1]] != null) return EXTENSION_TO_FILE_FORMAT[compoundMatch[1]] ?? "text";
45239
+ if (Object.hasOwn(EXTENSION_TO_FILE_FORMAT, compoundMatch[1])) return EXTENSION_TO_FILE_FORMAT[compoundMatch[1]] ?? "text";
44198
45240
  }
44199
45241
  const simpleMatch = fileName.match(/\.([^.]+)$/)?.[1] ?? "";
44200
45242
  if (CUSTOM_EXTENSION_TO_FILE_FORMAT.has(simpleMatch)) return CUSTOM_EXTENSION_TO_FILE_FORMAT.get(simpleMatch) ?? "text";
44201
- return EXTENSION_TO_FILE_FORMAT[simpleMatch] ?? "text";
45243
+ return Object.hasOwn(EXTENSION_TO_FILE_FORMAT, simpleMatch) ? EXTENSION_TO_FILE_FORMAT[simpleMatch] ?? "text" : null;
44202
45244
  }
44203
45245
 
44204
45246
  // node_modules/@pierre/diffs/dist/utils/getHighlighterOptions.js
@@ -44564,8 +45606,8 @@ function normalizeThemeColors(theme3) {
44564
45606
  function fill(colors, key2, value) {
44565
45607
  if (value != null && value !== "") colors[key2] = value;
44566
45608
  }
44567
- function firstColor(...candidates) {
44568
- for (const candidate of candidates) if (candidate != null && candidate !== "") return candidate;
45609
+ function firstColor(...candidates2) {
45610
+ for (const candidate of candidates2) if (candidate != null && candidate !== "") return candidate;
44569
45611
  }
44570
45612
  function matchesSurface(color, surface2) {
44571
45613
  return surface2 != null && color.toLowerCase() === surface2.toLowerCase();
@@ -45671,6 +46713,12 @@ function isStyleNode(element2) {
45671
46713
  return typeof tagName === "string" && tagName.toLowerCase() === "style";
45672
46714
  }
45673
46715
 
46716
+ // node_modules/@pierre/diffs/dist/utils/platform.js
46717
+ var _isSafari = void 0;
46718
+ function isSafari() {
46719
+ return _isSafari ??= "safari" in window && "pushNotification" in window.safari || /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
46720
+ }
46721
+
45674
46722
  // node_modules/@pierre/diffs/dist/utils/editSessionAnnotations.js
45675
46723
  function adoptEditSessionAnnotations(annotations, getName, previousSession) {
45676
46724
  const slotNames = /* @__PURE__ */ new Map();
@@ -45762,10 +46810,31 @@ function createHostThemeStyleNode() {
45762
46810
  return node;
45763
46811
  }
45764
46812
 
45765
- // node_modules/@pierre/diffs/dist/utils/platform.js
45766
- var _isSafari = void 0;
45767
- function isSafari() {
45768
- return _isSafari ??= "safari" in window && "pushNotification" in window.safari || /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
46813
+ // node_modules/@pierre/diffs/dist/worker/errors.js
46814
+ var WorkerPoolTerminatedError = class extends Error {
46815
+ constructor() {
46816
+ super("WorkerPoolManager: operation canceled because the pool terminated");
46817
+ this.name = "WorkerPoolTerminatedError";
46818
+ }
46819
+ };
46820
+ var WorkerPoolTaskCanceledError = class extends Error {
46821
+ constructor() {
46822
+ super("WorkerPoolManager: operation canceled before the task completed");
46823
+ this.name = "WorkerPoolTaskCanceledError";
46824
+ }
46825
+ };
46826
+ var WorkerPoolWorkerError = class extends Error {
46827
+ constructor(message, options) {
46828
+ super(message, options);
46829
+ this.name = "WorkerPoolWorkerError";
46830
+ }
46831
+ };
46832
+ var reportedWorkerErrors = /* @__PURE__ */ new WeakSet();
46833
+ function isWorkerPoolCancellation(error) {
46834
+ return error instanceof WorkerPoolTerminatedError || error instanceof WorkerPoolTaskCanceledError;
46835
+ }
46836
+ function isHandledWorkerPoolError(error) {
46837
+ return isWorkerPoolCancellation(error) || error instanceof WorkerPoolWorkerError && reportedWorkerErrors.has(error);
45769
46838
  }
45770
46839
 
45771
46840
  // node_modules/@pierre/diffs/dist/components/web-components.js
@@ -46417,6 +47486,7 @@ var File = class {
46417
47486
  const tokenizeMaxLength = this.options.tokenizeMaxLength ?? 1e5;
46418
47487
  if (this.fileRenderer.getOrCreateLineCache(file).length > tokenizeMaxLength) return;
46419
47488
  await workerManager.primeFileHighlightCache(file).catch((error) => {
47489
+ if (isHandledWorkerPoolError(error)) return;
46420
47490
  console.error(error);
46421
47491
  });
46422
47492
  }
@@ -49288,13 +50358,13 @@ function getChangeIterationRanges(state3, content, diffStyle) {
49288
50358
  }
49289
50359
  if (iterationRanges.length === 0) return iterationRanges;
49290
50360
  iterationRanges.sort((a22, b13) => a22[0] - b13[0]);
49291
- const merged = [iterationRanges[0]];
50361
+ const merged2 = [iterationRanges[0]];
49292
50362
  for (const [start, end] of iterationRanges.slice(1)) {
49293
- const last = merged[merged.length - 1];
50363
+ const last = merged2[merged2.length - 1];
49294
50364
  if (start <= last[1]) last[1] = Math.max(last[1], end);
49295
- else merged.push([start, end]);
50365
+ else merged2.push([start, end]);
49296
50366
  }
49297
- return merged;
50367
+ return merged2;
49298
50368
  }
49299
50369
  function getChangeLineData({ hunkIndex, hunk, collapsedAfter, collapsedBefore, diffStyle, index, unifiedLineIndex, splitLineIndex, additionLineIndex, deletionLineIndex, additionLineNumber, deletionLineNumber, content, isLastContent, unifiedCount, splitCount }) {
49300
50370
  const unifiedDeletionLineIndex = index < content.deletions ? unifiedLineIndex + index : void 0;
@@ -50491,7 +51561,7 @@ var DiffHunksRenderer = class {
50491
51561
  * row set without a line-count change — the host must escalate to a full
50492
51562
  * re-render instead of its cheap refresh path.
50493
51563
  */
50494
- updateRenderCache(dirtyLines, themeType, lineCountChangeInFlight = false) {
51564
+ updateRenderCache(dirtyLines, themeType, lineCountChangeInFlight = false, changedDocumentLines, documentLineCount) {
50495
51565
  this.pendingStructuralRows = void 0;
50496
51566
  const { renderCache } = this;
50497
51567
  if (renderCache == null) return false;
@@ -50502,13 +51572,27 @@ var DiffHunksRenderer = class {
50502
51572
  const pendingStructuralRows = this.pendingStructuralRows = lineCountChangeInFlight ? /* @__PURE__ */ new Map() : void 0;
50503
51573
  const changedAdditionLines = [];
50504
51574
  const previousAdditionLines = /* @__PURE__ */ new Map();
51575
+ if (pendingStructuralRows == null && changedDocumentLines != null) {
51576
+ const additionLineCount = diff.additionLines.length;
51577
+ const canAppendFinalRow = canAppendFinalDocumentRow(diff.additionLines, documentLineCount);
51578
+ for (const [line, text2] of changedDocumentLines) {
51579
+ if (line < 0 || line > additionLineCount || line === additionLineCount && (text2 === "" || !canAppendFinalRow)) continue;
51580
+ const previous = diff.additionLines[line] ?? "";
51581
+ if (previous !== text2) {
51582
+ diff.additionLines[line] = text2;
51583
+ changedAdditionLines.push(line);
51584
+ previousAdditionLines.set(line, previous);
51585
+ if (!dirtyLines.has(line)) hastLines[line] = createPlainAdditionLineElement(line, cleanLastNewline(text2));
51586
+ }
51587
+ }
51588
+ }
50505
51589
  for (const [line, tokens] of dirtyLines) {
50506
51590
  const prevProps = hastLines[line]?.properties ?? {};
50507
51591
  const lineText = tokens.map((a22) => a22[2]).join("");
50508
51592
  const canSyncDiffLine = line < diff.additionLines.length;
50509
51593
  const prevLine = canSyncDiffLine ? diff.additionLines[line] ?? "" : "";
50510
51594
  const prevText = cleanLastNewline(prevLine);
50511
- if (pendingStructuralRows == null && canSyncDiffLine) {
51595
+ if (pendingStructuralRows == null && canSyncDiffLine && changedDocumentLines?.has(line) !== true) {
50512
51596
  diff.additionLines[line] = applyLineTextWithNewline(prevLine, lineText);
50513
51597
  if (prevText !== lineText) {
50514
51598
  changedAdditionLines.push(line);
@@ -51502,6 +52586,9 @@ function realignAdditionHastLines(previousLines, nextLines, hastLines, textDocum
51502
52586
  for (let index = prefix; index < nextLines.length; index++) realigned[index] ??= createPlainAdditionLineElement(index, textDocument.getLineText(index));
51503
52587
  return realigned;
51504
52588
  }
52589
+ function canAppendFinalDocumentRow(additionLines, documentLineCount) {
52590
+ return documentLineCount === additionLines.length + 1 && additionLines.at(-1)?.endsWith("\n") === true;
52591
+ }
51505
52592
  function createPlainAdditionLineElement(lineIndex, lineText, unifiedLineIndex = lineIndex, splitLineIndex = lineIndex) {
51506
52593
  return {
51507
52594
  type: "element",
@@ -51604,6 +52691,7 @@ function getDiffHunksRendererOptions(options) {
51604
52691
  hunkSeparators: typeof options?.hunkSeparators === "function" ? "custom" : options?.hunkSeparators,
51605
52692
  expandUnchanged: options?.expandUnchanged,
51606
52693
  loadDiffFiles: options?.loadDiffFiles,
52694
+ parseDiffOptions: options?.parseDiffOptions,
51607
52695
  collapsedContextThreshold: options?.collapsedContextThreshold,
51608
52696
  lineDiffType: options?.lineDiffType,
51609
52697
  maxLineDiffLength: options?.maxLineDiffLength,
@@ -52596,7 +53684,7 @@ var FileDiff = class {
52596
53684
  this.detachAdditionLines();
52597
53685
  this.hunksRenderer.beginEditSession(editSessionDiff);
52598
53686
  const { shouldRefreshDiffsView, lineCountChangeInFlight } = options;
52599
- if (this.hunksRenderer.updateRenderCache(dirtyLines, themeType, lineCountChangeInFlight)) {
53687
+ if (this.hunksRenderer.updateRenderCache(dirtyLines, themeType, lineCountChangeInFlight, options.changedDocumentLines, options.documentLineCount)) {
52600
53688
  if (this.refreshViewTimeout != null) {
52601
53689
  clearTimeout(this.refreshViewTimeout);
52602
53690
  this.refreshViewTimeout = void 0;
@@ -52743,6 +53831,7 @@ var FileDiff = class {
52743
53831
  const tokenizeMaxLength = this.options.tokenizeMaxLength ?? 1e5;
52744
53832
  if (Math.max(fileDiff.additionLines.length, fileDiff.deletionLines.length) > tokenizeMaxLength) return;
52745
53833
  await workerManager.primeDiffHighlightCache(fileDiff).catch((error) => {
53834
+ if (isHandledWorkerPoolError(error)) return;
52746
53835
  console.error(error);
52747
53836
  });
52748
53837
  }
@@ -54240,9 +55329,9 @@ function disableTextSelection(rootNode = document) {
54240
55329
  }
54241
55330
  function getDockviewTheme(element2) {
54242
55331
  function toClassList(element3) {
54243
- const list4 = [];
54244
- for (let i25 = 0; i25 < element3.classList.length; i25++) list4.push(element3.classList.item(i25));
54245
- return list4;
55332
+ const list5 = [];
55333
+ for (let i25 = 0; i25 < element3.classList.length; i25++) list5.push(element3.classList.item(i25));
55334
+ return list5;
54246
55335
  }
54247
55336
  let theme3 = void 0;
54248
55337
  let parent = element2;
@@ -55446,7 +56535,7 @@ var BranchNode = class BranchNode2 extends CompositeDisposable {
55446
56535
  if (child instanceof BranchNode2) child.proportionalLayout = value;
55447
56536
  });
55448
56537
  }
55449
- constructor(orientation, proportionalLayout, styles, size4, orthogonalSize, disabled, margin, childDescriptors) {
56538
+ constructor(orientation, proportionalLayout, styles, size4, orthogonalSize, disabled2, margin, childDescriptors) {
55450
56539
  super();
55451
56540
  this.orientation = orientation;
55452
56541
  this.styles = styles;
@@ -55489,7 +56578,7 @@ var BranchNode = class BranchNode2 extends CompositeDisposable {
55489
56578
  });
55490
56579
  this.splitview.layout(this.size, this.orthogonalSize);
55491
56580
  }
55492
- this.disabled = disabled;
56581
+ this.disabled = disabled2;
55493
56582
  this.addDisposables(this._onDidChange, this._onDidVisibilityChange, this.splitview.onDidSashEnd(() => {
55494
56583
  this._onDidChange.fire({});
55495
56584
  }));
@@ -65093,9 +66182,9 @@ var ENTERPRISE_MODULE_NAMES = /* @__PURE__ */ new Set([
65093
66182
  var _warnedMissingModule = /* @__PURE__ */ new Set();
65094
66183
  function missingModuleMessage(moduleName, reason) {
65095
66184
  const reasons = reason === void 0 ? [] : [].concat(reason);
65096
- const quoted = reasons.map((r39) => `\`${r39}\``).join(", ");
66185
+ const quoted2 = reasons.map((r39) => `\`${r39}\``).join(", ");
65097
66186
  const requires = reasons.length > 1 ? "require" : "requires";
65098
- const needed = reasons.length ? `${quoted} ${requires} the "${moduleName}" module` : `The "${moduleName}" module is required`;
66187
+ const needed = reasons.length ? `${quoted2} ${requires} the "${moduleName}" module` : `The "${moduleName}" module is required`;
65099
66188
  if (ENTERPRISE_MODULE_NAMES.has(moduleName)) return `dockview: ${needed}, which ships in dockview-enterprise.
65100
66189
 
65101
66190
  npm install dockview-enterprise
@@ -65695,9 +66784,9 @@ var RootDropTargetService = class {
65695
66784
  }
65696
66785
  setOptions(options) {
65697
66786
  if ("dndEdges" in options) {
65698
- const disabled = typeof options.dndEdges === "boolean" && options.dndEdges === false;
65699
- this._html5Target.disabled = disabled;
65700
- this._pointerTarget.disabled = disabled;
66787
+ const disabled2 = typeof options.dndEdges === "boolean" && options.dndEdges === false;
66788
+ this._html5Target.disabled = disabled2;
66789
+ this._pointerTarget.disabled = disabled2;
65701
66790
  }
65702
66791
  if ("dndEdges" in options || "dockToEdgeGroups" in options) {
65703
66792
  const model = resolveRootOverlayModel({
@@ -66076,16 +67165,16 @@ var nextContextMenuItemId = () => `dv-ctx-menu-item-${_nextId++}`;
66076
67165
  function isItemConfig(item2) {
66077
67166
  return typeof item2 === "object";
66078
67167
  }
66079
- function buildItem(label, close, action, disabled) {
67168
+ function buildItem(label, close, action, disabled2) {
66080
67169
  const el = document.createElement("div");
66081
67170
  el.className = "dv-context-menu-item";
66082
67171
  el.setAttribute("role", "menuitem");
66083
- if (disabled) {
67172
+ if (disabled2) {
66084
67173
  el.classList.add("dv-context-menu-item--disabled");
66085
67174
  el.setAttribute("aria-disabled", "true");
66086
67175
  }
66087
67176
  el.textContent = label;
66088
- if (!disabled) el.addEventListener("click", () => {
67177
+ if (!disabled2) el.addEventListener("click", () => {
66089
67178
  action();
66090
67179
  close();
66091
67180
  });
@@ -71287,9 +72376,9 @@ var getBaseFileName = (path) => {
71287
72376
  };
71288
72377
  var getExtensionCandidates = (fileName) => {
71289
72378
  const segments = fileName.toLowerCase().split(".");
71290
- const candidates = [];
71291
- for (let index = 1; index < segments.length; index += 1) candidates.push(segments.slice(index).join("."));
71292
- return candidates;
72379
+ const candidates2 = [];
72380
+ for (let index = 1; index < segments.length; index += 1) candidates2.push(segments.slice(index).join("."));
72381
+ return candidates2;
71293
72382
  };
71294
72383
  function remapEntryToIcon(entry, remappedFrom) {
71295
72384
  if (typeof entry === "string") return {
@@ -77442,8 +78531,8 @@ function getFileTreeRowAriaLabel(row) {
77442
78531
  if (flattenedSegments == null || flattenedSegments.length === 0) return row.name;
77443
78532
  return flattenedSegments.map((segment2) => segment2.name).join(" / ");
77444
78533
  }
77445
- function computeStickyRowsFromCandidates(candidates, scrollTop, itemHeight, totalRowCount) {
77446
- return candidates.map((candidate, slotDepth) => {
78534
+ function computeStickyRowsFromCandidates(candidates2, scrollTop, itemHeight, totalRowCount) {
78535
+ return candidates2.map((candidate, slotDepth) => {
77447
78536
  const defaultTop = slotDepth * itemHeight;
77448
78537
  const nextBoundaryIndex = candidate.subtreeEndIndex + 1;
77449
78538
  if (nextBoundaryIndex >= totalRowCount) return {
@@ -77490,9 +78579,9 @@ function getPointElement(rootNode, clientX, clientY) {
77490
78579
  return element2 instanceof HTMLElement ? element2 : null;
77491
78580
  }
77492
78581
  function getShadowPointElementByGeometry(rootNode, clientX, clientY) {
77493
- const candidates = Array.from(rootNode.querySelectorAll('[data-type="item"], [data-item-flattened-subitem]'));
77494
- for (let index = candidates.length - 1; index >= 0; index--) {
77495
- const candidate = candidates[index];
78582
+ const candidates2 = Array.from(rootNode.querySelectorAll('[data-type="item"], [data-item-flattened-subitem]'));
78583
+ for (let index = candidates2.length - 1; index >= 0; index--) {
78584
+ const candidate = candidates2[index];
77496
78585
  const rect = candidate.getBoundingClientRect();
77497
78586
  if (clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom) return candidate;
77498
78587
  }
@@ -80010,6 +81099,8 @@ var elements = {
80010
81099
  "slicc-network": SliccNetwork,
80011
81100
  "slicc-notices": SliccNotices,
80012
81101
  "slicc-approvals": SliccApprovals,
81102
+ "slicc-secrets": SliccSecrets,
81103
+ "slicc-vault-button": SliccVaultButton,
80013
81104
  "slicc-confirm": SliccConfirm,
80014
81105
  "slicc-prompt": SliccPrompt,
80015
81106
  "slicc-app": SliccApp
@@ -80046,7 +81137,9 @@ export {
80046
81137
  SliccNetwork,
80047
81138
  SliccNotices,
80048
81139
  SliccPrompt,
81140
+ SliccSecrets,
80049
81141
  SliccUpdates,
81142
+ SliccVaultButton,
80050
81143
  confirm,
80051
81144
  define2 as define,
80052
81145
  grammarBase,