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