@ai-ecoverse/slicc-spectrum 1.63.0 → 1.64.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/README.md +6 -5
- package/dist/chunk-XQHRTHDQ.js +26 -0
- package/dist/chunk-XQHRTHDQ.js.map +7 -0
- package/dist/slicc-dummy.js +314 -62
- package/dist/slicc-dummy.js.map +3 -3
- package/dist/slicc-ui.js +1577 -590
- package/dist/slicc-ui.js.map +4 -4
- package/dist/types/app/composer.d.ts +16 -2
- package/dist/types/app/secrets.d.ts +87 -6
- package/dist/types/app/value-request.d.ts +47 -0
- package/dist/types/app/vault.d.ts +9 -3
- package/dist/types/dummy/vault.d.ts +36 -15
- package/dist/types/dummy.d.ts +1 -1
- package/dist/types/model/types.d.ts +112 -10
- package/dist/types/model/values.d.ts +5 -0
- package/dist/types/ui.d.ts +3 -1
- package/package.json +3 -2
package/dist/slicc-ui.js
CHANGED
|
@@ -25,6 +25,11 @@ import {
|
|
|
25
25
|
import {
|
|
26
26
|
define
|
|
27
27
|
} from "./chunk-XI74SELH.js";
|
|
28
|
+
import {
|
|
29
|
+
isVaultFailure,
|
|
30
|
+
nameProblem,
|
|
31
|
+
valueProblem
|
|
32
|
+
} from "./chunk-XQHRTHDQ.js";
|
|
28
33
|
import {
|
|
29
34
|
Emitter
|
|
30
35
|
} from "./chunk-T5NHW4KC.js";
|
|
@@ -9589,8 +9594,8 @@ function basename(path) {
|
|
|
9589
9594
|
function treePaths(entries) {
|
|
9590
9595
|
return entries.map((entry) => relative(entry.path) + (entry.kind === "directory" ? "/" : ""));
|
|
9591
9596
|
}
|
|
9592
|
-
function treeStatus(
|
|
9593
|
-
return
|
|
9597
|
+
function treeStatus(changes2) {
|
|
9598
|
+
return changes2.map((change) => ({ path: relative(change.path), status: change.status }));
|
|
9594
9599
|
}
|
|
9595
9600
|
function ancestors(paths) {
|
|
9596
9601
|
const out = /* @__PURE__ */ new Set();
|
|
@@ -9868,11 +9873,11 @@ var SliccFiles = class extends ModelElement {
|
|
|
9868
9873
|
}
|
|
9869
9874
|
#sync() {
|
|
9870
9875
|
const tree = this.#tree();
|
|
9871
|
-
const
|
|
9876
|
+
const changes2 = this.model ? changesOf(this.model).changes() : [];
|
|
9872
9877
|
if (!tree) return;
|
|
9873
|
-
if (tree.paths.length === 0) tree.expanded = ancestors(
|
|
9878
|
+
if (tree.paths.length === 0) tree.expanded = ancestors(changes2.map((change) => change.path));
|
|
9874
9879
|
tree.paths = treePaths(this.#entries);
|
|
9875
|
-
tree.gitStatus = treeStatus(
|
|
9880
|
+
tree.gitStatus = treeStatus(changes2);
|
|
9876
9881
|
this.#show();
|
|
9877
9882
|
if (this.#pending) {
|
|
9878
9883
|
this.#pending = false;
|
|
@@ -11726,8 +11731,8 @@ var QrSegment = class {
|
|
|
11726
11731
|
// Creates a new QR Code segment with the given attributes and data.
|
|
11727
11732
|
// The character count (numChars) must agree with the mode and the bit buffer length,
|
|
11728
11733
|
// but the constraint isn't checked. The given bit buffer is cloned and stored.
|
|
11729
|
-
constructor(
|
|
11730
|
-
this.mode =
|
|
11734
|
+
constructor(mode2, numChars, bitData) {
|
|
11735
|
+
this.mode = mode2;
|
|
11731
11736
|
this.numChars = numChars;
|
|
11732
11737
|
this.bitData = bitData;
|
|
11733
11738
|
if (numChars < 0)
|
|
@@ -11743,8 +11748,8 @@ var QrSegment = class {
|
|
|
11743
11748
|
var MODE_NUMERIC = [1, 10, 12, 14];
|
|
11744
11749
|
var MODE_ALPHANUMERIC = [2, 9, 11, 13];
|
|
11745
11750
|
var MODE_BYTE = [4, 8, 16, 16];
|
|
11746
|
-
function numCharCountBits(
|
|
11747
|
-
return
|
|
11751
|
+
function numCharCountBits(mode2, ver) {
|
|
11752
|
+
return mode2[Math.floor((ver + 7) / 17) + 1];
|
|
11748
11753
|
}
|
|
11749
11754
|
function makeBytes(data) {
|
|
11750
11755
|
const bb = [];
|
|
@@ -12273,14 +12278,14 @@ function networkStatus(port) {
|
|
|
12273
12278
|
}
|
|
12274
12279
|
function remoteLight(status2) {
|
|
12275
12280
|
const devices = status2?.links?.devices ?? [];
|
|
12276
|
-
const
|
|
12281
|
+
const asking3 = devices.filter((device) => device.asking);
|
|
12277
12282
|
const prompting = devices.filter((device) => device.controlling === "prompt");
|
|
12278
12283
|
const watching = devices.filter((device) => device.controlling === "watch");
|
|
12279
12284
|
const shells = devices.filter((device) => device.terminals);
|
|
12280
|
-
if (!
|
|
12285
|
+
if (!asking3.length && !prompting.length && !watching.length && !shells.length) return null;
|
|
12281
12286
|
const tooltip = [
|
|
12282
12287
|
...say(
|
|
12283
|
-
|
|
12288
|
+
asking3,
|
|
12284
12289
|
(device) => `${device.name} asks to follow this SLICC. Allow it in Linked devices.`,
|
|
12285
12290
|
"devices ask to follow this SLICC. Allow them in Linked devices."
|
|
12286
12291
|
),
|
|
@@ -12301,8 +12306,8 @@ function remoteLight(status2) {
|
|
|
12301
12306
|
)
|
|
12302
12307
|
].join(" ");
|
|
12303
12308
|
const by = (list5) => list5.length === 1 ? list5[0].name : `${list5.length} linked devices`;
|
|
12304
|
-
if (
|
|
12305
|
-
const text2 =
|
|
12309
|
+
if (asking3.length) {
|
|
12310
|
+
const text2 = asking3.length === 1 ? `${asking3[0].name} asks to follow` : `${asking3.length} devices ask to follow`;
|
|
12306
12311
|
return { mode: "ask", variant: "notice", text: text2, tooltip };
|
|
12307
12312
|
}
|
|
12308
12313
|
if (prompting.length)
|
|
@@ -22036,11 +22041,11 @@ var SliccUpdates = class extends ModelElement {
|
|
|
22036
22041
|
</p>`;
|
|
22037
22042
|
}
|
|
22038
22043
|
const version2 = item2.version === null ? item2.offered : item2.offered && item2.offered !== item2.version ? `${item2.version} \u2192 ${item2.offered}` : item2.version;
|
|
22039
|
-
const
|
|
22044
|
+
const download2 = item2.size !== void 0 && (item2.version === null || item2.offered !== item2.version);
|
|
22040
22045
|
const requires = requiresText(item2, all2);
|
|
22041
22046
|
return b`<p class="meta">
|
|
22042
22047
|
${version2 ? b`<span class="version">${version2}</span>` : A}
|
|
22043
|
-
${
|
|
22048
|
+
${download2 ? b`<span>${size3(item2.size)}</span>` : A}
|
|
22044
22049
|
${requires ? b`<span data-requires>${requires}</span>` : A}
|
|
22045
22050
|
</p>`;
|
|
22046
22051
|
}
|
|
@@ -22804,13 +22809,13 @@ var SliccApp = class extends ThemedElement {
|
|
|
22804
22809
|
this.#detach(id, null, false);
|
|
22805
22810
|
}
|
|
22806
22811
|
#railButton(item2, side) {
|
|
22807
|
-
const
|
|
22812
|
+
const changes2 = item2.id === "changes" ? this.#changes() : 0;
|
|
22808
22813
|
const driven = item2.id === "browser" && !!this.model?.browser.list().some((tab) => tab.controlled);
|
|
22809
22814
|
const visible2 = shown(this.dock, item2.id);
|
|
22810
|
-
const label = `${visible2 ? `${item2.title}, shown` : `Open ${item2.title}`}${
|
|
22815
|
+
const label = `${visible2 ? `${item2.title}, shown` : `Open ${item2.title}`}${changes2 ? `, ${changeCount(changes2)}` : driven ? ", a tab is in use" : ""}`;
|
|
22811
22816
|
const button = u16`<swc-action-button id=${`rail-${item2.id}`} class=${visible2 ? "selected" : ""} quiet size="m" accessible-label=${label} data-surface=${item2.id} data-cone=${o2(item2.cone)} ?data-visible=${visible2} @click=${() => this.show(item2.id)}>${railIcon(item2.icon)}</swc-action-button>`;
|
|
22812
22817
|
const tooltip = b`<swc-tooltip for=${`rail-${item2.id}`} placement=${{ left: "end", right: "start", bottom: "top" }[side]}>${item2.title}</swc-tooltip>`;
|
|
22813
|
-
return
|
|
22818
|
+
return changes2 ? b`<span class="badged">${button}<swc-badge size="s" variant="neutral" aria-hidden="true">${changes2}</swc-badge></span>${tooltip}` : driven ? b`<span class="badged">${button}<span class="dot" data-driven aria-hidden="true"></span></span>${tooltip}` : b`${button}${tooltip}`;
|
|
22814
22819
|
}
|
|
22815
22820
|
#changes() {
|
|
22816
22821
|
const port = this.model ? changesOf(this.model) : null;
|
|
@@ -22818,13 +22823,13 @@ var SliccApp = class extends ThemedElement {
|
|
|
22818
22823
|
}
|
|
22819
22824
|
#more(items) {
|
|
22820
22825
|
if (!items.length) return A;
|
|
22821
|
-
const
|
|
22822
|
-
const label =
|
|
22826
|
+
const changes2 = items.some((item2) => item2.id === "changes") ? this.#changes() : 0;
|
|
22827
|
+
const label = changes2 ? `More panels, ${changeCount(changes2)}` : "More panels";
|
|
22823
22828
|
const menu = u16`<sp-action-menu quiet size="m" label=${label} placement="top-end" @change=${(event2) => this.show(event2.target.value)}>
|
|
22824
22829
|
<swc-icon-more slot="icon"></swc-icon-more>
|
|
22825
22830
|
${items.map((item2) => u16`<sp-menu-item value=${item2.id}>${railIcon(item2.icon)}${item2.title}</sp-menu-item>`)}
|
|
22826
22831
|
</sp-action-menu>`;
|
|
22827
|
-
return
|
|
22832
|
+
return changes2 ? b`<span class="badged">${menu}<swc-badge size="s" variant="neutral" aria-hidden="true">${changes2}</swc-badge></span>` : menu;
|
|
22828
22833
|
}
|
|
22829
22834
|
#rail(items, side) {
|
|
22830
22835
|
const primary = side === "bottom" ? items.filter((item2) => phoneRail.includes(item2.id)) : items;
|
|
@@ -23058,6 +23063,7 @@ var SliccApp = class extends ThemedElement {
|
|
|
23058
23063
|
${rails.bottom}
|
|
23059
23064
|
</div>
|
|
23060
23065
|
<slicc-approvals .model=${this.model}></slicc-approvals>
|
|
23066
|
+
<slicc-value-request .model=${this.model}></slicc-value-request>
|
|
23061
23067
|
</sp-theme></div>`;
|
|
23062
23068
|
}
|
|
23063
23069
|
};
|
|
@@ -24813,9 +24819,9 @@ function where(change) {
|
|
|
24813
24819
|
if (at === change.repo) return "";
|
|
24814
24820
|
return at.startsWith(`${change.repo}/`) ? at.slice(change.repo.length + 1) : at;
|
|
24815
24821
|
}
|
|
24816
|
-
function lost(
|
|
24817
|
-
const kind =
|
|
24818
|
-
return `${
|
|
24822
|
+
function lost(changes2) {
|
|
24823
|
+
const kind = changes2.every((change) => change.repo) ? "uncommitted" : "pending";
|
|
24824
|
+
return `${changes2.length === 1 ? "Its" : "Their"} ${kind} changes are discarded and can\u2019t be undone.`;
|
|
24819
24825
|
}
|
|
24820
24826
|
var confirmRevert = (change) => confirm({ title: `Revert ${basename(change.path)}?`, body: lost([change]), action: "Revert" });
|
|
24821
24827
|
async function revertPaths(port, paths) {
|
|
@@ -24830,9 +24836,9 @@ async function revertPaths(port, paths) {
|
|
|
24830
24836
|
if (errors.length > 1) return `Couldn\u2019t revert ${errors.length} files. ${errors[0]}`;
|
|
24831
24837
|
return errors[0] ?? "";
|
|
24832
24838
|
}
|
|
24833
|
-
function groups(
|
|
24839
|
+
function groups(changes2) {
|
|
24834
24840
|
const byRepo = /* @__PURE__ */ new Map();
|
|
24835
|
-
for (const change of
|
|
24841
|
+
for (const change of changes2) {
|
|
24836
24842
|
const key2 = change.repo ?? "";
|
|
24837
24843
|
byRepo.set(key2, [...byRepo.get(key2) ?? [], change]);
|
|
24838
24844
|
}
|
|
@@ -25003,18 +25009,18 @@ var SliccChanges = class extends ModelElement {
|
|
|
25003
25009
|
}
|
|
25004
25010
|
async #all(action) {
|
|
25005
25011
|
const port = this.#port();
|
|
25006
|
-
const
|
|
25012
|
+
const changes2 = port.changes();
|
|
25007
25013
|
this.error = "";
|
|
25008
25014
|
if (action === "accept") {
|
|
25009
|
-
for (const change of
|
|
25015
|
+
for (const change of changes2) port.accept(change.path);
|
|
25010
25016
|
return;
|
|
25011
25017
|
}
|
|
25012
|
-
const count =
|
|
25018
|
+
const count = changes2.length;
|
|
25013
25019
|
const title = `Revert ${count} ${count === 1 ? "change" : "changes"}?`;
|
|
25014
|
-
if (await confirm({ title, body: lost(
|
|
25020
|
+
if (await confirm({ title, body: lost(changes2), action: "Revert all" }))
|
|
25015
25021
|
this.error = await revertPaths(
|
|
25016
25022
|
port,
|
|
25017
|
-
|
|
25023
|
+
changes2.map((change) => change.path)
|
|
25018
25024
|
);
|
|
25019
25025
|
}
|
|
25020
25026
|
#keydown(event2) {
|
|
@@ -25069,10 +25075,10 @@ var SliccChanges = class extends ModelElement {
|
|
|
25069
25075
|
</span>
|
|
25070
25076
|
</li>`;
|
|
25071
25077
|
}
|
|
25072
|
-
#list(
|
|
25073
|
-
const grouped = groups(
|
|
25078
|
+
#list(changes2) {
|
|
25079
|
+
const grouped = groups(changes2);
|
|
25074
25080
|
if (grouped.length === 1 && !grouped[0][0])
|
|
25075
|
-
return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${
|
|
25081
|
+
return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${changes2.map((change) => this.#row(change))}</ul>`;
|
|
25076
25082
|
return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${grouped.map(
|
|
25077
25083
|
([repo, items]) => b`<li data-repo=${repo}>
|
|
25078
25084
|
<div class="repo" title=${repo}>
|
|
@@ -25112,15 +25118,15 @@ var SliccChanges = class extends ModelElement {
|
|
|
25112
25118
|
const port = this.model ? changesOf(this.model) : null;
|
|
25113
25119
|
const unavailable = port?.unavailable?.() ?? null;
|
|
25114
25120
|
if (unavailable) return this.#unavailable(unavailable);
|
|
25115
|
-
const
|
|
25121
|
+
const changes2 = port?.changes() ?? [];
|
|
25116
25122
|
return b`<div class="bar">
|
|
25117
|
-
<span class="summary">${
|
|
25123
|
+
<span class="summary">${changes2.length} pending ${changes2.length === 1 ? "change" : "changes"}</span>
|
|
25118
25124
|
<span class="spacer"></span>
|
|
25119
|
-
${
|
|
25125
|
+
${changes2.length ? b`<swc-action-button size="s" quiet @click=${() => this.#all("accept")}>Accept all</swc-action-button>
|
|
25120
25126
|
<swc-action-button size="s" quiet @click=${() => this.#all("revert")}>Revert all</swc-action-button>` : A}
|
|
25121
25127
|
</div>
|
|
25122
25128
|
${errorLine(this.error)}
|
|
25123
|
-
${
|
|
25129
|
+
${changes2.length ? this.#list(changes2) : b`<div class="note">No pending changes. Edits by agents show up here for review.</div>`}`;
|
|
25124
25130
|
}
|
|
25125
25131
|
};
|
|
25126
25132
|
var SliccDiffPanel = class extends ThemedElement {
|
|
@@ -26530,6 +26536,286 @@ var o84 = class extends a10 {
|
|
|
26530
26536
|
};
|
|
26531
26537
|
e25("swc-icon-clock", o84);
|
|
26532
26538
|
|
|
26539
|
+
// src/app/vault.ts
|
|
26540
|
+
var exitNames = {
|
|
26541
|
+
page: "This page",
|
|
26542
|
+
proxy: "Local proxy",
|
|
26543
|
+
"vault-direct": "Straight from the vault",
|
|
26544
|
+
"local-proxy": "Local proxy",
|
|
26545
|
+
"cli-v": "Local SLICC, direct",
|
|
26546
|
+
tailscale: "Tailscale",
|
|
26547
|
+
"local-link": "Linked SLICC, through this page"
|
|
26548
|
+
};
|
|
26549
|
+
function devicesOf(model) {
|
|
26550
|
+
return model?.network?.status().links?.devices ?? [];
|
|
26551
|
+
}
|
|
26552
|
+
function deviceName2(id, devices) {
|
|
26553
|
+
return (devices.find((device) => device.id === id)?.name ?? id).replace(/^slicc\b/i, "SLICC");
|
|
26554
|
+
}
|
|
26555
|
+
function exitLabel(exit, devices) {
|
|
26556
|
+
if (exit.startsWith("device:")) return deviceName2(exit.slice("device:".length), devices);
|
|
26557
|
+
return exitNames[exit];
|
|
26558
|
+
}
|
|
26559
|
+
function list4(items) {
|
|
26560
|
+
if (items.length < 2) return items.join("");
|
|
26561
|
+
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
26562
|
+
}
|
|
26563
|
+
function ruleLine(rule) {
|
|
26564
|
+
const methods = rule.methods.length ? rule.methods.join(" or ") : "any method";
|
|
26565
|
+
const paths = rule.paths.length ? rule.paths.join(" or ") : "any path";
|
|
26566
|
+
return `${rule.domain}, in ${rule.header}, ${methods}, ${paths}`;
|
|
26567
|
+
}
|
|
26568
|
+
function shellWord(word) {
|
|
26569
|
+
return /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replace(/'/g, "'\\''")}'`;
|
|
26570
|
+
}
|
|
26571
|
+
function execLine(exec, argv = []) {
|
|
26572
|
+
if (typeof exec === "object") return execLine("argv", exec.argv);
|
|
26573
|
+
if (exec === "any" || exec === true) return "Revealed to any command";
|
|
26574
|
+
if (exec === "shell") return "Revealed in every bash";
|
|
26575
|
+
if (exec === false) return null;
|
|
26576
|
+
if (!argv.length) return "Revealed only to listed commands";
|
|
26577
|
+
return `Revealed only to ${list4(argv.map((words) => words.map(shellWord).join(" ")))}`;
|
|
26578
|
+
}
|
|
26579
|
+
function lower(line) {
|
|
26580
|
+
return `${line[0].toLowerCase()}${line.slice(1)}`;
|
|
26581
|
+
}
|
|
26582
|
+
function mode(exec) {
|
|
26583
|
+
return lower(execLine(exec) ?? "Never revealed to commands");
|
|
26584
|
+
}
|
|
26585
|
+
function changeLine(change, devices) {
|
|
26586
|
+
switch (change.kind) {
|
|
26587
|
+
case "rule":
|
|
26588
|
+
return `${change.secret} ${change.change === "added" ? "may now" : "may no longer"} be sent to ${ruleLine(change.rule)}`;
|
|
26589
|
+
case "exec":
|
|
26590
|
+
return `${change.secret} was ${mode(change.from)}, now ${mode(change.to)}`;
|
|
26591
|
+
case "exits":
|
|
26592
|
+
if (change.to?.length === 0) return `${change.secret} now has no exit`;
|
|
26593
|
+
return `${change.secret} now leaves through ${change.to ? list4(change.to.map((exit) => exitLabel(exit, devices))) : "any exit"}`;
|
|
26594
|
+
default:
|
|
26595
|
+
return `The limit ${change.field} changed from ${change.from} to ${change.to}`;
|
|
26596
|
+
}
|
|
26597
|
+
}
|
|
26598
|
+
var codeTexts = {
|
|
26599
|
+
EACCES: "Unlock the vault first",
|
|
26600
|
+
ENOTSUP: "This arrives with a later vault version"
|
|
26601
|
+
};
|
|
26602
|
+
function widening(change, devices) {
|
|
26603
|
+
switch (change.kind) {
|
|
26604
|
+
case "rule":
|
|
26605
|
+
return `${change.secret} may now be sent to ${ruleLine(change.rule)}`;
|
|
26606
|
+
case "methods":
|
|
26607
|
+
return `${change.secret} may now use ${list4(change.methods)} on ${change.domain}`;
|
|
26608
|
+
case "paths":
|
|
26609
|
+
return `${change.secret} may now reach ${list4(change.paths)} on ${change.domain}`;
|
|
26610
|
+
case "exec":
|
|
26611
|
+
return `${change.secret} is now ${mode(change.grant)}`;
|
|
26612
|
+
case "exit":
|
|
26613
|
+
return `${change.secret} may now leave through ${exitLabel(change.exit, devices)}`;
|
|
26614
|
+
default:
|
|
26615
|
+
return `The limit ${change.field} rose from ${change.from} to ${change.to}`;
|
|
26616
|
+
}
|
|
26617
|
+
}
|
|
26618
|
+
function failureText(error) {
|
|
26619
|
+
const text2 = isVaultFailure(error) ? codeTexts[error.code] : void 0;
|
|
26620
|
+
return text2 ?? (error instanceof Error ? error.message : "The vault did not answer");
|
|
26621
|
+
}
|
|
26622
|
+
function fieldOf(error, field) {
|
|
26623
|
+
return isVaultFailure(error) && error.code === "EINVAL" ? field : null;
|
|
26624
|
+
}
|
|
26625
|
+
function away(vault) {
|
|
26626
|
+
const state3 = vault.availability?.() ?? (vault.status() ? "ready" : "waiting");
|
|
26627
|
+
return state3 === "connecting" || state3 === "waiting";
|
|
26628
|
+
}
|
|
26629
|
+
function take(input) {
|
|
26630
|
+
const value = input.value;
|
|
26631
|
+
input.value = "";
|
|
26632
|
+
return value;
|
|
26633
|
+
}
|
|
26634
|
+
function clearValues(root2) {
|
|
26635
|
+
for (const input of root2.querySelectorAll("input[type=password]"))
|
|
26636
|
+
input.value = "";
|
|
26637
|
+
}
|
|
26638
|
+
var fieldStyles = i`
|
|
26639
|
+
.field {
|
|
26640
|
+
display: grid;
|
|
26641
|
+
gap: var(--swc-spacing-75);
|
|
26642
|
+
min-width: 0;
|
|
26643
|
+
}
|
|
26644
|
+
.field > span {
|
|
26645
|
+
font-size: var(--swc-font-size-75);
|
|
26646
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
26647
|
+
}
|
|
26648
|
+
.field input:not([type='checkbox']) {
|
|
26649
|
+
box-sizing: border-box;
|
|
26650
|
+
inline-size: 100%;
|
|
26651
|
+
font: inherit;
|
|
26652
|
+
min-height: var(--swc-component-height-100);
|
|
26653
|
+
padding: 0 var(--swc-spacing-100);
|
|
26654
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-400);
|
|
26655
|
+
border-radius: var(--swc-corner-radius-small-default);
|
|
26656
|
+
background: var(--swc-background-layer-2-color);
|
|
26657
|
+
color: inherit;
|
|
26658
|
+
}
|
|
26659
|
+
.field input[aria-invalid='true'] {
|
|
26660
|
+
border-color: var(--swc-negative-border-color-default);
|
|
26661
|
+
}
|
|
26662
|
+
.field input[type='file'] {
|
|
26663
|
+
padding: var(--swc-spacing-75) var(--swc-spacing-100);
|
|
26664
|
+
}
|
|
26665
|
+
.field input[type='file']::file-selector-button {
|
|
26666
|
+
font: inherit;
|
|
26667
|
+
font-weight: var(--swc-bold-font-weight);
|
|
26668
|
+
margin-inline-end: var(--swc-spacing-200);
|
|
26669
|
+
padding: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
26670
|
+
border: none;
|
|
26671
|
+
border-radius: var(--swc-corner-radius-full);
|
|
26672
|
+
background: var(--swc-gray-200);
|
|
26673
|
+
color: inherit;
|
|
26674
|
+
}
|
|
26675
|
+
.field input:focus-visible,
|
|
26676
|
+
input[type='checkbox']:focus-visible {
|
|
26677
|
+
outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
|
|
26678
|
+
outline-offset: var(--swc-focus-ring-gap);
|
|
26679
|
+
}
|
|
26680
|
+
`;
|
|
26681
|
+
function shown2(element2, style = getComputedStyle(element2)) {
|
|
26682
|
+
return !element2.hidden && !element2.inert && style.display !== "none";
|
|
26683
|
+
}
|
|
26684
|
+
function disabled(element2) {
|
|
26685
|
+
if (element2.matches(":disabled")) return true;
|
|
26686
|
+
if (!element2.matches("button, input, select, textarea")) return false;
|
|
26687
|
+
let fieldset = element2.closest("fieldset[disabled]");
|
|
26688
|
+
while (fieldset) {
|
|
26689
|
+
if (!fieldset.querySelector(":scope > legend")?.contains(element2)) return true;
|
|
26690
|
+
fieldset = fieldset.parentElement?.closest("fieldset[disabled]") ?? null;
|
|
26691
|
+
}
|
|
26692
|
+
return false;
|
|
26693
|
+
}
|
|
26694
|
+
function reachable(element2) {
|
|
26695
|
+
const radio = element2;
|
|
26696
|
+
if (radio.localName !== "input" || radio.type !== "radio" || !radio.name) return true;
|
|
26697
|
+
const root2 = radio.getRootNode();
|
|
26698
|
+
const group = Array.from(root2.querySelectorAll("input[type=radio]")).filter(
|
|
26699
|
+
(other) => other.name === radio.name && other.form === radio.form
|
|
26700
|
+
);
|
|
26701
|
+
const checked = group.find((other) => other.checked);
|
|
26702
|
+
return checked ? checked === radio : radio === group[0] || radio === group.at(-1);
|
|
26703
|
+
}
|
|
26704
|
+
function tabbables(root2, stop, out = []) {
|
|
26705
|
+
for (const child of Array.from(root2.children)) {
|
|
26706
|
+
if (child === stop) {
|
|
26707
|
+
out.push(null);
|
|
26708
|
+
continue;
|
|
26709
|
+
}
|
|
26710
|
+
const style = getComputedStyle(child);
|
|
26711
|
+
if (!shown2(child, style)) continue;
|
|
26712
|
+
if (child.localName === "details" && !child.open) {
|
|
26713
|
+
const summary = child.querySelector(":scope > summary");
|
|
26714
|
+
if (summary && shown2(summary) && getComputedStyle(summary).visibility !== "hidden" && !(summary.hasAttribute("tabindex") && summary.tabIndex < 0))
|
|
26715
|
+
out.push(summary);
|
|
26716
|
+
continue;
|
|
26717
|
+
}
|
|
26718
|
+
if (child.tabIndex >= 0 && !disabled(child) && style.visibility !== "hidden" && reachable(child))
|
|
26719
|
+
out.push(child);
|
|
26720
|
+
if (child.shadowRoot) tabbables(child.shadowRoot, stop, out);
|
|
26721
|
+
tabbables(child, stop, out);
|
|
26722
|
+
}
|
|
26723
|
+
return out;
|
|
26724
|
+
}
|
|
26725
|
+
function sequential(order) {
|
|
26726
|
+
const rank = (element2) => element2 && element2.tabIndex > 0 ? element2.tabIndex : Number.POSITIVE_INFINITY;
|
|
26727
|
+
return [...order].sort((a22, b13) => rank(a22) - rank(b13) || 0);
|
|
26728
|
+
}
|
|
26729
|
+
var SliccVaultButton = class extends i2 {
|
|
26730
|
+
static properties = {
|
|
26731
|
+
vault: { attribute: false },
|
|
26732
|
+
config: { attribute: false }
|
|
26733
|
+
};
|
|
26734
|
+
#button = null;
|
|
26735
|
+
#off = null;
|
|
26736
|
+
#ready = false;
|
|
26737
|
+
#sent = "";
|
|
26738
|
+
static styles = i`
|
|
26739
|
+
:host {
|
|
26740
|
+
display: inline-flex;
|
|
26741
|
+
vertical-align: middle;
|
|
26742
|
+
}
|
|
26743
|
+
iframe {
|
|
26744
|
+
border: 0;
|
|
26745
|
+
background: transparent;
|
|
26746
|
+
color-scheme: normal;
|
|
26747
|
+
}
|
|
26748
|
+
`;
|
|
26749
|
+
constructor() {
|
|
26750
|
+
super();
|
|
26751
|
+
this.vault = null;
|
|
26752
|
+
this.config = null;
|
|
26753
|
+
}
|
|
26754
|
+
connectedCallback() {
|
|
26755
|
+
super.connectedCallback();
|
|
26756
|
+
this.requestUpdate();
|
|
26757
|
+
}
|
|
26758
|
+
disconnectedCallback() {
|
|
26759
|
+
super.disconnectedCallback();
|
|
26760
|
+
this.#drop();
|
|
26761
|
+
}
|
|
26762
|
+
focus() {
|
|
26763
|
+
this.#button?.post({ type: "slicc-vault", v: 1, op: "focus" });
|
|
26764
|
+
}
|
|
26765
|
+
updated(changed) {
|
|
26766
|
+
if (changed.has("vault")) this.#drop();
|
|
26767
|
+
if (!this.#button && this.vault) this.#mount(this.vault);
|
|
26768
|
+
this.#send();
|
|
26769
|
+
}
|
|
26770
|
+
#mount(vault) {
|
|
26771
|
+
const button = vault.button();
|
|
26772
|
+
this.#button = button;
|
|
26773
|
+
this.#off = button.listen((event2) => this.#event(event2));
|
|
26774
|
+
this.renderRoot.append(button.element);
|
|
26775
|
+
}
|
|
26776
|
+
#drop() {
|
|
26777
|
+
this.#off?.();
|
|
26778
|
+
this.#button?.element.remove();
|
|
26779
|
+
this.#button = null;
|
|
26780
|
+
this.#off = null;
|
|
26781
|
+
this.#ready = false;
|
|
26782
|
+
this.#sent = "";
|
|
26783
|
+
}
|
|
26784
|
+
#send() {
|
|
26785
|
+
if (!(this.#ready && this.#button && this.config)) return;
|
|
26786
|
+
const sent = JSON.stringify(this.config);
|
|
26787
|
+
if (sent === this.#sent) return;
|
|
26788
|
+
this.#sent = sent;
|
|
26789
|
+
this.#button.post({ type: "slicc-vault", v: 1, op: "button", button: this.config });
|
|
26790
|
+
}
|
|
26791
|
+
#event(event2) {
|
|
26792
|
+
const element2 = this.#button?.element;
|
|
26793
|
+
if (event2.event === "ready") {
|
|
26794
|
+
this.#ready = true;
|
|
26795
|
+
this.#send();
|
|
26796
|
+
} else if (event2.event === "size") {
|
|
26797
|
+
element2.style.width = `${event2.width}px`;
|
|
26798
|
+
element2.style.height = `${event2.height}px`;
|
|
26799
|
+
element2.style.margin = `${-event2.inset}px`;
|
|
26800
|
+
} else if (event2.event === "label") {
|
|
26801
|
+
element2.title = event2.label;
|
|
26802
|
+
} else if (event2.event === "focus") {
|
|
26803
|
+
const order = sequential(tabbables(this.ownerDocument, this));
|
|
26804
|
+
const at = order.indexOf(null);
|
|
26805
|
+
order[event2.direction === "next" ? at + 1 : at - 1]?.focus();
|
|
26806
|
+
} else if (event2.event === "popup") {
|
|
26807
|
+
const { intent, state: state3 } = event2;
|
|
26808
|
+
this.dispatchEvent(
|
|
26809
|
+
new CustomEvent("vault-popup", {
|
|
26810
|
+
detail: { intent, state: state3 },
|
|
26811
|
+
bubbles: true,
|
|
26812
|
+
composed: true
|
|
26813
|
+
})
|
|
26814
|
+
);
|
|
26815
|
+
}
|
|
26816
|
+
}
|
|
26817
|
+
};
|
|
26818
|
+
|
|
26533
26819
|
// src/app/composer.ts
|
|
26534
26820
|
var limit = 25 * 1024 * 1024;
|
|
26535
26821
|
function available(model) {
|
|
@@ -26619,6 +26905,10 @@ function trigger(text2, caret) {
|
|
|
26619
26905
|
return { kind: "mention", start: before.length - mention[2].length - 1, query: mention[2] };
|
|
26620
26906
|
return null;
|
|
26621
26907
|
}
|
|
26908
|
+
function blocked(vault) {
|
|
26909
|
+
if (away(vault)) return "Waiting for the vault";
|
|
26910
|
+
return vault.status()?.locked ? "Unlock the vault first" : null;
|
|
26911
|
+
}
|
|
26622
26912
|
var SliccComposer = class extends ThemedElement {
|
|
26623
26913
|
static properties = {
|
|
26624
26914
|
...ThemedElement.properties,
|
|
@@ -26627,6 +26917,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26627
26917
|
popup: { state: true },
|
|
26628
26918
|
dictating: { state: true },
|
|
26629
26919
|
blocked: { state: true },
|
|
26920
|
+
sharing: { state: true },
|
|
26921
|
+
secretError: { state: true },
|
|
26922
|
+
secretField: { state: true },
|
|
26630
26923
|
agent: {}
|
|
26631
26924
|
};
|
|
26632
26925
|
#drafts = /* @__PURE__ */ new Map();
|
|
@@ -26643,6 +26936,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26643
26936
|
this.popup = null;
|
|
26644
26937
|
this.dictating = false;
|
|
26645
26938
|
this.blocked = false;
|
|
26939
|
+
this.sharing = false;
|
|
26940
|
+
this.secretError = null;
|
|
26941
|
+
this.secretField = null;
|
|
26646
26942
|
this.agent = "";
|
|
26647
26943
|
}
|
|
26648
26944
|
static styles = [
|
|
@@ -26849,6 +27145,14 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26849
27145
|
gap: var(--swc-spacing-100);
|
|
26850
27146
|
padding: var(--swc-spacing-100);
|
|
26851
27147
|
}
|
|
27148
|
+
.secret .field {
|
|
27149
|
+
display: grid;
|
|
27150
|
+
gap: var(--swc-spacing-75);
|
|
27151
|
+
}
|
|
27152
|
+
.secret .field > span {
|
|
27153
|
+
font-size: var(--swc-font-size-75);
|
|
27154
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
27155
|
+
}
|
|
26852
27156
|
.secret input {
|
|
26853
27157
|
font: inherit;
|
|
26854
27158
|
min-height: var(--swc-component-height-100);
|
|
@@ -26858,6 +27162,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26858
27162
|
background: var(--swc-background-layer-2-color);
|
|
26859
27163
|
color: inherit;
|
|
26860
27164
|
}
|
|
27165
|
+
.secret input[aria-invalid='true'] {
|
|
27166
|
+
border-color: var(--swc-negative-border-color-default);
|
|
27167
|
+
}
|
|
26861
27168
|
.secret input:focus-visible {
|
|
26862
27169
|
outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
|
|
26863
27170
|
outline-offset: var(--swc-focus-ring-gap);
|
|
@@ -26865,6 +27172,14 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26865
27172
|
.secret swc-button {
|
|
26866
27173
|
justify-self: start;
|
|
26867
27174
|
}
|
|
27175
|
+
.secret-error {
|
|
27176
|
+
display: flex;
|
|
27177
|
+
align-items: flex-start;
|
|
27178
|
+
gap: var(--swc-spacing-75);
|
|
27179
|
+
color: var(--swc-negative-content-color-default);
|
|
27180
|
+
font-size: var(--swc-font-size-75);
|
|
27181
|
+
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
27182
|
+
}
|
|
26868
27183
|
sp-menu {
|
|
26869
27184
|
min-width: 240px;
|
|
26870
27185
|
}
|
|
@@ -26875,6 +27190,7 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26875
27190
|
];
|
|
26876
27191
|
willUpdate(changed) {
|
|
26877
27192
|
super.willUpdate(changed);
|
|
27193
|
+
if (changed.has("popup") && this.popup?.kind !== "secret") clearValues(this.renderRoot);
|
|
26878
27194
|
if (changed.has("agent") && this.agent && this.model && this.agent !== this.#agent) {
|
|
26879
27195
|
this.#switch(this.agent);
|
|
26880
27196
|
}
|
|
@@ -26886,6 +27202,10 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26886
27202
|
firstUpdated() {
|
|
26887
27203
|
this.#wire();
|
|
26888
27204
|
}
|
|
27205
|
+
disconnectedCallback() {
|
|
27206
|
+
super.disconnectedCallback();
|
|
27207
|
+
clearValues(this.renderRoot);
|
|
27208
|
+
}
|
|
26889
27209
|
updated(changed) {
|
|
26890
27210
|
if (changed.has("popup"))
|
|
26891
27211
|
this.renderRoot.querySelector('.item[aria-selected="true"]')?.scrollIntoView({ block: "nearest" });
|
|
@@ -26919,7 +27239,8 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26919
27239
|
model.agent.on("messages", update),
|
|
26920
27240
|
model.agent.on("message", update),
|
|
26921
27241
|
model.settings.on("settings", update),
|
|
26922
|
-
...model.follow ? [model.follow.on("follow", update)] : []
|
|
27242
|
+
...model.follow ? [model.follow.on("follow", update)] : [],
|
|
27243
|
+
...model.vault ? [model.vault.on("availability", update), model.vault.on("status", update)] : []
|
|
26923
27244
|
];
|
|
26924
27245
|
}
|
|
26925
27246
|
#held() {
|
|
@@ -26954,7 +27275,7 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26954
27275
|
#busy() {
|
|
26955
27276
|
return this.model?.agent.busy(this.#agent) ?? false;
|
|
26956
27277
|
}
|
|
26957
|
-
send(
|
|
27278
|
+
send(mode2 = "send") {
|
|
26958
27279
|
const model = this.model;
|
|
26959
27280
|
const text2 = this.value.trim();
|
|
26960
27281
|
const attachments = this.attachments.filter((attachment2) => !attachment2.error);
|
|
@@ -26970,7 +27291,7 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26970
27291
|
return;
|
|
26971
27292
|
}
|
|
26972
27293
|
const busy = this.#busy();
|
|
26973
|
-
const resolved =
|
|
27294
|
+
const resolved = mode2 === "queue" ? busy ? "queue" : "send" : busy || mode2 === "steer" ? "steer" : "send";
|
|
26974
27295
|
void model.agent.send(this.#agent, { text: text2, attachments, mode: resolved });
|
|
26975
27296
|
}
|
|
26976
27297
|
#id() {
|
|
@@ -27035,9 +27356,17 @@ var SliccComposer = class extends ThemedElement {
|
|
|
27035
27356
|
text2 === null || text2 === void 0 ? { ...base, kind: "file", size: 0, error: "Could not read the file" } : { ...base, kind: "text", size: text2.length, text: text2 }
|
|
27036
27357
|
];
|
|
27037
27358
|
}
|
|
27038
|
-
shareSecret(name) {
|
|
27359
|
+
async shareSecret(name, field = null) {
|
|
27039
27360
|
const clean = name.trim().toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
27040
|
-
if (
|
|
27361
|
+
if (this.sharing) return;
|
|
27362
|
+
if (!clean) {
|
|
27363
|
+
if (field) this.#refuse("Enter a name", "name", true);
|
|
27364
|
+
return;
|
|
27365
|
+
}
|
|
27366
|
+
const value = field ? take(field) : "";
|
|
27367
|
+
const vault = this.model?.vault;
|
|
27368
|
+
if (field && vault?.put && !await this.#store(vault, clean, value)) return;
|
|
27369
|
+
this.#refuse(null);
|
|
27041
27370
|
this.attachments = [
|
|
27042
27371
|
...this.attachments,
|
|
27043
27372
|
{
|
|
@@ -27050,6 +27379,51 @@ var SliccComposer = class extends ThemedElement {
|
|
|
27050
27379
|
];
|
|
27051
27380
|
this.popup = null;
|
|
27052
27381
|
}
|
|
27382
|
+
#refuse(text2, field = null, focus = false) {
|
|
27383
|
+
this.secretError = text2;
|
|
27384
|
+
this.secretField = text2 ? field : null;
|
|
27385
|
+
if (focus && text2 && field)
|
|
27386
|
+
void this.updateComplete.then(
|
|
27387
|
+
() => this.renderRoot.querySelector(`form.secret input[name=${field}]`)?.focus()
|
|
27388
|
+
);
|
|
27389
|
+
}
|
|
27390
|
+
async #store(vault, clean, value) {
|
|
27391
|
+
if (blocked(vault)) {
|
|
27392
|
+
this.#refuse(blocked(vault));
|
|
27393
|
+
return false;
|
|
27394
|
+
}
|
|
27395
|
+
const exists = !!vault.list()?.secrets.some((secret) => secret.name === clean && secret.state !== "removed");
|
|
27396
|
+
if (exists && value === "") return true;
|
|
27397
|
+
const bad = nameProblem(clean);
|
|
27398
|
+
const problem = bad ?? valueProblem(value);
|
|
27399
|
+
this.#refuse(problem, bad ? "name" : "value", true);
|
|
27400
|
+
if (problem) return false;
|
|
27401
|
+
const agent = this.#agent;
|
|
27402
|
+
const mine = () => this.#agent === agent && this.model?.vault === vault;
|
|
27403
|
+
this.sharing = true;
|
|
27404
|
+
try {
|
|
27405
|
+
if (exists) {
|
|
27406
|
+
const sure = await confirm({
|
|
27407
|
+
title: `Replace ${clean}?`,
|
|
27408
|
+
body: "A secret with this name exists. Sharing replaces its value, and its placeholder stays.",
|
|
27409
|
+
action: "Replace",
|
|
27410
|
+
variant: "confirmation"
|
|
27411
|
+
});
|
|
27412
|
+
if (!sure || !mine()) return false;
|
|
27413
|
+
if (blocked(vault)) {
|
|
27414
|
+
this.#refuse(blocked(vault));
|
|
27415
|
+
return false;
|
|
27416
|
+
}
|
|
27417
|
+
}
|
|
27418
|
+
await vault.put?.(clean, value);
|
|
27419
|
+
return mine();
|
|
27420
|
+
} catch (error) {
|
|
27421
|
+
if (mine()) this.#refuse(failureText(error), fieldOf(error, "value"));
|
|
27422
|
+
return false;
|
|
27423
|
+
} finally {
|
|
27424
|
+
this.sharing = false;
|
|
27425
|
+
}
|
|
27426
|
+
}
|
|
27053
27427
|
#choices(kind, query) {
|
|
27054
27428
|
const model = this.model;
|
|
27055
27429
|
if (kind === "command") {
|
|
@@ -27093,6 +27467,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
27093
27467
|
this.popup = found && (found.kind !== "argument" || takes) ? { ...found, items: this.#choices(found.kind, found.query), index: 0 } : null;
|
|
27094
27468
|
}
|
|
27095
27469
|
openPopup(kind) {
|
|
27470
|
+
clearValues(this.renderRoot);
|
|
27471
|
+
this.secretError = null;
|
|
27472
|
+
this.secretField = null;
|
|
27096
27473
|
this.popup = {
|
|
27097
27474
|
kind,
|
|
27098
27475
|
start: 0,
|
|
@@ -27254,17 +27631,32 @@ var SliccComposer = class extends ThemedElement {
|
|
|
27254
27631
|
const popup2 = this.popup;
|
|
27255
27632
|
if (!popup2) return A;
|
|
27256
27633
|
if (popup2.kind === "secret") {
|
|
27634
|
+
const vault = this.model?.vault;
|
|
27635
|
+
const valued = !!vault?.put && !blocked(vault);
|
|
27636
|
+
const waiting2 = vault?.put ? blocked(vault) : null;
|
|
27637
|
+
if (!valued) clearValues(this.renderRoot);
|
|
27257
27638
|
const submit = (event2) => {
|
|
27258
27639
|
event2.preventDefault();
|
|
27259
27640
|
const form = event2.currentTarget;
|
|
27260
|
-
this.shareSecret(
|
|
27641
|
+
void this.shareSecret(
|
|
27642
|
+
form.elements.namedItem("name").value,
|
|
27643
|
+
form.elements.namedItem("value")
|
|
27644
|
+
);
|
|
27645
|
+
};
|
|
27646
|
+
const close = (event2) => {
|
|
27647
|
+
if (event2.key !== "Escape") return;
|
|
27648
|
+
clearValues(this.renderRoot);
|
|
27649
|
+
this.popup = null;
|
|
27261
27650
|
};
|
|
27262
|
-
|
|
27651
|
+
const bad = (name) => this.secretField === name ? "true" : A;
|
|
27652
|
+
const described = (name) => this.secretField === name ? "secret-error" : A;
|
|
27653
|
+
return b`<form class="popup secret" data-vault=${valued ? "on" : "off"} @submit=${submit} @keydown=${close} @input=${() => this.secretField = null}>
|
|
27263
27654
|
<strong>Share a secret</strong>
|
|
27264
|
-
<span class="lead"
|
|
27265
|
-
<input name="name" placeholder="
|
|
27266
|
-
|
|
27267
|
-
|
|
27655
|
+
<span class="lead">${valued ? "The value goes to the vault; the agent only sees its name. Leave the value empty to share a secret the vault already has." : waiting2 === "Unlock the vault first" ? "The vault is locked. You can share the name now and add the value once it is unlocked." : waiting2 ? "Waiting for the vault. You can share the name now and add the value in Settings \u203A Secrets later." : "Add the value in Settings \u203A Secrets. The agent only sees the name."}</span>
|
|
27656
|
+
<label class="field"><span>Name</span><input name="name" placeholder="API_TOKEN" autocomplete="off" spellcheck="false" aria-invalid=${bad("name")} aria-describedby=${described("name")} /></label>
|
|
27657
|
+
${valued ? b`<label class="field"><span>Value</span><input name="value" type="password" autocomplete="off" spellcheck="false" aria-invalid=${bad("value")} aria-describedby=${described("value")} /></label>` : A}
|
|
27658
|
+
${this.secretError ? b`<span class="secret-error" role="alert" id="secret-error" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${this.secretError}</span></span>` : A}
|
|
27659
|
+
<swc-button size="s" variant="accent" data-action="share-secret" ?pending=${this.sharing} @click=${(event2) => event2.currentTarget.closest("form")?.requestSubmit()}>Share</swc-button>
|
|
27268
27660
|
</form>`;
|
|
27269
27661
|
}
|
|
27270
27662
|
const title = {
|
|
@@ -28293,197 +28685,6 @@ var SliccNotices = class extends ModelElement {
|
|
|
28293
28685
|
}
|
|
28294
28686
|
};
|
|
28295
28687
|
|
|
28296
|
-
// src/app/vault.ts
|
|
28297
|
-
var exitNames = {
|
|
28298
|
-
"vault-direct": "Straight from the vault",
|
|
28299
|
-
"local-proxy": "Local proxy",
|
|
28300
|
-
"cli-v": "Local SLICC, direct",
|
|
28301
|
-
tailscale: "Tailscale",
|
|
28302
|
-
"local-link": "Linked SLICC, through this page"
|
|
28303
|
-
};
|
|
28304
|
-
function devicesOf(model) {
|
|
28305
|
-
return model?.network?.status().links?.devices ?? [];
|
|
28306
|
-
}
|
|
28307
|
-
function deviceName2(id, devices) {
|
|
28308
|
-
return (devices.find((device) => device.id === id)?.name ?? id).replace(/^slicc\b/i, "SLICC");
|
|
28309
|
-
}
|
|
28310
|
-
function exitLabel(exit, devices) {
|
|
28311
|
-
if (exit.startsWith("device:")) return deviceName2(exit.slice("device:".length), devices);
|
|
28312
|
-
return exitNames[exit];
|
|
28313
|
-
}
|
|
28314
|
-
function list4(items) {
|
|
28315
|
-
if (items.length < 2) return items.join("");
|
|
28316
|
-
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
28317
|
-
}
|
|
28318
|
-
function ruleLine(rule) {
|
|
28319
|
-
const methods = rule.methods.length ? rule.methods.join(" or ") : "any method";
|
|
28320
|
-
const paths = rule.paths.length ? rule.paths.join(" or ") : "any path";
|
|
28321
|
-
return `${rule.domain}, in ${rule.header}, ${methods}, ${paths}`;
|
|
28322
|
-
}
|
|
28323
|
-
function shellWord(word) {
|
|
28324
|
-
return /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replace(/'/g, "'\\''")}'`;
|
|
28325
|
-
}
|
|
28326
|
-
function execLine(grant) {
|
|
28327
|
-
if (grant === false) return "Never revealed to programs";
|
|
28328
|
-
if (grant === true) return "Revealed to any program that asks";
|
|
28329
|
-
return `Revealed only to ${list4(grant.argv.map((argv) => argv.map(shellWord).join(" ")))}`;
|
|
28330
|
-
}
|
|
28331
|
-
function widening(change, devices) {
|
|
28332
|
-
switch (change.kind) {
|
|
28333
|
-
case "rule":
|
|
28334
|
-
return `${change.secret} may now be sent to ${ruleLine(change.rule)}`;
|
|
28335
|
-
case "methods":
|
|
28336
|
-
return `${change.secret} may now use ${list4(change.methods)} on ${change.domain}`;
|
|
28337
|
-
case "paths":
|
|
28338
|
-
return `${change.secret} may now reach ${list4(change.paths)} on ${change.domain}`;
|
|
28339
|
-
case "exec": {
|
|
28340
|
-
const line = execLine(change.grant);
|
|
28341
|
-
return `${change.secret}: ${line[0].toLowerCase()}${line.slice(1)}`;
|
|
28342
|
-
}
|
|
28343
|
-
case "exit":
|
|
28344
|
-
return `${change.secret} may now leave through ${exitLabel(change.exit, devices)}`;
|
|
28345
|
-
default:
|
|
28346
|
-
return `The limit ${change.field} rose from ${change.from} to ${change.to}`;
|
|
28347
|
-
}
|
|
28348
|
-
}
|
|
28349
|
-
function shown2(element2, style = getComputedStyle(element2)) {
|
|
28350
|
-
return !element2.hidden && !element2.inert && style.display !== "none";
|
|
28351
|
-
}
|
|
28352
|
-
function disabled(element2) {
|
|
28353
|
-
if (element2.matches(":disabled")) return true;
|
|
28354
|
-
if (!element2.matches("button, input, select, textarea")) return false;
|
|
28355
|
-
let fieldset = element2.closest("fieldset[disabled]");
|
|
28356
|
-
while (fieldset) {
|
|
28357
|
-
if (!fieldset.querySelector(":scope > legend")?.contains(element2)) return true;
|
|
28358
|
-
fieldset = fieldset.parentElement?.closest("fieldset[disabled]") ?? null;
|
|
28359
|
-
}
|
|
28360
|
-
return false;
|
|
28361
|
-
}
|
|
28362
|
-
function reachable(element2) {
|
|
28363
|
-
const radio = element2;
|
|
28364
|
-
if (radio.localName !== "input" || radio.type !== "radio" || !radio.name) return true;
|
|
28365
|
-
const root2 = radio.getRootNode();
|
|
28366
|
-
const group = Array.from(root2.querySelectorAll("input[type=radio]")).filter(
|
|
28367
|
-
(other) => other.name === radio.name && other.form === radio.form
|
|
28368
|
-
);
|
|
28369
|
-
const checked = group.find((other) => other.checked);
|
|
28370
|
-
return checked ? checked === radio : radio === group[0] || radio === group.at(-1);
|
|
28371
|
-
}
|
|
28372
|
-
function tabbables(root2, stop, out = []) {
|
|
28373
|
-
for (const child of Array.from(root2.children)) {
|
|
28374
|
-
if (child === stop) {
|
|
28375
|
-
out.push(null);
|
|
28376
|
-
continue;
|
|
28377
|
-
}
|
|
28378
|
-
const style = getComputedStyle(child);
|
|
28379
|
-
if (!shown2(child, style)) continue;
|
|
28380
|
-
if (child.localName === "details" && !child.open) {
|
|
28381
|
-
const summary = child.querySelector(":scope > summary");
|
|
28382
|
-
if (summary && shown2(summary) && getComputedStyle(summary).visibility !== "hidden" && !(summary.hasAttribute("tabindex") && summary.tabIndex < 0))
|
|
28383
|
-
out.push(summary);
|
|
28384
|
-
continue;
|
|
28385
|
-
}
|
|
28386
|
-
if (child.tabIndex >= 0 && !disabled(child) && style.visibility !== "hidden" && reachable(child))
|
|
28387
|
-
out.push(child);
|
|
28388
|
-
if (child.shadowRoot) tabbables(child.shadowRoot, stop, out);
|
|
28389
|
-
tabbables(child, stop, out);
|
|
28390
|
-
}
|
|
28391
|
-
return out;
|
|
28392
|
-
}
|
|
28393
|
-
function sequential(order) {
|
|
28394
|
-
const rank = (element2) => element2 && element2.tabIndex > 0 ? element2.tabIndex : Number.POSITIVE_INFINITY;
|
|
28395
|
-
return [...order].sort((a22, b13) => rank(a22) - rank(b13) || 0);
|
|
28396
|
-
}
|
|
28397
|
-
var SliccVaultButton = class extends i2 {
|
|
28398
|
-
static properties = {
|
|
28399
|
-
vault: { attribute: false },
|
|
28400
|
-
config: { attribute: false }
|
|
28401
|
-
};
|
|
28402
|
-
#button = null;
|
|
28403
|
-
#off = null;
|
|
28404
|
-
#ready = false;
|
|
28405
|
-
#sent = "";
|
|
28406
|
-
static styles = i`
|
|
28407
|
-
:host {
|
|
28408
|
-
display: inline-flex;
|
|
28409
|
-
vertical-align: middle;
|
|
28410
|
-
}
|
|
28411
|
-
iframe {
|
|
28412
|
-
border: 0;
|
|
28413
|
-
background: transparent;
|
|
28414
|
-
color-scheme: normal;
|
|
28415
|
-
}
|
|
28416
|
-
`;
|
|
28417
|
-
constructor() {
|
|
28418
|
-
super();
|
|
28419
|
-
this.vault = null;
|
|
28420
|
-
this.config = null;
|
|
28421
|
-
}
|
|
28422
|
-
connectedCallback() {
|
|
28423
|
-
super.connectedCallback();
|
|
28424
|
-
this.requestUpdate();
|
|
28425
|
-
}
|
|
28426
|
-
disconnectedCallback() {
|
|
28427
|
-
super.disconnectedCallback();
|
|
28428
|
-
this.#drop();
|
|
28429
|
-
}
|
|
28430
|
-
focus() {
|
|
28431
|
-
this.#button?.post({ type: "slicc-vault", v: 1, op: "focus" });
|
|
28432
|
-
}
|
|
28433
|
-
updated(changed) {
|
|
28434
|
-
if (changed.has("vault")) this.#drop();
|
|
28435
|
-
if (!this.#button && this.vault) this.#mount(this.vault);
|
|
28436
|
-
this.#send();
|
|
28437
|
-
}
|
|
28438
|
-
#mount(vault) {
|
|
28439
|
-
const button = vault.button();
|
|
28440
|
-
this.#button = button;
|
|
28441
|
-
this.#off = button.listen((event2) => this.#event(event2));
|
|
28442
|
-
this.renderRoot.append(button.element);
|
|
28443
|
-
}
|
|
28444
|
-
#drop() {
|
|
28445
|
-
this.#off?.();
|
|
28446
|
-
this.#button?.element.remove();
|
|
28447
|
-
this.#button = null;
|
|
28448
|
-
this.#off = null;
|
|
28449
|
-
this.#ready = false;
|
|
28450
|
-
this.#sent = "";
|
|
28451
|
-
}
|
|
28452
|
-
#send() {
|
|
28453
|
-
if (!(this.#ready && this.#button && this.config)) return;
|
|
28454
|
-
const sent = JSON.stringify(this.config);
|
|
28455
|
-
if (sent === this.#sent) return;
|
|
28456
|
-
this.#sent = sent;
|
|
28457
|
-
this.#button.post({ type: "slicc-vault", v: 1, op: "button", button: this.config });
|
|
28458
|
-
}
|
|
28459
|
-
#event(event2) {
|
|
28460
|
-
const element2 = this.#button?.element;
|
|
28461
|
-
if (event2.event === "ready") {
|
|
28462
|
-
this.#ready = true;
|
|
28463
|
-
this.#send();
|
|
28464
|
-
} else if (event2.event === "size") {
|
|
28465
|
-
element2.style.width = `${event2.width}px`;
|
|
28466
|
-
element2.style.height = `${event2.height}px`;
|
|
28467
|
-
element2.style.margin = `${-event2.inset}px`;
|
|
28468
|
-
} else if (event2.event === "label") {
|
|
28469
|
-
element2.title = event2.label;
|
|
28470
|
-
} else if (event2.event === "focus") {
|
|
28471
|
-
const order = sequential(tabbables(this.ownerDocument, this));
|
|
28472
|
-
const at = order.indexOf(null);
|
|
28473
|
-
order[event2.direction === "next" ? at + 1 : at - 1]?.focus();
|
|
28474
|
-
} else if (event2.event === "popup") {
|
|
28475
|
-
const { intent, state: state3, result } = event2;
|
|
28476
|
-
this.dispatchEvent(
|
|
28477
|
-
new CustomEvent("vault-popup", {
|
|
28478
|
-
detail: { intent, state: state3, ...result ? { result } : {} },
|
|
28479
|
-
bubbles: true,
|
|
28480
|
-
composed: true
|
|
28481
|
-
})
|
|
28482
|
-
);
|
|
28483
|
-
}
|
|
28484
|
-
}
|
|
28485
|
-
};
|
|
28486
|
-
|
|
28487
28688
|
// src/app/secrets.ts
|
|
28488
28689
|
var kinds = { secret: null, grant: "Sign-in", model: "Model key", mcp: "MCP server" };
|
|
28489
28690
|
var lockModes = {
|
|
@@ -28502,12 +28703,27 @@ function until(at, now = Date.now()) {
|
|
|
28502
28703
|
}
|
|
28503
28704
|
function who(entry) {
|
|
28504
28705
|
if (entry.tag) return entry.tag;
|
|
28505
|
-
if (entry.uid === null) return "
|
|
28706
|
+
if (entry.uid === null) return "you";
|
|
28506
28707
|
return entry.uid === 0 ? "root" : `uid ${entry.uid}`;
|
|
28507
28708
|
}
|
|
28709
|
+
function asker(request2) {
|
|
28710
|
+
if (request2.tag) return request2.tag;
|
|
28711
|
+
return request2.uid === 0 ? "A program running as root" : `A program running as uid ${request2.uid}`;
|
|
28712
|
+
}
|
|
28713
|
+
function asking2(request2) {
|
|
28714
|
+
const by = asker(request2);
|
|
28715
|
+
if (request2.kind === "oauth") return b`${by} asks you to sign in to ${request2.provider}`;
|
|
28716
|
+
if (request2.kind === "jerk-seal")
|
|
28717
|
+
return b`${by} asks for a jerk lease for ${request2.provider}`;
|
|
28718
|
+
return request2.name ? b`${by} asks for <code>${request2.name}</code>` : b`${by} asks for a value`;
|
|
28719
|
+
}
|
|
28720
|
+
function byName(a22, b13) {
|
|
28721
|
+
return a22.name < b13.name ? -1 : a22.name > b13.name ? 1 : 0;
|
|
28722
|
+
}
|
|
28508
28723
|
function sourceLine(secret, devices) {
|
|
28509
28724
|
const on = secret.sourceDevice ? ` on ${deviceName2(secret.sourceDevice, devices)}` : "";
|
|
28510
28725
|
const [kind, detail = ""] = secret.source.split(/:(.*)/s);
|
|
28726
|
+
if (kind === "settings") return `Entered in SLICC${on}`;
|
|
28511
28727
|
if (kind === "popup") return `Entered in the vault${on}`;
|
|
28512
28728
|
if (kind === "process") return `Saved by a program${on}`;
|
|
28513
28729
|
if (kind === "import") return `Imported from ${detail}`;
|
|
@@ -28534,11 +28750,16 @@ function revealed(name, entries, now = Date.now(), more = false) {
|
|
|
28534
28750
|
const when = today ? `${partial ? "at least " : ""}${today} ${today === 1 ? "time" : "times"} today` : since(last.at, now);
|
|
28535
28751
|
return b`Revealed to programs ${when}, last by ${who(last)} with <code>${last.argv}</code>`;
|
|
28536
28752
|
}
|
|
28753
|
+
function changes(entry, devices) {
|
|
28754
|
+
if (entry.changes)
|
|
28755
|
+
return entry.changes.map((change) => [change.kind, changeLine(change, devices)]);
|
|
28756
|
+
return (entry.widened ?? []).map((change) => [change.kind, widening(change, devices)]);
|
|
28757
|
+
}
|
|
28537
28758
|
function auditLine(entry, devices) {
|
|
28538
28759
|
switch (entry.type) {
|
|
28539
28760
|
case "inject":
|
|
28540
28761
|
case "forward":
|
|
28541
|
-
return b
|
|
28762
|
+
return b`Sent to ${entry.domain}: <code>${entry.method} ${entry.path}</code>, through ${exitLabel(entry.exit, devices)}`;
|
|
28542
28763
|
case "materialize":
|
|
28543
28764
|
return b`Revealed to <code>${entry.argv}</code> in <code>${entry.cwd}</code>`;
|
|
28544
28765
|
case "seal":
|
|
@@ -28547,11 +28768,10 @@ function auditLine(entry, devices) {
|
|
|
28547
28768
|
return b`Removed`;
|
|
28548
28769
|
case "restore":
|
|
28549
28770
|
return b`Restored`;
|
|
28550
|
-
|
|
28551
|
-
|
|
28552
|
-
|
|
28553
|
-
return b`<code>${entry.file}</code> ${entry.accepted ?
|
|
28554
|
-
}
|
|
28771
|
+
case "refresh":
|
|
28772
|
+
return entry.grant ? b`Refreshed automatically with the sign-in <code>${entry.grant}</code>` : b`Refreshed automatically`;
|
|
28773
|
+
default:
|
|
28774
|
+
return b`<code>${entry.file}</code> ${entry.accepted ? "changed" : "changed and was refused"}${changes(entry, devices).map(([kind, line]) => b`<span class="change" data-change=${kind}>${line}</span>`)}${entry.warning ? b`<span class="warning" data-warning>${entry.warning}</span>` : A}${entry.accepted ? b`<span class="hint" data-hint>If you didn’t mean this, change the file back with sudo.</span>` : A}`;
|
|
28555
28775
|
}
|
|
28556
28776
|
}
|
|
28557
28777
|
function merged(...pages) {
|
|
@@ -28559,6 +28779,37 @@ function merged(...pages) {
|
|
|
28559
28779
|
for (const page of pages) for (const entry of page) bySeq.set(entry.seq, entry);
|
|
28560
28780
|
return [...bySeq.values()].sort((a22, b13) => b13.seq - a22.seq);
|
|
28561
28781
|
}
|
|
28782
|
+
function replaceable(secret) {
|
|
28783
|
+
return secret.state !== "removed" && secret.kind !== "grant" && (secret.source === "settings" || secret.source === "process" || secret.source.startsWith("import:"));
|
|
28784
|
+
}
|
|
28785
|
+
function filename(now = Date.now()) {
|
|
28786
|
+
const date = new Date(now);
|
|
28787
|
+
const day2 = [date.getFullYear(), date.getMonth() + 1, date.getDate()].map((part2) => String(part2).padStart(2, "0")).join("-");
|
|
28788
|
+
return `slicc-secrets-${day2}.slicc-vault`;
|
|
28789
|
+
}
|
|
28790
|
+
function download(bytes, name, root2) {
|
|
28791
|
+
const url = URL.createObjectURL(
|
|
28792
|
+
new Blob([bytes], { type: "application/octet-stream" })
|
|
28793
|
+
);
|
|
28794
|
+
const link = document.createElement("a");
|
|
28795
|
+
link.href = url;
|
|
28796
|
+
link.download = name;
|
|
28797
|
+
link.hidden = true;
|
|
28798
|
+
root2.append(link);
|
|
28799
|
+
link.click();
|
|
28800
|
+
link.remove();
|
|
28801
|
+
URL.revokeObjectURL(url);
|
|
28802
|
+
}
|
|
28803
|
+
var importKinds = {
|
|
28804
|
+
bundle: "Bundle",
|
|
28805
|
+
keepass: "KeePass (.kdbx)",
|
|
28806
|
+
six: "six"
|
|
28807
|
+
};
|
|
28808
|
+
function exported(at) {
|
|
28809
|
+
if (at === void 0) return A;
|
|
28810
|
+
const when = at === null ? "Never exported" : `Last exported ${new Intl.DateTimeFormat(void 0, { dateStyle: "medium" }).format(at)}`;
|
|
28811
|
+
return b`<span class="muted" data-exported>${when}</span>`;
|
|
28812
|
+
}
|
|
28562
28813
|
function prompt2(text2) {
|
|
28563
28814
|
return text2.length > 200 ? `${text2.slice(0, 199)}\u2026` : text2;
|
|
28564
28815
|
}
|
|
@@ -28570,10 +28821,20 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28570
28821
|
loading: { state: true },
|
|
28571
28822
|
reveals: { state: true },
|
|
28572
28823
|
popup: { state: true },
|
|
28573
|
-
|
|
28574
|
-
|
|
28824
|
+
failure: { state: true },
|
|
28825
|
+
form: { state: true },
|
|
28826
|
+
busy: { state: true },
|
|
28827
|
+
problem: { state: true },
|
|
28828
|
+
invalid: { state: true },
|
|
28829
|
+
said: { state: true },
|
|
28830
|
+
acting: { state: true },
|
|
28831
|
+
importKind: { state: true },
|
|
28832
|
+
candidates: { state: true },
|
|
28833
|
+
picked: { state: true },
|
|
28834
|
+
again: { state: true }
|
|
28575
28835
|
};
|
|
28576
28836
|
#tick;
|
|
28837
|
+
#offline = false;
|
|
28577
28838
|
constructor() {
|
|
28578
28839
|
super();
|
|
28579
28840
|
this.older = [];
|
|
@@ -28581,252 +28842,353 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28581
28842
|
this.loading = false;
|
|
28582
28843
|
this.reveals = false;
|
|
28583
28844
|
this.popup = null;
|
|
28584
|
-
this.acking = /* @__PURE__ */ new Set();
|
|
28585
28845
|
this.failure = null;
|
|
28846
|
+
this.form = null;
|
|
28847
|
+
this.busy = false;
|
|
28848
|
+
this.problem = null;
|
|
28849
|
+
this.invalid = null;
|
|
28850
|
+
this.said = null;
|
|
28851
|
+
this.acting = /* @__PURE__ */ new Set();
|
|
28852
|
+
this.importKind = "bundle";
|
|
28853
|
+
this.candidates = null;
|
|
28854
|
+
this.picked = /* @__PURE__ */ new Set();
|
|
28855
|
+
this.again = false;
|
|
28586
28856
|
}
|
|
28587
|
-
static styles =
|
|
28588
|
-
|
|
28589
|
-
|
|
28590
|
-
|
|
28591
|
-
|
|
28592
|
-
|
|
28593
|
-
|
|
28594
|
-
|
|
28595
|
-
|
|
28596
|
-
|
|
28597
|
-
|
|
28598
|
-
|
|
28599
|
-
|
|
28600
|
-
|
|
28601
|
-
|
|
28602
|
-
|
|
28603
|
-
|
|
28604
|
-
|
|
28605
|
-
|
|
28606
|
-
|
|
28607
|
-
|
|
28608
|
-
|
|
28609
|
-
|
|
28610
|
-
|
|
28611
|
-
|
|
28612
|
-
|
|
28613
|
-
|
|
28614
|
-
|
|
28615
|
-
|
|
28616
|
-
|
|
28617
|
-
|
|
28618
|
-
|
|
28619
|
-
|
|
28620
|
-
|
|
28621
|
-
|
|
28622
|
-
|
|
28623
|
-
|
|
28624
|
-
|
|
28625
|
-
|
|
28626
|
-
|
|
28627
|
-
|
|
28628
|
-
|
|
28629
|
-
|
|
28630
|
-
|
|
28631
|
-
|
|
28632
|
-
|
|
28633
|
-
|
|
28634
|
-
|
|
28635
|
-
|
|
28636
|
-
|
|
28637
|
-
|
|
28638
|
-
|
|
28639
|
-
|
|
28640
|
-
|
|
28641
|
-
|
|
28642
|
-
|
|
28643
|
-
|
|
28644
|
-
|
|
28645
|
-
|
|
28646
|
-
|
|
28647
|
-
|
|
28648
|
-
|
|
28649
|
-
|
|
28650
|
-
|
|
28651
|
-
|
|
28652
|
-
|
|
28653
|
-
|
|
28654
|
-
|
|
28655
|
-
|
|
28656
|
-
|
|
28657
|
-
|
|
28658
|
-
|
|
28659
|
-
|
|
28660
|
-
|
|
28661
|
-
|
|
28662
|
-
|
|
28663
|
-
|
|
28664
|
-
|
|
28665
|
-
|
|
28666
|
-
|
|
28667
|
-
|
|
28668
|
-
|
|
28669
|
-
|
|
28670
|
-
|
|
28671
|
-
|
|
28672
|
-
|
|
28673
|
-
|
|
28674
|
-
|
|
28675
|
-
|
|
28676
|
-
|
|
28677
|
-
|
|
28678
|
-
|
|
28679
|
-
|
|
28680
|
-
|
|
28681
|
-
|
|
28682
|
-
|
|
28683
|
-
|
|
28684
|
-
|
|
28685
|
-
|
|
28686
|
-
|
|
28687
|
-
|
|
28688
|
-
|
|
28689
|
-
|
|
28690
|
-
|
|
28691
|
-
|
|
28692
|
-
|
|
28693
|
-
|
|
28694
|
-
|
|
28695
|
-
|
|
28696
|
-
|
|
28697
|
-
|
|
28698
|
-
|
|
28699
|
-
|
|
28700
|
-
|
|
28701
|
-
|
|
28702
|
-
|
|
28703
|
-
|
|
28704
|
-
|
|
28705
|
-
|
|
28706
|
-
|
|
28707
|
-
|
|
28708
|
-
|
|
28709
|
-
|
|
28710
|
-
|
|
28711
|
-
|
|
28712
|
-
|
|
28713
|
-
|
|
28714
|
-
|
|
28715
|
-
|
|
28716
|
-
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
|
|
28721
|
-
|
|
28722
|
-
|
|
28723
|
-
|
|
28724
|
-
|
|
28725
|
-
|
|
28726
|
-
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28733
|
-
|
|
28734
|
-
|
|
28735
|
-
.audit-head {
|
|
28736
|
-
display: flex;
|
|
28737
|
-
flex-wrap: wrap;
|
|
28738
|
-
align-items: baseline;
|
|
28739
|
-
justify-content: space-between;
|
|
28740
|
-
gap: var(--swc-spacing-200);
|
|
28741
|
-
margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
|
|
28742
|
-
}
|
|
28743
|
-
.audit-head h3 {
|
|
28744
|
-
margin-block: 0;
|
|
28745
|
-
}
|
|
28746
|
-
.audit li {
|
|
28747
|
-
display: grid;
|
|
28748
|
-
grid-template-columns: 7em minmax(0, 1fr);
|
|
28749
|
-
gap: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
28750
|
-
padding: var(--swc-spacing-100) 0;
|
|
28751
|
-
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28752
|
-
font-size: var(--swc-font-size-75);
|
|
28753
|
-
line-height: var(--swc-line-height-200);
|
|
28754
|
-
}
|
|
28755
|
-
.audit time {
|
|
28756
|
-
color: var(--swc-neutral-subdued-content-color-default);
|
|
28757
|
-
}
|
|
28758
|
-
.audit .what {
|
|
28759
|
-
overflow-wrap: anywhere;
|
|
28760
|
-
}
|
|
28761
|
-
.audit .by {
|
|
28762
|
-
color: var(--swc-neutral-subdued-content-color-default);
|
|
28763
|
-
}
|
|
28764
|
-
.row {
|
|
28765
|
-
display: flex;
|
|
28766
|
-
flex-wrap: wrap;
|
|
28767
|
-
align-items: center;
|
|
28768
|
-
gap: var(--swc-spacing-200);
|
|
28769
|
-
margin-top: var(--swc-spacing-200);
|
|
28770
|
-
}
|
|
28771
|
-
.error {
|
|
28772
|
-
display: flex;
|
|
28773
|
-
align-items: flex-start;
|
|
28774
|
-
gap: var(--swc-spacing-100);
|
|
28775
|
-
color: var(--swc-negative-content-color-default);
|
|
28776
|
-
font-size: var(--swc-font-size-75);
|
|
28777
|
-
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
28778
|
-
}
|
|
28779
|
-
@container (max-width: 480px) {
|
|
28857
|
+
static styles = [
|
|
28858
|
+
fieldStyles,
|
|
28859
|
+
i`
|
|
28860
|
+
:host {
|
|
28861
|
+
display: block;
|
|
28862
|
+
container-type: inline-size;
|
|
28863
|
+
}
|
|
28864
|
+
h2 {
|
|
28865
|
+
font-size: var(--swc-heading-size-xs);
|
|
28866
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28867
|
+
line-height: var(--swc-heading-line-height);
|
|
28868
|
+
color: var(--swc-heading-color);
|
|
28869
|
+
margin: 0;
|
|
28870
|
+
}
|
|
28871
|
+
h3 {
|
|
28872
|
+
font-size: var(--swc-font-size-100);
|
|
28873
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28874
|
+
color: var(--swc-heading-color);
|
|
28875
|
+
margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
|
|
28876
|
+
}
|
|
28877
|
+
p {
|
|
28878
|
+
margin: var(--swc-spacing-100) 0;
|
|
28879
|
+
}
|
|
28880
|
+
ul,
|
|
28881
|
+
ol {
|
|
28882
|
+
list-style: none;
|
|
28883
|
+
margin: 0;
|
|
28884
|
+
padding: 0;
|
|
28885
|
+
}
|
|
28886
|
+
code {
|
|
28887
|
+
font-family: var(--swc-code-font-family, ui-monospace, monospace);
|
|
28888
|
+
font-size: 0.9em;
|
|
28889
|
+
overflow-wrap: anywhere;
|
|
28890
|
+
}
|
|
28891
|
+
.head {
|
|
28892
|
+
display: flex;
|
|
28893
|
+
flex-wrap: wrap;
|
|
28894
|
+
align-items: baseline;
|
|
28895
|
+
gap: var(--swc-spacing-200) var(--swc-spacing-300);
|
|
28896
|
+
margin: var(--swc-spacing-500) 0 var(--swc-spacing-200);
|
|
28897
|
+
}
|
|
28898
|
+
.head .controls {
|
|
28899
|
+
display: flex;
|
|
28900
|
+
flex-wrap: wrap;
|
|
28901
|
+
align-items: center;
|
|
28902
|
+
gap: var(--swc-spacing-200);
|
|
28903
|
+
align-self: center;
|
|
28904
|
+
margin-inline-start: auto;
|
|
28905
|
+
}
|
|
28906
|
+
.muted {
|
|
28907
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28908
|
+
}
|
|
28909
|
+
.box {
|
|
28910
|
+
display: grid;
|
|
28911
|
+
gap: var(--swc-spacing-100);
|
|
28912
|
+
padding: var(--swc-spacing-200) var(--swc-spacing-300);
|
|
28913
|
+
margin: var(--swc-spacing-200) 0;
|
|
28914
|
+
border-radius: var(--swc-corner-radius-100);
|
|
28915
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28916
|
+
background: var(--swc-background-layer-1-color);
|
|
28917
|
+
}
|
|
28918
|
+
.box.info {
|
|
28919
|
+
border-color: var(--swc-informative-visual-color);
|
|
28920
|
+
--swc-icon-color: var(--swc-informative-visual-color);
|
|
28921
|
+
}
|
|
28922
|
+
.availability {
|
|
28923
|
+
display: flex;
|
|
28924
|
+
align-items: center;
|
|
28925
|
+
gap: var(--swc-spacing-100);
|
|
28926
|
+
}
|
|
28927
|
+
.box .title {
|
|
28928
|
+
display: flex;
|
|
28929
|
+
align-items: flex-start;
|
|
28930
|
+
gap: var(--swc-spacing-100);
|
|
28931
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28932
|
+
}
|
|
28933
|
+
.box .actions,
|
|
28934
|
+
.buttons {
|
|
28935
|
+
display: flex;
|
|
28936
|
+
flex-wrap: wrap;
|
|
28937
|
+
align-items: center;
|
|
28938
|
+
gap: var(--swc-spacing-200);
|
|
28939
|
+
}
|
|
28940
|
+
.prompt {
|
|
28941
|
+
margin: 0;
|
|
28942
|
+
padding-inline-start: var(--swc-spacing-200);
|
|
28943
|
+
border-inline-start: var(--swc-border-width-200) solid var(--swc-gray-300);
|
|
28944
|
+
overflow-wrap: anywhere;
|
|
28945
|
+
}
|
|
28946
|
+
.said {
|
|
28947
|
+
white-space: pre-wrap;
|
|
28948
|
+
}
|
|
28949
|
+
.from {
|
|
28950
|
+
display: block;
|
|
28951
|
+
font-size: var(--swc-font-size-75);
|
|
28952
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28953
|
+
}
|
|
28954
|
+
.form {
|
|
28955
|
+
display: grid;
|
|
28956
|
+
gap: var(--swc-spacing-200);
|
|
28957
|
+
max-inline-size: 32rem;
|
|
28958
|
+
padding: var(--swc-spacing-300);
|
|
28959
|
+
margin: var(--swc-spacing-200) 0;
|
|
28960
|
+
border-radius: var(--swc-corner-radius-100);
|
|
28961
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-300);
|
|
28962
|
+
background: var(--swc-background-layer-1-color);
|
|
28963
|
+
}
|
|
28964
|
+
.form strong {
|
|
28965
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28966
|
+
}
|
|
28967
|
+
.form sp-picker {
|
|
28968
|
+
inline-size: 100%;
|
|
28969
|
+
}
|
|
28970
|
+
.picks {
|
|
28971
|
+
display: grid;
|
|
28972
|
+
gap: var(--swc-spacing-100);
|
|
28973
|
+
margin: 0;
|
|
28974
|
+
padding: var(--swc-spacing-200) var(--swc-spacing-300);
|
|
28975
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28976
|
+
border-radius: var(--swc-corner-radius-100);
|
|
28977
|
+
}
|
|
28978
|
+
.picks legend {
|
|
28979
|
+
padding: 0 var(--swc-spacing-75);
|
|
28980
|
+
font-size: var(--swc-font-size-75);
|
|
28981
|
+
}
|
|
28982
|
+
.picks label {
|
|
28983
|
+
display: grid;
|
|
28984
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
28985
|
+
align-items: start;
|
|
28986
|
+
gap: var(--swc-spacing-50) var(--swc-spacing-100);
|
|
28987
|
+
}
|
|
28988
|
+
.picks input {
|
|
28989
|
+
margin: 0.2em 0 0;
|
|
28990
|
+
accent-color: var(--swc-accent-background-color-default);
|
|
28991
|
+
}
|
|
28992
|
+
.picks .about {
|
|
28993
|
+
display: grid;
|
|
28994
|
+
gap: var(--swc-spacing-50);
|
|
28995
|
+
min-width: 0;
|
|
28996
|
+
}
|
|
28997
|
+
.picks .suggested {
|
|
28998
|
+
font-size: var(--swc-font-size-75);
|
|
28999
|
+
overflow-wrap: anywhere;
|
|
29000
|
+
}
|
|
29001
|
+
.secrets {
|
|
29002
|
+
display: grid;
|
|
29003
|
+
gap: var(--swc-spacing-200);
|
|
29004
|
+
}
|
|
28780
29005
|
.secret {
|
|
28781
|
-
|
|
29006
|
+
display: grid;
|
|
29007
|
+
grid-template-columns: minmax(0, 1fr) max-content;
|
|
29008
|
+
gap: var(--swc-spacing-100) var(--swc-spacing-300);
|
|
29009
|
+
padding: var(--swc-spacing-200) 0;
|
|
29010
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28782
29011
|
}
|
|
28783
|
-
.secret
|
|
28784
|
-
|
|
28785
|
-
|
|
29012
|
+
.secret:first-child {
|
|
29013
|
+
border-top: 0;
|
|
29014
|
+
}
|
|
29015
|
+
.secret .form {
|
|
29016
|
+
grid-column: 1 / -1;
|
|
29017
|
+
}
|
|
29018
|
+
.secret .buttons {
|
|
29019
|
+
align-self: start;
|
|
29020
|
+
justify-content: flex-end;
|
|
29021
|
+
}
|
|
29022
|
+
.name {
|
|
29023
|
+
display: flex;
|
|
29024
|
+
flex-wrap: wrap;
|
|
29025
|
+
align-items: baseline;
|
|
29026
|
+
gap: var(--swc-spacing-100) var(--swc-spacing-200);
|
|
29027
|
+
min-width: 0;
|
|
29028
|
+
}
|
|
29029
|
+
.name code {
|
|
29030
|
+
font-size: var(--swc-font-size-100);
|
|
29031
|
+
font-weight: var(--swc-bold-font-weight);
|
|
29032
|
+
}
|
|
29033
|
+
.removed {
|
|
29034
|
+
margin-top: var(--swc-spacing-200);
|
|
29035
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
29036
|
+
padding-top: var(--swc-spacing-200);
|
|
29037
|
+
}
|
|
29038
|
+
.removed summary {
|
|
29039
|
+
cursor: pointer;
|
|
29040
|
+
font-size: var(--swc-font-size-75);
|
|
29041
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
29042
|
+
}
|
|
29043
|
+
.removed .secret dl,
|
|
29044
|
+
.removed .secret .name code {
|
|
29045
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28786
29046
|
}
|
|
28787
29047
|
dl {
|
|
28788
|
-
grid-
|
|
29048
|
+
grid-column: 1 / -1;
|
|
29049
|
+
display: grid;
|
|
29050
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
29051
|
+
gap: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
29052
|
+
margin: 0;
|
|
29053
|
+
font-size: var(--swc-font-size-75);
|
|
29054
|
+
line-height: var(--swc-line-height-200);
|
|
29055
|
+
}
|
|
29056
|
+
dt {
|
|
29057
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28789
29058
|
}
|
|
28790
29059
|
dd {
|
|
28791
|
-
margin
|
|
29060
|
+
margin: 0;
|
|
29061
|
+
min-width: 0;
|
|
29062
|
+
overflow-wrap: anywhere;
|
|
29063
|
+
}
|
|
29064
|
+
.refused li {
|
|
29065
|
+
display: grid;
|
|
29066
|
+
gap: var(--swc-spacing-50);
|
|
29067
|
+
padding: var(--swc-spacing-100) 0;
|
|
29068
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
29069
|
+
font-size: var(--swc-font-size-75);
|
|
29070
|
+
overflow-wrap: anywhere;
|
|
29071
|
+
}
|
|
29072
|
+
.audit-head {
|
|
29073
|
+
display: flex;
|
|
29074
|
+
flex-wrap: wrap;
|
|
29075
|
+
align-items: baseline;
|
|
29076
|
+
justify-content: space-between;
|
|
29077
|
+
gap: var(--swc-spacing-200);
|
|
29078
|
+
margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
|
|
29079
|
+
}
|
|
29080
|
+
.audit-head h3 {
|
|
29081
|
+
margin-block: 0;
|
|
28792
29082
|
}
|
|
28793
29083
|
.audit li {
|
|
28794
|
-
|
|
29084
|
+
display: grid;
|
|
29085
|
+
grid-template-columns: 7em minmax(0, 1fr);
|
|
29086
|
+
gap: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
29087
|
+
padding: var(--swc-spacing-100) 0;
|
|
29088
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
29089
|
+
font-size: var(--swc-font-size-75);
|
|
29090
|
+
line-height: var(--swc-line-height-200);
|
|
28795
29091
|
}
|
|
28796
|
-
|
|
28797
|
-
|
|
28798
|
-
|
|
29092
|
+
.audit time {
|
|
29093
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
29094
|
+
}
|
|
29095
|
+
.audit .what {
|
|
29096
|
+
overflow-wrap: anywhere;
|
|
29097
|
+
}
|
|
29098
|
+
.audit .by,
|
|
29099
|
+
.audit .hint {
|
|
29100
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
29101
|
+
}
|
|
29102
|
+
.audit .change::before {
|
|
29103
|
+
content: '• ' / '';
|
|
29104
|
+
}
|
|
29105
|
+
.audit .change,
|
|
29106
|
+
.audit .warning,
|
|
29107
|
+
.audit .hint {
|
|
29108
|
+
display: block;
|
|
29109
|
+
}
|
|
29110
|
+
.row {
|
|
29111
|
+
display: flex;
|
|
29112
|
+
flex-wrap: wrap;
|
|
29113
|
+
align-items: center;
|
|
29114
|
+
gap: var(--swc-spacing-200);
|
|
29115
|
+
margin-top: var(--swc-spacing-200);
|
|
29116
|
+
}
|
|
29117
|
+
.error {
|
|
29118
|
+
display: flex;
|
|
29119
|
+
align-items: flex-start;
|
|
29120
|
+
gap: var(--swc-spacing-100);
|
|
29121
|
+
margin: 0;
|
|
29122
|
+
color: var(--swc-negative-content-color-default);
|
|
29123
|
+
font-size: var(--swc-font-size-75);
|
|
29124
|
+
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
29125
|
+
}
|
|
29126
|
+
@container (max-width: 480px) {
|
|
29127
|
+
.secret {
|
|
29128
|
+
grid-template-columns: minmax(0, 1fr);
|
|
29129
|
+
}
|
|
29130
|
+
.secret .buttons {
|
|
29131
|
+
order: 1;
|
|
29132
|
+
justify-content: flex-start;
|
|
29133
|
+
}
|
|
29134
|
+
.secret .form {
|
|
29135
|
+
order: 2;
|
|
29136
|
+
}
|
|
29137
|
+
.form {
|
|
29138
|
+
max-inline-size: none;
|
|
29139
|
+
}
|
|
29140
|
+
dl {
|
|
29141
|
+
grid-template-columns: minmax(0, 1fr);
|
|
29142
|
+
}
|
|
29143
|
+
dd {
|
|
29144
|
+
margin-bottom: var(--swc-spacing-75);
|
|
29145
|
+
}
|
|
29146
|
+
.audit li {
|
|
29147
|
+
grid-template-columns: minmax(0, 1fr);
|
|
29148
|
+
}
|
|
29149
|
+
}
|
|
29150
|
+
`
|
|
29151
|
+
];
|
|
28799
29152
|
disconnectedCallback() {
|
|
28800
29153
|
super.disconnectedCallback();
|
|
28801
29154
|
clearTimeout(this.#tick);
|
|
29155
|
+
clearValues(this.renderRoot);
|
|
28802
29156
|
this.older = [];
|
|
28803
29157
|
this.more = null;
|
|
28804
|
-
this.#pushed = [];
|
|
28805
29158
|
}
|
|
28806
29159
|
willUpdate(changed) {
|
|
28807
29160
|
super.willUpdate(changed);
|
|
28808
29161
|
const before = changed.get("model");
|
|
28809
29162
|
if (!changed.has("model") || before?.vault === this.model?.vault) return;
|
|
29163
|
+
clearValues(this.renderRoot);
|
|
28810
29164
|
this.older = [];
|
|
28811
29165
|
this.more = null;
|
|
28812
29166
|
this.loading = false;
|
|
28813
29167
|
this.popup = null;
|
|
28814
|
-
this.acking = /* @__PURE__ */ new Set();
|
|
28815
29168
|
this.failure = null;
|
|
28816
|
-
this
|
|
29169
|
+
this.form = null;
|
|
29170
|
+
this.busy = false;
|
|
29171
|
+
this.problem = null;
|
|
29172
|
+
this.invalid = null;
|
|
29173
|
+
this.said = null;
|
|
29174
|
+
this.acting = /* @__PURE__ */ new Set();
|
|
29175
|
+
this.candidates = null;
|
|
28817
29176
|
}
|
|
28818
29177
|
updated() {
|
|
28819
29178
|
clearTimeout(this.#tick);
|
|
28820
29179
|
if (!this.isConnected) return;
|
|
28821
29180
|
const now = Date.now();
|
|
29181
|
+
const vault = this.model?.vault;
|
|
28822
29182
|
const next = Math.min(
|
|
28823
29183
|
now + 6e4,
|
|
28824
|
-
...
|
|
29184
|
+
...[
|
|
29185
|
+
...(vault?.list()?.secrets ?? []).map((secret) => secret.expiresAt),
|
|
29186
|
+
...(vault?.status()?.waiting ?? []).map((request2) => request2.expiresAt)
|
|
29187
|
+
].map((at) => at ?? Number.POSITIVE_INFINITY).filter((at) => at > now)
|
|
28825
29188
|
);
|
|
28826
29189
|
this.#tick = setTimeout(() => this.requestUpdate(), next - now);
|
|
28827
29190
|
}
|
|
28828
29191
|
#listed(vault) {
|
|
28829
|
-
this.#pushed = [];
|
|
28830
29192
|
const head2 = vault.list()?.audit ?? [];
|
|
28831
29193
|
const last = head2[head2.length - 1];
|
|
28832
29194
|
if (this.older.length && (!last || last.seq > this.older[0].seq + 1)) {
|
|
@@ -28835,25 +29197,22 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28835
29197
|
}
|
|
28836
29198
|
this.requestUpdate();
|
|
28837
29199
|
}
|
|
28838
|
-
#noticed(notice) {
|
|
28839
|
-
this.#pushed = [...this.#pushed.filter((item2) => item2.id !== notice.id), notice];
|
|
28840
|
-
this.requestUpdate();
|
|
28841
|
-
}
|
|
28842
29200
|
subscribe(model) {
|
|
28843
29201
|
const update = () => this.requestUpdate();
|
|
28844
29202
|
return [
|
|
28845
29203
|
...super.subscribe(model),
|
|
28846
29204
|
...model.vault ? [
|
|
28847
29205
|
model.vault.on("status", update),
|
|
28848
|
-
model.vault.on("
|
|
28849
|
-
model.vault.on("
|
|
29206
|
+
model.vault.on("availability", update),
|
|
29207
|
+
model.vault.on("list", () => this.#listed(model.vault))
|
|
28850
29208
|
] : [],
|
|
28851
29209
|
...model.network ? [model.network.on("network", update)] : []
|
|
28852
29210
|
];
|
|
28853
29211
|
}
|
|
28854
|
-
#button(config) {
|
|
29212
|
+
#button(config, action) {
|
|
28855
29213
|
const theme3 = this.color;
|
|
28856
29214
|
return b`<slicc-vault-button
|
|
29215
|
+
data-action=${action}
|
|
28857
29216
|
.vault=${this.model?.vault}
|
|
28858
29217
|
.config=${{ size: "m", variant: "secondary", ...config, theme: theme3 }}
|
|
28859
29218
|
@vault-popup=${(event2) => this.#popup(event2.detail)}
|
|
@@ -28862,6 +29221,238 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28862
29221
|
#popup(detail) {
|
|
28863
29222
|
this.popup = detail;
|
|
28864
29223
|
}
|
|
29224
|
+
open(form) {
|
|
29225
|
+
if (form && this.busy) return;
|
|
29226
|
+
clearValues(this.renderRoot);
|
|
29227
|
+
this.form = form;
|
|
29228
|
+
this.problem = null;
|
|
29229
|
+
this.invalid = null;
|
|
29230
|
+
this.said = null;
|
|
29231
|
+
this.candidates = null;
|
|
29232
|
+
this.again = false;
|
|
29233
|
+
if (form?.kind === "import") this.importKind = "bundle";
|
|
29234
|
+
if (form) void this.updateComplete.then(() => this.#focus());
|
|
29235
|
+
}
|
|
29236
|
+
#refuse(text2, field = null, focus = false) {
|
|
29237
|
+
this.problem = text2;
|
|
29238
|
+
this.invalid = text2 ? field : null;
|
|
29239
|
+
if (focus && text2 && field) void this.updateComplete.then(() => this.#field(field)?.focus());
|
|
29240
|
+
}
|
|
29241
|
+
#typed() {
|
|
29242
|
+
this.invalid = null;
|
|
29243
|
+
}
|
|
29244
|
+
#bad(field) {
|
|
29245
|
+
return this.invalid === field ? "true" : A;
|
|
29246
|
+
}
|
|
29247
|
+
#described(field) {
|
|
29248
|
+
return this.invalid === field ? "error-form" : A;
|
|
29249
|
+
}
|
|
29250
|
+
#focus() {
|
|
29251
|
+
this.renderRoot.querySelector("[data-form] input, [data-form] sp-picker")?.focus();
|
|
29252
|
+
}
|
|
29253
|
+
#field(name) {
|
|
29254
|
+
return this.renderRoot.querySelector(
|
|
29255
|
+
`[data-form] input[data-field=${name}]`
|
|
29256
|
+
);
|
|
29257
|
+
}
|
|
29258
|
+
#same(vault, form, kind, file) {
|
|
29259
|
+
return this.#mine(vault, form) && this.importKind === kind && this.#field("file")?.files?.[0] === file;
|
|
29260
|
+
}
|
|
29261
|
+
#shut(vault) {
|
|
29262
|
+
if (!vault.status()?.locked) return false;
|
|
29263
|
+
this.#refuse("Unlock the vault first");
|
|
29264
|
+
return true;
|
|
29265
|
+
}
|
|
29266
|
+
#mine(vault, form) {
|
|
29267
|
+
return this.model?.vault === vault && this.isConnected && !away(vault) && (form === void 0 || this.form === form);
|
|
29268
|
+
}
|
|
29269
|
+
async save(vault) {
|
|
29270
|
+
const form = this.form;
|
|
29271
|
+
if (this.busy) return;
|
|
29272
|
+
const name = form.kind === "replace" ? form.name : this.#field("name").value.trim();
|
|
29273
|
+
const bad = nameProblem(name);
|
|
29274
|
+
if (bad) {
|
|
29275
|
+
this.#refuse(bad, "name", true);
|
|
29276
|
+
return;
|
|
29277
|
+
}
|
|
29278
|
+
const value = take(this.#field("value"));
|
|
29279
|
+
const problem = valueProblem(value);
|
|
29280
|
+
this.#refuse(problem, "value", true);
|
|
29281
|
+
if (problem) return;
|
|
29282
|
+
if (form.kind === "add" && vault.list()?.secrets.some((secret) => secret.name === name)) {
|
|
29283
|
+
this.busy = true;
|
|
29284
|
+
const sure = await confirm({
|
|
29285
|
+
title: `Replace ${name}?`,
|
|
29286
|
+
body: "A secret with this name exists. Saving replaces its value, and its placeholder stays.",
|
|
29287
|
+
action: "Replace",
|
|
29288
|
+
variant: "confirmation"
|
|
29289
|
+
});
|
|
29290
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29291
|
+
if (!sure || !this.#mine(vault, form) || this.#shut(vault)) return;
|
|
29292
|
+
}
|
|
29293
|
+
this.busy = true;
|
|
29294
|
+
try {
|
|
29295
|
+
await vault.put?.(name, value);
|
|
29296
|
+
if (!this.#mine(vault, form)) return;
|
|
29297
|
+
this.form = null;
|
|
29298
|
+
this.said = { kind: "saved", name };
|
|
29299
|
+
} catch (error) {
|
|
29300
|
+
if (this.#mine(vault, form)) this.#refuse(failureText(error), fieldOf(error, "value"));
|
|
29301
|
+
} finally {
|
|
29302
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29303
|
+
}
|
|
29304
|
+
}
|
|
29305
|
+
async #act(vault, key2, run2, missing = "") {
|
|
29306
|
+
if (this.acting.has(key2)) return;
|
|
29307
|
+
this.acting = /* @__PURE__ */ new Set([...this.acting, key2]);
|
|
29308
|
+
this.failure = null;
|
|
29309
|
+
try {
|
|
29310
|
+
await run2();
|
|
29311
|
+
} catch (error) {
|
|
29312
|
+
if (this.#mine(vault))
|
|
29313
|
+
this.failure = missing && isVaultFailure(error) && error.code === "ENOENT" ? missing : failureText(error);
|
|
29314
|
+
} finally {
|
|
29315
|
+
if (this.model?.vault === vault)
|
|
29316
|
+
this.acting = new Set([...this.acting].filter((item2) => item2 !== key2));
|
|
29317
|
+
}
|
|
29318
|
+
}
|
|
29319
|
+
async removeSecret(vault, secret, trigger2 = null) {
|
|
29320
|
+
const { name, kind } = secret;
|
|
29321
|
+
const sure = await confirm({
|
|
29322
|
+
title: `Remove ${name}?`,
|
|
29323
|
+
body: "Agents and programs can no longer use it. You can restore it from Removed.",
|
|
29324
|
+
action: "Remove",
|
|
29325
|
+
variant: "confirmation",
|
|
29326
|
+
trigger: trigger2
|
|
29327
|
+
});
|
|
29328
|
+
if (!sure || !this.#mine(vault)) return;
|
|
29329
|
+
if (this.form?.kind === "replace" && this.form.name === name) this.open(null);
|
|
29330
|
+
await this.#act(vault, `remove:${name}`, async () => vault.remove?.(name, kind));
|
|
29331
|
+
}
|
|
29332
|
+
restoreSecret(vault, secret) {
|
|
29333
|
+
const { name, kind } = secret;
|
|
29334
|
+
return this.#act(
|
|
29335
|
+
vault,
|
|
29336
|
+
`restore:${name}`,
|
|
29337
|
+
async () => vault.restore?.(name, kind),
|
|
29338
|
+
"Removed too long ago to restore"
|
|
29339
|
+
);
|
|
29340
|
+
}
|
|
29341
|
+
cancelRequest(vault, id) {
|
|
29342
|
+
return this.#act(vault, `cancel:${id}`, async () => vault.cancel?.(id));
|
|
29343
|
+
}
|
|
29344
|
+
lockVault(vault) {
|
|
29345
|
+
return this.#act(vault, "lock", async () => vault.lock?.());
|
|
29346
|
+
}
|
|
29347
|
+
dismissBackup(vault) {
|
|
29348
|
+
return this.#act(vault, "backup", async () => vault.dismissBackupReminder?.());
|
|
29349
|
+
}
|
|
29350
|
+
answer(id) {
|
|
29351
|
+
const vault = this.model?.vault;
|
|
29352
|
+
this.dispatchEvent(
|
|
29353
|
+
new CustomEvent("value-request", { detail: { id, vault }, bubbles: true, composed: true })
|
|
29354
|
+
);
|
|
29355
|
+
}
|
|
29356
|
+
#kind(event2) {
|
|
29357
|
+
this.importKind = event2.currentTarget.value;
|
|
29358
|
+
this.candidates = null;
|
|
29359
|
+
this.#refuse(null);
|
|
29360
|
+
}
|
|
29361
|
+
#reset() {
|
|
29362
|
+
this.candidates = null;
|
|
29363
|
+
this.#refuse(null);
|
|
29364
|
+
}
|
|
29365
|
+
async read(vault) {
|
|
29366
|
+
const form = this.form;
|
|
29367
|
+
const kind = this.importKind;
|
|
29368
|
+
if (this.busy) return;
|
|
29369
|
+
const password = take(this.#field("password"));
|
|
29370
|
+
const file = this.#field("file").files?.[0];
|
|
29371
|
+
if (!file) {
|
|
29372
|
+
this.#refuse("Choose a file to import", "file", true);
|
|
29373
|
+
return;
|
|
29374
|
+
}
|
|
29375
|
+
const pick = this.candidates?.filter((item2) => this.picked.has(item2.name)).map(
|
|
29376
|
+
(item2) => item2.kind && item2.kind !== "secret" ? { name: item2.name, kind: item2.kind } : item2.name
|
|
29377
|
+
);
|
|
29378
|
+
if (pick && !pick.length) {
|
|
29379
|
+
this.#refuse("Choose at least one secret to import");
|
|
29380
|
+
return;
|
|
29381
|
+
}
|
|
29382
|
+
this.busy = true;
|
|
29383
|
+
this.#refuse(null);
|
|
29384
|
+
try {
|
|
29385
|
+
let bytes = new Uint8Array(await file.arrayBuffer());
|
|
29386
|
+
if (!this.#same(vault, form, kind, file) || this.#shut(vault)) return;
|
|
29387
|
+
const call = vault.import?.(kind, bytes, {
|
|
29388
|
+
...password ? { password } : {},
|
|
29389
|
+
...pick ? { pick } : {}
|
|
29390
|
+
});
|
|
29391
|
+
bytes = null;
|
|
29392
|
+
const result = await call;
|
|
29393
|
+
if (!this.#same(vault, form, kind, file)) return;
|
|
29394
|
+
if (result.stage === "pick") {
|
|
29395
|
+
this.candidates = result.candidates;
|
|
29396
|
+
this.picked = new Set(
|
|
29397
|
+
result.candidates.filter((item2) => !item2.refused).map((item2) => item2.name)
|
|
29398
|
+
);
|
|
29399
|
+
this.again = !!password;
|
|
29400
|
+
return;
|
|
29401
|
+
}
|
|
29402
|
+
this.form = null;
|
|
29403
|
+
this.candidates = null;
|
|
29404
|
+
this.said = {
|
|
29405
|
+
kind: "imported",
|
|
29406
|
+
imported: result.imported.length,
|
|
29407
|
+
skipped: result.skipped.map((name) => {
|
|
29408
|
+
const reason = result.reasons?.[name];
|
|
29409
|
+
return reason ? { name, reason } : { name };
|
|
29410
|
+
})
|
|
29411
|
+
};
|
|
29412
|
+
} catch (error) {
|
|
29413
|
+
if (this.#mine(vault, form))
|
|
29414
|
+
this.#refuse(failureText(error), fieldOf(error, password ? "password" : "file"));
|
|
29415
|
+
} finally {
|
|
29416
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29417
|
+
}
|
|
29418
|
+
}
|
|
29419
|
+
#pick(name, event2) {
|
|
29420
|
+
const on = event2.currentTarget.checked;
|
|
29421
|
+
this.picked = new Set(
|
|
29422
|
+
on ? [...this.picked, name] : [...this.picked].filter((item2) => item2 !== name)
|
|
29423
|
+
);
|
|
29424
|
+
}
|
|
29425
|
+
async exportAll(vault, trigger2 = null) {
|
|
29426
|
+
const form = this.form;
|
|
29427
|
+
if (this.busy) return;
|
|
29428
|
+
const passphrase = take(this.#field("passphrase"));
|
|
29429
|
+
const repeat = take(this.#field("repeat"));
|
|
29430
|
+
const short2 = new TextEncoder().encode(passphrase).length < 8;
|
|
29431
|
+
const problem = short2 ? "Passphrases need at least 8 bytes" : passphrase !== repeat ? "The passphrases don't match" : null;
|
|
29432
|
+
this.#refuse(problem, short2 ? "passphrase" : "repeat", true);
|
|
29433
|
+
if (problem) return;
|
|
29434
|
+
const sure = await confirm({
|
|
29435
|
+
title: "Export your secrets?",
|
|
29436
|
+
body: "The file holds every value, encrypted with your passphrase. Keep it somewhere safe.",
|
|
29437
|
+
action: "Export",
|
|
29438
|
+
variant: "confirmation",
|
|
29439
|
+
trigger: trigger2
|
|
29440
|
+
});
|
|
29441
|
+
if (!sure || !this.#mine(vault, form) || this.#shut(vault)) return;
|
|
29442
|
+
this.busy = true;
|
|
29443
|
+
try {
|
|
29444
|
+
const bytes = await vault.export?.(passphrase);
|
|
29445
|
+
if (!this.#mine(vault, form)) return;
|
|
29446
|
+
const file = filename();
|
|
29447
|
+
download(bytes, file, this.renderRoot);
|
|
29448
|
+
this.form = null;
|
|
29449
|
+
this.said = { kind: "exported", file };
|
|
29450
|
+
} catch (error) {
|
|
29451
|
+
if (this.#mine(vault, form)) this.#refuse(failureText(error), fieldOf(error, "passphrase"));
|
|
29452
|
+
} finally {
|
|
29453
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29454
|
+
}
|
|
29455
|
+
}
|
|
28865
29456
|
async showOlder(vault, entries) {
|
|
28866
29457
|
this.loading = true;
|
|
28867
29458
|
this.failure = null;
|
|
@@ -28874,112 +29465,181 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28874
29465
|
this.older = merged(this.older, page.audit);
|
|
28875
29466
|
this.more = page.more;
|
|
28876
29467
|
} catch (error) {
|
|
28877
|
-
if (this
|
|
29468
|
+
if (this.#mine(vault)) this.failure = error.message;
|
|
28878
29469
|
} finally {
|
|
28879
29470
|
if (this.model?.vault === vault) this.loading = false;
|
|
28880
29471
|
}
|
|
28881
29472
|
}
|
|
28882
|
-
|
|
28883
|
-
|
|
28884
|
-
|
|
28885
|
-
|
|
28886
|
-
|
|
28887
|
-
|
|
28888
|
-
|
|
28889
|
-
|
|
28890
|
-
} catch (error) {
|
|
28891
|
-
if (this.model?.vault === vault && this.isConnected) this.failure = error.message;
|
|
28892
|
-
} finally {
|
|
28893
|
-
if (this.model?.vault === vault)
|
|
28894
|
-
this.acking = new Set([...this.acking].filter((id) => id !== notice.id));
|
|
29473
|
+
#error(text2, id) {
|
|
29474
|
+
return b`<p class="error" role="alert" id=${`error-${id}`} data-error=${id}><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${text2}</span></p>`;
|
|
29475
|
+
}
|
|
29476
|
+
#enter(event2, run2, locked) {
|
|
29477
|
+
if (event2.key === "Escape") {
|
|
29478
|
+
event2.preventDefault();
|
|
29479
|
+
this.open(null);
|
|
29480
|
+
return;
|
|
28895
29481
|
}
|
|
29482
|
+
if (event2.key !== "Enter" || event2.target.localName !== "input") return;
|
|
29483
|
+
event2.preventDefault();
|
|
29484
|
+
if (!locked && !this.busy) void run2();
|
|
29485
|
+
}
|
|
29486
|
+
#value(label, field = "value") {
|
|
29487
|
+
return b`<label class="field"><span>${label}</span><input type="password" autocomplete="off" spellcheck="false" data-field=${field} aria-invalid=${this.#bad(field)} aria-describedby=${this.#described(field)} /></label>`;
|
|
28896
29488
|
}
|
|
28897
|
-
#
|
|
28898
|
-
|
|
28899
|
-
|
|
29489
|
+
#actions(locked, label, action, run2) {
|
|
29490
|
+
return b`<div class="buttons">
|
|
29491
|
+
<swc-button size="m" variant="accent" data-action=${action} ?pending=${this.busy} ?disabled=${locked} @click=${run2}>${label}</swc-button>
|
|
29492
|
+
<swc-button size="m" variant="secondary" fill-style="outline" data-action="cancel" @click=${() => this.open(null)}>Cancel</swc-button>
|
|
29493
|
+
</div>`;
|
|
29494
|
+
}
|
|
29495
|
+
#locked(locked) {
|
|
29496
|
+
return locked ? b`<p class="muted" data-locked>Unlock the vault first</p>` : A;
|
|
29497
|
+
}
|
|
29498
|
+
#valueForm(vault, form, locked) {
|
|
29499
|
+
const save = () => this.save(vault);
|
|
29500
|
+
const add = form.kind === "add";
|
|
29501
|
+
return b`<div class="form" data-form=${form.kind} @input=${() => this.#typed()} @keydown=${(event2) => this.#enter(event2, save, locked)}>
|
|
29502
|
+
<strong>${add ? "Add a secret" : b`Replace the value of <code>${form.name}</code>`}</strong>
|
|
29503
|
+
${add ? b`<label class="field"><span>Name</span><input type="text" autocomplete="off" spellcheck="false" autocapitalize="characters" data-field="name" placeholder="API_TOKEN" aria-invalid=${this.#bad("name")} aria-describedby=${this.#described("name")} @input=${(event2) => this.#upper(event2)} /></label>` : A}
|
|
29504
|
+
${this.#value(add ? "Value" : "New value")}
|
|
29505
|
+
${this.#locked(locked)}
|
|
29506
|
+
${this.problem ? this.#error(this.problem, "form") : A}
|
|
29507
|
+
${this.#actions(locked, "Save", "save", save)}
|
|
29508
|
+
</div>`;
|
|
29509
|
+
}
|
|
29510
|
+
#upper(event2) {
|
|
29511
|
+
const input = event2.currentTarget;
|
|
29512
|
+
input.value = input.value.toUpperCase();
|
|
29513
|
+
}
|
|
29514
|
+
#importForm(vault, locked) {
|
|
29515
|
+
const read = () => this.read(vault);
|
|
29516
|
+
const candidates2 = this.candidates;
|
|
29517
|
+
return b`<div class="form" data-form="import" @input=${() => this.#typed()} @keydown=${(event2) => this.#enter(event2, read, locked)}>
|
|
29518
|
+
<strong>Import secrets</strong>
|
|
29519
|
+
<label class="field"><span id="import-kind">Kind</span>
|
|
29520
|
+
<sp-picker size="m" label="Kind" aria-labelledby="import-kind" data-field="kind" value=${this.importKind} @change=${(event2) => this.#kind(event2)}>
|
|
29521
|
+
${Object.entries(importKinds).map(([value, label]) => b`<sp-menu-item value=${value}>${label}</sp-menu-item>`)}
|
|
29522
|
+
</sp-picker>
|
|
29523
|
+
</label>
|
|
29524
|
+
<label class="field"><span>File</span><input type="file" data-field="file" aria-invalid=${this.#bad("file")} aria-describedby=${this.#described("file")} @change=${() => this.#reset()} /></label>
|
|
29525
|
+
<label class="field"><span>${this.again ? "Password, once more to import" : "Password, if the file has one"}</span><input type="password" autocomplete="off" spellcheck="false" data-field="password" aria-invalid=${this.#bad("password")} aria-describedby=${this.#described("password")} /></label>
|
|
29526
|
+
${candidates2 ? b`<fieldset class="picks" data-picks>
|
|
29527
|
+
<legend class="muted">Choose what to import</legend>
|
|
29528
|
+
<p class="muted" data-rules-note>Rules from the file aren't applied. Add them with sudo.</p>
|
|
29529
|
+
${candidates2.map(
|
|
29530
|
+
(item2) => b`<label data-candidate=${item2.name}>
|
|
29531
|
+
<input type="checkbox" data-pick=${item2.name} .checked=${this.picked.has(item2.name)} ?disabled=${!!item2.refused} @change=${(event2) => this.#pick(item2.name, event2)} />
|
|
29532
|
+
<span class="about">
|
|
29533
|
+
<span><code>${item2.name}</code>${item2.exists ? b` <swc-badge size="s" variant="notice" subtle>Replaces a secret</swc-badge>` : A}</span>
|
|
29534
|
+
${item2.refused ? b`<span class="muted" data-refused-reason>Can't be imported: ${item2.refused}</span>` : A}
|
|
29535
|
+
${item2.suggestedRules ? b`<span class="suggested" data-suggested><span class="from">From the file, not checked by SLICC:</span> <span class="said">${prompt2(item2.suggestedRules)}</span></span>` : A}
|
|
29536
|
+
</span>
|
|
29537
|
+
</label>`
|
|
29538
|
+
)}
|
|
29539
|
+
</fieldset>` : A}
|
|
29540
|
+
${this.#locked(locked)}
|
|
29541
|
+
${this.problem ? this.#error(this.problem, "form") : A}
|
|
29542
|
+
${candidates2 ? this.#actions(
|
|
29543
|
+
locked || !this.picked.size,
|
|
29544
|
+
`Import ${this.picked.size}`,
|
|
29545
|
+
"import-picked",
|
|
29546
|
+
read
|
|
29547
|
+
) : this.#actions(locked, "Continue", "read", read)}
|
|
29548
|
+
</div>`;
|
|
29549
|
+
}
|
|
29550
|
+
#exportForm(vault, locked) {
|
|
29551
|
+
const run2 = () => this.exportAll(vault);
|
|
29552
|
+
return b`<div class="form" data-form="export" @input=${() => this.#typed()} @keydown=${(event2) => this.#enter(event2, run2, locked)}>
|
|
29553
|
+
<strong>Export secrets</strong>
|
|
29554
|
+
<span class="muted">The file is sealed with this passphrase. You need it to import the file again.</span>
|
|
29555
|
+
${this.#value("Passphrase", "passphrase")}
|
|
29556
|
+
${this.#value("Passphrase again", "repeat")}
|
|
29557
|
+
${exported(this.model?.vault?.status()?.exportedAt)}
|
|
29558
|
+
${this.#locked(locked)}
|
|
29559
|
+
${this.problem ? this.#error(this.problem, "form") : A}
|
|
29560
|
+
${this.#actions(locked, "Export", "download", run2)}
|
|
29561
|
+
</div>`;
|
|
29562
|
+
}
|
|
29563
|
+
#request(vault, request2) {
|
|
29564
|
+
const what = asking2(request2);
|
|
28900
29565
|
return b`<div class="box" data-request=${request2.id}>
|
|
28901
29566
|
<span class="title">${what}</span>
|
|
28902
29567
|
${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}
|
|
28903
29568
|
<div class="actions">
|
|
28904
|
-
${
|
|
29569
|
+
${request2.kind === "value" && vault.put && !this.#offline ? b`<swc-button size="m" variant="accent" data-action="answer" @click=${() => this.answer(request2.id)}>Enter value</swc-button>` : A}
|
|
29570
|
+
${vault.cancel && !this.#offline ? b`<swc-button size="m" variant="secondary" fill-style="outline" data-action="cancel-request" ?pending=${this.acting.has(`cancel:${request2.id}`)} @click=${() => this.cancelRequest(vault, request2.id)}>Cancel request</swc-button>` : A}
|
|
28905
29571
|
<span class="muted">Expires ${until(request2.expiresAt)}</span>
|
|
28906
29572
|
</div>
|
|
28907
29573
|
</div>`;
|
|
28908
29574
|
}
|
|
28909
|
-
#notice(vault, notice, devices) {
|
|
28910
|
-
return b`<div class="box notice" role="alert" data-notice=${notice.id}>
|
|
28911
|
-
<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>
|
|
28912
|
-
<ul>${notice.widened.map((change) => b`<li>${widening(change, devices)}</li>`)}</ul>
|
|
28913
|
-
<span>If you didn’t mean this, change the file back with sudo.</span>
|
|
28914
|
-
<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>
|
|
28915
|
-
</div>`;
|
|
28916
|
-
}
|
|
28917
29575
|
#state(secret) {
|
|
28918
29576
|
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"];
|
|
28919
29577
|
return b`<swc-status-light size="s" variant=${variant}>${label}</swc-status-light>`;
|
|
28920
29578
|
}
|
|
28921
|
-
#
|
|
29579
|
+
#controls(vault, secret) {
|
|
29580
|
+
if (this.#offline) return A;
|
|
29581
|
+
const { name } = secret;
|
|
28922
29582
|
if (secret.state === "removed")
|
|
28923
|
-
return this
|
|
28924
|
-
|
|
28925
|
-
|
|
28926
|
-
|
|
28927
|
-
})
|
|
28928
|
-
|
|
28929
|
-
|
|
28930
|
-
intent: { kind: "signin", provider: secret.source.slice("oauth:".length) },
|
|
28931
|
-
label: "Sign in again",
|
|
28932
|
-
size: "s"
|
|
28933
|
-
});
|
|
28934
|
-
return this.#button({
|
|
28935
|
-
intent: { kind: "enter", name: secret.name },
|
|
28936
|
-
label: "Replace value",
|
|
28937
|
-
size: "s"
|
|
28938
|
-
});
|
|
29583
|
+
return vault.restore ? b`<div class="buttons"><swc-button size="s" variant="secondary" data-action="restore" ?pending=${this.acting.has(`restore:${name}`)} @click=${() => this.restoreSecret(vault, secret)}>Restore</swc-button></div>` : A;
|
|
29584
|
+
const replace = vault.put && replaceable(secret);
|
|
29585
|
+
if (!replace && !vault.remove) return A;
|
|
29586
|
+
return b`<div class="buttons">
|
|
29587
|
+
${replace ? b`<swc-button size="s" variant="secondary" data-action="replace" @click=${() => this.open({ kind: "replace", name })}>Replace value</swc-button>` : A}
|
|
29588
|
+
${vault.remove ? b`<swc-button size="s" variant="secondary" fill-style="outline" data-action="remove" ?pending=${this.acting.has(`remove:${name}`)} @click=${(event2) => this.removeSecret(vault, secret, event2.currentTarget)}>Remove</swc-button>` : A}
|
|
29589
|
+
</div>`;
|
|
28939
29590
|
}
|
|
28940
|
-
#secret(secret, entries, devices, more) {
|
|
29591
|
+
#secret(vault, secret, entries, devices, more, locked) {
|
|
28941
29592
|
const kind = kinds[secret.kind];
|
|
28942
29593
|
const reveal = revealed(secret.name, entries, Date.now(), more);
|
|
29594
|
+
const exec = execLine(secret.exec, secret.execArgv);
|
|
28943
29595
|
const gone2 = secret.state === "removed";
|
|
29596
|
+
const form = this.#offline ? null : this.form;
|
|
28944
29597
|
return b`<li class="secret" data-secret=${secret.name} data-state=${secret.state}>
|
|
28945
29598
|
<div class="name">
|
|
28946
29599
|
<code>${secret.name}</code>
|
|
28947
29600
|
${kind ? b`<swc-badge size="s" variant="neutral" subtle>${kind}</swc-badge>` : A}
|
|
28948
29601
|
${this.#state(secret)}
|
|
28949
29602
|
</div>
|
|
28950
|
-
${this.#
|
|
29603
|
+
${this.#controls(vault, secret)}
|
|
28951
29604
|
<dl>
|
|
28952
29605
|
<dt>${gone2 ? "Was sent to" : "Sent to"}</dt>
|
|
28953
29606
|
<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>
|
|
28954
|
-
|
|
28955
|
-
|
|
28956
|
-
<dt>Programs</dt>
|
|
28957
|
-
<dd data-exec>${execLine(secret.exec)}${reveal ? b`<br />${reveal}` : A}</dd>
|
|
29607
|
+
${secret.exits ? b`<dt>${gone2 ? "Left through" : "Leaves through"}</dt><dd data-exits>${secret.exits.length ? list4(secret.exits.map((exit) => exitLabel(exit, devices))) : "No exit"}</dd>` : A}
|
|
29608
|
+
${exec || reveal ? b`<dt>Programs</dt><dd data-exec>${exec}${exec && reveal ? b`<br />` : A}${reveal}</dd>` : A}
|
|
28958
29609
|
<dt>From</dt>
|
|
28959
29610
|
<dd data-source>${sourceLine(secret, devices)}</dd>
|
|
28960
29611
|
${secret.usedAt ? b`<dt>Last used</dt><dd data-used>${since(secret.usedAt)}</dd>` : A}
|
|
28961
29612
|
${secret.expiresAt ? b`<dt>Expires</dt><dd data-expires>${until(secret.expiresAt)}</dd>` : A}
|
|
28962
29613
|
${secret.removedAt ? b`<dt>Removed</dt><dd>${since(secret.removedAt)}</dd>` : A}
|
|
28963
29614
|
</dl>
|
|
29615
|
+
${form?.kind === "replace" && form.name === secret.name ? this.#valueForm(vault, form, locked) : A}
|
|
28964
29616
|
</li>`;
|
|
28965
29617
|
}
|
|
28966
|
-
#secrets(list5, entries, devices) {
|
|
29618
|
+
#secrets(vault, list5, entries, devices, locked) {
|
|
28967
29619
|
const more = this.more ?? list5.auditMore;
|
|
28968
|
-
const row = (secret) => this.#secret(secret, entries, devices, more);
|
|
28969
|
-
const
|
|
28970
|
-
const
|
|
29620
|
+
const row = (secret) => this.#secret(vault, secret, entries, devices, more, locked);
|
|
29621
|
+
const sorted = [...list5.secrets].sort(byName);
|
|
29622
|
+
const live = sorted.filter((secret) => secret.state !== "removed");
|
|
29623
|
+
const removed = sorted.filter((secret) => secret.state === "removed");
|
|
28971
29624
|
return b`${live.length ? b`<ul class="secrets" aria-labelledby="secrets">${live.map(row)}</ul>` : A}
|
|
28972
29625
|
${removed.length ? b`<details class="removed" data-removed>
|
|
28973
29626
|
<summary>Removed (${removed.length})</summary>
|
|
28974
29627
|
<ul class="secrets">${removed.map(row)}</ul>
|
|
28975
29628
|
</details>` : A}`;
|
|
28976
29629
|
}
|
|
29630
|
+
#refused(refused2) {
|
|
29631
|
+
if (!refused2.length) return A;
|
|
29632
|
+
return b`<h3 id="secrets-refused">Rules SLICC refused</h3>
|
|
29633
|
+
<ul class="refused" aria-labelledby="secrets-refused" data-refused>
|
|
29634
|
+
${refused2.map((item2) => b`<li data-refused-secret=${item2.secret}><span><code>${item2.secret}</code> to ${ruleLine(item2.rule)}</span><span class="muted">${item2.reason}</span></li>`)}
|
|
29635
|
+
</ul>`;
|
|
29636
|
+
}
|
|
28977
29637
|
#entry(entry, devices) {
|
|
28978
29638
|
const date = new Date(entry.at);
|
|
28979
29639
|
const name = entry.type === "policy" ? null : entry.name;
|
|
28980
29640
|
return b`<li data-seq=${entry.seq} data-type=${entry.type}>
|
|
28981
29641
|
<time datetime=${date.toISOString()} title=${date.toLocaleString("en-GB", { dateStyle: "medium", timeStyle: "short" })}>${since(entry.at)}</time>
|
|
28982
|
-
<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>
|
|
29642
|
+
<span class="what">${name ? b`<code>${name}</code> · ` : A}${auditLine(entry, devices)}${entry.type === "policy" || entry.type === "refresh" ? A : b` <span class="by">by ${who(entry)}</span>`}</span>
|
|
28983
29643
|
</li>`;
|
|
28984
29644
|
}
|
|
28985
29645
|
#audit(vault, list5, entries, devices) {
|
|
@@ -28995,12 +29655,52 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28995
29655
|
${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}`;
|
|
28996
29656
|
}
|
|
28997
29657
|
#feedback() {
|
|
29658
|
+
const said = this.said;
|
|
28998
29659
|
if (this.popup?.state === "blocked")
|
|
28999
29660
|
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>`;
|
|
29000
|
-
if (
|
|
29001
|
-
|
|
29661
|
+
if (!said) return A;
|
|
29662
|
+
if (said.kind === "saved")
|
|
29663
|
+
return b`<p role="status" data-said="saved">Saved <code>${said.name}</code> in the vault</p>`;
|
|
29664
|
+
if (said.kind === "imported")
|
|
29665
|
+
return b`<div role="status" data-said="imported"><p>Imported ${said.imported}</p>${said.skipped.map((item2) => b`<p class="skipped" data-skipped=${item2.name}>Skipped <code>${item2.name}</code>${item2.reason ? b`: <span class="said">${item2.reason}</span>` : A}</p>`)}</div>`;
|
|
29666
|
+
return b`<p role="status" data-said="exported">Exported to <code>${said.file}</code></p>`;
|
|
29667
|
+
}
|
|
29668
|
+
#availability() {
|
|
29669
|
+
if (this.#offline)
|
|
29670
|
+
return b`<p class="availability" role="status" data-availability="waiting"><swc-progress-circle size="s" indeterminate label="Waiting for the vault" aria-hidden="true"></swc-progress-circle><span>Waiting for the vault</span></p>`;
|
|
29002
29671
|
return A;
|
|
29003
29672
|
}
|
|
29673
|
+
#backup(vault, status2) {
|
|
29674
|
+
if (status2?.backupReminder !== "due" || this.#offline) return A;
|
|
29675
|
+
return b`<div class="box info" role="region" aria-labelledby="secrets-backup" data-backup>
|
|
29676
|
+
<span class="title" id="secrets-backup"><swc-icon-info-circle size="s" aria-hidden="true"></swc-icon-info-circle><span>Export a backup of your secrets. Clearing this site's data loses every value.</span></span>
|
|
29677
|
+
<div class="actions">
|
|
29678
|
+
${vault.export ? b`<swc-button size="m" variant="accent" data-action="export" @click=${() => this.open({ kind: "export" })}>Export backup</swc-button>` : A}
|
|
29679
|
+
${vault.dismissBackupReminder ? b`<swc-button size="m" variant="secondary" fill-style="outline" data-action="dismiss-backup" ?pending=${this.acting.has("backup")} @click=${() => this.dismissBackup(vault)}>Not now</swc-button>` : A}
|
|
29680
|
+
</div>
|
|
29681
|
+
</div>`;
|
|
29682
|
+
}
|
|
29683
|
+
#header(vault, status2) {
|
|
29684
|
+
if (!status2) return A;
|
|
29685
|
+
if (this.#offline)
|
|
29686
|
+
return b`<swc-status-light size="m" variant="neutral">Waiting</swc-status-light>`;
|
|
29687
|
+
return b`<swc-status-light size="m" variant=${status2.locked ? "notice" : "positive"}>${status2.locked ? "Locked" : "Unlocked"}</swc-status-light><span class="muted">${lockModes[status2.lock]}</span>
|
|
29688
|
+
<span class="controls">${status2.locked ? b`${status2.scrub?.needed && !status2.scrub.ready ? b`<span class="availability" role="status" data-availability="unlock"><swc-icon-info-circle size="s" aria-hidden="true"></swc-icon-info-circle><span>Unlock the vault to continue</span></span>` : A}${this.#button({ intent: { kind: "unlock" }, label: "Unlock", variant: "accent" }, "unlock")}` : b`${vault.lock ? b`<swc-button size="m" variant="secondary" fill-style="outline" data-action="lock" ?pending=${this.acting.has("lock")} @click=${() => this.lockVault(vault)}>Lock</swc-button>` : A}
|
|
29689
|
+
${this.#button({ intent: { kind: "protect" }, label: status2.lock === "auto" ? "Protect with a passkey" : "Change protection" }, "protect")}`}</span>`;
|
|
29690
|
+
}
|
|
29691
|
+
#tools(vault, locked) {
|
|
29692
|
+
if (this.#offline) return A;
|
|
29693
|
+
const form = this.form;
|
|
29694
|
+
const tool2 = (kind, label, variant = "secondary") => b`<swc-button size="m" variant=${variant} data-action=${kind === "add" ? "add-secret" : kind} aria-expanded=${form?.kind === kind ? "true" : "false"} @click=${() => this.open(form?.kind === kind ? null : { kind })}>${label}</swc-button>`;
|
|
29695
|
+
return b`${vault.put || vault.import || vault.export ? b`<div class="row" data-tools>
|
|
29696
|
+
${vault.put ? tool2("add", "Add secret", "accent") : A}
|
|
29697
|
+
${vault.import ? tool2("import", "Import\u2026") : A}
|
|
29698
|
+
${vault.export ? tool2("export", "Export\u2026") : A}
|
|
29699
|
+
</div>` : A}
|
|
29700
|
+
${form?.kind === "add" ? this.#valueForm(vault, form, locked) : A}
|
|
29701
|
+
${form?.kind === "import" ? this.#importForm(vault, locked) : A}
|
|
29702
|
+
${form?.kind === "export" ? this.#exportForm(vault, locked) : A}`;
|
|
29703
|
+
}
|
|
29004
29704
|
render() {
|
|
29005
29705
|
const vault = this.model?.vault;
|
|
29006
29706
|
if (!vault) return A;
|
|
@@ -29008,28 +29708,26 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
29008
29708
|
const current = vault.list();
|
|
29009
29709
|
const devices = devicesOf(this.model);
|
|
29010
29710
|
const entries = merged(current?.audit ?? [], this.older);
|
|
29011
|
-
const
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
].filter((
|
|
29711
|
+
const locked = !!status2?.locked;
|
|
29712
|
+
this.#offline = away(vault);
|
|
29713
|
+
if (this.#offline && this.form) clearValues(this.renderRoot);
|
|
29714
|
+
const now = Date.now();
|
|
29715
|
+
const waiting2 = (status2?.waiting ?? []).filter((request2) => request2.expiresAt > now);
|
|
29016
29716
|
return b`<section aria-labelledby="secrets" data-vault=${status2 ? status2.locked ? "locked" : "unlocked" : "loading"}>
|
|
29017
29717
|
<div class="head">
|
|
29018
29718
|
<h2 id="secrets">Secrets</h2>
|
|
29019
|
-
${
|
|
29020
|
-
${status2?.locked ? this.#button({ intent: { kind: "unlock" }, label: "Unlock", variant: "accent" }) : this.#button({ intent: { kind: "manage" }, label: "Open the vault" })}
|
|
29719
|
+
${this.#header(vault, status2)}
|
|
29021
29720
|
</div>
|
|
29022
|
-
<p class="muted">Agents and programs use secrets by name.
|
|
29721
|
+
<p class="muted">Agents and programs use secrets by name. SLICC sends each value only where its rules allow, so agents never see it.</p>
|
|
29722
|
+
${this.#availability()}
|
|
29023
29723
|
${this.#feedback()}
|
|
29024
|
-
${this.failure ?
|
|
29025
|
-
${
|
|
29026
|
-
${
|
|
29027
|
-
${
|
|
29724
|
+
${this.failure ? this.#error(this.failure, "vault") : A}
|
|
29725
|
+
${waiting2.length ? b`<h3>Waiting for you</h3>${waiting2.map((request2) => this.#request(vault, request2))}` : A}
|
|
29726
|
+
${this.#backup(vault, status2)}
|
|
29727
|
+
${this.#tools(vault, locked)}
|
|
29728
|
+
${!current ? this.#offline ? A : b`<p class="muted" data-loading>Loading secrets…</p>` : current.secrets.length ? this.#secrets(vault, current, entries, devices, locked) : b`<p data-empty>No secrets yet. Add one here, or enter the value when an agent or program asks for one.</p>`}
|
|
29729
|
+
${this.#refused(current?.refused ?? [])}
|
|
29028
29730
|
<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>
|
|
29029
|
-
<div class="row">
|
|
29030
|
-
${this.#button({ intent: { kind: "import" }, label: "Import\u2026", size: "s" })}
|
|
29031
|
-
${this.#button({ intent: { kind: "export" }, label: "Export\u2026", size: "s" })}
|
|
29032
|
-
</div>
|
|
29033
29731
|
${current ? this.#audit(vault, current, entries, devices) : A}
|
|
29034
29732
|
</section>`;
|
|
29035
29733
|
}
|
|
@@ -29824,6 +30522,292 @@ ${data.html}`;
|
|
|
29824
30522
|
}
|
|
29825
30523
|
};
|
|
29826
30524
|
|
|
30525
|
+
// src/app/value-request.ts
|
|
30526
|
+
function valueRequests(vault, now) {
|
|
30527
|
+
return [...vault?.status()?.waiting ?? []].filter((request2) => request2.kind === "value" && request2.expiresAt > now).sort((a22, b13) => a22.createdAt - b13.createdAt);
|
|
30528
|
+
}
|
|
30529
|
+
var SliccValueRequest = class extends ThemedElement {
|
|
30530
|
+
static properties = {
|
|
30531
|
+
...ThemedElement.properties,
|
|
30532
|
+
now: { state: true },
|
|
30533
|
+
busy: { state: true },
|
|
30534
|
+
problem: { state: true },
|
|
30535
|
+
blocked: { state: true }
|
|
30536
|
+
};
|
|
30537
|
+
#later = /* @__PURE__ */ new Set();
|
|
30538
|
+
#done = /* @__PURE__ */ new Set();
|
|
30539
|
+
#front = "";
|
|
30540
|
+
#shown = "";
|
|
30541
|
+
#trigger = null;
|
|
30542
|
+
#timer = null;
|
|
30543
|
+
#port;
|
|
30544
|
+
#open = (event2) => {
|
|
30545
|
+
const { id, vault } = event2.detail;
|
|
30546
|
+
if (vault === void 0 || vault === this.model?.vault) this.reopen(id);
|
|
30547
|
+
};
|
|
30548
|
+
constructor() {
|
|
30549
|
+
super();
|
|
30550
|
+
this.now = Date.now();
|
|
30551
|
+
this.busy = false;
|
|
30552
|
+
this.problem = null;
|
|
30553
|
+
this.blocked = false;
|
|
30554
|
+
}
|
|
30555
|
+
static styles = [
|
|
30556
|
+
dialogStyles,
|
|
30557
|
+
fieldStyles,
|
|
30558
|
+
i`
|
|
30559
|
+
:host {
|
|
30560
|
+
display: contents;
|
|
30561
|
+
}
|
|
30562
|
+
.asked {
|
|
30563
|
+
margin-block-start: var(--swc-spacing-100);
|
|
30564
|
+
}
|
|
30565
|
+
.timer,
|
|
30566
|
+
.more,
|
|
30567
|
+
.locked {
|
|
30568
|
+
margin-block-start: var(--swc-spacing-100);
|
|
30569
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
30570
|
+
font-size: var(--swc-font-size-75);
|
|
30571
|
+
}
|
|
30572
|
+
.prompt {
|
|
30573
|
+
margin-block-start: var(--swc-spacing-200);
|
|
30574
|
+
padding-inline-start: var(--swc-spacing-200);
|
|
30575
|
+
border-inline-start: var(--swc-border-width-200) solid var(--swc-gray-300);
|
|
30576
|
+
overflow-wrap: anywhere;
|
|
30577
|
+
}
|
|
30578
|
+
.said {
|
|
30579
|
+
white-space: pre-wrap;
|
|
30580
|
+
}
|
|
30581
|
+
.from {
|
|
30582
|
+
display: block;
|
|
30583
|
+
font-size: var(--swc-font-size-75);
|
|
30584
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
30585
|
+
}
|
|
30586
|
+
.fields {
|
|
30587
|
+
display: grid;
|
|
30588
|
+
gap: var(--swc-spacing-200);
|
|
30589
|
+
margin-block-start: var(--swc-spacing-300);
|
|
30590
|
+
padding: var(--swc-spacing-75);
|
|
30591
|
+
}
|
|
30592
|
+
.unlock {
|
|
30593
|
+
display: flex;
|
|
30594
|
+
flex-wrap: wrap;
|
|
30595
|
+
align-items: center;
|
|
30596
|
+
gap: var(--swc-spacing-200);
|
|
30597
|
+
margin-block-start: var(--swc-spacing-200);
|
|
30598
|
+
}
|
|
30599
|
+
.problem {
|
|
30600
|
+
display: flex;
|
|
30601
|
+
align-items: flex-start;
|
|
30602
|
+
gap: var(--swc-spacing-75);
|
|
30603
|
+
margin-block-start: var(--swc-spacing-200);
|
|
30604
|
+
color: var(--swc-negative-content-color-default);
|
|
30605
|
+
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
30606
|
+
}
|
|
30607
|
+
code {
|
|
30608
|
+
font-family: var(--swc-code-font-family-stack);
|
|
30609
|
+
overflow-wrap: anywhere;
|
|
30610
|
+
}
|
|
30611
|
+
`
|
|
30612
|
+
];
|
|
30613
|
+
connectedCallback() {
|
|
30614
|
+
super.connectedCallback();
|
|
30615
|
+
this.ownerDocument.addEventListener("value-request", this.#open);
|
|
30616
|
+
}
|
|
30617
|
+
disconnectedCallback() {
|
|
30618
|
+
super.disconnectedCallback();
|
|
30619
|
+
this.ownerDocument.removeEventListener("value-request", this.#open);
|
|
30620
|
+
clearValues(this.renderRoot);
|
|
30621
|
+
this.#tick(false);
|
|
30622
|
+
this.#shown = "";
|
|
30623
|
+
}
|
|
30624
|
+
subscribe(model) {
|
|
30625
|
+
if (model.vault !== this.#port) {
|
|
30626
|
+
clearValues(this.renderRoot);
|
|
30627
|
+
this.#port = model.vault;
|
|
30628
|
+
this.#later.clear();
|
|
30629
|
+
this.#done.clear();
|
|
30630
|
+
this.#front = "";
|
|
30631
|
+
this.busy = false;
|
|
30632
|
+
this.problem = null;
|
|
30633
|
+
this.blocked = false;
|
|
30634
|
+
}
|
|
30635
|
+
const update = () => {
|
|
30636
|
+
this.now = Date.now();
|
|
30637
|
+
this.requestUpdate();
|
|
30638
|
+
};
|
|
30639
|
+
return [
|
|
30640
|
+
...super.subscribe(model),
|
|
30641
|
+
...model.vault ? [model.vault.on("status", update), model.vault.on("availability", update)] : []
|
|
30642
|
+
];
|
|
30643
|
+
}
|
|
30644
|
+
reopen(id) {
|
|
30645
|
+
this.#later.delete(id);
|
|
30646
|
+
this.#front = id;
|
|
30647
|
+
this.now = Date.now();
|
|
30648
|
+
}
|
|
30649
|
+
later(id) {
|
|
30650
|
+
if (this.busy) return;
|
|
30651
|
+
clearValues(this.renderRoot);
|
|
30652
|
+
this.#later.add(id);
|
|
30653
|
+
if (this.#front === id) this.#front = "";
|
|
30654
|
+
this.problem = null;
|
|
30655
|
+
this.requestUpdate();
|
|
30656
|
+
}
|
|
30657
|
+
#queue() {
|
|
30658
|
+
const vault = this.model?.vault;
|
|
30659
|
+
if (!vault || away(vault)) return [];
|
|
30660
|
+
return valueRequests(vault, this.now).filter(({ id }) => !this.#done.has(id));
|
|
30661
|
+
}
|
|
30662
|
+
#current(queue) {
|
|
30663
|
+
return queue.find(({ id }) => id === this.#front) ?? queue.find(({ id }) => !this.#later.has(id)) ?? null;
|
|
30664
|
+
}
|
|
30665
|
+
#tick(on) {
|
|
30666
|
+
if (on && !this.#timer) this.#timer = setInterval(() => this.now = Date.now(), 1e3);
|
|
30667
|
+
if (!on && this.#timer) {
|
|
30668
|
+
clearInterval(this.#timer);
|
|
30669
|
+
this.#timer = null;
|
|
30670
|
+
}
|
|
30671
|
+
}
|
|
30672
|
+
#mine(vault) {
|
|
30673
|
+
return this.model?.vault === vault && this.isConnected;
|
|
30674
|
+
}
|
|
30675
|
+
#field(name) {
|
|
30676
|
+
return this.renderRoot.querySelector(`input[data-field=${name}]`);
|
|
30677
|
+
}
|
|
30678
|
+
async save(request2) {
|
|
30679
|
+
const vault = this.model?.vault;
|
|
30680
|
+
if (this.busy) return;
|
|
30681
|
+
const name = request2.name ?? this.#field("name").value.trim();
|
|
30682
|
+
const bad = nameProblem(name);
|
|
30683
|
+
const value = bad ? "" : take(this.#field("value"));
|
|
30684
|
+
const text2 = bad ?? valueProblem(value);
|
|
30685
|
+
const field = bad ? "name" : "value";
|
|
30686
|
+
this.problem = text2 ? { id: request2.id, text: text2, field } : null;
|
|
30687
|
+
if (text2) {
|
|
30688
|
+
void this.updateComplete.then(() => this.#field(field)?.focus());
|
|
30689
|
+
return;
|
|
30690
|
+
}
|
|
30691
|
+
this.busy = true;
|
|
30692
|
+
try {
|
|
30693
|
+
await vault.put?.(name, value, request2.id);
|
|
30694
|
+
if (!this.#mine(vault)) return;
|
|
30695
|
+
this.#done.add(request2.id);
|
|
30696
|
+
} catch (error) {
|
|
30697
|
+
if (this.#mine(vault)) {
|
|
30698
|
+
const field2 = fieldOf(error, "value");
|
|
30699
|
+
this.problem = { id: request2.id, text: failureText(error), ...field2 ? { field: field2 } : {} };
|
|
30700
|
+
}
|
|
30701
|
+
} finally {
|
|
30702
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
30703
|
+
}
|
|
30704
|
+
}
|
|
30705
|
+
#typed() {
|
|
30706
|
+
if (this.problem?.field) this.problem = { id: this.problem.id, text: this.problem.text };
|
|
30707
|
+
}
|
|
30708
|
+
#aria(field, problem) {
|
|
30709
|
+
const bad = problem?.field === field;
|
|
30710
|
+
return { invalid: bad ? "true" : A, described: bad ? "error-request" : A };
|
|
30711
|
+
}
|
|
30712
|
+
async cancelRequest(request2) {
|
|
30713
|
+
const vault = this.model?.vault;
|
|
30714
|
+
if (this.busy) return;
|
|
30715
|
+
clearValues(this.renderRoot);
|
|
30716
|
+
this.busy = true;
|
|
30717
|
+
this.problem = null;
|
|
30718
|
+
try {
|
|
30719
|
+
await vault.cancel?.(request2.id);
|
|
30720
|
+
if (this.#mine(vault)) this.#done.add(request2.id);
|
|
30721
|
+
} catch (error) {
|
|
30722
|
+
if (this.#mine(vault)) this.problem = { id: request2.id, text: failureText(error) };
|
|
30723
|
+
} finally {
|
|
30724
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
30725
|
+
}
|
|
30726
|
+
}
|
|
30727
|
+
willUpdate(changed) {
|
|
30728
|
+
super.willUpdate(changed);
|
|
30729
|
+
const current = this.#current(this.#queue());
|
|
30730
|
+
if ((current?.id ?? "") !== this.#shown) clearValues(this.renderRoot);
|
|
30731
|
+
}
|
|
30732
|
+
updated(changed) {
|
|
30733
|
+
super.updated(changed);
|
|
30734
|
+
const dialog = this.renderRoot.querySelector("dialog");
|
|
30735
|
+
this.#tick(this.isConnected && !!dialog);
|
|
30736
|
+
const key2 = dialog?.dataset.request ?? "";
|
|
30737
|
+
if (key2 === this.#shown) return;
|
|
30738
|
+
if (dialog && !this.#shown) this.#trigger = focused();
|
|
30739
|
+
this.#shown = key2;
|
|
30740
|
+
if (!dialog) {
|
|
30741
|
+
if (this.#trigger?.isConnected) this.#trigger.focus();
|
|
30742
|
+
this.#trigger = null;
|
|
30743
|
+
return;
|
|
30744
|
+
}
|
|
30745
|
+
if (!dialog.open) dialog.showModal();
|
|
30746
|
+
const target = dialog.querySelector("input") ?? dialog.querySelector("[data-action=later]");
|
|
30747
|
+
void dialog.querySelector("sp-alert-dialog").updateComplete.then(
|
|
30748
|
+
() => target.focus()
|
|
30749
|
+
);
|
|
30750
|
+
}
|
|
30751
|
+
#onKey(event2, request2) {
|
|
30752
|
+
if (event2.key !== "Enter" || event2.target.localName !== "input") return;
|
|
30753
|
+
event2.preventDefault();
|
|
30754
|
+
if (!this.model?.vault?.status()?.locked) void this.save(request2);
|
|
30755
|
+
}
|
|
30756
|
+
#unlock(vault) {
|
|
30757
|
+
return b`<div class="unlock" data-locked>
|
|
30758
|
+
<span class="locked">Unlock the vault first</span>
|
|
30759
|
+
<slicc-vault-button
|
|
30760
|
+
data-action="unlock"
|
|
30761
|
+
.vault=${vault}
|
|
30762
|
+
.config=${{ intent: { kind: "unlock" }, label: "Unlock", size: "m", variant: "accent", theme: this.color }}
|
|
30763
|
+
@vault-popup=${(event2) => {
|
|
30764
|
+
this.blocked = event2.detail.state === "blocked";
|
|
30765
|
+
}}
|
|
30766
|
+
></slicc-vault-button>
|
|
30767
|
+
${this.blocked ? b`<span class="problem" 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></span>` : A}
|
|
30768
|
+
</div>`;
|
|
30769
|
+
}
|
|
30770
|
+
render() {
|
|
30771
|
+
const vault = this.model?.vault;
|
|
30772
|
+
const queue = this.#queue();
|
|
30773
|
+
const request2 = this.#current(queue);
|
|
30774
|
+
if (!vault || !request2) return A;
|
|
30775
|
+
const locked = !!vault.status()?.locked;
|
|
30776
|
+
const rest = queue.length - 1;
|
|
30777
|
+
const shown3 = this.problem?.id === request2.id ? this.problem : null;
|
|
30778
|
+
const problem = shown3?.text ?? "";
|
|
30779
|
+
const name = this.#aria("name", shown3);
|
|
30780
|
+
const field = this.#aria("value", shown3);
|
|
30781
|
+
return i17(
|
|
30782
|
+
request2.id,
|
|
30783
|
+
b`<dialog role="alertdialog" aria-labelledby="title" aria-describedby="asked" data-request=${request2.id} @cancel=${(event2) => {
|
|
30784
|
+
event2.preventDefault();
|
|
30785
|
+
this.later(request2.id);
|
|
30786
|
+
}}>
|
|
30787
|
+
<sp-alert-dialog variant="confirmation">
|
|
30788
|
+
<h2 id="title" slot="heading">${request2.name ? b`Enter a value for <code>${request2.name}</code>` : "Enter a value"}</h2>
|
|
30789
|
+
<p class="asked" id="asked" data-asked>${asking2(request2)}</p>
|
|
30790
|
+
${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}
|
|
30791
|
+
${vault.put ? b`<div class="fields" @input=${() => this.#typed()} @keydown=${(event2) => this.#onKey(event2, request2)}>
|
|
30792
|
+
${request2.name ? A : b`<label class="field"><span>Name</span><input type="text" autocomplete="off" spellcheck="false" autocapitalize="characters" data-field="name" aria-invalid=${name.invalid} aria-describedby=${name.described} @input=${(event2) => {
|
|
30793
|
+
const input = event2.currentTarget;
|
|
30794
|
+
input.value = input.value.toUpperCase();
|
|
30795
|
+
}} /></label>`}
|
|
30796
|
+
<label class="field"><span>Value</span><input type="password" autocomplete="off" spellcheck="false" data-field="value" aria-invalid=${field.invalid} aria-describedby=${field.described} /></label>
|
|
30797
|
+
</div>` : A}
|
|
30798
|
+
${locked ? this.#unlock(vault) : A}
|
|
30799
|
+
${problem ? b`<p class="problem" role="alert" id="error-request" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${problem}</span></p>` : A}
|
|
30800
|
+
<p class="timer" data-timer>Expires ${until(request2.expiresAt, this.now)}</p>
|
|
30801
|
+
${rest > 0 ? b`<p class="more" data-more>${rest} more waiting</p>` : A}
|
|
30802
|
+
<swc-button slot="button" variant="secondary" fill-style="outline" data-action="later" ?disabled=${this.busy} @click=${() => this.later(request2.id)}>Later</swc-button>
|
|
30803
|
+
${vault.cancel ? b`<swc-button slot="button" variant="secondary" fill-style="outline" data-action="cancel-request" ?disabled=${this.busy} @click=${() => this.cancelRequest(request2)}>Cancel request</swc-button>` : A}
|
|
30804
|
+
${vault.put ? b`<swc-button slot="button" variant="accent" data-action="save" ?pending=${this.busy} ?disabled=${locked} @click=${() => this.save(request2)}>Save</swc-button>` : A}
|
|
30805
|
+
</sp-alert-dialog>
|
|
30806
|
+
</dialog>`
|
|
30807
|
+
);
|
|
30808
|
+
}
|
|
30809
|
+
};
|
|
30810
|
+
|
|
29827
30811
|
// node_modules/@pierre/diffs/dist/constants.js
|
|
29828
30812
|
var DIFFS_TAG_NAME = "diffs-container";
|
|
29829
30813
|
var DIFFS_DEVELOPMENT_BUILD = (() => {
|
|
@@ -40468,7 +41452,7 @@ var captureDelim = r35`${namedCaptureDelim}|(?<unnamed>\()(?!\?)`;
|
|
|
40468
41452
|
var token = new RegExp(r35`${namedCaptureDelim}|${recursiveToken}|\(\?|\\?.`, "gsu");
|
|
40469
41453
|
var overlappingRecursionMsg = "Cannot use multiple overlapping recursions";
|
|
40470
41454
|
function recursion(pattern2, data) {
|
|
40471
|
-
const { hiddenCaptures, mode } = {
|
|
41455
|
+
const { hiddenCaptures, mode: mode2 } = {
|
|
40472
41456
|
hiddenCaptures: [],
|
|
40473
41457
|
mode: "plugin",
|
|
40474
41458
|
...data
|
|
@@ -40481,7 +41465,7 @@ function recursion(pattern2, data) {
|
|
|
40481
41465
|
hiddenCaptures
|
|
40482
41466
|
};
|
|
40483
41467
|
}
|
|
40484
|
-
if (
|
|
41468
|
+
if (mode2 === "plugin" && hasUnescaped(pattern2, r35`\(\?\(DEFINE\)`, Context.DEFAULT)) {
|
|
40485
41469
|
throw new Error("DEFINE groups cannot be used with recursion");
|
|
40486
41470
|
}
|
|
40487
41471
|
const addedHiddenCaptures = [];
|
|
@@ -40507,7 +41491,7 @@ function recursion(pattern2, data) {
|
|
|
40507
41491
|
throw new Error(
|
|
40508
41492
|
// When used in `external` mode by transpilers other than Regex+, backrefs might have
|
|
40509
41493
|
// gone through conversion from named to numbered, so avoid a misleading error
|
|
40510
|
-
`${
|
|
41494
|
+
`${mode2 === "external" ? "Backrefs" : "Numbered backrefs"} cannot be used with global recursion`
|
|
40511
41495
|
);
|
|
40512
41496
|
}
|
|
40513
41497
|
const left = pattern2.slice(0, match.index);
|
|
@@ -40547,7 +41531,7 @@ function recursion(pattern2, data) {
|
|
|
40547
41531
|
}
|
|
40548
41532
|
}
|
|
40549
41533
|
if (!isWithinReffedGroup) {
|
|
40550
|
-
throw new Error(r35`Recursive \g cannot be used outside the referenced group "${
|
|
41534
|
+
throw new Error(r35`Recursive \g cannot be used outside the referenced group "${mode2 === "external" ? gRNameOrNum : r35`\g<${gRNameOrNum}&R=${gRDepth}>`}"`);
|
|
40551
41535
|
}
|
|
40552
41536
|
const startPos = groupContentsStartPos.get(gRNameOrNum);
|
|
40553
41537
|
const groupContents = getGroupContents(pattern2, startPos);
|
|
@@ -40555,7 +41539,7 @@ function recursion(pattern2, data) {
|
|
|
40555
41539
|
throw new Error(
|
|
40556
41540
|
// When used in `external` mode by transpilers other than Regex+, backrefs might have
|
|
40557
41541
|
// gone through conversion from named to numbered, so avoid a misleading error
|
|
40558
|
-
`${
|
|
41542
|
+
`${mode2 === "external" ? "Backrefs" : "Numbered backrefs"} cannot be used with recursion of capturing groups`
|
|
40559
41543
|
);
|
|
40560
41544
|
}
|
|
40561
41545
|
const groupContentsLeft = pattern2.slice(startPos, match.index);
|
|
@@ -40837,17 +41821,17 @@ function getIgnoreCaseMatchChars(char) {
|
|
|
40837
41821
|
return [char];
|
|
40838
41822
|
}
|
|
40839
41823
|
const set = /* @__PURE__ */ new Set();
|
|
40840
|
-
const
|
|
40841
|
-
const upper =
|
|
40842
|
-
const title = LowerToTitleCaseMap.get(
|
|
40843
|
-
const altLower = LowerToAlternativeLowerCaseMap.get(
|
|
40844
|
-
const altUpper = LowerToAlternativeUpperCaseMap.get(
|
|
41824
|
+
const lower2 = char.toLowerCase();
|
|
41825
|
+
const upper = lower2.toUpperCase();
|
|
41826
|
+
const title = LowerToTitleCaseMap.get(lower2);
|
|
41827
|
+
const altLower = LowerToAlternativeLowerCaseMap.get(lower2);
|
|
41828
|
+
const altUpper = LowerToAlternativeUpperCaseMap.get(lower2);
|
|
40845
41829
|
if ([...upper].length === 1) {
|
|
40846
41830
|
set.add(upper);
|
|
40847
41831
|
}
|
|
40848
41832
|
altUpper && set.add(altUpper);
|
|
40849
41833
|
title && set.add(title);
|
|
40850
|
-
set.add(
|
|
41834
|
+
set.add(lower2);
|
|
40851
41835
|
altLower && set.add(altLower);
|
|
40852
41836
|
return [...set];
|
|
40853
41837
|
}
|
|
@@ -43331,8 +44315,8 @@ var InteractionManager = class {
|
|
|
43331
44315
|
renderedEditorActiveLineState;
|
|
43332
44316
|
selectionAnchor;
|
|
43333
44317
|
pointerSession = { mode: "idle" };
|
|
43334
|
-
constructor(
|
|
43335
|
-
this.mode =
|
|
44318
|
+
constructor(mode2, options) {
|
|
44319
|
+
this.mode = mode2;
|
|
43336
44320
|
this.options = options;
|
|
43337
44321
|
}
|
|
43338
44322
|
setOptions(options) {
|
|
@@ -44845,23 +45829,23 @@ function getIconForType(type) {
|
|
|
44845
45829
|
}
|
|
44846
45830
|
|
|
44847
45831
|
// node_modules/@pierre/diffs/dist/utils/createFileHeaderElement.js
|
|
44848
|
-
function createFileHeaderElement({ fileOrDiff, mode, stickyHeader }) {
|
|
45832
|
+
function createFileHeaderElement({ fileOrDiff, mode: mode2, stickyHeader }) {
|
|
44849
45833
|
const fileDiff = "type" in fileOrDiff ? fileOrDiff : void 0;
|
|
44850
45834
|
const properties = {
|
|
44851
|
-
"data-diffs-header":
|
|
45835
|
+
"data-diffs-header": mode2,
|
|
44852
45836
|
"data-change-type": fileDiff?.type,
|
|
44853
45837
|
"data-sticky": stickyHeader ? "" : void 0
|
|
44854
45838
|
};
|
|
44855
45839
|
return createHastElement({
|
|
44856
45840
|
tagName: "div",
|
|
44857
|
-
children: [
|
|
45841
|
+
children: [mode2 === "custom" ? createHastElement({
|
|
44858
45842
|
tagName: "slot",
|
|
44859
45843
|
properties: { name: CUSTOM_HEADER_SLOT_ID }
|
|
44860
45844
|
}) : createHeaderElement({
|
|
44861
45845
|
name: fileOrDiff.name,
|
|
44862
45846
|
prevName: "prevName" in fileOrDiff ? fileOrDiff.prevName : void 0,
|
|
44863
45847
|
iconType: fileDiff?.type ?? "file"
|
|
44864
|
-
}), ...
|
|
45848
|
+
}), ...mode2 === "custom" ? [] : [createMetadataElement(fileDiff)]],
|
|
44865
45849
|
properties
|
|
44866
45850
|
});
|
|
44867
45851
|
}
|
|
@@ -47374,8 +48358,8 @@ var File = class {
|
|
|
47374
48358
|
* mode always restores the external values. An accepted file cannot reuse
|
|
47375
48359
|
* the replaced file's `cacheKey`.
|
|
47376
48360
|
*/
|
|
47377
|
-
__completeEditSession(editor,
|
|
47378
|
-
this.settleEditSession(
|
|
48361
|
+
__completeEditSession(editor, mode2) {
|
|
48362
|
+
this.settleEditSession(mode2 === "install", editor);
|
|
47379
48363
|
}
|
|
47380
48364
|
settleEditSession(installResult, editor) {
|
|
47381
48365
|
const { editSession, file: externalFile, lineAnnotations: externalAnnotations } = this;
|
|
@@ -48530,10 +49514,10 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
|
|
|
48530
49514
|
else currentFile.type = "rename-changed";
|
|
48531
49515
|
}
|
|
48532
49516
|
if (line.startsWith("index ")) {
|
|
48533
|
-
const [, prevObjectId, newObjectId,
|
|
49517
|
+
const [, prevObjectId, newObjectId, mode2] = line.trim().match(INDEX_LINE_METADATA) ?? [];
|
|
48534
49518
|
if (prevObjectId != null) currentFile.prevObjectId = detachString(prevObjectId);
|
|
48535
49519
|
if (newObjectId != null) currentFile.newObjectId = detachString(newObjectId);
|
|
48536
|
-
if (
|
|
49520
|
+
if (mode2 != null) currentFile.mode = detachString(mode2);
|
|
48537
49521
|
}
|
|
48538
49522
|
if (line.startsWith("rename from ") || line.startsWith("copy from ")) currentFile.prevName = detachString(decodeDiffFileName(line.slice(line.startsWith("rename") ? 12 : 10)));
|
|
48539
49523
|
if (line.startsWith("rename to ") || line.startsWith("copy to ")) currentFile.name = detachString(decodeDiffFileName(line.slice(line.startsWith("rename") ? 10 : 8)));
|
|
@@ -49232,14 +50216,14 @@ var WordDiff = class extends Diff {
|
|
|
49232
50216
|
}
|
|
49233
50217
|
}).join("");
|
|
49234
50218
|
}
|
|
49235
|
-
postProcess(
|
|
49236
|
-
if (!
|
|
49237
|
-
return
|
|
50219
|
+
postProcess(changes2, options) {
|
|
50220
|
+
if (!changes2 || options.oneChangePerToken) {
|
|
50221
|
+
return changes2;
|
|
49238
50222
|
}
|
|
49239
50223
|
let lastKeep = null;
|
|
49240
50224
|
let insertion = null;
|
|
49241
50225
|
let deletion = null;
|
|
49242
|
-
|
|
50226
|
+
changes2.forEach((change) => {
|
|
49243
50227
|
if (change.added) {
|
|
49244
50228
|
insertion = change;
|
|
49245
50229
|
} else if (change.removed) {
|
|
@@ -49256,7 +50240,7 @@ var WordDiff = class extends Diff {
|
|
|
49256
50240
|
if (insertion || deletion) {
|
|
49257
50241
|
dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter);
|
|
49258
50242
|
}
|
|
49259
|
-
return
|
|
50243
|
+
return changes2;
|
|
49260
50244
|
}
|
|
49261
50245
|
};
|
|
49262
50246
|
var wordDiff = new WordDiff();
|
|
@@ -53674,8 +54658,8 @@ var FileDiff = class {
|
|
|
53674
54658
|
* values. `discard` mode always restores the external values. An accepted
|
|
53675
54659
|
* diff cannot reuse the replaced diff's `cacheKey`.
|
|
53676
54660
|
*/
|
|
53677
|
-
__completeEditSession(editor,
|
|
53678
|
-
this.settleEditSession(
|
|
54661
|
+
__completeEditSession(editor, mode2) {
|
|
54662
|
+
this.settleEditSession(mode2 === "install", editor);
|
|
53679
54663
|
}
|
|
53680
54664
|
settleEditSession(installResult, editor) {
|
|
53681
54665
|
const { editSession, fileDiff: externalDiff, lineAnnotations: externalAnnotations } = this;
|
|
@@ -74563,7 +75547,7 @@ function createCleanupMetricSnapshot(state3) {
|
|
|
74563
75547
|
totalNodeSlotCount: Math.max(0, state3.snapshot.nodes.length - 1)
|
|
74564
75548
|
};
|
|
74565
75549
|
}
|
|
74566
|
-
function createCleanupResult(
|
|
75550
|
+
function createCleanupResult(mode2, idsPreserved, before, after) {
|
|
74567
75551
|
return {
|
|
74568
75552
|
activeNodeCountAfter: after.activeNodeCount,
|
|
74569
75553
|
activeNodeCountBefore: before.activeNodeCount,
|
|
@@ -74572,7 +75556,7 @@ function createCleanupResult(mode, idsPreserved, before, after) {
|
|
|
74572
75556
|
idsPreserved,
|
|
74573
75557
|
loadInfoEntryCountAfter: after.loadInfoEntryCount,
|
|
74574
75558
|
loadInfoEntryCountBefore: before.loadInfoEntryCount,
|
|
74575
|
-
mode,
|
|
75559
|
+
mode: mode2,
|
|
74576
75560
|
reclaimedCachedPathEntryCount: before.cachedPathEntryCount - after.cachedPathEntryCount,
|
|
74577
75561
|
reclaimedLoadInfoEntryCount: before.loadInfoEntryCount - after.loadInfoEntryCount,
|
|
74578
75562
|
reclaimedNodeSlotCount: before.totalNodeSlotCount - after.totalNodeSlotCount,
|
|
@@ -74721,12 +75705,12 @@ function hasActiveCleanupBlockingLoads(state3) {
|
|
|
74721
75705
|
for (const loadInfo of state3.directoryLoadInfoById.values()) if (loadInfo.state === "loading" && loadInfo.activeAttemptId != null) return true;
|
|
74722
75706
|
return false;
|
|
74723
75707
|
}
|
|
74724
|
-
function cleanupPathStoreState(state3,
|
|
75708
|
+
function cleanupPathStoreState(state3, mode2) {
|
|
74725
75709
|
const before = createCleanupMetricSnapshot(state3);
|
|
74726
|
-
if (
|
|
75710
|
+
if (mode2 === "stable") withBenchmarkPhase(state3.instrumentation, "store.cleanup.stable", () => runStableCleanup(state3));
|
|
74727
75711
|
else withBenchmarkPhase(state3.instrumentation, "store.cleanup.aggressive", () => runAggressiveCleanup(state3));
|
|
74728
75712
|
const after = createCleanupMetricSnapshot(state3);
|
|
74729
|
-
return createCleanupResult(
|
|
75713
|
+
return createCleanupResult(mode2, mode2 === "stable", before, after);
|
|
74730
75714
|
}
|
|
74731
75715
|
|
|
74732
75716
|
// node_modules/@pierre/trees/dist/path-store/src/projection.js
|
|
@@ -77962,35 +78946,35 @@ function OverflowMarker({ children, marker, variant = "default" }) {
|
|
|
77962
78946
|
}
|
|
77963
78947
|
function OverflowContent(options) {
|
|
77964
78948
|
"use no memo";
|
|
77965
|
-
const { mode, children } = options;
|
|
78949
|
+
const { mode: mode2, children } = options;
|
|
77966
78950
|
return /* @__PURE__ */ u25("div", { children: [/* @__PURE__ */ u25("div", {
|
|
77967
78951
|
"data-truncate-content": "visible",
|
|
77968
|
-
children:
|
|
78952
|
+
children: mode2 === "fruncate" ? /* @__PURE__ */ u25("span", { children }) : children
|
|
77969
78953
|
}), /* @__PURE__ */ u25("div", {
|
|
77970
78954
|
"data-truncate-content": "overflow",
|
|
77971
78955
|
"aria-hidden": true,
|
|
77972
|
-
children:
|
|
78956
|
+
children: mode2 === "fruncate" ? /* @__PURE__ */ u25("span", { children }) : children
|
|
77973
78957
|
})] });
|
|
77974
78958
|
}
|
|
77975
|
-
function OverflowText({ children, mode = "truncate", marker = "\u2026", variant = "default", ...props }) {
|
|
78959
|
+
function OverflowText({ children, mode: mode2 = "truncate", marker = "\u2026", variant = "default", ...props }) {
|
|
77976
78960
|
"use no memo";
|
|
77977
78961
|
const contentNode = /* @__PURE__ */ u25(OverflowContent, {
|
|
77978
|
-
mode,
|
|
78962
|
+
mode: mode2,
|
|
77979
78963
|
children
|
|
77980
78964
|
}, "content");
|
|
77981
78965
|
const markerNode = /* @__PURE__ */ u25(OverflowMarker, {
|
|
77982
78966
|
marker,
|
|
77983
|
-
mode,
|
|
78967
|
+
mode: mode2,
|
|
77984
78968
|
variant
|
|
77985
78969
|
}, "marker");
|
|
77986
78970
|
const fillNode = /* @__PURE__ */ u25("div", { "data-truncate-fill": true }, "fill");
|
|
77987
78971
|
return /* @__PURE__ */ u25("div", {
|
|
77988
|
-
"data-truncate-container":
|
|
78972
|
+
"data-truncate-container": mode2,
|
|
77989
78973
|
"data-truncate-variant": variant,
|
|
77990
78974
|
...props,
|
|
77991
78975
|
children: /* @__PURE__ */ u25("div", {
|
|
77992
78976
|
"data-truncate-grid": true,
|
|
77993
|
-
children:
|
|
78977
|
+
children: mode2 === "truncate" ? [contentNode, markerNode] : [
|
|
77994
78978
|
markerNode,
|
|
77995
78979
|
contentNode,
|
|
77996
78980
|
fillNode
|
|
@@ -78466,8 +79450,8 @@ function RenameInput({ ariaLabel, isFlattened = false, ref, value, onBlur, onInp
|
|
|
78466
79450
|
|
|
78467
79451
|
// node_modules/@pierre/trees/dist/render/rowAttributes.js
|
|
78468
79452
|
function computeFileTreeRowElementAttributes(input) {
|
|
78469
|
-
const { row, mode, targetPath, ariaLabel, domId, isParked, itemHeight, features, state: state3, extraStyle } = input;
|
|
78470
|
-
const isSticky =
|
|
79453
|
+
const { row, mode: mode2, targetPath, ariaLabel, domId, isParked, itemHeight, features, state: state3, extraStyle } = input;
|
|
79454
|
+
const isSticky = mode2 === "sticky";
|
|
78471
79455
|
const parentPath = row.ancestorPaths.at(-1) ?? "";
|
|
78472
79456
|
const stateAttributes = {};
|
|
78473
79457
|
if (state3.isFocusRinged) stateAttributes["data-item-focused"] = true;
|
|
@@ -78509,7 +79493,7 @@ function computeFileTreeRowElementAttributes(input) {
|
|
|
78509
79493
|
|
|
78510
79494
|
// node_modules/@pierre/trees/dist/render/rowClickPlan.js
|
|
78511
79495
|
function computeFileTreeRowClickPlan(input) {
|
|
78512
|
-
const { event: event2, mode, isSearchOpen, isDirectory } = input;
|
|
79496
|
+
const { event: event2, mode: mode2, isSearchOpen, isDirectory } = input;
|
|
78513
79497
|
const additive = event2.ctrlKey || event2.metaKey;
|
|
78514
79498
|
const hasModifier = event2.shiftKey || additive;
|
|
78515
79499
|
const selection = event2.shiftKey ? {
|
|
@@ -78518,7 +79502,7 @@ function computeFileTreeRowClickPlan(input) {
|
|
|
78518
79502
|
} : additive ? { kind: "toggle" } : { kind: "single" };
|
|
78519
79503
|
return {
|
|
78520
79504
|
closeSearch: isSearchOpen,
|
|
78521
|
-
revealCanonical:
|
|
79505
|
+
revealCanonical: mode2 === "sticky",
|
|
78522
79506
|
selection,
|
|
78523
79507
|
toggleDirectory: !hasModifier && isDirectory
|
|
78524
79508
|
};
|
|
@@ -79060,8 +80044,8 @@ function renderFileTreeRowContent(row, resolveIcon, { actionLaneEnabled = false,
|
|
|
79060
80044
|
function renderStyledRow(frame, row, key2, options = {}) {
|
|
79061
80045
|
const { controller, renameView, visualFocusPath, contextHoverPath, draggedPathSet, dragTarget, dragAndDropEnabled, shouldSuppressContextMenu, handleRowDragStart, handleRowDragEnd, handleRowTouchStart, instanceId: instanceId5, itemHeight, gitStatusByPath, ignoredGitDirectories, ignoredInheritanceCache, directoriesWithGitChanges, gitLaneActive, contextMenuEnabled, contextMenuTriggerMode, contextMenuButtonTriggerEnabled, contextMenuButtonVisibility, contextMenuRightClickEnabled, registerRenameInput, registerButton, resolveIcon, renderDecorationForRow, openContextMenuForRow, onRowClick, onKeyDown } = frame;
|
|
79062
80046
|
const targetPath = getFileTreeRowPath(row);
|
|
79063
|
-
const { isParked = false, mode = "flow", style } = options;
|
|
79064
|
-
const isSticky =
|
|
80047
|
+
const { isParked = false, mode: mode2 = "flow", style } = options;
|
|
80048
|
+
const isSticky = mode2 === "sticky";
|
|
79065
80049
|
const effectiveGitStatus = gitStatusByPath?.get(targetPath) ?? null ?? getInheritedIgnoredGitStatus(row.ancestorPaths, ignoredGitDirectories, ignoredInheritanceCache);
|
|
79066
80050
|
const containsGitChange = row.kind === "directory" && (directoriesWithGitChanges?.has(targetPath) ?? false);
|
|
79067
80051
|
const customDecoration = renderDecorationForRow(row, targetPath);
|
|
@@ -79107,7 +80091,7 @@ function renderStyledRow(frame, row, key2, options = {}) {
|
|
|
79107
80091
|
},
|
|
79108
80092
|
isParked,
|
|
79109
80093
|
itemHeight,
|
|
79110
|
-
mode,
|
|
80094
|
+
mode: mode2,
|
|
79111
80095
|
row,
|
|
79112
80096
|
state: {
|
|
79113
80097
|
containsGitChange,
|
|
@@ -79165,7 +80149,7 @@ function renderStyledRow(frame, row, key2, options = {}) {
|
|
|
79165
80149
|
handleRowTouchStart(event2, row, targetPath);
|
|
79166
80150
|
} : void 0,
|
|
79167
80151
|
onClick: (event2) => {
|
|
79168
|
-
onRowClick(event2, row, targetPath,
|
|
80152
|
+
onRowClick(event2, row, targetPath, mode2);
|
|
79169
80153
|
},
|
|
79170
80154
|
children: rowContent
|
|
79171
80155
|
});
|
|
@@ -80329,7 +81313,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
|
80329
81313
|
top: `${pointerAnchorRect.top}px`
|
|
80330
81314
|
} : rowAnchorTop != null ? { top: `${rowAnchorTop}px` } : void 0;
|
|
80331
81315
|
const contextMenuTriggerStyle = isPointerContextMenuOpen ? { opacity: "0" } : void 0;
|
|
80332
|
-
const handleRowClick = b12((event2, row, targetPath,
|
|
81316
|
+
const handleRowClick = b12((event2, row, targetPath, mode2) => {
|
|
80333
81317
|
const plan = computeFileTreeRowClickPlan({
|
|
80334
81318
|
event: {
|
|
80335
81319
|
ctrlKey: event2.ctrlKey,
|
|
@@ -80338,7 +81322,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
|
80338
81322
|
},
|
|
80339
81323
|
isDirectory: row.kind === "directory",
|
|
80340
81324
|
isSearchOpen,
|
|
80341
|
-
mode
|
|
81325
|
+
mode: mode2
|
|
80342
81326
|
});
|
|
80343
81327
|
const shouldToggleDirectory = plan.toggleDirectory && row.kind === "directory";
|
|
80344
81328
|
const mountedDirectoryPath = shouldToggleDirectory ? controller.resolveMountedDirectoryPathFromInput(targetPath) : null;
|
|
@@ -80357,7 +81341,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
|
80357
81341
|
}
|
|
80358
81342
|
const clickedElement = event2.currentTarget instanceof HTMLElement ? event2.currentTarget : null;
|
|
80359
81343
|
const clickedRowIsVisible = row.index >= layoutSnapshot.visible.startIndex && row.index <= layoutSnapshot.visible.endIndex;
|
|
80360
|
-
const shouldExposeFocusedTrigger =
|
|
81344
|
+
const shouldExposeFocusedTrigger = mode2 === "flow" && clickedRowIsVisible && clickedElement != null && clickedElement.dataset.itemParked !== "true";
|
|
80361
81345
|
controller.focusMountedPathFromInput(actionTargetPath);
|
|
80362
81346
|
if (shouldExposeFocusedTrigger) {
|
|
80363
81347
|
domFocusOwnerRef.current = true;
|
|
@@ -81268,6 +82252,7 @@ var elements = {
|
|
|
81268
82252
|
"slicc-approvals": SliccApprovals,
|
|
81269
82253
|
"slicc-secrets": SliccSecrets,
|
|
81270
82254
|
"slicc-vault-button": SliccVaultButton,
|
|
82255
|
+
"slicc-value-request": SliccValueRequest,
|
|
81271
82256
|
"slicc-confirm": SliccConfirm,
|
|
81272
82257
|
"slicc-prompt": SliccPrompt,
|
|
81273
82258
|
"slicc-app": SliccApp
|
|
@@ -81306,10 +82291,12 @@ export {
|
|
|
81306
82291
|
SliccPrompt,
|
|
81307
82292
|
SliccSecrets,
|
|
81308
82293
|
SliccUpdates,
|
|
82294
|
+
SliccValueRequest,
|
|
81309
82295
|
SliccVaultButton,
|
|
81310
82296
|
confirm,
|
|
81311
82297
|
define2 as define,
|
|
81312
82298
|
grammarBase,
|
|
82299
|
+
isVaultFailure,
|
|
81313
82300
|
panelCommand,
|
|
81314
82301
|
prompt,
|
|
81315
82302
|
resolveColor,
|