@ai-ecoverse/slicc-spectrum 1.62.2 → 1.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -7
- package/dist/chunk-XQHRTHDQ.js +26 -0
- package/dist/chunk-XQHRTHDQ.js.map +7 -0
- package/dist/slicc-dummy.js +343 -63
- package/dist/slicc-dummy.js.map +3 -3
- package/dist/slicc-ui.js +1663 -597
- package/dist/slicc-ui.js.map +4 -4
- package/dist/types/app/composer.d.ts +16 -2
- package/dist/types/app/messages.d.ts +1 -0
- package/dist/types/app/monitor.d.ts +9 -0
- 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 +119 -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)
|
|
@@ -13845,13 +13850,16 @@ function table(rows) {
|
|
|
13845
13850
|
var done = (result, note = "") => result.code === 0 ? { stdout: `${result.message}${note}
|
|
13846
13851
|
`, stderr: "", code: 0 } : { stdout: "", stderr: `panel: ${result.message}
|
|
13847
13852
|
`, code: result.code };
|
|
13853
|
+
function closedWhen(ago2) {
|
|
13854
|
+
return ago2 < 5e3 ? "just now" : `${Math.round(ago2 / 1e3)} s ago`;
|
|
13855
|
+
}
|
|
13848
13856
|
function act(scope, parsed) {
|
|
13849
13857
|
const { panels, reachable: reachable2, cone } = scope;
|
|
13850
13858
|
if (parsed.verb === "reset") {
|
|
13851
13859
|
const recent = scope.agent ? panels.recentClose() : null;
|
|
13852
13860
|
if (recent)
|
|
13853
13861
|
return refusedOutput(
|
|
13854
|
-
`the user closed ${recent.id} ${
|
|
13862
|
+
`the user closed ${recent.id} ${closedWhen(recent.ago)}; ask before resetting the layout`
|
|
13855
13863
|
);
|
|
13856
13864
|
return done(panels.reset());
|
|
13857
13865
|
}
|
|
@@ -13867,9 +13875,7 @@ function act(scope, parsed) {
|
|
|
13867
13875
|
if (parsed.verb === "close") return done(panels.close(id));
|
|
13868
13876
|
const ago2 = scope.agent && !panels.find(id)?.open ? panels.closedAgo(id) : null;
|
|
13869
13877
|
if (ago2 !== null)
|
|
13870
|
-
return refusedOutput(
|
|
13871
|
-
`the user closed ${id} ${Math.round(ago2 / 1e3)} s ago; ask before opening it again`
|
|
13872
|
-
);
|
|
13878
|
+
return refusedOutput(`the user closed ${id} ${closedWhen(ago2)}; ask before opening it again`);
|
|
13873
13879
|
if (parsed.verb === "move") return done(panels.move(id, place3));
|
|
13874
13880
|
const options = { place: place3, section: parsed.section };
|
|
13875
13881
|
if (parsed.verb === "open") return done(panels.open(id, options));
|
|
@@ -20497,6 +20503,16 @@ function body(call, color) {
|
|
|
20497
20503
|
}
|
|
20498
20504
|
return b`<pre class="input">${call.input}</pre>`;
|
|
20499
20505
|
}
|
|
20506
|
+
var severityWords = {
|
|
20507
|
+
error: "Error: ",
|
|
20508
|
+
warn: "Warning: ",
|
|
20509
|
+
info: "Note: "
|
|
20510
|
+
};
|
|
20511
|
+
function notes(list5) {
|
|
20512
|
+
return b`<ul class="notes">${list5.map(
|
|
20513
|
+
(note) => b`<li data-note data-severity=${note.severity}>${note.severity === "info" ? b`<swc-icon-info-circle size="s" aria-hidden="true"></swc-icon-info-circle>` : b`<swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle>`}<span><span class="sr">${severityWords[note.severity]}</span>${note.text}</span></li>`
|
|
20514
|
+
)}</ul>`;
|
|
20515
|
+
}
|
|
20500
20516
|
function tool(call, color = "light") {
|
|
20501
20517
|
const kind = toolKind(call.name);
|
|
20502
20518
|
return b`<details class="tool" data-status=${call.status} data-tool=${call.name} data-kind=${kind.id}>
|
|
@@ -20514,6 +20530,7 @@ function tool(call, color = "light") {
|
|
|
20514
20530
|
<div class="call">
|
|
20515
20531
|
${body(call, color)}
|
|
20516
20532
|
${call.output ? b`<pre class="output">${call.output}</pre>` : A}
|
|
20533
|
+
${call.notes?.length ? notes(call.notes) : A}
|
|
20517
20534
|
${call.image ? b`<img class="shot" src=${call.image} alt=${call.title} />` : A}
|
|
20518
20535
|
</div>
|
|
20519
20536
|
</details>`;
|
|
@@ -21168,6 +21185,33 @@ var messageCss = i`
|
|
|
21168
21185
|
max-block-size: calc(var(--swc-spacing-1000) * 2.5);
|
|
21169
21186
|
overflow: auto;
|
|
21170
21187
|
}
|
|
21188
|
+
.call > pre {
|
|
21189
|
+
white-space: pre-wrap;
|
|
21190
|
+
overflow-wrap: anywhere;
|
|
21191
|
+
}
|
|
21192
|
+
.notes {
|
|
21193
|
+
display: flex;
|
|
21194
|
+
flex-direction: column;
|
|
21195
|
+
gap: var(--swc-spacing-75);
|
|
21196
|
+
margin: var(--swc-spacing-100) 0 0;
|
|
21197
|
+
padding: 0;
|
|
21198
|
+
list-style: none;
|
|
21199
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
21200
|
+
}
|
|
21201
|
+
.notes li {
|
|
21202
|
+
display: flex;
|
|
21203
|
+
align-items: flex-start;
|
|
21204
|
+
gap: var(--swc-spacing-75);
|
|
21205
|
+
overflow-wrap: anywhere;
|
|
21206
|
+
}
|
|
21207
|
+
.notes swc-icon-alert-triangle,
|
|
21208
|
+
.notes swc-icon-info-circle {
|
|
21209
|
+
flex: none;
|
|
21210
|
+
margin-block-start: var(--swc-spacing-50);
|
|
21211
|
+
}
|
|
21212
|
+
.notes [data-severity='error'] {
|
|
21213
|
+
color: var(--swc-negative-content-color-default);
|
|
21214
|
+
}
|
|
21171
21215
|
.call > pre.input:has(+ pre.output) {
|
|
21172
21216
|
margin-block-end: calc(-1 * var(--swc-spacing-100));
|
|
21173
21217
|
border-block-end: 0;
|
|
@@ -21455,7 +21499,8 @@ var messageCss = i`
|
|
|
21455
21499
|
.lick[data-severity='warn'] {
|
|
21456
21500
|
--severity: var(--swc-notice-visual-color);
|
|
21457
21501
|
}
|
|
21458
|
-
.lick .sr
|
|
21502
|
+
.lick .sr,
|
|
21503
|
+
.notes .sr {
|
|
21459
21504
|
position: absolute;
|
|
21460
21505
|
inline-size: 1px;
|
|
21461
21506
|
block-size: 1px;
|
|
@@ -21996,11 +22041,11 @@ var SliccUpdates = class extends ModelElement {
|
|
|
21996
22041
|
</p>`;
|
|
21997
22042
|
}
|
|
21998
22043
|
const version2 = item2.version === null ? item2.offered : item2.offered && item2.offered !== item2.version ? `${item2.version} \u2192 ${item2.offered}` : item2.version;
|
|
21999
|
-
const
|
|
22044
|
+
const download2 = item2.size !== void 0 && (item2.version === null || item2.offered !== item2.version);
|
|
22000
22045
|
const requires = requiresText(item2, all2);
|
|
22001
22046
|
return b`<p class="meta">
|
|
22002
22047
|
${version2 ? b`<span class="version">${version2}</span>` : A}
|
|
22003
|
-
${
|
|
22048
|
+
${download2 ? b`<span>${size3(item2.size)}</span>` : A}
|
|
22004
22049
|
${requires ? b`<span data-requires>${requires}</span>` : A}
|
|
22005
22050
|
</p>`;
|
|
22006
22051
|
}
|
|
@@ -22764,13 +22809,13 @@ var SliccApp = class extends ThemedElement {
|
|
|
22764
22809
|
this.#detach(id, null, false);
|
|
22765
22810
|
}
|
|
22766
22811
|
#railButton(item2, side) {
|
|
22767
|
-
const
|
|
22812
|
+
const changes2 = item2.id === "changes" ? this.#changes() : 0;
|
|
22768
22813
|
const driven = item2.id === "browser" && !!this.model?.browser.list().some((tab) => tab.controlled);
|
|
22769
22814
|
const visible2 = shown(this.dock, item2.id);
|
|
22770
|
-
const label = `${visible2 ? `${item2.title}, shown` : `Open ${item2.title}`}${
|
|
22815
|
+
const label = `${visible2 ? `${item2.title}, shown` : `Open ${item2.title}`}${changes2 ? `, ${changeCount(changes2)}` : driven ? ", a tab is in use" : ""}`;
|
|
22771
22816
|
const button = u16`<swc-action-button id=${`rail-${item2.id}`} class=${visible2 ? "selected" : ""} quiet size="m" accessible-label=${label} data-surface=${item2.id} data-cone=${o2(item2.cone)} ?data-visible=${visible2} @click=${() => this.show(item2.id)}>${railIcon(item2.icon)}</swc-action-button>`;
|
|
22772
22817
|
const tooltip = b`<swc-tooltip for=${`rail-${item2.id}`} placement=${{ left: "end", right: "start", bottom: "top" }[side]}>${item2.title}</swc-tooltip>`;
|
|
22773
|
-
return
|
|
22818
|
+
return changes2 ? b`<span class="badged">${button}<swc-badge size="s" variant="neutral" aria-hidden="true">${changes2}</swc-badge></span>${tooltip}` : driven ? b`<span class="badged">${button}<span class="dot" data-driven aria-hidden="true"></span></span>${tooltip}` : b`${button}${tooltip}`;
|
|
22774
22819
|
}
|
|
22775
22820
|
#changes() {
|
|
22776
22821
|
const port = this.model ? changesOf(this.model) : null;
|
|
@@ -22778,13 +22823,13 @@ var SliccApp = class extends ThemedElement {
|
|
|
22778
22823
|
}
|
|
22779
22824
|
#more(items) {
|
|
22780
22825
|
if (!items.length) return A;
|
|
22781
|
-
const
|
|
22782
|
-
const label =
|
|
22826
|
+
const changes2 = items.some((item2) => item2.id === "changes") ? this.#changes() : 0;
|
|
22827
|
+
const label = changes2 ? `More panels, ${changeCount(changes2)}` : "More panels";
|
|
22783
22828
|
const menu = u16`<sp-action-menu quiet size="m" label=${label} placement="top-end" @change=${(event2) => this.show(event2.target.value)}>
|
|
22784
22829
|
<swc-icon-more slot="icon"></swc-icon-more>
|
|
22785
22830
|
${items.map((item2) => u16`<sp-menu-item value=${item2.id}>${railIcon(item2.icon)}${item2.title}</sp-menu-item>`)}
|
|
22786
22831
|
</sp-action-menu>`;
|
|
22787
|
-
return
|
|
22832
|
+
return changes2 ? b`<span class="badged">${menu}<swc-badge size="s" variant="neutral" aria-hidden="true">${changes2}</swc-badge></span>` : menu;
|
|
22788
22833
|
}
|
|
22789
22834
|
#rail(items, side) {
|
|
22790
22835
|
const primary = side === "bottom" ? items.filter((item2) => phoneRail.includes(item2.id)) : items;
|
|
@@ -23018,6 +23063,7 @@ var SliccApp = class extends ThemedElement {
|
|
|
23018
23063
|
${rails.bottom}
|
|
23019
23064
|
</div>
|
|
23020
23065
|
<slicc-approvals .model=${this.model}></slicc-approvals>
|
|
23066
|
+
<slicc-value-request .model=${this.model}></slicc-value-request>
|
|
23021
23067
|
</sp-theme></div>`;
|
|
23022
23068
|
}
|
|
23023
23069
|
};
|
|
@@ -24773,9 +24819,9 @@ function where(change) {
|
|
|
24773
24819
|
if (at === change.repo) return "";
|
|
24774
24820
|
return at.startsWith(`${change.repo}/`) ? at.slice(change.repo.length + 1) : at;
|
|
24775
24821
|
}
|
|
24776
|
-
function lost(
|
|
24777
|
-
const kind =
|
|
24778
|
-
return `${
|
|
24822
|
+
function lost(changes2) {
|
|
24823
|
+
const kind = changes2.every((change) => change.repo) ? "uncommitted" : "pending";
|
|
24824
|
+
return `${changes2.length === 1 ? "Its" : "Their"} ${kind} changes are discarded and can\u2019t be undone.`;
|
|
24779
24825
|
}
|
|
24780
24826
|
var confirmRevert = (change) => confirm({ title: `Revert ${basename(change.path)}?`, body: lost([change]), action: "Revert" });
|
|
24781
24827
|
async function revertPaths(port, paths) {
|
|
@@ -24790,9 +24836,9 @@ async function revertPaths(port, paths) {
|
|
|
24790
24836
|
if (errors.length > 1) return `Couldn\u2019t revert ${errors.length} files. ${errors[0]}`;
|
|
24791
24837
|
return errors[0] ?? "";
|
|
24792
24838
|
}
|
|
24793
|
-
function groups(
|
|
24839
|
+
function groups(changes2) {
|
|
24794
24840
|
const byRepo = /* @__PURE__ */ new Map();
|
|
24795
|
-
for (const change of
|
|
24841
|
+
for (const change of changes2) {
|
|
24796
24842
|
const key2 = change.repo ?? "";
|
|
24797
24843
|
byRepo.set(key2, [...byRepo.get(key2) ?? [], change]);
|
|
24798
24844
|
}
|
|
@@ -24963,18 +25009,18 @@ var SliccChanges = class extends ModelElement {
|
|
|
24963
25009
|
}
|
|
24964
25010
|
async #all(action) {
|
|
24965
25011
|
const port = this.#port();
|
|
24966
|
-
const
|
|
25012
|
+
const changes2 = port.changes();
|
|
24967
25013
|
this.error = "";
|
|
24968
25014
|
if (action === "accept") {
|
|
24969
|
-
for (const change of
|
|
25015
|
+
for (const change of changes2) port.accept(change.path);
|
|
24970
25016
|
return;
|
|
24971
25017
|
}
|
|
24972
|
-
const count =
|
|
25018
|
+
const count = changes2.length;
|
|
24973
25019
|
const title = `Revert ${count} ${count === 1 ? "change" : "changes"}?`;
|
|
24974
|
-
if (await confirm({ title, body: lost(
|
|
25020
|
+
if (await confirm({ title, body: lost(changes2), action: "Revert all" }))
|
|
24975
25021
|
this.error = await revertPaths(
|
|
24976
25022
|
port,
|
|
24977
|
-
|
|
25023
|
+
changes2.map((change) => change.path)
|
|
24978
25024
|
);
|
|
24979
25025
|
}
|
|
24980
25026
|
#keydown(event2) {
|
|
@@ -25029,10 +25075,10 @@ var SliccChanges = class extends ModelElement {
|
|
|
25029
25075
|
</span>
|
|
25030
25076
|
</li>`;
|
|
25031
25077
|
}
|
|
25032
|
-
#list(
|
|
25033
|
-
const grouped = groups(
|
|
25078
|
+
#list(changes2) {
|
|
25079
|
+
const grouped = groups(changes2);
|
|
25034
25080
|
if (grouped.length === 1 && !grouped[0][0])
|
|
25035
|
-
return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${
|
|
25081
|
+
return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${changes2.map((change) => this.#row(change))}</ul>`;
|
|
25036
25082
|
return b`<ul aria-label="Pending changes" @keydown=${this.#keydown}>${grouped.map(
|
|
25037
25083
|
([repo, items]) => b`<li data-repo=${repo}>
|
|
25038
25084
|
<div class="repo" title=${repo}>
|
|
@@ -25072,15 +25118,15 @@ var SliccChanges = class extends ModelElement {
|
|
|
25072
25118
|
const port = this.model ? changesOf(this.model) : null;
|
|
25073
25119
|
const unavailable = port?.unavailable?.() ?? null;
|
|
25074
25120
|
if (unavailable) return this.#unavailable(unavailable);
|
|
25075
|
-
const
|
|
25121
|
+
const changes2 = port?.changes() ?? [];
|
|
25076
25122
|
return b`<div class="bar">
|
|
25077
|
-
<span class="summary">${
|
|
25123
|
+
<span class="summary">${changes2.length} pending ${changes2.length === 1 ? "change" : "changes"}</span>
|
|
25078
25124
|
<span class="spacer"></span>
|
|
25079
|
-
${
|
|
25125
|
+
${changes2.length ? b`<swc-action-button size="s" quiet @click=${() => this.#all("accept")}>Accept all</swc-action-button>
|
|
25080
25126
|
<swc-action-button size="s" quiet @click=${() => this.#all("revert")}>Revert all</swc-action-button>` : A}
|
|
25081
25127
|
</div>
|
|
25082
25128
|
${errorLine(this.error)}
|
|
25083
|
-
${
|
|
25129
|
+
${changes2.length ? this.#list(changes2) : b`<div class="note">No pending changes. Edits by agents show up here for review.</div>`}`;
|
|
25084
25130
|
}
|
|
25085
25131
|
};
|
|
25086
25132
|
var SliccDiffPanel = class extends ThemedElement {
|
|
@@ -26490,6 +26536,286 @@ var o84 = class extends a10 {
|
|
|
26490
26536
|
};
|
|
26491
26537
|
e25("swc-icon-clock", o84);
|
|
26492
26538
|
|
|
26539
|
+
// src/app/vault.ts
|
|
26540
|
+
var exitNames = {
|
|
26541
|
+
page: "This page",
|
|
26542
|
+
proxy: "Local proxy",
|
|
26543
|
+
"vault-direct": "Straight from the vault",
|
|
26544
|
+
"local-proxy": "Local proxy",
|
|
26545
|
+
"cli-v": "Local SLICC, direct",
|
|
26546
|
+
tailscale: "Tailscale",
|
|
26547
|
+
"local-link": "Linked SLICC, through this page"
|
|
26548
|
+
};
|
|
26549
|
+
function devicesOf(model) {
|
|
26550
|
+
return model?.network?.status().links?.devices ?? [];
|
|
26551
|
+
}
|
|
26552
|
+
function deviceName2(id, devices) {
|
|
26553
|
+
return (devices.find((device) => device.id === id)?.name ?? id).replace(/^slicc\b/i, "SLICC");
|
|
26554
|
+
}
|
|
26555
|
+
function exitLabel(exit, devices) {
|
|
26556
|
+
if (exit.startsWith("device:")) return deviceName2(exit.slice("device:".length), devices);
|
|
26557
|
+
return exitNames[exit];
|
|
26558
|
+
}
|
|
26559
|
+
function list4(items) {
|
|
26560
|
+
if (items.length < 2) return items.join("");
|
|
26561
|
+
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
26562
|
+
}
|
|
26563
|
+
function ruleLine(rule) {
|
|
26564
|
+
const methods = rule.methods.length ? rule.methods.join(" or ") : "any method";
|
|
26565
|
+
const paths = rule.paths.length ? rule.paths.join(" or ") : "any path";
|
|
26566
|
+
return `${rule.domain}, in ${rule.header}, ${methods}, ${paths}`;
|
|
26567
|
+
}
|
|
26568
|
+
function shellWord(word) {
|
|
26569
|
+
return /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replace(/'/g, "'\\''")}'`;
|
|
26570
|
+
}
|
|
26571
|
+
function execLine(exec, argv = []) {
|
|
26572
|
+
if (typeof exec === "object") return execLine("argv", exec.argv);
|
|
26573
|
+
if (exec === "any" || exec === true) return "Revealed to any command";
|
|
26574
|
+
if (exec === "shell") return "Revealed in every bash";
|
|
26575
|
+
if (exec === false) return null;
|
|
26576
|
+
if (!argv.length) return "Revealed only to listed commands";
|
|
26577
|
+
return `Revealed only to ${list4(argv.map((words) => words.map(shellWord).join(" ")))}`;
|
|
26578
|
+
}
|
|
26579
|
+
function lower(line) {
|
|
26580
|
+
return `${line[0].toLowerCase()}${line.slice(1)}`;
|
|
26581
|
+
}
|
|
26582
|
+
function mode(exec) {
|
|
26583
|
+
return lower(execLine(exec) ?? "Never revealed to commands");
|
|
26584
|
+
}
|
|
26585
|
+
function changeLine(change, devices) {
|
|
26586
|
+
switch (change.kind) {
|
|
26587
|
+
case "rule":
|
|
26588
|
+
return `${change.secret} ${change.change === "added" ? "may now" : "may no longer"} be sent to ${ruleLine(change.rule)}`;
|
|
26589
|
+
case "exec":
|
|
26590
|
+
return `${change.secret} was ${mode(change.from)}, now ${mode(change.to)}`;
|
|
26591
|
+
case "exits":
|
|
26592
|
+
if (change.to?.length === 0) return `${change.secret} now has no exit`;
|
|
26593
|
+
return `${change.secret} now leaves through ${change.to ? list4(change.to.map((exit) => exitLabel(exit, devices))) : "any exit"}`;
|
|
26594
|
+
default:
|
|
26595
|
+
return `The limit ${change.field} changed from ${change.from} to ${change.to}`;
|
|
26596
|
+
}
|
|
26597
|
+
}
|
|
26598
|
+
var codeTexts = {
|
|
26599
|
+
EACCES: "Unlock the vault first",
|
|
26600
|
+
ENOTSUP: "This arrives with a later vault version"
|
|
26601
|
+
};
|
|
26602
|
+
function widening(change, devices) {
|
|
26603
|
+
switch (change.kind) {
|
|
26604
|
+
case "rule":
|
|
26605
|
+
return `${change.secret} may now be sent to ${ruleLine(change.rule)}`;
|
|
26606
|
+
case "methods":
|
|
26607
|
+
return `${change.secret} may now use ${list4(change.methods)} on ${change.domain}`;
|
|
26608
|
+
case "paths":
|
|
26609
|
+
return `${change.secret} may now reach ${list4(change.paths)} on ${change.domain}`;
|
|
26610
|
+
case "exec":
|
|
26611
|
+
return `${change.secret} is now ${mode(change.grant)}`;
|
|
26612
|
+
case "exit":
|
|
26613
|
+
return `${change.secret} may now leave through ${exitLabel(change.exit, devices)}`;
|
|
26614
|
+
default:
|
|
26615
|
+
return `The limit ${change.field} rose from ${change.from} to ${change.to}`;
|
|
26616
|
+
}
|
|
26617
|
+
}
|
|
26618
|
+
function failureText(error) {
|
|
26619
|
+
const text2 = isVaultFailure(error) ? codeTexts[error.code] : void 0;
|
|
26620
|
+
return text2 ?? (error instanceof Error ? error.message : "The vault did not answer");
|
|
26621
|
+
}
|
|
26622
|
+
function fieldOf(error, field) {
|
|
26623
|
+
return isVaultFailure(error) && error.code === "EINVAL" ? field : null;
|
|
26624
|
+
}
|
|
26625
|
+
function away(vault) {
|
|
26626
|
+
const state3 = vault.availability?.() ?? (vault.status() ? "ready" : "waiting");
|
|
26627
|
+
return state3 === "connecting" || state3 === "waiting";
|
|
26628
|
+
}
|
|
26629
|
+
function take(input) {
|
|
26630
|
+
const value = input.value;
|
|
26631
|
+
input.value = "";
|
|
26632
|
+
return value;
|
|
26633
|
+
}
|
|
26634
|
+
function clearValues(root2) {
|
|
26635
|
+
for (const input of root2.querySelectorAll("input[type=password]"))
|
|
26636
|
+
input.value = "";
|
|
26637
|
+
}
|
|
26638
|
+
var fieldStyles = i`
|
|
26639
|
+
.field {
|
|
26640
|
+
display: grid;
|
|
26641
|
+
gap: var(--swc-spacing-75);
|
|
26642
|
+
min-width: 0;
|
|
26643
|
+
}
|
|
26644
|
+
.field > span {
|
|
26645
|
+
font-size: var(--swc-font-size-75);
|
|
26646
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
26647
|
+
}
|
|
26648
|
+
.field input:not([type='checkbox']) {
|
|
26649
|
+
box-sizing: border-box;
|
|
26650
|
+
inline-size: 100%;
|
|
26651
|
+
font: inherit;
|
|
26652
|
+
min-height: var(--swc-component-height-100);
|
|
26653
|
+
padding: 0 var(--swc-spacing-100);
|
|
26654
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-400);
|
|
26655
|
+
border-radius: var(--swc-corner-radius-small-default);
|
|
26656
|
+
background: var(--swc-background-layer-2-color);
|
|
26657
|
+
color: inherit;
|
|
26658
|
+
}
|
|
26659
|
+
.field input[aria-invalid='true'] {
|
|
26660
|
+
border-color: var(--swc-negative-border-color-default);
|
|
26661
|
+
}
|
|
26662
|
+
.field input[type='file'] {
|
|
26663
|
+
padding: var(--swc-spacing-75) var(--swc-spacing-100);
|
|
26664
|
+
}
|
|
26665
|
+
.field input[type='file']::file-selector-button {
|
|
26666
|
+
font: inherit;
|
|
26667
|
+
font-weight: var(--swc-bold-font-weight);
|
|
26668
|
+
margin-inline-end: var(--swc-spacing-200);
|
|
26669
|
+
padding: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
26670
|
+
border: none;
|
|
26671
|
+
border-radius: var(--swc-corner-radius-full);
|
|
26672
|
+
background: var(--swc-gray-200);
|
|
26673
|
+
color: inherit;
|
|
26674
|
+
}
|
|
26675
|
+
.field input:focus-visible,
|
|
26676
|
+
input[type='checkbox']:focus-visible {
|
|
26677
|
+
outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
|
|
26678
|
+
outline-offset: var(--swc-focus-ring-gap);
|
|
26679
|
+
}
|
|
26680
|
+
`;
|
|
26681
|
+
function shown2(element2, style = getComputedStyle(element2)) {
|
|
26682
|
+
return !element2.hidden && !element2.inert && style.display !== "none";
|
|
26683
|
+
}
|
|
26684
|
+
function disabled(element2) {
|
|
26685
|
+
if (element2.matches(":disabled")) return true;
|
|
26686
|
+
if (!element2.matches("button, input, select, textarea")) return false;
|
|
26687
|
+
let fieldset = element2.closest("fieldset[disabled]");
|
|
26688
|
+
while (fieldset) {
|
|
26689
|
+
if (!fieldset.querySelector(":scope > legend")?.contains(element2)) return true;
|
|
26690
|
+
fieldset = fieldset.parentElement?.closest("fieldset[disabled]") ?? null;
|
|
26691
|
+
}
|
|
26692
|
+
return false;
|
|
26693
|
+
}
|
|
26694
|
+
function reachable(element2) {
|
|
26695
|
+
const radio = element2;
|
|
26696
|
+
if (radio.localName !== "input" || radio.type !== "radio" || !radio.name) return true;
|
|
26697
|
+
const root2 = radio.getRootNode();
|
|
26698
|
+
const group = Array.from(root2.querySelectorAll("input[type=radio]")).filter(
|
|
26699
|
+
(other) => other.name === radio.name && other.form === radio.form
|
|
26700
|
+
);
|
|
26701
|
+
const checked = group.find((other) => other.checked);
|
|
26702
|
+
return checked ? checked === radio : radio === group[0] || radio === group.at(-1);
|
|
26703
|
+
}
|
|
26704
|
+
function tabbables(root2, stop, out = []) {
|
|
26705
|
+
for (const child of Array.from(root2.children)) {
|
|
26706
|
+
if (child === stop) {
|
|
26707
|
+
out.push(null);
|
|
26708
|
+
continue;
|
|
26709
|
+
}
|
|
26710
|
+
const style = getComputedStyle(child);
|
|
26711
|
+
if (!shown2(child, style)) continue;
|
|
26712
|
+
if (child.localName === "details" && !child.open) {
|
|
26713
|
+
const summary = child.querySelector(":scope > summary");
|
|
26714
|
+
if (summary && shown2(summary) && getComputedStyle(summary).visibility !== "hidden" && !(summary.hasAttribute("tabindex") && summary.tabIndex < 0))
|
|
26715
|
+
out.push(summary);
|
|
26716
|
+
continue;
|
|
26717
|
+
}
|
|
26718
|
+
if (child.tabIndex >= 0 && !disabled(child) && style.visibility !== "hidden" && reachable(child))
|
|
26719
|
+
out.push(child);
|
|
26720
|
+
if (child.shadowRoot) tabbables(child.shadowRoot, stop, out);
|
|
26721
|
+
tabbables(child, stop, out);
|
|
26722
|
+
}
|
|
26723
|
+
return out;
|
|
26724
|
+
}
|
|
26725
|
+
function sequential(order) {
|
|
26726
|
+
const rank = (element2) => element2 && element2.tabIndex > 0 ? element2.tabIndex : Number.POSITIVE_INFINITY;
|
|
26727
|
+
return [...order].sort((a22, b13) => rank(a22) - rank(b13) || 0);
|
|
26728
|
+
}
|
|
26729
|
+
var SliccVaultButton = class extends i2 {
|
|
26730
|
+
static properties = {
|
|
26731
|
+
vault: { attribute: false },
|
|
26732
|
+
config: { attribute: false }
|
|
26733
|
+
};
|
|
26734
|
+
#button = null;
|
|
26735
|
+
#off = null;
|
|
26736
|
+
#ready = false;
|
|
26737
|
+
#sent = "";
|
|
26738
|
+
static styles = i`
|
|
26739
|
+
:host {
|
|
26740
|
+
display: inline-flex;
|
|
26741
|
+
vertical-align: middle;
|
|
26742
|
+
}
|
|
26743
|
+
iframe {
|
|
26744
|
+
border: 0;
|
|
26745
|
+
background: transparent;
|
|
26746
|
+
color-scheme: normal;
|
|
26747
|
+
}
|
|
26748
|
+
`;
|
|
26749
|
+
constructor() {
|
|
26750
|
+
super();
|
|
26751
|
+
this.vault = null;
|
|
26752
|
+
this.config = null;
|
|
26753
|
+
}
|
|
26754
|
+
connectedCallback() {
|
|
26755
|
+
super.connectedCallback();
|
|
26756
|
+
this.requestUpdate();
|
|
26757
|
+
}
|
|
26758
|
+
disconnectedCallback() {
|
|
26759
|
+
super.disconnectedCallback();
|
|
26760
|
+
this.#drop();
|
|
26761
|
+
}
|
|
26762
|
+
focus() {
|
|
26763
|
+
this.#button?.post({ type: "slicc-vault", v: 1, op: "focus" });
|
|
26764
|
+
}
|
|
26765
|
+
updated(changed) {
|
|
26766
|
+
if (changed.has("vault")) this.#drop();
|
|
26767
|
+
if (!this.#button && this.vault) this.#mount(this.vault);
|
|
26768
|
+
this.#send();
|
|
26769
|
+
}
|
|
26770
|
+
#mount(vault) {
|
|
26771
|
+
const button = vault.button();
|
|
26772
|
+
this.#button = button;
|
|
26773
|
+
this.#off = button.listen((event2) => this.#event(event2));
|
|
26774
|
+
this.renderRoot.append(button.element);
|
|
26775
|
+
}
|
|
26776
|
+
#drop() {
|
|
26777
|
+
this.#off?.();
|
|
26778
|
+
this.#button?.element.remove();
|
|
26779
|
+
this.#button = null;
|
|
26780
|
+
this.#off = null;
|
|
26781
|
+
this.#ready = false;
|
|
26782
|
+
this.#sent = "";
|
|
26783
|
+
}
|
|
26784
|
+
#send() {
|
|
26785
|
+
if (!(this.#ready && this.#button && this.config)) return;
|
|
26786
|
+
const sent = JSON.stringify(this.config);
|
|
26787
|
+
if (sent === this.#sent) return;
|
|
26788
|
+
this.#sent = sent;
|
|
26789
|
+
this.#button.post({ type: "slicc-vault", v: 1, op: "button", button: this.config });
|
|
26790
|
+
}
|
|
26791
|
+
#event(event2) {
|
|
26792
|
+
const element2 = this.#button?.element;
|
|
26793
|
+
if (event2.event === "ready") {
|
|
26794
|
+
this.#ready = true;
|
|
26795
|
+
this.#send();
|
|
26796
|
+
} else if (event2.event === "size") {
|
|
26797
|
+
element2.style.width = `${event2.width}px`;
|
|
26798
|
+
element2.style.height = `${event2.height}px`;
|
|
26799
|
+
element2.style.margin = `${-event2.inset}px`;
|
|
26800
|
+
} else if (event2.event === "label") {
|
|
26801
|
+
element2.title = event2.label;
|
|
26802
|
+
} else if (event2.event === "focus") {
|
|
26803
|
+
const order = sequential(tabbables(this.ownerDocument, this));
|
|
26804
|
+
const at = order.indexOf(null);
|
|
26805
|
+
order[event2.direction === "next" ? at + 1 : at - 1]?.focus();
|
|
26806
|
+
} else if (event2.event === "popup") {
|
|
26807
|
+
const { intent, state: state3 } = event2;
|
|
26808
|
+
this.dispatchEvent(
|
|
26809
|
+
new CustomEvent("vault-popup", {
|
|
26810
|
+
detail: { intent, state: state3 },
|
|
26811
|
+
bubbles: true,
|
|
26812
|
+
composed: true
|
|
26813
|
+
})
|
|
26814
|
+
);
|
|
26815
|
+
}
|
|
26816
|
+
}
|
|
26817
|
+
};
|
|
26818
|
+
|
|
26493
26819
|
// src/app/composer.ts
|
|
26494
26820
|
var limit = 25 * 1024 * 1024;
|
|
26495
26821
|
function available(model) {
|
|
@@ -26579,6 +26905,10 @@ function trigger(text2, caret) {
|
|
|
26579
26905
|
return { kind: "mention", start: before.length - mention[2].length - 1, query: mention[2] };
|
|
26580
26906
|
return null;
|
|
26581
26907
|
}
|
|
26908
|
+
function blocked(vault) {
|
|
26909
|
+
if (away(vault)) return "Waiting for the vault";
|
|
26910
|
+
return vault.status()?.locked ? "Unlock the vault first" : null;
|
|
26911
|
+
}
|
|
26582
26912
|
var SliccComposer = class extends ThemedElement {
|
|
26583
26913
|
static properties = {
|
|
26584
26914
|
...ThemedElement.properties,
|
|
@@ -26587,6 +26917,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26587
26917
|
popup: { state: true },
|
|
26588
26918
|
dictating: { state: true },
|
|
26589
26919
|
blocked: { state: true },
|
|
26920
|
+
sharing: { state: true },
|
|
26921
|
+
secretError: { state: true },
|
|
26922
|
+
secretField: { state: true },
|
|
26590
26923
|
agent: {}
|
|
26591
26924
|
};
|
|
26592
26925
|
#drafts = /* @__PURE__ */ new Map();
|
|
@@ -26603,6 +26936,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26603
26936
|
this.popup = null;
|
|
26604
26937
|
this.dictating = false;
|
|
26605
26938
|
this.blocked = false;
|
|
26939
|
+
this.sharing = false;
|
|
26940
|
+
this.secretError = null;
|
|
26941
|
+
this.secretField = null;
|
|
26606
26942
|
this.agent = "";
|
|
26607
26943
|
}
|
|
26608
26944
|
static styles = [
|
|
@@ -26809,6 +27145,14 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26809
27145
|
gap: var(--swc-spacing-100);
|
|
26810
27146
|
padding: var(--swc-spacing-100);
|
|
26811
27147
|
}
|
|
27148
|
+
.secret .field {
|
|
27149
|
+
display: grid;
|
|
27150
|
+
gap: var(--swc-spacing-75);
|
|
27151
|
+
}
|
|
27152
|
+
.secret .field > span {
|
|
27153
|
+
font-size: var(--swc-font-size-75);
|
|
27154
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
27155
|
+
}
|
|
26812
27156
|
.secret input {
|
|
26813
27157
|
font: inherit;
|
|
26814
27158
|
min-height: var(--swc-component-height-100);
|
|
@@ -26818,6 +27162,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26818
27162
|
background: var(--swc-background-layer-2-color);
|
|
26819
27163
|
color: inherit;
|
|
26820
27164
|
}
|
|
27165
|
+
.secret input[aria-invalid='true'] {
|
|
27166
|
+
border-color: var(--swc-negative-border-color-default);
|
|
27167
|
+
}
|
|
26821
27168
|
.secret input:focus-visible {
|
|
26822
27169
|
outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
|
|
26823
27170
|
outline-offset: var(--swc-focus-ring-gap);
|
|
@@ -26825,6 +27172,14 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26825
27172
|
.secret swc-button {
|
|
26826
27173
|
justify-self: start;
|
|
26827
27174
|
}
|
|
27175
|
+
.secret-error {
|
|
27176
|
+
display: flex;
|
|
27177
|
+
align-items: flex-start;
|
|
27178
|
+
gap: var(--swc-spacing-75);
|
|
27179
|
+
color: var(--swc-negative-content-color-default);
|
|
27180
|
+
font-size: var(--swc-font-size-75);
|
|
27181
|
+
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
27182
|
+
}
|
|
26828
27183
|
sp-menu {
|
|
26829
27184
|
min-width: 240px;
|
|
26830
27185
|
}
|
|
@@ -26835,6 +27190,7 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26835
27190
|
];
|
|
26836
27191
|
willUpdate(changed) {
|
|
26837
27192
|
super.willUpdate(changed);
|
|
27193
|
+
if (changed.has("popup") && this.popup?.kind !== "secret") clearValues(this.renderRoot);
|
|
26838
27194
|
if (changed.has("agent") && this.agent && this.model && this.agent !== this.#agent) {
|
|
26839
27195
|
this.#switch(this.agent);
|
|
26840
27196
|
}
|
|
@@ -26846,6 +27202,10 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26846
27202
|
firstUpdated() {
|
|
26847
27203
|
this.#wire();
|
|
26848
27204
|
}
|
|
27205
|
+
disconnectedCallback() {
|
|
27206
|
+
super.disconnectedCallback();
|
|
27207
|
+
clearValues(this.renderRoot);
|
|
27208
|
+
}
|
|
26849
27209
|
updated(changed) {
|
|
26850
27210
|
if (changed.has("popup"))
|
|
26851
27211
|
this.renderRoot.querySelector('.item[aria-selected="true"]')?.scrollIntoView({ block: "nearest" });
|
|
@@ -26879,7 +27239,8 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26879
27239
|
model.agent.on("messages", update),
|
|
26880
27240
|
model.agent.on("message", update),
|
|
26881
27241
|
model.settings.on("settings", update),
|
|
26882
|
-
...model.follow ? [model.follow.on("follow", update)] : []
|
|
27242
|
+
...model.follow ? [model.follow.on("follow", update)] : [],
|
|
27243
|
+
...model.vault ? [model.vault.on("availability", update), model.vault.on("status", update)] : []
|
|
26883
27244
|
];
|
|
26884
27245
|
}
|
|
26885
27246
|
#held() {
|
|
@@ -26914,7 +27275,7 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26914
27275
|
#busy() {
|
|
26915
27276
|
return this.model?.agent.busy(this.#agent) ?? false;
|
|
26916
27277
|
}
|
|
26917
|
-
send(
|
|
27278
|
+
send(mode2 = "send") {
|
|
26918
27279
|
const model = this.model;
|
|
26919
27280
|
const text2 = this.value.trim();
|
|
26920
27281
|
const attachments = this.attachments.filter((attachment2) => !attachment2.error);
|
|
@@ -26930,7 +27291,7 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26930
27291
|
return;
|
|
26931
27292
|
}
|
|
26932
27293
|
const busy = this.#busy();
|
|
26933
|
-
const resolved =
|
|
27294
|
+
const resolved = mode2 === "queue" ? busy ? "queue" : "send" : busy || mode2 === "steer" ? "steer" : "send";
|
|
26934
27295
|
void model.agent.send(this.#agent, { text: text2, attachments, mode: resolved });
|
|
26935
27296
|
}
|
|
26936
27297
|
#id() {
|
|
@@ -26995,9 +27356,17 @@ var SliccComposer = class extends ThemedElement {
|
|
|
26995
27356
|
text2 === null || text2 === void 0 ? { ...base, kind: "file", size: 0, error: "Could not read the file" } : { ...base, kind: "text", size: text2.length, text: text2 }
|
|
26996
27357
|
];
|
|
26997
27358
|
}
|
|
26998
|
-
shareSecret(name) {
|
|
27359
|
+
async shareSecret(name, field = null) {
|
|
26999
27360
|
const clean = name.trim().toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
27000
|
-
if (
|
|
27361
|
+
if (this.sharing) return;
|
|
27362
|
+
if (!clean) {
|
|
27363
|
+
if (field) this.#refuse("Enter a name", "name", true);
|
|
27364
|
+
return;
|
|
27365
|
+
}
|
|
27366
|
+
const value = field ? take(field) : "";
|
|
27367
|
+
const vault = this.model?.vault;
|
|
27368
|
+
if (field && vault?.put && !await this.#store(vault, clean, value)) return;
|
|
27369
|
+
this.#refuse(null);
|
|
27001
27370
|
this.attachments = [
|
|
27002
27371
|
...this.attachments,
|
|
27003
27372
|
{
|
|
@@ -27010,6 +27379,51 @@ var SliccComposer = class extends ThemedElement {
|
|
|
27010
27379
|
];
|
|
27011
27380
|
this.popup = null;
|
|
27012
27381
|
}
|
|
27382
|
+
#refuse(text2, field = null, focus = false) {
|
|
27383
|
+
this.secretError = text2;
|
|
27384
|
+
this.secretField = text2 ? field : null;
|
|
27385
|
+
if (focus && text2 && field)
|
|
27386
|
+
void this.updateComplete.then(
|
|
27387
|
+
() => this.renderRoot.querySelector(`form.secret input[name=${field}]`)?.focus()
|
|
27388
|
+
);
|
|
27389
|
+
}
|
|
27390
|
+
async #store(vault, clean, value) {
|
|
27391
|
+
if (blocked(vault)) {
|
|
27392
|
+
this.#refuse(blocked(vault));
|
|
27393
|
+
return false;
|
|
27394
|
+
}
|
|
27395
|
+
const exists = !!vault.list()?.secrets.some((secret) => secret.name === clean && secret.state !== "removed");
|
|
27396
|
+
if (exists && value === "") return true;
|
|
27397
|
+
const bad = nameProblem(clean);
|
|
27398
|
+
const problem = bad ?? valueProblem(value);
|
|
27399
|
+
this.#refuse(problem, bad ? "name" : "value", true);
|
|
27400
|
+
if (problem) return false;
|
|
27401
|
+
const agent = this.#agent;
|
|
27402
|
+
const mine = () => this.#agent === agent && this.model?.vault === vault;
|
|
27403
|
+
this.sharing = true;
|
|
27404
|
+
try {
|
|
27405
|
+
if (exists) {
|
|
27406
|
+
const sure = await confirm({
|
|
27407
|
+
title: `Replace ${clean}?`,
|
|
27408
|
+
body: "A secret with this name exists. Sharing replaces its value, and its placeholder stays.",
|
|
27409
|
+
action: "Replace",
|
|
27410
|
+
variant: "confirmation"
|
|
27411
|
+
});
|
|
27412
|
+
if (!sure || !mine()) return false;
|
|
27413
|
+
if (blocked(vault)) {
|
|
27414
|
+
this.#refuse(blocked(vault));
|
|
27415
|
+
return false;
|
|
27416
|
+
}
|
|
27417
|
+
}
|
|
27418
|
+
await vault.put?.(clean, value);
|
|
27419
|
+
return mine();
|
|
27420
|
+
} catch (error) {
|
|
27421
|
+
if (mine()) this.#refuse(failureText(error), fieldOf(error, "value"));
|
|
27422
|
+
return false;
|
|
27423
|
+
} finally {
|
|
27424
|
+
this.sharing = false;
|
|
27425
|
+
}
|
|
27426
|
+
}
|
|
27013
27427
|
#choices(kind, query) {
|
|
27014
27428
|
const model = this.model;
|
|
27015
27429
|
if (kind === "command") {
|
|
@@ -27053,6 +27467,9 @@ var SliccComposer = class extends ThemedElement {
|
|
|
27053
27467
|
this.popup = found && (found.kind !== "argument" || takes) ? { ...found, items: this.#choices(found.kind, found.query), index: 0 } : null;
|
|
27054
27468
|
}
|
|
27055
27469
|
openPopup(kind) {
|
|
27470
|
+
clearValues(this.renderRoot);
|
|
27471
|
+
this.secretError = null;
|
|
27472
|
+
this.secretField = null;
|
|
27056
27473
|
this.popup = {
|
|
27057
27474
|
kind,
|
|
27058
27475
|
start: 0,
|
|
@@ -27214,17 +27631,32 @@ var SliccComposer = class extends ThemedElement {
|
|
|
27214
27631
|
const popup2 = this.popup;
|
|
27215
27632
|
if (!popup2) return A;
|
|
27216
27633
|
if (popup2.kind === "secret") {
|
|
27634
|
+
const vault = this.model?.vault;
|
|
27635
|
+
const valued = !!vault?.put && !blocked(vault);
|
|
27636
|
+
const waiting2 = vault?.put ? blocked(vault) : null;
|
|
27637
|
+
if (!valued) clearValues(this.renderRoot);
|
|
27217
27638
|
const submit = (event2) => {
|
|
27218
27639
|
event2.preventDefault();
|
|
27219
27640
|
const form = event2.currentTarget;
|
|
27220
|
-
this.shareSecret(
|
|
27641
|
+
void this.shareSecret(
|
|
27642
|
+
form.elements.namedItem("name").value,
|
|
27643
|
+
form.elements.namedItem("value")
|
|
27644
|
+
);
|
|
27645
|
+
};
|
|
27646
|
+
const close = (event2) => {
|
|
27647
|
+
if (event2.key !== "Escape") return;
|
|
27648
|
+
clearValues(this.renderRoot);
|
|
27649
|
+
this.popup = null;
|
|
27221
27650
|
};
|
|
27222
|
-
|
|
27651
|
+
const bad = (name) => this.secretField === name ? "true" : A;
|
|
27652
|
+
const described = (name) => this.secretField === name ? "secret-error" : A;
|
|
27653
|
+
return b`<form class="popup secret" data-vault=${valued ? "on" : "off"} @submit=${submit} @keydown=${close} @input=${() => this.secretField = null}>
|
|
27223
27654
|
<strong>Share a secret</strong>
|
|
27224
|
-
<span class="lead"
|
|
27225
|
-
<input name="name" placeholder="
|
|
27226
|
-
|
|
27227
|
-
|
|
27655
|
+
<span class="lead">${valued ? "The value goes to the vault; the agent only sees its name. Leave the value empty to share a secret the vault already has." : waiting2 === "Unlock the vault first" ? "The vault is locked. You can share the name now and add the value once it is unlocked." : waiting2 ? "Waiting for the vault. You can share the name now and add the value in Settings \u203A Secrets later." : "Add the value in Settings \u203A Secrets. The agent only sees the name."}</span>
|
|
27656
|
+
<label class="field"><span>Name</span><input name="name" placeholder="API_TOKEN" autocomplete="off" spellcheck="false" aria-invalid=${bad("name")} aria-describedby=${described("name")} /></label>
|
|
27657
|
+
${valued ? b`<label class="field"><span>Value</span><input name="value" type="password" autocomplete="off" spellcheck="false" aria-invalid=${bad("value")} aria-describedby=${described("value")} /></label>` : A}
|
|
27658
|
+
${this.secretError ? b`<span class="secret-error" role="alert" id="secret-error" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${this.secretError}</span></span>` : A}
|
|
27659
|
+
<swc-button size="s" variant="accent" data-action="share-secret" ?pending=${this.sharing} @click=${(event2) => event2.currentTarget.closest("form")?.requestSubmit()}>Share</swc-button>
|
|
27228
27660
|
</form>`;
|
|
27229
27661
|
}
|
|
27230
27662
|
const title = {
|
|
@@ -27746,11 +28178,13 @@ function attention(section) {
|
|
|
27746
28178
|
var SliccMonitor = class extends ModelElement {
|
|
27747
28179
|
static properties = {
|
|
27748
28180
|
...ModelElement.properties,
|
|
27749
|
-
expanded: { state: true }
|
|
28181
|
+
expanded: { state: true },
|
|
28182
|
+
copied: { state: true }
|
|
27750
28183
|
};
|
|
27751
28184
|
constructor() {
|
|
27752
28185
|
super();
|
|
27753
28186
|
this.expanded = {};
|
|
28187
|
+
this.copied = null;
|
|
27754
28188
|
}
|
|
27755
28189
|
static styles = [
|
|
27756
28190
|
shared,
|
|
@@ -27850,6 +28284,36 @@ var SliccMonitor = class extends ModelElement {
|
|
|
27850
28284
|
display: block;
|
|
27851
28285
|
color: var(--swc-neutral-subdued-content-color-default);
|
|
27852
28286
|
}
|
|
28287
|
+
.alert > div {
|
|
28288
|
+
min-width: 0;
|
|
28289
|
+
}
|
|
28290
|
+
.alert .command {
|
|
28291
|
+
display: flex;
|
|
28292
|
+
align-items: center;
|
|
28293
|
+
gap: var(--swc-spacing-100);
|
|
28294
|
+
margin-block-start: var(--swc-spacing-75);
|
|
28295
|
+
padding-inline-start: var(--swc-spacing-100);
|
|
28296
|
+
border-radius: var(--swc-corner-radius-medium-default);
|
|
28297
|
+
background: var(--swc-background-layer-1-color);
|
|
28298
|
+
}
|
|
28299
|
+
.alert code {
|
|
28300
|
+
flex: 1;
|
|
28301
|
+
min-width: 0;
|
|
28302
|
+
overflow-x: auto;
|
|
28303
|
+
white-space: nowrap;
|
|
28304
|
+
font-family: var(--swc-code-font-family-stack);
|
|
28305
|
+
font-size: var(--swc-font-size-75);
|
|
28306
|
+
color: var(--swc-code-color);
|
|
28307
|
+
}
|
|
28308
|
+
.alert .lead {
|
|
28309
|
+
display: block;
|
|
28310
|
+
margin-block-start: var(--swc-spacing-75);
|
|
28311
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28312
|
+
}
|
|
28313
|
+
.alert .uncopied {
|
|
28314
|
+
display: block;
|
|
28315
|
+
color: var(--swc-negative-content-color-default);
|
|
28316
|
+
}
|
|
27853
28317
|
.sections {
|
|
27854
28318
|
display: grid;
|
|
27855
28319
|
margin: 0;
|
|
@@ -27974,9 +28438,16 @@ var SliccMonitor = class extends ModelElement {
|
|
|
27974
28438
|
const error = alert.severity === "error";
|
|
27975
28439
|
return b`<li class="alert" data-severity=${alert.severity}>
|
|
27976
28440
|
${error ? b`<swc-icon-alert-diamond size="s" aria-hidden="true"></swc-icon-alert-diamond>` : b`<swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle>`}
|
|
27977
|
-
<div><span class="sr">${error ? "Error: " : "Warning: "}</span><strong>${alert.title}</strong><span class="detail">${alert.detail}</span
|
|
28441
|
+
<div><span class="sr">${error ? "Error: " : "Warning: "}</span><strong>${alert.title}</strong><span class="detail">${alert.detail}</span>${alert.command ? this.#command(alert.id, alert.command, alert.commandLabel ?? "Run") : A}</div>
|
|
27978
28442
|
</li>`;
|
|
27979
28443
|
}
|
|
28444
|
+
#command(id, text2, label) {
|
|
28445
|
+
const copied = this.copied?.id === id && this.copied.text === text2 ? this.copied : null;
|
|
28446
|
+
return b`<span class="lead">${label}:</span><div class="command" data-command><code>${text2}</code><swc-action-button size="s" quiet data-action="copy-command" accessible-label=${copied?.done ? "Copied" : "Copy command"} @click=${() => this.#copy(id, text2)}><swc-icon-copy slot="icon"></swc-icon-copy>${copied?.done ? "Copied" : "Copy"}</swc-action-button></div>${copied && !copied.done ? b`<span class="uncopied" role="alert" data-error="copy">Couldn’t copy. Select the command and copy it.</span>` : A}`;
|
|
28447
|
+
}
|
|
28448
|
+
async #copy(id, text2) {
|
|
28449
|
+
this.copied = { id, text: text2, done: await copyText(text2) };
|
|
28450
|
+
}
|
|
27980
28451
|
#open(id) {
|
|
27981
28452
|
this.dispatchEvent(
|
|
27982
28453
|
new CustomEvent("show-surface", { detail: { id }, bubbles: true, composed: true })
|
|
@@ -28214,197 +28685,6 @@ var SliccNotices = class extends ModelElement {
|
|
|
28214
28685
|
}
|
|
28215
28686
|
};
|
|
28216
28687
|
|
|
28217
|
-
// src/app/vault.ts
|
|
28218
|
-
var exitNames = {
|
|
28219
|
-
"vault-direct": "Straight from the vault",
|
|
28220
|
-
"local-proxy": "Local proxy",
|
|
28221
|
-
"cli-v": "Local SLICC, direct",
|
|
28222
|
-
tailscale: "Tailscale",
|
|
28223
|
-
"local-link": "Linked SLICC, through this page"
|
|
28224
|
-
};
|
|
28225
|
-
function devicesOf(model) {
|
|
28226
|
-
return model?.network?.status().links?.devices ?? [];
|
|
28227
|
-
}
|
|
28228
|
-
function deviceName2(id, devices) {
|
|
28229
|
-
return (devices.find((device) => device.id === id)?.name ?? id).replace(/^slicc\b/i, "SLICC");
|
|
28230
|
-
}
|
|
28231
|
-
function exitLabel(exit, devices) {
|
|
28232
|
-
if (exit.startsWith("device:")) return deviceName2(exit.slice("device:".length), devices);
|
|
28233
|
-
return exitNames[exit];
|
|
28234
|
-
}
|
|
28235
|
-
function list4(items) {
|
|
28236
|
-
if (items.length < 2) return items.join("");
|
|
28237
|
-
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
28238
|
-
}
|
|
28239
|
-
function ruleLine(rule) {
|
|
28240
|
-
const methods = rule.methods.length ? rule.methods.join(" or ") : "any method";
|
|
28241
|
-
const paths = rule.paths.length ? rule.paths.join(" or ") : "any path";
|
|
28242
|
-
return `${rule.domain}, in ${rule.header}, ${methods}, ${paths}`;
|
|
28243
|
-
}
|
|
28244
|
-
function shellWord(word) {
|
|
28245
|
-
return /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replace(/'/g, "'\\''")}'`;
|
|
28246
|
-
}
|
|
28247
|
-
function execLine(grant) {
|
|
28248
|
-
if (grant === false) return "Never revealed to programs";
|
|
28249
|
-
if (grant === true) return "Revealed to any program that asks";
|
|
28250
|
-
return `Revealed only to ${list4(grant.argv.map((argv) => argv.map(shellWord).join(" ")))}`;
|
|
28251
|
-
}
|
|
28252
|
-
function widening(change, devices) {
|
|
28253
|
-
switch (change.kind) {
|
|
28254
|
-
case "rule":
|
|
28255
|
-
return `${change.secret} may now be sent to ${ruleLine(change.rule)}`;
|
|
28256
|
-
case "methods":
|
|
28257
|
-
return `${change.secret} may now use ${list4(change.methods)} on ${change.domain}`;
|
|
28258
|
-
case "paths":
|
|
28259
|
-
return `${change.secret} may now reach ${list4(change.paths)} on ${change.domain}`;
|
|
28260
|
-
case "exec": {
|
|
28261
|
-
const line = execLine(change.grant);
|
|
28262
|
-
return `${change.secret}: ${line[0].toLowerCase()}${line.slice(1)}`;
|
|
28263
|
-
}
|
|
28264
|
-
case "exit":
|
|
28265
|
-
return `${change.secret} may now leave through ${exitLabel(change.exit, devices)}`;
|
|
28266
|
-
default:
|
|
28267
|
-
return `The limit ${change.field} rose from ${change.from} to ${change.to}`;
|
|
28268
|
-
}
|
|
28269
|
-
}
|
|
28270
|
-
function shown2(element2, style = getComputedStyle(element2)) {
|
|
28271
|
-
return !element2.hidden && !element2.inert && style.display !== "none";
|
|
28272
|
-
}
|
|
28273
|
-
function disabled(element2) {
|
|
28274
|
-
if (element2.matches(":disabled")) return true;
|
|
28275
|
-
if (!element2.matches("button, input, select, textarea")) return false;
|
|
28276
|
-
let fieldset = element2.closest("fieldset[disabled]");
|
|
28277
|
-
while (fieldset) {
|
|
28278
|
-
if (!fieldset.querySelector(":scope > legend")?.contains(element2)) return true;
|
|
28279
|
-
fieldset = fieldset.parentElement?.closest("fieldset[disabled]") ?? null;
|
|
28280
|
-
}
|
|
28281
|
-
return false;
|
|
28282
|
-
}
|
|
28283
|
-
function reachable(element2) {
|
|
28284
|
-
const radio = element2;
|
|
28285
|
-
if (radio.localName !== "input" || radio.type !== "radio" || !radio.name) return true;
|
|
28286
|
-
const root2 = radio.getRootNode();
|
|
28287
|
-
const group = Array.from(root2.querySelectorAll("input[type=radio]")).filter(
|
|
28288
|
-
(other) => other.name === radio.name && other.form === radio.form
|
|
28289
|
-
);
|
|
28290
|
-
const checked = group.find((other) => other.checked);
|
|
28291
|
-
return checked ? checked === radio : radio === group[0] || radio === group.at(-1);
|
|
28292
|
-
}
|
|
28293
|
-
function tabbables(root2, stop, out = []) {
|
|
28294
|
-
for (const child of Array.from(root2.children)) {
|
|
28295
|
-
if (child === stop) {
|
|
28296
|
-
out.push(null);
|
|
28297
|
-
continue;
|
|
28298
|
-
}
|
|
28299
|
-
const style = getComputedStyle(child);
|
|
28300
|
-
if (!shown2(child, style)) continue;
|
|
28301
|
-
if (child.localName === "details" && !child.open) {
|
|
28302
|
-
const summary = child.querySelector(":scope > summary");
|
|
28303
|
-
if (summary && shown2(summary) && getComputedStyle(summary).visibility !== "hidden" && !(summary.hasAttribute("tabindex") && summary.tabIndex < 0))
|
|
28304
|
-
out.push(summary);
|
|
28305
|
-
continue;
|
|
28306
|
-
}
|
|
28307
|
-
if (child.tabIndex >= 0 && !disabled(child) && style.visibility !== "hidden" && reachable(child))
|
|
28308
|
-
out.push(child);
|
|
28309
|
-
if (child.shadowRoot) tabbables(child.shadowRoot, stop, out);
|
|
28310
|
-
tabbables(child, stop, out);
|
|
28311
|
-
}
|
|
28312
|
-
return out;
|
|
28313
|
-
}
|
|
28314
|
-
function sequential(order) {
|
|
28315
|
-
const rank = (element2) => element2 && element2.tabIndex > 0 ? element2.tabIndex : Number.POSITIVE_INFINITY;
|
|
28316
|
-
return [...order].sort((a22, b13) => rank(a22) - rank(b13) || 0);
|
|
28317
|
-
}
|
|
28318
|
-
var SliccVaultButton = class extends i2 {
|
|
28319
|
-
static properties = {
|
|
28320
|
-
vault: { attribute: false },
|
|
28321
|
-
config: { attribute: false }
|
|
28322
|
-
};
|
|
28323
|
-
#button = null;
|
|
28324
|
-
#off = null;
|
|
28325
|
-
#ready = false;
|
|
28326
|
-
#sent = "";
|
|
28327
|
-
static styles = i`
|
|
28328
|
-
:host {
|
|
28329
|
-
display: inline-flex;
|
|
28330
|
-
vertical-align: middle;
|
|
28331
|
-
}
|
|
28332
|
-
iframe {
|
|
28333
|
-
border: 0;
|
|
28334
|
-
background: transparent;
|
|
28335
|
-
color-scheme: normal;
|
|
28336
|
-
}
|
|
28337
|
-
`;
|
|
28338
|
-
constructor() {
|
|
28339
|
-
super();
|
|
28340
|
-
this.vault = null;
|
|
28341
|
-
this.config = null;
|
|
28342
|
-
}
|
|
28343
|
-
connectedCallback() {
|
|
28344
|
-
super.connectedCallback();
|
|
28345
|
-
this.requestUpdate();
|
|
28346
|
-
}
|
|
28347
|
-
disconnectedCallback() {
|
|
28348
|
-
super.disconnectedCallback();
|
|
28349
|
-
this.#drop();
|
|
28350
|
-
}
|
|
28351
|
-
focus() {
|
|
28352
|
-
this.#button?.post({ type: "slicc-vault", v: 1, op: "focus" });
|
|
28353
|
-
}
|
|
28354
|
-
updated(changed) {
|
|
28355
|
-
if (changed.has("vault")) this.#drop();
|
|
28356
|
-
if (!this.#button && this.vault) this.#mount(this.vault);
|
|
28357
|
-
this.#send();
|
|
28358
|
-
}
|
|
28359
|
-
#mount(vault) {
|
|
28360
|
-
const button = vault.button();
|
|
28361
|
-
this.#button = button;
|
|
28362
|
-
this.#off = button.listen((event2) => this.#event(event2));
|
|
28363
|
-
this.renderRoot.append(button.element);
|
|
28364
|
-
}
|
|
28365
|
-
#drop() {
|
|
28366
|
-
this.#off?.();
|
|
28367
|
-
this.#button?.element.remove();
|
|
28368
|
-
this.#button = null;
|
|
28369
|
-
this.#off = null;
|
|
28370
|
-
this.#ready = false;
|
|
28371
|
-
this.#sent = "";
|
|
28372
|
-
}
|
|
28373
|
-
#send() {
|
|
28374
|
-
if (!(this.#ready && this.#button && this.config)) return;
|
|
28375
|
-
const sent = JSON.stringify(this.config);
|
|
28376
|
-
if (sent === this.#sent) return;
|
|
28377
|
-
this.#sent = sent;
|
|
28378
|
-
this.#button.post({ type: "slicc-vault", v: 1, op: "button", button: this.config });
|
|
28379
|
-
}
|
|
28380
|
-
#event(event2) {
|
|
28381
|
-
const element2 = this.#button?.element;
|
|
28382
|
-
if (event2.event === "ready") {
|
|
28383
|
-
this.#ready = true;
|
|
28384
|
-
this.#send();
|
|
28385
|
-
} else if (event2.event === "size") {
|
|
28386
|
-
element2.style.width = `${event2.width}px`;
|
|
28387
|
-
element2.style.height = `${event2.height}px`;
|
|
28388
|
-
element2.style.margin = `${-event2.inset}px`;
|
|
28389
|
-
} else if (event2.event === "label") {
|
|
28390
|
-
element2.title = event2.label;
|
|
28391
|
-
} else if (event2.event === "focus") {
|
|
28392
|
-
const order = sequential(tabbables(this.ownerDocument, this));
|
|
28393
|
-
const at = order.indexOf(null);
|
|
28394
|
-
order[event2.direction === "next" ? at + 1 : at - 1]?.focus();
|
|
28395
|
-
} else if (event2.event === "popup") {
|
|
28396
|
-
const { intent, state: state3, result } = event2;
|
|
28397
|
-
this.dispatchEvent(
|
|
28398
|
-
new CustomEvent("vault-popup", {
|
|
28399
|
-
detail: { intent, state: state3, ...result ? { result } : {} },
|
|
28400
|
-
bubbles: true,
|
|
28401
|
-
composed: true
|
|
28402
|
-
})
|
|
28403
|
-
);
|
|
28404
|
-
}
|
|
28405
|
-
}
|
|
28406
|
-
};
|
|
28407
|
-
|
|
28408
28688
|
// src/app/secrets.ts
|
|
28409
28689
|
var kinds = { secret: null, grant: "Sign-in", model: "Model key", mcp: "MCP server" };
|
|
28410
28690
|
var lockModes = {
|
|
@@ -28423,12 +28703,27 @@ function until(at, now = Date.now()) {
|
|
|
28423
28703
|
}
|
|
28424
28704
|
function who(entry) {
|
|
28425
28705
|
if (entry.tag) return entry.tag;
|
|
28426
|
-
if (entry.uid === null) return "
|
|
28706
|
+
if (entry.uid === null) return "you";
|
|
28427
28707
|
return entry.uid === 0 ? "root" : `uid ${entry.uid}`;
|
|
28428
28708
|
}
|
|
28709
|
+
function asker(request2) {
|
|
28710
|
+
if (request2.tag) return request2.tag;
|
|
28711
|
+
return request2.uid === 0 ? "A program running as root" : `A program running as uid ${request2.uid}`;
|
|
28712
|
+
}
|
|
28713
|
+
function asking2(request2) {
|
|
28714
|
+
const by = asker(request2);
|
|
28715
|
+
if (request2.kind === "oauth") return b`${by} asks you to sign in to ${request2.provider}`;
|
|
28716
|
+
if (request2.kind === "jerk-seal")
|
|
28717
|
+
return b`${by} asks for a jerk lease for ${request2.provider}`;
|
|
28718
|
+
return request2.name ? b`${by} asks for <code>${request2.name}</code>` : b`${by} asks for a value`;
|
|
28719
|
+
}
|
|
28720
|
+
function byName(a22, b13) {
|
|
28721
|
+
return a22.name < b13.name ? -1 : a22.name > b13.name ? 1 : 0;
|
|
28722
|
+
}
|
|
28429
28723
|
function sourceLine(secret, devices) {
|
|
28430
28724
|
const on = secret.sourceDevice ? ` on ${deviceName2(secret.sourceDevice, devices)}` : "";
|
|
28431
28725
|
const [kind, detail = ""] = secret.source.split(/:(.*)/s);
|
|
28726
|
+
if (kind === "settings") return `Entered in SLICC${on}`;
|
|
28432
28727
|
if (kind === "popup") return `Entered in the vault${on}`;
|
|
28433
28728
|
if (kind === "process") return `Saved by a program${on}`;
|
|
28434
28729
|
if (kind === "import") return `Imported from ${detail}`;
|
|
@@ -28455,11 +28750,16 @@ function revealed(name, entries, now = Date.now(), more = false) {
|
|
|
28455
28750
|
const when = today ? `${partial ? "at least " : ""}${today} ${today === 1 ? "time" : "times"} today` : since(last.at, now);
|
|
28456
28751
|
return b`Revealed to programs ${when}, last by ${who(last)} with <code>${last.argv}</code>`;
|
|
28457
28752
|
}
|
|
28753
|
+
function changes(entry, devices) {
|
|
28754
|
+
if (entry.changes)
|
|
28755
|
+
return entry.changes.map((change) => [change.kind, changeLine(change, devices)]);
|
|
28756
|
+
return (entry.widened ?? []).map((change) => [change.kind, widening(change, devices)]);
|
|
28757
|
+
}
|
|
28458
28758
|
function auditLine(entry, devices) {
|
|
28459
28759
|
switch (entry.type) {
|
|
28460
28760
|
case "inject":
|
|
28461
28761
|
case "forward":
|
|
28462
|
-
return b
|
|
28762
|
+
return b`Sent to ${entry.domain}: <code>${entry.method} ${entry.path}</code>, through ${exitLabel(entry.exit, devices)}`;
|
|
28463
28763
|
case "materialize":
|
|
28464
28764
|
return b`Revealed to <code>${entry.argv}</code> in <code>${entry.cwd}</code>`;
|
|
28465
28765
|
case "seal":
|
|
@@ -28468,11 +28768,10 @@ function auditLine(entry, devices) {
|
|
|
28468
28768
|
return b`Removed`;
|
|
28469
28769
|
case "restore":
|
|
28470
28770
|
return b`Restored`;
|
|
28471
|
-
|
|
28472
|
-
|
|
28473
|
-
|
|
28474
|
-
return b`<code>${entry.file}</code> ${entry.accepted ?
|
|
28475
|
-
}
|
|
28771
|
+
case "refresh":
|
|
28772
|
+
return entry.grant ? b`Refreshed automatically with the sign-in <code>${entry.grant}</code>` : b`Refreshed automatically`;
|
|
28773
|
+
default:
|
|
28774
|
+
return b`<code>${entry.file}</code> ${entry.accepted ? "changed" : "changed and was refused"}${changes(entry, devices).map(([kind, line]) => b`<span class="change" data-change=${kind}>${line}</span>`)}${entry.warning ? b`<span class="warning" data-warning>${entry.warning}</span>` : A}${entry.accepted ? b`<span class="hint" data-hint>If you didn’t mean this, change the file back with sudo.</span>` : A}`;
|
|
28476
28775
|
}
|
|
28477
28776
|
}
|
|
28478
28777
|
function merged(...pages) {
|
|
@@ -28480,6 +28779,37 @@ function merged(...pages) {
|
|
|
28480
28779
|
for (const page of pages) for (const entry of page) bySeq.set(entry.seq, entry);
|
|
28481
28780
|
return [...bySeq.values()].sort((a22, b13) => b13.seq - a22.seq);
|
|
28482
28781
|
}
|
|
28782
|
+
function replaceable(secret) {
|
|
28783
|
+
return secret.state !== "removed" && secret.kind !== "grant" && (secret.source === "settings" || secret.source === "process" || secret.source.startsWith("import:"));
|
|
28784
|
+
}
|
|
28785
|
+
function filename(now = Date.now()) {
|
|
28786
|
+
const date = new Date(now);
|
|
28787
|
+
const day2 = [date.getFullYear(), date.getMonth() + 1, date.getDate()].map((part2) => String(part2).padStart(2, "0")).join("-");
|
|
28788
|
+
return `slicc-secrets-${day2}.slicc-vault`;
|
|
28789
|
+
}
|
|
28790
|
+
function download(bytes, name, root2) {
|
|
28791
|
+
const url = URL.createObjectURL(
|
|
28792
|
+
new Blob([bytes], { type: "application/octet-stream" })
|
|
28793
|
+
);
|
|
28794
|
+
const link = document.createElement("a");
|
|
28795
|
+
link.href = url;
|
|
28796
|
+
link.download = name;
|
|
28797
|
+
link.hidden = true;
|
|
28798
|
+
root2.append(link);
|
|
28799
|
+
link.click();
|
|
28800
|
+
link.remove();
|
|
28801
|
+
URL.revokeObjectURL(url);
|
|
28802
|
+
}
|
|
28803
|
+
var importKinds = {
|
|
28804
|
+
bundle: "Bundle",
|
|
28805
|
+
keepass: "KeePass (.kdbx)",
|
|
28806
|
+
six: "six"
|
|
28807
|
+
};
|
|
28808
|
+
function exported(at) {
|
|
28809
|
+
if (at === void 0) return A;
|
|
28810
|
+
const when = at === null ? "Never exported" : `Last exported ${new Intl.DateTimeFormat(void 0, { dateStyle: "medium" }).format(at)}`;
|
|
28811
|
+
return b`<span class="muted" data-exported>${when}</span>`;
|
|
28812
|
+
}
|
|
28483
28813
|
function prompt2(text2) {
|
|
28484
28814
|
return text2.length > 200 ? `${text2.slice(0, 199)}\u2026` : text2;
|
|
28485
28815
|
}
|
|
@@ -28491,10 +28821,20 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28491
28821
|
loading: { state: true },
|
|
28492
28822
|
reveals: { state: true },
|
|
28493
28823
|
popup: { state: true },
|
|
28494
|
-
|
|
28495
|
-
|
|
28824
|
+
failure: { state: true },
|
|
28825
|
+
form: { state: true },
|
|
28826
|
+
busy: { state: true },
|
|
28827
|
+
problem: { state: true },
|
|
28828
|
+
invalid: { state: true },
|
|
28829
|
+
said: { state: true },
|
|
28830
|
+
acting: { state: true },
|
|
28831
|
+
importKind: { state: true },
|
|
28832
|
+
candidates: { state: true },
|
|
28833
|
+
picked: { state: true },
|
|
28834
|
+
again: { state: true }
|
|
28496
28835
|
};
|
|
28497
28836
|
#tick;
|
|
28837
|
+
#offline = false;
|
|
28498
28838
|
constructor() {
|
|
28499
28839
|
super();
|
|
28500
28840
|
this.older = [];
|
|
@@ -28502,252 +28842,353 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28502
28842
|
this.loading = false;
|
|
28503
28843
|
this.reveals = false;
|
|
28504
28844
|
this.popup = null;
|
|
28505
|
-
this.acking = /* @__PURE__ */ new Set();
|
|
28506
28845
|
this.failure = null;
|
|
28846
|
+
this.form = null;
|
|
28847
|
+
this.busy = false;
|
|
28848
|
+
this.problem = null;
|
|
28849
|
+
this.invalid = null;
|
|
28850
|
+
this.said = null;
|
|
28851
|
+
this.acting = /* @__PURE__ */ new Set();
|
|
28852
|
+
this.importKind = "bundle";
|
|
28853
|
+
this.candidates = null;
|
|
28854
|
+
this.picked = /* @__PURE__ */ new Set();
|
|
28855
|
+
this.again = false;
|
|
28507
28856
|
}
|
|
28508
|
-
static styles =
|
|
28509
|
-
|
|
28510
|
-
|
|
28511
|
-
|
|
28512
|
-
|
|
28513
|
-
|
|
28514
|
-
|
|
28515
|
-
|
|
28516
|
-
|
|
28517
|
-
|
|
28518
|
-
|
|
28519
|
-
|
|
28520
|
-
|
|
28521
|
-
|
|
28522
|
-
|
|
28523
|
-
|
|
28524
|
-
|
|
28525
|
-
|
|
28526
|
-
|
|
28527
|
-
|
|
28528
|
-
|
|
28529
|
-
|
|
28530
|
-
|
|
28531
|
-
|
|
28532
|
-
|
|
28533
|
-
|
|
28534
|
-
|
|
28535
|
-
|
|
28536
|
-
|
|
28537
|
-
|
|
28538
|
-
|
|
28539
|
-
|
|
28540
|
-
|
|
28541
|
-
|
|
28542
|
-
|
|
28543
|
-
|
|
28544
|
-
|
|
28545
|
-
|
|
28546
|
-
|
|
28547
|
-
|
|
28548
|
-
|
|
28549
|
-
|
|
28550
|
-
|
|
28551
|
-
|
|
28552
|
-
|
|
28553
|
-
|
|
28554
|
-
|
|
28555
|
-
|
|
28556
|
-
|
|
28557
|
-
|
|
28558
|
-
|
|
28559
|
-
|
|
28560
|
-
|
|
28561
|
-
|
|
28562
|
-
|
|
28563
|
-
|
|
28564
|
-
|
|
28565
|
-
|
|
28566
|
-
|
|
28567
|
-
|
|
28568
|
-
|
|
28569
|
-
|
|
28570
|
-
|
|
28571
|
-
|
|
28572
|
-
|
|
28573
|
-
|
|
28574
|
-
|
|
28575
|
-
|
|
28576
|
-
|
|
28577
|
-
|
|
28578
|
-
|
|
28579
|
-
|
|
28580
|
-
|
|
28581
|
-
|
|
28582
|
-
|
|
28583
|
-
|
|
28584
|
-
|
|
28585
|
-
|
|
28586
|
-
|
|
28587
|
-
|
|
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
|
-
.audit-head {
|
|
28657
|
-
display: flex;
|
|
28658
|
-
flex-wrap: wrap;
|
|
28659
|
-
align-items: baseline;
|
|
28660
|
-
justify-content: space-between;
|
|
28661
|
-
gap: var(--swc-spacing-200);
|
|
28662
|
-
margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
|
|
28663
|
-
}
|
|
28664
|
-
.audit-head h3 {
|
|
28665
|
-
margin-block: 0;
|
|
28666
|
-
}
|
|
28667
|
-
.audit li {
|
|
28668
|
-
display: grid;
|
|
28669
|
-
grid-template-columns: 7em minmax(0, 1fr);
|
|
28670
|
-
gap: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
28671
|
-
padding: var(--swc-spacing-100) 0;
|
|
28672
|
-
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28673
|
-
font-size: var(--swc-font-size-75);
|
|
28674
|
-
line-height: var(--swc-line-height-200);
|
|
28675
|
-
}
|
|
28676
|
-
.audit time {
|
|
28677
|
-
color: var(--swc-neutral-subdued-content-color-default);
|
|
28678
|
-
}
|
|
28679
|
-
.audit .what {
|
|
28680
|
-
overflow-wrap: anywhere;
|
|
28681
|
-
}
|
|
28682
|
-
.audit .by {
|
|
28683
|
-
color: var(--swc-neutral-subdued-content-color-default);
|
|
28684
|
-
}
|
|
28685
|
-
.row {
|
|
28686
|
-
display: flex;
|
|
28687
|
-
flex-wrap: wrap;
|
|
28688
|
-
align-items: center;
|
|
28689
|
-
gap: var(--swc-spacing-200);
|
|
28690
|
-
margin-top: var(--swc-spacing-200);
|
|
28691
|
-
}
|
|
28692
|
-
.error {
|
|
28693
|
-
display: flex;
|
|
28694
|
-
align-items: flex-start;
|
|
28695
|
-
gap: var(--swc-spacing-100);
|
|
28696
|
-
color: var(--swc-negative-content-color-default);
|
|
28697
|
-
font-size: var(--swc-font-size-75);
|
|
28698
|
-
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
28699
|
-
}
|
|
28700
|
-
@container (max-width: 480px) {
|
|
28857
|
+
static styles = [
|
|
28858
|
+
fieldStyles,
|
|
28859
|
+
i`
|
|
28860
|
+
:host {
|
|
28861
|
+
display: block;
|
|
28862
|
+
container-type: inline-size;
|
|
28863
|
+
}
|
|
28864
|
+
h2 {
|
|
28865
|
+
font-size: var(--swc-heading-size-xs);
|
|
28866
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28867
|
+
line-height: var(--swc-heading-line-height);
|
|
28868
|
+
color: var(--swc-heading-color);
|
|
28869
|
+
margin: 0;
|
|
28870
|
+
}
|
|
28871
|
+
h3 {
|
|
28872
|
+
font-size: var(--swc-font-size-100);
|
|
28873
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28874
|
+
color: var(--swc-heading-color);
|
|
28875
|
+
margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
|
|
28876
|
+
}
|
|
28877
|
+
p {
|
|
28878
|
+
margin: var(--swc-spacing-100) 0;
|
|
28879
|
+
}
|
|
28880
|
+
ul,
|
|
28881
|
+
ol {
|
|
28882
|
+
list-style: none;
|
|
28883
|
+
margin: 0;
|
|
28884
|
+
padding: 0;
|
|
28885
|
+
}
|
|
28886
|
+
code {
|
|
28887
|
+
font-family: var(--swc-code-font-family, ui-monospace, monospace);
|
|
28888
|
+
font-size: 0.9em;
|
|
28889
|
+
overflow-wrap: anywhere;
|
|
28890
|
+
}
|
|
28891
|
+
.head {
|
|
28892
|
+
display: flex;
|
|
28893
|
+
flex-wrap: wrap;
|
|
28894
|
+
align-items: baseline;
|
|
28895
|
+
gap: var(--swc-spacing-200) var(--swc-spacing-300);
|
|
28896
|
+
margin: var(--swc-spacing-500) 0 var(--swc-spacing-200);
|
|
28897
|
+
}
|
|
28898
|
+
.head .controls {
|
|
28899
|
+
display: flex;
|
|
28900
|
+
flex-wrap: wrap;
|
|
28901
|
+
align-items: center;
|
|
28902
|
+
gap: var(--swc-spacing-200);
|
|
28903
|
+
align-self: center;
|
|
28904
|
+
margin-inline-start: auto;
|
|
28905
|
+
}
|
|
28906
|
+
.muted {
|
|
28907
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28908
|
+
}
|
|
28909
|
+
.box {
|
|
28910
|
+
display: grid;
|
|
28911
|
+
gap: var(--swc-spacing-100);
|
|
28912
|
+
padding: var(--swc-spacing-200) var(--swc-spacing-300);
|
|
28913
|
+
margin: var(--swc-spacing-200) 0;
|
|
28914
|
+
border-radius: var(--swc-corner-radius-100);
|
|
28915
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28916
|
+
background: var(--swc-background-layer-1-color);
|
|
28917
|
+
}
|
|
28918
|
+
.box.info {
|
|
28919
|
+
border-color: var(--swc-informative-visual-color);
|
|
28920
|
+
--swc-icon-color: var(--swc-informative-visual-color);
|
|
28921
|
+
}
|
|
28922
|
+
.availability {
|
|
28923
|
+
display: flex;
|
|
28924
|
+
align-items: center;
|
|
28925
|
+
gap: var(--swc-spacing-100);
|
|
28926
|
+
}
|
|
28927
|
+
.box .title {
|
|
28928
|
+
display: flex;
|
|
28929
|
+
align-items: flex-start;
|
|
28930
|
+
gap: var(--swc-spacing-100);
|
|
28931
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28932
|
+
}
|
|
28933
|
+
.box .actions,
|
|
28934
|
+
.buttons {
|
|
28935
|
+
display: flex;
|
|
28936
|
+
flex-wrap: wrap;
|
|
28937
|
+
align-items: center;
|
|
28938
|
+
gap: var(--swc-spacing-200);
|
|
28939
|
+
}
|
|
28940
|
+
.prompt {
|
|
28941
|
+
margin: 0;
|
|
28942
|
+
padding-inline-start: var(--swc-spacing-200);
|
|
28943
|
+
border-inline-start: var(--swc-border-width-200) solid var(--swc-gray-300);
|
|
28944
|
+
overflow-wrap: anywhere;
|
|
28945
|
+
}
|
|
28946
|
+
.said {
|
|
28947
|
+
white-space: pre-wrap;
|
|
28948
|
+
}
|
|
28949
|
+
.from {
|
|
28950
|
+
display: block;
|
|
28951
|
+
font-size: var(--swc-font-size-75);
|
|
28952
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28953
|
+
}
|
|
28954
|
+
.form {
|
|
28955
|
+
display: grid;
|
|
28956
|
+
gap: var(--swc-spacing-200);
|
|
28957
|
+
max-inline-size: 32rem;
|
|
28958
|
+
padding: var(--swc-spacing-300);
|
|
28959
|
+
margin: var(--swc-spacing-200) 0;
|
|
28960
|
+
border-radius: var(--swc-corner-radius-100);
|
|
28961
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-300);
|
|
28962
|
+
background: var(--swc-background-layer-1-color);
|
|
28963
|
+
}
|
|
28964
|
+
.form strong {
|
|
28965
|
+
font-weight: var(--swc-bold-font-weight);
|
|
28966
|
+
}
|
|
28967
|
+
.form sp-picker {
|
|
28968
|
+
inline-size: 100%;
|
|
28969
|
+
}
|
|
28970
|
+
.picks {
|
|
28971
|
+
display: grid;
|
|
28972
|
+
gap: var(--swc-spacing-100);
|
|
28973
|
+
margin: 0;
|
|
28974
|
+
padding: var(--swc-spacing-200) var(--swc-spacing-300);
|
|
28975
|
+
border: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28976
|
+
border-radius: var(--swc-corner-radius-100);
|
|
28977
|
+
}
|
|
28978
|
+
.picks legend {
|
|
28979
|
+
padding: 0 var(--swc-spacing-75);
|
|
28980
|
+
font-size: var(--swc-font-size-75);
|
|
28981
|
+
}
|
|
28982
|
+
.picks label {
|
|
28983
|
+
display: grid;
|
|
28984
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
28985
|
+
align-items: start;
|
|
28986
|
+
gap: var(--swc-spacing-50) var(--swc-spacing-100);
|
|
28987
|
+
}
|
|
28988
|
+
.picks input {
|
|
28989
|
+
margin: 0.2em 0 0;
|
|
28990
|
+
accent-color: var(--swc-accent-background-color-default);
|
|
28991
|
+
}
|
|
28992
|
+
.picks .about {
|
|
28993
|
+
display: grid;
|
|
28994
|
+
gap: var(--swc-spacing-50);
|
|
28995
|
+
min-width: 0;
|
|
28996
|
+
}
|
|
28997
|
+
.picks .suggested {
|
|
28998
|
+
font-size: var(--swc-font-size-75);
|
|
28999
|
+
overflow-wrap: anywhere;
|
|
29000
|
+
}
|
|
29001
|
+
.secrets {
|
|
29002
|
+
display: grid;
|
|
29003
|
+
gap: var(--swc-spacing-200);
|
|
29004
|
+
}
|
|
28701
29005
|
.secret {
|
|
28702
|
-
|
|
29006
|
+
display: grid;
|
|
29007
|
+
grid-template-columns: minmax(0, 1fr) max-content;
|
|
29008
|
+
gap: var(--swc-spacing-100) var(--swc-spacing-300);
|
|
29009
|
+
padding: var(--swc-spacing-200) 0;
|
|
29010
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
28703
29011
|
}
|
|
28704
|
-
.secret
|
|
28705
|
-
|
|
28706
|
-
|
|
29012
|
+
.secret:first-child {
|
|
29013
|
+
border-top: 0;
|
|
29014
|
+
}
|
|
29015
|
+
.secret .form {
|
|
29016
|
+
grid-column: 1 / -1;
|
|
29017
|
+
}
|
|
29018
|
+
.secret .buttons {
|
|
29019
|
+
align-self: start;
|
|
29020
|
+
justify-content: flex-end;
|
|
29021
|
+
}
|
|
29022
|
+
.name {
|
|
29023
|
+
display: flex;
|
|
29024
|
+
flex-wrap: wrap;
|
|
29025
|
+
align-items: baseline;
|
|
29026
|
+
gap: var(--swc-spacing-100) var(--swc-spacing-200);
|
|
29027
|
+
min-width: 0;
|
|
29028
|
+
}
|
|
29029
|
+
.name code {
|
|
29030
|
+
font-size: var(--swc-font-size-100);
|
|
29031
|
+
font-weight: var(--swc-bold-font-weight);
|
|
29032
|
+
}
|
|
29033
|
+
.removed {
|
|
29034
|
+
margin-top: var(--swc-spacing-200);
|
|
29035
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
29036
|
+
padding-top: var(--swc-spacing-200);
|
|
29037
|
+
}
|
|
29038
|
+
.removed summary {
|
|
29039
|
+
cursor: pointer;
|
|
29040
|
+
font-size: var(--swc-font-size-75);
|
|
29041
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
29042
|
+
}
|
|
29043
|
+
.removed .secret dl,
|
|
29044
|
+
.removed .secret .name code {
|
|
29045
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28707
29046
|
}
|
|
28708
29047
|
dl {
|
|
28709
|
-
grid-
|
|
29048
|
+
grid-column: 1 / -1;
|
|
29049
|
+
display: grid;
|
|
29050
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
29051
|
+
gap: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
29052
|
+
margin: 0;
|
|
29053
|
+
font-size: var(--swc-font-size-75);
|
|
29054
|
+
line-height: var(--swc-line-height-200);
|
|
29055
|
+
}
|
|
29056
|
+
dt {
|
|
29057
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
28710
29058
|
}
|
|
28711
29059
|
dd {
|
|
28712
|
-
margin
|
|
29060
|
+
margin: 0;
|
|
29061
|
+
min-width: 0;
|
|
29062
|
+
overflow-wrap: anywhere;
|
|
29063
|
+
}
|
|
29064
|
+
.refused li {
|
|
29065
|
+
display: grid;
|
|
29066
|
+
gap: var(--swc-spacing-50);
|
|
29067
|
+
padding: var(--swc-spacing-100) 0;
|
|
29068
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
29069
|
+
font-size: var(--swc-font-size-75);
|
|
29070
|
+
overflow-wrap: anywhere;
|
|
29071
|
+
}
|
|
29072
|
+
.audit-head {
|
|
29073
|
+
display: flex;
|
|
29074
|
+
flex-wrap: wrap;
|
|
29075
|
+
align-items: baseline;
|
|
29076
|
+
justify-content: space-between;
|
|
29077
|
+
gap: var(--swc-spacing-200);
|
|
29078
|
+
margin: var(--swc-spacing-400) 0 var(--swc-spacing-100);
|
|
29079
|
+
}
|
|
29080
|
+
.audit-head h3 {
|
|
29081
|
+
margin-block: 0;
|
|
28713
29082
|
}
|
|
28714
29083
|
.audit li {
|
|
28715
|
-
|
|
29084
|
+
display: grid;
|
|
29085
|
+
grid-template-columns: 7em minmax(0, 1fr);
|
|
29086
|
+
gap: var(--swc-spacing-50) var(--swc-spacing-300);
|
|
29087
|
+
padding: var(--swc-spacing-100) 0;
|
|
29088
|
+
border-top: var(--swc-border-width-100) solid var(--swc-gray-200);
|
|
29089
|
+
font-size: var(--swc-font-size-75);
|
|
29090
|
+
line-height: var(--swc-line-height-200);
|
|
28716
29091
|
}
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
29092
|
+
.audit time {
|
|
29093
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
29094
|
+
}
|
|
29095
|
+
.audit .what {
|
|
29096
|
+
overflow-wrap: anywhere;
|
|
29097
|
+
}
|
|
29098
|
+
.audit .by,
|
|
29099
|
+
.audit .hint {
|
|
29100
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
29101
|
+
}
|
|
29102
|
+
.audit .change::before {
|
|
29103
|
+
content: '• ' / '';
|
|
29104
|
+
}
|
|
29105
|
+
.audit .change,
|
|
29106
|
+
.audit .warning,
|
|
29107
|
+
.audit .hint {
|
|
29108
|
+
display: block;
|
|
29109
|
+
}
|
|
29110
|
+
.row {
|
|
29111
|
+
display: flex;
|
|
29112
|
+
flex-wrap: wrap;
|
|
29113
|
+
align-items: center;
|
|
29114
|
+
gap: var(--swc-spacing-200);
|
|
29115
|
+
margin-top: var(--swc-spacing-200);
|
|
29116
|
+
}
|
|
29117
|
+
.error {
|
|
29118
|
+
display: flex;
|
|
29119
|
+
align-items: flex-start;
|
|
29120
|
+
gap: var(--swc-spacing-100);
|
|
29121
|
+
margin: 0;
|
|
29122
|
+
color: var(--swc-negative-content-color-default);
|
|
29123
|
+
font-size: var(--swc-font-size-75);
|
|
29124
|
+
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
29125
|
+
}
|
|
29126
|
+
@container (max-width: 480px) {
|
|
29127
|
+
.secret {
|
|
29128
|
+
grid-template-columns: minmax(0, 1fr);
|
|
29129
|
+
}
|
|
29130
|
+
.secret .buttons {
|
|
29131
|
+
order: 1;
|
|
29132
|
+
justify-content: flex-start;
|
|
29133
|
+
}
|
|
29134
|
+
.secret .form {
|
|
29135
|
+
order: 2;
|
|
29136
|
+
}
|
|
29137
|
+
.form {
|
|
29138
|
+
max-inline-size: none;
|
|
29139
|
+
}
|
|
29140
|
+
dl {
|
|
29141
|
+
grid-template-columns: minmax(0, 1fr);
|
|
29142
|
+
}
|
|
29143
|
+
dd {
|
|
29144
|
+
margin-bottom: var(--swc-spacing-75);
|
|
29145
|
+
}
|
|
29146
|
+
.audit li {
|
|
29147
|
+
grid-template-columns: minmax(0, 1fr);
|
|
29148
|
+
}
|
|
29149
|
+
}
|
|
29150
|
+
`
|
|
29151
|
+
];
|
|
28720
29152
|
disconnectedCallback() {
|
|
28721
29153
|
super.disconnectedCallback();
|
|
28722
29154
|
clearTimeout(this.#tick);
|
|
29155
|
+
clearValues(this.renderRoot);
|
|
28723
29156
|
this.older = [];
|
|
28724
29157
|
this.more = null;
|
|
28725
|
-
this.#pushed = [];
|
|
28726
29158
|
}
|
|
28727
29159
|
willUpdate(changed) {
|
|
28728
29160
|
super.willUpdate(changed);
|
|
28729
29161
|
const before = changed.get("model");
|
|
28730
29162
|
if (!changed.has("model") || before?.vault === this.model?.vault) return;
|
|
29163
|
+
clearValues(this.renderRoot);
|
|
28731
29164
|
this.older = [];
|
|
28732
29165
|
this.more = null;
|
|
28733
29166
|
this.loading = false;
|
|
28734
29167
|
this.popup = null;
|
|
28735
|
-
this.acking = /* @__PURE__ */ new Set();
|
|
28736
29168
|
this.failure = null;
|
|
28737
|
-
this
|
|
29169
|
+
this.form = null;
|
|
29170
|
+
this.busy = false;
|
|
29171
|
+
this.problem = null;
|
|
29172
|
+
this.invalid = null;
|
|
29173
|
+
this.said = null;
|
|
29174
|
+
this.acting = /* @__PURE__ */ new Set();
|
|
29175
|
+
this.candidates = null;
|
|
28738
29176
|
}
|
|
28739
29177
|
updated() {
|
|
28740
29178
|
clearTimeout(this.#tick);
|
|
28741
29179
|
if (!this.isConnected) return;
|
|
28742
29180
|
const now = Date.now();
|
|
29181
|
+
const vault = this.model?.vault;
|
|
28743
29182
|
const next = Math.min(
|
|
28744
29183
|
now + 6e4,
|
|
28745
|
-
...
|
|
29184
|
+
...[
|
|
29185
|
+
...(vault?.list()?.secrets ?? []).map((secret) => secret.expiresAt),
|
|
29186
|
+
...(vault?.status()?.waiting ?? []).map((request2) => request2.expiresAt)
|
|
29187
|
+
].map((at) => at ?? Number.POSITIVE_INFINITY).filter((at) => at > now)
|
|
28746
29188
|
);
|
|
28747
29189
|
this.#tick = setTimeout(() => this.requestUpdate(), next - now);
|
|
28748
29190
|
}
|
|
28749
29191
|
#listed(vault) {
|
|
28750
|
-
this.#pushed = [];
|
|
28751
29192
|
const head2 = vault.list()?.audit ?? [];
|
|
28752
29193
|
const last = head2[head2.length - 1];
|
|
28753
29194
|
if (this.older.length && (!last || last.seq > this.older[0].seq + 1)) {
|
|
@@ -28756,25 +29197,22 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28756
29197
|
}
|
|
28757
29198
|
this.requestUpdate();
|
|
28758
29199
|
}
|
|
28759
|
-
#noticed(notice) {
|
|
28760
|
-
this.#pushed = [...this.#pushed.filter((item2) => item2.id !== notice.id), notice];
|
|
28761
|
-
this.requestUpdate();
|
|
28762
|
-
}
|
|
28763
29200
|
subscribe(model) {
|
|
28764
29201
|
const update = () => this.requestUpdate();
|
|
28765
29202
|
return [
|
|
28766
29203
|
...super.subscribe(model),
|
|
28767
29204
|
...model.vault ? [
|
|
28768
29205
|
model.vault.on("status", update),
|
|
28769
|
-
model.vault.on("
|
|
28770
|
-
model.vault.on("
|
|
29206
|
+
model.vault.on("availability", update),
|
|
29207
|
+
model.vault.on("list", () => this.#listed(model.vault))
|
|
28771
29208
|
] : [],
|
|
28772
29209
|
...model.network ? [model.network.on("network", update)] : []
|
|
28773
29210
|
];
|
|
28774
29211
|
}
|
|
28775
|
-
#button(config) {
|
|
29212
|
+
#button(config, action) {
|
|
28776
29213
|
const theme3 = this.color;
|
|
28777
29214
|
return b`<slicc-vault-button
|
|
29215
|
+
data-action=${action}
|
|
28778
29216
|
.vault=${this.model?.vault}
|
|
28779
29217
|
.config=${{ size: "m", variant: "secondary", ...config, theme: theme3 }}
|
|
28780
29218
|
@vault-popup=${(event2) => this.#popup(event2.detail)}
|
|
@@ -28783,6 +29221,238 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28783
29221
|
#popup(detail) {
|
|
28784
29222
|
this.popup = detail;
|
|
28785
29223
|
}
|
|
29224
|
+
open(form) {
|
|
29225
|
+
if (form && this.busy) return;
|
|
29226
|
+
clearValues(this.renderRoot);
|
|
29227
|
+
this.form = form;
|
|
29228
|
+
this.problem = null;
|
|
29229
|
+
this.invalid = null;
|
|
29230
|
+
this.said = null;
|
|
29231
|
+
this.candidates = null;
|
|
29232
|
+
this.again = false;
|
|
29233
|
+
if (form?.kind === "import") this.importKind = "bundle";
|
|
29234
|
+
if (form) void this.updateComplete.then(() => this.#focus());
|
|
29235
|
+
}
|
|
29236
|
+
#refuse(text2, field = null, focus = false) {
|
|
29237
|
+
this.problem = text2;
|
|
29238
|
+
this.invalid = text2 ? field : null;
|
|
29239
|
+
if (focus && text2 && field) void this.updateComplete.then(() => this.#field(field)?.focus());
|
|
29240
|
+
}
|
|
29241
|
+
#typed() {
|
|
29242
|
+
this.invalid = null;
|
|
29243
|
+
}
|
|
29244
|
+
#bad(field) {
|
|
29245
|
+
return this.invalid === field ? "true" : A;
|
|
29246
|
+
}
|
|
29247
|
+
#described(field) {
|
|
29248
|
+
return this.invalid === field ? "error-form" : A;
|
|
29249
|
+
}
|
|
29250
|
+
#focus() {
|
|
29251
|
+
this.renderRoot.querySelector("[data-form] input, [data-form] sp-picker")?.focus();
|
|
29252
|
+
}
|
|
29253
|
+
#field(name) {
|
|
29254
|
+
return this.renderRoot.querySelector(
|
|
29255
|
+
`[data-form] input[data-field=${name}]`
|
|
29256
|
+
);
|
|
29257
|
+
}
|
|
29258
|
+
#same(vault, form, kind, file) {
|
|
29259
|
+
return this.#mine(vault, form) && this.importKind === kind && this.#field("file")?.files?.[0] === file;
|
|
29260
|
+
}
|
|
29261
|
+
#shut(vault) {
|
|
29262
|
+
if (!vault.status()?.locked) return false;
|
|
29263
|
+
this.#refuse("Unlock the vault first");
|
|
29264
|
+
return true;
|
|
29265
|
+
}
|
|
29266
|
+
#mine(vault, form) {
|
|
29267
|
+
return this.model?.vault === vault && this.isConnected && !away(vault) && (form === void 0 || this.form === form);
|
|
29268
|
+
}
|
|
29269
|
+
async save(vault) {
|
|
29270
|
+
const form = this.form;
|
|
29271
|
+
if (this.busy) return;
|
|
29272
|
+
const name = form.kind === "replace" ? form.name : this.#field("name").value.trim();
|
|
29273
|
+
const bad = nameProblem(name);
|
|
29274
|
+
if (bad) {
|
|
29275
|
+
this.#refuse(bad, "name", true);
|
|
29276
|
+
return;
|
|
29277
|
+
}
|
|
29278
|
+
const value = take(this.#field("value"));
|
|
29279
|
+
const problem = valueProblem(value);
|
|
29280
|
+
this.#refuse(problem, "value", true);
|
|
29281
|
+
if (problem) return;
|
|
29282
|
+
if (form.kind === "add" && vault.list()?.secrets.some((secret) => secret.name === name)) {
|
|
29283
|
+
this.busy = true;
|
|
29284
|
+
const sure = await confirm({
|
|
29285
|
+
title: `Replace ${name}?`,
|
|
29286
|
+
body: "A secret with this name exists. Saving replaces its value, and its placeholder stays.",
|
|
29287
|
+
action: "Replace",
|
|
29288
|
+
variant: "confirmation"
|
|
29289
|
+
});
|
|
29290
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29291
|
+
if (!sure || !this.#mine(vault, form) || this.#shut(vault)) return;
|
|
29292
|
+
}
|
|
29293
|
+
this.busy = true;
|
|
29294
|
+
try {
|
|
29295
|
+
await vault.put?.(name, value);
|
|
29296
|
+
if (!this.#mine(vault, form)) return;
|
|
29297
|
+
this.form = null;
|
|
29298
|
+
this.said = { kind: "saved", name };
|
|
29299
|
+
} catch (error) {
|
|
29300
|
+
if (this.#mine(vault, form)) this.#refuse(failureText(error), fieldOf(error, "value"));
|
|
29301
|
+
} finally {
|
|
29302
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29303
|
+
}
|
|
29304
|
+
}
|
|
29305
|
+
async #act(vault, key2, run2, missing = "") {
|
|
29306
|
+
if (this.acting.has(key2)) return;
|
|
29307
|
+
this.acting = /* @__PURE__ */ new Set([...this.acting, key2]);
|
|
29308
|
+
this.failure = null;
|
|
29309
|
+
try {
|
|
29310
|
+
await run2();
|
|
29311
|
+
} catch (error) {
|
|
29312
|
+
if (this.#mine(vault))
|
|
29313
|
+
this.failure = missing && isVaultFailure(error) && error.code === "ENOENT" ? missing : failureText(error);
|
|
29314
|
+
} finally {
|
|
29315
|
+
if (this.model?.vault === vault)
|
|
29316
|
+
this.acting = new Set([...this.acting].filter((item2) => item2 !== key2));
|
|
29317
|
+
}
|
|
29318
|
+
}
|
|
29319
|
+
async removeSecret(vault, secret, trigger2 = null) {
|
|
29320
|
+
const { name, kind } = secret;
|
|
29321
|
+
const sure = await confirm({
|
|
29322
|
+
title: `Remove ${name}?`,
|
|
29323
|
+
body: "Agents and programs can no longer use it. You can restore it from Removed.",
|
|
29324
|
+
action: "Remove",
|
|
29325
|
+
variant: "confirmation",
|
|
29326
|
+
trigger: trigger2
|
|
29327
|
+
});
|
|
29328
|
+
if (!sure || !this.#mine(vault)) return;
|
|
29329
|
+
if (this.form?.kind === "replace" && this.form.name === name) this.open(null);
|
|
29330
|
+
await this.#act(vault, `remove:${name}`, async () => vault.remove?.(name, kind));
|
|
29331
|
+
}
|
|
29332
|
+
restoreSecret(vault, secret) {
|
|
29333
|
+
const { name, kind } = secret;
|
|
29334
|
+
return this.#act(
|
|
29335
|
+
vault,
|
|
29336
|
+
`restore:${name}`,
|
|
29337
|
+
async () => vault.restore?.(name, kind),
|
|
29338
|
+
"Removed too long ago to restore"
|
|
29339
|
+
);
|
|
29340
|
+
}
|
|
29341
|
+
cancelRequest(vault, id) {
|
|
29342
|
+
return this.#act(vault, `cancel:${id}`, async () => vault.cancel?.(id));
|
|
29343
|
+
}
|
|
29344
|
+
lockVault(vault) {
|
|
29345
|
+
return this.#act(vault, "lock", async () => vault.lock?.());
|
|
29346
|
+
}
|
|
29347
|
+
dismissBackup(vault) {
|
|
29348
|
+
return this.#act(vault, "backup", async () => vault.dismissBackupReminder?.());
|
|
29349
|
+
}
|
|
29350
|
+
answer(id) {
|
|
29351
|
+
const vault = this.model?.vault;
|
|
29352
|
+
this.dispatchEvent(
|
|
29353
|
+
new CustomEvent("value-request", { detail: { id, vault }, bubbles: true, composed: true })
|
|
29354
|
+
);
|
|
29355
|
+
}
|
|
29356
|
+
#kind(event2) {
|
|
29357
|
+
this.importKind = event2.currentTarget.value;
|
|
29358
|
+
this.candidates = null;
|
|
29359
|
+
this.#refuse(null);
|
|
29360
|
+
}
|
|
29361
|
+
#reset() {
|
|
29362
|
+
this.candidates = null;
|
|
29363
|
+
this.#refuse(null);
|
|
29364
|
+
}
|
|
29365
|
+
async read(vault) {
|
|
29366
|
+
const form = this.form;
|
|
29367
|
+
const kind = this.importKind;
|
|
29368
|
+
if (this.busy) return;
|
|
29369
|
+
const password = take(this.#field("password"));
|
|
29370
|
+
const file = this.#field("file").files?.[0];
|
|
29371
|
+
if (!file) {
|
|
29372
|
+
this.#refuse("Choose a file to import", "file", true);
|
|
29373
|
+
return;
|
|
29374
|
+
}
|
|
29375
|
+
const pick = this.candidates?.filter((item2) => this.picked.has(item2.name)).map(
|
|
29376
|
+
(item2) => item2.kind && item2.kind !== "secret" ? { name: item2.name, kind: item2.kind } : item2.name
|
|
29377
|
+
);
|
|
29378
|
+
if (pick && !pick.length) {
|
|
29379
|
+
this.#refuse("Choose at least one secret to import");
|
|
29380
|
+
return;
|
|
29381
|
+
}
|
|
29382
|
+
this.busy = true;
|
|
29383
|
+
this.#refuse(null);
|
|
29384
|
+
try {
|
|
29385
|
+
let bytes = new Uint8Array(await file.arrayBuffer());
|
|
29386
|
+
if (!this.#same(vault, form, kind, file) || this.#shut(vault)) return;
|
|
29387
|
+
const call = vault.import?.(kind, bytes, {
|
|
29388
|
+
...password ? { password } : {},
|
|
29389
|
+
...pick ? { pick } : {}
|
|
29390
|
+
});
|
|
29391
|
+
bytes = null;
|
|
29392
|
+
const result = await call;
|
|
29393
|
+
if (!this.#same(vault, form, kind, file)) return;
|
|
29394
|
+
if (result.stage === "pick") {
|
|
29395
|
+
this.candidates = result.candidates;
|
|
29396
|
+
this.picked = new Set(
|
|
29397
|
+
result.candidates.filter((item2) => !item2.refused).map((item2) => item2.name)
|
|
29398
|
+
);
|
|
29399
|
+
this.again = !!password;
|
|
29400
|
+
return;
|
|
29401
|
+
}
|
|
29402
|
+
this.form = null;
|
|
29403
|
+
this.candidates = null;
|
|
29404
|
+
this.said = {
|
|
29405
|
+
kind: "imported",
|
|
29406
|
+
imported: result.imported.length,
|
|
29407
|
+
skipped: result.skipped.map((name) => {
|
|
29408
|
+
const reason = result.reasons?.[name];
|
|
29409
|
+
return reason ? { name, reason } : { name };
|
|
29410
|
+
})
|
|
29411
|
+
};
|
|
29412
|
+
} catch (error) {
|
|
29413
|
+
if (this.#mine(vault, form))
|
|
29414
|
+
this.#refuse(failureText(error), fieldOf(error, password ? "password" : "file"));
|
|
29415
|
+
} finally {
|
|
29416
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29417
|
+
}
|
|
29418
|
+
}
|
|
29419
|
+
#pick(name, event2) {
|
|
29420
|
+
const on = event2.currentTarget.checked;
|
|
29421
|
+
this.picked = new Set(
|
|
29422
|
+
on ? [...this.picked, name] : [...this.picked].filter((item2) => item2 !== name)
|
|
29423
|
+
);
|
|
29424
|
+
}
|
|
29425
|
+
async exportAll(vault, trigger2 = null) {
|
|
29426
|
+
const form = this.form;
|
|
29427
|
+
if (this.busy) return;
|
|
29428
|
+
const passphrase = take(this.#field("passphrase"));
|
|
29429
|
+
const repeat = take(this.#field("repeat"));
|
|
29430
|
+
const short2 = new TextEncoder().encode(passphrase).length < 8;
|
|
29431
|
+
const problem = short2 ? "Passphrases need at least 8 bytes" : passphrase !== repeat ? "The passphrases don't match" : null;
|
|
29432
|
+
this.#refuse(problem, short2 ? "passphrase" : "repeat", true);
|
|
29433
|
+
if (problem) return;
|
|
29434
|
+
const sure = await confirm({
|
|
29435
|
+
title: "Export your secrets?",
|
|
29436
|
+
body: "The file holds every value, encrypted with your passphrase. Keep it somewhere safe.",
|
|
29437
|
+
action: "Export",
|
|
29438
|
+
variant: "confirmation",
|
|
29439
|
+
trigger: trigger2
|
|
29440
|
+
});
|
|
29441
|
+
if (!sure || !this.#mine(vault, form) || this.#shut(vault)) return;
|
|
29442
|
+
this.busy = true;
|
|
29443
|
+
try {
|
|
29444
|
+
const bytes = await vault.export?.(passphrase);
|
|
29445
|
+
if (!this.#mine(vault, form)) return;
|
|
29446
|
+
const file = filename();
|
|
29447
|
+
download(bytes, file, this.renderRoot);
|
|
29448
|
+
this.form = null;
|
|
29449
|
+
this.said = { kind: "exported", file };
|
|
29450
|
+
} catch (error) {
|
|
29451
|
+
if (this.#mine(vault, form)) this.#refuse(failureText(error), fieldOf(error, "passphrase"));
|
|
29452
|
+
} finally {
|
|
29453
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
29454
|
+
}
|
|
29455
|
+
}
|
|
28786
29456
|
async showOlder(vault, entries) {
|
|
28787
29457
|
this.loading = true;
|
|
28788
29458
|
this.failure = null;
|
|
@@ -28795,112 +29465,181 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28795
29465
|
this.older = merged(this.older, page.audit);
|
|
28796
29466
|
this.more = page.more;
|
|
28797
29467
|
} catch (error) {
|
|
28798
|
-
if (this
|
|
29468
|
+
if (this.#mine(vault)) this.failure = error.message;
|
|
28799
29469
|
} finally {
|
|
28800
29470
|
if (this.model?.vault === vault) this.loading = false;
|
|
28801
29471
|
}
|
|
28802
29472
|
}
|
|
28803
|
-
|
|
28804
|
-
|
|
28805
|
-
|
|
28806
|
-
|
|
28807
|
-
|
|
28808
|
-
|
|
28809
|
-
|
|
28810
|
-
|
|
28811
|
-
} catch (error) {
|
|
28812
|
-
if (this.model?.vault === vault && this.isConnected) this.failure = error.message;
|
|
28813
|
-
} finally {
|
|
28814
|
-
if (this.model?.vault === vault)
|
|
28815
|
-
this.acking = new Set([...this.acking].filter((id) => id !== notice.id));
|
|
29473
|
+
#error(text2, id) {
|
|
29474
|
+
return b`<p class="error" role="alert" id=${`error-${id}`} data-error=${id}><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${text2}</span></p>`;
|
|
29475
|
+
}
|
|
29476
|
+
#enter(event2, run2, locked) {
|
|
29477
|
+
if (event2.key === "Escape") {
|
|
29478
|
+
event2.preventDefault();
|
|
29479
|
+
this.open(null);
|
|
29480
|
+
return;
|
|
28816
29481
|
}
|
|
29482
|
+
if (event2.key !== "Enter" || event2.target.localName !== "input") return;
|
|
29483
|
+
event2.preventDefault();
|
|
29484
|
+
if (!locked && !this.busy) void run2();
|
|
29485
|
+
}
|
|
29486
|
+
#value(label, field = "value") {
|
|
29487
|
+
return b`<label class="field"><span>${label}</span><input type="password" autocomplete="off" spellcheck="false" data-field=${field} aria-invalid=${this.#bad(field)} aria-describedby=${this.#described(field)} /></label>`;
|
|
29488
|
+
}
|
|
29489
|
+
#actions(locked, label, action, run2) {
|
|
29490
|
+
return b`<div class="buttons">
|
|
29491
|
+
<swc-button size="m" variant="accent" data-action=${action} ?pending=${this.busy} ?disabled=${locked} @click=${run2}>${label}</swc-button>
|
|
29492
|
+
<swc-button size="m" variant="secondary" fill-style="outline" data-action="cancel" @click=${() => this.open(null)}>Cancel</swc-button>
|
|
29493
|
+
</div>`;
|
|
29494
|
+
}
|
|
29495
|
+
#locked(locked) {
|
|
29496
|
+
return locked ? b`<p class="muted" data-locked>Unlock the vault first</p>` : A;
|
|
29497
|
+
}
|
|
29498
|
+
#valueForm(vault, form, locked) {
|
|
29499
|
+
const save = () => this.save(vault);
|
|
29500
|
+
const add = form.kind === "add";
|
|
29501
|
+
return b`<div class="form" data-form=${form.kind} @input=${() => this.#typed()} @keydown=${(event2) => this.#enter(event2, save, locked)}>
|
|
29502
|
+
<strong>${add ? "Add a secret" : b`Replace the value of <code>${form.name}</code>`}</strong>
|
|
29503
|
+
${add ? b`<label class="field"><span>Name</span><input type="text" autocomplete="off" spellcheck="false" autocapitalize="characters" data-field="name" placeholder="API_TOKEN" aria-invalid=${this.#bad("name")} aria-describedby=${this.#described("name")} @input=${(event2) => this.#upper(event2)} /></label>` : A}
|
|
29504
|
+
${this.#value(add ? "Value" : "New value")}
|
|
29505
|
+
${this.#locked(locked)}
|
|
29506
|
+
${this.problem ? this.#error(this.problem, "form") : A}
|
|
29507
|
+
${this.#actions(locked, "Save", "save", save)}
|
|
29508
|
+
</div>`;
|
|
29509
|
+
}
|
|
29510
|
+
#upper(event2) {
|
|
29511
|
+
const input = event2.currentTarget;
|
|
29512
|
+
input.value = input.value.toUpperCase();
|
|
29513
|
+
}
|
|
29514
|
+
#importForm(vault, locked) {
|
|
29515
|
+
const read = () => this.read(vault);
|
|
29516
|
+
const candidates2 = this.candidates;
|
|
29517
|
+
return b`<div class="form" data-form="import" @input=${() => this.#typed()} @keydown=${(event2) => this.#enter(event2, read, locked)}>
|
|
29518
|
+
<strong>Import secrets</strong>
|
|
29519
|
+
<label class="field"><span id="import-kind">Kind</span>
|
|
29520
|
+
<sp-picker size="m" label="Kind" aria-labelledby="import-kind" data-field="kind" value=${this.importKind} @change=${(event2) => this.#kind(event2)}>
|
|
29521
|
+
${Object.entries(importKinds).map(([value, label]) => b`<sp-menu-item value=${value}>${label}</sp-menu-item>`)}
|
|
29522
|
+
</sp-picker>
|
|
29523
|
+
</label>
|
|
29524
|
+
<label class="field"><span>File</span><input type="file" data-field="file" aria-invalid=${this.#bad("file")} aria-describedby=${this.#described("file")} @change=${() => this.#reset()} /></label>
|
|
29525
|
+
<label class="field"><span>${this.again ? "Password, once more to import" : "Password, if the file has one"}</span><input type="password" autocomplete="off" spellcheck="false" data-field="password" aria-invalid=${this.#bad("password")} aria-describedby=${this.#described("password")} /></label>
|
|
29526
|
+
${candidates2 ? b`<fieldset class="picks" data-picks>
|
|
29527
|
+
<legend class="muted">Choose what to import</legend>
|
|
29528
|
+
<p class="muted" data-rules-note>Rules from the file aren't applied. Add them with sudo.</p>
|
|
29529
|
+
${candidates2.map(
|
|
29530
|
+
(item2) => b`<label data-candidate=${item2.name}>
|
|
29531
|
+
<input type="checkbox" data-pick=${item2.name} .checked=${this.picked.has(item2.name)} ?disabled=${!!item2.refused} @change=${(event2) => this.#pick(item2.name, event2)} />
|
|
29532
|
+
<span class="about">
|
|
29533
|
+
<span><code>${item2.name}</code>${item2.exists ? b` <swc-badge size="s" variant="notice" subtle>Replaces a secret</swc-badge>` : A}</span>
|
|
29534
|
+
${item2.refused ? b`<span class="muted" data-refused-reason>Can't be imported: ${item2.refused}</span>` : A}
|
|
29535
|
+
${item2.suggestedRules ? b`<span class="suggested" data-suggested><span class="from">From the file, not checked by SLICC:</span> <span class="said">${prompt2(item2.suggestedRules)}</span></span>` : A}
|
|
29536
|
+
</span>
|
|
29537
|
+
</label>`
|
|
29538
|
+
)}
|
|
29539
|
+
</fieldset>` : A}
|
|
29540
|
+
${this.#locked(locked)}
|
|
29541
|
+
${this.problem ? this.#error(this.problem, "form") : A}
|
|
29542
|
+
${candidates2 ? this.#actions(
|
|
29543
|
+
locked || !this.picked.size,
|
|
29544
|
+
`Import ${this.picked.size}`,
|
|
29545
|
+
"import-picked",
|
|
29546
|
+
read
|
|
29547
|
+
) : this.#actions(locked, "Continue", "read", read)}
|
|
29548
|
+
</div>`;
|
|
28817
29549
|
}
|
|
28818
|
-
#
|
|
28819
|
-
const
|
|
28820
|
-
|
|
29550
|
+
#exportForm(vault, locked) {
|
|
29551
|
+
const run2 = () => this.exportAll(vault);
|
|
29552
|
+
return b`<div class="form" data-form="export" @input=${() => this.#typed()} @keydown=${(event2) => this.#enter(event2, run2, locked)}>
|
|
29553
|
+
<strong>Export secrets</strong>
|
|
29554
|
+
<span class="muted">The file is sealed with this passphrase. You need it to import the file again.</span>
|
|
29555
|
+
${this.#value("Passphrase", "passphrase")}
|
|
29556
|
+
${this.#value("Passphrase again", "repeat")}
|
|
29557
|
+
${exported(this.model?.vault?.status()?.exportedAt)}
|
|
29558
|
+
${this.#locked(locked)}
|
|
29559
|
+
${this.problem ? this.#error(this.problem, "form") : A}
|
|
29560
|
+
${this.#actions(locked, "Export", "download", run2)}
|
|
29561
|
+
</div>`;
|
|
29562
|
+
}
|
|
29563
|
+
#request(vault, request2) {
|
|
29564
|
+
const what = asking2(request2);
|
|
28821
29565
|
return b`<div class="box" data-request=${request2.id}>
|
|
28822
29566
|
<span class="title">${what}</span>
|
|
28823
29567
|
${request2.prompt ? b`<p class="prompt" data-prompt><span class="from">From the agent, not checked by SLICC:</span> <span class="said">${prompt2(request2.prompt)}</span></p>` : A}
|
|
28824
29568
|
<div class="actions">
|
|
28825
|
-
${
|
|
29569
|
+
${request2.kind === "value" && vault.put && !this.#offline ? b`<swc-button size="m" variant="accent" data-action="answer" @click=${() => this.answer(request2.id)}>Enter value</swc-button>` : A}
|
|
29570
|
+
${vault.cancel && !this.#offline ? b`<swc-button size="m" variant="secondary" fill-style="outline" data-action="cancel-request" ?pending=${this.acting.has(`cancel:${request2.id}`)} @click=${() => this.cancelRequest(vault, request2.id)}>Cancel request</swc-button>` : A}
|
|
28826
29571
|
<span class="muted">Expires ${until(request2.expiresAt)}</span>
|
|
28827
29572
|
</div>
|
|
28828
29573
|
</div>`;
|
|
28829
29574
|
}
|
|
28830
|
-
#notice(vault, notice, devices) {
|
|
28831
|
-
return b`<div class="box notice" role="alert" data-notice=${notice.id}>
|
|
28832
|
-
<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>
|
|
28833
|
-
<ul>${notice.widened.map((change) => b`<li>${widening(change, devices)}</li>`)}</ul>
|
|
28834
|
-
<span>If you didn’t mean this, change the file back with sudo.</span>
|
|
28835
|
-
<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>
|
|
28836
|
-
</div>`;
|
|
28837
|
-
}
|
|
28838
29575
|
#state(secret) {
|
|
28839
29576
|
const [variant, label] = secret.state === "removed" ? ["neutral", "Removed"] : secret.expiresAt !== void 0 && secret.expiresAt <= Date.now() ? ["notice", "Expired"] : secret.state === "inert" ? ["neutral", "No rule yet"] : ["positive", "Active"];
|
|
28840
29577
|
return b`<swc-status-light size="s" variant=${variant}>${label}</swc-status-light>`;
|
|
28841
29578
|
}
|
|
28842
|
-
#
|
|
29579
|
+
#controls(vault, secret) {
|
|
29580
|
+
if (this.#offline) return A;
|
|
29581
|
+
const { name } = secret;
|
|
28843
29582
|
if (secret.state === "removed")
|
|
28844
|
-
return this
|
|
28845
|
-
|
|
28846
|
-
|
|
28847
|
-
|
|
28848
|
-
})
|
|
28849
|
-
|
|
28850
|
-
|
|
28851
|
-
intent: { kind: "signin", provider: secret.source.slice("oauth:".length) },
|
|
28852
|
-
label: "Sign in again",
|
|
28853
|
-
size: "s"
|
|
28854
|
-
});
|
|
28855
|
-
return this.#button({
|
|
28856
|
-
intent: { kind: "enter", name: secret.name },
|
|
28857
|
-
label: "Replace value",
|
|
28858
|
-
size: "s"
|
|
28859
|
-
});
|
|
29583
|
+
return vault.restore ? b`<div class="buttons"><swc-button size="s" variant="secondary" data-action="restore" ?pending=${this.acting.has(`restore:${name}`)} @click=${() => this.restoreSecret(vault, secret)}>Restore</swc-button></div>` : A;
|
|
29584
|
+
const replace = vault.put && replaceable(secret);
|
|
29585
|
+
if (!replace && !vault.remove) return A;
|
|
29586
|
+
return b`<div class="buttons">
|
|
29587
|
+
${replace ? b`<swc-button size="s" variant="secondary" data-action="replace" @click=${() => this.open({ kind: "replace", name })}>Replace value</swc-button>` : A}
|
|
29588
|
+
${vault.remove ? b`<swc-button size="s" variant="secondary" fill-style="outline" data-action="remove" ?pending=${this.acting.has(`remove:${name}`)} @click=${(event2) => this.removeSecret(vault, secret, event2.currentTarget)}>Remove</swc-button>` : A}
|
|
29589
|
+
</div>`;
|
|
28860
29590
|
}
|
|
28861
|
-
#secret(secret, entries, devices, more) {
|
|
29591
|
+
#secret(vault, secret, entries, devices, more, locked) {
|
|
28862
29592
|
const kind = kinds[secret.kind];
|
|
28863
29593
|
const reveal = revealed(secret.name, entries, Date.now(), more);
|
|
29594
|
+
const exec = execLine(secret.exec, secret.execArgv);
|
|
28864
29595
|
const gone2 = secret.state === "removed";
|
|
29596
|
+
const form = this.#offline ? null : this.form;
|
|
28865
29597
|
return b`<li class="secret" data-secret=${secret.name} data-state=${secret.state}>
|
|
28866
29598
|
<div class="name">
|
|
28867
29599
|
<code>${secret.name}</code>
|
|
28868
29600
|
${kind ? b`<swc-badge size="s" variant="neutral" subtle>${kind}</swc-badge>` : A}
|
|
28869
29601
|
${this.#state(secret)}
|
|
28870
29602
|
</div>
|
|
28871
|
-
${this.#
|
|
29603
|
+
${this.#controls(vault, secret)}
|
|
28872
29604
|
<dl>
|
|
28873
29605
|
<dt>${gone2 ? "Was sent to" : "Sent to"}</dt>
|
|
28874
29606
|
<dd data-rules>${secret.rules.length ? secret.rules.map((rule, index) => b`${index ? b`<br />` : A}${ruleLine(rule)}`) : "Nowhere yet: no rule names it"}</dd>
|
|
28875
|
-
|
|
28876
|
-
|
|
28877
|
-
<dt>Programs</dt>
|
|
28878
|
-
<dd data-exec>${execLine(secret.exec)}${reveal ? b`<br />${reveal}` : A}</dd>
|
|
29607
|
+
${secret.exits ? b`<dt>${gone2 ? "Left through" : "Leaves through"}</dt><dd data-exits>${secret.exits.length ? list4(secret.exits.map((exit) => exitLabel(exit, devices))) : "No exit"}</dd>` : A}
|
|
29608
|
+
${exec || reveal ? b`<dt>Programs</dt><dd data-exec>${exec}${exec && reveal ? b`<br />` : A}${reveal}</dd>` : A}
|
|
28879
29609
|
<dt>From</dt>
|
|
28880
29610
|
<dd data-source>${sourceLine(secret, devices)}</dd>
|
|
28881
29611
|
${secret.usedAt ? b`<dt>Last used</dt><dd data-used>${since(secret.usedAt)}</dd>` : A}
|
|
28882
29612
|
${secret.expiresAt ? b`<dt>Expires</dt><dd data-expires>${until(secret.expiresAt)}</dd>` : A}
|
|
28883
29613
|
${secret.removedAt ? b`<dt>Removed</dt><dd>${since(secret.removedAt)}</dd>` : A}
|
|
28884
29614
|
</dl>
|
|
29615
|
+
${form?.kind === "replace" && form.name === secret.name ? this.#valueForm(vault, form, locked) : A}
|
|
28885
29616
|
</li>`;
|
|
28886
29617
|
}
|
|
28887
|
-
#secrets(list5, entries, devices) {
|
|
29618
|
+
#secrets(vault, list5, entries, devices, locked) {
|
|
28888
29619
|
const more = this.more ?? list5.auditMore;
|
|
28889
|
-
const row = (secret) => this.#secret(secret, entries, devices, more);
|
|
28890
|
-
const
|
|
28891
|
-
const
|
|
29620
|
+
const row = (secret) => this.#secret(vault, secret, entries, devices, more, locked);
|
|
29621
|
+
const sorted = [...list5.secrets].sort(byName);
|
|
29622
|
+
const live = sorted.filter((secret) => secret.state !== "removed");
|
|
29623
|
+
const removed = sorted.filter((secret) => secret.state === "removed");
|
|
28892
29624
|
return b`${live.length ? b`<ul class="secrets" aria-labelledby="secrets">${live.map(row)}</ul>` : A}
|
|
28893
29625
|
${removed.length ? b`<details class="removed" data-removed>
|
|
28894
29626
|
<summary>Removed (${removed.length})</summary>
|
|
28895
29627
|
<ul class="secrets">${removed.map(row)}</ul>
|
|
28896
29628
|
</details>` : A}`;
|
|
28897
29629
|
}
|
|
29630
|
+
#refused(refused2) {
|
|
29631
|
+
if (!refused2.length) return A;
|
|
29632
|
+
return b`<h3 id="secrets-refused">Rules SLICC refused</h3>
|
|
29633
|
+
<ul class="refused" aria-labelledby="secrets-refused" data-refused>
|
|
29634
|
+
${refused2.map((item2) => b`<li data-refused-secret=${item2.secret}><span><code>${item2.secret}</code> to ${ruleLine(item2.rule)}</span><span class="muted">${item2.reason}</span></li>`)}
|
|
29635
|
+
</ul>`;
|
|
29636
|
+
}
|
|
28898
29637
|
#entry(entry, devices) {
|
|
28899
29638
|
const date = new Date(entry.at);
|
|
28900
29639
|
const name = entry.type === "policy" ? null : entry.name;
|
|
28901
29640
|
return b`<li data-seq=${entry.seq} data-type=${entry.type}>
|
|
28902
29641
|
<time datetime=${date.toISOString()} title=${date.toLocaleString("en-GB", { dateStyle: "medium", timeStyle: "short" })}>${since(entry.at)}</time>
|
|
28903
|
-
<span class="what">${name ? b`<code>${name}</code> · ` : A}${auditLine(entry, devices)}${entry.type === "policy" ? A : b` <span class="by">by ${who(entry)}</span>`}</span>
|
|
29642
|
+
<span class="what">${name ? b`<code>${name}</code> · ` : A}${auditLine(entry, devices)}${entry.type === "policy" || entry.type === "refresh" ? A : b` <span class="by">by ${who(entry)}</span>`}</span>
|
|
28904
29643
|
</li>`;
|
|
28905
29644
|
}
|
|
28906
29645
|
#audit(vault, list5, entries, devices) {
|
|
@@ -28916,12 +29655,52 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28916
29655
|
${more ? b`<div class="row"><swc-button size="s" variant="secondary" fill-style="outline" data-action="older" ?pending=${this.loading} @click=${() => this.showOlder(vault, entries)}>Show older</swc-button></div>` : A}`;
|
|
28917
29656
|
}
|
|
28918
29657
|
#feedback() {
|
|
29658
|
+
const said = this.said;
|
|
28919
29659
|
if (this.popup?.state === "blocked")
|
|
28920
29660
|
return b`<div class="error" role="alert" data-popup="blocked"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>The browser blocked the vault window. Allow pop-ups for this site, then try again.</span></div>`;
|
|
28921
|
-
if (
|
|
28922
|
-
|
|
29661
|
+
if (!said) return A;
|
|
29662
|
+
if (said.kind === "saved")
|
|
29663
|
+
return b`<p role="status" data-said="saved">Saved <code>${said.name}</code> in the vault</p>`;
|
|
29664
|
+
if (said.kind === "imported")
|
|
29665
|
+
return b`<div role="status" data-said="imported"><p>Imported ${said.imported}</p>${said.skipped.map((item2) => b`<p class="skipped" data-skipped=${item2.name}>Skipped <code>${item2.name}</code>${item2.reason ? b`: <span class="said">${item2.reason}</span>` : A}</p>`)}</div>`;
|
|
29666
|
+
return b`<p role="status" data-said="exported">Exported to <code>${said.file}</code></p>`;
|
|
29667
|
+
}
|
|
29668
|
+
#availability() {
|
|
29669
|
+
if (this.#offline)
|
|
29670
|
+
return b`<p class="availability" role="status" data-availability="waiting"><swc-progress-circle size="s" indeterminate label="Waiting for the vault" aria-hidden="true"></swc-progress-circle><span>Waiting for the vault</span></p>`;
|
|
28923
29671
|
return A;
|
|
28924
29672
|
}
|
|
29673
|
+
#backup(vault, status2) {
|
|
29674
|
+
if (status2?.backupReminder !== "due" || this.#offline) return A;
|
|
29675
|
+
return b`<div class="box info" role="region" aria-labelledby="secrets-backup" data-backup>
|
|
29676
|
+
<span class="title" id="secrets-backup"><swc-icon-info-circle size="s" aria-hidden="true"></swc-icon-info-circle><span>Export a backup of your secrets. Clearing this site's data loses every value.</span></span>
|
|
29677
|
+
<div class="actions">
|
|
29678
|
+
${vault.export ? b`<swc-button size="m" variant="accent" data-action="export" @click=${() => this.open({ kind: "export" })}>Export backup</swc-button>` : A}
|
|
29679
|
+
${vault.dismissBackupReminder ? b`<swc-button size="m" variant="secondary" fill-style="outline" data-action="dismiss-backup" ?pending=${this.acting.has("backup")} @click=${() => this.dismissBackup(vault)}>Not now</swc-button>` : A}
|
|
29680
|
+
</div>
|
|
29681
|
+
</div>`;
|
|
29682
|
+
}
|
|
29683
|
+
#header(vault, status2) {
|
|
29684
|
+
if (!status2) return A;
|
|
29685
|
+
if (this.#offline)
|
|
29686
|
+
return b`<swc-status-light size="m" variant="neutral">Waiting</swc-status-light>`;
|
|
29687
|
+
return b`<swc-status-light size="m" variant=${status2.locked ? "notice" : "positive"}>${status2.locked ? "Locked" : "Unlocked"}</swc-status-light><span class="muted">${lockModes[status2.lock]}</span>
|
|
29688
|
+
<span class="controls">${status2.locked ? b`${status2.scrub?.needed && !status2.scrub.ready ? b`<span class="availability" role="status" data-availability="unlock"><swc-icon-info-circle size="s" aria-hidden="true"></swc-icon-info-circle><span>Unlock the vault to continue</span></span>` : A}${this.#button({ intent: { kind: "unlock" }, label: "Unlock", variant: "accent" }, "unlock")}` : b`${vault.lock ? b`<swc-button size="m" variant="secondary" fill-style="outline" data-action="lock" ?pending=${this.acting.has("lock")} @click=${() => this.lockVault(vault)}>Lock</swc-button>` : A}
|
|
29689
|
+
${this.#button({ intent: { kind: "protect" }, label: status2.lock === "auto" ? "Protect with a passkey" : "Change protection" }, "protect")}`}</span>`;
|
|
29690
|
+
}
|
|
29691
|
+
#tools(vault, locked) {
|
|
29692
|
+
if (this.#offline) return A;
|
|
29693
|
+
const form = this.form;
|
|
29694
|
+
const tool2 = (kind, label, variant = "secondary") => b`<swc-button size="m" variant=${variant} data-action=${kind === "add" ? "add-secret" : kind} aria-expanded=${form?.kind === kind ? "true" : "false"} @click=${() => this.open(form?.kind === kind ? null : { kind })}>${label}</swc-button>`;
|
|
29695
|
+
return b`${vault.put || vault.import || vault.export ? b`<div class="row" data-tools>
|
|
29696
|
+
${vault.put ? tool2("add", "Add secret", "accent") : A}
|
|
29697
|
+
${vault.import ? tool2("import", "Import\u2026") : A}
|
|
29698
|
+
${vault.export ? tool2("export", "Export\u2026") : A}
|
|
29699
|
+
</div>` : A}
|
|
29700
|
+
${form?.kind === "add" ? this.#valueForm(vault, form, locked) : A}
|
|
29701
|
+
${form?.kind === "import" ? this.#importForm(vault, locked) : A}
|
|
29702
|
+
${form?.kind === "export" ? this.#exportForm(vault, locked) : A}`;
|
|
29703
|
+
}
|
|
28925
29704
|
render() {
|
|
28926
29705
|
const vault = this.model?.vault;
|
|
28927
29706
|
if (!vault) return A;
|
|
@@ -28929,28 +29708,26 @@ var SliccSecrets = class extends ThemedElement {
|
|
|
28929
29708
|
const current = vault.list();
|
|
28930
29709
|
const devices = devicesOf(this.model);
|
|
28931
29710
|
const entries = merged(current?.audit ?? [], this.older);
|
|
28932
|
-
const
|
|
28933
|
-
|
|
28934
|
-
|
|
28935
|
-
|
|
28936
|
-
].filter((
|
|
29711
|
+
const locked = !!status2?.locked;
|
|
29712
|
+
this.#offline = away(vault);
|
|
29713
|
+
if (this.#offline && this.form) clearValues(this.renderRoot);
|
|
29714
|
+
const now = Date.now();
|
|
29715
|
+
const waiting2 = (status2?.waiting ?? []).filter((request2) => request2.expiresAt > now);
|
|
28937
29716
|
return b`<section aria-labelledby="secrets" data-vault=${status2 ? status2.locked ? "locked" : "unlocked" : "loading"}>
|
|
28938
29717
|
<div class="head">
|
|
28939
29718
|
<h2 id="secrets">Secrets</h2>
|
|
28940
|
-
${
|
|
28941
|
-
${status2?.locked ? this.#button({ intent: { kind: "unlock" }, label: "Unlock", variant: "accent" }) : this.#button({ intent: { kind: "manage" }, label: "Open the vault" })}
|
|
29719
|
+
${this.#header(vault, status2)}
|
|
28942
29720
|
</div>
|
|
28943
|
-
<p class="muted">Agents and programs use secrets by name.
|
|
29721
|
+
<p class="muted">Agents and programs use secrets by name. SLICC sends each value only where its rules allow, so agents never see it.</p>
|
|
29722
|
+
${this.#availability()}
|
|
28944
29723
|
${this.#feedback()}
|
|
28945
|
-
${this.failure ?
|
|
28946
|
-
${
|
|
28947
|
-
${
|
|
28948
|
-
${
|
|
29724
|
+
${this.failure ? this.#error(this.failure, "vault") : A}
|
|
29725
|
+
${waiting2.length ? b`<h3>Waiting for you</h3>${waiting2.map((request2) => this.#request(vault, request2))}` : A}
|
|
29726
|
+
${this.#backup(vault, status2)}
|
|
29727
|
+
${this.#tools(vault, locked)}
|
|
29728
|
+
${!current ? this.#offline ? A : b`<p class="muted" data-loading>Loading secrets…</p>` : current.secrets.length ? this.#secrets(vault, current, entries, devices, locked) : b`<p data-empty>No secrets yet. Add one here, or enter the value when an agent or program asks for one.</p>`}
|
|
29729
|
+
${this.#refused(current?.refused ?? [])}
|
|
28949
29730
|
<p class="muted" data-policy>Rules live in <code>/etc/fnox/config.toml</code> and <code>/etc/slicc/secrets-policy.toml</code>. Change them with sudo; SLICC asks you before every change.</p>
|
|
28950
|
-
<div class="row">
|
|
28951
|
-
${this.#button({ intent: { kind: "import" }, label: "Import\u2026", size: "s" })}
|
|
28952
|
-
${this.#button({ intent: { kind: "export" }, label: "Export\u2026", size: "s" })}
|
|
28953
|
-
</div>
|
|
28954
29731
|
${current ? this.#audit(vault, current, entries, devices) : A}
|
|
28955
29732
|
</section>`;
|
|
28956
29733
|
}
|
|
@@ -29745,6 +30522,292 @@ ${data.html}`;
|
|
|
29745
30522
|
}
|
|
29746
30523
|
};
|
|
29747
30524
|
|
|
30525
|
+
// src/app/value-request.ts
|
|
30526
|
+
function valueRequests(vault, now) {
|
|
30527
|
+
return [...vault?.status()?.waiting ?? []].filter((request2) => request2.kind === "value" && request2.expiresAt > now).sort((a22, b13) => a22.createdAt - b13.createdAt);
|
|
30528
|
+
}
|
|
30529
|
+
var SliccValueRequest = class extends ThemedElement {
|
|
30530
|
+
static properties = {
|
|
30531
|
+
...ThemedElement.properties,
|
|
30532
|
+
now: { state: true },
|
|
30533
|
+
busy: { state: true },
|
|
30534
|
+
problem: { state: true },
|
|
30535
|
+
blocked: { state: true }
|
|
30536
|
+
};
|
|
30537
|
+
#later = /* @__PURE__ */ new Set();
|
|
30538
|
+
#done = /* @__PURE__ */ new Set();
|
|
30539
|
+
#front = "";
|
|
30540
|
+
#shown = "";
|
|
30541
|
+
#trigger = null;
|
|
30542
|
+
#timer = null;
|
|
30543
|
+
#port;
|
|
30544
|
+
#open = (event2) => {
|
|
30545
|
+
const { id, vault } = event2.detail;
|
|
30546
|
+
if (vault === void 0 || vault === this.model?.vault) this.reopen(id);
|
|
30547
|
+
};
|
|
30548
|
+
constructor() {
|
|
30549
|
+
super();
|
|
30550
|
+
this.now = Date.now();
|
|
30551
|
+
this.busy = false;
|
|
30552
|
+
this.problem = null;
|
|
30553
|
+
this.blocked = false;
|
|
30554
|
+
}
|
|
30555
|
+
static styles = [
|
|
30556
|
+
dialogStyles,
|
|
30557
|
+
fieldStyles,
|
|
30558
|
+
i`
|
|
30559
|
+
:host {
|
|
30560
|
+
display: contents;
|
|
30561
|
+
}
|
|
30562
|
+
.asked {
|
|
30563
|
+
margin-block-start: var(--swc-spacing-100);
|
|
30564
|
+
}
|
|
30565
|
+
.timer,
|
|
30566
|
+
.more,
|
|
30567
|
+
.locked {
|
|
30568
|
+
margin-block-start: var(--swc-spacing-100);
|
|
30569
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
30570
|
+
font-size: var(--swc-font-size-75);
|
|
30571
|
+
}
|
|
30572
|
+
.prompt {
|
|
30573
|
+
margin-block-start: var(--swc-spacing-200);
|
|
30574
|
+
padding-inline-start: var(--swc-spacing-200);
|
|
30575
|
+
border-inline-start: var(--swc-border-width-200) solid var(--swc-gray-300);
|
|
30576
|
+
overflow-wrap: anywhere;
|
|
30577
|
+
}
|
|
30578
|
+
.said {
|
|
30579
|
+
white-space: pre-wrap;
|
|
30580
|
+
}
|
|
30581
|
+
.from {
|
|
30582
|
+
display: block;
|
|
30583
|
+
font-size: var(--swc-font-size-75);
|
|
30584
|
+
color: var(--swc-neutral-subdued-content-color-default);
|
|
30585
|
+
}
|
|
30586
|
+
.fields {
|
|
30587
|
+
display: grid;
|
|
30588
|
+
gap: var(--swc-spacing-200);
|
|
30589
|
+
margin-block-start: var(--swc-spacing-300);
|
|
30590
|
+
padding: var(--swc-spacing-75);
|
|
30591
|
+
}
|
|
30592
|
+
.unlock {
|
|
30593
|
+
display: flex;
|
|
30594
|
+
flex-wrap: wrap;
|
|
30595
|
+
align-items: center;
|
|
30596
|
+
gap: var(--swc-spacing-200);
|
|
30597
|
+
margin-block-start: var(--swc-spacing-200);
|
|
30598
|
+
}
|
|
30599
|
+
.problem {
|
|
30600
|
+
display: flex;
|
|
30601
|
+
align-items: flex-start;
|
|
30602
|
+
gap: var(--swc-spacing-75);
|
|
30603
|
+
margin-block-start: var(--swc-spacing-200);
|
|
30604
|
+
color: var(--swc-negative-content-color-default);
|
|
30605
|
+
--swc-icon-color: var(--swc-negative-content-color-default);
|
|
30606
|
+
}
|
|
30607
|
+
code {
|
|
30608
|
+
font-family: var(--swc-code-font-family-stack);
|
|
30609
|
+
overflow-wrap: anywhere;
|
|
30610
|
+
}
|
|
30611
|
+
`
|
|
30612
|
+
];
|
|
30613
|
+
connectedCallback() {
|
|
30614
|
+
super.connectedCallback();
|
|
30615
|
+
this.ownerDocument.addEventListener("value-request", this.#open);
|
|
30616
|
+
}
|
|
30617
|
+
disconnectedCallback() {
|
|
30618
|
+
super.disconnectedCallback();
|
|
30619
|
+
this.ownerDocument.removeEventListener("value-request", this.#open);
|
|
30620
|
+
clearValues(this.renderRoot);
|
|
30621
|
+
this.#tick(false);
|
|
30622
|
+
this.#shown = "";
|
|
30623
|
+
}
|
|
30624
|
+
subscribe(model) {
|
|
30625
|
+
if (model.vault !== this.#port) {
|
|
30626
|
+
clearValues(this.renderRoot);
|
|
30627
|
+
this.#port = model.vault;
|
|
30628
|
+
this.#later.clear();
|
|
30629
|
+
this.#done.clear();
|
|
30630
|
+
this.#front = "";
|
|
30631
|
+
this.busy = false;
|
|
30632
|
+
this.problem = null;
|
|
30633
|
+
this.blocked = false;
|
|
30634
|
+
}
|
|
30635
|
+
const update = () => {
|
|
30636
|
+
this.now = Date.now();
|
|
30637
|
+
this.requestUpdate();
|
|
30638
|
+
};
|
|
30639
|
+
return [
|
|
30640
|
+
...super.subscribe(model),
|
|
30641
|
+
...model.vault ? [model.vault.on("status", update), model.vault.on("availability", update)] : []
|
|
30642
|
+
];
|
|
30643
|
+
}
|
|
30644
|
+
reopen(id) {
|
|
30645
|
+
this.#later.delete(id);
|
|
30646
|
+
this.#front = id;
|
|
30647
|
+
this.now = Date.now();
|
|
30648
|
+
}
|
|
30649
|
+
later(id) {
|
|
30650
|
+
if (this.busy) return;
|
|
30651
|
+
clearValues(this.renderRoot);
|
|
30652
|
+
this.#later.add(id);
|
|
30653
|
+
if (this.#front === id) this.#front = "";
|
|
30654
|
+
this.problem = null;
|
|
30655
|
+
this.requestUpdate();
|
|
30656
|
+
}
|
|
30657
|
+
#queue() {
|
|
30658
|
+
const vault = this.model?.vault;
|
|
30659
|
+
if (!vault || away(vault)) return [];
|
|
30660
|
+
return valueRequests(vault, this.now).filter(({ id }) => !this.#done.has(id));
|
|
30661
|
+
}
|
|
30662
|
+
#current(queue) {
|
|
30663
|
+
return queue.find(({ id }) => id === this.#front) ?? queue.find(({ id }) => !this.#later.has(id)) ?? null;
|
|
30664
|
+
}
|
|
30665
|
+
#tick(on) {
|
|
30666
|
+
if (on && !this.#timer) this.#timer = setInterval(() => this.now = Date.now(), 1e3);
|
|
30667
|
+
if (!on && this.#timer) {
|
|
30668
|
+
clearInterval(this.#timer);
|
|
30669
|
+
this.#timer = null;
|
|
30670
|
+
}
|
|
30671
|
+
}
|
|
30672
|
+
#mine(vault) {
|
|
30673
|
+
return this.model?.vault === vault && this.isConnected;
|
|
30674
|
+
}
|
|
30675
|
+
#field(name) {
|
|
30676
|
+
return this.renderRoot.querySelector(`input[data-field=${name}]`);
|
|
30677
|
+
}
|
|
30678
|
+
async save(request2) {
|
|
30679
|
+
const vault = this.model?.vault;
|
|
30680
|
+
if (this.busy) return;
|
|
30681
|
+
const name = request2.name ?? this.#field("name").value.trim();
|
|
30682
|
+
const bad = nameProblem(name);
|
|
30683
|
+
const value = bad ? "" : take(this.#field("value"));
|
|
30684
|
+
const text2 = bad ?? valueProblem(value);
|
|
30685
|
+
const field = bad ? "name" : "value";
|
|
30686
|
+
this.problem = text2 ? { id: request2.id, text: text2, field } : null;
|
|
30687
|
+
if (text2) {
|
|
30688
|
+
void this.updateComplete.then(() => this.#field(field)?.focus());
|
|
30689
|
+
return;
|
|
30690
|
+
}
|
|
30691
|
+
this.busy = true;
|
|
30692
|
+
try {
|
|
30693
|
+
await vault.put?.(name, value, request2.id);
|
|
30694
|
+
if (!this.#mine(vault)) return;
|
|
30695
|
+
this.#done.add(request2.id);
|
|
30696
|
+
} catch (error) {
|
|
30697
|
+
if (this.#mine(vault)) {
|
|
30698
|
+
const field2 = fieldOf(error, "value");
|
|
30699
|
+
this.problem = { id: request2.id, text: failureText(error), ...field2 ? { field: field2 } : {} };
|
|
30700
|
+
}
|
|
30701
|
+
} finally {
|
|
30702
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
30703
|
+
}
|
|
30704
|
+
}
|
|
30705
|
+
#typed() {
|
|
30706
|
+
if (this.problem?.field) this.problem = { id: this.problem.id, text: this.problem.text };
|
|
30707
|
+
}
|
|
30708
|
+
#aria(field, problem) {
|
|
30709
|
+
const bad = problem?.field === field;
|
|
30710
|
+
return { invalid: bad ? "true" : A, described: bad ? "error-request" : A };
|
|
30711
|
+
}
|
|
30712
|
+
async cancelRequest(request2) {
|
|
30713
|
+
const vault = this.model?.vault;
|
|
30714
|
+
if (this.busy) return;
|
|
30715
|
+
clearValues(this.renderRoot);
|
|
30716
|
+
this.busy = true;
|
|
30717
|
+
this.problem = null;
|
|
30718
|
+
try {
|
|
30719
|
+
await vault.cancel?.(request2.id);
|
|
30720
|
+
if (this.#mine(vault)) this.#done.add(request2.id);
|
|
30721
|
+
} catch (error) {
|
|
30722
|
+
if (this.#mine(vault)) this.problem = { id: request2.id, text: failureText(error) };
|
|
30723
|
+
} finally {
|
|
30724
|
+
if (this.model?.vault === vault) this.busy = false;
|
|
30725
|
+
}
|
|
30726
|
+
}
|
|
30727
|
+
willUpdate(changed) {
|
|
30728
|
+
super.willUpdate(changed);
|
|
30729
|
+
const current = this.#current(this.#queue());
|
|
30730
|
+
if ((current?.id ?? "") !== this.#shown) clearValues(this.renderRoot);
|
|
30731
|
+
}
|
|
30732
|
+
updated(changed) {
|
|
30733
|
+
super.updated(changed);
|
|
30734
|
+
const dialog = this.renderRoot.querySelector("dialog");
|
|
30735
|
+
this.#tick(this.isConnected && !!dialog);
|
|
30736
|
+
const key2 = dialog?.dataset.request ?? "";
|
|
30737
|
+
if (key2 === this.#shown) return;
|
|
30738
|
+
if (dialog && !this.#shown) this.#trigger = focused();
|
|
30739
|
+
this.#shown = key2;
|
|
30740
|
+
if (!dialog) {
|
|
30741
|
+
if (this.#trigger?.isConnected) this.#trigger.focus();
|
|
30742
|
+
this.#trigger = null;
|
|
30743
|
+
return;
|
|
30744
|
+
}
|
|
30745
|
+
if (!dialog.open) dialog.showModal();
|
|
30746
|
+
const target = dialog.querySelector("input") ?? dialog.querySelector("[data-action=later]");
|
|
30747
|
+
void dialog.querySelector("sp-alert-dialog").updateComplete.then(
|
|
30748
|
+
() => target.focus()
|
|
30749
|
+
);
|
|
30750
|
+
}
|
|
30751
|
+
#onKey(event2, request2) {
|
|
30752
|
+
if (event2.key !== "Enter" || event2.target.localName !== "input") return;
|
|
30753
|
+
event2.preventDefault();
|
|
30754
|
+
if (!this.model?.vault?.status()?.locked) void this.save(request2);
|
|
30755
|
+
}
|
|
30756
|
+
#unlock(vault) {
|
|
30757
|
+
return b`<div class="unlock" data-locked>
|
|
30758
|
+
<span class="locked">Unlock the vault first</span>
|
|
30759
|
+
<slicc-vault-button
|
|
30760
|
+
data-action="unlock"
|
|
30761
|
+
.vault=${vault}
|
|
30762
|
+
.config=${{ intent: { kind: "unlock" }, label: "Unlock", size: "m", variant: "accent", theme: this.color }}
|
|
30763
|
+
@vault-popup=${(event2) => {
|
|
30764
|
+
this.blocked = event2.detail.state === "blocked";
|
|
30765
|
+
}}
|
|
30766
|
+
></slicc-vault-button>
|
|
30767
|
+
${this.blocked ? b`<span class="problem" role="alert" data-popup="blocked"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>The browser blocked the vault window. Allow pop-ups for this site, then try again.</span></span>` : A}
|
|
30768
|
+
</div>`;
|
|
30769
|
+
}
|
|
30770
|
+
render() {
|
|
30771
|
+
const vault = this.model?.vault;
|
|
30772
|
+
const queue = this.#queue();
|
|
30773
|
+
const request2 = this.#current(queue);
|
|
30774
|
+
if (!vault || !request2) return A;
|
|
30775
|
+
const locked = !!vault.status()?.locked;
|
|
30776
|
+
const rest = queue.length - 1;
|
|
30777
|
+
const shown3 = this.problem?.id === request2.id ? this.problem : null;
|
|
30778
|
+
const problem = shown3?.text ?? "";
|
|
30779
|
+
const name = this.#aria("name", shown3);
|
|
30780
|
+
const field = this.#aria("value", shown3);
|
|
30781
|
+
return i17(
|
|
30782
|
+
request2.id,
|
|
30783
|
+
b`<dialog role="alertdialog" aria-labelledby="title" aria-describedby="asked" data-request=${request2.id} @cancel=${(event2) => {
|
|
30784
|
+
event2.preventDefault();
|
|
30785
|
+
this.later(request2.id);
|
|
30786
|
+
}}>
|
|
30787
|
+
<sp-alert-dialog variant="confirmation">
|
|
30788
|
+
<h2 id="title" slot="heading">${request2.name ? b`Enter a value for <code>${request2.name}</code>` : "Enter a value"}</h2>
|
|
30789
|
+
<p class="asked" id="asked" data-asked>${asking2(request2)}</p>
|
|
30790
|
+
${request2.prompt ? b`<p class="prompt" data-prompt><span class="from">From the agent, not checked by SLICC:</span> <span class="said">${prompt2(request2.prompt)}</span></p>` : A}
|
|
30791
|
+
${vault.put ? b`<div class="fields" @input=${() => this.#typed()} @keydown=${(event2) => this.#onKey(event2, request2)}>
|
|
30792
|
+
${request2.name ? A : b`<label class="field"><span>Name</span><input type="text" autocomplete="off" spellcheck="false" autocapitalize="characters" data-field="name" aria-invalid=${name.invalid} aria-describedby=${name.described} @input=${(event2) => {
|
|
30793
|
+
const input = event2.currentTarget;
|
|
30794
|
+
input.value = input.value.toUpperCase();
|
|
30795
|
+
}} /></label>`}
|
|
30796
|
+
<label class="field"><span>Value</span><input type="password" autocomplete="off" spellcheck="false" data-field="value" aria-invalid=${field.invalid} aria-describedby=${field.described} /></label>
|
|
30797
|
+
</div>` : A}
|
|
30798
|
+
${locked ? this.#unlock(vault) : A}
|
|
30799
|
+
${problem ? b`<p class="problem" role="alert" id="error-request" data-error><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${problem}</span></p>` : A}
|
|
30800
|
+
<p class="timer" data-timer>Expires ${until(request2.expiresAt, this.now)}</p>
|
|
30801
|
+
${rest > 0 ? b`<p class="more" data-more>${rest} more waiting</p>` : A}
|
|
30802
|
+
<swc-button slot="button" variant="secondary" fill-style="outline" data-action="later" ?disabled=${this.busy} @click=${() => this.later(request2.id)}>Later</swc-button>
|
|
30803
|
+
${vault.cancel ? b`<swc-button slot="button" variant="secondary" fill-style="outline" data-action="cancel-request" ?disabled=${this.busy} @click=${() => this.cancelRequest(request2)}>Cancel request</swc-button>` : A}
|
|
30804
|
+
${vault.put ? b`<swc-button slot="button" variant="accent" data-action="save" ?pending=${this.busy} ?disabled=${locked} @click=${() => this.save(request2)}>Save</swc-button>` : A}
|
|
30805
|
+
</sp-alert-dialog>
|
|
30806
|
+
</dialog>`
|
|
30807
|
+
);
|
|
30808
|
+
}
|
|
30809
|
+
};
|
|
30810
|
+
|
|
29748
30811
|
// node_modules/@pierre/diffs/dist/constants.js
|
|
29749
30812
|
var DIFFS_TAG_NAME = "diffs-container";
|
|
29750
30813
|
var DIFFS_DEVELOPMENT_BUILD = (() => {
|
|
@@ -40389,7 +41452,7 @@ var captureDelim = r35`${namedCaptureDelim}|(?<unnamed>\()(?!\?)`;
|
|
|
40389
41452
|
var token = new RegExp(r35`${namedCaptureDelim}|${recursiveToken}|\(\?|\\?.`, "gsu");
|
|
40390
41453
|
var overlappingRecursionMsg = "Cannot use multiple overlapping recursions";
|
|
40391
41454
|
function recursion(pattern2, data) {
|
|
40392
|
-
const { hiddenCaptures, mode } = {
|
|
41455
|
+
const { hiddenCaptures, mode: mode2 } = {
|
|
40393
41456
|
hiddenCaptures: [],
|
|
40394
41457
|
mode: "plugin",
|
|
40395
41458
|
...data
|
|
@@ -40402,7 +41465,7 @@ function recursion(pattern2, data) {
|
|
|
40402
41465
|
hiddenCaptures
|
|
40403
41466
|
};
|
|
40404
41467
|
}
|
|
40405
|
-
if (
|
|
41468
|
+
if (mode2 === "plugin" && hasUnescaped(pattern2, r35`\(\?\(DEFINE\)`, Context.DEFAULT)) {
|
|
40406
41469
|
throw new Error("DEFINE groups cannot be used with recursion");
|
|
40407
41470
|
}
|
|
40408
41471
|
const addedHiddenCaptures = [];
|
|
@@ -40428,7 +41491,7 @@ function recursion(pattern2, data) {
|
|
|
40428
41491
|
throw new Error(
|
|
40429
41492
|
// When used in `external` mode by transpilers other than Regex+, backrefs might have
|
|
40430
41493
|
// gone through conversion from named to numbered, so avoid a misleading error
|
|
40431
|
-
`${
|
|
41494
|
+
`${mode2 === "external" ? "Backrefs" : "Numbered backrefs"} cannot be used with global recursion`
|
|
40432
41495
|
);
|
|
40433
41496
|
}
|
|
40434
41497
|
const left = pattern2.slice(0, match.index);
|
|
@@ -40468,7 +41531,7 @@ function recursion(pattern2, data) {
|
|
|
40468
41531
|
}
|
|
40469
41532
|
}
|
|
40470
41533
|
if (!isWithinReffedGroup) {
|
|
40471
|
-
throw new Error(r35`Recursive \g cannot be used outside the referenced group "${
|
|
41534
|
+
throw new Error(r35`Recursive \g cannot be used outside the referenced group "${mode2 === "external" ? gRNameOrNum : r35`\g<${gRNameOrNum}&R=${gRDepth}>`}"`);
|
|
40472
41535
|
}
|
|
40473
41536
|
const startPos = groupContentsStartPos.get(gRNameOrNum);
|
|
40474
41537
|
const groupContents = getGroupContents(pattern2, startPos);
|
|
@@ -40476,7 +41539,7 @@ function recursion(pattern2, data) {
|
|
|
40476
41539
|
throw new Error(
|
|
40477
41540
|
// When used in `external` mode by transpilers other than Regex+, backrefs might have
|
|
40478
41541
|
// gone through conversion from named to numbered, so avoid a misleading error
|
|
40479
|
-
`${
|
|
41542
|
+
`${mode2 === "external" ? "Backrefs" : "Numbered backrefs"} cannot be used with recursion of capturing groups`
|
|
40480
41543
|
);
|
|
40481
41544
|
}
|
|
40482
41545
|
const groupContentsLeft = pattern2.slice(startPos, match.index);
|
|
@@ -40758,17 +41821,17 @@ function getIgnoreCaseMatchChars(char) {
|
|
|
40758
41821
|
return [char];
|
|
40759
41822
|
}
|
|
40760
41823
|
const set = /* @__PURE__ */ new Set();
|
|
40761
|
-
const
|
|
40762
|
-
const upper =
|
|
40763
|
-
const title = LowerToTitleCaseMap.get(
|
|
40764
|
-
const altLower = LowerToAlternativeLowerCaseMap.get(
|
|
40765
|
-
const altUpper = LowerToAlternativeUpperCaseMap.get(
|
|
41824
|
+
const lower2 = char.toLowerCase();
|
|
41825
|
+
const upper = lower2.toUpperCase();
|
|
41826
|
+
const title = LowerToTitleCaseMap.get(lower2);
|
|
41827
|
+
const altLower = LowerToAlternativeLowerCaseMap.get(lower2);
|
|
41828
|
+
const altUpper = LowerToAlternativeUpperCaseMap.get(lower2);
|
|
40766
41829
|
if ([...upper].length === 1) {
|
|
40767
41830
|
set.add(upper);
|
|
40768
41831
|
}
|
|
40769
41832
|
altUpper && set.add(altUpper);
|
|
40770
41833
|
title && set.add(title);
|
|
40771
|
-
set.add(
|
|
41834
|
+
set.add(lower2);
|
|
40772
41835
|
altLower && set.add(altLower);
|
|
40773
41836
|
return [...set];
|
|
40774
41837
|
}
|
|
@@ -43252,8 +44315,8 @@ var InteractionManager = class {
|
|
|
43252
44315
|
renderedEditorActiveLineState;
|
|
43253
44316
|
selectionAnchor;
|
|
43254
44317
|
pointerSession = { mode: "idle" };
|
|
43255
|
-
constructor(
|
|
43256
|
-
this.mode =
|
|
44318
|
+
constructor(mode2, options) {
|
|
44319
|
+
this.mode = mode2;
|
|
43257
44320
|
this.options = options;
|
|
43258
44321
|
}
|
|
43259
44322
|
setOptions(options) {
|
|
@@ -44766,23 +45829,23 @@ function getIconForType(type) {
|
|
|
44766
45829
|
}
|
|
44767
45830
|
|
|
44768
45831
|
// node_modules/@pierre/diffs/dist/utils/createFileHeaderElement.js
|
|
44769
|
-
function createFileHeaderElement({ fileOrDiff, mode, stickyHeader }) {
|
|
45832
|
+
function createFileHeaderElement({ fileOrDiff, mode: mode2, stickyHeader }) {
|
|
44770
45833
|
const fileDiff = "type" in fileOrDiff ? fileOrDiff : void 0;
|
|
44771
45834
|
const properties = {
|
|
44772
|
-
"data-diffs-header":
|
|
45835
|
+
"data-diffs-header": mode2,
|
|
44773
45836
|
"data-change-type": fileDiff?.type,
|
|
44774
45837
|
"data-sticky": stickyHeader ? "" : void 0
|
|
44775
45838
|
};
|
|
44776
45839
|
return createHastElement({
|
|
44777
45840
|
tagName: "div",
|
|
44778
|
-
children: [
|
|
45841
|
+
children: [mode2 === "custom" ? createHastElement({
|
|
44779
45842
|
tagName: "slot",
|
|
44780
45843
|
properties: { name: CUSTOM_HEADER_SLOT_ID }
|
|
44781
45844
|
}) : createHeaderElement({
|
|
44782
45845
|
name: fileOrDiff.name,
|
|
44783
45846
|
prevName: "prevName" in fileOrDiff ? fileOrDiff.prevName : void 0,
|
|
44784
45847
|
iconType: fileDiff?.type ?? "file"
|
|
44785
|
-
}), ...
|
|
45848
|
+
}), ...mode2 === "custom" ? [] : [createMetadataElement(fileDiff)]],
|
|
44786
45849
|
properties
|
|
44787
45850
|
});
|
|
44788
45851
|
}
|
|
@@ -47295,8 +48358,8 @@ var File = class {
|
|
|
47295
48358
|
* mode always restores the external values. An accepted file cannot reuse
|
|
47296
48359
|
* the replaced file's `cacheKey`.
|
|
47297
48360
|
*/
|
|
47298
|
-
__completeEditSession(editor,
|
|
47299
|
-
this.settleEditSession(
|
|
48361
|
+
__completeEditSession(editor, mode2) {
|
|
48362
|
+
this.settleEditSession(mode2 === "install", editor);
|
|
47300
48363
|
}
|
|
47301
48364
|
settleEditSession(installResult, editor) {
|
|
47302
48365
|
const { editSession, file: externalFile, lineAnnotations: externalAnnotations } = this;
|
|
@@ -48451,10 +49514,10 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
|
|
|
48451
49514
|
else currentFile.type = "rename-changed";
|
|
48452
49515
|
}
|
|
48453
49516
|
if (line.startsWith("index ")) {
|
|
48454
|
-
const [, prevObjectId, newObjectId,
|
|
49517
|
+
const [, prevObjectId, newObjectId, mode2] = line.trim().match(INDEX_LINE_METADATA) ?? [];
|
|
48455
49518
|
if (prevObjectId != null) currentFile.prevObjectId = detachString(prevObjectId);
|
|
48456
49519
|
if (newObjectId != null) currentFile.newObjectId = detachString(newObjectId);
|
|
48457
|
-
if (
|
|
49520
|
+
if (mode2 != null) currentFile.mode = detachString(mode2);
|
|
48458
49521
|
}
|
|
48459
49522
|
if (line.startsWith("rename from ") || line.startsWith("copy from ")) currentFile.prevName = detachString(decodeDiffFileName(line.slice(line.startsWith("rename") ? 12 : 10)));
|
|
48460
49523
|
if (line.startsWith("rename to ") || line.startsWith("copy to ")) currentFile.name = detachString(decodeDiffFileName(line.slice(line.startsWith("rename") ? 10 : 8)));
|
|
@@ -49153,14 +50216,14 @@ var WordDiff = class extends Diff {
|
|
|
49153
50216
|
}
|
|
49154
50217
|
}).join("");
|
|
49155
50218
|
}
|
|
49156
|
-
postProcess(
|
|
49157
|
-
if (!
|
|
49158
|
-
return
|
|
50219
|
+
postProcess(changes2, options) {
|
|
50220
|
+
if (!changes2 || options.oneChangePerToken) {
|
|
50221
|
+
return changes2;
|
|
49159
50222
|
}
|
|
49160
50223
|
let lastKeep = null;
|
|
49161
50224
|
let insertion = null;
|
|
49162
50225
|
let deletion = null;
|
|
49163
|
-
|
|
50226
|
+
changes2.forEach((change) => {
|
|
49164
50227
|
if (change.added) {
|
|
49165
50228
|
insertion = change;
|
|
49166
50229
|
} else if (change.removed) {
|
|
@@ -49177,7 +50240,7 @@ var WordDiff = class extends Diff {
|
|
|
49177
50240
|
if (insertion || deletion) {
|
|
49178
50241
|
dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter);
|
|
49179
50242
|
}
|
|
49180
|
-
return
|
|
50243
|
+
return changes2;
|
|
49181
50244
|
}
|
|
49182
50245
|
};
|
|
49183
50246
|
var wordDiff = new WordDiff();
|
|
@@ -53595,8 +54658,8 @@ var FileDiff = class {
|
|
|
53595
54658
|
* values. `discard` mode always restores the external values. An accepted
|
|
53596
54659
|
* diff cannot reuse the replaced diff's `cacheKey`.
|
|
53597
54660
|
*/
|
|
53598
|
-
__completeEditSession(editor,
|
|
53599
|
-
this.settleEditSession(
|
|
54661
|
+
__completeEditSession(editor, mode2) {
|
|
54662
|
+
this.settleEditSession(mode2 === "install", editor);
|
|
53600
54663
|
}
|
|
53601
54664
|
settleEditSession(installResult, editor) {
|
|
53602
54665
|
const { editSession, fileDiff: externalDiff, lineAnnotations: externalAnnotations } = this;
|
|
@@ -74484,7 +75547,7 @@ function createCleanupMetricSnapshot(state3) {
|
|
|
74484
75547
|
totalNodeSlotCount: Math.max(0, state3.snapshot.nodes.length - 1)
|
|
74485
75548
|
};
|
|
74486
75549
|
}
|
|
74487
|
-
function createCleanupResult(
|
|
75550
|
+
function createCleanupResult(mode2, idsPreserved, before, after) {
|
|
74488
75551
|
return {
|
|
74489
75552
|
activeNodeCountAfter: after.activeNodeCount,
|
|
74490
75553
|
activeNodeCountBefore: before.activeNodeCount,
|
|
@@ -74493,7 +75556,7 @@ function createCleanupResult(mode, idsPreserved, before, after) {
|
|
|
74493
75556
|
idsPreserved,
|
|
74494
75557
|
loadInfoEntryCountAfter: after.loadInfoEntryCount,
|
|
74495
75558
|
loadInfoEntryCountBefore: before.loadInfoEntryCount,
|
|
74496
|
-
mode,
|
|
75559
|
+
mode: mode2,
|
|
74497
75560
|
reclaimedCachedPathEntryCount: before.cachedPathEntryCount - after.cachedPathEntryCount,
|
|
74498
75561
|
reclaimedLoadInfoEntryCount: before.loadInfoEntryCount - after.loadInfoEntryCount,
|
|
74499
75562
|
reclaimedNodeSlotCount: before.totalNodeSlotCount - after.totalNodeSlotCount,
|
|
@@ -74642,12 +75705,12 @@ function hasActiveCleanupBlockingLoads(state3) {
|
|
|
74642
75705
|
for (const loadInfo of state3.directoryLoadInfoById.values()) if (loadInfo.state === "loading" && loadInfo.activeAttemptId != null) return true;
|
|
74643
75706
|
return false;
|
|
74644
75707
|
}
|
|
74645
|
-
function cleanupPathStoreState(state3,
|
|
75708
|
+
function cleanupPathStoreState(state3, mode2) {
|
|
74646
75709
|
const before = createCleanupMetricSnapshot(state3);
|
|
74647
|
-
if (
|
|
75710
|
+
if (mode2 === "stable") withBenchmarkPhase(state3.instrumentation, "store.cleanup.stable", () => runStableCleanup(state3));
|
|
74648
75711
|
else withBenchmarkPhase(state3.instrumentation, "store.cleanup.aggressive", () => runAggressiveCleanup(state3));
|
|
74649
75712
|
const after = createCleanupMetricSnapshot(state3);
|
|
74650
|
-
return createCleanupResult(
|
|
75713
|
+
return createCleanupResult(mode2, mode2 === "stable", before, after);
|
|
74651
75714
|
}
|
|
74652
75715
|
|
|
74653
75716
|
// node_modules/@pierre/trees/dist/path-store/src/projection.js
|
|
@@ -77883,35 +78946,35 @@ function OverflowMarker({ children, marker, variant = "default" }) {
|
|
|
77883
78946
|
}
|
|
77884
78947
|
function OverflowContent(options) {
|
|
77885
78948
|
"use no memo";
|
|
77886
|
-
const { mode, children } = options;
|
|
78949
|
+
const { mode: mode2, children } = options;
|
|
77887
78950
|
return /* @__PURE__ */ u25("div", { children: [/* @__PURE__ */ u25("div", {
|
|
77888
78951
|
"data-truncate-content": "visible",
|
|
77889
|
-
children:
|
|
78952
|
+
children: mode2 === "fruncate" ? /* @__PURE__ */ u25("span", { children }) : children
|
|
77890
78953
|
}), /* @__PURE__ */ u25("div", {
|
|
77891
78954
|
"data-truncate-content": "overflow",
|
|
77892
78955
|
"aria-hidden": true,
|
|
77893
|
-
children:
|
|
78956
|
+
children: mode2 === "fruncate" ? /* @__PURE__ */ u25("span", { children }) : children
|
|
77894
78957
|
})] });
|
|
77895
78958
|
}
|
|
77896
|
-
function OverflowText({ children, mode = "truncate", marker = "\u2026", variant = "default", ...props }) {
|
|
78959
|
+
function OverflowText({ children, mode: mode2 = "truncate", marker = "\u2026", variant = "default", ...props }) {
|
|
77897
78960
|
"use no memo";
|
|
77898
78961
|
const contentNode = /* @__PURE__ */ u25(OverflowContent, {
|
|
77899
|
-
mode,
|
|
78962
|
+
mode: mode2,
|
|
77900
78963
|
children
|
|
77901
78964
|
}, "content");
|
|
77902
78965
|
const markerNode = /* @__PURE__ */ u25(OverflowMarker, {
|
|
77903
78966
|
marker,
|
|
77904
|
-
mode,
|
|
78967
|
+
mode: mode2,
|
|
77905
78968
|
variant
|
|
77906
78969
|
}, "marker");
|
|
77907
78970
|
const fillNode = /* @__PURE__ */ u25("div", { "data-truncate-fill": true }, "fill");
|
|
77908
78971
|
return /* @__PURE__ */ u25("div", {
|
|
77909
|
-
"data-truncate-container":
|
|
78972
|
+
"data-truncate-container": mode2,
|
|
77910
78973
|
"data-truncate-variant": variant,
|
|
77911
78974
|
...props,
|
|
77912
78975
|
children: /* @__PURE__ */ u25("div", {
|
|
77913
78976
|
"data-truncate-grid": true,
|
|
77914
|
-
children:
|
|
78977
|
+
children: mode2 === "truncate" ? [contentNode, markerNode] : [
|
|
77915
78978
|
markerNode,
|
|
77916
78979
|
contentNode,
|
|
77917
78980
|
fillNode
|
|
@@ -78387,8 +79450,8 @@ function RenameInput({ ariaLabel, isFlattened = false, ref, value, onBlur, onInp
|
|
|
78387
79450
|
|
|
78388
79451
|
// node_modules/@pierre/trees/dist/render/rowAttributes.js
|
|
78389
79452
|
function computeFileTreeRowElementAttributes(input) {
|
|
78390
|
-
const { row, mode, targetPath, ariaLabel, domId, isParked, itemHeight, features, state: state3, extraStyle } = input;
|
|
78391
|
-
const isSticky =
|
|
79453
|
+
const { row, mode: mode2, targetPath, ariaLabel, domId, isParked, itemHeight, features, state: state3, extraStyle } = input;
|
|
79454
|
+
const isSticky = mode2 === "sticky";
|
|
78392
79455
|
const parentPath = row.ancestorPaths.at(-1) ?? "";
|
|
78393
79456
|
const stateAttributes = {};
|
|
78394
79457
|
if (state3.isFocusRinged) stateAttributes["data-item-focused"] = true;
|
|
@@ -78430,7 +79493,7 @@ function computeFileTreeRowElementAttributes(input) {
|
|
|
78430
79493
|
|
|
78431
79494
|
// node_modules/@pierre/trees/dist/render/rowClickPlan.js
|
|
78432
79495
|
function computeFileTreeRowClickPlan(input) {
|
|
78433
|
-
const { event: event2, mode, isSearchOpen, isDirectory } = input;
|
|
79496
|
+
const { event: event2, mode: mode2, isSearchOpen, isDirectory } = input;
|
|
78434
79497
|
const additive = event2.ctrlKey || event2.metaKey;
|
|
78435
79498
|
const hasModifier = event2.shiftKey || additive;
|
|
78436
79499
|
const selection = event2.shiftKey ? {
|
|
@@ -78439,7 +79502,7 @@ function computeFileTreeRowClickPlan(input) {
|
|
|
78439
79502
|
} : additive ? { kind: "toggle" } : { kind: "single" };
|
|
78440
79503
|
return {
|
|
78441
79504
|
closeSearch: isSearchOpen,
|
|
78442
|
-
revealCanonical:
|
|
79505
|
+
revealCanonical: mode2 === "sticky",
|
|
78443
79506
|
selection,
|
|
78444
79507
|
toggleDirectory: !hasModifier && isDirectory
|
|
78445
79508
|
};
|
|
@@ -78981,8 +80044,8 @@ function renderFileTreeRowContent(row, resolveIcon, { actionLaneEnabled = false,
|
|
|
78981
80044
|
function renderStyledRow(frame, row, key2, options = {}) {
|
|
78982
80045
|
const { controller, renameView, visualFocusPath, contextHoverPath, draggedPathSet, dragTarget, dragAndDropEnabled, shouldSuppressContextMenu, handleRowDragStart, handleRowDragEnd, handleRowTouchStart, instanceId: instanceId5, itemHeight, gitStatusByPath, ignoredGitDirectories, ignoredInheritanceCache, directoriesWithGitChanges, gitLaneActive, contextMenuEnabled, contextMenuTriggerMode, contextMenuButtonTriggerEnabled, contextMenuButtonVisibility, contextMenuRightClickEnabled, registerRenameInput, registerButton, resolveIcon, renderDecorationForRow, openContextMenuForRow, onRowClick, onKeyDown } = frame;
|
|
78983
80046
|
const targetPath = getFileTreeRowPath(row);
|
|
78984
|
-
const { isParked = false, mode = "flow", style } = options;
|
|
78985
|
-
const isSticky =
|
|
80047
|
+
const { isParked = false, mode: mode2 = "flow", style } = options;
|
|
80048
|
+
const isSticky = mode2 === "sticky";
|
|
78986
80049
|
const effectiveGitStatus = gitStatusByPath?.get(targetPath) ?? null ?? getInheritedIgnoredGitStatus(row.ancestorPaths, ignoredGitDirectories, ignoredInheritanceCache);
|
|
78987
80050
|
const containsGitChange = row.kind === "directory" && (directoriesWithGitChanges?.has(targetPath) ?? false);
|
|
78988
80051
|
const customDecoration = renderDecorationForRow(row, targetPath);
|
|
@@ -79028,7 +80091,7 @@ function renderStyledRow(frame, row, key2, options = {}) {
|
|
|
79028
80091
|
},
|
|
79029
80092
|
isParked,
|
|
79030
80093
|
itemHeight,
|
|
79031
|
-
mode,
|
|
80094
|
+
mode: mode2,
|
|
79032
80095
|
row,
|
|
79033
80096
|
state: {
|
|
79034
80097
|
containsGitChange,
|
|
@@ -79086,7 +80149,7 @@ function renderStyledRow(frame, row, key2, options = {}) {
|
|
|
79086
80149
|
handleRowTouchStart(event2, row, targetPath);
|
|
79087
80150
|
} : void 0,
|
|
79088
80151
|
onClick: (event2) => {
|
|
79089
|
-
onRowClick(event2, row, targetPath,
|
|
80152
|
+
onRowClick(event2, row, targetPath, mode2);
|
|
79090
80153
|
},
|
|
79091
80154
|
children: rowContent
|
|
79092
80155
|
});
|
|
@@ -80250,7 +81313,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
|
80250
81313
|
top: `${pointerAnchorRect.top}px`
|
|
80251
81314
|
} : rowAnchorTop != null ? { top: `${rowAnchorTop}px` } : void 0;
|
|
80252
81315
|
const contextMenuTriggerStyle = isPointerContextMenuOpen ? { opacity: "0" } : void 0;
|
|
80253
|
-
const handleRowClick = b12((event2, row, targetPath,
|
|
81316
|
+
const handleRowClick = b12((event2, row, targetPath, mode2) => {
|
|
80254
81317
|
const plan = computeFileTreeRowClickPlan({
|
|
80255
81318
|
event: {
|
|
80256
81319
|
ctrlKey: event2.ctrlKey,
|
|
@@ -80259,7 +81322,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
|
80259
81322
|
},
|
|
80260
81323
|
isDirectory: row.kind === "directory",
|
|
80261
81324
|
isSearchOpen,
|
|
80262
|
-
mode
|
|
81325
|
+
mode: mode2
|
|
80263
81326
|
});
|
|
80264
81327
|
const shouldToggleDirectory = plan.toggleDirectory && row.kind === "directory";
|
|
80265
81328
|
const mountedDirectoryPath = shouldToggleDirectory ? controller.resolveMountedDirectoryPathFromInput(targetPath) : null;
|
|
@@ -80278,7 +81341,7 @@ function FileTreeView({ composition, controller, gitStatusByPath, ignoredGitDire
|
|
|
80278
81341
|
}
|
|
80279
81342
|
const clickedElement = event2.currentTarget instanceof HTMLElement ? event2.currentTarget : null;
|
|
80280
81343
|
const clickedRowIsVisible = row.index >= layoutSnapshot.visible.startIndex && row.index <= layoutSnapshot.visible.endIndex;
|
|
80281
|
-
const shouldExposeFocusedTrigger =
|
|
81344
|
+
const shouldExposeFocusedTrigger = mode2 === "flow" && clickedRowIsVisible && clickedElement != null && clickedElement.dataset.itemParked !== "true";
|
|
80282
81345
|
controller.focusMountedPathFromInput(actionTargetPath);
|
|
80283
81346
|
if (shouldExposeFocusedTrigger) {
|
|
80284
81347
|
domFocusOwnerRef.current = true;
|
|
@@ -81189,6 +82252,7 @@ var elements = {
|
|
|
81189
82252
|
"slicc-approvals": SliccApprovals,
|
|
81190
82253
|
"slicc-secrets": SliccSecrets,
|
|
81191
82254
|
"slicc-vault-button": SliccVaultButton,
|
|
82255
|
+
"slicc-value-request": SliccValueRequest,
|
|
81192
82256
|
"slicc-confirm": SliccConfirm,
|
|
81193
82257
|
"slicc-prompt": SliccPrompt,
|
|
81194
82258
|
"slicc-app": SliccApp
|
|
@@ -81227,10 +82291,12 @@ export {
|
|
|
81227
82291
|
SliccPrompt,
|
|
81228
82292
|
SliccSecrets,
|
|
81229
82293
|
SliccUpdates,
|
|
82294
|
+
SliccValueRequest,
|
|
81230
82295
|
SliccVaultButton,
|
|
81231
82296
|
confirm,
|
|
81232
82297
|
define2 as define,
|
|
81233
82298
|
grammarBase,
|
|
82299
|
+
isVaultFailure,
|
|
81234
82300
|
panelCommand,
|
|
81235
82301
|
prompt,
|
|
81236
82302
|
resolveColor,
|